How do I use LRE?#
LRE works in two main stages: generate noise-scaled circuits via layerwise scaling, and apply inference to resulting measurements post-execution.
This workflow can be executed by a single call to execute_with_lre()
.
If more control is needed over the protocol, Mitiq provides multivariate_layer_scaling()
and multivariate_richardson_coefficients()
to handle the first and second steps respectively.
Problem Setup#
To demonstrate the use of LRE, we’ll first define a quantum circuit, and a method of executing circuits for demonstration purposes.
For simplicity, we define a circuit whose unitary compiles to the identity operation. Here we will use a randomized benchmarking circuit on a single qubit, visualized below.
from mitiq import benchmarks
circuit = benchmarks.generate_rb_circuits(n_qubits=1, num_cliffords=3)[0]
print(circuit)
0: ───X^-0.5───Y^-0.5───Y^-0.5───X^0.5───Y^0.5───Y───I───(Z-Y^-0.5)───
We define an executor which simulates the input circuit subjected to depolarizing noise, and returns the probability of measuring the ground state.
By altering the value for noise_level
, ideal and noisy expectation values can be obtained.
from cirq import DensityMatrixSimulator, depolarize
def execute(circuit, noise_level=0.025):
noisy_circuit = circuit.with_noise(depolarize(p=noise_level))
rho = DensityMatrixSimulator().simulate(noisy_circuit).final_density_matrix
return rho[0, 0].real
Compare the noisy and ideal expectation values:
noisy = execute(circuit)
ideal = execute(circuit, noise_level=0.0)
print(f"Error without mitigation: {abs(ideal - noisy) :.5f}")
Error without mitigation: 0.11877
Apply LRE directly#
With the circuit and executor defined, we just need to choose the polynomial extrapolation degree as well as the fold multiplier.
from mitiq.lre import execute_with_lre
degree = 2
fold_multiplier = 3
mitigated = execute_with_lre(
circuit,
execute,
degree=degree,
fold_multiplier=fold_multiplier,
)
print(f"Error with mitigation (LRE): {abs(ideal - mitigated):.{3}}")
Error with mitigation (LRE): 0.00513
As you can see, the technique is extremely simple to apply, and no knowledge of the hardware/simulator noise is required.
Step by step application of LRE#
In this section we demonstrate the use of multivariate_layer_scaling()
and multivariate_richardson_coefficients()
for those who might want to inspect the intermediary circuits, and have more control over the protocol.
Create noise-scaled circuits#
We start by creating a number of noise-scaled circuits which we will pass to the executor.
from mitiq.lre.multivariate_scaling import multivariate_layer_scaling
noise_scaled_circuits = multivariate_layer_scaling(circuit, degree, fold_multiplier)
num_scaled_circuits = len(noise_scaled_circuits)
print(f"total number of noise-scaled circuits for LRE = {num_scaled_circuits}")
print(
f"Average circuit depth = {sum(len(circuit) for circuit in noise_scaled_circuits) / num_scaled_circuits}"
)
total number of noise-scaled circuits for LRE = 45
Average circuit depth = 18.666666666666668
As you can see, the noise scaled circuits are on average much longer than the original circuit. An example noise-scaled circuit is shown below.
noise_scaled_circuits[3]
0: ───X^-0.5───Y^-0.5───Y^-0.5───Y^0.5───Y^-0.5───Y^0.5───Y^-0.5───Y^0.5───Y^-0.5───X^0.5───Y^0.5───Y───I───(Z-Y^-0.5)───
With the many noise-scaled circuits in hand, we can run them through our executor to obtain the expectation values.
noise_scaled_exp_values = [
execute(circuit) for circuit in noise_scaled_circuits
]
Classical inference#
The penultimate step here is to fetch the coefficients we’ll use to combine the noisy data we obtained above.
The astute reader will note that we haven’t defined or used a degree
or fold_multiplier
parameter, and this is where they are both needed.
from mitiq.lre.inference import multivariate_richardson_coefficients
coefficients = multivariate_richardson_coefficients(
circuit,
fold_multiplier=fold_multiplier,
degree=degree,
)
Each noise scaled circuit has a coefficient of linear combination and a noisy expectation value associated with it.
Combine the results#
mitigated = sum(
exp_val * coeff
for exp_val, coeff in zip(noise_scaled_exp_values, coefficients)
)
print(f"Error with mitigation (LRE): {abs(ideal - mitigated):.{3}}")
Error with mitigation (LRE): 0.00513
As you can see we again see a nice improvement in the accuracy using a two stage application of LRE.