Built directly from in-source docstrings: rustdoc JSON for the Rust
crates, griffe for the Python package. Use the language filter to
narrow the view; the search box always queries across both.
Python items 116Rust items 109Generated
Pythonppvm
Pythonic wrapper around the native Rust runtime. All items below
live under the ppvm top-level module.
Generalized stabilizer tableau for quantum circuit simulation.
Full docstring
Generalized stabilizer tableau for quantum circuit simulation.
Represents an arbitrary quantum state in the basis spanned by the
stabilizer tableau. It supports Clifford gates, arbitrary single- and two-qubit rotations,
noise channels, and mid-circuit measurement.
The coefficient vector grows exponentially with the
number of non-Clifford operations applied.
Apply a state-dependent ("asymmetric") loss channel to a qubit.
Full docstring
Apply a state-dependent ("asymmetric") loss channel to a qubit.
The qubit is lost from |0> with probability p0 and from |1> with
probability p1, so the total loss probability depends on the
current populations: p_tot = p0 * (1 + <Z>)/2 + p1 * (1 - <Z>)/2.
.. note::
This is the trajectory approximation of the loss channel. It is
exact for the loss statistics and in the symmetric limit
p0 == p1 (where it matches loss_channel), but it does
not apply the survival back-action, so for p0 != p1 the
surviving qubit's state is left unchanged. See issue #39.
Return a snapshot of the sparse coefficient vector.
Full docstring
Return a snapshot of the sparse coefficient vector.
The tableau represents the state as a sparse superposition over the
basis states of its stabilizer frame. This returns that vector as a
mapping from basis-state index to complex amplitude.
The returned dict is a copy: mutating it does not affect the tableau's
internal state.
Returns
A dict mapping each populated basis-state index to its complex amplitude.
Fork this tableau into an independent simulation branch.
Full docstring
Fork this tableau into an independent simulation branch.
Clones all quantum state but reinitializes the RNG, so the returned
tableau evolves independently from this one. If seed is provided
the new RNG is seeded deterministically; otherwise it is seeded from
OS entropy.
Use this when branching a simulation into independent trajectories.
To preserve the RNG state exactly (e.g. for checkpointing), use
copy.copy() or copy.deepcopy() instead.
Parameters
seed
Optional integer seed for the forked RNG.
Returns
GeneralizedTableau
A new GeneralizedTableau with the same quantum state but an independent RNG.
Execute a parsed Stim program against this tableau (single shot).
Full docstring
Execute a parsed Stim program against this tableau (single shot).
.. note::
This mutates the tableau in place. For independent shots use
fork or ppvm.sample_stim / sample helpers (which build a
fresh tableau per shot).
Run num_shots shots of prog and return all measurement results.
Full docstring
Run num_shots shots of prog and return all measurement results.
Each shot starts from a fresh tableau, so this is the right entry
point for multi-shot sampling.
Shots run in parallel across CPU cores (the GIL is released during
sampling), with a serial fallback for small batches. When seed is
given (it must fit in an unsigned 64-bit integer), shot i uses
(seed + i) % 2**64 (wrapping u64 arithmetic), so results are
reproducible and independent of the number of threads. Set the
RAYON_NUM_THREADS environment variable before the first call to
control the pool size (it defaults to the number of logical cores).
A sum over generalized tableaus, representing a density matrix that is a weighted sum over pure state projectors (classical mixture). Each projector is represented by a generalized tableau. The respective weights are the probabilities wi…
Full docstring
A sum over generalized tableaus, representing a density matrix that is a
weighted sum over pure state projectors (classical mixture). Each projector
is represented by a generalized tableau. The respective weights are the
probabilities with which the system is in the corresponding state.
Convert a dictionary of two-qubit Pauli error probabilities to a list.
Full docstring
Convert a dictionary of two-qubit Pauli error probabilities to a list.
Convenience method to convert a dictionary mapping two-qubit Pauli
strings (e.g., "IX", "ZZ") to their probabilities into the ordered
list format required by two_qubit_pauli_error.
Parameters
error_probabilities
Dictionary mapping two-qubit Pauli strings
to their error probabilities. Missing keys default to 0.0.
Returns
A list of 15 probabilities in the canonical order (excludes "II").
If True (default), run the configured truncation
strategy after the gate; if False, leave the map
untruncated so the next gate sees the full unpruned state.
Apply RXX (Ising XX) rotation gates over consecutive qubit pairs.
Full docstring
Apply RXX (Ising XX) rotation gates over consecutive qubit pairs.
See RotationsMixin.rxx for the gate definition.
Parameters
*targets
A flat list of qubit indices, broadcast as pairs.
theta
The rotation angle in radians.
truncatebool
If True (default), run the configured truncation
strategy after the gate. Set to False to compose a
U(1)-conserving step like rxx + ryy on the same edge
without dropping the conserved-charge component between
them — then call PauliSum.truncate once at the
end of the composition.
This is achieved by extending the set of Pauli basis operators to include
an addition operator {I, X, Y, Z, L}, where L is the projector on
a third leakage state. This basis effectively allows simulating qutrits,
where we neglect any coherences between the qubit subspace and the leakage
state.
In addition to the new channels, there is also another truncation strategy:
Since Pauli Strings that have an L at multiple positions contribute only
minimally, these can get truncated by setting an appropriate max_loss_weight.
The truncation is similar to how max_pauli_weight truncates strings, but only
counting Ls.
A weighted sum of Pauli strings for quantum simulation.
Full docstring
A weighted sum of Pauli strings for quantum simulation.
PauliSum represents a linear combination of Pauli operators, commonly used
to represent quantum observables or Hamiltonians. It provides methods for
applying quantum gates (Clifford operations and rotations) and computing
expectation values via the trace operation.
This applies a correlated loss channel to the qubits at addr0 and addr1.
The channel accepts 3 probabilities as argument:
* p[0]: The probability of losing both qubits, when they are originally
in the qubit subspace.
* p[1]: The probability of losing a single qubit, when both qubits
are originally in the qubit subspace.
* p[2]: The probability of losing one qubit when the other one
has already been lost prior to applying the channel. This is to
account for the fact that when one qubit is missing during e.g.
a controlled gate, the remaining qubit undergoes a different dynamic.
We account for this difference with this distinct probability.
truncate: If True (default), run the configured truncation
strategy after the channel; if False, defer it.
Reduces the trace of qubit-subspace operators by (1 - p).
Adds back population into I or Z if the Pauli string has an L
at addr0. This can only occur if a reset channel has been applied before
and accounts for the fact of falsely counting a lost qubit as 0 in a
measurement.
Parameters
addr0int
The index of the target qubit.
pfloat
Loss probability in [0, 1].
truncatebool
If True (default), run the configured truncation
strategy after the channel; if False, defer it.
Reset a lost qubit to the 0 state. Usually, you want to apply this channel at the end of the circuit, i.e. at the beginning when propagating backwards.
Full docstring
Reset a lost qubit to the 0 state. Usually, you want to apply
this channel at the end of the circuit, i.e. at the beginning when
propagating backwards.
NOTE: This channel causes exponential branching in I and Z.
Make sure to set an appropriate max_loss_weight to truncate.
Parameters
addr0int
The index of the qubit to reset.
truncatebool
If True (default), run the configured truncation
strategy after the channel; if False, defer it.
Create a PauliSum from one or more terms with flexible input formats.
Full docstring
Create a PauliSum from one or more terms with flexible input formats.
Parameters
n_qubitsint
Number of qubits.
terms
A single term or list of terms. Each term is either:
A full Pauli string (e.g. "IX"), with coefficient 1.0.
A compact string "P{i}" (e.g. "X1"), placing Pauli P
at 0-based qubit index i with coefficient 1.0.
A tuple (str, float) pairing either of the above with an
explicit coefficient.
min_abs_coefffloat
Terms with absolute coefficient below this threshold
are dropped. Defaults to 1e-10.
max_pauli_weight
Maximum number of non-identity Paulis per term.
If None, truncation is disabled.
max_loss_weight
Maximum loss weight per term (only used by
LossyPauliSum). If None, truncation is disabled.
Note, that this should usually be chosen to be quite low, since
e.g. 10 would correspond to keeping terms that contribute if
up to 10 qubits are lost simultaneously.
preserve_strings
Pauli strings (length n_qubits each) that
truncation must never drop. Empty by default.
Returns
Self
A new instance of the class this method is called on.
Raises
ValueError
If a compact qubit index is out of range for n_qubits.
A pattern specifying which terms to include in the trace.
Use 'Z' to project onto |0>, '?' for any single character,
and '*' to match zero or more characters.
Run the configured truncation strategy (min_abs_coeff and/or max_pauli_weight) on the current state.
Full docstring
Run the configured truncation strategy (min_abs_coeff and/or
max_pauli_weight) on the current state.
Useful when gates were called with truncate=False to chain a
composition of commuting operations (e.g. rxx + ryy on the
same edge, an exchange-like step that conserves total Z), so
that intermediate truncation does not drop conserved-charge
components. Call truncate once at the end of the
composition to apply the cut to the combined result.
The four standard Paulis are encoded so that the low two bits identify
the operator (I = 0b00, X = 0b01, Z = 0b10, Y = 0b11), which is
the same encoding stabilizer-formalism tools commonly use. The extra
variant Pauli::L marks a qubit as lost, used by the loss-aware
portions of the runtime.
Config is a zero-cost generic dispatch mechanism: it pins down the
storage backing (Storage), coefficient type (Coeff), truncation
strategy (Strategy), hasher (BuildHasher), Pauli-word representation
(PauliWordType), and concrete map (Map) used by a single
PauliSum instantiation. Pre-built bundles live in the submodules
(fxhash, indexmap, …); user code may define its own.
Two-qubit Pauli rotations, generated by P_a ⊗ P_b for any pair of
non-identity Paulis. Provides the named convenience methods
rxx, rxy, …, rzz on top of the generic [rotate_2].
Full docstring
Two-qubit Pauli rotations, generated by P_a ⊗ P_b for any pair of
non-identity Paulis. Provides the named convenience methods
rxx, rxy, …, rzz on top of the generic rotate_2.
The minimal Clifford gate set: the single-qubit Paulis (X, Y, Z),
Hadamard (H), phase gate (S), and the two entangling Cliffords
CNOT and CZ.
Full docstring
The minimal Clifford gate set: the single-qubit Paulis (X, Y, Z),
Hadamard (H), phase gate (S), and the two entangling Cliffords
CNOT and CZ.
Implemented by PauliSum, by every tableau type, and — via the
blanket impl in this module — by every PauliWordTrait
implementor.
Examples
Build the GHZ-preparation circuit on a PauliSum (Heisenberg picture,
so gates are applied in reverse). PauliSum lives in the downstream
ppvm-pauli-sum crate, so this example is ignored here:
use ppvm_pauli_sum::prelude::*;
let mut state: PauliSum<config::indexmap::ByteFxHashF64<1>> =
PauliSum::builder().n_qubits(2).build();
state += ("ZZ", 1.0);
state.cnot(0, 1);
state.h(0);
assert_eq!(state.len(), 1);
Batched Clifford gates: apply the same gate to many qubits in one call.
Full docstring
Batched Clifford gates: apply the same gate to many qubits in one call.
Default implementations loop over the corresponding single-qubit
(or single-pair) method on Clifford. Types like the stabilizer
Tableau override these methods with a fused inner-loop or bitmask
implementation. Types that don't need specialization can implement
this trait with an empty impl to use the defaults.
Numeric coefficient type usable inside a
PauliSum.
Full docstring
Numeric coefficient type usable inside a
PauliSum.
Coefficient bundles every arithmetic operation a Pauli-propagation
step needs — addition, multiplication, signed multiplication, half,
sin/cos, and a cutoff predicate used by truncation strategies. The
built-in f64 impl covers the common case; Complex<f64> is
available when phase tracking is required.
Post-processing that a PauliWord's hasher
applies to its raw 64-bit digest before it is cached as the map-key hash.
Full docstring
Post-processing that a PauliWord's hasher
applies to its raw 64-bit digest before it is cached as the map-key hash.
The cached value is what hashbrown ultimately splits into a bucket index
(low bits) and a control-byte tag (top 7 bits). Whether the raw digest is
good enough for that split is a property of the hasher, not of the
Pauli word: an AES-based hasher such as gxhash avalanches well even for an
8-byte key, whereas FxHasher — a couple of multiply-rotate rounds — leaves
the low bits of a short key highly correlated and needs a fold to fix them.
Keeping this on the hasher is what makes the abstraction correct. An earlier
version folded based on storage width alone, which conflated "narrow
storage" with "weak hasher" and so wrongly folded gxhash too. Here each
hasher declares how (if at all) its output must be adjusted, and
PauliWord::rehash just defers to it. The default
is the identity — the right choice for any hasher that already distributes
its low bits well — so a custom hasher opts in with a bare
impl HashFinalize for MyHasher {}.
State-dependent ("asymmetric") single-qubit loss channel: a qubit is
lost from |0⟩ with probability p0 and from |1⟩ with probability
p1. Unlike LossChannel, the total loss probability depends on the
qubit's populations, so th…
Full docstring
State-dependent ("asymmetric") single-qubit loss channel: a qubit is
lost from |0⟩ with probability p0 and from |1⟩ with probability
p1. Unlike LossChannel, the total loss probability depends on the
qubit's populations, so the channel reads the current ⟨Z⟩.
Backing storage for a PauliWord — a
fixed-size, Copy-able block of bits (typically [u8; N] or
[u64; N]).
Full docstring
Backing storage for a PauliWord — a
fixed-size, Copy-able block of bits (typically [u8; N] or
[u64; N]).
The bytemuck::Pod bound guarantees the storage is a plain-old-data
type with no padding and all bit patterns valid, which lets
PauliWord::rehash view it as a &[u8] for
fast byte-slice hashing withoutunsafe. Every concrete storage used
here ([u8; N], [u64; N]) is already Pod.
A truncation policy applied to a PauliSum
during Pauli propagation.
Full docstring
A truncation policy applied to a PauliSum
during Pauli propagation.
The strategy controls two things: the initial capacity allocated
for the underlying map (estimating how many Pauli paths the
simulation is expected to generate) and the cut applied when
truncate is called explicitly. Implementations
include NoStrategy, the coefficient-magnitude threshold, the
max-Pauli-weight bound, etc.
Word-level Pauli operations. Types implementing this trait automatically
gain crate::traits::Clifford and crate::traits::CliffordExtensions
behavior via blanket impls in the crate::traits::clifford module, using
get_lbit / `g…
Full docstring
Word-level Pauli operations. Types implementing this trait automatically
gain crate::traits::Clifford and crate::traits::CliffordExtensions
behavior via blanket impls in the crate::traits::clifford module, using
get_lbit / get_xbit / set_xbit / set_zbit / rehash to transform
Pauli words.
Word-level vs. state-level gate semantics
The blanket Clifford impl applies gates at the bit level of a single
Pauli word. X / Y / Z are bit-level no-ops on a Pauli word — they affect
phase, not the X/Z bits — so word.x(i), word.y(i), word.z(i) are
deliberately silent. Phase is tracked separately by
PhasedPauliWord, which implements Clifford manually.
If you need a word representation whose gate behavior is not pure
bit manipulation (phase tracking, fused multi-qubit updates, alternative
loss semantics), do not implement PauliWordTrait on it — define a
specialized Clifford impl instead, the way PhasedPauliWord does.
Implementing both PauliWordTrait and a custom impl Clifford for ...
for the same type will not compile: the blanket impl overlaps with your
custom impl (coherence error), not silently shadows it.
ppvm-pauli-word
Packed Pauli strings: `PauliWord`, phased, lossy, and pattern variants.
A PauliWord-like type that additionally
tracks per-qubit loss.
Full docstring
A PauliWord-like type that additionally
tracks per-qubit loss.
In neutral-atom hardware (and in any loss-aware error model), a
measurement can return "lost" instead of 0 or 1. LossyPauliWord
adds a parallel lbits array marking which qubits have been lost; a
set loss bit excludes that qubit from the standard Pauli operations
and shows up as the [Pauli::L] symbol.
Examples
use ppvm_traits::char::Pauli;
use ppvm_pauli_word::loss::LossyPauliWord;
use ppvm_traits::traits::PauliWordTrait;
let w: LossyPauliWord<[u8; 1]> = "XLZL".into();
assert_eq!(w.weight(), 4); // X, L, Z, L are all non-identity
assert_eq!(w.loss_weight(), 2); // two qubits are lost
assert!(w.is(1, Pauli::L));
assert!(w.is(0, Pauli::X));
A fixed-width Pauli string stored as parallel x and z bit arrays.
Full docstring
A fixed-width Pauli string stored as parallel x and z bit arrays.
Each qubit slot is encoded by two bits, (x, z), giving the four
Pauli operators I = (0,0), X = (1,0), Z = (0,1), Y = (1,1) —
the same encoding stabilizer-formalism tools use. The bit arrays live
in a single PauliStorage blob (typically [u8; N] or [u64; N]),
so a PauliWord<[u8; 1]> packs up to 8 qubits, [u8; 2] up to 16,
etc.
A cached hash speeds up use as a map key; pass REHASH = false if
you build words in bulk and want to control rehashing manually.
Examples
use ppvm_traits::char::Pauli;
use ppvm_traits::traits::PauliWordTrait;
use ppvm_pauli_word::word::PauliWord;
// Build a word from a string …
let w: PauliWord<[u8; 1]> = "XYZI".into();
assert_eq!(w.n_qubits(), 4);
assert_eq!(w.get(0), Pauli::X);
assert_eq!(w.get(3), Pauli::I);
// … or build it slot-by-slot.
let mut w2: PauliWord<[u8; 1]> = PauliWord::new(2);
w2.set(0, Pauli::X).set(1, Pauli::Y);
assert_eq!(w2.to_string(), "XY");
assert_eq!(w2.weight(), 2);
Implemented by Pauli patterns over symbols (Contains<Pauli>) and
over whole words (Contains<W: PauliIter>); used by the masking
machinery to ask "does this pattern accept this concrete word?"
ppvm-pauli-sum
The `PauliSum` engine, truncation strategies, and concrete config bundles.
Pre-built configs backed by dashmap::DashMap for concurrent access.
Native-only: dashmap pulls rayon, which needs OS threads, so this
module is unavailable on wasm32.
HashMap-backed Config with native-word ([usize; N]) storage and
FxHasher.
Full docstring
HashMap-backed Config with native-word ([usize; N]) storage and
FxHasher.
The storage element is usize, i.e. the target's native machine word:
u64 on 64-bit targets (identical layout and performance to a hardcoded
[u64; N]) and u32 on 32-bit targets such as wasm32. Using usize
rather than u64 keeps this config available on every target — bitvec
only implements BitStore for u64 on 64-bit pointer widths, but always
implements it for usize. (The Byte8 name refers to the 64-bit word
this config packs into on native targets.)
Drop terms whose coefficient magnitude falls below the given threshold.
Defaults to 1e-12.
Full docstring
Drop terms whose coefficient magnitude falls below the given threshold.
Defaults to 1e-12.
Examples
use ppvm_pauli_sum::prelude::*;
use ppvm_pauli_sum::strategy::CoefficientThreshold;
let strict = CoefficientThreshold(1e-6);
let mut state: PauliSum<config::indexmap::ByteFxHashF64<1, CoefficientThreshold>> =
PauliSum::builder().n_qubits(2).strategy(strict).build();
state += ("ZZ", 1.0);
state += ("XX", 1e-9); // below threshold
state.truncate();
assert_eq!(state.len(), 1); // the XX term was dropped
The capacity hint is the smaller of the two; truncation applies both
policies in order, so use this when you want, e.g.,
"drop by coefficient threshold and cap maximum Pauli weight".
The central data type of the Pauli-propagation backend. Keys are
PauliWord-shaped Pauli strings; values are
numeric coefficients. Generic over a Config that fixes the
concrete storage / hasher / coefficient / strategy.
Internally PauliSum holds two maps — a primary and an auxiliary —
and swaps between them during gate propagation to avoid repeated
allocations. The [PauliSum::data] / [PauliSum::aux] accessors
expose the current orientation; most callers will only ever touch
the primary side via the high-level gate / measurement traits.
Examples
Heisenberg-picture propagation of ZZ through the GHZ circuit:
use ppvm_pauli_sum::prelude::*;
let mut state: PauliSum<config::indexmap::ByteFxHashF64<1>> =
PauliSum::builder().n_qubits(2).build();
state += ("ZZ", 1.0);
// Circuit: H(0); CNOT(0, 1) — apply in reverse for Heisenberg propagation.
state.cnot(0, 1);
state.h(0);
// ZZ → IZ under the GHZ circuit, with coefficient 1.0.
assert_eq!(state.len(), 1);
Builder's type state specifies if members are set or not (unset).
Full docstring
Builder's type state specifies if members are set or not (unset).
You can use the associated types of this trait to control the state of individual members with the [IsSet] and [IsUnset] traits. You can change the state of the members with the Set* structs available in this module.
type aliasByteFxHashF64ppvm_pauli_sum::config::dashmap::ByteFxHashF64
Implement multiplication by a scalar coefficient for PauliSum.
Use this macro to implement MulAssign for other scalar types
if needed. This macro will forward the multiplication to the underlying map's
mul_assign method.
Generalized stabilizer-tableau simulator built on top of the ppvm core
crates (ppvm-traits and ppvm-pauli-word).
Full docstring
Generalized stabilizer-tableau simulator built on top of the ppvm core
crates (ppvm-traits and ppvm-pauli-word).
Provides a forward-evolving state representation using the stabilizer
formalism, extended to non-Clifford gates by tracking a sparse vector
of coefficients indexed over bitstrings. The two top-level types are
data::Tableau (pure Clifford) and data::GeneralizedTableau
(Clifford + non-Clifford with sparse coefficient tracking).
Quick example
Prepare a Bell pair and verify the two measurements are perfectly
correlated:
use ppvm_tableau::prelude::*;
use ppvm_pauli_sum::config::fxhash::ByteF64;
let mut tab: GeneralizedTableau<ByteF64<1>> =
GeneralizedTableau::new_with_seed(2, 1e-12, 0);
tab.h(0);
tab.cnot(0, 1);
let r0 = LossyMeasure::measure(&mut tab, 0);
let r1 = LossyMeasure::measure(&mut tab, 1);
assert_eq!(r0, r1);
TableauLike — shared trait for
stabilizer-tableau backends.
TableauLike trait: shared interface for stabilizer-tableau backends.
Full docstring
TableauLike — shared trait for
stabilizer-tableau backends.
TableauLike trait: shared interface for stabilizer-tableau backends.
Any type implementing TableauLike gets default implementations of
single- and two-qubit Pauli noise channels (Depolarizing, PauliError,
Depolarizing2, TwoQubitPauliError). New tableau backends only need to
provide TableauLike::rng_mut and (optionally) override
TableauLike::is_qubit_lost.
A Tableau extended with sparse coefficient tracking to handle
non-Clifford gates.
Full docstring
A Tableau extended with sparse coefficient tracking to handle
non-Clifford gates.
Non-Clifford gates (T, rotations) split a single tableau into a sum
of weighted branches indexed by bitstrings. GeneralizedTableau
stores those weights in a SparseVector keyed by an
IndexType. Choose:
IndexType = usize for up to 64 qubits,
IndexType = u128 for up to 128,
IndexType = bnum::types::U256 and friends for the very wide
regime.
Per-qubit loss is tracked in is_lost;
gates respect it automatically.
Examples
Prepare a Bell pair and sample one shot. With a fixed seed the two
measurements are perfectly correlated on every shot:
use ppvm_pauli_sum::config::fxhash::ByteF64;
use ppvm_traits::traits::{Clifford, LossyMeasure};
use ppvm_tableau::data::GeneralizedTableau;
let mut tab: GeneralizedTableau<ByteF64<1>> =
GeneralizedTableau::new_with_seed(2, 1e-12, 0);
tab.h(0);
tab.cnot(0, 1);
let r0 = LossyMeasure::measure(&mut tab, 0);
let r1 = LossyMeasure::measure(&mut tab, 1);
assert_eq!(r0, r1);
Non-Clifford gates work through the same interface — apply a T gate
followed by T† and the state is unchanged:
use ppvm_pauli_sum::config::fxhash::ByteF64;
use ppvm_traits::traits::{Clifford, TGate};
use ppvm_tableau::data::GeneralizedTableau;
let mut tab: GeneralizedTableau<ByteF64<1>> =
GeneralizedTableau::new_with_seed(1, 1e-12, 0);
tab.h(0);
tab.t(0);
tab.t_dag(0);
// T followed by T† is the identity; the |+⟩ state is restored.
Rows 0..n hold the destabilizers; rows n..2n hold the
stabilizers. Each row is a PhasedPauliWord tracking both its
X/Z bits and a phase in {±1, ±i}. Implements every
Clifford-only operation natively (Hadamard, phase, CNOT, CZ, etc.).
Examples
use ppvm_pauli_sum::config::fxhash::ByteF64;
use ppvm_traits::traits::Clifford;
use ppvm_tableau::data::Tableau;
let mut tab: Tableau<ByteF64<1>> = Tableau::new(2);
tab.h(0);
tab.cnot(0, 1);
assert_eq!(tab.n_qubits, 2);
assert_eq!(tab.stabilizers().len(), 2);
Per-measurement scratch buffers, reused across qubits within a single
measure_all invocation — and, when threaded through
measure_all_with_scratch,
across many shots of a sampler too. R…
Full docstring
Per-measurement scratch buffers, reused across qubits within a single
measure_all invocation — and, when threaded through
measure_all_with_scratch,
across many shots of a sampler too. Reusing one scratch keeps the case-a
HashMap and the b-entries Vec out of the per-shot allocator churn.
odd_phase_mask is lazily computed and cached until the destabilizers
change (i.e. until a case-a measurement runs update_tableau_according_to_outcome).
coeff_map is the case-a HashMap holding (idx → amplitude) between
the overlap, partition, and merge passes.
b_entries is the case-a partition's "k-bit = 1" scratch Vec.
Construct one per active sampling thread; the type is not meant to be
shared across threads concurrently.
A sparse vector keyed by index type I with values of type T.
Full docstring
A sparse vector keyed by index type I with values of type T.
Used by GeneralizedTableau to
store the coefficient over each branching bitstring. The default
implementation is Vec<(T, I)>; alternative backings (BTreeMap,
HashMap, etc.) can be provided by downstream code.
A stabilizer-tableau-like backend that supports Clifford gates and an RNG.
Full docstring
A stabilizer-tableau-like backend that supports Clifford gates and an RNG.
Implementing this trait grants default implementations of the Pauli noise
channels via [TableauLike::depolarize_impl] and friends. The associated
Rng type lets each backend choose its own RNG; nothing in this trait
depends on SmallRng.
ppvm-sym provides a Term type that represents a polynomial in
sines and cosines of symbolic parameters. It is used by ppvm to
propagate Pauli operators through parametric circuits (e.g.,
variational ansätze) without committing to specific angle values
until the very end.
Quick example
Build the symbolic expression sin(x0) * cos(x1), then evaluate it
at a concrete (x0, x1):
use ppvm_sym::Term;
let expr = Term::var(0).sin() * Term::var(1).cos();
let v = expr.eval(&[0.5, 1.0]).unwrap();
let expected = 0.5_f64.sin() * 1.0_f64.cos();
assert!((v - expected).abs() < 1e-12);
A single product of trigonometric atoms over symbolic variables.
Sines and cosines are grouped by variable id; powers are tracked as
totals so we can quickly compute and bound them. The order of
variables is kept canonical (ascending) so two Prod values
representing the same monomial compare equal.
Term is the public-facing wrapper around its Inner enum. It
also carries two truncation parameters, applied during multiplication
and addition:
Examples
use ppvm_sym::Term;
// sin²(x0) at x0 = π/2 equals 1.
let expr = Term::var(0).sin() * Term::var(0).sin();
let v = expr.eval(&[std::f64::consts::FRAC_PI_2]).unwrap();
assert!((v - 1.0).abs() < 1e-12);
max_sin — drop terms whose total sine power exceeds this bound.
min_eps — drop terms whose coefficient magnitude falls below
this threshold.
Sum holds a full formal sum; One is the optimisation for a
single weighted product; Var is a bare symbolic variable used
before it has been wrapped in a sin or cos; Const is a
numeric scalar.