Skip to content

feat: resolve symbolic loop-opening op values from the solution - #4894

Open
baggepinnen wants to merge 3 commits into
masterfrom
bagge/symbolic-loop-opening-op
Open

feat: resolve symbolic loop-opening op values from the solution#4894
baggepinnen wants to merge 3 commits into
masterfrom
bagge/symbolic-loop-opening-op

Conversation

@baggepinnen

Copy link
Copy Markdown
Contributor

Implements the symbolic-value half of #4830 (the missing half was implemented in #4855).

What

Values in LinearizationOpPoint.op may now be symbolic expressions, e.g. op = Dict(opened_signal => driving_signal), which are evaluated from the wrapped solution at each time point. Mapping an opened signal to the expression that drives it thus linearizes around the value the opened signal has in the loop-closed solution — the natural operating point when linearizing along a trajectory with loop_openings.

Why resolve in _build_op_from_solution

Previously, symbolic values were passed through verbatim, and depending on the model they either

  • errored at problem construction, because MTKParameters evaluates operating-point values eagerly before any initialization has run ("Could not evaluate value of parameter … Missing values for variables in expression …"), or
  • silently produced a constant, stale linearization at every time point: _resolve_op_value routes symbolic values through getu(prob, v)(prob), but state values are written as Initial(x) parameters and prob.u0 is only refreshed by initialization inside solve, so the observed function evaluates against the construction-time state at every iteration of __linearize_multiple_op_barrier.

Resolving symbolic values against the solution inside _build_op_from_solution (once per value for all time points) means the downstream machinery — problem construction and the per-point setters — only ever sees numbers, avoiding both failure modes as well as any sensitivity to dict iteration order.

On a plant/controller loop where the controller dynamics are nonlinear in its input, the new test verifies that the per-point linearizations exactly match ground truth (and match single-point linearizations with manually resolved numeric values), where previously they were constant along the trajectory.

Also

  • missing op values are now skipped in __linearize_multiple_op_barrier, mirroring the skip added to single-point linearize in feat: allow passing missing for loop opening variables in linearize #4855 (they previously threw convert(Float64, ::Missing) in the multi-timepoint path).
  • Docstring of LinearizationOpPoint and the _check_loop_opening_op error message updated to mention symbolic values.

Not addressed (out of scope): symbolic op values in plain linearize without a solution still error at problem construction; supporting that would require initialization-level changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SWPXe76HwiugWWyLP7BYrL

Values in `LinearizationOpPoint.op` may now be symbolic expressions, e.g.
`opened_signal => driving_signal`, which are evaluated from the solution at
each time point. This linearizes the opened signal around the value it has in
the loop-closed solution, which is the natural operating point when
linearizing along a trajectory.

Previously such values were passed through verbatim: they either errored at
problem construction (eager varmap evaluation), or silently resolved via
`getu(prob, v)(prob)` against a `prob.u0` that is only refreshed by
initialization inside `solve`, yielding a constant stale linearization at
every time point.

Also skip `missing` op values in `__linearize_multiple_op_barrier`,
mirroring the skip added to single-point `linearize` in #4855.

Closes the symbolic-value half of #4830.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWPXe76HwiugWWyLP7BYrL
Comment thread src/linearization.jl Outdated
Comment thread src/linearization.jl Outdated
baggepinnen and others added 2 commits August 7, 2026 11:24
Co-authored-by: Aayush Sabharwal <aayush.sabharwal@gmail.com>
Co-authored-by: Aayush Sabharwal <aayush.sabharwal@gmail.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.

2 participants