Skip to content

fix(update): UpdatePlan must not read the destination when beta == 0; add execute_uninit - #317

Merged
shinaoka merged 1 commit into
mainfrom
fix/update-plan-beta-zero
Oct 17, 2026
Merged

shinaoka merged 1 commit into
mainfrom
fix/update-plan-beta-zero

Conversation

@shinaoka

Copy link
Copy Markdown
Member

Follow-up to #316, found by the tcontract 0.3 pre-review (tcontract-rs#121). UpdatePlan::execute replayed *dst = alpha * value + beta * *dst unconditionally. BLAS semantics require that beta == 0 does not read the destination; otherwise NaN or garbage in D leaks through 0 * NaN = NaN, and a fresh output can never be represented as uninitialized.

  • With beta == 0 (Zero::is_zero, so -0.0 counts as zero and a NaN beta keeps the read path), UpdatePlan and ErasedUpdatePlan take a write-only replay (*dst = alpha * value). The bounds gain Zero + One + PartialEq.
  • New UpdatePlan::execute_uninit and ErasedUpdatePlan::execute_uninit write into MaybeUninit storage with beta implicitly 0. Validation and the overlap check happen before any write, and every reachable slot is initialized.
  • Tests:
    • A destination poisoned with NaN, for f32/f64/c64, with contiguous and permuted layouts, serial and in a 2-worker pool, through both the typed and the erased plan.
    • beta = 0.5 still reads the destination, and a NaN beta reads it too.
    • execute_uninit initializes every slot, including a layout with holes.
    • The alloc_matrix arms assert 0 allocations at rank 1..=8.
  • Coverage: copy_plan.rs 97.2%, erased.rs 87.6%, all 48 files pass. cargo test --profile ci, the parallel lane and --no-default-features are green.

This lands before the 0.6.0 release PR.

🤖 Generated with Claude Code

UpdatePlan::execute and ErasedUpdatePlan::execute always replayed
`alpha*f(src) + beta*dst`, so even beta == 0 read the old destination.
BLAS semantics (and the fresh-output accumulate tcontract needs) require
beta == 0 to be write-only: otherwise NaN/garbage in D propagates through
0 * NaN and a fresh output can never be represented as uninitialized.

- Branch on num_traits::{Zero, One, PartialEq}: beta.is_zero() replays
  `*dst = alpha * value` (or `*dst = value` when alpha.is_one()), never
  forming a destination read. -0.0 counts as zero; NaN stays on the read
  path.
- Add UpdatePlan::execute_uninit and ErasedUpdatePlan::execute_uninit
  (beta implicitly zero) that fully initialize every reachable slot,
  following the existing *_uninit validation-before-write convention.
- Tests: typed and erased f32/f64/c64, contiguous/permuted, NaN-poisoned
  destinations and poisoned MaybeUninit, serial and two-worker, -0.0 and
  NaN beta. alloc_matrix asserts zero allocations for the uninit replay.
@shinaoka
shinaoka enabled auto-merge (squash) October 17, 2026 11:57
@github-actions

Copy link
Copy Markdown

Repository rules review

Repository rules review (ddbe17bcb64969a062d2a052f61afbdec9cd18c3...62d259f3e4e99e871082e660e2f78abfd668f7ea)
Verdict: pass
Findings:
- [warn] llm-skipped (External LLM Review) <unknown>: External LLM review was skipped
  External LLM review is permanently disabled; deterministic checks only.

@shinaoka
shinaoka merged commit 967850a into main Oct 17, 2026
10 checks passed
@shinaoka
shinaoka deleted the fix/update-plan-beta-zero branch October 17, 2026 12:03
shinaoka added a commit that referenced this pull request Oct 17, 2026
The GitHub-hosted runner measured S3a 1.87 / S3b 3.15 after #317 made the
beta == 0 compiled baseline write-only; the reference host measures ~1.5 /
~2.2. Initial thresholds 2.5 / 4.0, to be tightened from CI history (#306).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
shinaoka added a commit that referenced this pull request Oct 17, 2026
* chore: release strided 0.6.0 (all crates)

Allocation-free API (#316, #306) and UpdatePlan beta=0 (#317). Versions
unified on the workspace at 0.6.0. Release note:
docs/worklogs/2026-10-17-release-0.6.0.md.

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

* bench(basic): set the S3 smoke thresholds from the slowest machine seen

The GitHub-hosted runner measured S3a 1.87 / S3b 3.15 after #317 made the
beta == 0 compiled baseline write-only; the reference host measures ~1.5 /
~2.2. Initial thresholds 2.5 / 4.0, to be tightened from CI history (#306).

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

---------

Co-authored-by: Claude Opus 5.5 (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