# Protocols to Generate Circuits¶

## Keys for QCVV protocols¶

 Key Names Description Type Relevant protocols Examples protocol uniquely specifies the characterization protocol used to generate the circuit str SRB, IRB, XRB, CB, NR “SRB”, “XRB” n_random_cycles the number of independently random cycles in the circuit int SRB, IRB, XRB, CB, NR 4, 16, 32 twirl specifies the twirling groups used for subsystems tuple SRB, IRB, XRB, CB, NR ((‘C1’, 0),) cycle a fixed cycle to be characterized custom IRB, CB, NR seq_label a number to group related sequences int XRB 3094, 4326 pauli_decay an n-qubit Pauli operator custom CB, NR

## API Methods¶

trueq.protocols.make_cb(cycle, n_random_cycles, n_circuits=30, n_decays=20, twirling_group=None, propagate_correction=False)

Generates a CircuitCollection for cycle benchmarking (CB).

import trueq as tq

# generate a circuit collection to run CB on the 0th qubit, with 30 circuits,
# for each length in [5, 20] and each with 3 randomly chosen Pauli decay strings
circuits = tq.make_cb(tq.Cycle({(0,): tq.Gate.x}), [5, 20], 30, 3)

Parameters
• cycle (Cycle) – The cycle to benchmark.

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• n_decays (int) – An integer specifying the total number of randomly chosen pauli decay strings used to measure the process infidelity. Setting this value lower than min(20, 4 ** n_qubits - 1) may result in a biased estimate.

• twirling_group (Iterable) – The twirling group to use in this protocol. This can be one of "P" (Pauli), "SU" (special unitary), "C" (Clifford), or a mixture such as [["P", 0], ["C", 1, 2], ["C", 3], ["P", 4]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "P" by default.

• propagate_correction (bool) – Whether to propagate correction gates to the end of the circuit or compile them in to neighbouring cycles. Warning: can result in arbitrary two-qubit gates at the end of the circuit!

Returns

A collection of CB circuits.

Return type

CircuitCollection

trueq.protocols.make_sc(cycle, n_random_cycles, n_circuits=30, pauli_decays=None, twirling_group=None, propagate_correction=False)

Generates a CircuitCollection for stochastic calibration (SC). Pauli decays should be chosen so that they anticommute with the generators of a known noise model.

import trueq as tq

# generate a circuit collection to run SC on the 0th qubit, with 30 circuits,
# for each length in [5, 20] and each with a Pauli decay string "Z"
circuits = tq.make_sc(tq.Cycle({(0,): tq.Gate.x}), [5, 20], 30, "Z")

Parameters
• cycle (Cycle) – The cycle to benchmark.

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• pauli_decays (Iterable) – A list of pauli decay strings, e.g. ["ZIZIZ", "XYXYX"] that specify which elements of the diagonalized channel should be averaged to approximate the effects of noise.

• twirling_group (Iterable) – The twirling group to use in this protocol. This can be one of "P" (Pauli), "SU" (special unitary), "C" (Clifford), or a mixture such as [["P", 0], ["C", 1, 2], ["C", 3], ["P", 4]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "P" by default.

• propagate_correction (bool) – Whether to propagate correction gates to the end of the circuit or compile them in to neighbouring cycles. Warning: can result in arbitrary two-qubit gates at the end of the circuit!

Returns

A collection of SC circuits.

Return type

CircuitCollection

trueq.protocols.make_knr(cycle, n_random_cycles, n_circuits=30, n_bodies=1, twirling_group=None, propagate_correction=False)

Generates a circuit collection to perform k-body noise reconstruction (KNR) on all sets of subsystems targeted by a combination of n gates.

For example, if the input cycle is {0: tq.Gate.id, (1, 3): tq.Gate.cnot, 2: tq.Gate.x} and n_bodies=2, then data will be present to reconstruct any Pauli error rate on the subsystems [0, 1, 3], [0, 2], [1, 2, 3] (and any subsystems thereof, e.g. [1, 2] but not [0, 1, 2]). Note that the number of returned circuits scales with the value of n_bodies, so it is best to pick the smallest number that suits your needs.

import trueq as tq

# generate a circuit collection to reconsturct two-body marginal
# error distributions
# on a 4-qubit device using 30 circuits for each length in [6, 20]
# and for each Pauli subspace in a set of log2(4) subspaces
circuits = tq.make_knr(
tq.Cycle({(j,): tq.Gate.x for j in range(4)}), [6, 20], 30
)

Parameters
• cycle (Cycle) – The cycle to benchmark.

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• n_bodies (int) – A number of gate bodies to reconstruct marginal probability distributions for.

• twirling_group – The twirling group to use in this protocol. This can be one of "P" (Pauli), "SU" (special unitary), "C" (Clifford), or a mixture such as [["P", 0], ["C", 1, 2], ["C", 3], ["P", 4]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "P" by default.

• propagate_correction (bool) – Whether to propagate correction gates to the end of the circuit or compile them in to neighbouring cycles. Warning: can result in arbitrary two-qubit gates at the end of the circuit!

Returns

A collection of KNR circuits.

Return type

CircuitCollection

trueq.protocols.make_tnr(cycle, n_random_cycles, n_circuits=30, targeted_errors=None, n_decays=15, twirling_group=None, propagate_correction=False)

Generates a circuit collection to perform targeted noise reconstruction (TNR) of the rate at which each Pauli error in a specified set occurs.

import trueq as tq

# generate a circuit collection to reconstruct targeted error distributions
# on a 4-qubit device using 30 circuits for each length in [6, 20]
# and for each Pauli subspace in a set of log2(4) subspaces
circuits = tq.make_tnr(
tq.Cycle({(j,): tq.Gate.x for j in range(4)}), [6, 20], 30, ["XXZZ", "XYXY"]
)

Parameters
• cycle (Cycle) – The cycle to benchmark.

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• targeted_errors (Iterable) – A list of pauli strings, e.g. ["ZIZIZ", "XYXYX"] that specify which errors to target.

• n_decays (int) – The number of commuting and anti-commuting Pauli decays to guarantee for each specified targeted error. For example, if this value is 10, than each targeted error will have at least 10 commuting Pauli decays and 10 anti-commuting Pauli decays in the resulting circuit collection. These Pauli decays are stored in the measurement_basis keyword of each circuit’s key.

• twirling_group – The twirling group to use in this protocol. This can be one of "P" (Pauli), "SU" (special unitary), "C" (Clifford), or a mixture such as [["P", 0], ["C", 1, 2], ["C", 3], ["P", 4]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "P" by default.

• propagate_correction (bool) – Whether to propagate correction gates to the end of the circuit or compile them in to neighbouring cycles. Warning: can result in arbitrary two-qubit gates at the end of the circuit!

Returns

A collection of TNR circuits.

Return type

CircuitCollection

trueq.protocols.make_srb(labels, n_random_cycles, n_circuits=30, twirling_group=None)

Generates a circuit collection for (simultaneous) streamlined randomized benchmarking (SRB). Clifford twirls are generated for all qubits specified in labels. One can choose to do any combination of single-qubit twirling or two-qubit twirling on the labels. For instance, setting labels as [5, 6] indicates single-qubit twirling on qubits 5 and 6, whereas [[5, 6]] indicates two-qubit twirling on the pair [5, 6].

import trueq as tq

# generate a circuit collection to run single qubit SRB on qubit 5
circuits = tq.make_srb([5], [4, 200], 30)

# generate a circuit collection to run two-qubit SRB on qubit pair [5, 6]
circuits = tq.make_srb([[5, 6]], [4, 200], 30)

# generate a circuit collection to run simultaneous one-qubit SRB on [5, 6, 7]
circuits = tq.make_srb([5, 6, 7], [4, 200], 30)

# generate a circuit collection to run simultaneous one-qubit SRB [5, 6, 7],
# two-qubit SRB on [0, 1] and [8, 9]
circuits = tq.make_srb([[0, 1], 5, 6, 7, [8, 9]], [4, 200], 30)

Parameters
• labels (Iterable) – A list of (lists of) positive integers, specifying qubit labels in each circuit, e.g. [3, [1, 2], 4].

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• twirling_group (Iterable) – The twirling group to use in this protocol. This can be one of "SU" (special unitary), "C" (Clifford), or a mixture such as [["SU", 0], ["C", 1, 2], ["C", 3], ["SU", 4, 6]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "C" by default.

Returns

A collection of SRB circuits.

Return type

CircuitCollection

trueq.protocols.make_irb(cycle, n_random_cycles, n_circuits=30, twirling_group=None, propagate_correction=False)

Generates a circuit collection for (simultaneous) interleaved randomized benchmarking (IRB) of a single cycle.

import trueq as tq

# generate a circuit collection to run single qubit IRB on an X gate acting on
# qubit 0, with 30 random circuits for each circuit length in [5, 40, 60, 100]
circuits = tq.make_irb(tq.Cycle({(0,): tq.Gate.x}), [5, 40, 60, 100], 30)

# next, generate circuits to run IRB on a cycle with an X gate acting on qubit 0
# and a CZ gate on qubits (2, 3), with 20 random circuits at each circuit length
tq.make_irb(tq.Cycle({(0,): tq.Gate.x, (2, 3): tq.Gate.cz}), [2, 100], 20)

Parameters
• cycle (Cycle) – The cycle to benchmark.

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• twirling_group (Iterable) – The twirling group to use in this protocol. This can be one of "SU" (special unitary), "C" (Clifford), or a mixture such as [["SU", 0], ["C", 1, 2], ["C", 3], ["SU", 4, 6]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "C" by default.

• propagate_correction (bool) – Whether to propagate correction gates to the end of the circuit or compile them in to neighbouring cycles. Warning: can result in arbitrary two-qubit gates at the end of the circuit!

Returns

A collection of IRB circuits.

Return type

CircuitCollection

trueq.protocols.make_xrb(labels, n_random_cycles, n_circuits=30, twirling_group=None)

Generates a circuit collection for (simultaneous) extended randomized benchmarking (XRB), to study both the unitarity and leakage of the noise on single qubit(s).

import trueq as tq

# generate circuit collections to run XRB on a single qubit (qubit 0), with
# 30 random circuits for each length in [4, 50, 500]
circuits = tq.make_xrb([0], [4, 50, 500], 30)

# generate circuit collections to run two-qubit XRB on qubit pair [5, 6], with
# 50 random circuits for each length in [3, 150]
circuits = tq.make_xrb([[5, 6]], [3, 150], 50)

# generate a circuit collection to run simultaneous one-qubit XRB on [5, 6, 7]
# with 30 random circuits for each length in [5, 10, 100]
circuits = tq.make_xrb([5, 6, 7], [5, 10, 100], 30)

# generate a circuit collection to run simultaneous one-qubit XRB on qubit 5,
# and two-qubit XRB on qubits [1, 2], with 15 random circuits for each circuit
# length in [4, 30]
circuits = tq.make_xrb([[1, 2], 5], [4, 30], 15)

Parameters
• labels (Iterable) – A list of (lists of) positive integers, specifying qubit labels in each circuit, e.g. [3, [1, 2], 4].

• n_random_cycles (Iterable) – A list of positive integers, specifying how many random cycles will be generated during the protocol, e.g. [6, 20].

• n_circuits (int) – The number of circuits for each random cycle.

• twirling_group (Iterable) – The twirling group to use in this protocol. This can be one of "SU" (special unitary), "C" (Clifford), or a mixture such as [["SU", 0], ["C", 1, 2], ["C", 3], ["SU", 4, 6]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "C" by default.

Returns

A collection of XRB circuits.

Return type

CircuitCollection

trueq.protocols.randomly_compile(circuits, n_compilations=30, twirling_group=None, compile_paulis=False, compress=True)

Randomly compiles the given circuit into many new random circuits which implement the same algorithm. Random gates are inserted adjacent to gates in the provided circuit, chosen from the specified twirling group (the Pauli group is used by default).

Cycles in the input circuit that are immutable will be treated as hard gates, and those that are mutable will be treated as easy gates. Recall that two-qubit gates are always considered immutable.

Note: Running randomly_compile() on a circuit several times is likely to return different compiled circuits due to the random nature of the algorithm. The circuit returned will always contain the same number of cycles as the input circuit, and will be logically equivalent, up to a global phase.

import trueq as tq

#Define a circuit which applies an X gate on the 0th qubit, a controlled-Z
#gate on qubits 0 and 1, and another X gate on the 0th qubit.
cycle1 = tq.Cycle({(0, ): tq.Gate.x})
cycle2 = tq.Cycle({(0, 1): tq.Gate.cz});
circuit = tq.Circuit((cycle1, cycle2, cycle1))
circuit.measure_all()

#Run randomized compiling on the circuit
compiled_circuit = tq.randomly_compile(circuit)


One possible output for the example above is:

    (0,): Gate.y                   (1,): Gate.x
Imm  (0, 1): Gate.cz
(0,): Gate.x                   (1,): Gate.x
Imm  (0,): Meas()                   (1,): Meas()

Parameters
• circuits (Circuit) – A circuit to randomly compile.

• n_compilations (int) – The number of random compilations of the input circuit. Each instance will appear as a new circuit in the returned circuit collection.

• twirling_group (Iterable) – The twirling group to use, e.g., "P", "C", or "SU". These can be applied differently to different qubit labels, e.g. [["P", 0], ["C", 1, 2], ["C", 3], ["P", 4]]. If the twirling group is not specified or if some labels are omitted in the specification, they will be populated from labels with "P" by default.

• compile_paulis (bool) – Whether or not to compile a random Pauli gate onto a qubit in the cycle preceding a measurement operation for each Meas operation encountered in the circuit. Which Paulis were compiled in are stored as a string in the key, where the order is first defined by cycle index, and then by sorted labels of each cycle. (default is False).

• compress (bool) – Whether or not to compress the easy cycles (default is True).

Returns

A circuit collection containing randomly compiled versions of the circuit.

Return type

py:class:~trueq.CircuitCollection

trueq.protocols.make_readout_calibration(labels, stagger=False, independent=True, batch=None)

Generates a circuit collection to measure readout error on the provided qubit labels. These circuits contain identity and X gates.

Parameters
• labels (Iterable) – A list of qubit labels to calibrate the readout error of.

• stagger (bool) – Whether X gates should appear in separate immutable cycles. If gates are much worse when applied in parallel, then staggering the gates will reduce systematic errors, provided gate duration multiplied by the number of qubits is much shorter than T1.

• independent (bool) – Whether it can be assumed that readout error is independent over qubits. Under this assumption, only two circuits are required, whereas (warning!) $$2^n$$ are required when this assumption does not hold. Note that if you measure the readout calibration matrix in both indepdent and non-indepedent mode, any observed non-independence could potentially be due to gate cross-talk errors.

• batch (int) – A unique identifier for these calibration circuits. Circuits which are to be calibrated off of these circuits’ results in particular should set their trueq.Circuit.key batch attribute to the same value.

Return type

trueq.CircuitCollection