Repository navigation
Let postcondition correctors declare the coordinates they act in - #1148
Closed
ChrisRackauckas-Claude wants to merge 5 commits into
Closed
ChrisRackauckas-Claude wants to merge 5 commits into
ChrisRackauckas-Claude wants to merge 5 commits into
Conversation
`lb`/`ub` bounds are handled by reparametrizing the iterate to an unconstrained variable, and that transform runs after the conditioning transform, so an iterate corrector was applied to the unconstrained coordinate. A limiting rule like SPICE `pnjlim` is written for a junction voltage in volts; applied to the logit of a scaled voltage it means nothing. Which space the corrector acts in is now the user's choice, defaulting to the problem's own variable. - `PostconditionSpecifier(H; space = :original | :transformed)` wraps the corrector value instead of adding a solve keyword, so no new SciMLBase `allowedkeywords` entry is needed. A bare corrector is `:original`. - `:original` maps each committed iterate back through the bounds transform, applies `H` there, and maps it forward again. A correction landing exactly on a bound is at infinity under the logit, so `_clamp_to_bounds` nudges it into the interior before the inverse map. - The initial-guess correction now runs on bounded problems in `:original` (`u0` is still in the original coordinates at that point). It stays skipped for `:transformed`, which is also the only case that reports the `postcondition_bounds_transform` verbosity toggle now. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Address review feedback: declare the postcondition coordinate space with EnumX (`PostconditionSpace.Original` / `PostconditionSpace.Transformed`) rather than bare symbols. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
The original-space bounded corrector path was broadcasting into new `u_orig`/`u_prev_orig` arrays on every commit. Reuse the `BoundedWrapper` temps (add a second `u_prev_cache`) so the in-place path is allocation-free. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Default is Original space, which matches user expectations, and Transformed is an explicit opt-in, so warning about it is unnecessary. Keep skipping the initial-guess correction for Transformed + bounds. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Member
Author
|
Closing as a duplicate — my error. This work is already on master via #1142 (merged 2026-08-07, The only diff between this branch and master is a one-line |
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.
Important
This PR should be ignored until reviewed by @ChrisRackauckas.
Follow-up to #1084, which added the
precondition/postconditionsolver options.The problem
lb/ubbounds are handled by reparametrizing the iterate to an unconstrained variable, and that transform runs after the conditioning transform — so an iterate corrector was applied to the unconstrained coordinate. A limiting rule like SPICEpnjlimis written for a junction voltage in volts; applied to the logit of a scaled voltage it means nothing. #1084 only warned about this.The change
Which space the corrector acts in is now the user's choice, defaulting to the problem's own variable:
PostconditionSpecifierwraps the corrector value rather than adding asolvekeyword, soallowedkeywordsin SciMLBase is untouched and this stays a one-repo change. A bare corrector means:original.:originalmaps each committed iterate back through the bounds transform, appliesHin the user's coordinates, and maps it forward again._clamp_to_boundsnudges it into the interior before the inverse map. Clamping onto a bound is exactly what a limiting/projection corrector does, so this is the common case, not a corner case.:original(u0is still in original coordinates at that point). It stays skipped for:transformed, which is now also the only case that reports thepostcondition_bounds_transformverbosity toggle — the warning fires only when the corrector really is acting in transformed coordinates.Unbounded problems are unaffected: with no
lb/ubthere is no transform and both spaces coincide.Why
:originalis the defaultCorrectors are written against physical quantities — a junction voltage, a concentration, a saturation — and every generated corrector we produce is of that kind (ModelingToolkit's
limited(...)operator compiles limiters for model variables). Defaulting to the coordinate the user wrote the rule in is the least surprising behaviour;:transformedremains available for correctors deliberately expressed in solver coordinates.Verification (local, Julia 1.12.4, registry NonlinearSolveBase 2.41.0 base)
All conditioning tests pass, and the suite grew where the new behaviour needed cover:
lib/NonlinearSolveBase/test/conditioning.jllib/NonlinearSolveFirstOrder/test/conditioning_tests__item1.jllib/NonlinearSolveFirstOrder/test/conditioning_tests__item2.jllib/NonlinearSolveQuasiNewton/test/core_tests__item10.jllib/NonlinearSolveSpectralMethods/test/core_tests__item6.jllib/SimpleNonlinearSolve/test/core/conditioning_tests__item1.jltest/Core/core_tests__item23.jlThe load-bearing test is a clamping corrector combined with bounds, asserting the clamp lands on the intended physical value under
:originaland on a different value under:transformed.Note on CI
Spell Check on this branch is red for a reason inherited from #1084 and unrelated to this change: the typo-rejection test deliberately misspells a keyword (
postcondtion) to assert the keyword whitelist rejects it. #1141 fixes that with a narrow typos-config entry. This branch will go green once that lands or is rebased in.🤖 Generated with Claude Code
https://claude.ai/code/session_01B9GHoo4pFa3DU9yhyTkevL