pyquil.simulation package¶
Functions and classes for running simulations.
- class pyquil.simulation.NumpyWavefunctionSimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulatorInitialize 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 ofNonedisallows doing anything stochastic.
- do_gate(gate: Gate) NumpyWavefunctionSimulator[source]¶
Perform a gate.
- Returns:
selfto 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:
selfto 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:
selfto 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:
selfto support method chaining.
- class pyquil.simulation.ReferenceDensitySimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulatorA 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 ofNonedisallows 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:
selfto 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:
selfto 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:
selfto 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.densitytoself.initial_density.- Returns:
selfto 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.densityis 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_matrixequal to the default initial state on n_qubits (i.e.|000...00>) and then callreset(). We have provided a helper functionn_qubit_zero_statein the_reference.pymodule to simplify this step.- Parameters:
state_matrix – numpy.ndarray or None.
- Returns:
selfto support method chaining.
- class pyquil.simulation.ReferenceWavefunctionSimulator(n_qubits: int, rs: RandomState | None = None)[source]¶
Bases:
AbstractQuantumSimulatorInitialize 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 ofNonedisallows doing anything stochastic.
- do_gate(gate: Gate) ReferenceWavefunctionSimulator[source]¶
Perform a gate.
- Returns:
selfto 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:
selfto 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:
selfto 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:
selfto 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
wfwith shape (2, 2, 2, 2, 2, 2), and a 2-qubit unitary operationopwith shape (2, 2, 2, 2), and you want to applyopto 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.tensordotinstead 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.