Hi Catalina.
Thanks for answering. I have tried running the demo you told me and it did work, the problem is in the optimizer I think.
Here I attach you all my code and the whole error:
import pennylane as qml
from pennylane import numpy as np
from mitiq.zne.scaling import fold_global
from mitiq.zne.inference import RichardsonFactory
from pennylane.transforms import mitigate_with_zne
n_wires = 2
dev_ideal = qml.device("default.mixed", wires=n_wires)
dev_noisy = qml.device("qiskit.aer", wires=n_wires)
def QCNN(a, symbols):
qml.RX(a[0], 0)
qml.RX(a[1], 1)
qml.RY(symbols[0], 0)
qml.RX(symbols[1], 0)
qml.RZ(symbols[2], 0)
qml.CNOT([0, 1])
qml.RY((-1) * symbols[0], 1)
qml.RX((-1) * symbols[1], 1)
qml.RZ((-1) * symbols[2], 1)
return qml.expval(qml.PauliZ(1))
ideal_qnode2 = qml.QNode(QCNN, dev_ideal)
noisy_qnode2 = qml.QNode(QCNN, dev_noisy)
import qiskit_machine_learning as qiskitml
from qiskit_machine_learning import datasets
train_feats, train_labels, test_feats, test_labels = qiskitml.datasets.breast_cancer(
80, 20, n=2, plot_data=False, one_hot=False
)
def square_loss(labels, predictions):
loss = 0
for l, p in zip(labels, predictions):
loss = loss + (l - p) ** 2
loss = loss / len(labels)
return loss
def mitigated_noisy_cost(symbols, X, Y):
# with X the feats of the dataset and Y the labels
extrapolate = RichardsonFactory.extrapolate
scale_factors = [1, 2, 3]
mitigated_qnode = mitigate_with_zne(scale_factors, fold_global, extrapolate)(
noisy_qnode2
)
predictions = [mitigated_qnode(x, symbols) for x in X]
return square_loss(Y, predictions)
def noisy_cost(symbols, X, Y):
predictions = [noisy_qnode2(x, symbols) for x in X]
return square_loss(Y, predictions)
def cost(symbols, X, Y):
predictions = [ideal_qnode2(x, symbols) for x in X]
return square_loss(Y, predictions)
symbols = np.random.randn(3, requires_grad=True)
from pennylane.optimize import NesterovMomentumOptimizer
from pennylane.optimize import AdamOptimizer
opt = NesterovMomentumOptimizer(0.01)
symbols, _, _ = opt.step(cost, symbols, train_feats[0:3], train_labels[0:3])
print(symbols)
symbols, _, _ = opt.step(noisy_cost, symbols, train_feats[0:3], train_labels[0:3])
print(symbols)
# here we find the error of translation from pennylane to QASM
symbols, _, _ = opt.step(
mitigated_noisy_cost, symbols, train_feats[0:3], train_labels[0:3]
)
print(symbols)
And here I attach the obtained error:
QasmException Traceback (most recent call last)
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\conversions.py:89, in convert_to_mitiq(circuit)
88 try:
—> 89 mitiq_circuit = conversion_function(circuit)
90 except Exception:
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\mitiq_pennylane\conversions.py:72, in from_pennylane(tape)
70 qasm = tape.to_openqasm(rotations=False, wires=wires, measure_all=False)
—> 72 return cirq_from_qasm(qasm)
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\mitiq_qiskit\conversions.py:311, in from_qasm(qasm)
310 qasm = _remove_qasm_barriers(qasm)
→ 311 return circuit_from_qasm(qasm)
File ~\Miniconda3\envs\catastro\Lib\site-packages\cirq\contrib\qasm_import\qasm.py:29, in circuit_from_qasm(qasm)
20 “”“Parses an OpenQASM string to cirq.Circuit
.
21
22 Args:
(…)
26 The parsed circuit
27 “””
—> 29 return QasmParser().parse(qasm).circuit
File ~\Miniconda3\envs\catastro\Lib\site-packages\cirq\contrib\qasm_import_parser.py:542, in QasmParser.parse(self, qasm)
541 self.lexer.input(self.qasm)
→ 542 self.parsedQasm = self.parser.parse(lexer=self.lexer)
543 return self.parsedQasm
File ~\Miniconda3\envs\catastro\Lib\site-packages\ply\yacc.py:333, in LRParser.parse(self, input, lexer, debug, tracking, tokenfunc)
332 else:
→ 333 return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
File ~\Miniconda3\envs\catastro\Lib\site-packages\ply\yacc.py:1201, in LRParser.parseopt_notrack(self, input, lexer, debug, tracking, tokenfunc)
1200 self.state = state
→ 1201 tok = call_errorfunc(self.errorfunc, errtoken, self)
1202 if self.errorok:
1203 # User must have done some kind of panic
1204 # mode recovery on their own. The
1205 # returned token is the next lookahead
File ~\Miniconda3\envs\catastro\Lib\site-packages\ply\yacc.py:192, in call_errorfunc(errorfunc, token, parser)
191 _restart = parser.restart
→ 192 r = errorfunc(token)
193 try:
File ~\Miniconda3\envs\catastro\Lib\site-packages\cirq\contrib\qasm_import_parser.py:525, in QasmParser.p_error(self, p)
523 raise QasmException(‘Unexpected end of file’)
→ 525 raise QasmException(
526 f"““Syntax error: ‘{p.value}’
527 {self.debug_context(p)}
528 at line {p.lineno}, column {self.find_column(p)}””"
529 )
QasmException: Syntax error: ‘ArrayBox’
…grad ArrayBox with value 1.1077815696203488) q[0];
rx(Autograd ArrayBox with value -0.9704731462846121) q[0];
rz(Autograd ArrayBox with value -0.5289506146594846) q[0];
cx q[0],q[1];
ry(Autograd ArrayBox with value -1.1077815696203488) q[1];
rx(Autograd ArrayBox with value 0.9704731462846121) q[1];
rz(Autograd ArrayBox with value 0.5289506146594846) q[1]
^
at line 7, column 13
During handling of the above exception, another exception occurred:
CircuitConversionError Traceback (most recent call last)
Cell In[67], line 1
----> 1 symbols, _, _ = opt.step(mitigated_noisy_cost, symbols, train_feats[0:3], train_labels[0:3])
2 print(symbols)
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\optimize\gradient_descent.py:88, in GradientDescentOptimizer.step(self, objective_fn, grad_fn, *args, **kwargs)
70 def step(self, objective_fn, *args, grad_fn=None, **kwargs):
71 “”“Update trainable arguments with one step of the optimizer.
72
73 Args:
(…)
85 If single arg is provided, list [array] is replaced by array.
86 “””
—> 88 g, _ = self.compute_grad(objective_fn, args, kwargs, grad_fn=grad_fn)
89 new_args = self.apply_grad(g, args)
91 # unwrap from list if one argument, cleaner return
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\optimize\nesterov_momentum.py:71, in NesterovMomentumOptimizer.compute_grad(self, objective_fn, args, kwargs, grad_fn)
68 shifted_args[index] = args[index] - self.momentum * self.accumulation[index]
70 g = get_gradient(objective_fn) if grad_fn is None else grad_fn
—> 71 grad = g(*shifted_args, **kwargs)
72 forward = getattr(g, “forward”, None)
74 grad = (grad,) if len(trainable_indices) == 1 else grad
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane_grad.py:115, in grad.call(self, *args, **kwargs)
112 self._forward = self._fun(*args, **kwargs)
113 return ()
→ 115 grad_value, ans = grad_fn(*args, **kwargs)
116 self._forward = ans
118 return grad_value
File ~\Miniconda3\envs\catastro\Lib\site-packages\autograd\wrap_util.py:20, in unary_to_nary..nary_operator..nary_f(*args, **kwargs)
18 else:
19 x = tuple(args[i] for i in argnum)
—> 20 return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane_grad.py:133, in grad._grad_with_forward(fun, x)
127 @staticmethod
128 @unary_to_nary
129 def _grad_with_forward(fun, x):
130 “”“This function is a replica of autograd.grad
, with the only
131 difference being that it returns both the gradient and the forward pass
132 value.”“”
→ 133 vjp, ans = _make_vjp(fun, x)
135 if not vspace(ans).size == 1:
136 raise TypeError(
137 "Grad only applies to real scalar-output functions. "
138 “Try jacobian, elementwise_grad or holomorphic_grad.”
139 )
File ~\Miniconda3\envs\catastro\Lib\site-packages\autograd\core.py:10, in make_vjp(fun, x)
8 def make_vjp(fun, x):
9 start_node = VJPNode.new_root()
—> 10 end_value, end_node = trace(start_node, fun, x)
11 if end_node is None:
12 def vjp(g): return vspace(x).zeros()
File ~\Miniconda3\envs\catastro\Lib\site-packages\autograd\tracer.py:10, in trace(start_node, fun, x)
8 with trace_stack.new_trace() as t:
9 start_box = new_box(x, t, start_node)
—> 10 end_box = fun(start_box)
11 if isbox(end_box) and end_box._trace == start_box._trace:
12 return end_box._value, end_box._node
File ~\Miniconda3\envs\catastro\Lib\site-packages\autograd\wrap_util.py:15, in unary_to_nary..nary_operator..nary_f..unary_f(x)
13 else:
14 subargs = subvals(args, zip(argnum, x))
—> 15 return fun(*subargs, **kwargs)
Cell In[43], line 16, in mitigated_noisy_cost(symbols, X, Y)
12 scale_factors = [1, 2, 3]
14 mitigated_qnode=mitigate_with_zne(scale_factors, fold_global, extrapolate)(
15 noisy_qnode2)
—> 16 predictions= [mitigated_qnode(x, symbols) for x in X]
17 return square_loss(Y, predictions)
Cell In[43], line 16, in (.0)
12 scale_factors = [1, 2, 3]
14 mitigated_qnode=mitigate_with_zne(scale_factors, fold_global, extrapolate)(
15 noisy_qnode2)
—> 16 predictions= [mitigated_qnode(x, symbols) for x in X]
17 return square_loss(Y, predictions)
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\transforms\batch_transform.py:295, in batch_transform.default_qnode_wrapper.._wrapper(*args, **kwargs)
292 qnode.interface = qml.math.get_interface(*args, *list(kwargs.values()))
294 qnode.construct(args, kwargs)
→ 295 tapes, processing_fn = self.construct(qnode.qtape, *targs, **tkwargs)
297 interface = qnode.interface
298 execute_kwargs = getattr(qnode, “execute_kwargs”, {}).copy()
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\transforms\batch_transform.py:412, in batch_transform.construct(self, tape, *args, **kwargs)
409 if expand and self.expand_fn is not None:
410 tape = self.expand_fn(tape, *args, **kwargs)
→ 412 tapes, processing_fn = self.transform_fn(tape, *args, **kwargs)
414 if processing_fn is None:
416 def processing_fn(x):
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\transforms\mitigate.py:517, in mitigate_with_zne(circuit, scale_factors, folding, extrapolate, folding_kwargs, extrapolate_kwargs, reps_per_factor)
514 tape = circuit.expand(stop_at=lambda op: not isinstance(op, QuantumScript))
515 script_removed = QuantumScript(tape.ops)
→ 517 tapes = [
518 [folding(script_removed, s, **folding_kwargs) for _ in range(reps_per_factor)]
519 for s in scale_factors
520 ]
522 tapes = [tape for tapes_ in tapes for tape_ in tapes_] # flattens nested list
523 out_tapes = [QuantumScript(tape_.operations, tape.measurements, tape.prep) for tape in tapes]
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\transforms\mitigate.py:518, in (.0)
514 tape = circuit.expand(stop_at=lambda op: not isinstance(op, QuantumScript))
515 script_removed = QuantumScript(tape.ops)
517 tapes = [
→ 518 [folding(script_removed, s, **folding_kwargs) for _ in range(reps_per_factor)]
519 for s in scale_factors
520 ]
522 tapes = [tape for tapes_ in tapes for tape_ in tapes_] # flattens nested list
523 out_tapes = [QuantumScript(tape_.operations, tape.measurements, tape.prep) for tape in tapes]
File ~\Miniconda3\envs\catastro\Lib\site-packages\pennylane\transforms\mitigate.py:518, in (.0)
514 tape = circuit.expand(stop_at=lambda op: not isinstance(op, QuantumScript))
515 script_removed = QuantumScript(tape.ops)
517 tapes = [
→ 518 [folding(script_removed, s, **folding_kwargs) for _ in range(reps_per_factor)]
519 for s in scale_factors
520 ]
522 tapes = [tape for tapes_ in tapes for tape_ in tapes_] # flattens nested list
523 out_tapes = [QuantumScript(tape_.operations, tape.measurements, tape.prep) for tape in tapes]
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\conversions.py:251, in noise_scaling_converter..new_scaling_function(circuit, *args, **kwargs)
247 # Apply identity gates to idle qubits otherwise they get lost
248 # when converting to Cirq. Eventually, identities will be removed.
249 idle_qubits = _add_identity_to_idle(circuit)
→ 251 scaled_circuit = atomic_converter(noise_scaling_function)(
252 circuit, *args, **kwargs
253 )
255 # Post atomic conversion
256 # PyQuil: Restore declarations, measurements, and metadata.
257 if “pyquil” in scaled_circuit.module:
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\conversions.py:181, in atomic_converter..qprogram_modifier(circuit, *args, **kwargs)
176 @wraps(cirq_circuit_modifier)
177 def qprogram_modifier(
178 circuit: QPROGRAM, *args: Any, **kwargs: Any
179 ) → QPROGRAM:
180 # Convert to Mitiq representation.
→ 181 mitiq_circuit, input_circuit_type = convert_to_mitiq(circuit)
183 # Modify the Cirq circuit.
184 scaled_circuit = cirq_circuit_modifier(mitiq_circuit, *args, **kwargs)
File ~\Miniconda3\envs\catastro\Lib\site-packages\mitiq\interface\conversions.py:91, in convert_to_mitiq(circuit)
89 mitiq_circuit = conversion_function(circuit)
90 except Exception:
—> 91 raise CircuitConversionError(
92 "Circuit could not be converted to an internal Mitiq circuit. "
93 "This may be because the circuit contains custom gates or Pragmas "
94 "(pyQuil). If you think this is a bug or that this circuit should "
95 "be supported, you can open an issue at "
96 “GitHub - unitaryfund/mitiq: Mitiq is an open source toolkit for implementing error mitigation techniques on most current intermediate-scale quantum computers.. \n\nProvided circuit has "
97 f"type {type(circuit)} and is:\n\n{circuit}\n\nCircuit types "
98 f"supported by Mitiq are \n{SUPPORTED_PROGRAM_TYPES}.”
99 )
101 return mitiq_circuit, input_circuit_type
CircuitConversionError: Circuit could not be converted to an internal Mitiq circuit. This may be because the circuit contains custom gates or Pragmas (pyQuil). If you think this is a bug or that this circuit should be supported, you can open an issue at GitHub - unitaryfund/mitiq: Mitiq is an open source toolkit for implementing error mitigation techniques on most current intermediate-scale quantum computers..
Provided circuit has type <class ‘pennylane.tape.qscript.QuantumScript’> and is:
<QuantumScript: wires=[0, 1], params=8>
Circuit types supported by Mitiq are
{‘cirq’: ‘Circuit’, ‘pyquil’: ‘Program’, ‘qiskit’: ‘QuantumCircuit’, ‘braket’: ‘Circuit’, ‘pennylane’: ‘QuantumTape’}.
Thanks in advance.