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 of None 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.

sample_bitstrings(n_samples: int) 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

Returns:

An array of shape (n_samples, n_qubits)

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 of None 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 to self.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 call reset(). We have provided a helper function n_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 of None 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.

sample_bitstrings(n_samples: int) 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

Returns:

An array of shape (n_samples, n_qubits)

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 operation op with shape (2, 2, 2, 2), and you want to apply op to the 5th and 3rd qubits within input_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 uses np.tensordot instead of np.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.

Submodules