ForceFreeStates - BUGFIX! - Keep the sign of crit so fixed-boundary crossings are detected - #419
Open
jhalpern30 wants to merge 1 commit into
Open
ForceFreeStates - BUGFIX! - Keep the sign of crit so fixed-boundary crossings are detected#419jhalpern30 wants to merge 1 commit into
jhalpern30 wants to merge 1 commit into
Conversation
…rossings are detected compute_smallest_eigenvalue returned findmin(abs, evals)[1], which is the smallest eigenvalue *magnitude* and therefore non-negative by construction. The caller detects conjugate points by testing crit_store[istep] * crit_store[istep-1] < 0, so that product could never be negative: no zero crossing was ever recorded and nzero was always zero, reporting every equilibrium as fixed-boundary stable. Return the signed eigenvalue at the smallest-magnitude index instead. This matches ode_output_get_crit in the Fortran, which sorts on -ABS(evalsi) to find the index and then returns evalsi at that index, keeping the sign. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YkwX4YMDVFaDi1NM9WcJD
Collaborator
Author
|
@logan-nc randomly came across this doing something completely different trying to understand benchmarking between 3D GPEC and TERPSICHORE. I had Claude look into something for me and it was like "by the way, here's a bug I found in your code"... idk how we missed this one On an unrelated note, Claude seems to think we can construct the fixed boundary marginal eigenfunctions with a few lines of code change (which is what its final note is about). Not sure if we would ever need this |
jhalpern30
marked this pull request as ready for review
August 21, 2026 19:09
logan-nc
approved these changes
Aug 21, 2026
logan-nc
left a comment
Collaborator
There was a problem hiding this comment.
oopsies! Good catch.
IDK why we'd ever need the eigenvector, but good to have the note on record I suppose.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release note
nzero, the fixed-boundary instability count, changes from always-zero to reporting genuine conjugate-point crossings (harness @ 39bfde6)nzero; equilibria previously reported stable may now be reported unstableForceFreeStates (FFS) reported every equilibrium as fixed-boundary stable. The critical eigenvalue
critwas stored as a magnitude rather than as a signed value, so the sign-change test that detects conjugate points could never fire andnzerowas always zero. Fixed-boundary instabilities are now detected.Regression report
Notes for reviewers
The mechanism.
findmin(abs, evals)returns the pair(min|λ|, index).compute_smallest_eigenvaluetook element[1]— the magnitude — socritwas non-negative by construction.check_for_zero_crossings!detects a conjugate point viacrit_store[istep] * crit_store[istep-1] < 0, and a product of two non-negative numbers is never negative, sonzerostayed at 0 for every run. The fix takes element[2]and indexes back intoevals, which is what the Fortranode_output_get_critdoes: it sorts on-ABS(evalsi)to locate the index, then returnsevalsiat that index, keeping the sign.Why the harness shows no movement.
diiid_n1is fixed-boundary stable, socritnever crosses zero andnzerois 0 both before and after. No tracked case currently exercises a fixed-boundary-unstable equilibrium, which is precisely the regime this bug hid. Suggested follow-up: add a regression case with a fixed-boundary-unstable equilibrium sonzerois actually pinned by the harness. I did not add one here to keep the change minimal, but it would be worth doing.Why the
!. Results move for any user running a fixed-boundary-unstable equilibrium: the reported stability verdict flips from stable to unstable. Nothing moves for stable cases.Deliberately out of scope. Switching
eigvals!toeigenhere would additionally expose the null vector at the crossing, which is what one needs to reconstruct fixed-boundary marginal eigenfunctions. That is a capability change, not a bug fix, and belongs in its own PR.Opened as a draft: no human reviewer is named yet. Per
docs/development/contributors.mdthe natural reviewers for ForceFreeStates are@logan-nc,@matt-pharr, or@d-burg— please pick one and mark ready for review.🤖 Generated with Claude Code
https://claude.ai/code/session_018YkwX4YMDVFaDi1NM9WcJD