# Simulators

QVMs promise to behave like a real QPU. However, under-the-hood there is usually a simulation
that has fewer constraints than a physical device. For example, in a wavefunction (or statevector)
simulation, you can directly inspect amplitudes and probabilities.

## Reference Utilities

`lifted_pauli` (pauli_sum, qubits) |
Takes a PauliSum object along with a list of qubits and returns a matrix corresponding the tensor representation of the object. |

`lifted_gate` (gate, n_qubits) |
Lift a pyquil `Gate` in a full `n_qubits` -qubit Hilbert space. |

`program_unitary` (program, n_qubits) |
Return the unitary of a pyQuil program. |

`all_bitstrings` (n_bits) |
All bitstrings in lexicographical order as a 2d np.ndarray. |

## Numpy Utilities

`targeted_einsum` (gate, wf, wf_target_inds) |
Left-multiplies the given axes of the wf tensor by the given gate matrix. |

`targeted_tensordot` (gate, wf, wf_target_inds) |
Left-multiplies the given axes of the wf tensor by the given gate matrix. |