Skip to main content

ppvm_tableau/
lib.rs

1// SPDX-FileCopyrightText: 2026 The PPVM Authors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Generalized stabilizer-tableau simulator built on top of the ppvm core
5//! crates (`ppvm-traits` and `ppvm-pauli-word`).
6//!
7//! Provides a forward-evolving state representation using the stabilizer
8//! formalism, extended to non-Clifford gates by tracking a sparse vector
9//! of coefficients indexed over bitstrings. The two top-level types are
10//! [`data::Tableau`] (pure Clifford) and [`data::GeneralizedTableau`]
11//! (Clifford + non-Clifford with sparse coefficient tracking).
12//!
13//! # Quick example
14//!
15//! Prepare a Bell pair and verify the two measurements are perfectly
16//! correlated:
17//!
18//! ```
19//! use ppvm_tableau::prelude::*;
20//! use ppvm_pauli_sum::config::fxhash::ByteF64;
21//!
22//! let mut tab: GeneralizedTableau<ByteF64<1>> =
23//!     GeneralizedTableau::new_with_seed(2, 1e-12, 0);
24//! tab.h(0);
25//! tab.cnot(0, 1);
26//!
27//! let r0 = LossyMeasure::measure(&mut tab, 0);
28//! let r1 = LossyMeasure::measure(&mut tab, 1);
29//! assert_eq!(r0, r1);
30//! ```
31//!
32//! ## Data-parallel / GPU-offloadable surface
33//!
34//! A handful of primitives in this crate operate on whole contiguous arrays
35//! at once, with no per-element host closures — the shape a thread pool or a
36//! CUDA kernel would want:
37//!
38//! - Every tableau row ([`PhasedPauliWord`](ppvm_pauli_word::phase::PhasedPauliWord))
39//!   stores its Pauli word as fixed-size `bytemuck::Pod` integer bit-planes
40//!   (`xbits`/`zbits`, backed by `[u8; N]` or `[u64; N]`), reachable as
41//!   contiguous raw integer slices via `as_raw_slice`/`as_raw_mut_slice` —
42//!   plain-old-data, not a bit-addressed abstraction.
43//! - The single-gate Clifford path
44//!   (`crates/ppvm-tableau/src/gates/clifford.rs`) has one shared
45//!   implementation per gate that loops over rows operating directly on
46//!   those raw integer slices with a hoisted word-index/bit/mask, bypassing
47//!   `bitvec`'s per-bit bounds checks inside the loop. Both
48//!   [`data::Tableau`] and [`data::GeneralizedTableau`] (via the
49//!   `impl_generalized_tableau_clifford*` macros) funnel through it.
50//! - The batch path does **not** share that implementation. The
51//!   [`CliffordBatch`](ppvm_traits::traits::CliffordBatch) methods (`x_many`,
52//!   `cz_many`, …) each carry their own raw-plane loop that fuses many gates
53//!   into a single pass over the rows, and `Tableau` and
54//!   `GeneralizedTableau` have separate `CliffordBatch` impls (the latter
55//!   via the `impl_gen_tableau_batch_*` macros). Anyone porting the Clifford
56//!   layer to a thread pool or a CUDA kernel has to cover both the
57//!   single-gate implementation and these batch bodies.
58//! - The batch methods take arbitrary index lists (`&[usize]`,
59//!   `&[(usize, usize)]`). [`data::GeneralizedTableau::cz_block`] /
60//!   `cz_block_pairs` / `cz_block_pairs_cross_word` are the
61//!   contiguous-block variants: they apply CZ to a whole contiguous range
62//!   of qubits as bulk masked slice operations, which is the layout a
63//!   kernel can address without an index indirection.
64//! - `GeneralizedTableau::branch_with_coefficients` (crate-private) transforms
65//!   the whole coefficient array in one pass. Its `#[cfg(feature = "rayon")]`
66//!   path (`branch_coefficients_parallel`, gated by `RAYON_COEFF_THRESHOLD`)
67//!   computes the per-entry branch/non-branch coefficient math in parallel,
68//!   with no shared mutable state — the accumulation of those results into
69//!   the coefficient map afterwards remains sequential.
70
71/// Core [`Tableau`](data::Tableau) and
72/// [`GeneralizedTableau`](data::GeneralizedTableau) types.
73pub mod data;
74/// `Display` implementations for tableau types.
75pub mod display;
76/// Pauli-string expectation values and pattern traces.
77pub mod expectation;
78/// Gate implementations (Clifford, T, rotations).
79pub mod gates;
80/// Z-basis measurement, including loss-aware variants.
81pub mod measure;
82/// Per-qubit [`QubitStatus`](qubit_status::QubitStatus) relative to the
83/// computational subspace.
84pub mod qubit_status;
85
86pub mod measure_all;
87
88/// Noise channels: depolarizing, Pauli error, loss.
89pub mod noise;
90/// [`SparseVector`](sparsevec::SparseVector) trait and implementations.
91pub mod sparsevec;
92/// [`TableauIndex`](tableau_index::TableauIndex) — abstraction over
93/// the bitstring index type (`usize`, `u128`, `U256`, …).
94pub mod tableau_index;
95/// [`TableauLike`](tableau_like::TableauLike) — shared trait for
96/// stabilizer-tableau backends.
97pub mod tableau_like;
98
99/// Convenience re-exports for downstream code.
100pub mod prelude {
101    pub use crate::data::{GeneralizedTableau, Tableau};
102    pub use crate::qubit_status::QubitStatus;
103    pub use crate::sparsevec::SparseVector;
104    pub use crate::tableau_index::TableauIndex;
105    pub use crate::tableau_like::TableauLike;
106    pub use ppvm_pauli_sum::prelude::*;
107}