Skip to content

GeneralizedTableauSum(sum_cutoff=0.0) panics on sampler() for any multi-branch channel #206

Description

@Roger-luo

Summary

GeneralizedTableauSum with sum_cutoff=0.0 panics when you build a sampler, for any channel that produces three or more branches. The branch weights sum to 0.9999999999999999 in f64, and the normalization debug_assert uses a strict >= against 1 - sum_cutoff, which at sum_cutoff == 0 leaves no room for rounding.

Reachable from Python, and it surfaces as a PanicException rather than a Python-level error.

Reproduction

from ppvm.generalized_tableau_sum import GeneralizedTableauSum

t = GeneralizedTableauSum(n_qubits=2, sum_cutoff=0.0, seed=1)
t.depolarize1(0, 0.3)
t.sampler()
thread '<unnamed>' panicked at crates/ppvm-tableau-sum/src/data.rs:136:9:
Normalization error in sum
PanicException: Normalization error in sum

Scope

Any channel whose branch weights don't sum to exactly 1.0 in binary floating point. Two-branch splits are fine because the halves are exact:

operation sum_cutoff=0.0
depolarize1(0, 0.3) panics (p/3 is not exact)
pauli_error(0, [0.1, 0.2, 0.3]) panics
correlated_loss_channel(0, 1, [0.1, 0.2, 0.0]) panics
loss_channel(0, 0.1) ok
x_error(0, 0.1) ok

Cause

crates/ppvm-tableau-sum/src/data.rs:136:

debug_assert!(
    *p_cum.last().unwrap_or(&T::Coeff::zero()) >= T::Coeff::one() - self.sum_cutoff.clone(),
    "Normalization error in sum"
);

sum_cutoff doubles as both the truncation threshold and the normalization tolerance. That coupling is fine while sum_cutoff is comfortably larger than accumulated f64 error, but at 0.0 the assert demands the cumulative mass be exactly >= 1.0, which a sum of three or more f64 weights generally is not.

Notes

  • The debug_assert means release wheels don't hit this, so it affects development and maturin develop installs. The invariant it's checking is still worth checking — the issue is the tolerance, not the assert.
  • Convention-independent: I verified it reproduces with weights from both the old and new correlated-loss conventions, and with channels that have nothing to do with loss.
  • A plausible fix is to separate the normalization tolerance from sum_cutoff — compare against 1.0 - max(sum_cutoff, k * f64::EPSILON) for a small k, or scale the slack with the branch count.
  • Found while building a cross-backend verification harness for fix(tableau): correlated-loss convention, duplicate batch targets, CZ-block overlap #205; unrelated to that PR's changes.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: PPVMArea: Pauli Propagation VM related issues.category: bugCategory: this is a bug or something isn't working as expected.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions