Download
Download this file as Jupyter notebook: intro.ipynb.
Example: Introduction to the Simulator
True-Q™ offers a highly versatile Simulator
that allows
users to simulate arbitrary circuits with a wide variety of noise models and options
for noise model customization. In particular, the simulator can be used to:
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.
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.
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.
In this example, we go through the basic features of the True-Q™ simulator. We begin by instantiating a circuit to play with:
[2]:
import numpy as np
import trueq as tq
circuit = tq.Circuit([{0: tq.Gate.x, 1: tq.Gate.y}, {(0, 1): tq.Gate.cz}])
circuit.measure_all()
circuit.draw()
[2]:
Simulator Basics
In its simplest configuration, a (noiseless) simulator can be instantiated from
True-Q™’s Simulator
class as follows:
[3]:
sim = tq.Simulator()
We can use it to simulate the final state of the circuit, with all initial states prepared as \(|0\rangle\) by default. Since the simulator is noiseless, the output state is a pure state; a noisy simulator will generally return a density matrix instead.
[4]:
sim.state(circuit).mat()
[4]:
array([0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j])
If we want to force the output to be a density matrix, we can use:
[5]:
sim.state(circuit).upgrade().mat()
[5]:
array([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.-0.j, 0.-0.j, 0.-0.j, 1.+0.j]])
We can also use it to compute the overall action of the circuit. Since the simulator is currently noiseless, the output is a unitary matrix; a noisy simulator will return a superoperator (in the rowstacked basis).
[6]:
tq.plot_mat(sim.operator(circuit).mat())
Finally, we can use a simulator to populate the results
attribute of the circuit. Currently, this attribute is just an empty dictionary:
[7]:
circuit.results
[7]:
Results({}, dim=None)
But after calling the run()
method, it has
results
that are randomly sampled bitstrings from the final
state of a state simulation:
[8]:
sim.run(circuit, n_shots=100)
circuit.results
[8]:
Results({'11': 100})
In this case, all 100 shots end in the 11
state because the final state is a
computational eigenstate.
When re-running the simulation, it will overwrite the existing
results
unless
otherwise specified. Another option is to call the simulator’s
sample()
method which returns a Results
object directly without affecting the circuit’s results
attribute:
[9]:
results = sim.sample(circuit, n_shots=100)
results
[9]:
Results({'11': 100})
We can also specify infinite shots to get the expectation values of each bitstring:
[10]:
sim.run(circuit, n_shots=np.inf, overwrite=True)
circuit.results
[10]:
Results({'11': 1.0})
Adding Noise Sources
We construct a noisy simulator by appending noise sources to a noiseless simulator. The example below demonstrates this using two of True-Q™'s built-in noise sources:
[11]:
# Add an overrotation noise, which causes single qubit gates to be simulated as U^1.02
sim.add_overrotation(single_sys=0.02)
# Add a depolarizing noise source at a rate of 0.8% per acted-on qubit per cycle
sim.add_depolarizing(p=0.008)
# Note that noisy simulators can be constructed as one-liners
other_sim = tq.Simulator().add_overrotation(single_sys=0.02).add_depolarizing(p=0.008)
Note
Note that simulation is cycle-based.
Each noise source is called to add noise to the quantum state (or to the
superoperator if operator()
is called) for each cycle
in a circuit. The order in which noise sources are applied is dictated by the
order in which they were added to the simulator.
Now, since the simulator applies a depolarizing noise source, we get a density operator rather than a pure state:
[12]:
tq.plot_mat(sim.state(circuit).mat())
After calling the run()
method (overwriting the
results
from above), we end up with noisy outcomes:
[13]:
sim.run(circuit, n_shots=100, overwrite=True)
circuit.results
[13]:
Results({'11': 100})
For more information on both built-in and custom noise sources, check out Example: Advanced Simulator Usage next.
Download
Download this file as Jupyter notebook: intro.ipynb.