I am trying to implement a global folding from scratch as a learning project.
1. Prepare a Bell State
from typing import List
import pennylane as qml
noise_strength = 0.05
dev_noise_free = qml.device("default.mixed", wires=2)
dev = qml.transforms.insert(
dev_noise_free,
qml.DepolarizingChannel,
noise_strength
)
def circuit():
"""
A circuit preparing a Bell state
"""
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))
2. Implement the unitary fold
def unitary_fold(circuit, scale_factor: int):
# original ops
circuit() # somehow I have to run in so that `.tape` works
# take all the operations of a circuit
original_ops = circuit.tape.operations
ops = circuit.tape.copy(copy_operations=True).operations
n, s = divmod(scale_factor - 1, 2)
# For the 1st part (U^H U)**n
for i in range(n):
for op in original_ops[::-1]:
ops.append(qml.adjoint(op))
for op in original_ops:
ops.append(op)
# For the 2nd part (L_d^H .. L_s^H) (L_s .. L_d)
if s > 0:
last_layers = original_ops[-s:]
for op in last_layers[::-1]:
ops.append(qml.adjoint(op))
for i in last_layers:
ops.append(op)
# Return list of op to create the circuit
return ops, circuit.tape.measurements
3. Test run
The conundrum is in this session
@qml.qnode(dev)
def circuit_from_ops(operations: List, measurements: List):
for op in operations[:]: ## This line is important
qml.apply(op)
print(op)
return qml.apply(measurements[0])
device_circuit = qml.QNode(circuit, dev)
ops, measurements = unitary_fold(device_circuit, 5)
print(qml.draw(circuit_from_ops)(ops, measurements))
It would give me
0: ββHβββββββββHβ ββββββHβ ββHβββββ€ β<Z@Z>
1: βββββ°Xββ°Xβ ββββββ°Xβ βββββββββ°Xββ€ β°<Z@Z>
In the 3rd line above, if I change operations[:]
to operations[:6]
, then I have
0: ββHβββββββββHβ ββHβββββ€ β<Z@Z>
1: βββββ°Xββ°Xβ βββββββββ°Xββ€ β°<Z@Z>
Which is correct
But if I change operations[:]
to operations[:7]
, then I have
0: ββHβββββββββHβ ββHββββββ€ β<Z@Z>
1: βββββ°Xββ°Xβ βββββββββ°Xβ ββ€ β°<Z@Z>
Note the last CNOT
was replaced by its adjoint, instead of adding a new adjoint CNOT like below
0: ββHβββββββββHβ ββHβββββββββ€ β<Z@Z>
1: βββββ°Xββ°Xβ βββββββββ°Xββ°Xβ ββ€ β°<Z@Z>
I donβt understand what I am doint wrong here?
qml.about
Name: PennyLane
Version: 0.35.1
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: GitHub - PennyLaneAI/pennylane: PennyLane is a cross-platform Python library for differentiable programming of quantum computers. Train a quantum computer the same way as a neural network.
Author:
Author-email:
License: Apache License 2.0
Location: c:\code\zne\venv\lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-qiskit, PennyLane_Lightning
Platform info: Windows-10-10.0.19045-SP0
Python version: 3.10.9
Numpy version: 1.26.4
Scipy version: 1.11.4
Installed devices:
- default.clifford (PennyLane-0.35.1)
- default.gaussian (PennyLane-0.35.1)
- default.mixed (PennyLane-0.35.1)
- default.qubit (PennyLane-0.35.1)
- default.qubit.autograd (PennyLane-0.35.1)
- default.qubit.jax (PennyLane-0.35.1)
- default.qubit.legacy (PennyLane-0.35.1)
- default.qubit.tf (PennyLane-0.35.1)
- default.qubit.torch (PennyLane-0.35.1)
- default.qutrit (PennyLane-0.35.1)
- null.qubit (PennyLane-0.35.1)
- lightning.qubit (PennyLane_Lightning-0.35.1)
- qiskit.aer (PennyLane-qiskit-0.35.1)
- qiskit.basicaer (PennyLane-qiskit-0.35.1)
- qiskit.ibmq (PennyLane-qiskit-0.35.1)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.35.1)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.35.1)
- qiskit.remote (PennyLane-qiskit-0.35.1)