True-Q™ includes a built-in Simulator that can be configured with custom or pre-defined noise models. Noise models can define gate and cycle noise, as well as preparation and measurement noise. A simulator object can be used to:

  1. Simulate the final quantum state of a circuit. This will be a pure state vector if the noise model is ideal or has only unitary noise, and will be a density matrix otherwise.

  2. Simulate the total effective operator of a circuit. This will be a unitary matrix if the noise model is ideal or has only unitary noise, and will be a superoperator otherwise.

  3. Sample a given number of bitstrings (or ditstrings if higher energy levels are defined) from the distribution defined by the final simulated quantum state of a circuit. These results can be returned, or can be automatically populated into the respective results attributes of the given circuits.

Noise Models

A Simulator instance owns an ordered list of noise models. There are a number of built-in noise models that can be chained together in a single simulator instance as follows:

import trueq as tq

# make a simulator that first overrotates single qubit gates by 0.03, and then
# adds stochastic error in the X direction
sim = tq.Simulator().add_overrotation(0.03).add_stochastic_pauli(px=0.02)

Demonstrations of adding custom noise models can be found in the examples at the bottom of this page. A noise model is defined as a function that accepts a Cycle to simulate and the current state of simulation, and mutates the current state of simulation based on the cycle. Here, the “state of simulation” is a generalized notion of state and can refer to either:

  • A StateTensor which can store either a pure state or a mixed state. Anytime it represents a pure state and a noise model asks it to update by a non-unitary operation, it casts itself into a mixed state.

  • A OperatorTensor which can store either a unitary or a superoperator. Anytime it represents a unitary and a noise model asks it to update itself by a non-unitary operation, it casts itself into a superoperator.

During the simulation of a circuit, the simulator iterates through cycles and passes each cycle to each noise model in turn. The order is defined by the order in which they are added to the simulator, with two exceptions:

  1. Preparation noise takes place before any other noise, and a simulator can only have one source of preparation noise (noise is flagged as being preparation noise when it is added to the simulator, usually under the hood).

  2. Measurement noise happens after any other noise source. Note that measurements are currently only supported in the last cycle of a circuit.

Advanced Note

The following note is included for advanced users of the simulator and for the benefit of users who are interested in writing their own noise model.

Every simulator has one special noise source whose job is to attempt to actually simulate the cycle at hand. Indeed, if no noise sources tried to simulate the gates, it would not really be a simulation of the circuit, and if more than one of the noise sources tried to simulate the circuit, the end result would be quite incorrect. Therefore, every noise source defines a flag that specifies whether it is the kind of noise source that tries to actually implement the cycles it finds, as opposed to only injecting noise. For example, add_overrotation() sets this flag to True because it implements gates as \(U^{1+\epsilon}\) which is an attempt to actually implement \(U\), but add_depolarizing() sets this flag to False because it just adds a small perturbation to the state or superoperator during each cycle.

If no noise sources in a simulator have this flag as true then an “ideal noise source” is automatically prepended to the noise list. This “noise source” simulates the gates it sees and adds no noise. Therefore, for example, if it is of interest to add a noise source that precedes the cycle in question (rather than the default of following the cycle in question), then an ideal noise source could be manually added to the simulator after the actual noise source.

import trueq as tq
import warnings

# If more than one noise source is added whose flag is true, a warning is raised, as
# in the following example.
bad_sim = tq.Simulator()
with warnings.catch_warnings():
    bad_sim.add_overrotation(0.01, noisy_gates=tq.Gate.x)
    bad_sim.add_overrotation(0.02, noisy_gates=tq.Gate.y)

# In the example above, it happens to be easy to get around the problem by noting
# that we can use Kraus maps with one unitary operator as overrotation noise
good_sim = tq.Simulator()
good_sim.add_kraus([(tq.Gate.x ** 0.01).mat], noisy_gates=tq.Gate.x)
good_sim.add_kraus([(tq.Gate.y ** 0.02).mat], noisy_gates=tq.Gate.y)
<trueq.simulation.simulator.Simulator at 0x7fdc37ad4160>



Simulator: Introduction


Simulator: State Preparation and Measurement Noise


Simulator: Adding Leakage