jupytext | kernelspec | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Here we show how to use CDR by means of a simple example.
import numpy as np
import warnings
warnings.simplefilter("ignore", np.ComplexWarning)
import cirq
from mitiq import cdr, Observable, PauliString
To use CDR, we call {func}.cdr.execute_with_cdr
with four "ingredients":
- A quantum circuit to prepare a state
$\rho$ . - A quantum computer or noisy simulator to return a {class}
.QuantumResult
from$\rho$ . - An observable
$O$ which specifies what we wish to compute via$\text{Tr} [ \rho O ]$ . - A near-Clifford (classical) circuit simulator.
+++
The quantum circuit can be specified as any quantum circuit supported by Mitiq but
must be compiled into a gateset in which the only non-Clifford gates are
single-qubit rotations around the
In the next cell we define (as an example) a quantum circuit which contains some
Clifford gates and some non-Clifford
a, b = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.H.on(a), # Clifford
cirq.H.on(b), # Clifford
cirq.rz(1.75).on(a),
cirq.rz(2.31).on(b),
cirq.CNOT.on(a, b), # Clifford
cirq.rz(-1.17).on(b),
cirq.rz(3.23).on(a),
cirq.rx(np.pi / 2).on(a), # Clifford
cirq.rx(np.pi / 2).on(b), # Clifford
)
# CDR works better if the circuit is not too short. So we increase its depth.
circuit = 5 * circuit
We define an executor function which inputs a circuit and returns a {class}.QuantumResult
. Here for sake of example we use a simulator that adds single-qubit depolarizing noise after each moment and returns the final density matrix.
from mitiq.interface.mitiq_cirq import compute_density_matrix
compute_density_matrix(circuit).round(3)
As an example, assume that we wish to compute the expectation value
# Observable to measure.
obs = Observable(PauliString("ZZ"), PauliString("X", coeff=-1.75))
print(obs)
Note: To apply CDR the {class}Observable
should be Hermitian, i.e., it should always produce real expectation values.
+++
You can read more about the {class}Observable
class in the documentation.
+++
The CDR method creates a set of "training circuits" which are related to the input circuit and are efficiently simulable. These circuits are simulated on a classical (noiseless) simulator to collect data for regression. The simulator should also return a QuantumResult
.
To use CDR at scale, an efficient near-Clifford circuit simulator must be specified. In this example, the circuit is small enough to use any classical simulator, and we use the same density matrix simulator as above but without noise.
def simulate(circuit: cirq.Circuit) -> np.ndarray:
return compute_density_matrix(circuit, noise_level=(0.0,))
simulate(circuit).round(3)
Now we can run CDR. We first compute the noiseless result then the noisy result to compare to the mitigated result from CDR.
+++
ideal_measurement = obs.expectation(circuit, simulate).real
print("ideal_measurement = ",ideal_measurement)
We now generate the noisy result. Note that {func}.compute_density_matrix
function by default runs a simulation with noise.
unmitigated_measurement = obs.expectation(circuit, compute_density_matrix).real
print("unmitigated_measurement = ", unmitigated_measurement)
mitigated_measurement = cdr.execute_with_cdr(
circuit,
compute_density_matrix,
observable=obs,
simulator=simulate,
seed=0,
).real
print("mitigated_measurement = ", mitigated_measurement)
error_unmitigated = abs(unmitigated_measurement-ideal_measurement)
error_mitigated = abs(mitigated_measurement-ideal_measurement)
print("Error (unmitigated):", error_unmitigated)
print("Error (mitigated with CDR):", error_mitigated)
print("Relative error (unmitigated):", (error_unmitigated/ideal_measurement))
print("Relative error (mitigated with CDR):", error_mitigated/ideal_measurement)
print(f"Error reduction with CDR: {(error_unmitigated-error_mitigated)/error_unmitigated :.1%}.")