Simulation¶
A (noisy) quantum simulator for 

Appends a noise source to this simulator that adds isotropic depolarizing noise to the simulation. 

A noise source that replaces all matched 

A noise source which reconstructs the noise of each cycle for each KNR experiment in 

Appends a noise source to this simulator that adds Kraus noise to the simulation. 

Appends a noise source to this simulator that performs gate over/underrotation. 

Appends measurement noise in the form of a positive operatorvalued measurement (POVM). 

Appends a state preparation description to this simulator that chooses which state to prepare whenever a operator is encountered in a circuit. 

Appends measurement classification error to this simulator, where errors are specified by confusion matrices estimated by the readout calibration protocol (RCAL). 

Appends measurement classification error to this simulator, where errors are specified by confusion matrices. 

Appends a noise source to this simulator that adds \(T_1\) and \(T_2\) relaxation noise to the simulation. 

Appends a noise source to this simulator that introduces stochastic Pauli noise. 

Computes the dressed noise of the given cycle for every list of labels in 

Returns the unitary or superoperator that results from simulating the given circuit. 

Predicts the estimates that would be generated by simulating 

Predicts the estimates that would be generated by simulating 

Predicts the estimates that would be generated by simulating 

Predicts the estimates that would be generated by simulating 

Updates the 

Returns the quantum state that results from simulating the given 

Wraps a 

A class whose purpose is to filter the operations presented to a given 

Wraps labels and an 

Parent class for all built in noise sources which can be added to the simulator. 

A helper class to 
Simulator¶

class
trueq.
Simulator
¶ A (noisy) quantum simulator for
Circuit
objects that can be used to compute the finalstate()
, the total effectiveoperator()
, or simplyrun()
them tosample()
shots.import trueq as tq # initialize a simulator with no noise present sim = tq.Simulator() # initialize a simulator with depolarizing noise at rate 1% sim = tq.Simulator().add_depolarizing(0.01) # initialize a simulator with depolarizing noise at rate 1%, and unitary # overration by 5% sim = tq.Simulator().add_depolarizing(0.01).add_overrotation(0.05) # make some circuits and populate their results with random shots circuits = tq.make_srb([0], [4, 60]) sim.run(circuits, n_shots=100) circuits[0].results
Results({'0': 97, '1': 3})

add_depolarizing
(p, d=2, match=None)¶ Appends a noise source to this simulator that adds isotropic depolarizing noise to the simulation. By default, noise is added every time a gate is encountered, however, by specifying
match
, the user can design a noise profile which is gate and/or qubitdependent. SeeMatch
for more details. The noise map for a given gate is defined by\[\mathcal{D}(\rho) = (1p) \rho + p \text{Tr}(\rho) \mathcal{I} / d\]where \(d=2\) for qubits. If, for example, a twoqubit gate is encountered, the tensor product of two onequbit depolarizing channels will be simulated. By default, depolarizing noise is applied to every system being acted on by a gate in a given cycle. For example, if qubits (0,1) get a CNOT, and qubit 3 gets an X in a given cycle, then depolarizing noise is applied to only these three qubits, even if the preceeding cycle contained a gate which acted on qubit 2. To ensure a depolarizing channel acts on all qubits during each cycle, include identity gates explicitly in the cycle definition.
Note that this is noise only—it does not try to implement the cycle in question, but only adds noise to it.
import trueq as tq import trueq.simulation as tqs circuit = tq.Circuit([{(0,1): tq.Gate.cx, 2: tq.Gate.h}]) # make a simulator with depolarizing noise with p=0.02 acting at every # location where a gate is applied sim = tq.Simulator().add_depolarizing(0.02) print(sim.sample(circuit, 1000)) # make a simulator where depolarizing noise acts only on locations where # gates act on qubit 5 sim = tq.Simulator().add_depolarizing(0.04, match=tqs.LabelMatch(5)) print(sim.sample(circuit, 1000))
Results({'000': 506, '001': 473, '010': 5, '011': 6, '110': 6, '111': 4}) Results({'000': 495, '001': 505})
 Parameters
p (
float
) – The depolarizing parameter, as defined in the equation above.d (
int
) – The subsystem dimension, 2 for qubits.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
NotImplementedError – If not called for qubits.

add_gate_replace
(fn, match=None)¶ A noise source that replaces all matched
Gate
s in the circuit with the returned valued offn
. Each new gate returned byfn
must have the same dimensions as the gate it replaces.No caching is performed on the outputs of
fn
; consider memoizing your function withfunctools.lru_cache()
to increase speed.See below for an example of gate replacement noise, which overrotates native gates matching a specific name by a random value within \([5, +5]\) degrees.
import trueq as tq import trueq.simulation as tqs import random def rand_noise(gate): # a function which creates a small amount of random parameter noise # this function expects ``gate`` to be native and have the parameter # "theta" theta = gate.parameters["theta"] return tq.Gate.rp("X", theta + random.uniform(5, 5)) # this match will ensure that ``rand_noise`` only ever applies to native # gates with the name "rx_noisy" match = tqs.NativeMatch("rx_noisy") # create and simulate a circuit with nontrivial noise application, where # any native gate with name "rx_noisy" also has a parameter named "theta" g = tq.NativeGate.from_generators("rx_noisy", "X", 90, params={"theta": 90}) circuit = tq.Circuit([{(0,): g}]) sim = tq.Simulator().add_gate_replace(rand_noise, match) # The 90 degree X rotation has been overrotated by a random amount sim.state(circuit).mat()
array([0.72079141+0.j , 0. 0.69315203j])
 Parameters
fn (
function
) – A function which takes in a gate and returns a gate with the same dimensions.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Raises
ValueError – If the new gate does not match the dimensions of the gate that it is replacing.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type

add_knr_noise
(fit_or_circuits, exclusive=False, ignore_identity=False, ignore_marker=True)¶ A noise source which reconstructs the noise of each cycle for each KNR experiment in
fit_or_circuits
; for more information refer to the KNR guide.For each unique
Cycle
with results contained infit_or_circuits
, we extract theNormalEstimate
s for each gatebody within the cycle. For each gatebody, we construct theSuperop
which models the onebody noise, as measured by the KNR protocol. If the same cycle appears more than once, it is ambiguous which fit should be used to reconstruct the noise, and an error is raised.Running the KNR protocol on a cycle with explicitly defined identities will estimate the noise seen by idle qubits. For convenience, setting the flag
ignore_identity
toTrue
will allow the reconstructed noise operator to match with cycles that do not contain explicit identity operators, so long as another cycle within the circuit being simulated contains operations which act on those qubits.Similarly, KNR noise can be set to apply to only those cycles which are equal to the cycle estimated by the KNR protocol and have equal marker values, by setting
ignore_marker
toFalse
. The matching occurs via an internally instantiatedCycleMatch
.In the example below, we instantiate a noisy simulator and estimate the noise seen by an example cycle via the KNR protocol. We then use the resulting fit to instantiate a new simulator which reconstructs the noise of the first simulator.
import trueq as tq import trueq.simulation as tqs cycle = tq.Cycle({0: tq.Gate.h, 1: tq.Gate.z, (2,3):tq.Gate.cx}) knr_circuits = tq.make_knr( cycle, n_random_cycles=[4, 6, 8], n_circuits=30, n_bodies=1 ) sim = tq.Simulator().add_stochastic_pauli(px=0.01, py=.03) sim.add_stochastic_pauli(pz=0.05, match=tqs.LabelMatch((0,3))) sim.run(knr_circuits) knr_sim = tq.Simulator().add_knr_noise(knr_circuits) circuit = tq.Circuit(cycle) circuit.measure_all() knr_sim.sample(circuit, 100).plot() sim.sample(circuit, 100).plot()
 Parameters
fit_or_circuits (
EstimateCollection
CircuitCollection
) – An estimate collection or a set of circuits which contain estimates of or circuits for the KNR protocol.exclusive (
bool
) – IfTrue
, all gates within the targeted cycles will be marked asno_more_noise
during simulation. This isFalse
by default.ignore_identity (
bool
) – Whether or not to match this noise to cycles containing identical operations, ignoring any identity operators. This isFalse
by default.ignore_marker (
bool
) – IfTrue
, match this noise to cycles which contain the same operations but have differet markers. This isTrue
by default.
 Raises
ValueError – If a cycle in the
fit_or_circuits
appears in the fit multiple times, or if the fit is empty. Returns
This simulator instance so that
add_*()
calls can be chained. Return type

add_kraus
(kraus_ops, match=None, dim=2)¶ Appends a noise source to this simulator that adds Kraus noise to the simulation. The noise is added to each gate matched by
match
, so long as the Kraus operators’ dimensions allow it to be applied to the matched gates. By default, single qubit Kraus noise will apply to to all subsystems of any matched gate, whereas multiqubit Kraus noise will only be applied to gates of the same dimension. If a multiqubit Kraus channel matches to a multiqubit gate acting on more subsystems than the Kraus operators, an error will be raised. The noise map is defined by\[\mathcal{K}(\rho) = \sum_{i} K_i \rho K_i^\dagger\]Note that this is noise only—it does not try to implement a given cycle in question, but only adds noise to it.
By default, Kraus noise will affect only those subsystems of a cycle with a gate present. For example, if qubits (0,1) get a CNOT, and qubit 3 gets an X in given cycle, then Kraus noise only has the ability to match with these three qubits, even if the preceeding cycle had a gate which acted on qubit 2. To ensure that the Kraus channel has the opportunity to act on all qubits during each cycle, include identity gates explicitly in the cycle definition.
The dimension of the underlying subsystems upon which the Kraus operators act is specified by
dim
, which has a default value of 2. Kraus noise which induces leakage into additional levels must specifydim
accordingly to account for the increased dimension.import trueq as tq import trueq.simulation as tqs import numpy as np circuit = tq.Circuit([{(0,1): tq.Gate.cx, 2: tq.Gate.h}]) # define qubit dephasing kraus operators kraus_ops = [np.sqrt(0.99)*np.eye(2), np.sqrt(0.01)*np.diag([1,1])] # initialize a simulator in which qubit dephasing noise acts on every # location where gates are applied sim = tq.Simulator().add_kraus(kraus_ops) print(sim.sample(circuit, 1000)) # define a set of Kraus operators acting on single qubit gates, and set # of Kraus operators to explicitly act on two qubit gates kraus_ops1 = [np.sqrt(0.999) * np.eye(2), np.sqrt(0.001) * np.diag([1, 1])] kraus_ops2 = [ np.sqrt(0.99) * np.eye(4), np.sqrt(0.01) * np.fliplr(np.diag([1, 1, 1, 1])) ] # initialize a simulator with the noise defined above acting at # every location where a gate acts sim = tq.Simulator().add_kraus(kraus_ops1, match=tqs.SingleQubitMatch()) sim.add_kraus(kraus_ops2, match=tqs.NQubitMatch(2)) print(sim.sample(circuit, 1000)) # initialize a simulator which applies the above noise when a gate acts # on qubit 0 noisy_label = tqs.LabelMatch(0, strict=False) sim = tq.Simulator().add_kraus(kraus_ops1, match=noisy_label) sim.add_kraus(kraus_ops2, match=noisy_label) print(sim.sample(circuit, 1000)) # initialize a simulator which applies the above noise when an X gate acts # on qubit 2 or 3 # no 2 qubit gates will be matched under these conditions, no need to add # the two qubit kraus channel to the simulator sim=tq.Simulator() noise_match = tqs.LabelMatch((2,3)) & tqs.GateMatch(tq.Gate.x) sim.add_kraus(kraus_ops1, match=noise_match) print(sim.sample(circuit, 1000))
Results({'000': 481, '001': 519}) Results({'000': 488, '100': 4, '001': 503, '101': 5}) Results({'000': 463, '001': 529, '100': 2, '101': 6}) Results({'000': 488, '001': 512})
 Parameters
kraus_ops (
iterable
) – An iterable of square matrices, each of which must be the same size, and act on subsystems of dimensiondim
.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.dim (
int
) – An integer representing the dimension of the subsystem upon which the Kraus operators act.dim
is 2, representing qubits, by default.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
ValueError – If
kraus_ops
has the wrong dimension or is not a list of square matrices.

add_overrotation
(single_sys=0, multi_sys=0, match=None)¶ Appends a noise source to this simulator that performs gate over/underrotation. This is done by propagating by the matrix power \(U_{err}=U^{(1+\epsilon)}\) instead of the ideal gate \(U\). Overrotation noise does attempt to simulate the gates within a circuit, it is not just noise only.
import trueq as tq import trueq.simulation as tqs circuit = tq.Circuit([{(0,1): tq.Gate.cx, 2: tq.Gate.h}]) # initialize a simulator in which every single qubit gate is overrotated by # epsilon=0.01 sim = tq.Simulator().add_overrotation(single_sys=0.01) print(sim.sample(circuit, 1000)) # initialize a simulator in which every single qubit gate is overrotated by # epsilon=0.02 and every multiqubit gate by epsilon=0.04 sim = tq.Simulator().add_overrotation(single_sys=0.02, multi_sys=0.04) print(sim.sample(circuit, 1000)) # initialize a simulator in which overrotations are applied whenever a gate # acts on any qubits in {0, 2} sim = tq.Simulator() noisy_labels = tqs.LabelMatch((0,2)) sim.add_overrotation(single_sys=0.02, multi_sys=0.01, match=noisy_labels) print(sim.sample(circuit, 1000))
Results({'000': 507, '001': 493}) Results({'000': 550, '001': 450}) Results({'000': 485, '001': 515})
 Parameters
single_sys (
float
) – The amount of over/underrotation to apply to gates that act on a single subsystem (ie. singlequbit). A value of0
corresponds to no overrotation, a negative value corresponds to underrotation, and a positive value corresponds to overrotation.multi_sys (
float
) – The amount of over/underrotation to apply to gates that act on a multiple subsystems (ie. multiqubit). A value of0
corresponds to no overrotation, a negative value corresponds to underrotation, and a positive value corresponds to overrotation.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type

add_povm
(povm, match=None)¶ Appends measurement noise in the form of a positive operatorvalued measurement (POVM). This method allows two types of POVMs: “true” POVMs, and “classification” POVMs, described below.
A true POVM applies to density matrices, where the probability of a particular outcome \(x\) is given by \(p_x=\operatorname{Tr}(\rho E_x)\). Here, \(x\) is typically a bitstring and \(E_x\) is the corresponding positivesemidefinite measurement operator. For measurement noise that is uncorrelated between subsystems, \(E_x\) will be a tensor product \(E_x=E_{x_1}\otimes \cdots \otimes E_{x_n}\). This is entered as a
Tensor
with shape((k,), (d, d))
wherek
is the number of outcomes per qubit, andd
is the Hilbert state dimension, which must match the simulation. A sum over thek
axis must produce the identity matrix for a probability preserving POVM. Note that there is no requirement thatk == d
, for example,k = 3; d = 2
represents a qubit simulation being classified into three possible results.import trueq as tq import numpy as np # define a set of ideal POVM operators ideal = np.array([[[1, 0], [0, 0]], [[0, 0], [0, 1]]]) # define a unitary rotation about X by 5 degrees U = tq.Gate.from_generators("X", 5).mat # define noisy POVM operators by rotating the ideal POVM operators by U twisted = [U @ x @ U.conj().T for x in ideal] # specify how the operations defined above will impact the simulation # in this instance, the ideal POVMs will act on every qubit, except for # qubit 0, which will have the twisted POVM (rotation about X) povm = tq.math.Tensor( 2, (2, 2), # num of POVMs, (dimension, dimension) spawn=ideal, # default measurement operation value={(0,): twisted}, # measurement operation on qubit 0 dtype=np.complex128 # tensor is real by default ) # initialize a simulator with the above POVM specifications. sim = tq.Simulator().add_povm(povm) # initialize a circuit circuit = tq.Circuit([{(0, ): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) circuit.measure_all() # run the circuit on the simulator sim.sample(circuit, 1000).plot()
This method additionally allows for what we call classification POVMs. This is a less general form of measurement noise, which can be expressed as inner products against the density matrix as described above, but which are more efficiently described as a transformation of the ideal measurement probability vector in the computational basis. In this case, we have \(p=Cq\) where \(p\) is the vector of outcome probabilities \(p_x\), \(C\) is a classification error matrix, and \(q\) is the vector of ideal measurement probabilities of \(\rho\) in the computational basis. For measurement noise that is uncorrelated between subsystems, \(C=C_1\otimes\cdots\otimes C_n\). This is entered as a
Tensor
with shape((k,), (d,))
wherek
is the number of outcomes per qubit, andd
is the Hilbert state dimension, which must match the simulation. Each column must sum to 1 for a probability preserving measurement.import trueq as tq import numpy as np # classification error on qubit 0 p0 = np.array([[0.99, 0.02], [0.01, 0.98]]) # correlated classification error on qubits 1, 2 p12 = np.array([ [0.99, 0.02, 0.0, 0.0], [0.01, 0.98, 0.05, 0.0], [0.0, 0.0, 0.94, 0.0], [0.0, 0.0, 0.01, 1.0] ]) povm = tq.math.Tensor( 2, 2, # num of POVMs, dimension spawn=np.eye(2), # default measurement operation value={(0,): p0, (1, 2): p12}, # errors ) # initialize a simulator with the above POVM specifications. sim = tq.Simulator().add_povm(povm) # initialize a circuit circuit = tq.Circuit([{(0, 2): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) circuit.measure_all() # run the circuit on the simulator sim.sample(circuit, 1000).plot()
 Parameters
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type

add_prep
(state, match=None)¶ Appends a state preparation description to this simulator that chooses which state to prepare whenever a operator is encountered in a circuit.
A state to add can be specified in any of the following formats:
A number between 0 and 1, representing a bitflip error probability of the ideal preparation \(0\rangle\)
A length\(d\) vector, representing a pure state
A \(d\times d\) matrix, representing a density matrix
If only one of the above is provided, it is used every time a
Prep
object is encountered. One can also specify that different subsystems get different errors by providing a dictionary mapping whose values are combination of the above formats; see the examples below.import trueq as tq circuit = tq.Circuit([{i: tq.Prep() for i in range(3)}]) # add 5% bitflip error to any qubit sim = tq.Simulator().add_prep(0.05) print(sim.sample(circuit, float("inf"))) # add 2% bitflip error by default, but 5% for qubits 1 and 2 sim = tq.Simulator().add_prep({None: 0.02, 2: 0.05, 1: 0.05}) print(sim.sample(circuit, float("inf"))) # add specific density matrix to qubit 1, but 1% bitflip error by default sim = tq.Simulator().add_prep({None: 0.01, 1: [[0.8, 0.1], [0.1, 0.2]]}) print(sim.sample(circuit, float("inf")))
Results({'000': 0.8573749999999999, '001': 0.045125, '010': 0.045125, '011': 0.0023750000000000004, '100': 0.045125, '101': 0.0023750000000000004, '110': 0.0023750000000000004, '111': 0.00012500000000000003}) Results({'000': 0.8844499999999998, '001': 0.04655, '010': 0.04655, '011': 0.0024500000000000004, '100': 0.01805, '101': 0.00095, '110': 0.00095, '111': 5e05}) Results({'000': 0.78408, '001': 0.00792, '010': 0.19602, '011': 0.00198, '100': 0.00792, '101': 8e05, '110': 0.00198, '111': 2e05})
For state simulation, if a
Prep
operator is encountered on a subsystem that has previously been initialized, then the register is tracedout and the state is replaced with a new one. For operator simulation,Prep
objects are taken as the partialtracewithreplacement channel \(\rho\mapsto\mathrm{Tr}_\text{i}(\rho)\otimes\rho'\) where \(i\) is the subsystem label being prepared, \(\rho\) is the old state on all subsystems, and \(\rho'\) is the new state being prepared on \(i\). Although, note thatoperator()
skips preparation objects by default. Parameters
state (
float
numpy.ndarray
like dict
) – A description of quantum states to initialize with.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
ValueError – If inconsistent dimensions are provided.

add_rcal_noise
(fit_or_circuits)¶ Appends measurement classification error to this simulator, where errors are specified by confusion matrices estimated by the readout calibration protocol (RCAL).
fit_or_circuits
should be either a circuit collection with results from the RCAL protocol, or an estimate collection containing the fit for an RCAL estimate. If no RCAL fitting information is found, or if there are multiple fits present infit_or_circuits
, an error will be raised.import trueq as tq import numpy as np # generate RCAL circuits to measure the readout errors on qubits [0, 1] circuits = tq.make_rcal([0, 1]) # initialize a mock device with a 20% readout error on every qubit sim = tq.Simulator().add_readout_error(0.2) # run the circuits on the mock device to populate their results and # estimate the readout error sim.run(circuits, n_shots=1000) fit = circuits.fit() # instantiate a simulator with the RCAL estimate and report the results # of running an example circuit with the new simulator sim = tq.Simulator().add_rcal_noise(fit) circuit = tq.Circuit({(0,1): tq.Gate.x}).measure_all() sim.run(circuit, n_shots=np.inf) circuit.results.plot()
 Parameters
fit_or_circuits (
EstimateCollection
CircuitCollection
) – An estimate collection or a set of circuits which contain estimates of or circuits for the KNR protocol. Raises
ValueError – If
fit_or_circuits
does not contain exactly one RCAL estimate. Returns
This simulator instance so that
add_*()
calls can be chained. Return type

add_readout_error
(default_error=None, errors=None, match=None)¶ Appends measurement classification error to this simulator, where errors are specified by confusion matrices. For qubits, errors can instead be specified by a single misclassification probability (symmetric readout error), or a pair of readout errors (asymmetric readout error, where the probability of misclassifying \(0\rangle\) is different than \(1\rangle\)).
Errors can differ on individual qubits by singling out their labels in the second argument, see the example below. Similarly, correlated errors can be added by specifying larger confusion matrices and the qubits they act on.
import trueq as tq # make a test circuit that measures 4 qubits circuit = tq.Circuit([{range(4): tq.Meas()}]) # all qubits get 1% readout error sim = tq.Simulator().add_readout_error(0.01) print(sim.sample(circuit, 200)) # all qubits get 1% readout error, except qubit 1 gets 5% readout error sim = tq.Simulator().add_readout_error(0.01, {1: 0.05}) print(sim.sample(circuit, 200)) # all qubits get 1% readout error, except qubit 1 get 5% readout error, # and qubit 3 get asymmetric readout error of 1% on 0> and 7% on 1> sim = tq.Simulator().add_readout_error(0.01, {1: 0.05, 3: [0.01,0.07]}) print(sim.sample(circuit, 200)) # we specify correlated measurement errors on qubits (3, 2) with a 4x4 # confusion matrix (row/column order is 00, 01, 10, 11). all other qubits # get 1% symmetric classification error. confusion = [ [0.81, 0.72, 0.72, 0.64], [0.09, 0.18, 0.08, 0.16], [0.06, 0.08, 0.18, 0.16], [0.04, 0.02, 0.02, 0.04] ] sim = tq.Simulator().add_readout_error(0.01, {(3,2):confusion}) print(sim.sample(circuit, 200)) # here we add asymmetric qutrit classification error to all three levels, # where 0> is reported as a '0' 99% of the time, 1> is reported as a '1' # 92% of the time, and 2> is reported as a '2' 80% of the time. # offdiagonals are the probabilities of misclassification into specific # outcomes corresponding to the row they are located in. we add this error # specifically to qutrit 2, the rest of the qutrits have ideal measurements. confusion = [[0.99, 0.03, 0.02], [0.005, 0.92, 0.18], [0.005, 0.05, 0.8]] sim = tq.Simulator().add_readout_error(errors={2: confusion}) print(sim.sample(circuit, 200)) # classify qutrit measurements into binary outcomes. this situation arises, # for example, in superconducting qubits when there is leakage into the # third level of the anharmonic oscillator, but readout always reports a '0' # or a '1'. we use a rectangular confusion matrix where 2> is classified as # a '0' 70% of the time, and as a '1' 30% of the time. confusion = [[0.99, 0.08, 0.7], [0.01, 0.92, 0.3]] sim = tq.Simulator().add_readout_error(confusion) print(sim.sample(circuit, 200))
Results({'0000': 191, '0001': 3, '0010': 3, '0100': 2, '1000': 1}) Results({'0000': 191, '0001': 1, '0010': 1, '0100': 5, '1000': 2}) Results({'0000': 181, '0001': 2, '0010': 4, '0100': 11, '1000': 2}) Results({'0000': 160, '0010': 17, '0001': 14, '0011': 6, '0101': 1, '1000': 1, '1010': 1}) Results({'0000': 198, '0010': 1, '0020': 1}, dim=3) Results({'0000': 188, '0001': 2, '0010': 2, '0100': 4, '0110': 1, '1000': 3})
 Parameters
default_error (
numpy.ndarray
like float
) – Default readout error specificed as a confusion matrix to be applied to all qubits that don’t receive special errors inerrors
. For qubits, the confusion matrix can be replaced by a single number or pair of numbers for symmetric and asymmetric classification error, respectively. The default is no error.errors (
dict
) – A dictionary mapping tuples of qubit labels to confusion matrices. For qubits, confusion matrices can be replaced by a single number or pair of numbers for symmetric and asymmetric classification error, respectively.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
ValueError – For any inconsistencies in the input arguments.

add_relaxation
(t1, t2, t_single, t_multi, excited_pop=0, match=None)¶ Appends a noise source to this simulator that adds \(T_1\) and \(T_2\) relaxation noise to the simulation. Specifically, for every cycle in a circuit, this noise source adds error to every qubit in the state defined by the Choi matrix:
\[\begin{split}C = \begin{pmatrix} 1p(1e^{t/T_1}) & 0 & 0 & e^{t/T_2} \\ 0 & (1p)e^{t/T_1} & 0 & 0 \\ 0 & 0 & pe^{t/T_1} & 0 \\ e^{t/T_2} & 0 & 0 & 1(1p)e^{t/T_1} \end{pmatrix}\end{split}\]where \(t\) is the time of the longest gate in the cycle (i.e. either
t_single
ort_multi
for an entire cycle).import trueq circuit = tq.Circuit([{(0,1): tq.Gate.cx, 2: tq.Gate.h}]) # make a simulator with relaxation noise with t1=100e6, t2=50e6, # singlequbit gate time 25e9, two qubit gate time 100e9 and an excited # equilibrium population 0.01. sim = tq.Simulator().add_relaxation(100e6, 50e6, 25e9, 100e9, 0.01) print(sim.sample(circuit, 1000)) # make a simulator with relaxation noise with t1=10us, singlequbit gate # time 25ns and two qubit gate time 100ns. t2=5us on all qubits except qubit # 0 which has t2=2.5us. t2 = {None: 5e6, 0: 2.5e6} sim = tq.Simulator().add_relaxation(10e6, t2, 25e9, 100e9) # plot the final state tq.visualization.plot_mat(sim.state(circuit).mat())
Results({'000': 517, '001': 483})
 Parameters
t1 (
float
dict
) – The \(T_1\) time, i.e. the characteristic time of relaxation. These can vary from qubit to qubit, see the example above.t2 (
float
dict
) – The \(T_2\) time, i.e. the characteristic time of dephasing. These can vary from qubit to qubit, see the example above.t_single (
float
) – The time it takes to perform a singlequbit gate.t_multi (
float
) – The time it takes to perform a multiqubit gate.excited_pop (
float
dict
) – The excited state population at equilibrium.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
ValueError – If invalid \(T_1\) and \(T_2\) arguments are provided.

add_stochastic_pauli
(px=0, py=0, pz=0, match=None)¶ Appends a noise source to this simulator that introduces stochastic Pauli noise. This is done by applying the following singlequbit Kraus operators to every qubit that is explicitly acted upon by a gate in a given cycle:
\[\begin{split}K_1 &= \sqrt{1p_xp_yp_z} \mathcal{I} \\ K_2 &= \sqrt{p_x} \sigma_x \\ K_3 &= \sqrt{p_y} \sigma_y \\ K_4 &= \sqrt{p_z} \sigma_z\end{split}\]Note that this is noise only—it does not try to implement the cycle in question, but only adds noise to it.
By default, this noise is applied to every system being acted on by a gate in a given cycle. For example, if qubits (0,1) get a CNOT, and qubit 3 gets an X in a given cycle, then stochastic Pauli noise is applied to only these three qubits, even if the preceeding cycle acted on qubit 2. The
match
argument can be used to specify under which conditions the stochastic Pauli noise should be applied, seeMatch
for more information.import trueq as tq circuit = tq.Circuit([{(0,1): tq.Gate.cx, 2: tq.Gate.x, 3: tq.Gate.h}]) # initialize a simulator in which every location where a gate acts undergoes # Pauli noise with px=0.01 and py=0.04 sim = tq.Simulator().add_stochastic_pauli(px=0.01, py=0.04) print(sim.sample(circuit, 1000)) # initialize a simulator where every X gate undergoes Pauli noise with # py=pz=0 and px=0.04 noisy_gate = tqs.GateMatch(tq.Gate.x) sim = tq.Simulator().add_stochastic_pauli(px=0.04, match = noisy_gate) print(sim.sample(circuit, 1000))
Results({'0000': 22, '0001': 31, '0010': 416, '0011': 440, '0100': 3, '0101': 1, '0110': 19, '0111': 19, '1010': 3, '1100': 1, '1101': 3, '1110': 25, '1111': 17}) Results({'0000': 21, '0001': 27, '0010': 458, '0011': 494})
 Parameters
px (
float
) – The probability of an X error.py (
float
) – The probability of a Y error.pz (
float
) – The probability of a Z error.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Returns
This simulator instance so that
add_*()
calls can be chained. Return type
 Raises
ValueError – If the probabilities of X, Y, and Z errors sum to more than 1.

append_noise_source
(noise_source)¶ Appends a noise source to the simulator. A noise source in an instance of some subclass of
NoiseSource
, which includes custom user subclasses.The order in which noise sources are added is the order in which they will be applied (cycle by cycle) during simulation.
 Parameters
noise_source (
NoiseSource
) – A source of noise to be added to the simulator. Returns
This simulator instance.
 Return type

dressed_noise
(cycle, labels_list, n_randomizations=None, twirl='P', compiler=None)¶ Computes the dressed noise of the given cycle for every list of labels in
labels_list
. The dressed noise superoperator is defined as\[\mathcal{E} = \mathbb{E}[ \mathcal{T}^\dagger \mathcal{C}^\dagger \tilde{\mathcal{C}} \tilde{\mathcal{T}} ]\]where \(\mathcal{C}\) is the cycle of interest, \(\tilde{\mathcal{C}}\) its noisy simulation, \(\mathcal{T}\) an element of the twirling group, \(\tilde{\mathcal{T}}\) its noisy simulation, and where the expectation is taken uniformly over the twirling group.
The expectation value is taken in one of two ways. If
n_randomizations=None
, twirling operations are assumed to be perfect so that the expectation value is a simple function of the diagonal elements of the superoperator \(\mathcal{C}^\dagger \tilde{\mathcal{C}}\) in the Pauli vectorization basis. Otherwise, the expectation is computed usingn_randomizations
MonteCarlo samples from the twirling group, each of which is simulated with this simulator. Parameters
cycle (
Cycle
) – The cycle to find the dressed noise of.labels_list (
Iterable
) – A list of lists of labels. Simulations are performed once on all labels present, and marginalizations are performed on each of these lists afterwards.n_randomizations (
int
None
) – The number of random twirls to average over. IfNone
, the twirling group is assumed to have a perfect implementation.twirl (
Twirl
str
) – The twirling group to use.compiler (
Compiler
) – A compiler to run all cycles through before simulating them.
 Returns
A list of
Tensor
s, corresponding to the givenlabels_list
. The tensors report Pauli probabilities of the Pauli Kraus map. Return type
list

predict_cb
(cycle, labels=None, n_randomizations=50, targeted_errors=None, twirl='P', compiler=None)¶ Predicts the estimates that would be generated by simulating
make_cb()
with this simulator.import trueq as tq sim = tq.Simulator().add_stochastic_pauli(px=0.01).add_overrotation(0.04) sim.predict_cb({0: tq.Gate.id, (1,2): tq.Gate.cnot})
TrueQ formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File > Trust Notebook".CBCycle BenchmarkingPaulis (0,) : Gate.id
(1, 2) : Gate.cx
 Key:

 cycles: (Cycle((0,): Gate.id, (1, 2): Gate.cx),)
 labels: (0, 1, 2)
 name:
 protocol: CB
 twirl: Paulis on [0, 1, 2]
${e}_{F}$The probability of an error acting on the specified labels during a dressed cycle of interest.6.7e02 (0.0e+00) 0.06677697015689155, 0.0${e}_{III}$The probability of the subscripted error acting on the specified labels.9.3e01 (0.0e+00) 0.9332230298431085, 0.0 Parameters
labels (
Iterable
) – A list of which sets of system labels are to be twirled together in each circuit, e.g.[3, [1, 2], 4]
.n_randomizations (
int
None
) – The number of random twirls to average over. IfNone
, the twirling group is assumed to have a perfect implementation.twirl (
Twirl
str
) – The twirling group to use.compiler (
Compiler
) – A compiler to run all cycles through before simulating them.
 Return type
 Raises
ValueError – If
targeted_errors
are not all Pauli strings of the correct length.

predict_irb
(cycle, n_randomizations=50, targeted_errors=None, twirl='C', compiler=None)¶ Predicts the estimates that would be generated by simulating
make_irb()
with this simulator.import trueq as tq sim = tq.Simulator().add_stochastic_pauli(px=0.01).add_overrotation(0, 0.1) sim.predict_irb({0: tq.Gate.id, (1,2): tq.Gate.cnot})
TrueQ formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File > Trust Notebook".IRBInterleaved Randomized BenchmarkingCliffords (0,) : Gate.id
(1, 2) : Gate.cx
 Key:

 cycles: (Cycle((0,): Gate.id, (1, 2): Gate.cx),)
 labels: (0,)
 name:
 protocol: IRB
 twirl: Cliffords on [0, (1, 2)]
Cliffords (0,) : Gate.id
(1, 2) : Gate.cx
 Key:

 cycles: (Cycle((0,): Gate.id, (1, 2): Gate.cx),)
 labels: (1, 2)
 name:
 protocol: IRB
 twirl: Cliffords on [0, (1, 2)]
${e}_{F}$The probability of an error acting on the targeted systems during a dressed gate of interest.2.0e02 (0.0e+00) 0.019872000000000112, 0.07.8e02 (0.0e+00) 0.07778965405991278, 0.0${p}$Decay parameter of the exponential decay $Ap^m$.9.8e01 (0.0e+00) 0.9801279999999999, 0.09.2e01 (0.0e+00) 0.9222103459400872, 0.0 Parameters
labels (
Iterable
) – A list of which sets of system labels are to be twirled together in each circuit, e.g.[3, [1, 2], 4]
.n_randomizations (
int
None
) – The number of random twirls to average over. IfNone
, the twirling group is assumed to have a perfect implementation.twirl (
Twirl
str
) – The twirling group to use.compiler (
Compiler
) – A compiler to run all cycles through before simulating them.
 Return type

predict_knr
(cycle, n_bodies=1, n_randomizations=50, twirl='P', compiler=None)¶ Predicts the estimates that would be generated by simulating
make_knr()
with this simulator.import trueq as tq sim = tq.Simulator().add_stochastic_pauli(px=0.01).add_overrotation(0, 0.1) cycle = {0: tq.Gate.h, (1,2): tq.Gate.cnot} prediction = sim.predict_knr(cycle, n_bodies=2) prediction.plot.knr_heatmap()
 Parameters
labels (
dict
Cycle
) – The cycle to make the prediction for.n_randomizations (
int
None
) – The number of random twirls to average over. IfNone
, the twirling group is assumed to have a perfect implementation.twirl (
Twirl
str
) – The twirling group to use.compiler (
Compiler
) – A compiler to run all cycles through before simulating them.
 Return type
 Raises
ValueError – If the twirl is missing subsystems present in the cycle.
ValueError – If the subsystems in the twirl partially overlap with those in the cycle.

predict_srb
(labels, n_randomizations=50, twirl='C', compiler=None)¶ Predicts the estimates that would be generated by simulating
make_srb()
with this simulator.import trueq as tq sim = tq.Simulator().add_stochastic_pauli(px=0.01).add_overrotation(0.04) prediction = sim.predict_srb([0, [1,2]]) prediction += sim.predict_srb([0]) prediction += sim.predict_srb([[1, 2]]) prediction.plot.compare_rb()
 Parameters
labels (
Iterable
) – A list of which sets of system labels are to be twirled together in each circuit, e.g.[3, [1, 2], 4]
.n_randomizations (
int
None
) – The number of random twirls to average over. IfNone
, the twirling group is assumed to have a perfect implementation.twirl (
Twirl
str
) – The twirling group to use.compiler (
Compiler
) – A compiler to run all cycles through before simulating them.
 Return type

state
(circuit)¶ Returns the quantum state that results from simulating the given
circuit
.If this simulator contains only unitary errors and pure state preparations, a pure state will be simulated and returned, otherwise, a density matrix will be simulated and returned. Unless this simulator contains a special preparation (see e.g.
add_prep()
), every qubit in the circuit will be prepared with the state \(0\rangle\).import trueq as tq # make a circuit with two clock cycles circuit = tq.Circuit([{(0, ): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) # simulate the circuit to find the final pure state psi = tq.Simulator().state(circuit) print("Pure state: ", psi.mat()) # if we add depolarizing noise we get a density matrix rho = tq.Simulator().add_depolarizing(0.01).state(circuit) print("Density matrix: ", rho.mat()) # we can get outcome probabilities from the state print("Pure state probabilities: ", psi.probabilities()) print("Density matrix probabilities: ", rho.probabilities()) # and we can convert them to Result objects print("Pure state as results: ", psi.probabilities().to_results()) print("Density matrix as results: ", rho.probabilities().to_results())
Pure state: [0.70710678+0.j 0. +0.j 0. +0.j 0.70710678+0.j] Density matrix: [[0.4975 +0.j 0. +0.j 0. +0.j 0.48759975+0.j] [0. +0.j 0.0025 +0.j 0.00245025+0.j 0. +0.j] [0. +0.j 0.00245025+0.j 0.0025 +0.j 0. +0.j] [0.48759975+0.j 0. +0.j 0. +0.j 0.4975 +0.j]] Pure state probabilities: Tensor(<[(2,), ()] on labels [(0, 1)]>) Density matrix probabilities: Tensor(<[(2,), ()] on labels [(0, 1)]>) Pure state as results: Results({'00': 0.5000000000000001, '11': 0.5000000000000001}) Density matrix as results: Results({'00': 0.4975000000000001, '01': 0.002500000000000001, '10': 0.002500000000000001, '11': 0.4975000000000001})
 Parameters
circuit (
Circuit
) – A circuit to find the final state of. Return type
 Raises
NotImplementedError – If the circuit contains measurements before the final cycle.

operator
(circuit)¶ Returns the unitary or superoperator that results from simulating the given circuit.
If this simulator contains only unitary errors and pure state preparations, a unitary will be simulated and returned, otherwise, a superoperator will be simulated and returned.
import trueq as tq # make a circuit with two clock cycles circuit = tq.Circuit([{(0, ): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) # simulate the circuit to find the final unitary u = tq.Simulator().operator(circuit) tq.visualization.plot_mat(u.mat()) # if we add depolarizing noise we get a superoperator s = tq.Simulator().add_depolarizing(0.01).operator(circuit) print("Super operator shape: ", s.mat().shape)
Super operator shape: (16, 16)
 Parameters
circuit (
Circuit
) – A circuit to find the final operator of. Returns
The effective operator of the circuit after simulation.
 Return type
 Raises
NotImplementedError – If the last cycle in the circuit contains measurements on some qubits but not all.

sample
(circuit, n_shots=50)¶ Samples ditstrings from the final state of the simulated circuit. In contrast to
run()
, this method does not update the results of the circuit.import trueq as tq # make a circuit with two clock cycles and a measurement round circuit = tq.Circuit([{(0, ): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) circuit.measure_all() # instantiate a simulator with depolarizing and overrotation noise sim = tq.Simulator().add_depolarizing(0.01).add_overrotation(0.04) # sample 100 shots from the final state of the circuit print(sim.sample(circuit, 100))
Results({'00': 53, '11': 47})
 Parameters
circuit (
Circuit
) – A single circuit.n_shots (
int
float("inf")
) – The number of shots to sample. The final state of the circuit is simulated once and shots are drawn from the resulting probability distribution. Or, if this value is infinitylike (e.g.float("inf")
ornumpy.inf
) then results are populated with the exact simulated probabilities.
 Return type

run
(circuits, n_shots=50, overwrite=None, max_workers=1)¶ Updates the
results
attribute of each given circuit by simulating its final quantum state and sampling shots from it.import trueq as tq # make a circuit with two clock cycles and a measurement round circuit = tq.Circuit([{(0, ): tq.Gate.h}, {(0, 1): tq.Gate.cnot}]) circuit.measure_all() # initialize a simulator with no noise sim = tq.Simulator() # run the circuit on the simulator 100 times to populate the results sim.run(circuit, n_shots=100) print(circuit.results) # instantiate a simulator with depolarizing and overrotation noise sim = tq.Simulator().add_depolarizing(0.01).add_overrotation(0.04) # we can also use run to evaluate circuit collections generated by protocols # like CB, SRB, IRB, and XRB on a simulator: circuits = tq.make_srb([0], [5, 50, 100], 30) sim.run(circuits, n_shots=100) circuits.plot.raw()
Results({'00': 55, '11': 45})
 Parameters
circuits (
Circuit
Iterable
) – A single circuit or an iterable of circuits.n_shots (
int
float("inf")
) – The number of shots to sample. The final state of the circuit is simulated once and shots are drawn from the resulting probability distribution. Or, if this value is infinitylike (e.g.float("inf")
ornumpy.inf
) then results are populated with the exact simulated probabilities.overwrite (
bool
None
) – IfFalse
, a circuit that already has results will have new simulation results added to the old results. IfTrue
orNone
, old results will be erased and replaced with new results, though a warning will be raised in the latter case ofNone
(default).max_workers (
int
None
) – The maximum number of workers to use when parallelizing this simulation over circuits. A value ofNone
defaults to the number of processors on the machine. This feature is not available on Windows, which defaults to serial simulation.

CircuitPropagator¶

class
trueq.simulation.simulator.
CircuitPropagator
(obj, noise_sources)¶ A helper class to
Simulator
that abstracts the logic of iterating through the cycles of a circuit and applying noise sources to whatever kind of state is provided.During initialization of this class, the constructor checks if any of the
NoiseSource
s added to the simulator have specified required dimensions via the noise source’s dimension,dim
, and ensures they match the subsystem dimensions of theCircuit
to be simulated. If there is a dimension mismatch, and error will be raised. An additional error will be raised if a measurement occurs before the last cycle within the circuit.Each noise source will, in order, attempt to create a cache of information about the circuit. For more information, see
make_circuit_cache()
. Parameters
 Raises
ValueError – If
obj
isn’t recognized as a circuit or a cycle, and if aNoiseSource
has a specified dimension which does not match the subsystem dimensions ofobj
.NotImplementedError – If there are measurements before the last cycle of a circuit.

propagate
(state)¶ Cycle by cycle, this function gives each noise source, in order, the opportunity to mutate the
state
, effectively simulating theCircuit
. Parameters
state (
StateTensor
OperatorTensor
) – The initial state undergoing propagation. Returns
The final state at the end of simulation.
 Return type
 Raises
NotImplementedError – If a measurement is found in a cycle prior to the last cycle in the circuit.
Match¶

class
trueq.simulation.match.
Match
(exclusive=False)¶ A class whose purpose is to filter the operations presented to a given
NoiseSource
in aSimulator
instance. This is typically used by a noise source to specify, for example, which gate, label, and cycle combinations to apply noise to. This base class is a passthrough that does not do any filtering except the following which is common to all noise sources:Any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
The match also defines
iter_*
functions, which are called byNoiseSource
s, and return an iterator of pairs ofOperation
s and labels (tuple
s). The noise source function called during propagation,apply()
, does not calliter()
directly, which returns an iterator ofOpWrappers
, but instead calls to the match via theiter_*
wrapper functions, meaning that aNoiseSource
does not (and should not) need to interact with aOpWrapper
.Two or more matches can be joined together with
&
(AndMatch
) and
(OrMatch
) that restrict operations to the intersection of matches, or the union of matches, respectively. This is seen in the following examples:import trueq as tq import trueq.simulation as tqs # Create a match that matches only X gates. noisy_x = tqs.GateMatch(tq.Gate.x) # Create a match that matches only Y gates. noisy_y = tqs.GateMatch(tq.Gate.y) # Create a match that matches any operation acting on a subset of labels # (2, 4). noisy_labels = tqs.LabelMatch((2,4)) # Single label matches can send in the label as an integer instead of a tuple # of length 1. This match matches all operations on qubit 0. zero_match = tqs.LabelMatch(0) # A match which prevents subsequent noise sources from seeing operations # that are matched with this one. no_more_match = tqs.Match(exclusive=True) # Create a match that restricts to X gates and any gate on qubits 2 and 4 noise_restriction = tqs.OrMatch(noisy_x, noisy_labels) # Equivalently, we can use ```` noise_restriction = noisy_x  noisy_labels # Create a match that restricts to X gates only on qubits 2 and 4 noise_restriction = tqs.AndMatch(noisy_x, noisy_labels) # Equivalently, we can use ``&`` noise_restriction = noisy_x & noisy_labels # Create a match that restricts to Y gates on qubits 2 and 4, and any X gates compound_match = (noisy_y & noisy_labels)  noisy_x # The following produce equivalent match behavior: equiv1 = noisy_x  noisy_y equiv2 = tqs.GateMatch([tq.Gate.x, tq.Gate.y])

iter
(op_type, cycle_wrapper, noise_only=True, update_flags=True)¶ Iterates through the operations in the
cycle_wrapper
, yielding every operation of typeop_type
that is matched by this instance and that has not yet been marked for no further simulation viaOpwrapper.no_more_noise
. Parameters
op_type (
Gate
Meas
Prep
) – The type ofOperation
to extract from thecycle_wrapper
.cycle_wrapper (
CycleWrapper
) – The cycle to match against.noise_only (
bool
) – Whether to mark theOpWrapper
ashas_been_simulated
after it has been yielded.update_flags (
bool
) – Whether to mutateOpWrapper
flags when an operation is yielded. Only composite matches such asAndMatch
should consider setting this toFalse
.
 Returns
An iterator of
OpWrapper
s with operations of typeop_type
 Return type
Iterable

iter_gates
(cycle_wrapper, noise_only=True)¶ Yields pairs
(labels, gate)
in the givencycle_wrapper
wheregate
is aGate
that is matched by this instance. Parameters
cycle_wrapper (
CycleWrapper
) – The cycle to match against.noise_only (
bool
) – Whether to mark theOpWrapper
ashas_been_simulated
after it has been yielded.
 Returns
An iterator of labels and operators.
 Return type
Iterable

iter_meas
(cycle_wrapper, noise_only=True)¶ Yields pairs
(labels, meas)
in the givencycle_wrapper
wheremeas
is aMeas
that is matched by this instance. Parameters
cycle_wrapper (
CycleWrapper
) – The cycle to match against.noise_only (
bool
) – Whether to mark theOpWrapper
ashas_been_simulated
after it has been yielded.
 Returns
An iterator of labels and operators.
 Return type
Iterable

iter_prep
(cycle_wrapper, noise_only=True)¶ Yields pairs
(labels, prep)
in the givencycle_wrapper
whereprep
is aPrep
that is matched by this instance. Parameters
cycle_wrapper (
CycleWrapper
) – The cycle to match against.noise_only (
bool
) – Whether to mark theOpWrapper
ashas_been_simulated
after it has been yielded.
 Returns
An iterator of labels and operators.
 Return type
Iterable

class
trueq.simulation.match.
AndMatch
(*matches, exclusive=None)¶ Instances of this class match operations that match the intersection of the given
matches
. Operations are matched as follows:Any operation that matches all of the given
matches
.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.

class
trueq.simulation.match.
AssociativeMatch
(*matches, exclusive=None)¶ Abstract parent class for children
C
that store a list ofMatch
es and have the property thatC([A, C([B, C]))
andC([A, B, C])
share the same behaviour. This flattening process is performed automatically by the constructor whenAssociativeMatches
of the same type are encountered.

class
trueq.simulation.match.
CycleMatch
(*cycles, ignore_marker=True, ignore_id=False, exclusive=False)¶ Instances of this class match all operations in a given cycle that are equivalent to one of the cycles owned by this instance. By default, cycle equivalence means cycle equality, but the boolean arguments
ignore_marker
andignore_id
allow three more variants of cycle equivalence. Operations are matched as follows:All operations in a cycle if the cycle is equivalent to one of
cycles
.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
 Parameters
cycles (
Cycle
) – One or more cycles to match against.ignore_marker (
bool
) – Whether to ignore the marker values of cycles. Default isTrue
.ignore_id (
bool
) – Whether to treat all identity gates as though they are not present. Default isFalse
.exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped.

class
trueq.simulation.match.
GateMatch
(gates, exclusive=False)¶ Instances of this class match a fixed set of gates. Operations are matched as follows:
Any gate in
gates
.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.

class
trueq.simulation.match.
LabelMatch
(labels, strict=True, exclusive=False)¶ Instances of this class match operations whose qubit labels correspond to a specified set of labels. Operations are matched as follows:
If
strict
is true, operations whose labels are a strict subset of this instance’s labels are yielded.If
strict
isFalse
, operations whose labels have some intersection with this instance’s labels are yielded.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
For example, a
LabelMatch
initialized with the label 0 will match to single qubit operations on label 0, regardless of the value ofstrict
. Ifstrict
isFalse
, it will also match to any multiqubit operations on label 0, like a CNOT gate over labels 0 and 1. Parameters
labels (
tuple
) – A tuple of integers representing the labels to be matched.strict (
bool
) – Determines if label matching is performed by subset or by intersection.exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped.

class
trueq.simulation.match.
NQubitMatch
(n_sys, exclusive=False)¶ Instances of this class match operations that act on only
n_sys
qubit labels. Operations are matched as follows:All operations that act on a
n_sys
qubit labels.Any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
 Parameters
n_sys (
int
) – An integer defining the number of qubit labels upon which an operator must act on order to be matched by this instance.exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped.

class
trueq.simulation.match.
NativeMatch
(name, exclusive=False)¶ Instances of this class match operations that are
NativeGate
s with a specifiedname
. Operations are matched as follows:Any native gate with a name that matches
name
is returned.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
The following example showcases this behavior:
import trueq as tq import trueq.simulation as tqs # match all native gates with the name "rz" match = tqs.NativeMatch("rz")
 Parameters
name – A string for matching to names of native gates.
exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped.

class
trueq.simulation.match.
OrMatch
(*matches, exclusive=None)¶ Instances of this class match operations that match the union of the specified set of
matches
. Operations are matched as follows:Any operation that matches any of the given
matches
.However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.

class
trueq.simulation.match.
R90Match
(exclusive=False)¶ Instances of this class match qubit gates that can be represented as a 90 degree rotation about an axis within the XY plane. Operations are matched as follows:
Any qubit gate that is a 90 degree rotation about an axis within the XY plane.
However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
 Parameters
exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped. Raises
RuntimeError – Throws an error if the cycle is not from a qubit circuit.

class
trueq.simulation.match.
SingleQubitMatch
(exclusive=False)¶ Instances of this class match operations that act on only a single qubit label. Operations are matched as follows:
All operations that act on a single qubit label.
However, any presented
OpWrapper
whereno_more_noise
isTrue
is skipped.
 Parameters
exclusive (
bool
) – Whether to mark every operation yielded during iteration asno_more_noise
. In any future iterations by anyMatch
an operation with this marking will be skipped.
NoiseSource¶

class
trueq.simulation.add_common.
GateReplaceNoise
(fn, match=None)¶ A noise source that replaces all valid
Gate
s present in the circuit with the returned valued offn
; seeadd_gate_replace()
for details. Parameters
fn (
function
) – A function which takes in a gate and returns a gate with the same dimensions.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Raises
ValueError – If the new gate does not match the dimensions of the gate that it is replacing.

apply
(cycle_wrappers, state, cache)¶ Applies
fn
to every matched gate in the cycle, and then attempts to apply the new gate to the state. The gate returned byfun
must match the dimensions of the gate it replaces. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.state (
StateTensor
OperatorTensor
) – The state to propagate.cache (
dict
) – A dictionary to cache results in.
 Raises
ValueError – If the new gate does not match the dimensions of the gate that it is replacing.

class
trueq.simulation.add_common.
KNRNoise
(fit_or_circuits, exclusive=False, ignore_identity=False, ignore_marker=True)¶ A noise source which reconstructs the noise of each cycle for each KNR experiment in
fit_or_circuits
; see the KNR guide andadd_knr_noise()
for details. Parameters
fit_or_circuits (
EstimateCollection
CircuitCollection
) – An estimate collection or a set of circuits which contain estimates of or circuits for the KNR protocol.exclusive (
bool
) – IfTrue
, all gates within the targeted cycles will be marked asno_more_noise
during simulation. This isFalse
by default.ignore_identity (
bool
) – Whether or not to match this noise to cycles containing identical operations, ignoring any identity operators. This isFalse
by default.ignore_marker (
bool
) – IfTrue
, match this noise to cycles which contain the same operations but have differet markers. This isTrue
by default.
 Raises
ValueError – If a cycle in the
fit_or_circuits
appears in the fit multiple times, or if the fit is empty.

static
knr_superop
(estimate)¶ Determines the
Superop
representing the onebody noise acting on the gatebody estimated byestimate
, as fitted by the KNR protocol. The superoperator is given by a Pauli transfer matrix, seefrom_ptm()
for more information. Parameters
estimate (
NormalEstimate
) – The estimate containing the fit information for the gatebody. Returns
The reconstructed superoperator for the KNR estimate.
 Return type

apply
(cycle_wrappers, state, cache)¶ Applies the computed Pauli transfer matrix superoperator to each
Cycle
within theCircuit
whose KNR results were used to instantiate this instance. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.cache (
dict
) – A dictionary to cache results in.

class
trueq.simulation.add_common.
KrausNoise
(kraus_ops, match=None, dim=2)¶ A noise source that adds Kraus noise; see
add_kraus()
for details. On initialization, the constructor copies and reshapes the Kraus operators to prepare for direct application to the state as a superoperator. Parameters
kraus_ops (
Iterable
) – An iterable of square matrices, each of which must be the same size, and acting on subsystems of dimensiondim
.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.dim (
int
) – An integer representing the dimension of the subsystem upon which the Kraus operators act.dim
is 2, representing qubits, by default.
 Raises
ValueError – If
kraus_ops
has the wrong dimension or is not a list of square matrices of the same dimension.

apply
(cycle_wrappers, state, cache)¶ Applies the Kraus operators to the state on each label containing gates that match with
match
. If it encounters a multi qubit gate, and does not have Kraus operators specifically defined for the number of subspaces upon which the gate acts, then it will apply single qubit Kraus operators to each subsystem instead. This noise source does not attempt to simulate the gates in the cycle. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.state (
StateTensor
OperatorTensor
) – The state to propagate.cache (
dict
) – A dictionary to cache results in.
 Raises
ValueError – If a multiqubit Kraus channel matches to a multiqubit gate with a larger dimension.

class
trueq.simulation.add_common.
OverrotationNoise
(single_sys, multi_sys, match=None)¶ A noise source that adds overrotation, a unitary error; see
add_overrotation()
for details. Parameters
single_sys (
float
) – The amount of overrotation to add to single qubit gates, computed by exponentiating the target gate by 1 +single_sys
.multi_sys (
float
) – The amount of overrotation to add to multi qubit gates, computed by exponentiating the target gate by 1 +multi_sys
.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.

apply
(cycle_wrappers, state, cache)¶ Applies all the gates that match with
match
to the state, with overrotation. Gates are cached on first application, and read from the cache thereafter. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.state (
StateTensor
OperatorTensor
) – The state to propagate.cache (
dict
) – A dictionary to cache results in.

class
trueq.simulation.add_common.
RelaxationNoise
(t1, t2, t_single, t_multi, excited_pop=0, match=None)¶ A noise source that adds relaxation noise, a noise restricted to qubits; see
add_relaxation()
for details. Relaxation noise simulates a \(T_1\) and \(T_2\) process on the qubits, in an idealized manner assuming that gates happen instantaneously, and that the relaxation occurs before any ideal operation is simulated. Parameters
t1 (
float
dict
) – The \(T_1\) time, i.e. the characteristic time of relaxation.t2 (
float
dict
) – The \(T_2\) time, i.e. the characteristic time of dephasing.t_single (
float
) – The idealized time it takes for single qubit cycles to run.t_multi (
float
) – The idealized time it takes for multi qubit cycles to run.excited_pop (
float
dict
) – The excited state population at equilibrium.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.

make_circuit_cache
(circuit)¶ Instantiates a cache object that will be made available to
apply()
ascircuit_cache
for each call within the circuit. The cache is typically a dictionary that stores information about the circuit that is needed byapply()
but not available in individual cycles of the circuit, such as all of the labels the circuit acts on.A relaxation noise source will attempt to apply noise on all qubits present in the circuit, even if they do not have an operation acting on them during a particular cycle. Thus this cache contains all of the labels the circuit acts on.
 Parameters
circuit (
Circuit
) – The circuit being simulated by the (noisy) simulator. Returns
A dictionary of circuit information.
 Return type
dict

static
relaxation_channel
(t1, t2, t, excited_pop)¶ Determines and returns the superoperator for a relaxation channel by computing the choi representation, and casting it to a superoperator.
 Parameters
t1 (
float
dict
) – The \(T_1\) time, i.e. the characteristic time of relaxation.t2 (
float
dict
) – The \(T_2\) time, i.e. the characteristic time of dephasing.t (
float
) – The time that the channel is applied for.excited_pop (
float
dict
) – The excited state population at equilibrium.
 Return type
numpy.ndarray
 Raises
ValueError – Raises when \(T_1\) and \(T_2\) are physically invalid, or if
excited_pop
is a not a valid probability.

apply
(cycle_wrappers, state, cache)¶ Applies relaxation noise to all qubits in the circuit. If
match
finds any multi qubit gates within the cycle, the entire cycle takest_multi
amount of time. Otherwise, the cycle is assumed to taket_single
amount of time. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.cache (
dict
) – A dictionary to cache results in.

class
trueq.simulation.add_spam.
POVMNoise
(povm, match=None)¶ A noise source that adds POVM noise on a measurement; see
add_povm()
for details. Since measurement can only occur during the last cycle of a circuit, this noise source will only attempt to apply itself during a measurement cycle. Parameters
 Raises
NotImplementedError – If the match is not
None
.

apply
(cycle_wrapper, state, cache)¶ Applies all gates in the last of the given
cycle_wrappers
that have not yet been simulated to the given state. This method defines ideal simulation, which children will typically overload to add noise. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. These are all given to allow nonMarkovian noise; typically only the last will be used.state (
StateTensor
OperatorTensor
) – The state of the simulation. This can either represent the quantum state of the simulated circuit thus far, or the operator which describes the action of the simulated circuit thus far.circuit_cache (
dict
) – Cached information about the circuit.

class
trueq.simulation.add_spam.
PrepNoise
(state, match=None)¶ A noise source that adds state preparation error; see
add_prep()
for details. A preparation noise source can indicate a dictionary of labels and target noisy states, a single target noisy state, or a probability representing a classically mixed state as the noisy target. Only the preparation objects that match with the condition(s) ofmatch
will be affected. If a single state/probability is provided, it will be stored with aNone
key, and will apply this noise source to all valid preparation object returned bymatch
. Parameters
state (
dict
StateTensor
float
) – A state or a dictionary of(labels, states)
defining the state preparation error. A probability in place of a state represents a classically mixed state of the same probability.match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.
 Raises
ValueError – If dimensions are inconsistent during state preparation, or the bitflip probability is not a valid probability.

apply
(cycle_wrappers, state, cache)¶ Applies the preparation noise to the state, by checking if each matched label from
match
corresponds to a label within the initializedstates
, or ifNone
is encountered as a key, the preparation noise will be applied to all matched labels. The effective superoperator is the partial trace over matched subsystems, tensored together withstates
in the traced out subsystems. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. This noise source only uses the last one.state (
StateTensor
) – The state to propagate.cache (
dict
) – A dictionary to cache results in.

class
trueq.simulation.noise_source.
NoiseSource
(match=None, dim=None)¶ Parent class for all built in noise sources which can be added to the simulator. A noise source comprises a method
apply()
that mutates the state of simulation by inspecting a given cycle, aMatch
instance for filtering which operations in the cycle to consider, a cache for storing saved calculations that persists for the lifetime of the noise source, and an optional attributedim
for explicitly defining the allowed subsystem dimension.Generally, a
NoiseSource
is added to a simulator, and then during circuit propagation it has an opportunity to apply noise cycle by cycle. Within the simulation of each cycle, a noise source can either simply add noise, or additionally attempt to simulate some of the operations within a cycle. A default noise source is always included in theSimulator
to ensure that all gates within a cycle that are not simulated by a user append noise source are eventually simulated ideally. Parameters
match (
Match
None
) – A match object which determines the conditions required for a noise source to attempt to apply itself to the state during simulation.dim (
int
None
) – The subspace dimension expected by a noise source, orNone
, if there is no needed restriction to a particular subspace dimension.

property
dim
¶ Returns the Hilbert space dimension of each subsystem expected by this propagator. If the dimension is set to
None
, then the noise source does not care about the dimension of a given subsystem. Otherwise, the dimension is an integer, and the noise source can use this information to assert that it can be applied correctly during simulation. Returns
The expected dimension of subsystems as an integer, or
None
. Type
int
 None

property
match
¶ The
Match
instance owned by this noise source. This object is typically used byapply()
to filter which cycle operations are presented to it.For example, the noise source can be initialized with a match on gates, defined by an instance of
GateMatch
initialized with a list of gates. In this case, the noise source will only have the opportunity to apply itself to the state whenever one of these gates appears.

make_circuit_cache
(circuit)¶ Instantiates a cache object that will be made available to
apply()
ascircuit_cache
for each call within the circuit. The cache is typically a dictionary that stores information about the circuit that is needed byapply()
but not available in individual cycles of the circuit, such as all of the labels the circuit acts on. Parameters
circuit (
Circuit
) – The circuit being simulated by the (noisy) simulator. Returns
A dictionary of circuit information.
 Return type
dict

apply
(cycle_wrappers, state, circuit_cache)¶ Applies all gates in the last of the given
cycle_wrappers
that have not yet been simulated to the given state. This method defines ideal simulation, which children will typically overload to add noise. Parameters
cycle_wrappers (
list
) – AllCycleWrapper
s from the beginning of the circuit up until the current cycle in the simulation. These are all given to allow nonMarkovian noise; typically only the last will be used.state (
StateTensor
OperatorTensor
) – The state of the simulation. This can either represent the quantum state of the simulated circuit thus far, or the operator which describes the action of the simulated circuit thus far.circuit_cache (
dict
) – Cached information about the circuit.
OpWrapper¶

class
trueq.simulation.match.
OpWrapper
(labels, op)¶ Wraps labels and an
Operation
into one small object. The wrapper keeps track of whether or not it has been simulated viahas_been_simulated
, which is marked asTrue
during cycle propagation within a simulation by aNoiseSource
'sMatch
when it simulates the action of the operation on the state. Further, it keeps track of whether some noise source has indicated that no further noise should be applied viano_more_noise
, and is primarily modified by setting theexclusive
variable defined in aMatch
toTrue
.Two
OpWrapper
s are equal if and only if all four of their properties are equal. That is, the labels and operations must be equal, as well as the state of their flags,has_been_simulated
andno_more_noise
.
CycleWrapper¶

class
trueq.simulation.match.
CycleWrapper
(cycle)¶ Wraps a
Cycle
into a list ofOpWrapper
s, partitioning the cycle ops into three groups,Gate
which contains all gates,Meas
which contains all measurements, andPrep
which contains all state preparations in the cycle being propagated by the simulator. The wrapper also contains theCycle
itself, as well as its dimension viadim
.A
CycleWrapper
can be asked to return all gates which have not yet been simulated viafinal_iter()
, serving as a final catch during cycle propagation, and is utilized by the parent class of noise sources,NoiseSource
during the call ofapply()
. Parameters
cycle (
Cycle
) – The cycle being wrapped.