Skip to content

Fix segfault in affine_transform with negative b#45

Merged
shinaoka merged 2 commits intomainfrom
fix/affine-negative-b
Feb 13, 2026
Merged

Fix segfault in affine_transform with negative b#45
shinaoka merged 2 commits intomainfrom
fix/affine-negative-b

Conversation

@shinaoka
Copy link
Copy Markdown
Member

Summary

Fixes #44affine_transform_mpo segfaults (or causes ~50GB memory usage) when offset vector b has negative entries or entries exceeding 2^R.

Three bugs were identified and fixed in src/affine.jl:

  • Segfault (Bug 1): In affine_transform_core, when activebit=false, the isodd(s) branch computed y freely via z & 1, producing y_index=2 on a length-1 array. @inbounds hid the BoundsError as a segfault. Fix: skip carry paths where y != 0 when bits are inactive.

  • Infinite loop / 50GB memory (Bug 2): Arithmetic right shift on negative b never reaches 0 (-1 >> 1 = -1), so the extension loop in affine_transform_tensors ran forever. Fix: work with abs(b) and track signs separately so shifting always terminates.

  • Sign of b lost (Bug 3): copysign(b_, abs(b_)) & 1 always returned abs(b_) & 1, so negative offsets were treated as positive — the MPO would be mathematically wrong. Fix: pass signed bit contributions (b .& 1) .* bsign to the core function.

Additionally, Project.toml now requires TensorCrossInterpolation >= 0.9.18, which provides the TCIITensorConversion extension (the MPO(::TensorTrain) / MPS(::TensorTrain) constructors needed after the standalone TCIITensorConversion.jl was dropped in 9cf8d28).

Test plan

  • Original issue reproduction (b=[-32, 32], R=6) — no crash, correct MPO
  • All cases from the issue comment ([-1,1], [-5,5], [100,32]) — verified against reference matrix
  • Already-working cases ([32,32], [0,0]) — still pass
  • All 1728 existing affine tests pass
  • Full test suite: 10045 passed, 0 failed, 0 errored

🤖 Generated with Claude Code

shinaoka and others added 2 commits February 13, 2026 06:53
Three bugs in affine_transform_core/tensors when offset vector b has
negative entries or entries exceeding 2^R (fixes #44):

1. BoundsError (hidden as segfault by @inbounds): activebit=false path
   computed y freely via z & 1, producing y_index=2 on a length-1 array.
   Fix: skip carry paths where y != 0 when bits are inactive.

2. Infinite loop (caused ~50GB memory): arithmetic right shift on negative
   b never reaches 0 (-1 >> 1 = -1). Fix: work with abs(b) and track
   signs separately so shifting always terminates.

3. Sign of b lost: copysign(b_, abs(b_)) always returned abs(b_), so
   negative offsets were treated as positive. Fix: pass signed bit
   contributions (bsign .* (b .& 1)) to the core function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…xtension

The MPO(::TensorTrain; sites=...) and MPS(::TensorTrain; sites=...)
constructors used in fouriertransform.jl were moved from the standalone
TCIITensorConversion.jl package (dropped in 9cf8d28) to a weak-dep
extension in TensorCrossInterpolation.jl v0.9.18.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shinaoka shinaoka merged commit 5044db6 into main Feb 13, 2026
6 checks passed
@shinaoka shinaoka deleted the fix/affine-negative-b branch February 13, 2026 10:23
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.

Possible bug in affine_transform_core

1 participant