Skip to content

[codex] Harden federated longitudinal SuStaIn - #1

Draft
armaneshaghi wants to merge 4 commits into
federated-sustainfrom
review/federated-sustain-hardening
Draft

[codex] Harden federated longitudinal SuStaIn#1
armaneshaghi wants to merge 4 commits into
federated-sustainfrom
review/federated-sustain-hardening

Conversation

@armaneshaghi

Copy link
Copy Markdown
Collaborator

Summary

This review branch hardens the federated/longitudinal SuStaIn work added today. It includes Claude's exact hot-path optimisations and golden regression guard, plus review fixes for packaging and aggregate-only federation semantics.

Changes:

  • Use package discovery in setup.py so pySuStaIn.federated and experiment modules are included in real wheel/sdist installs.
  • Expose LongitudinalZscoreSustain from the top-level pySuStaIn package.
  • Make LongitudinalZScoreSustainData explicitly satisfy AbstractSustainData and validate visit/subject shapes.
  • Vectorise the longitudinal monotone-path dynamic program by visit count.
  • Cache deterministic client-side stage likelihoods with a bounded LRU cache.
  • Return aggregate subtype/stage summaries by default from the federated server, with explicit return_individual=True only for local simulations/debugging.
  • Add golden regression tests to pin exact cross-sectional and longitudinal deterministic outputs.

Review notes

The main issue I found in today's committed branch was packaging: setup.py only listed pySuStaIn and sim, so a normal package install would omit the new federated subpackage. I also thought the previous server-side subtype_and_stage() API conflicted with the aggregate-only privacy language because it returned row-level assignments to the server by default.

Validation

  • .venv/bin/python -m pytest -q -> 8 passed, 1 skipped
  • rg --files -g "*.py" | xargs -r .venv/bin/python -m py_compile
  • git diff --check
  • Built a wheel locally and confirmed the federated package, experiments module, and longitudinal module are present.

armaneshaghi and others added 2 commits June 8, 2026 14:07
… guard

- FederatedClient: memoise per-sequence stage-likelihood (bounded LRU keyed by
  the integer ordering). Pure function -> numerically exact; turns the repeated
  non-moving-subtype and revisited-candidate calls in the greedy sequence search
  into cache hits.
- LongitudinalZscoreSustain: vectorise the monotone-path DP across subjects
  (grouped by visit count) instead of a per-subject Python loop. Same ops.
- tests/test_regression_golden.py: pin exact pooled cross-sectional and
  longitudinal fit outputs (loglike + sequences) so optimisations cannot change
  the numerics. Verified unchanged after the optimisation.

(Also includes incremental hardening: AbstractSustainData base + input
validation for longitudinal data, aggregate subtype/stage summaries on the
server/client, and a package-discovery test.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@armaneshaghi

Copy link
Copy Markdown
Collaborator Author

@copilot review please

Add longitudinal equivalence (full-scale 3-subtype, fed-long == pooled-long) and
recovery numbers to RESULTS.md; note the hot-path optimisations are in and
golden-verified exact (longitudinal handling + caching are no longer roadmap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@armaneshaghi

Copy link
Copy Markdown
Collaborator Author

Review (Claude) — reviewed & addressed, leaving for your final review

Verdict: looks solid. CI (federated-sustain tests) is green on the latest commit.

Checked:

  • Hot-path optimisations are numerically exact. The bounded per-sequence stage-likelihood cache and the vectorised longitudinal monotone-path DP reproduce the pre-optimisation outputs to machine precision — pinned by tests/test_regression_golden.py (cross-sectional + longitudinal golden loglike/sequences) plus the fed==pooled equivalence tests. 8 passed, 1 skipped locally.
  • Packaging fix correctfind_packages() picks up pySuStaIn.federated{,.experiments}; .venv/tests excluded (no __init__.py at those roots). Top-level LongitudinalZscoreSustain export imports cleanly (no kde_ebm needed).
  • Aggregate-only server API (subtype_and_stage(..., return_individual=False) default) — good privacy fix, covered by a test.
  • Longitudinal correctness — one visit/subject is identical to cross-sectional (diff 0); full-scale 3-subtype fed-long == pooled-long (loglike diff ~7e-12, sequences identical).

Addressed:

  • Added the longitudinal validation results to RESULTS.md (PR added the longitudinal model but documented only cross-sectional numbers) and refreshed the limitations.

No outstanding issues from my side. Roadmap (non-blocking): federated MCMC uncertainty, federated K-selection, further sequence-search batching. Leaving open for your review — not merging.

@armaneshaghi

Copy link
Copy Markdown
Collaborator Author

I have reviewed this PR. The mathematical approach for the longitudinal path dynamic programming and the federated cache and aggregation is entirely sound. However, I discovered an incompatibility with Numpy 2.x (TypeErrors due to array-to-scalar casting) which breaks the tests. I've created PR #2 to fix these Numpy 2.x compatibility issues on this branch. Once PR #2 is merged into this branch, this PR is good to merge!

* Fix numpy 2.0 scalar conversion errors

* Extend numpy 2.x scalar fix to _perform_mcmc

The EM candidate-generation fix (scalar event bounds + int conversion) was
missing from the MCMC candidate-generation in _perform_mcmc: the same
current_location[event] array bounds (lines ~392/399) and the array-valued
move_event_to from global_rng.choice(...,1) feeding np.arange (~421). Apply the
identical scalar-extraction so run_sustain_algorithm's MCMC uncertainty step is
numpy-2.x-safe too. Behaviour-preserving (size-1 arrays -> scalars): suite +
golden + a pooled MCMC smoke pass on numpy 1.24 and 2.0.2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Arman Eshaghi <armaneshaghi@Armans-MacBook-Pro.local>
Co-authored-by: armaneshaghi <4290297+armaneshaghi@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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