How do I use DDD?#

Digital Dynamical Decoupling (DDD) is an error mitigation technique in which sequences of gates are applied to slack windows, i.e. single-qubit idle windows, in a quantum circuit. Such sequences of gates can reduce the coupling between the qubits and the environment, mitigating the effects of noise. For more discussion of the theory of DDD, see the section What is the theory behind DDD?.

As with all techniques, DDD is compatible with any frontend supported by Mitiq:

import mitiq 

mitiq.SUPPORTED_PROGRAM_TYPES.keys()
dict_keys(['cirq', 'pyquil', 'qiskit', 'braket', 'pennylane'])

Problem setup#

We first define the circuit of interest. In this example, the circuit has a slack window with a length of 4 (in the sense that 4 single-qubit gates can fit in that window).

from cirq import LineQubit, Circuit, rx, rz, CNOT

a, b = LineQubit.range(2)
circuit = Circuit(
    rx(0.1).on(a),
    rx(0.1).on(a),
    rz(0.4).on(a),
    rx(-0.72).on(a),
    rz(0.2).on(a),
    rx(-0.8).on(b),
    CNOT.on(a, b),
)

print(circuit)
0: ───Rx(0.032π)────Rx(0.032π)───Rz(0.127π)───Rx(-0.229π)───Rz(0.064π)───@───
                                                                         │
1: ───Rx(-0.255π)────────────────────────────────────────────────────────X───

Next we define a simple executor function which inputs a circuit, executes the circuit on a noisy simulator, and returns the probability of the ground state. See the Executors section for more information on how to define more advanced executors.

import numpy as np
from cirq import DensityMatrixSimulator, amplitude_damp
from mitiq.interface import convert_to_mitiq

def execute(circuit, noise_level=0.1):
    """Returns Tr[ρ |0⟩⟨0|] where ρ is the state prepared by the circuit
    executed with amplitude damping noise.
    """
    # Replace with code based on your frontend and backend.
    mitiq_circuit, _ = convert_to_mitiq(circuit)
    noisy_circuit = mitiq_circuit.with_noise(amplitude_damp(gamma=noise_level))
    rho = DensityMatrixSimulator().simulate(noisy_circuit).final_density_matrix
    return rho[0, 0].real

The executor can be used to evaluate noisy (unmitigated) expectation values.

# Compute the expectation value of the |0><0| observable.
noisy_value = execute(circuit)
ideal_value = execute(circuit, noise_level=0.0)      
print(f"Error without mitigation: {abs(ideal_value - noisy_value) :.3}")
Error without mitigation: 0.0753

Select the DDD sequences to be applied#

We now import a DDD rule from Mitiq, i. e., a function that generates DDD sequences of different length. In this example, we opt for YY sequences (pairs of Pauli Y operations).

from mitiq import ddd

rule = ddd.rules.yy

Apply DDD#

Digital dynamical decoupling can be easily implemented with the function execute_with_ddd().

mitigated_result = ddd.execute_with_ddd(
    circuit=circuit, 
    executor=execute, 
    rule=rule,
)
print(f"Error with mitigation (DDD): {abs(ideal_value - mitigated_result) :.3}")
Error with mitigation (DDD): 0.00743

Here we observe that the application of DDD reduces the estimation error when compared to the unmitigated result.

Note:

DDD is designed to mitigate noise that has a finite correlation time. For the simple Markovian noise simulated in this example, DDD can still have a non-trivial effect on the final error, but it is not always a positive effect. For example, one can check that by changing the parameters of the input circuit, the error with DDD is sometimes larger than the unmitigated error.

The section What additional options are available when using DDD? contains information on more advanced ways of applying DDD with Mitiq.