Utility functions

There are a couple of functionalities that are needed for easy mitigation, but are not part of the Qiskit SDK and thus are included in M3. Each is detailed below.

Final-measurement mapping

We have already seen the mthree.utils.final_measurement_mapping() routine in the section on detailing with Transpiled circuits, where the addition of SWAP gates made it difficult to determine exactly which physical qubits are being used, and which classical bits they correspond to. Here we show another example of this usage. First we start with a 7-qubit GHZ state:

from qiskit import *
from qiskit_ibm_runtime.fake_provider import FakeCasablancaV2
import mthree

qc = QuantumCircuit(7)
qc.h(0)
qc.cx(0, range(1,7))
qc.measure_all()
qc.draw('mpl')
_images/utils_0_0.png

and then transpile it:

backend = FakeCasablancaV2()
trans_qc = transpile(qc, backend, optimization_level=3, seed_transpiler=54321)
trans_qc.draw('mpl')
_images/utils_1_0.png

Once again we see that the physical qubits used and to which classical bits they map to is non-trivial to find. Yet this information is critical for successfully mitigating the results. This is where the mthree.utils.final_measurement_mapping() plays a critical role:

mapping = mthree.utils.final_measurement_mapping(trans_qc)
mapping
{0: 5, 1: 0, 2: 2, 3: 3, 4: 1, 5: 4, 6: 6}

The keys of this mapping index the classical bits, whereas the values tell you which qubits were measured to obtain the bit values. The mapping is ordered in terms of the classical bit indices. You can just pass the generated mapping into M3 functions.

Evaluating raw counts data

When mitigating results one often wants to know how much better the results are with mitigation compared to without. However, Qiskit does not have great support for computing things like expectation values. So M3 includes the generic functions mthree.utils.expval(), mthree.utils.stddev(), and mthree.utils.expval_and_stddev() that operate on the native Counts objects in Qiskit.

For example let us compare raw data verse the mitigated results in a simple case.

from qiskit_ibm_runtime.fake_provider import FakeAthensV2
backend = FakeAthensV2()
qc = QuantumCircuit(4)
qc.h(2)
qc.cx(2, 1)
qc.cx(2, 3)
qc.cx(1, 0)
qc.measure_all()

raw_counts = backend.run(qc).result().get_counts()
mit = mthree.M3Mitigation(backend)
mit.cals_from_system()
mit_counts = mit.apply_correction(raw_counts, qubits=range(4),
                                  return_mitigation_overhead=True)

print('Raw counts expval', mthree.utils.expval(raw_counts))
print('Mitigated expval', mit_counts.expval())
Raw counts expval 0.8378906
Mitigated expval 0.9542639851570129

We can also compare things like upper-bounds on the standard deviation:

print('Raw counts uncertainty', mthree.utils.stddev(raw_counts))
print('Mitigated uncertainty', mit_counts.stddev())
Raw counts uncertainty 0.03125
Mitigated uncertainty 0.038387565292661976

where the uncertainty for the raw Counts data is just \(1/\sqrt{\rm{shots}}\).

These convenence functions work in the same manner as the methods for the distribution classes mthree.classes.QuasiDistribution and mthree.classes.ProbDistribution and collections mthree.classes.QuasiCollection and mthree.classes.ProbCollection. That is to say that, for example, I can pass operators to expval function:

print('These should be equal:', mthree.utils.expval(raw_counts, 'IIII'),
      mit_counts.expval('IIII'))
These should be equal: 1.0 0.9999998807907104

The routines also allow you to pass the native M3 distributions and collections. E.g.

print(mthree.utils.expval(mit_counts), mit_counts.expval())
0.954264 0.9542639851570129

Finally we note that you can pass multiple values at the same time. Here we run and mitigate 5 circuits:

raw_counts = backend.run([qc]*5).result().get_counts()
mit = mthree.M3Mitigation(backend)
mit.cals_from_system()
mit_counts = mit.apply_correction(raw_counts, qubits=range(4),
                                  return_mitigation_overhead=True)


print('Raw counts expval', mthree.utils.expval(raw_counts))
print('Mitigated expval', mit_counts.expval())
Raw counts expval [0.8222656 0.8359375 0.8183594 0.8535156 0.8417969]
Mitigated expval [0.93866026 0.9571036  0.92995524 0.9757097  0.9604602 ]