unitaryfund / mitiq

Mitiq is an open source toolkit for implementing error mitigation techniques on most current intermediate-scale quantum computers.
https://mitiq.readthedocs.io
GNU General Public License v3.0
363 stars 160 forks source link

Error for when passing folded circuit to calculate expectation value in qiskit #1150

Closed anhdpham closed 2 years ago

anhdpham commented 2 years ago

I think there is a problem with passing a folded circuit generated by mitiq to the expectation value routine used to calculate in mitiq

def ansatz(parameter): circuit = QuantumCircuit(2) circuit.rx(parameter[0],0) circuit.cnot(0,1) circuit.rx(parameter[0],1) circuit.cnot(0,1) circuit.rx(parameter[0],0) return circuit

angles = [] for angle in np.linspace(0, 2 * np.pi, 50): angles.append(angle)

circuits = [] for angle in angles: circuits.append(ansatz([angle]))

def qiskit_executor(circuit: qiskit.QuantumCircuit, shots: int = 8192) -> float: quantum_instance = QuantumInstance(backend=Aer.get_backend('qasm_simulator'),noise_model = noise_model, basis_gates = noise_model.basis_gates, shots=10000) psi = CircuitStateFn(circuit) measurable_expression = StateFn(Hamiltonian, is_measurement=True).compose(psi) expectation = PauliExpectation().convert(measurable_expression) sampler = CircuitSampler(quantum_instance).convert(expectation) value = sampler.eval().real return value

scale_factors = [1., 1.5, 2., 2.5, 3.] folded_circuits = [ zne.scaling.fold_gates_at_random(circuits[0], scale) for scale in scale_factors ]

qiskit_executor(folded_circuits[0])

Error:

ValueError Traceback (most recent call last) /tmp/ipykernel_300/1422248828.py in ----> 1 qiskit_executor(folded_circuits[0])

/tmp/ipykernel_300/1414635650.py in qiskit_executor(circuit, shots) 4 # ansatz_value = ansatz.bind_parameters({theta: val for val in theta_val}) 5 psi = CircuitStateFn(circuit) ----> 6 measurable_expression = StateFn(Hamiltonian, is_measurement=True).compose(psi) 7 expectation = PauliExpectation().convert(measurable_expression) 8 sampler = CircuitSampler(quantum_instance).convert(expectation)

~/anaconda3/envs/IBM_qiskit/lib/python3.9/site-packages/qiskit/opflow/state_fns/state_fn.py in compose(self, other, permutation, front) 308 ) 309 --> 310 new_self, other = self._expand_shorter_operator_and_permute(other, permutation) 311 312 if front:

~/anaconda3/envs/IBM_qiskit/lib/python3.9/site-packages/qiskit/opflow/state_fns/state_fn.py in _expand_shorter_operator_and_permute(self, other, permutation) 263 return self, StateFn("0" * self.num_qubits) 264 --> 265 return super()._expand_shorter_operator_and_permute(other, permutation) 266 267 def to_matrix(self, massive: bool = False) -> np.ndarray:

~/anaconda3/envs/IBM_qiskit/lib/python3.9/site-packages/qiskit/opflow/operator_base.py in _expand_shorter_operator_and_permute(self, other, permutation) 436 other = Zero.class("0" * self.num_qubits) 437 elif other.num_qubits < self.num_qubits: --> 438 other = other._expand_dim(self.num_qubits - other.num_qubits) 439 elif other.num_qubits > self.num_qubits: 440 new_self = self._expand_dim(other.num_qubits - self.num_qubits)

~/anaconda3/envs/IBM_qiskit/lib/python3.9/site-packages/qiskit/opflow/state_fns/circuit_state_fn.py in _expand_dim(self, num_qubits) 383 # this is equivalent to self.tensor(identity_operator), but optimized for better performance 384 # just like in tensor method, qiskit endianness is reversed here --> 385 return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) 386 387 def permute(self, permutation: List[int]) -> "CircuitStateFn":

~/anaconda3/envs/IBM_qiskit/lib/python3.9/site-packages/qiskit/opflow/state_fns/circuit_state_fn.py in permute(self, permutation) 396 A new CircuitStateFn containing the permuted circuit. 397 """ --> 398 new_qc = QuantumCircuit(max(permutation) + 1).compose(self.primitive, qubits=permutation) 399 return CircuitStateFn(new_qc, coeff=self.coeff, is_measurement=self.is_measurement)

ValueError: max() arg is an empty sequence

It works fine if i pass a circuit created by QuantumCircuit in qiskit.

github-actions[bot] commented 2 years ago

Hello @anhdpham, thank you for your interest in Mitiq! If this is a bug report, please provide screenshots and/or minimum viable code to reproduce your issue, so we can do our best to help get it fixed. If you have any questions in the meantime, you can also ask us on the Unitary Fund Discord.

andreamari commented 2 years ago

Thanks @anhdpham for reporting this! It seems a Mitiq bug but we need to investigate more to understand the problem.

nathanshammah commented 2 years ago

@anhdpham thanks for opening this and the other issue. If it could help clarify them, you're welcome to join the Mitiq community call on Unitary Fund's Discord, which is on Fridays at 18:00 CET (https://discord.com/invite/JqVGmpkP96).

Aaron-Robertson commented 2 years ago

Hi @anhdpham, could you provide more details on your Hamiltonian, noise_model, and installed packages? Can use the mitiq.about() function to retrieve the installed dependencies.

I attempted to reproduce this error but was unable to with my interpretation of the provided code (plus a few fast/unchecked assumptions from tutorials), to yield ~-1.063038113954:

from qiskit.utils import QuantumInstance
from qiskit.opflow import I, X, Y, Z, CircuitStateFn, StateFn, CircuitSampler, PauliExpectation
from qiskit.providers.aer.noise.errors.standard_errors import coherent_unitary_error
from qiskit.providers.aer.noise import NoiseModel
import qiskit.quantum_info as qi
import numpy as np
from mitiq import zne

def ansatz(parameter):
    circuit = QuantumCircuit(2)
    circuit.rx(parameter[0],0)
    circuit.cnot(0,1)
    circuit.rx(parameter[0],1)
    circuit.cnot(0,1)
    circuit.rx(parameter[0],0)
    return circuit

epsilon = 0.1

err_h = QuantumCircuit(1, 1)
err_h.h(0)
err_h.p(epsilon, 0)
err_h.h(0)
err_h.p(-epsilon, 0)

u_err_h = qi.Operator(err_h)

noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(coherent_unitary_error(u_err_h), 'h')

angles = []
for angle in np.linspace(0, 2 * np.pi, 50):
    angles.append(angle)

circuits = []
for angle in angles:
    circuits.append(ansatz([angle]))

Hamiltonian = (-1.0523732 * I^I) + \
              (0.39793742 * I^Z) + \
              (-0.3979374 * Z^I) + \
              (-0.0112801 * Z^Z) + \
              (0.18093119 * X^X)

def qiskit_executor(circuit: QuantumCircuit, shots: int = 8192) -> float:
    quantum_instance = QuantumInstance(
        backend=Aer.get_backend('qasm_simulator'),
        noise_model = noise_model,
        basis_gates = noise_model.basis_gates, shots=10000
    )
    psi = CircuitStateFn(circuit)
    measurable_expression = StateFn(Hamiltonian, is_measurement=True).compose(psi)
    expectation = PauliExpectation().convert(measurable_expression)
    sampler = CircuitSampler(quantum_instance).convert(expectation)
    value = sampler.eval().real
    return value

scale_factors = [1., 1.5, 2., 2.5, 3.]
folded_circuits = [
    zne.scaling.fold_gates_at_random(circuits[0], scale)
    for scale in scale_factors
]

qiskit_executor(folded_circuits[0])
anhdpham commented 2 years ago

Hi @Aaron-Robertson. My dependancies from !pip list:

Package Version


anyio 2.2.0 appnope 0.1.2 argon2-cffi 20.1.0 async-generator 1.10 attrs 21.4.0 Babel 2.9.1 backcall 0.2.0 bleach 4.1.0 brotlipy 0.7.0 cachetools 4.2.4 certifi 2021.10.8 cffi 1.15.0 charset-normalizer 2.0.10 cirq 0.10.0 cryptography 36.0.1 cycler 0.11.0 debugpy 1.5.1 decorator 4.4.2 defusedxml 0.7.1 dill 0.3.4 docplex 2.22.213 entrypoints 0.3 fonttools 4.28.5 google-api-core 1.31.5 google-auth 1.35.0 googleapis-common-protos 1.54.0 graphviz 0.19.1 grpcio 1.43.0 gurobipy 9.5.0 h5py 3.6.0 ibm-quantum-widgets 1.0.3 idna 3.3 importlib-metadata 4.8.2 ipykernel 6.4.1 ipython 7.29.0 ipython-genutils 0.2.0 ipywidgets 7.6.5 jedi 0.18.0 Jinja2 2.11.3 joblib 1.1.0 json5 0.9.6 jsonschema 3.2.0 jupyter-client 7.1.0 jupyter-core 4.9.1 jupyter-server 1.4.1 jupyterlab 3.2.1 jupyterlab-pygments 0.1.2 jupyterlab-server 2.10.2 jupyterlab-widgets 1.0.2 kiwisolver 1.3.2 lark-parser 0.12.0 MarkupSafe 2.0.1 matplotlib 3.5.1 matplotlib-inline 0.1.2 mistune 0.8.4 mitiq 0.12.0 mpmath 1.2.1 nbclassic 0.2.6 nbclient 0.5.3 nbconvert 6.3.0 nbformat 5.1.3 nest-asyncio 1.5.1 networkx 2.5.1 notebook 6.4.6 ntlm-auth 1.5.0 numpy 1.22.2 packaging 21.3 pandas 1.3.5 pandocfilters 1.4.3 parso 0.8.3 pbr 5.8.0 pexpect 4.8.0 pickleshare 0.7.5 Pillow 9.0.0 pip 21.2.4 ply 3.11 prometheus-client 0.12.0 prompt-toolkit 3.0.20 protobuf 3.13.0 psutil 5.9.0 ptyprocess 0.7.0 pyasn1 0.4.8 pyasn1-modules 0.2.8 pycparser 2.21 Pygments 2.10.0 pylatexenc 2.10 pyOpenSSL 21.0.0 pyparsing 3.0.4 pyrsistent 0.18.0 pyscf 2.0.1 PySocks 1.7.1 python-constraint 1.4.0 python-dateutil 2.8.2 pytket 0.19.0 pytket-qiskit 0.22.0 pytz 2021.3 pyzmq 22.3.0 qiskit 0.34.1 qiskit-aer 0.10.2 qiskit-ibmq-provider 0.18.3 qiskit-ignis 0.7.0 qiskit-ionq 0.1.4 qiskit-nature 0.3.0 qiskit-optimization 0.3.0 qiskit-terra 0.19.1 requests 2.27.1 requests-ntlm 1.1.0 retworkx 0.11.0 rsa 4.8 scikit-learn 1.0.2 scipy 1.7.3 seaborn 0.11.2 Send2Trash 1.8.0 setuptools 58.0.4 six 1.16.0 sniffio 1.2.0 sortedcontainers 2.4.0 stevedore 3.5.0 symengine 0.8.1 sympy 1.9 terminado 0.9.4 testpath 0.5.0 threadpoolctl 3.0.0 tornado 6.1 tqdm 4.62.3 traitlets 5.1.1 tweedledum 1.1.1 types-Jinja2 2.11.9 types-MarkupSafe 1.1.10 types-pkg-resources 0.1.3 typing-extensions 3.10.0.2 urllib3 1.26.8 wcwidth 0.2.5 webencodings 0.5.1 websocket-client 1.2.3 wheel 0.37.1 widgetsnbextension 3.5.2 zipp 3.7.0

Here is my code that created the error in the last line when trying to evaluate the expectation value of the folded circuit using qiskit.

import pylab import qiskit import numpy as np from qiskit import Aer, BasicAer from qiskit.compiler import transpile from qiskit.opflow import X, Z, I, Y, StateFn, CircuitStateFn, SummedOp, PauliExpectation, CircuitSampler from qiskit.quantum_info.operators import Operator, Pauli from qiskit.utils import QuantumInstance, algorithm_globals from qiskit.algorithms import VQE, NumPyMinimumEigensolver from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.algorithms.optimizers import COBYLA, L_BFGS_B, SLSQP from qiskit.circuit.library import TwoLocal from mitiq.interface.mitiq_qiskit.qiskit_utils import initialized_depolarizing_noise from qiskit.circuit import Parameter from mitiq.zne import mitigate_executor from mitiq.zne.inference import RichardsonFactory from mitiq import zne from mitiq.zne.scaling.folding import fold_gates_from_left, fold_gates_from_right from scipy.optimize import minimize, minimize_scalar

H2_op = (-1.052373245772859 I ^ I) + (0.39793742484318045 I ^ Z) + (-0.39793742484318045 Z ^ I) + \ (-0.01128010425623538 Z ^ Z) + (0.18093119978423156 * X ^ X)

def trial_circuit(parameter): circuit=QuantumCircuit(2) circuit.ry(parameter[0],0) circuit.ry(parameter[1],1) circuit.cz(0,1) circuit.ry(parameter[2],0) circuit.ry(parameter[3],1) return circuit

scale_factors = [1., 1.5, 2., 2.5, 3.] folded_circuits = [ zne.scaling.fold_gates_at_random(trial_circuit([0,0,0,0]), scale) for scale in scale_factors ]

def qiskit_executor_no_noise(circuit: qiskit.QuantumCircuit, shots: int = 8192) -> float: quantum_instance = QuantumInstance(backend=Aer.get_backend('qasm_simulator'), shots=20000) psi = CircuitStateFn(circuit) value_list = [] for i in range(0,len(H2_op),1): measurable_expression = StateFn(H2_op[i], is_measurement=True).compose(psi) expectation = PauliExpectation().convert(measurable_expression) sampler = CircuitSampler(quantum_instance).convert(expectation) value = sampler.eval().real value_list.append(value) return value_list

qiskit_executor_no_noise(trial_circuit([0,0,0,0]))

qiskit_executor_no_noise(folded_circuits[0])

Aaron-Robertson commented 2 years ago

@anhdpham I see! I reproduced the error with qiskit>=0.34. Official mitiq support (currently) is qiskit~=0.32.1, and your code block passes when using that version (and latest mitiq==0.13). We strive to support the latest frontend versions, and I'll make sure that version support is better documented, but in the meantime you may want to try an older release.

anhdpham commented 2 years ago

@Aaron-Robertson Thanks. Will retest the program using a qiskit=0.32.1

Aaron-Robertson commented 2 years ago

Closing with documentation issue noted in #1201