Clifford data regression API

This example shows how to use Clifford data regression (CDR) by means of a simple example.

import warnings
warnings.filterwarnings("ignore")

import numpy as np

import cirq
from mitiq import cdr, Observable, PauliString

Setup

To use CDR, we call cdr.execute_with_cdr with four “ingredients”:

  1. A quantum circuit to prepare a state \(\rho\).

  2. A quantum computer or noisy simulator to return a mitiq.QuantumResult from \(\rho\).

  3. An observable \(O\) which specifies what we wish to compute via \(\text{Tr} [ \rho O ]\).

  4. A near-Clifford (classical) circuit simulator.

(1) Circuit

The circuit can be specified as any quantum circuit supported by Mitiq but must be compiled into the gateset \(\{ \sqrt{X}, Z, \text{CNOT}\}\).

a, b = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
    cirq.rx(0.1).on(a),
    cirq.rx(-0.72).on(b),
    cirq.rz(0.4).on(a),
    cirq.rz(0.2).on(b),
    cirq.CNOT.on(a, b),
    cirq.rx(-0.1).on(b),
    cirq.rz(-0.23).on(a),
    cirq.CNOT.on(b, a),
    cirq.rx(-0.112).on(a),
)
circuit
0: ───Rx(0.032π)────Rz(0.127π)───@───Rz(-0.073π)───X───Rx(-0.036π)───
                                 │                 │
1: ───Rx(-0.229π)───Rz(0.064π)───X───Rx(-0.032π)───@─────────────────

(2) Executor

The executor inputs a circuit and returns a mitiq.QuantumResult. Typically this function will send the circuit to a quantum computer and wait for the results. 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)
array([[ 0.842+0.j   , -0.012+0.043j,  0.016-0.053j, -0.06 -0.344j],
       [-0.012-0.043j,  0.005+0.j   , -0.003-0.j   , -0.017+0.008j],
       [ 0.016+0.053j, -0.003+0.j   ,  0.007-0.j   ,  0.02 -0.011j],
       [-0.06 +0.344j, -0.017-0.008j,  0.02 +0.011j,  0.146-0.j   ]],
      dtype=complex64)

(3) Observable

The observables \(O\) indicates what we wish to compute via \(\text{Tr} [ \rho O ]\).

# Observable to measure.
obs = Observable(PauliString("ZZ"), PauliString("X", coeff=-1.75))
print(obs)
Z(0)*Z(1) + (-1.75+0j)*X(0)

(4) (Near-clifford) Simulator

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)
array([[ 0.836-0.j   , -0.013+0.045j,  0.017-0.053j, -0.062-0.357j],
       [-0.013-0.045j,  0.003-0.j   , -0.003-0.j   , -0.018+0.009j],
       [ 0.017+0.053j, -0.003+0.j   ,  0.004+0.j   ,  0.021-0.011j],
       [-0.062+0.357j, -0.018-0.009j,  0.021+0.011j,  0.157+0.j   ]],
      dtype=complex64)

Results

Now we can run CDR. We first compute the noiseless result then the noisy result to compare to the mitigated result from CDR.

The noiseless result

obs.expectation(circuit, simulate).real
0.9912016373127699

The noisy result

obs.expectation(circuit, compute_density_matrix).real
0.9796480312943459

The mitigated result

cdr.execute_with_cdr(
    circuit,
    compute_density_matrix,
    observable=obs,
    simulator=simulate,
).real
0.9912016373127699

Additional options

In addition to the four necessary arguments shown above, there are additional parameters in CDR.

Training circuits

One option is how many circuits are in the training set (default is 10). This can be changed as follows.

cdr.execute_with_cdr(
    circuit,
    compute_density_matrix,
    observable=obs,
    simulator=simulate,
    num_training_circuits=20,
).real
0.9912016373127699

Another option is which fit function to use for regresstion (default is cdr.linear_fit_function).

Fit function

cdr.execute_with_cdr(
    circuit,
    compute_density_matrix,
    observable=obs,
    simulator=simulate,
    fit_function=cdr.linear_fit_function_no_intercept,
).real
0.9912016373127698

Variable noise CDR

The circuit + training circuits can also be run at different noise scale factors to implement variable noise Clifford data regression.

from mitiq.zne import scaling

cdr.execute_with_cdr(
    circuit,
    compute_density_matrix,
    observable=obs,
    simulator=simulate,
    scale_factors=(3,),
).real
0.9912018934264779