Repository navigation
fix(solutions): dual() on missing duals + limits of the path duals at switching times - #483
Merged
Merged
Conversation
…ind were not stored A solution may carry the duals of some constraints only (a flow solution carries the path duals). dual(sol, model, label) then returned a function that failed with a MethodError on call (box labels), or failed at once (boundary labels). It now throws a PreconditionError naming the kind of constraint and how to get its duals. The message of the dual-free case no longer says that a flow solution has no duals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wn as jumps SwitchingModel gains the component :path_dual, the (left, right) limits of the duals of the path constraints at each switching time (no column when not known, the default). The dual panel of the plots splices them as the state, costate and control panels do, so a multiplier that jumps at the entry or exit of a boundary arc is drawn as a vertical segment (or a break, with jumps=:none). Serialized with the other limits; a file written before loads with the dual limits not known. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 23, 2026
…oducer; unknown label checked first When a dual is missing, the suggestion of the PreconditionError is the note left by the producer of the solution in infos(sol)[:missing_duals], when there is one: CTFlows knows why it could not rebuild a dual and how to get it. An unknown label is now an IncorrectArgument on every solution, including one with no dual at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ocots
added a commit
to control-toolbox/CTFlows.jl
that referenced
this pull request
Oct 23, 2026
…issing_duals] dual(sol, ocp, :label) uses this note as the suggestion of its PreconditionError (control-toolbox/CTModels.jl#483): a constraint given without label, or the boundary and box duals, which a flow does not compute (#495). A zero would be wrong for them: a boundary constraint is always active, a control box is active on a bang arc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
|
Update: two more changes in
|
…s SGN2, SGN3) dual(sol, model, :box_label) returns the lower-bound multiplier for a component with a lower bound only, the upper-bound multiplier (>= 0) for an upper bound only, and ub_dual - lb_dual for two finite bounds or a fixed component (it was lb_dual - ub_dual). The same constraint written as a box and as a path constraint now has the same dual (SGN5). The Duals & Diagnostics page states the convention, with a reference to ct-conventions SGN1-SGN6, the errors of dual, and the dual of a box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
|
Update: the sign of the box duals is aligned with the convention (open question 1 of the description), and the convention now has a reference, control-toolbox/ct-conventions#49 (
|
Member
Author
|
Note Release 0.21.0 right after merging. CTFlows#494 depends on this release ( |
Closed
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.
Needed by control-toolbox/CTFlows.jl#494 (#472, constraint duals of a flow solution). Convention: control-toolbox/OptimalControl.jl#1014.
Conventions applied: ct-conventions v0.8.0 · ct-agents v0.3.0.
What this PR does
1.
dual(sol, model, label)when some duals were not stored (bug fix)A solution may carry the duals of some kinds of constraints only. The solution of a CTFlows flow, for instance, carries the path duals only. For a label whose kind has no stored dual,
dualused to:BoxDualDiff(nothing, nothing, i), which failed withMethodError: objects of type Nothing are not callablewhen called;nothing[i].It now throws a
PreconditionErrorthat names the kind of constraint and how to get its duals. The message for a solution with no dual at all no longer says "a solution built by a flow has none".Why
PreconditionErrorand notIncorrectArgument(EXC1): the label is valid (it exists in the model), and so is the solution. What is wrong is the pair: this solution holds no dual of that kind. This is also the type already used when a solution has no dual at all. An unknown label still throwsIncorrectArgument.2. Limits of the path duals in the switching model (feature)
SwitchingModelgains the component:path_dual: the(left, right)limits of the duals of the path constraints at each switching time. It is a keywordpath_dual, with no column (not known) by default.limits,left_limit,right_limitaccept it, andbuild_solutionchecks its number of columns (0ordim_path_constraints_nl).PlotCase): the dual panel splices the limits like the state, costate and control panels. A multiplier that jumps at the entry or exit of a boundary arc is drawn as a vertical segment, or as a break withjumps = :none.The phase labels already go to the first drawn group when the control is not drawn: tested here for
plot(sol, :dual).Tests
test_dual_model.jl: every kind of label on a solution with the path duals only, and the reverse.test_switching.jl:path_duallimits, defaults, display, and shape errors.test_plot_switching.jl: the jump of the dual panel,jumps=:none, limits not known, and the labels on the dual cell.test_switching_serialization.jl: the new keys, and an old file without them.Locally:
solutions,plotting,serializationandextensionssuites, 3243 passed.Documentation
Switching structure: the
path_duallimits, with an example plotted.CHANGELOG.md/BREAKING.md: a feature, a fix, and a near-breaking note (a new field ofSwitchingModel, whose default positional constructor changes; the documented keyword constructor does not).Next version:
0.20.1(no breaking change by REL1). control-toolbox/CTFlows.jl#494 will require it.Open questions
dual(sol, model, :box_label)returnslb_dual − ub_dual. For a box with only an upper bound, that is−zU ≤ 0, while a path row with only an upper bound givesμ ≥ 0in the convention of CTSolvers#288. So the same constraint written as a box or as a path row has duals of opposite signs.lb_dualorub_dual). For a two-sided box, keepub_dual − lb_dual, to matchy = μU − μL.🤖 Generated with Claude Code