Repository navigation
feat(Solutions): switching structure of a solution; strict time grids - #463
Merged
Merged
Conversation
A Solution keeps the switching structure of a solution made of phases: switching times, phase labels, and left/right limits of the state, costate and control (`build_solution(...; switching=SwitchingModel(...))`). Sampled trajectories are interpolated with the limits; the display lists the switching times and phases; plots draw the jumps as vertical segments, with lines at the switching times and the phase labels; JLD2/JSON save and read the structure back. Breaking: a time grid with a repeated time raises an IncorrectArgument. Refs #460, control-toolbox/CTFlows.jl#443. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 18, 2026
- PlotCase uses Plotting.splice_jumps / switching_vlines / phase_annotations instead of its own copies (shared with CTFlows); _phase_label_group extracted from _build_root - left_limit/right_limit: PreconditionError when the limits are not stored (EXC1) - suggestions on every new error (EXC3); one component check for the limits - one pass for the repeated-time check; serialized limit keys from one function, reused by the JSON extension Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g models - plot(sol; jumps=:none) breaks the curves between the two limits instead of drawing the vertical segment (default :segment); the path constraints are evaluated at both limits and spliced the same way - Base.show for SwitchingModel (tree, as the Solution display) and EmptySwitchingModel; the phase sequence comes from one helper Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
This was referenced Oct 18, 2026
…tching_vlines, phase_annotations) Tested against the registered release: full suite and docs build. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Closes #460. Part of the switching-structure work tracked in control-toolbox/CTFlows.jl#443.
Depends on control-toolbox/CTBase.jl#613 (
Plotting.Annotation, used for the phase labels). CI stays red until that CTBase version is released and the compat is bumped. Locally, the tests run against the CTBase branch withPkg.develop.What
SwitchingModel/EmptySwitchingModel.(left, right)limits of the state, costate and control. Each limits matrix has one row per switching time, and no column when the limits are not known.Flow(ocp, law)Solution: reconstruct the constraint duals from the multipliers CTFlows.jl#472.Solutiongets an 11th field,switching. It is the last type parameter. The 10-argument positional constructor is kept and builds anEmptySwitchingModel.build_solution(...; switching=...)works in both variants._JumpInterpolant): the interpolation goes from the last grid point up to the left limit, and from the right limit to the next grid point. A jump is therefore not smeared over the next grid cell. Function trajectories are used as given.switching_model,switching_times,phase_labels,has_switching,left_limit(sol, c, i)andright_limit(sol, c, i). A 1-D component is returned as a scalar (DIM1).Switching times : [...]andPhases : bang → · → boundary.PlotCase, so both Plots and Makie).tᵢ, so each jump is drawn as a vertical segment. This applies to the state, costate, control, control norm, and the path constraints evaluated at both limits.switching_style. By default they look like the time markers, and a usertime_styleapplies to them too.:nonehides them.phase_labels = :control | :all | :noneandphase_labels_style. The labels arePlotting.Annotations centred on each phase. When the control is not drawn,:controluses the first drawn group.switching_times,phase_labelsandswitching_<component>_<left|right>. They are written only when the solution has a switching structure.format_versionbecomes 2. Files without these keys load with anEmptySwitchingModel.Breaking
A time grid with a repeated time now raises an
IncorrectArgument. It used to be accepted silently.BREAKING.mdgives a migration block. Suggested release: 0.20.0.Checked: CTDirect already rejects grids that are not strictly increasing (
DOCPtime) and derives all its grids from that one, so it never passes a repeated time. The OptimalControl suite has not been run.Tests
suite/solutions/test_switching.jl(100 tests): construction and defaults, every error with its exception type, getters (scalar and vector), jump-aware interpolation (τon or between grid points, piecewise-constant control, function data, unknown limits, multiple grids), strict grid, the 10-argument constructor, display (labels,·, no rows, separator),@inferred.suite/plotting/test_plot_switching.jl(67): splicing (τon the grid, inserted, after the last sample, unchanged cases), vertical segments in every panel, the control norm, path constraints at the limits, switching lines (style inheritance and merge,:none, kept whentime_style=:none, normalised time), labels (default,:all,:none, style, empty labels, fallback, group layout, single labelled phase), invalidphase_labels, keyword routing.suite/extensions/test_plot_switching_render.jl(15): rendering with Plots (the series holds the vertical segment, annotations on the control subplot) and with Makie (VLinesandTextcounts).suite/serialization/test_switching_serialization.jl(96): serialized keys, deserialization, JLD and JSON round trips (limits, labels, trajectories with jumps), labels only, a labelled single phase, files without the keys, a version-1 file.The full suite passes locally: 79,424 existing tests with no regression, plus the new files (one run before the last test fixes, then the new files again). The docs build cleanly (two passes), including the examples of the new page.
Found along the way (not fixed here)
A solution built without
iterationsorconstraints_violation(NotProvided) does not survive an export/import round trip:Float64(NotProvided)fails in JLD2, andFloat64(::String)fails in JSON. This is the case for every solution built byCTFlows.Flow(ocp, law). Worth a separate issue.🤖 Generated with Claude Code