qiskit-ignis
qiskit-ignis copied to clipboard
QPT fitter should marginalize counts over measured qubits
Informations
- Qiskit Ignis version: master
- Python version: 3.7.1
- Operating system: macOS Mojave
What is the current behavior?
ProcessTomographyFitter.fit()
gives an array with NaNs, because the counts dictionary is not marginalized.
Steps to reproduce the problem
Do something like:
qpt_tomo = q.ignis.verification.tomography.ProcessTomographyFitter(job.result(), qpt_circs)
choi_lstsq = qpt_tomo.fit(method='lstsq')
on a device that does not return pre-marginalized counts (maybe this is only on OpenPulse interfaces).
What is the expected behavior?
Should give a choi matrix that can be plotted as a state city.
Suggested solutions
Something like, in qiskit/ignis/verification/tomography/fitters/base_fitter.py:TomographyFitter._fitter_data, add
cts = qiskit.ignis.verification.tomography.data.marginal_counts(cts, meas_qubits=meas_qubits)
on the first line of the for
loop. This would require propogating the measured qubits to this function somehow though...
because the counts dictionary is not marginalized.
Could you explain what you mean here with an example?
@chriseclectic wasn't there a marginal counts in terra? I can't seem to find it
@chriseclectic wasn't there a marginal counts in terra? I can't seem to find it
I think that the plan is to move the code of marginal_counts from tomography to terra (qiskit.tools), see: https://github.com/Qiskit/qiskit-ignis/blob/master/qiskit/ignis/verification/tomography/init.py
@dcmckayibm sorry about the delay, I'll make a code snippet to reproduce, but will be a few days. Thanks!
Here is a code snippet to reproduce. It's the smallest one I could come up with:
import qiskit as q
provider = ...
backend = provider.get_backend('ibmq_johannesburg')
defaults = backend.defaults()
circ_inst_map = defaults.circuit_instruction_map
pulse_gate = q.circuit.Gate(name='pulse_gate', num_qubits=1, params=[])
circ_inst_map.add('pulse_gate', qubits=[0], schedule=q.pulse.Schedule()) # pulse_gate does nothing
qreg = q.QuantumRegister(1)
circ = q.QuantumCircuit(qreg)
_ = circ.append(pulse_gate, [0], [])
basis_gates = backend.configuration().basis_gates
basis_gates.append('pulse_gate')
qpt_circs = q.ignis.verification.tomography.process_tomography_circuits(
circ, prepared_qubits=[qreg[0]], measured_qubits=[qreg[0]])
qpt_circs = [q.transpile(qpt_circ, backend=backend, basis_gates=basis_gates) for qpt_circ in qpt_circs]
qpt_schedules = [q.schedule(qpt_circ, inst_map=circ_inst_map, backend=backend) for qpt_circ in qpt_circs]
job = q.execute(qpt_schedules, backend=backend, shots=100)
qpt_tomo = q.ignis.verification.tomography.ProcessTomographyFitter(job.result(), qpt_circs)
choi_lstsq = qpt_tomo.fit(method='lstsq')
and stacktrace for the last line:
~/Developer/qiskit/qiskit-ignis/qiskit/ignis/verification/tomography/fitters/base_fitter.py:292: RuntimeWarning: invalid value encountered in true_divide
probs = np.array(cts) / shots
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-13-cab92b209680> in <module>
----> 1 choi_lstsq = qpt_tomo.fit(method='lstsq')
~/Developer/qiskit/qiskit-ignis/qiskit/ignis/verification/tomography/fitters/process_fitter.py in fit(self, method, standard_weights, beta, **kwargs)
137 if method == 'lstsq':
138 return Choi(lstsq_fit(data, basis_matrix, weights=weights,
--> 139 trace=dim, **kwargs))
140 if method == 'cvx':
141 return Choi(cvx_fit(data, basis_matrix, weights=weights, trace=dim,
~/Developer/qiskit/qiskit-ignis/qiskit/ignis/verification/tomography/fitters/lstsq_fit.py in lstsq_fit(data, basis_matrix, weights, PSD, trace)
89
90 # Perform least squares fit using Scipy.linalg lstsq function
---> 91 rho_fit, _, _, _ = lstsq(a, b)
92
93 # Reshape fit to a density matrix
~/anaconda3/envs/QiskitDevenv/lib/python3.7/site-packages/scipy/linalg/basic.py in lstsq(a, b, cond, overwrite_a, overwrite_b, check_finite, lapack_driver)
1151 """
1152 a1 = _asarray_validated(a, check_finite=check_finite)
-> 1153 b1 = _asarray_validated(b, check_finite=check_finite)
1154 if len(a1.shape) != 2:
1155 raise ValueError('Input array a should be 2-D')
~/anaconda3/envs/QiskitDevenv/lib/python3.7/site-packages/scipy/_lib/_util.py in _asarray_validated(a, check_finite, sparse_ok, objects_ok, mask_ok, as_inexact)
237 raise ValueError('masked arrays are not supported')
238 toarray = np.asarray_chkfinite if check_finite else np.asarray
--> 239 a = toarray(a)
240 if not objects_ok:
241 if a.dtype is np.dtype('O'):
~/anaconda3/envs/QiskitDevenv/lib/python3.7/site-packages/numpy/lib/function_base.py in asarray_chkfinite(a, dtype, order)
494 if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
495 raise ValueError(
--> 496 "array must not contain infs or NaNs")
497 return a
498
ValueError: array must not contain infs or NaNs
The error is confusing, but the root cause is that OpenPulse jobs return measurement outcomes over all device qubits, not just the one that we are explicitly measuring. So for example, job.result().get_counts(i)
returns a dictionary where the keys are 20-long-bitstrings, which in turn messes up qiskit-ignis/qiskit/ignis/verification/tomography/fitters/base_fitter.py:_fitter_data
Perhaps the most correct fix is to change this behavior on OpenPulse backends--i.e. only return measurement outcomes over the qubits that are explicitly measured.
I can fix this problem locally in tomography by explicitly marginalizing if the size of the returned result is not the same as the number of clbits, but this is really a hack and not a good one - this problem should be fixed in the OpenPulse backends, or (better, in my opinion) in the Result
object.
Seeing something that looks like this report with ValueError: array must not contain infs or NaNs. I've been comparing to IBM's tutorials and find some that work that look identical in syntax for the statement that fails (rho_fit_qc = tomo_fitter_qc.fit(method='lstsq'))...but it isn't working with my circuit/gate combination.
Version: Pycharm 2020.3.5, python 3.8, qiskit 0.28.0, qiskit-ignis 0.6.0
Here are the errors:
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/bin/python "/Users/juliegermain/Library/Application Support/JetBrains/PyCharmCE2020.3/scratches/EntSwap_withDensityMatrix.py"
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/lib/python3.8/site-packages/qiskit/ignis/verification/tomography/basis/circuits.py:468: DeprecationWarning: The QuantumCircuit.iadd() method is being deprecated. Use the compose() (potentially with the inplace=True argument) and tensor() methods which are more flexible w.r.t circuit register compatibility.
prep += circuit
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:942: DeprecationWarning: The QuantumCircuit.extend() method is being deprecated. Use the compose() (potentially with the inplace=True argument) and tensor() methods which are more flexible w.r.t circuit register compatibility.
return self.extend(rhs)
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/lib/python3.8/site-packages/qiskit/ignis/verification/tomography/basis/circuits.py:478: DeprecationWarning: The QuantumCircuit.add() method is being deprecated.Use the compose() method which is more flexible w.r.t circuit register compatibility.
circ = prep + meas
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:933: DeprecationWarning: The QuantumCircuit.combine() method is being deprecated. Use the compose() method which is more flexible w.r.t circuit register compatibility.
return self.combine(rhs)
/Users/juliegermain/opt/anaconda3/envs/QuantumResearch/lib/python3.8/site-packages/qiskit/ignis/verification/tomography/fitters/base_fitter.py:348: RuntimeWarning: invalid value encountered in true_divide
probs = np.array(cts) / shots
Time taken: 3.728592872619629
Traceback (most recent call last):
File "/Users/juliegermain/Library/Application Support/JetBrains/PyCharmCE2020.3/scratches/EntSwap_withDensityMatrix.py", line 93, in
Here is the code:
from qiskit import * from qiskit.visualization import plot_histogram from qiskit.providers.ibmq import least_busy from qiskit.tools.monitor import job_monitor import qiskit.quantum_info as qi
Tomography functions
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
import matplotlib.pyplot as plt import time #======================================= qA = QuantumRegister(1,'alice') qC1= QuantumRegister(1,'charlie1') qC2= QuantumRegister(1,'charlie2') qB = QuantumRegister(1,'bob') cr = ClassicalRegister(2)
qc = QuantumCircuit(qA,qC1,qC2,qB,cr)
for i in range(0,4): qc.reset(i)
Entangle 2 pair
qc.h(qC1) qc.h(qC2) qc.cx(qC1,qA) qc.cx(qC2,qB)
qc.barrier()
entangle one "arm" of a pair to the 2nd pair
qc.h(qA) qc.h(qC2) qc.cx(qC2,qA) qc.h(qA) qc.h(qC2)
qc.barrier()
entangle 2nd "arm" to the 2nd pair...no all 4 entangled
qc.h(qB) qc.h(qC1) qc.cx(qC1,qB) qc.h(qB) qc.h(qC1)
qc.barrier()
#============================================
Get ideal output state
ideal_state_qc = qi.Statevector.from_instruction(qc) #===========================================
Get Experimental density matrix (rho_qc)
Generate circuits and run on simulator
t = time.time() qst_qc = state_tomography_circuits(qc,(qA,qC1,qC2,qB)) job = qiskit.execute(qst_qc, Aer.get_backend('qasm_simulator'), shots=5000)
Fit result
tomo_fitter_qc = StateTomographyFitter(job.result(), qst_qc) print('Time taken:', time.time() - t)
t = time.time() rho_fit_qc = tomo_fitter_qc.fit(method='lstsq') # needed to calculate fidelity print('Time taken fit:', time.time() - t)
Calculate Fidelity
F_qc = qi.state_fidelity(rho_fit_qc, ideal_state_qc) print('State Fidelity: F = {:.5f}'.format(F_qc))