Skip to content

ppvm

ppvm (Pauli Propagation and Virtual Machine) is a fast and easy-to-use quantum circuit simulator backed by a high-performance Rust core with Python bindings.

It offers two complementary simulation approaches:

Pauli Propagation

Instead of tracking a full quantum state vector, ppvm represents the quantum state as a sum of Pauli strings with real coefficients. Gates are applied by conjugating each term in the sum, and noise channels are applied as super-operators. This makes it possible to simulate large and deep quantum circuits, including noisy ones, at a fraction of the cost of full statevector simulation.

  • Clifford gates, arbitrary single- and two-qubit rotations, and common noise channels.
  • Automatic truncation: terms below a coefficient threshold or above a Pauli weight cutoff are dropped, controlling the approximation/performance trade-off.
  • Optional loss channel support via LossyPauliSum, including a reset channel to reset a qubit from being lost to its zero-state.

Generalized Stabilizer Tableau

The GeneralizedTableau simulates quantum circuits in the Schrodinger picture using a generalized stabilizer decomposition. Clifford operations are handled efficiently in the tableau, while non-Clifford gates (T gates, arbitrary rotations) are tracked via a sparse coefficient vector that grows with the stabilizer rank.

  • Clifford gates, T gates, and arbitrary single- and two-qubit rotations.
  • Mid-circuit measurement returning MeasurementResult (ZERO, ONE, or LOST).
  • Noise channels: depolarizing, Pauli error, loss, and correlated loss.
  • STIM circuit format support via run_stim_string and run_stim_file.
  • fork() for branching into independent simulation trajectories.

Quick installation

Just pip install directly from git:

pip install git+https://github.com/QuEraComputing/ppvm.git#subdirectory=ppvm-python

Short examples

Pauli Propagation

from ppvm import PauliSum

# Start with the terms for which you want to compute the average
state = PauliSum.new(n_qubits = 2, terms = ["ZZ"])

# Create a GHZ state
# NOTE: since this is Pauli Propagation, we need to backwards propagate, hence
# the CNOT needs to precede the Hadamard
state.cnot(0, 1)
state.h(0)

# The state is now represented as IZ
print(state)  # 1.000 * IZ

# Compute the average value
print(state.overlap_with_zero())

Stabilizer Tableau

from ppvm import GeneralizedTableau

tab = GeneralizedTableau(n_qubits=2)
tab.h(0)
tab.cnot(0, 1)

# Measure both qubits -- results are always correlated (Bell state)
r0 = tab.measure(0)
r1 = tab.measure(1)
print(f"Qubit 0: {r0}, Qubit 1: {r1}")

Getting started

Similar packages