Quantum simulator

Download NotebookDownload CodeView source on Gitee


After building the quantum circuit, we need to specify a back end to run the quantum circuit. In MindSpore Quantum, we can use the quantum Simulator ‘Simulator’ to simulate the quantum circuit. In this tutorial we declare a two-bit ‘ProjectQ’ simulator to introduce the key features of the simulator.

Environment preparation

Import the modules that this tutorial depends on.

import numpy as np                             # Import the numpy library and abbreviate to np
from mindquantum.simulator import Simulator    # Import the Simulator class from mindquantum. simulator
from mindquantum.core.gates import X, H, RY    # Import quantum gate H, X, RY


  1. Numpy is a powerful Python library used to perform calculations on multidimensional arrays. It supports a large number of dimensional arrays and matrix operations. It also provides a large number of mathematical function libraries for array operations.

  2. MindSpore Quantum is a quantum-classical hybrid computing framework that supports training and reasoning of various quantum neural networks;

  3. The quantum gate to be executed in the quantum circuit set up needs to be imported from mindquantum. core module;

sim = Simulator('mqvector', 2)  #Declare a two-bit mqvector simulator
sim                             #Display simulator status
mqvector simulator with 2 qubits (little endian).
Current quantum state:

In MindSpore Quantum, we can import the simulator in the ‘mindQuantum. simulator’ module. The ‘Simulator’ class takes three arguments:

  • ‘backend’ : name of the simulator used. Currently, ‘MindSpore Quantum’ supports ‘mqvector’ and ‘mqvector_gpu’ as a backend for emulation.

  • ‘n_qubits’ : The number of bits used by the simulator, which is 2 here.

  • ‘seed’ : the random seed used by the simulator when running the randomness correlation algorithm. By default, the seed is a random number, which is not required.

From the output of the simulator, we can see that this is a 2-bit simulator of ‘mqvector’ and little Endian. Little Endian means that throughout the simulator, we put bits with small bits to the right of the quantum state vector. Next, the output also states what quantum state the simulator is currently in, and after the simulator is initialized, the current quantum state defaults to zero. Note that the quantum simulator always maintains an internal quantum state that changes when we apply a quantum gate or a quantum circuit to the simulator, but does not change when we simply want to obtain some information about the quantum state. There are two types of operations for the quantum simulator:

  • Operations that change the quantum state, usually beginning with ‘apply’, mainly include the following

  • ‘apply_gate’ : applies a quantum gate to the simulator

  • ‘apply_circuit’ : applies a quantum circuit to the simulator

  • ‘apply_hamiltonian’ : Apply a Hamiltonian to the simulator. Note that the quantum state of the simulator is no longer a true quantum state

  • ‘set_qs’ : Sets the current quantum state of the simulator directly

  • reset : reset the state of the simulator to | 0 ⟩ state

  • Operations that do not change the quantum state, usually beginning with ‘get’, mainly include the following

  • ‘get_QS’ : gets the current quantum state of the simulator

  • ‘get_expectation’ : calculates the expected value of the simulator’s current quantum state regarding an observed quantity

  • ‘get_expectation_with_grad’ : similar to the previous interface, except that this method also calculates the expected value gradient with respect to parameterized quantum lines

  • ‘sampling’ : in the current quantum state, sampling of the given quantum circuit

Let’s learn the basic operation of the simulator briefly.

Interacts with quantum gates and quantum circuits

sim = Simulator('mqvector', 2)    #Declare a 2-bit mqvector emulator
sim.apply_gate(H.on(0))           #Apply a Hadamard gate to qubit 0
sim                               #Output quantum simulator information
mqvector simulator with 2 qubits (little endian).
Current quantum state:

Above, we acted a Hadamard gate on the initial state of the quantum simulator and output the quantum state after evolution. Next we generate a parameterized quantum circuit and apply it to the current quantum state.

from mindquantum.core.circuit import Circuit   # Import Circuit module to build quantum Circuit

circ = Circuit()                       # Declare an empty quantum circuit
circ += H.on(1)                        # Add a Hadamard gate to it and apply it to qubit 1
circ += RY('a').on(0)                  # Add a parameterized RY gate to it and apply it to qubit 0
circ.svg()                             # Draws a quantum circuit picture in SVG format
#Apply a quantum circuit. When the circuit is a parameterized quantum circuit, we also need to provide parameter values.
sim.apply_circuit(circ, pr={'a': 1.234})
mqvector simulator with 2 qubits (little endian).
Current quantum state:

In the above code, we create a parameterized quantum circuit ‘circ’, which we then apply to the quantum simulator and set parameter ‘A’ to ‘1.234’ by passing in a dictionary. Finally, the quantum state evolved from the quantum simulator is output.

Set and get the simulator state

We use ‘get_qs(ket=False)’ to check the state of the current simulator, The ket argument is a bool that determines whether the state of the current simulator is returned as a ket, numpy.ndarray when ket=False, or ket when ket=True. The default ket = False.

print(sim.get_qs())  #View the simulator status and return the result in numpy.ndarray form
[0.11851349+0.j 0.69710441+0.j 0.11851349+0.j 0.69710441+0.j]
print(sim.get_qs(True))  #View the simulator status and return the result in ket form

During actual code writing, we often need to specify an initial state for the simulator to start evolving, which can be done using ‘set_qs()’.

For example, we want the emulator state to be


Step 1: We calculate the vector form of the target state:

\[\begin{split}\frac{\sqrt{3}}{3}|00⟩+\frac{\sqrt{6}}{3}|11⟩ =\frac{\sqrt{3}}{3}\times \left( \begin{array}{l} 1\\ 0 \end{array} \right) \otimes \left( \begin{array}{l} 1\\ 0 \end{array} \right)+ \frac{\sqrt{6}}{3}\times \left( \begin{array}{l} 0\\ 1 \end{array} \right)\otimes \left( \begin{array}{l} 0\\ 1 \end{array} \right)= \frac{\sqrt{3}}{3}\times \left( \begin{array}{l} 1\\ 0\\ 0\\ 0 \end{array} \right)+ \frac{\sqrt{6}}{3}\times \left( \begin{array}{l} 0\\ 0\\ 0\\ 1 \end{array} \right)= \left( \begin{array}{l} \frac{\sqrt{3}}{3}\\ 0\\ 0\\ \frac{\sqrt{6}}{3} \end{array} \right)\end{split}\]

Step 2: We assign this vector to the simulator using ‘set_qs()’ as its state:

sim.set_qs(np.array([3**0.5, 0, 0, 6**0.5]))  #Set simulator state without normalization
print(sim.get_qs(True))                       #View simulator Status

Viewing the simulator status through get_qs() can find that the current simulator status is we want to set the \(\frac{\sqrt{3}}{3}|00⟩+\frac{\sqrt{6}}{3}|11⟩\).

In the actual programming process, we often need to simulate the circuit for several times, which will lead to a very large memory consumption by opening the simulator more than once. We can reuse the simulator by resetting the existing simulator, thus reducing the memory consumption.

We use ‘reset()’ to reset the simulator:

sim.reset()          #Reset simulator
print(sim.get_qs())  #View simulator Status
[1.+0.j 0.+0.j 0.+0.j 0.+0.j]

It can be found that the current simulator is reset to the initial \(1|00⟩\) state, which is equivalent to a brand new simulator.

Therefore, we can set up a corresponding quantum simulator and run a custom quantum circuit according to the quantum initial state we need. Get your hands on your first quantum circuit!

Quantum circuit sampling

Circuit sampling refers to performing multiple simulation measurements on quantum circuits, and statistically measuring the frequency of occurrence of various results. Sampling does not change the state in the quantum circuit.

sampling(circuit, pr=None, shots=1, seed=None)is the sampling method provided in MindSpore Quantum, which accepts four parameters:

  • circuit (Circuit):Quantum circuit for which sampling is desired, note that at least one measurement operation (i.e. sampling point) must be included in the circuit.

  • pr (Union[None, dict, ParameterResolver]):parameter resolver,When circuit is a parameterized circuit, the value of the parameter needs to be given.

  • shots (int):The number of times to sample, default 1.

  • seed:The random seed for sampling, which is a random number by default and can be omitted.

# Non-parameterized circuit sampling:
from mindquantum.core.gates import Measure  # Introduce measurement gate

circ = Circuit()                 # Initialize the quantum circuit
circ += H.on(0)                  # The H gate acts on qubit 0
circ += X.on(1, 0)               # The X gate acts on qubit 1 and is controlled by qubit 0
circ += Measure('q0').on(0)      # Apply a measurement on qubit 0 and name this measurement 'q0'
circ += Measure('q1').on(1)      # Apply a measurement to qubit 1 and name this measurement 'q1'
circ.svg()                       # Draw a quantum circuit picture in SVG format
result = sim.sampling(circ, shots=1000)  # Sample the circuit defined above 1000 times
shots: 1000
Keys: q1 q0│0.00    0.13       0.259       0.389       0.518       0.647


{'00': 482, '11': 518}

MindSpore Quantum also provides the function of drawing SVG diagrams from sampling results:

result.svg()  # Print out measurement results in SVG format

We can see that in sampling 1000 times, ‘00’ appears 499 times and ‘11’ appears 501 times. The circuit we built actually produces a Bell state \(\frac{\sqrt{2}}{2}|00⟩+\frac{\sqrt{2}}{2}|11⟩\). Intuitively, we can see that the probability of measuring the state to get ‘00’ is \(\frac{1}{2}\), the probability of getting ‘11’ is \(\frac{1}{2}\), the sampling result consistent with probability, slight errors are caused by simulator noise.

# Parameterized circuit sampling:
para_circ = Circuit()             # Initialize the quantum circuit
para_circ += H.on(0)              # The H gate acts on qubit 0
para_circ += X.on(1, 0)           # The X gate acts on qubit 1 and is controlled by qubit 0
para_circ += RY('theta').on(1)    # The RY(theta) gate acts on the qubit 1
para_circ += Measure('0').on(0)   # Apply a measurement on qubit 0 and name this measurement 'q0'
para_circ += Measure('q1').on(1)  # Apply a measurement to qubit 1 and name this measurement 'q1'
para_circ.svg()                   # Draw a quantum circuit picture in SVG format

# Assign the circuit parameter 'theta' defined above to 0 and sample 1000 times
result = sim.sampling(para_circ, {'theta': 0}, shots=1000)

We can see that ‘00’ appears 495 times and ‘11’ appears 505 times in the sampling result. In fact, the RY gate parameter is assigned to 0, which is the I gate and equivalent to not doing any operation on the circuit. Therefore, the sampling circuit is essentially the same as the above Non-parameterized circuit. It can be observed that the results of two times sampling are almost the same, as expected.

If you want to learn more about how to measure quantum circuits and understand the theoretical explanation of the distribution of sampling results, please click: Quantum Measurement Tutorial.

For more information about MindSpore Quantum API, please click: https://mindspore.cn/mindquantum/.