Skip to content

ppvm_tableau::data

data

ppvm_tableau::data

Core [`Tableau`](data::Tableau) and [`GeneralizedTableau`](data::GeneralizedTableau) types.

classGeneralizedTableausource

ppvm_tableau::data::GeneralizedTableau

Bases: Clone, Display, Clifford, CliffordExtensions, CliffordBatch, CliffordExtensionsBatch, Reset, RotationOne<T>, RotXY<T>, RotationTwo<T>, TGate<T>, U3Gate<T>, LossyMeasure, LossyMeasureAll, TableauLike, Depolarizing<T>, PauliError<T>, TwoQubitPauliError<T>, Depolarizing2<T>, LossChannel<T>, AsymmetricLossChannel<T>, CorrelatedLossChannel<T>, ResetLossChannel<T>

Rust struct. A [`Tableau`] extended with sparse coefficient tracking to handle non-Clifford gates.

Signature
pub struct GeneralizedTableau<T: Config, IndexType, SparseVectorType: SparseVector<Complex<<T as >::Coeff>, IndexType>>

Fields

NameTypeDescription
tableauTableau&lt;T&gt;Underlying Clifford tableau.
coefficientsSparseVectorTypeSparse coefficient vector indexed by bitstrings.
is_lostVec&lt;bool&gt;Per-qubit loss flags.
coefficient_threshold&lt;T as &gt;::CoeffCoefficient-magnitude threshold below which branches are dropped.
measurement_recordVec&lt;Option&lt;bool&gt;&gt;Ordered log of every measurement performed (mirrors stim's record).

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.

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. ```

source

methodappend_measurement_recordsource

ppvm_tableau::data::GeneralizedTableau::append_measurement_record

pub fn append_measurement_record(&mut self, result: Option<bool>)

Parameters

NameTypeDescription
resultOption&lt;bool&gt;

Append an externally defined measurement result to the record.

Used by Stim instructions such as `MPAD`, which append measurement record bits without measuring a qubit.

source

methodbernoullisource

ppvm_tableau::data::GeneralizedTableau::bernoulli

pub fn bernoulli(&mut self, p: f64) -> bool

Parameters

NameTypeDescription
pf64

Returns

bool

Sample a Bernoulli(`p`) outcome using the tableau’s internal RNG. Used by Stim measurement-noise dispatch in `ppvm-stim`.

source

methodcompute_decompositionsource

ppvm_tableau::data::GeneralizedTableau::compute_decomposition

Signature
pub fn compute_decomposition(&self, addr0: usize, pauli: Pauli) -> (u8, I, I)

Parameters

NameTypeDescription
addr0usize
pauliPauli

Returns

(u8, I, I)

Compute the decomposition of a pauli into stabilizer destabilizer products Any Pauli can be written as P_addr0 = phase * prod(d_k ^ gamma_k) * prod(s_l ^ lambda_l) where: gamma_k == 1 iff {P_addr0, s_k} = 0 lambda_l == 1 iff {P_addr0, d_l} = 0 Lemma 5. from T. J. Yoder (2012) NOTE: this is O(n^2)

The function returns `(phase, stab_anticomm_bits, destab_anticomm_bits)`, where `stab_anticomm_bits[k] = 1` iff P_addr0 anticommutes with stabilizer s_k, and `destab_anticomm_bits[l] = 1` iff P_addr0 anticommutes with destabilizer d_l. Note that stab_anticomm_bits is equal to the shift of the index when branching (`beta` in Eq(4) of the SOFT paper).

source

methodcompute_overlap_case_asource

ppvm_tableau::data::GeneralizedTableau::compute_overlap_case_a

Signature
pub fn compute_overlap_case_a(coeff_map: &HashMap<I, Complex<<T as >::Coeff>>, phase_decomp: u8, destab_anticomm_bits: I, stab_anticomm_bits: I, odd_phase_mask: I) -> f64

Parameters

NameTypeDescription
coeff_map&amp;HashMap&lt;I, Complex&lt;&lt;T as &gt;::Coeff&gt;&gt;
phase_decompu8
destab_anticomm_bitsI
stab_anticomm_bitsI
odd_phase_maskI

Returns

f64

Case_a overlap: cross-index pairing via HashMap lookup. Accumulates only the real part of z_overlap.

source

methodcompute_overlap_case_bsource

ppvm_tableau::data::GeneralizedTableau::compute_overlap_case_b

Signature
pub fn compute_overlap_case_b(entries: &[(Complex<<T as >::Coeff>, I)], phase_decomp: u8, destab_anticomm_bits: I) -> f64

Parameters

NameTypeDescription
entries&amp;[(Complex&lt;&lt;T as &gt;::Coeff&gt;, I)]
phase_decompu8
destab_anticomm_bitsI

Returns

f64

Case_b overlap: self-pairing (branch_index = idx), so overlap = ±|c|^2. Only even phases contribute to the real part.

source

methodcurrent_measurement_recordsource

ppvm_tableau::data::GeneralizedTableau::current_measurement_record

pub fn current_measurement_record(&self) -> &[Option<bool>]

Returns

&[Option<bool>]

All measurement outcomes recorded so far, in order.

source

methodcz_blocksource

ppvm_tableau::data::GeneralizedTableau::cz_block

Signature
pub fn cz_block(&mut self, control_base: usize, target_base: usize, count: usize)

Parameters

NameTypeDescription
control_baseusize
target_baseusize
countusize

Apply CZ to `count` pairs with a constant offset, given in qubit-index terms: `(control_base + i, target_base + i)` for `i in 0..count`.

This is the high-level entry point for a fused block of CZs: it splits the run at storage-word boundaries internally and dispatches each segment to Self::cz_block_pairs (control and target in the same word) or Self::cz_block_pairs_cross_word (straddling two words), so callers never need to reason about the `u64` packing. CZ is symmetric, so the two bases may be passed in either order.

Overlapping pairs — `|target_base - control_base| < count`, of which adjacent-pair brickwork `cz_block(0, 1, n)` is the extreme case — are handled: the same-word segments route through Self::cz_block_pairs into Tableau::cz_block_pairs, which falls back to the per-pair loop. A cross-word segment is always disjoint (its `run` never exceeds the offset), so the fused kernel stays live there.

source

methodcz_block_pairssource

ppvm_tableau::data::GeneralizedTableau::cz_block_pairs

Signature
pub fn cz_block_pairs(&mut self, base: usize, offset: usize, count: usize)

Parameters

NameTypeDescription
baseusize
offsetusize
countusize

Apply CZ to N pairs with constant offset: (base+i, base+offset+i) for i in 0..count. Falls back to individual CZ calls if any qubit in the range is lost. Overlap (`offset < count`) is owned by Tableau::cz_block_pairs.

source

methodcz_block_pairs_cross_wordsource

ppvm_tableau::data::GeneralizedTableau::cz_block_pairs_cross_word

Signature
pub fn cz_block_pairs_cross_word(&mut self, word_c: usize, base_bit_c: usize, word_t: usize, base_bit_t: usize, count: usize)

Parameters

NameTypeDescription
word_cusize
base_bit_cusize
word_tusize
base_bit_tusize
countusize

Apply CZ to N cross-word pairs. Controls at word_c, targets at word_t. Falls back to individual CZ calls if any qubit is lost.

source

methodexpectationsource

ppvm_tableau::data::GeneralizedTableau::expectation

pub fn expectation<W: PauliWordTrait>(&self, word: &W) -> f64

Parameters

NameTypeDescription
word&amp;W

Returns

f64

`⟨ψ|word|ψ⟩` for the multi-qubit Pauli `word`.

Conjugates `word` through the Clifford tableau (giving a Pauli on the canonical basis: an X-mask, Z-mask, and `i^φ` phase), then sums `⟨α|P_conj|β⟩ c_α* c_β` over the sparse coefficient vector. Always returns a real number (Hermitian operator on a normalized state).

source

methodflip_with_probsource

ppvm_tableau::data::GeneralizedTableau::flip_with_prob

pub fn flip_with_prob(&mut self, bit: bool, p: f64) -> bool

Parameters

NameTypeDescription
bitbool
pf64

Returns

bool

Flip `bit` with probability `p`. Used by Stim MR/MPad readout-noise dispatch in `ppvm-stim`. Returns `bit` unchanged when `p <= 0.0`.

source

methodforksource

ppvm_tableau::data::GeneralizedTableau::fork

pub fn fork(&self, seed: Option<u64>) -> Self

Parameters

NameTypeDescription
seedOption&lt;u64&gt;

Returns

Self

Clone the quantum state but reinitialize the RNG, producing an independent simulation branch. If `seed` is `Some`, the new RNG is seeded deterministically; if `None`, it is seeded from OS entropy.

source

methodmeasure_all_with_scratchsource

ppvm_tableau::data::GeneralizedTableau::measure_all_with_scratch

Signature
pub fn measure_all_with_scratch(&mut self, scratch: &mut MeasureScratch<I, <T as >::Coeff>) -> Vec<Option<bool>>

Parameters

NameTypeDescription
scratch&amp;mut MeasureScratch&lt;I, &lt;T as &gt;::Coeff&gt;

Returns

Vec<Option<bool>>

Same as LossyMeasureAll::measure_all, but the caller supplies a `MeasureScratch` that’s reused across the n per-qubit measurements (and, if the caller chooses, across many invocations / shots).

This is the entry point samplers should use when running many shots: initialize one scratch alongside the sampler and thread it through every shot to amortize the case-a HashMap and b_entries allocations.

source

methodmeasure_many_with_scratchsource

ppvm_tableau::data::GeneralizedTableau::measure_many_with_scratch

Signature
pub fn measure_many_with_scratch(&mut self, indices: &[usize], scratch: &mut MeasureScratch<I, <T as >::Coeff>) -> Vec<Option<bool>>

Parameters

NameTypeDescription
indices&amp;[usize]
scratch&amp;mut MeasureScratch&lt;I, &lt;T as &gt;::Coeff&gt;

Returns

Vec<Option<bool>>

Measure the given qubit `indices` in order, reusing a caller-supplied `MeasureScratch` across the per-index measurements (and, if the caller chooses, across many invocations / shots) — the explicit-index analogue of measure_all_with_scratch. This is the scratch-reusing engine behind the tableau’s `LossyMeasure::measure_many` override (in `measure.rs`), which the Stim executor and the Python `measure_many` binding both go through.

source

methodmeasure_noisysource

ppvm_tableau::data::GeneralizedTableau::measure_noisy

Signature
pub fn measure_noisy(&mut self, addr0: usize, flip_prob: f64) -> Option<bool>

Parameters

NameTypeDescription
addr0usize
flip_probf64

Returns

Option<bool>

Measure qubit `addr0` in Z basis with optional readout noise.

Behaves like measure, then with probability `flip_prob` flips the recorded bit. The qubit’s quantum state stays consistent with the true outcome — only the returned value flips. `flip_prob = 0.0` is equivalent to `measure`.

If the qubit is lost, returns `None` regardless of `flip_prob`.

source

methodn_qubitssource

ppvm_tableau::data::GeneralizedTableau::n_qubits

pub fn n_qubits(&self) -> usize

Returns

usize

Number of qubits.

source

methodnewsource

ppvm_tableau::data::GeneralizedTableau::new

Signature
pub fn new(n_qubits: usize, coefficient_threshold: <T as >::Coeff) -> Self

Parameters

NameTypeDescription
n_qubitsusize
coefficient_threshold&lt;T as &gt;::Coeff

Returns

Self

Construct a generalized tableau in the `|0…0⟩` state.

Branches whose coefficient magnitude falls below `coefficient_threshold` are dropped during gate application.

source

methodnew_with_seedsource

ppvm_tableau::data::GeneralizedTableau::new_with_seed

Signature
pub fn new_with_seed(n_qubits: usize, coefficient_threshold: <T as >::Coeff, seed: u64) -> Self

Parameters

NameTypeDescription
n_qubitsusize
coefficient_threshold&lt;T as &gt;::Coeff
seedu64

Returns

Self

Same as GeneralizedTableau::new, but seed the RNG deterministically.

source

methododd_phase_destabilizer_masksource

ppvm_tableau::data::GeneralizedTableau::odd_phase_destabilizer_mask

pub fn odd_phase_destabilizer_mask(&self) -> I

Returns

I

Build a bitmask where bit i is set if destabilizer i has odd phase (phase % 2 != 0).

source

methodoverwrite_last_measurement_recordsource

ppvm_tableau::data::GeneralizedTableau::overwrite_last_measurement_record

Signature
pub fn overwrite_last_measurement_record(&mut self, result: Option<bool>)

Parameters

NameTypeDescription
resultOption&lt;bool&gt;

Replace the most recent measurement record entry.

Used by noisy measurement paths where the quantum state follows the true outcome but the public record should hold the reported bit.

source

methodproject_case_asource

ppvm_tableau::data::GeneralizedTableau::project_case_a

Signature
pub fn project_case_a(&mut self, outcome: bool, scratch: &mut MeasureScratch<I, <T as >::Coeff>, phase_decomp: u8, stab_anticomm_bits: I, destab_anticomm_bits: I, addr0: usize)

Parameters

NameTypeDescription
outcomebool
scratch&amp;mut MeasureScratch&lt;I, &lt;T as &gt;::Coeff&gt;
phase_decompu8
stab_anticomm_bitsI
destab_anticomm_bitsI
addr0usize
source

methodproject_case_bsource

ppvm_tableau::data::GeneralizedTableau::project_case_b

Signature
pub fn project_case_b(&mut self, entries: &[(Complex<<T as >::Coeff>, I)], outcome: bool, phase_decomp: u8, destab_anticomm_bits: I)

Parameters

NameTypeDescription
entries&amp;[(Complex&lt;&lt;T as &gt;::Coeff&gt;, I)]
outcomebool
phase_decompu8
destab_anticomm_bitsI

project state in case b (Z is a stabilizer) according to sampled outcome

source

methodreset_allsource

ppvm_tableau::data::GeneralizedTableau::reset_all

pub fn reset_all(&mut self)
source

methodtracesource

ppvm_tableau::data::GeneralizedTableau::trace

pub fn trace(&self, pattern: &PauliPattern) -> f64

Parameters

NameTypeDescription
pattern&amp;PauliPattern

Returns

f64

`Σ_{P matches pattern} ⟨ψ|P|ψ⟩`.

Enumerates every `PauliWord` accepted by `pattern` via PauliPattern::enumerate_matches and sums their expectations. Star quantifiers (`X*`) panic — the pattern must be bounded; use counted repetition (`Z?{n}`) or positional anchors instead.

source

methodz_expectationsource

ppvm_tableau::data::GeneralizedTableau::z_expectation

pub fn z_expectation(&self, addr0: usize) -> f64

Parameters

NameTypeDescription
addr0usize

Returns

f64

`⟨Z⟩` on qubit `addr0`, computed non-destructively (the state is not collapsed). Reuses the measurement overlap machinery; cost scales with the number of coefficients (and n²).

source

classTableausource

ppvm_tableau::data::Tableau

Bases: Clone, Debug, Display, Clifford, CliffordExtensions, CliffordBatch, CliffordExtensionsBatch, Reset, Measure, TableauLike, Depolarizing&lt;T&gt;, PauliError&lt;T&gt;, TwoQubitPauliError&lt;T&gt;, Depolarizing2&lt;T&gt;

Rust struct. A `2n`-row stabilizer / destabilizer tableau.

pub struct Tableau<T: Config>

Fields

NameTypeDescription
n_qubitsusizeNumber of qubits.
dataVec&lt;PhasedPauliWord&lt;&lt;T as &gt;::Storage, &lt;T as &gt;::BuildHasher, PauliWord&lt;&lt;T as &gt;::Storage, &lt;T as &gt;::BuildHasher, false&gt;&gt;&gt;Destabilizer / Stabilizer tableau * Entries 0..n are the destabilizers * Entries n..2n are the stabilizers

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.).

``` 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); ```

source

methodcz_block_pairssource

ppvm_tableau::data::Tableau::cz_block_pairs

Signature
pub fn cz_block_pairs(&mut self, base: usize, offset: usize, count: usize)

Parameters

NameTypeDescription
baseusize
offsetusize
countusize

Apply CZ to N pairs with constant offset: (base+i, base+offset+i) for i in 0..count. All pairs must be in the same u64 word. This replaces N individual CZ calls with a single word-level shift+XOR operation per row.

The fused kernel needs `offset >= count`, i.e. pairwise-disjoint supports (pairs `i != j` collide iff `|i - j| == offset`, which needs `offset < count`, or `offset == 0`). Both fused updates need it: the single `count_ones() & 1` phase reads the pre-update `z` plane for every pair at once (`Batch.lean::czSeq_phase` proves it equal to the sequential loop only under pairwise disjointness, and `czSeq_phase_needs_disjoint` exhibits a counterexample), and the `z` delta `OR`s the two shifted planes, so a `z` bit written by two pairs is set once instead of XOR-cancelled.

Overlapping pairs (`offset < count`, including `offset == 0`) fall back to the per-pair `cz` loop, so this method is safe in release.

Debug-asserts that all bits are within the same word.

source

methodcz_block_pairs_cross_wordsource

ppvm_tableau::data::Tableau::cz_block_pairs_cross_word

Signature
pub fn cz_block_pairs_cross_word(&mut self, word_c: usize, base_bit_c: usize, word_t: usize, base_bit_t: usize, count: usize)

Parameters

NameTypeDescription
word_cusize
base_bit_cusize
word_tusize
base_bit_tusize
countusize

Apply CZ to N pairs with constant offset across two different words. Controls at (word_c, base_bit_c+i) and targets at (word_t, base_bit_t+i) for i in 0..count. word_c and word_t must be different.

source

methoddestabilizerssource

ppvm_tableau::data::Tableau::destabilizers

Signature
pub fn destabilizers(&self) -> &[PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Returns

&[PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

View of the destabilizer rows (the lower half of the tableau).

source

methoddestabilizers_mutsource

ppvm_tableau::data::Tableau::destabilizers_mut

Signature
pub fn destabilizers_mut(&mut self) -> &mut [PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Returns

&mut [PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Mutable view of the destabilizer rows.

source

methodnewsource

ppvm_tableau::data::Tableau::new

pub fn new(n_qubits: usize) -> Self

Parameters

NameTypeDescription
n_qubitsusize

Returns

Self

Construct a fresh tableau initialised to `|0…0⟩`.

source

methodnew_with_seedsource

ppvm_tableau::data::Tableau::new_with_seed

pub fn new_with_seed(n_qubits: usize, seed: u64) -> Self

Parameters

NameTypeDescription
n_qubitsusize
seedu64

Returns

Self

Same as Tableau::new, but seed the RNG deterministically.

source

methodreset_allsource

ppvm_tableau::data::Tableau::reset_all

pub fn reset_all(&mut self)
source

methodstabilizerssource

ppvm_tableau::data::Tableau::stabilizers

Signature
pub fn stabilizers(&self) -> &[PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Returns

&[PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

View of the stabilizer rows (the upper half of the tableau).

source

methodstabilizers_mutsource

ppvm_tableau::data::Tableau::stabilizers_mut

Signature
pub fn stabilizers_mut(&mut self) -> &mut [PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Returns

&mut [PhasedPauliWord<<T as >::Storage, <T as >::BuildHasher, PauliWord<<T as >::Storage, <T as >::BuildHasher, false>>]

Mutable view of the stabilizer rows.

source

functionsymplectic_innersource

ppvm_tableau::data::symplectic_inner

pub fn symplectic_inner<I>(alpha: I, beta: I) -> u32

Parameters

NameTypeDescription
alphaI
betaI

Returns

u32

Symplectic inner product of two tableau index values — the count of shared set bits, used in stabilizer phase calculations.

source