pyquil.simulation package¶
Functions and classes for running simulations.
- class pyquil.simulation.NumpyWavefunctionSimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulator
Initialize a wavefunction simulator that uses numpy’s tensordot or einsum to update a state vector.
Please consider using
PyQVM(..., quantum_simulator_type=NumpyWavefunctionSimulator)
rather than using this class directly.This class uses a n_qubit-dim ndarray to store wavefunction amplitudes. The array is indexed into with a tuple of n_qubits 1’s and 0’s, with qubit 0 as the leftmost bit. This is the opposite convention of the Rigetti Lisp QVM.
- Parameters:
n_qubits – Number of qubits to simulate.
rs – a RandomState (should be shared with the owning
PyQVM
) for doing anything stochastic. A value ofNone
disallows doing anything stochastic.
- do_gate(gate: Gate) NumpyWavefunctionSimulator [source]¶
Perform a gate.
- Returns:
self
to support method chaining.
- do_gate_matrix(matrix: ndarray, qubits: Sequence[int]) NumpyWavefunctionSimulator [source]¶
Apply an arbitrary unitary; not necessarily a named gate.
- Parameters:
matrix – The unitary matrix to apply. No checks are done
qubits – A list of qubits to apply the unitary to.
- Returns:
self
to support method chaining.
- do_measurement(qubit: int) int [source]¶
Measure a qubit, collapse the wavefunction, and return the measurement result.
- Parameters:
qubit – Index of the qubit to measure.
- Returns:
measured bit
- do_post_gate_noise(noise_type: str, noise_prob: float, qubits: list[int]) AbstractQuantumSimulator [source]¶
Apply noise that happens after each gate application.
WARNING! This is experimental and the signature of this interface will likely change.
- Parameters:
noise_type – The name of the noise type
noise_prob – The probability of that noise happening
qubits – Apply noise to these qubits.
- Returns:
self
to support method chaining
- expectation(operator: PauliTerm | PauliSum) float [source]¶
Compute the expectation of an operator.
- Parameters:
operator – The operator
- Returns:
The operator’s expectation value
- reset() NumpyWavefunctionSimulator [source]¶
Reset the wavefunction to the
|000...00>
state.- Returns:
self
to support method chaining.
- class pyquil.simulation.ReferenceDensitySimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulator
A density matrix simulator that prioritizes readability over performance.
Please consider using
PyQVM(..., wf_simulator_type=ReferenceDensitySimulator)
rather than using this class directly.This class uses a dense matrix of shape
(2^n_qubits, 2^n_qubits)
to store the density matrix.- Parameters:
n_qubits – Number of qubits to simulate.
rs – a RandomState (should be shared with the owning
PyQVM
) for doing anything stochastic. A value ofNone
disallows doing anything stochastic.
Initialize.
- Parameters:
n_qubits – Number of qubits to simulate.
rs – a RandomState (shared with the owning
PyQVM
) for doing anything stochastic.
- do_gate(gate: Gate) AbstractQuantumSimulator [source]¶
Perform a gate.
- Returns:
self
to support method chaining.
- do_gate_matrix(matrix: ndarray, qubits: Sequence[int]) AbstractQuantumSimulator [source]¶
Apply an arbitrary unitary; not necessarily a named gate.
- Parameters:
matrix – The unitary matrix to apply. No checks are done
qubits – A list of qubits to apply the unitary to.
- Returns:
self
to support method chaining.
- do_measurement(qubit: int) int [source]¶
Measure a qubit and collapse the wavefunction.
- Returns:
The measurement result. A 1 or a 0.
- do_post_gate_noise(noise_type: str, noise_prob: float, qubits: list[int]) ReferenceDensitySimulator [source]¶
Apply noise that happens after each gate application.
WARNING! This is experimental and the signature of this interface will likely change.
- Parameters:
noise_type – The name of the noise type
noise_prob – The probability of that noise happening
qubits – Apply noise to these qubits.
- Returns:
self
to support method chaining
- expectation(operator: PauliTerm | PauliSum) complex [source]¶
Compute the expectation of an operator.
- Parameters:
operator – The operator
- Returns:
The operator’s expectation value
- reset() AbstractQuantumSimulator [source]¶
Reset the current state of ReferenceDensitySimulator
self.density
toself.initial_density
.- Returns:
self
to support method chaining.
- sample_bitstrings(n_samples: int, tol_factor: float = 100000000.0) ndarray [source]¶
Sample bitstrings from the distribution defined by the wavefunction.
Qubit 0 is at
out[:, 0]
.- Parameters:
n_samples – The number of bitstrings to sample
tol_factor – Tolerance to set imaginary probabilities to zero, relative to machine epsilon.
- Returns:
An array of shape (n_samples, n_qubits)
- set_initial_state(state_matrix: ndarray) ReferenceDensitySimulator [source]¶
Update the initial state matrix that is initialized every time reset() is called.
The default initial state of ReferenceDensitySimulator is
|000...00>
.Note that the current state matrix, i.e.
self.density
is not affected by this method; you must change it directly or else call reset() after calling this method.To restore default state initialization behavior of ReferenceDensitySimulator pass in a
state_matrix
equal to the default initial state on n_qubits (i.e.|000...00>
) and then callreset()
. We have provided a helper functionn_qubit_zero_state
in the_reference.py
module to simplify this step.- Parameters:
state_matrix – numpy.ndarray or None.
- Returns:
self
to support method chaining.
- class pyquil.simulation.ReferenceWavefunctionSimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulator
Initialize a wavefunction simulator that prioritizes readability over performance.
Please consider using
PyQVM(..., wf_simulator_type=ReferenceWavefunctionSimulator)
rather than using this class directly.This class uses a flat state-vector of length 2^n_qubits to store wavefunction amplitudes. The basis is taken to be bitstrings ordered lexicographically with qubit 0 as the rightmost bit. This is the same as the Rigetti Lisp QVM.
- Parameters:
n_qubits – Number of qubits to simulate.
rs – a RandomState (should be shared with the owning
PyQVM
) for doing anything stochastic. A value ofNone
disallows doing anything stochastic.
- do_gate(gate: Gate) ReferenceWavefunctionSimulator [source]¶
Perform a gate.
- Returns:
self
to support method chaining.
- do_gate_matrix(matrix: ndarray, qubits: Sequence[int]) ReferenceWavefunctionSimulator [source]¶
Apply an arbitrary unitary; not necessarily a named gate.
- Parameters:
matrix – The unitary matrix to apply. No checks are done.
qubits – The qubits to apply the unitary to.
- Returns:
self
to support method chaining.
- do_measurement(qubit: int) int [source]¶
Measure a qubit, collapse the wavefunction, and return the measurement result.
- Parameters:
qubit – Index of the qubit to measure.
- Returns:
measured bit
- do_post_gate_noise(noise_type: str, noise_prob: float, qubits: list[int]) AbstractQuantumSimulator [source]¶
Apply noise that happens after each gate application.
WARNING! This is experimental and the signature of this interface will likely change.
- Parameters:
noise_type – The name of the noise type
noise_prob – The probability of that noise happening
qubits – Apply noise to these qubits.
- Returns:
self
to support method chaining
- expectation(operator: PauliTerm | PauliSum) float [source]¶
Compute the expectation of an operator.
- Parameters:
operator – The operator
- Returns:
The operator’s expectation value
- reset() ReferenceWavefunctionSimulator [source]¶
Reset the wavefunction to the
|000...00>
state.- Returns:
self
to support method chaining.
- pyquil.simulation.get_measure_probabilities(wf: ndarray, qubit: int) ndarray [source]¶
Get the probabilities of measuring a qubit.
- Parameters:
wf – The statevector with a dimension for each qubit
qubit – The qubit to measure. We will sum over every axis except this one.
- Returns:
A vector of classical probabilities.
- pyquil.simulation.targeted_einsum(gate: ndarray, wf: ndarray, wf_target_inds: list[int]) ndarray [source]¶
Left-multiplies the given axes of the wf tensor by the given gate matrix.
Note that the matrix must have a compatible tensor structure. For example, if you have an 6-qubit state vector
wf
with shape (2, 2, 2, 2, 2, 2), and a 2-qubit unitary operationop
with shape (2, 2, 2, 2), and you want to applyop
to the 5th and 3rd qubits withininput_state
, then the output state vector is computed as follows:output_state = targeted_einsum(op, input_state, [5, 3])
This method also works when the right hand side is a matrix instead of a vector. If a unitary circuit’s matrix is
old_effect
, and you append a CNOT(q1, q4) operation onto the circuit, where the control q1 is the qubit at offset 1 and the target q4 is the qubit at offset 4, then the appended circuit’s unitary matrix is computed as follows:new_effect = targeted_left_multiply(CNOT.reshape((2, 2, 2, 2)), old_effect, [1, 4])
- Parameters:
gate – What to left-multiply the target tensor by.
wf – A tensor to carefully broadcast a left-multiply over.
wf_target_inds – Which axes of the target are being operated on.
- Returns:
The output tensor.
- pyquil.simulation.targeted_tensordot(gate: ndarray, wf: ndarray, wf_target_inds: Sequence[int]) ndarray [source]¶
Left-multiplies the given axes of the wf tensor by the given gate matrix.
Compare with
targeted_einsum()
. The semantics of these two functions should be identical, except this usesnp.tensordot
instead ofnp.einsum
.- Parameters:
gate – What to left-multiply the target tensor by.
wf – A tensor to carefully broadcast a left-multiply over.
wf_target_inds – Which axes of the target are being operated on.
- Returns:
The output tensor.
- pyquil.simulation.zero_state_matrix(n_qubits: int) ndarray [source]¶
Construct a matrix corresponding to the tensor product of n ground states
|0><0|
.- Parameters:
n_qubits – The number of qubits.
- Returns:
The state matrix
|000...0><000...0|
for n_qubits.