pyquil.noise module

Module for creating and verifying noisy gate and readout definitions.

pyquil.noise.INFINITY = inf

Used for infinite coherence times.

class pyquil.noise.KrausModel(gate, params, targets, kraus_ops, fidelity)[source]

Bases: _KrausModel

Encapsulate a single gate’s noise model.

Variables:
  • gate (str) – The name of the gate.

  • params (Sequence[float]) – Optional parameters for the gate.

  • targets (Sequence[int]) – The target qubit ids.

  • kraus_ops (Sequence[np.array]) – The Kraus operators (must be square complex numpy arrays).

  • fidelity (float) – The average gate fidelity associated with the Kraus map relative to the ideal operation.

Create new instance of _KrausModel(gate, params, targets, kraus_ops, fidelity)

static from_dict(d: dict[str, Any]) KrausModel[source]

Recreate a KrausModel from the dictionary representation.

Parameters:

d – The dictionary representing the KrausModel. See to_dict for an example.

Returns:

The deserialized KrausModel.

to_dict() dict[str, Any][source]

Create a dictionary representation of a KrausModel.

For example:

{
    "gate": "RX",
    "params": np.pi,
    "targets": [0],
    "kraus_ops": [  # In this example single Kraus op = ideal RX(pi) gate
        [
            [
                [0, 0],  # element-wise real part of matrix
                [0, 0],
            ],
            [
                [0, -1],  # element-wise imaginary part of matrix
                [-1, 0],
            ],
        ]
    ],
    "fidelity": 1.0,
}
Returns:

A JSON compatible dictionary representation.

Return type:

dict[str,Any]

static unpack_kraus_matrix(m: list[Any] | ndarray) ndarray[source]

Unpack a JSON compatible representation of a complex Kraus matrix.

Parameters:

m – The representation of a Kraus operator. Either a complex square matrix (as numpy array or nested lists) or a JSON-able pair of real matrices (as nested lists) representing the element-wise real and imaginary part of m.

Returns:

A complex square numpy array representing the Kraus operator.

class pyquil.noise.NoiseModel(gates, assignment_probs)[source]

Bases: _NoiseModel

Encapsulate the QPU noise model containing information about the noisy gates.

Variables:
  • gates (Sequence[KrausModel]) – The tomographic estimates of all gates.

  • assignment_probs (dict[int,np.array]) – The single qubit readout assignment probability matrices keyed by qubit id.

Create new instance of _NoiseModel(gates, assignment_probs)

static from_dict(d: dict[str, Any]) NoiseModel[source]

Re-create the noise model from a dictionary representation.

Parameters:

d – The dictionary representation.

Returns:

The restored noise model.

gates_by_name(name: str) list[KrausModel][source]

Return all defined noisy gates of a particular gate name.

Parameters:

name (str) – The gate name.

Returns:

A list of noise models representing that gate.

to_dict() dict[str, Any][source]

Create a JSON serializable representation of the noise model.

For example:

{
    "gates": [
        # list of embedded dictionary representations of KrausModels here [...]
    ]
    "assignment_probs": {
        "0": [[.8, .1],
              [.2, .9]],
        "1": [[.9, .4],
              [.1, .6]],
    }
}
Returns:

A dictionary representation of self.

exception pyquil.noise.NoisyGateUndefined[source]

Bases: Exception

Raise when user attempts to use noisy gate outside of currently supported set.

pyquil.noise.add_decoherence_noise(prog: Program, T1: dict[int, float] | float = 3e-05, T2: dict[int, float] | float = 3e-05, gate_time_1q: float = 5e-08, gate_time_2q: float = 1.5e-07, ro_fidelity: dict[int, float] | float = 0.95) Program[source]

Add generic damping and dephasing noise to a program.

This high-level function is provided as a convenience to investigate the effects of a generic noise model on a program. For more fine-grained control, please investigate the other methods available in the pyquil.noise module.

In an attempt to closely model the QPU, noisy versions of RX(+-pi/2) and CZ are provided; I and parametric RZ are noiseless, and other gates are not allowed. To use this function, you need to compile your program to this native gate set.

The default noise parameters

  • T1 = 30 us

  • T2 = 30 us

  • 1q gate time = 50 ns

  • 2q gate time = 150 ns

are currently typical for near-term devices.

This function will define new gates and add Kraus noise to these gates. It will translate the input program to use the noisy version of the gates.

Parameters:
  • prog – A pyquil program consisting of I, RZ, CZ, and RX(+-pi/2) instructions

  • T1 – The T1 amplitude damping time either globally or in a dictionary indexed by qubit id. By default, this is 30 us.

  • T2 – The T2 dephasing time either globally or in a dictionary indexed by qubit id. By default, this is also 30 us.

  • gate_time_1q – The duration of the one-qubit gates, namely RX(+pi/2) and RX(-pi/2). By default, this is 50 ns.

  • gate_time_2q – The duration of the two-qubit gates, namely CZ. By default, this is 150 ns.

  • ro_fidelity – The readout assignment fidelity \(F = (p(0|0) + p(1|1))/2\) either globally or in a dictionary indexed by qubit id.

Returns:

A new program with noisy operators.

pyquil.noise.append_kraus_to_gate(kraus_ops: Sequence[ndarray], gate_matrix: ndarray) list[number | ndarray][source]

Follow a gate gate_matrix by a Kraus map described by kraus_ops.

Parameters:
  • kraus_ops – The Kraus operators.

  • gate_matrix – The unitary gate.

Returns:

A list of transformed Kraus operators.

pyquil.noise.apply_noise_model(prog: Program, noise_model: NoiseModel) Program[source]

Apply a noise model to a program and generated a ‘noisy-fied’ version of the program.

Parameters:
  • prog – A Quil Program object.

  • noise_model – A NoiseModel, either generated from an ISA or from a simple decoherence model.

Returns:

A new program translated to a noisy gateset and with noisy readout as described by the noisemodel.

pyquil.noise.bitstring_probs_to_z_moments(p: ndarray) ndarray[source]

Convert between bitstring probabilities and joint Z moment expectations.

Parameters:

p – An array that enumerates bitstring probabilities. When flattened out p = [p_00...0, p_00...1, ...,p_11...1]. The total number of elements must therefore be a power of 2. The canonical shape has a separate axis for each qubit, such that p[i,j,...,k] gives the estimated probability of bitstring ij...k.

Returns:

z_moments, an np.array with one length-2 axis per qubit which contains the expectations of all monomials in {I, Z_0, Z_1, ..., Z_{n-1}}. The expectations of each monomial can be accessed via:

<Z_0^j_0 Z_1^j_1 ... Z_m^j_m> = z_moments[j_0,j_1,...,j_m]

pyquil.noise.combine_kraus_maps(k1: list[ndarray], k2: list[ndarray]) list[ndarray][source]

Generate the Kraus map for two composed maps, with k1 applied after k2 on the same qubits.

Parameters:
  • k1 – The list of Kraus operators that are applied second.

  • k2 – The list of Kraus operators that are applied first.

Returns:

A combinatorially generated list of composed Kraus operators.

pyquil.noise.correct_bitstring_probs(p: ndarray, assignment_probabilities: list[ndarray]) ndarray[source]

Given a 2D array of corrupted bitstring probabilities and assignment matrices, compute the corrected probabilities.

Given a 2d array of corrupted bitstring probabilities (outer axis iterates over shots, inner axis over bits) and a list of assignment probability matrices (one for each bit in the readout) compute the corrected probabilities.

Parameters:
  • p – An array that enumerates bitstring probabilities. When flattened out p = [p_00...0, p_00...1, ...,p_11...1]. The total number of elements must therefore be a power of 2. The canonical shape has a separate axis for each qubit, such that p[i,j,...,k] gives the estimated probability of bitstring ij...k.

  • assignment_probabilities

    A list of assignment probability matrices per qubit. Each assignment probability matrix is expected to be of the form:

    [[p00 p01]
     [p10 p11]]
    

Returns:

p_corrected an array with as many dimensions as there are qubits that contains the noisy-readout-corrected estimated probabilities for each measured bitstring, i.e., p[i,j,...,k] gives the estimated probability of bitstring ij...k.

pyquil.noise.corrupt_bitstring_probs(p: ndarray, assignment_probabilities: list[ndarray]) ndarray[source]

Given a 2D array of bitstring probabilities and assignment matrices, compute the corrupted probabilities.

Given a 2d array of true bitstring probabilities (outer axis iterates over shots, inner axis over bits) and a list of assignment probability matrices (one for each bit in the readout, ordered like the inner axis of results) compute the corrupted probabilities.

Parameters:
  • p – An array that enumerates bitstring probabilities. When flattened out p = [p_00...0, p_00...1, ...,p_11...1]. The total number of elements must therefore be a power of 2. The canonical shape has a separate axis for each qubit, such that p[i,j,...,k] gives the estimated probability of bitstring ij...k.

  • assignment_probabilities

    A list of assignment probability matrices per qubit. Each assignment probability matrix is expected to be of the form:

    [[p00 p01]
     [p10 p11]]
    

Returns:

p_corrected an array with as many dimensions as there are qubits that contains the noisy-readout-corrected estimated probabilities for each measured bitstring, i.e., p[i,j,...,k] gives the estimated probability of bitstring ij...k.

pyquil.noise.damping_after_dephasing(T1: float, T2: float, gate_time: float) list[ndarray][source]

Generate the Kraus map for a dephasing channel followed by an amplitude damping channel.

Parameters:
  • T1 – The amplitude damping time

  • T2 – The dephasing time

  • gate_time – The gate duration.

Returns:

A list of Kraus operators.

pyquil.noise.damping_kraus_map(p: float = 0.1) list[ndarray][source]

Generate the Kraus operators corresponding to an amplitude damping noise channel.

Parameters:

p – The one-step damping probability.

Returns:

A list [k1, k2] of the Kraus operators that parametrize the map.

Return type:

list

pyquil.noise.decoherence_noise_with_asymmetric_ro(isa: CompilerISA, p00: float = 0.975, p11: float = 0.911) NoiseModel[source]

Similar to _decoherence_noise_model(), but with asymmetric readout.

For simplicity, we use the default values for T1, T2, gate times, et al. and only allow the specification of readout fidelities.

pyquil.noise.dephasing_kraus_map(p: float = 0.1) list[ndarray][source]

Generate the Kraus operators corresponding to a dephasing channel.

Params float p:

The one-step dephasing probability.

Returns:

A list [k1, k2] of the Kraus operators that parametrize the map.

Return type:

list

pyquil.noise.estimate_assignment_probs(q: int, trials: int, qc: PyquilApiQuantumComputer, p0: Program | None = None) ndarray[source]

Estimate the readout assignment probabilities for a given qubit q.

The returned matrix is of the form:

[[p00 p01]
 [p10 p11]]
Parameters:
  • q – The index of the qubit.

  • trials – The number of samples for each state preparation.

  • qc – The quantum computer to sample from.

  • p0 – A header program to prepend to the state preparation programs. Will not be compiled by quilc, so it must be native Quil.

Returns:

The assignment probability matrix

pyquil.noise.estimate_bitstring_probs(results: ndarray) ndarray[source]

Given an array of single shot results estimate the probability distribution over all bitstrings.

Parameters:

results – A 2d array where the outer axis iterates over shots and the inner axis over bits.

Returns:

An array with as many axes as there are qubit and normalized such that it sums to one. p[i,j,...,k] gives the estimated probability of bitstring ij...k.

pyquil.noise.get_noisy_gate(gate_name: str, params: Iterable[Expression | MemoryReference | int | float | complex | number]) tuple[ndarray, str][source]

Look up the numerical gate representation and a proposed ‘noisy’ name.

Parameters:
  • gate_name – The Quil gate name

  • params – The gate parameters.

Returns:

A tuple (matrix, noisy_name) with the representation of the ideal gate matrix and a proposed name for the noisy version.

pyquil.noise.pauli_kraus_map(probabilities: Sequence[float]) list[ndarray][source]

Generate the Kraus operators corresponding to a pauli channel.

Params probabilities:

The 4^num_qubits list of probabilities specifying the desired pauli channel. There should be either 4 or 16 probabilities specified in the order I, X, Y, Z for 1 qubit or II, IX, IY, IZ, XI, XX, XY, etc for 2 qubits.

For example:

The d-dimensional depolarizing channel \Delta parameterized as
\Delta(\rho) = p \rho + [(1-p)/d] I
is specified by the list of probabilities
[p + (1-p)/d, (1-p)/d,  (1-p)/d), ... , (1-p)/d)]
Returns:

A list of the 4^num_qubits Kraus operators that parametrize the map.

pyquil.noise.tensor_kraus_maps(k1: list[ndarray], k2: list[ndarray]) list[ndarray][source]

Generate the Kraus map corresponding to the composition of two maps on different qubits.

Parameters:
  • k1 – The Kraus operators for the first qubit.

  • k2 – The Kraus operators for the second qubit.

Returns:

A list of tensored Kraus operators.