# 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.9919966383227776


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.9925065107380328


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.9796387773266263


### 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.9998940640520744