Calibration#

The mitiq.Calibrator class provides a workflow for users to run a set of experiments to automatically determine an error mitigation strategy. This gives the user freedom to work on more important parts of their algorithm/quantum program, and allows them to spend less time tuning error mitigation parameters.

Workflow#

To begin, we will need to define an executor which tells Mitiq how to run circuits. In order to use the calibration capabilities of Mitiq, we will need to define an executor which returns all the measured bitstrings, rather than an expectation value. This allows the calibration experiment to extract more fine-grained data from each circuit experiment it will run

import cirq
import numpy as np
from mitiq import MeasurementResult
def execute(circuit, noise_level=0.001):
    circuit = circuit.with_noise(cirq.amplitude_damp(noise_level))
    result = cirq.DensityMatrixSimulator().run(circuit, repetitions=100)
    bitstrings = np.column_stack(list(result.measurements.values()))
    return MeasurementResult(bitstrings)

We can now import the required objects and functions required for calibration.

from mitiq import Calibrator

To instantiate a Calibrator we need to pass it an executor (as defined above), and a Settings object. You are free to define your own Settings, but as a simple starting point, we provide ZNE_SETTINGS based on different zero-noise extrapolation strategies and PEC_SETTINGS based on different quasiprobability representations of ideal gates. Finally, the execute_with_mitigation function allows us to pass the calibration results directly to Mitiq and have it pick the strategy that performed best of those supplied in the Settings object.

Calibration Experiments#

Before running any experiments, we can call the get_cost function to ensure the experiments will not be too costly. Once instantiated, we call the run method to run the set of experiments, and the results of such experiments are stored internal to the class in cal.results.

cal = Calibrator(execute, frontend="cirq")
print(cal.get_cost())
cal.run()
{'noisy_executions': 100, 'ideal_executions': 0}

Verbose Log Output#

To print results from the experiments the calibrator performs, the log parameter can be passed in to the run method with either the value of flat or cartesian. By using the log parameter, detailed information about each experiment is printed when the run method completes.

The detailed information can also be generated from the results of the calibrator after run is called by calling either log_results_flat() or log_results_cartesian().

The two options display the information in different formats, though both use a cross (✘) or a check (✔) to signal whether the error mitigation expirement obtained an expectation value better than the non-mitigated one.

# cal.results.log_results_flat()
cal.results.log_results_cartesian()
┌────────────────────────────────────┬────────────────────────────┬───────────────────────────┬────────────────────────────┬────────────────────────────┐
│ strategy\benchmark                 │ Type: ghz                  │ Type: w                   │ Type: rb                   │ Type: mirror               │
│                                    │ Num qubits: 2              │ Num qubits: 2             │ Num qubits: 2              │ Num qubits: 2              │
│                                    │ Circuit depth: 2           │ Circuit depth: 2          │ Circuit depth: 46          │ Circuit depth: 33          │
│                                    │ Two qubit gate count: 1    │ Two qubit gate count: 2   │ Two qubit gate count: 11   │ Two qubit gate count: 14   │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✘                          │ ✘                         │ ✘                          │ ✘                          │
│ Factory: Richardson                │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 2.0, 3.0       │ Mitigated error: 0.28      │ Mitigated error: 0.5      │ Mitigated error: 0.11      │ Mitigated error: 0.04      │
│ Scale method: fold_global          │ Improvement factor: 0.1429 │ Improvement factor: 1.0   │ Improvement factor: 0.2727 │ Improvement factor: 0.25   │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✔                          │ ✘                         │ ✔                          │ ✔                          │
│ Factory: Richardson                │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 3.0, 5.0       │ Mitigated error: 0.0075    │ Mitigated error: 0.5      │ Mitigated error: 0.0138    │ Mitigated error: 0.0075    │
│ Scale method: fold_global          │ Improvement factor: 5.3333 │ Improvement factor: 1.0   │ Improvement factor: 2.1818 │ Improvement factor: 1.3333 │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✘                          │ ✘                         │ ✔                          │ ✔                          │
│ Factory: Linear                    │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 2.0, 3.0       │ Mitigated error: 0.0467    │ Mitigated error: 0.5      │ Mitigated error: 0.0033    │ Mitigated error: 0.0067    │
│ Scale method: fold_global          │ Improvement factor: 0.8571 │ Improvement factor: 1.0   │ Improvement factor: 9.0    │ Improvement factor: 1.5    │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✔                          │ ✘                         │ ✔                          │ ✘                          │
│ Factory: Linear                    │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 3.0, 5.0       │ Mitigated error: 0.0117    │ Mitigated error: 0.5      │ Mitigated error: 0.0125    │ Mitigated error: 0.0225    │
│ Scale method: fold_global          │ Improvement factor: 3.4286 │ Improvement factor: 1.0   │ Improvement factor: 2.4    │ Improvement factor: 0.4444 │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✘                          │ ✘                         │ ✘                          │ ✘                          │
│ Factory: Richardson                │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 2.0, 3.0       │ Mitigated error: 0.15      │ Mitigated error: 0.5      │ Mitigated error: 0.12      │ Mitigated error: 0.06      │
│ Scale method: fold_gates_at_random │ Improvement factor: 0.2667 │ Improvement factor: 1.0   │ Improvement factor: 0.25   │ Improvement factor: 0.1667 │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✘                          │ ✘                         │ ✘                          │ ✘                          │
│ Factory: Richardson                │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 3.0, 5.0       │ Mitigated error: 0.2775    │ Mitigated error: 0.5      │ Mitigated error: 0.0337    │ Mitigated error: 0.0125    │
│ Scale method: fold_gates_at_random │ Improvement factor: 0.1441 │ Improvement factor: 1.0   │ Improvement factor: 0.8889 │ Improvement factor: 0.8    │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✔                          │ ✘                         │ ✔                          │ ✘                          │
│ Factory: Linear                    │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 2.0, 3.0       │ Mitigated error: 0.0033    │ Mitigated error: 0.5      │ Mitigated error: 0.0233    │ Mitigated error: 0.0233    │
│ Scale method: fold_gates_at_random │ Improvement factor: 12.0   │ Improvement factor: 1.0   │ Improvement factor: 1.2857 │ Improvement factor: 0.4286 │
├────────────────────────────────────┼────────────────────────────┼───────────────────────────┼────────────────────────────┼────────────────────────────┤
│ Technique: ZNE                     │ ✔                          │ ✘                         │ ✔                          │ ✘                          │
│ Factory: Linear                    │ Noisy error: 0.04          │ Noisy error: 0.5          │ Noisy error: 0.03          │ Noisy error: 0.01          │
│ Scale factors: 1.0, 3.0, 5.0       │ Mitigated error: 0.0133    │ Mitigated error: 0.5      │ Mitigated error: 0.0042    │ Mitigated error: 0.0183    │
│ Scale method: fold_gates_at_random │ Improvement factor: 3.0    │ Improvement factor: 1.0   │ Improvement factor: 7.2    │ Improvement factor: 0.5455 │
└────────────────────────────────────┴────────────────────────────┴───────────────────────────┴────────────────────────────┴────────────────────────────┘

Applying the optimal error mitigation strategy#

We first define randomized benchmarking circuit to test the effect of error mitigation.

from mitiq.benchmarks import generate_rb_circuits

circuit = generate_rb_circuits(2, 10)[0]
# circuits passed to an executor returning bitstrings must contain measurements
circuit.append(cirq.measure(circuit.all_qubits()))

Instead of deciding what error mitigation technique and what options to use, we can ask Mitiq to determine the optimal error mitigation strategy based on the previously performed calibration. We can obtain this by calling the execute_with_mitigation function and passing the circuit, Calibrator object, and a new expectation value executor.

def execute(circuit, noise_level=0.001):
    circuit = circuit.with_noise(cirq.amplitude_damp(noise_level))

    rho = (
        cirq.DensityMatrixSimulator()
        .simulate(circuit)
        .final_density_matrix
    )
    return rho[0, 0].real

cal.execute_with_mitigation(circuit, execute)
1.000000789761543

Tutorial#

You can find an example on quantum error mitigation calibration in the Examples section of the documentation. This example illustrates functionalities from the calibration module using ZNE on a simulated IBM Quantum backend using Qiskit, defining a new settings object.