pyquil.simulation package

class pyquil.simulation.NumpyWavefunctionSimulator(n_qubits: int, rs: Optional[numpy.random.mtrand.RandomState] = None)[source]

Bases: pyquil.pyqvm.AbstractQuantumSimulator

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: pyquil.quilbase.Gate) pyquil.simulation._numpy.NumpyWavefunctionSimulator[source]

Perform a gate.

Returns

self to support method chaining.

do_gate_matrix(matrix: numpy.ndarray, qubits: Sequence[int]) pyquil.simulation._numpy.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]) pyquil.pyqvm.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: Union[pyquil.paulis.PauliTerm, pyquil.paulis.PauliSum]) float[source]

Compute the expectation of an operator.

Parameters

operator – The operator

Returns

The operator’s expectation value

reset() pyquil.simulation._numpy.NumpyWavefunctionSimulator[source]

Reset the wavefunction to the |000...00> state.

Returns

self to support method chaining.

sample_bitstrings(n_samples: int) numpy.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: Optional[numpy.random.mtrand.RandomState] = None)[source]

Bases: pyquil.pyqvm.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: pyquil.quilbase.Gate) pyquil.pyqvm.AbstractQuantumSimulator[source]

Perform a gate.

Returns

self to support method chaining.

do_gate_matrix(matrix: numpy.ndarray, qubits: Sequence[int]) pyquil.pyqvm.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]) pyquil.simulation._reference.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: Union[pyquil.paulis.PauliTerm, pyquil.paulis.PauliSum]) complex[source]

Compute the expectation of an operator.

Parameters

operator – The operator

Returns

The operator’s expectation value

reset() pyquil.pyqvm.AbstractQuantumSimulator[source]

Resets 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) numpy.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: numpy.ndarray) pyquil.simulation._reference.ReferenceDensitySimulator[source]

This method is the correct way (TM) to 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: Optional[numpy.random.mtrand.RandomState] = None)[source]

Bases: pyquil.pyqvm.AbstractQuantumSimulator

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: pyquil.quilbase.Gate) pyquil.simulation._reference.ReferenceWavefunctionSimulator[source]

Perform a gate.

Returns

self to support method chaining.

do_gate_matrix(matrix: numpy.ndarray, qubits: Sequence[int]) pyquil.simulation._reference.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]) pyquil.pyqvm.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: Union[pyquil.paulis.PauliTerm, pyquil.paulis.PauliSum]) float[source]

Compute the expectation of an operator.

Parameters

operator – The operator

Returns

The operator’s expectation value

reset() pyquil.simulation._reference.ReferenceWavefunctionSimulator[source]

Reset the wavefunction to the |000...00> state.

Returns

self to support method chaining.

sample_bitstrings(n_samples: int) numpy.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: numpy.ndarray, qubit: int) numpy.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: numpy.ndarray, wf: numpy.ndarray, wf_target_inds: List[int]) numpy.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: numpy.ndarray, wf: numpy.ndarray, wf_target_inds: Sequence[int]) numpy.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) numpy.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.