# 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.

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

- 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.

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

- 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.

- 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)

- 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)

- 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)

- 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]))] sim = tq.Simulator().add_kraus(kraus_ops)

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

- 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 sim = tq.Simulator().add_readout_error(0.005) # all qubits get a 1% readout error, except qubit 1 gets a 3% readout error sim = tq.Simulator().add_readout_error({None: 0.01, 1: 0.03}) # all qubits get a 1% readout error, except qubit 1 gets a 4% readout error, and # qubit 3 gets an asymmetric readout error of 1% on |0> and 8% on |1> sim = tq.Simulator().add_readout_error({None: 0.01, 1: 0.04, 3: [0.01, 0.08]})