Skip to content

SAGA v2 follow-up: integer guard, repo hygiene, Falcon submodule - #4

Merged
tprest merged 3 commits into
masterfrom
saga-v2-followup-integer-guard
Jul 9, 2026
Merged

SAGA v2 follow-up: integer guard, repo hygiene, Falcon submodule#4
tprest merged 3 commits into
masterfrom
saga-v2-followup-integer-guard

Conversation

@tprest

@tprest tprest commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #3 (SAGA v2), from a fresh re-review of the merged suite. Three self-contained commits.

1. Enforce discrete Gaussians; fix a silent nan

UnivariateSamples histograms by integer key, so continuous input turned every sample into an outlier → n_effective = 0 → chi-square 0/0 = nan, silently (a RuntimeWarning in the suite). Consequences, found by running the merged suite:

  • Every multivariate test vector was continuous (rng.normal), so the per-coordinate Gaussianity channel (fisher_bh) was never actually exercised — a regression there would pass CI.
  • mv_bad_variance_one_coord was "detected" only via that nan degeneracy (spurious coord_fail_rate = 1.0).

Fixes: reject non-integer / all-outlier input with a clear error; MultivariateSamples runs the discrete per-coordinate channel only for integer data (nb_gaussian_coord=None otherwise); add an integer discrete-Gaussian good vector (samples the discrete Gaussian directly — rounding a continuous draw inflates variance by 1/12 and false-alarms the norm test) and make the wrong-variance vector integer; fold diagcov + BH-localization into the battery verdict so a single flawed coordinate or a correlated pair isn't silently passed; math.pi for a hardcoded constant.

2. Repo hygiene

Remove sampler_rep.py (orphaned dead code) and extensive_calibration.json (4700 lines of committed output); move the four standalone scripts under code/scripts/ so code/ shows only the core suite.

3. Reference Falcon as a submodule

The vendored code/falcon/ had diverged into a SAGA-specific fork (re-packaged imports, added __init__.py + newsampler.py, reject=False/T_fft hooks) while upstream restructured. Replace it with a git submodule pinned to tprest/falcon.py, and rewrite test_sig against the reference API (Falcon(n).keygen(), __sample_preimage__ for the raw (s0,s1) vector). The import is lazy, so the core suite has no dependency on falcon/ or its extra deps (pycryptodome, beartype → optional [falcon] extra).

Verification

  • Suite: 134 passed, 1 skipped, no RuntimeWarning (checked under -W error::RuntimeWarning).
  • test_sig(n=64) on real Falcon signatures: dim=128, σ=157.5, DH p=0.89, 128/128 Gaussian coordinates — exercises the integer per-coordinate channel on real data.

Note for reviewers/CI: test_sig needs git submodule update --init; the pytest suite does not (it never runs test_sig), so CI stays green without fetching the submodule.

🤖 Generated with Claude Code

tprest and others added 3 commits July 9, 2026 20:49
UnivariateSamples histograms by integer key, so continuous input turned
every sample into an outlier -> n_effective=0 -> chi-square 0/0 = nan
(a RuntimeWarning), silently. Because every multivariate test vector was
continuous, the per-coordinate Gaussianity channel (fisher_bh) was never
actually exercised, and mv_bad_variance_one_coord was "detected" only via
that nan degeneracy.

- UnivariateSamples: reject non-integer input and all-outlier data with a
  clear ValueError.
- MultivariateSamples: detect integer-ness; run the per-coordinate discrete
  channel only for integer data (nb_gaussian_coord=None otherwise), instead
  of feeding it nan p-values.
- Test vectors: add an integer discrete-Gaussian good vector (lights up the
  channel dim/dim) and make the wrong-variance vector integer so it is
  genuinely caught. Sampling the discrete Gaussian directly, not rounding a
  continuous draw (rounding inflates variance by 1/12 -> squared-norm false
  alarm).
- Battery verdict: fold in diagcov and BH-localization so a single flawed
  coordinate (diluted in the global Fisher p) and a correlated pair (which
  diagcov catches) are not silently passed.
- Minor: use math.pi instead of a hardcoded 3.14159265.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove sampler_rep.py: orphaned since the rejection-channel test was
  descoped (its import and test_rejind were already gone).
- Remove extensive_calibration.json: 4700 lines of committed calibration
  *output*, read by no code; regenerate with run_extensive_calibration.py
  (now gitignored).
- Move the four standalone scripts (report_card, run_baseline,
  run_extensive_calibration, visualize_mockups) under code/scripts/ so the
  code/ root shows only the core suite; fix their sys.path accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The vendored code/falcon/ had diverged into a SAGA-specific fork: re-packaged
to `from falcon.X` imports with an added __init__.py, plus a local
newsampler.py wired into ffsampling and reject=False / T_fft hooks. Meanwhile
upstream restructured (samplerz.py, rng.py). Replace it with a git submodule
pinned to the reference implementation.

- code/falcon is now a submodule of github.com/tprest/falcon.py.
- test_sig rewritten against the reference API: Falcon(n).keygen(), then
  __sample_preimage__ to read the raw (s0, s1) Gaussian vector directly. This
  replaces the old reject=False path (the norm rejection sits ~6.7 sigma out,
  mass ~1e-11, statistically indistinguishable). The T_fft perturbation demo
  is dropped -- it is covered by the synthetic mv_bad_fft_zeroed vector.
- The import is lazy (inside test_sig), so the core suite has no dependency on
  falcon/ or its extra deps (pycryptodome, beartype), exposed as the optional
  [falcon] extra. Fetch with: git submodule update --init.

Verified: test_sig(n=64) on real Falcon signatures gives dim=128, sigma=157.5,
DH p=0.89, 128/128 Gaussian coordinates -- exercising the integer per-coordinate
channel on real data.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tprest
tprest merged commit 140ea90 into master Jul 9, 2026
4 checks passed
@tprest
tprest deleted the saga-v2-followup-integer-guard branch July 9, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant