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