# Built-In Simulator¶

After defining a circuit or generating a circuit collection, the next step is to run it on a simulator or a quantum device. True-Qᵀᴹ includes a built-in Simulator that can be configured with custom or pre-defined noise models.

1. Generate circuits

The first step, before using a Simulator to simulate a Circuit or CircuitCollection, is to define the ideal version of the circuit(s) to be run. In this example, we will write a custom Circuit with an X gate acting on the $$0^{th}$$ qubit, followed by a controlled-Z gate on qubits 1 and 2 at the same time as a Y gate acts on the $$0^{th}$$ qubit:

import tq as trueq

circuit = tq.Circuit([{(0, ):tq.Gate.x}, {(0, ): tq.Gate.y, (1, 2):tq.Gate.cz}])

2. Initialize a Simulator

The next step is to initialize a Simulator, and (optionally) add noise. In this example we will not add noise; for a noisy implementation, see this example or other examples. To initialize a simulator, run:

sim = tq.Simulator()

3. Add Noise (Optional)

To simulate a noisy implementation of a Circuit or CircuitCollection, a noise process should be added to the simulator prior to running the circuit(s). The following code adds depolarizing noise to the Simulator initialized in step 2.

sim.add_depolarizing(p = 0.001)


See Noise for details about the True-Qᵀᴹ SDK suite of noise models.

4. Add an initial state (Optional)

By default, every qubit will initialize in the $$|0\rangle$$state. To prepare a different initial state, use add_prep(). An initial state can be specified by a $$d\times d$$ density matrix or a length $$d$$ vector representing a pure state. The following code specifies the initial state of qubit 1.

sim.add_prep({1: [[0.8, 0.1], [0.1, 0.2]]})

5. Run the Simulation

The final step is to run the Circuit or CircuitCollection on the simulator. The following line of code runs the simulation and accordingly populates the results of the circuit with 100 shots.

sim.run(circuit, n_shots = 100)


## Noise¶

The True-Qᵀᴹ SDK includes several functions for adding noise to a Simulator, including some common noise models and the option to define a custom noise process using Kraus operators. Some noise models, such as add_depolarizing, add_stochastic_pauli, add_overrotation, and add_kraus have options to target only certain qubits or gates with noise. Alternatively, when no qubit labels or gates are provided, the noise acts on every gate-filled location in a circuit.

1. Depolarizing

The add_depolarizing function adds depolarizing noise to a simulator. The following code initializes a Simulator with depolarizing noise with depolarizing parameter $$p = 0.03$$ acting independently and isotropically on every gate-filled location in a circuit.

sim = tq.Simulator().add_depolarizing(p = 0.03)

2. Stochastic Pauli

The add_stochastic_pauli function adds a stochastic pauli noise to a simulator. The following code initializes a simulator with stochastic pauli noise acting on every gate-filled location in a circuit, where the probability of an $$X$$, $$Y$$, and $$Z$$ error are $$px = 0.01$$, $$py = 0.02$$, and $$pz = 0.03$$, respectively.

sim = tq.Simulator().add_stochastic_pauli(px = 0.01, py = 0.02, pz = 0.03)

3. Overrotation

The add_overrotation function adds an overrotation error. The angle of overrotation can be specified separately for single and multi-qubit gates, for specific gate labels, or for specific qubit labels. The following code initializes a Simulator with an overrotation by $$\epsilon=0.01$$ to every location where a single qubit gate acts and an overrotation by $$\epsilon=0.05$$ to every location where a multi-qubit gate acts.

sim = tq.Simulator().add_overrotation(single_sys=0.01, multi_sys=0.05)

4. Custom Kraus

The add_kraus allows users to add custom noise to a simulator, specified by Kraus operators. The following code initializes a Simulator with amplitude damping noise constructed from Kraus operators acting independently and isotropically on every gate-filled location in a circuit, with a decay probability of $$p = 0.01$$.

import numpy as np

p = 0.01
kraus_ops = [np.sqrt(np.array([[0, p], [0, 0]])), np.sqrt(np.diag([1, 1-p]))]

5. State preparation errors

The add_prep method customizes the preparation of quantum registers. This can be used to set preparations to a specific pure or mixed state, or to add simple bitflip error.

# add 1% bitflip error by default, but 6% for qubits 2 and 3
sim = tq.Simulator().add_prep({None: 0.01, 2: 0.06, 3: 0.06})

# 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]]})

# prepare all qubits in the |+> state
sim = tq.Simulator().add_prep([1 / np.sqrt(2), 1 / np.sqrt(2)])

6. Measurement errors

The trueq.Simulator.add_readout_error method allows users to add measurement errors to a simulator.

# all qubits get a 0.5% readout error