mindquantum.simulator.Simulator#

class mindquantum.simulator.Simulator(backend, n_qubits=None, *args, seed=None, dtype=None, **kwargs)#

Quantum simulator that simulate quantum circuit.

Parameters:
  • backend (str) – which backend you want. The supported backend can be found in SUPPORTED_SIMULATOR

  • n_qubits (int) – number of quantum simulator. Default: None.

  • seed (int) – the random seed for this simulator, if None, seed will generate by numpy.random.randint. Default: None.

  • dtype (mindquantum.dtype) – the data type of simulator. Default: None.

Raises:
  • TypeError – if backend is not str.

  • TypeError – if n_qubits is not int.

  • TypeError – if seed is not int.

  • ValueError – if backend is not supported.

  • ValueError – if n_qubits is negative.

  • ValueError – if seed is less than 0 or great than \(2^23 - 1\).

Examples

>>> from mindquantum.algorithm.library import qft
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(qft(range(2)))
>>> sim.get_qs()
array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j])
apply_circuit(circuit, pr=None)#

Apply a circuit on this simulator.

Parameters:
  • circuit (Circuit) – The quantum circuit you want to apply on this simulator.

  • pr (Union[ParameterResolver, dict, numpy.ndarray, list, numbers.Number]) – The parameter resolver for this circuit. If the circuit is not parameterized, this arg should be None. Default: None.

Returns:

MeasureResult or None, if the circuit has measure gate, then return a MeasureResult, otherwise return None.

Examples

>>> import numpy as np
>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.core.gates import H
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(Circuit().un(H, 2))
>>> sim.apply_circuit(Circuit().ry('a', 0).ry('b', 1), np.array([1.1, 2.2]))
>>> sim
mqvector simulator with 2 qubits  (little endian).
Current quantum state:
-0.0721702531972066¦00⟩
-0.30090405886869676¦01⟩
0.22178317006196263¦10⟩
0.9246947752567126¦11⟩
>>> sim.apply_circuit(Circuit().measure(0).measure(1))
shots: 1
Keys: q1 q0│0.00     0.2         0.4         0.6         0.8         1.0
───────────┼───────────┴───────────┴───────────┴───────────┴───────────┴
         11│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

{'11': 1}
apply_gate(gate, pr=None, diff=False)#

Apply a gate on this simulator, can be a quantum gate or a measurement operator.

Parameters:
  • gate (BasicGate) – The gate you want to apply.

  • pr (Union[numbers.Number, numpy.ndarray, ParameterResolver, list]) – The parameter for parameterized gate. Default: None.

  • diff (bool) – Whether to apply the derivative gate on this simulator. Default: False.

Returns:

int or None, if the gate if a measure gate, then return a collapsed state, Otherwise return None.

Raises:
  • TypeError – if gate is not a BasicGate.

  • ValueError – if any qubit of gate is higher than simulator qubits.

  • ValueError – if gate is parameterized, but no parameter supplied.

  • TypeError – the pr is not a ParameterResolver if gate is parameterized.

Examples

>>> import numpy as np
>>> from mindquantum.core.gates import RY, Measure
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 1)
>>> sim.apply_gate(RY('a').on(0), np.pi/2)
>>> sim.get_qs()
array([0.70710678+0.j, 0.70710678+0.j])
>>> sim.apply_gate(Measure().on(0))
1
>>> sim.get_qs()
array([0.+0.j, 1.+0.j])
apply_hamiltonian(hamiltonian: Hamiltonian)#

Apply hamiltonian to a simulator, this hamiltonian can be hermitian or non hermitian.

Note

The quantum state may be not a normalized quantum state after apply hamiltonian.

Parameters:

hamiltonian (Hamiltonian) – the hamiltonian you want to apply.

Examples

>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.core.operators import QubitOperator, Hamiltonian
>>> from mindquantum.simulator import Simulator
>>> import scipy.sparse as sp
>>> sim = Simulator('mqvector', 1)
>>> sim.apply_circuit(Circuit().h(0))
>>> sim.get_qs()
array([0.70710678+0.j, 0.70710678+0.j])
>>> ham1 = Hamiltonian(QubitOperator('Z0'))
>>> sim.apply_hamiltonian(ham1)
>>> sim.get_qs()
array([ 0.70710678+0.j, -0.70710678+0.j])
>>> sim.reset()
>>> ham2 = Hamiltonian(sp.csr_matrix([[1, 2], [3, 4]]))
>>> sim.apply_hamiltonian(ham2)
>>> sim.get_qs()
array([1.+0.j, 3.+0.j])
astype(dtype, seed=None)#

Convert simulator to other data type.

Note

The quantum state will copied from origin simulator.

Parameters:
  • dtype (mindquantum.dtype) – the data type of new simulator.

  • seed (int) – the seed of new simulator. Default: None.

copy()#

Copy this simulator.

Returns:

Simulator, a copy version of this simulator.

Examples

>>> from mindquantum.core.gates import RX
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 1)
>>> sim.apply_gate(RX(1).on(0))
>>> sim2 = sim.copy()
>>> sim2.apply_gate(RX(-1).on(0))
>>> sim2
mqvector simulator with 1 qubit (little endian).
Current quantum state:
1¦0⟩
property dtype#

Get data type of simulator.

entropy()#

Calculate the von Neumann entropy of current quantum state.

Definition of von Neumann entropy \(S\) shown as below.

\[S(\rho) = -\text{tr}(\rho \ln \rho)\]

where \(\rho\) is density matrix.

Returns:

numbers.Number, the von Neumann entropy of current quantum state.

Examples

>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqmatrix', 1)
>>> sim.set_qs([[0.5, 0], [0, 0.5]])
>>> sim.entropy()
0.6931471805599453
get_expectation(hamiltonian, circ_right=None, circ_left=None, simulator_left=None, pr=None)#

Get expectation of the given hamiltonian. The hamiltonian could be non hermitian.

This method is designed to calculate the expectation shown as below.

\[E = \left<\varphi\right|U_l^\dagger H U_r \left|\psi\right>\]

where \(U_l\) is circ_left, \(U_r\) is circ_right, \(H\) is hams and \(\left|\psi\right>\) is the current quantum state of this simulator, and \(\left|\varphi\right>\) is the quantum state of simulator_left.

Note

The input circuits only participate in the expectation calculation and will not change the current quantum state of this simulator.

Parameters:
  • hamiltonian (Hamiltonian) – The hamiltonian you want to get expectation.

  • circ_right (Circuit) – The \(U_r\) circuit described above. If it is None, we will use empty circuit. Default: None.

  • circ_left (Circuit) – The \(U_l\) circuit described above. If it is None, then it will be the same as circ_right. Default: None.

  • simulator_left (Simulator) – The simulator that contains \(\left|\varphi\right>\). If None, then \(\left|\varphi\right>\) is assumed to be equals to \(\left|\psi\right>\). Default: None.

  • pr (Union[Dict[str, numbers.Number], ParameterResolver]) – the variable value of circuit. Default: None.

Returns:

numbers.Number, the expectation value.

Examples

>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.core.operators import QubitOperator, Hamiltonian
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 1)
>>> sim.apply_circuit(Circuit().ry(1.2, 0))
>>> ham = Hamiltonian(QubitOperator('Z0'))
>>> sim.get_expectation(ham)
(0.36235775447667357+0j)
>>> sim.get_expectation(ham, Circuit().rx('a', 0), Circuit().ry(2.3, 0), pr={'a': 2.4})
(-0.25463350745693886+0.8507316752782879j)
>>> sim1, sim2 = Simulator('mqvector', 1), Simulator('mqvector', 1)
>>> sim1.apply_circuit(Circuit().ry(1.2, 0).rx(2.4, 0))
>>> sim2.apply_circuit(Circuit().ry(1.2, 0).ry(2.3, 0))
>>> sim1.apply_hamiltonian(ham)
>>> from mindquantum.simulator import inner_product
>>> inner_product(sim2, sim1)
(-0.25463350745693886+0.8507316752782879j)
get_expectation_with_grad(hams, circ_right, circ_left=None, simulator_left=None, parallel_worker=None, pr_shift=False)#

Get a function that return the forward value and gradient w.r.t circuit parameters.

This method is designed to calculate the expectation and its gradient shown as below.

\[E = \left<\varphi\right|U_l^\dagger H U_r \left|\psi\right>\]

where \(U_l\) is circ_left, \(U_r\) is circ_right, \(H\) is hams and \(\left|\psi\right>\) is the current quantum state of this simulator, and \(\left|\varphi\right>\) is the quantum state of simulator_left.

Note

The input circuits only participate in the expectation and gradient calculation and will not change the current quantum state of this simulator.

Parameters:
  • hams (Union[Hamiltonian, List[Hamiltonian]]) – A Hamiltonian or a list of Hamiltonian that need to get expectation.

  • circ_right (Circuit) – The \(U_r\) circuit described above.

  • circ_left (Circuit) – The \(U_l\) circuit described above. By default, this circuit will be none, and in this situation, \(U_l\) will be equals to \(U_r\). Default: None.

  • simulator_left (Simulator) – The simulator that contains \(\left|\varphi\right>\). If None, then \(\left|\varphi\right>\) is assumed to be equals to \(\left|\psi\right>\). Default: None.

  • parallel_worker (int) – The parallel worker numbers. The parallel workers can handle batch in parallel threads. Default: None.

  • pr_shift (bool) – Whether or not to use parameter-shift rule. Only available in “mqvector” simulator. It will be enabled automatically when circuit contains noise channel. Noted that not every gate uses the same shift value π/2, so the gradient of FSim gate and parameterized custom gate will be calculated by finite difference method with gap 0.001. Default: False.

Returns:

GradOpsWrapper, a grad ops wrapper than contains information to generate this grad ops.

Examples

>>> import numpy as np
>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.core.operators import QubitOperator, Hamiltonian
>>> from mindquantum.simulator import Simulator
>>> circ = Circuit().ry('a', 0)
>>> ham = Hamiltonian(QubitOperator('Z0'))
>>> sim = Simulator('mqvector', 1)
>>> grad_ops = sim.get_expectation_with_grad(ham, circ)
>>> grad_ops(np.array([1.0]))
(array([[0.54030231+0.j]]), array([[[-0.84147098+0.j]]]))
>>> sim1 = Simulator('mqvector', 1)
>>> prep_circ = Circuit().h(0)
>>> ansatz = Circuit().ry('a', 0).rz('b', 0).ry('c', 0)
>>> sim1.apply_circuit(prep_circ)
>>> sim2 = Simulator('mqvector', 1)
>>> ham = Hamiltonian(QubitOperator(""))
>>> grad_ops = sim2.get_expectation_with_grad(ham, ansatz, Circuit(), simulator_left=sim1)
>>> f, g = grad_ops(np.array([7.902762e-01, 2.139225e-04, 7.795934e-01]))
>>> f
array([[0.99999989-7.52279618e-05j]])
get_partial_trace(qubits_to_trace)#

Calculate the partial trace of current density matrix.

Parameters:

qubits_to_trace (Union[int, list[int]]) – Specific which qubits (subsystems) to trace over.

Returns:

numpy.ndarray, the partial trace of current density matrix.

Examples

>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.simulator import Simulator
>>> circ = Circuit().h(0).x(1, 0)
>>> sim = Simulator('mqmatrix', 2)
>>> sim.apply_circuit(circ)
>>> mat = sim.get_partial_trace(0)
>>> mat
array([[0.5-0.j, 0. -0.j],
       [0. +0.j, 0.5-0.j]])
get_pure_state_vector()#

Get state vector if current density matrix is pure.

The relation between density matrix \(\rho\) and state vector \(\left| \psi \right>\) shown as below.

\[\rho = \left| \psi \right>\!\left< \psi \right|\]

Note that the state vector \(\left| \psi \right>\) may have an arbitrary global phase \(e^{i\phi}\).

Returns:

numpy.ndarray, a state vector calculated from current density matrix.

Examples

>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqmatrix', 1)
>>> sim.set_qs([[0.5, 0.5], [0.5, 0.5]])
>>> sim.get_pure_state_vector()
array([0.70710678+0.j, 0.70710678+0.j])
get_qs(ket=False)#

Get current quantum state of this simulator.

For state vector simulator, returns quantum state in state vector representation. For density matrix simulator, returns quantum state in density matrix representation.

The quantum state can optionally be returned in ket (Dirac notation) format. For mixed states, it will be represented as a probability weighted sum of pure states.

Parameters:

ket (bool) – Whether to return the quantum state in ket format or not. Default: False.

Returns:

The current quantum state. If ket is True, returns string representation in ket notation. For state vector simulator, returns 1D array or ket string of state vector. For density matrix simulator, returns 2D array or ket string of density matrix.

Return type:

Union[numpy.ndarray, str]

Examples

>>> from mindquantum.algorithm.library import qft
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(qft(range(2)))
>>> sim.get_qs()
array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j])
get_qs_of_qubits(qubits, ket=False) ndarray#

Get current reduced quantum state of specified qubits in this simulator.

The reduced quantum state is obtained by performing partial trace over other qubits. If the resulting state is pure, it returns state vector, while for mixed states, it returns density matrix.

It can optionally be returned in ket (Dirac notation) format. For mixed states, it will be represented as a probability weighted sum of pure states.

Note

  • The order of qubits in the input list does not affect the result.

  • The returned quantum state follows little-endian ordering (e.g., in ket notation, ¦01⟩ means q1=0, q0=1).

Parameters:
  • qubits (Union[int, List[int]]) – The qubits to observe. Can be a single integer or a list of integers.

  • ket (bool) – Whether to return the quantum state in ket notation string. Default: False.

Returns:

If ket is True, return string representation of

quantum state. If ket is False and the state is pure, return state vector as numpy array. If the state is mixed, return density matrix.

Return type:

Union[np.ndarray, str]

Examples

>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(Circuit().h(0).x(1,0))
>>> # Get state vector of qubit 0
>>> state_0 = sim.get_qs_of_qubits(0)
>>> state_0
array([[0.5+0.j, 0. +0.j],
      [0. +0.j, 0.5+0.j]])
>>> # Get ket string representation of qubit 1
>>> state_1 = sim.get_qs_of_qubits(1, ket=True)
>>> state_1
'1/2¦1⟩ + 1/2¦0⟩ (mixed state)'
get_reduced_density_matrix(kept_qubits) ndarray#

Get the reduced density matrix of specified qubits by performing partial trace over other qubits.

Note

  • The order of qubits in the input list does not affect the result.

  • The returned density matrix follows little-endian ordering (e.g., for a 2-qubit state, the basis states are ordered as ¦00⟩, ¦01⟩, ¦10⟩, ¦11⟩ where ¦01⟩ means q1=0, q0=1).

Parameters:

kept_qubits (Union[int, List[int]]) – The indices of qubits to keep, can be a single integer or a list of integers.

Returns:

The reduced density matrix of the specified qubits.

Return type:

numpy.ndarray

Examples

>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(Circuit().h(0).x(1,0))
>>> # Get reduced density matrix of qubit 1
>>> rho_1 = sim.get_reduced_density_matrix([1])
>>> print(rho_1)
[[0.5+0.j 0.0+0.j]
 [0.0+0.j 0.5+0.j]]
property n_qubits#

Get simulator qubit.

Returns:

int, the qubit number of simulator.

purity()#

Calculate the purity of current quantum state.

Definition of purity \(\gamma\) shown as below.

\[\gamma \equiv \text{tr}(\rho^2)\]

where \(\rho\) is density matrix.

Returns:

numbers.Number, the purity of current quantum state.

Examples

>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqmatrix', 1)
>>> sim.set_qs([[0.5, 0], [0, 0.5]])
>>> sim.purity()
0.5
reset()#

Reset simulator to zero state.

Examples

>>> from mindquantum.algorithm.library import qft
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 2)
>>> sim.apply_circuit(qft(range(2)))
>>> sim.reset()
>>> sim.get_qs()
array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j])
sampling(circuit, pr=None, shots=1, seed=None)#

Sample the measure qubit in circuit.

Note

  • The input circuit only participates in the sampling process and will not change the current quantum state of this simulator.

  • The sampling results are represented in little-endian order by default (e.g., ‘01’ means q1=0, q0=1). If big-endian order is needed, use MeasureResult.reverse_endian() method.

Parameters:
  • circuit (Circuit) – The circuit that you want to evolve and sample.

  • pr (Union[None, dict, ParameterResolver]) – The parameter resolver for this circuit, if this circuit is a parameterized circuit. Default: None.

  • shots (int) – How many shots you want to sample this circuit. Default: 1.

  • seed (int) – Random seed for random sampling. If None, seed will be a random int number. Default: None.

Returns:

MeasureResult, the measure result of sampling. The bit strings in the result are in little-endian order.

Examples

>>> from mindquantum.core.circuit import Circuit
>>> from mindquantum.core.gates import Measure
>>> from mindquantum.simulator import Simulator
>>> circ = Circuit().ry('a', 0).ry('b', 1)
>>> circ += Measure('q0_0').on(0)
>>> circ += Measure('q0_1').on(0)
>>> circ += Measure('q1').on(1)
>>> sim = Simulator('mqvector', circ.n_qubits)
>>> res = sim.sampling(circ, {'a': 1.1, 'b': 2.2}, shots=100, seed=42)
>>> res
shots: 100
Keys: q1 q0_1 q0_0│0.00   0.122       0.245       0.367        0.49       0.612
──────────────────┼───────────┴───────────┴───────────┴───────────┴───────────┴
               000│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

               011│▒▒▒▒▒▒▒▒▒

               100│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

               111│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

{'000': 18, '011': 9, '100': 49, '111': 24}
set_qs(quantum_state)#

Set quantum state for this simulation.

Parameters:

quantum_state (numpy.ndarray) – the quantum state that you want.

Examples

>>> import numpy as np
>>> from mindquantum.simulator import Simulator
>>> sim = Simulator('mqvector', 1)
>>> sim.get_qs()
array([1.+0.j, 0.+0.j])
>>> sim.set_qs(np.array([1, 1]))
>>> sim.get_qs()
array([0.70710678+0.j, 0.70710678+0.j])
set_threads_number(number)#

Set maximum number of threads.

Parameters:

number (int) – The thread number the simulator will use for thread pool.