Conversation
Add tests
Draft initialconditions
Easier and type stable
There was a problem hiding this comment.
Pull request overview
This PR is a substantial refactor of Corleone’s optimal-control “shooting” stack: controls and initial conditions are re-modeled as Lux layers/containers, single/multiple shooting evaluation is rewritten around binned time intervals, and new parallel/observed layers plus updated tests/docs are added.
Changes:
- Replace the previous “local controls” implementation with
ControlParameter/ControlParameters(+ fixed controls) and anInitialConditionlayer. - Rework
SingleShootingLayer/MultipleShootingLayertrajectory evaluation and introduceParallelShootingLayer. - Add/adjust tests, docs, and extensions; add
RuntimeGeneratedFunctionsdependency.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
src/Corleone.jl |
Wire up new layers/utilities; add RuntimeGeneratedFunctions init; update exports. |
src/controls.jl |
New control parameter and control container implementations (incl. fixed controls). |
src/initializers.jl |
Introduce InitialCondition Lux layer for tunable ICs and bounds. |
src/single_shooting.jl |
Rewrite SingleShootingLayer as a Lux container and implement binned interval evaluation. |
src/parallel_shooting.jl |
Add ParallelShootingLayer wrapper for ensemble-based evaluation of multiple layers. |
src/multiple_shooting.jl |
Reimplement multiple shooting as a wrapper over ParallelShootingLayer + matching constraints. |
src/trajectory.jl |
Extend Trajectory to carry control time series; adjust indexing/constraints helpers. |
src/observed.jl |
Add ObservedLayer that builds runtime-generated observation functions over trajectories. |
src/dynprob.jl |
Partially stub/disable dynamic opt problem machinery (mostly commented out). |
src/local_controls.jl |
Removed legacy local-control implementation. |
test/controls.jl |
New tests for control parameter/container behavior and remake semantics. |
test/initializers.jl |
New tests for InitialCondition bounds/setup/call/remake. |
test/single_shooting.jl |
New single-shooting tests: constructors, binning, evaluation, symbolic access fallback. |
test/parallel_shooting.jl |
New tests for ParallelShootingLayer construction/evaluation/remake. |
test/multiple_shooting.jl |
Replace old Lotka multiple-shooting tests with new layer-level tests. |
test/observed.jl |
Add observed-layer tests (currently not wired into runtests.jl). |
test/runtests.jl |
Reorganize testsets and add new shooting tests; comment out some example testsets. |
test/local_controls.jl |
Removed legacy tests for old control implementation. |
test/examples/lotka_oc.jl |
Update example to new controls/symbolic setup and revised optimization wiring. |
Project.toml |
Add RuntimeGeneratedFunctions dependency; reorder extensions. |
ext/CorleoneModelingToolkitExtension.jl |
Update MTK extension for control time-series indexing and system remaking. |
ext/CorleoneMakieExtension.jl |
Update plotting to handle state vs parameter time series. |
ext/CorleoneComponentArraysExtension.jl |
Comment out prior ComponentArrays wrappers (extension becomes mostly inert). |
docs/src/api.md |
Replace autodocs with explicit public API list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
This PR refactors Corleone’s shooting/optimization “layers” API, introducing structured control and initial-condition layers, adding parallel/multiple shooting composition, and updating the trajectory representation and dynamic optimization wrapper accordingly.
Changes:
- Introduces
ControlParameter/ControlParametersandInitialConditionLux layers, and rewiresSingleShootingLayerto compose them. - Adds
ParallelShootingLayerand updatesMultipleShootingLayerto wrap parallel solves and emit unifiedTrajectoryobjects with shooting violations. - Reworks
Trajectoryto expose time-series controls/parameters via SymbolicIndexingInterface; updates tests, docs, and project dependencies (RuntimeGeneratedFunctions).
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| test/single_shooting.jl | Adds coverage for new SingleShootingLayer constructors/state/time-binning and symbolic access. |
| test/runtests.jl | Reorganizes/renames testsets and adds new shooting/initializer/controls test files. |
| test/parallel_shooting.jl | Adds tests for ParallelShootingLayer block structure, evaluation, and remake behavior. |
| test/multiple_shooting.jl | Replaces older multi-shooting tests with new API exercising matching constraints and remake. |
| test/local_controls.jl | Removes legacy local-controls tests (replaced by test/controls.jl). |
| test/initializers.jl | Adds tests for InitialCondition construction/bounds/setup/call/remake. |
| test/examples/lotka_oc.jl | Updates example tests to new control/system wiring and DynamicOptimizationLayer. |
| test/controls.jl | Adds comprehensive tests for ControlParameter/ControlParameters, bounds, evaluation, and remake. |
| src/trajectory.jl | Extends Trajectory with control time series and revises symbolic indexing + shooting constraints utilities. |
| src/single_shooting.jl | Refactors single shooting to compose initial conditions + controls and rebuild symbolic systems. |
| src/parallel_shooting.jl | Introduces a wrapper to solve multiple layers via SciML ensemble mapping. |
| src/node_initialization.jl | Adds InitialCondition Lux layer implementation (and leaves legacy node init commented). |
| src/multiple_shooting.jl | Reimplements multiple shooting on top of ParallelShootingLayer, adds matching calculations. |
| src/local_controls.jl | Removes legacy local-controls implementation (replaced by src/controls.jl). |
| src/dynprob.jl | Replaces old dynamic opt problem wrapper with DynamicOptimizationLayer using runtime-generated getters. |
| src/controls.jl | Adds new controls layer system: tunable/fixed controls, containers, bounds/remake/eval utilities. |
| src/Corleone.jl | Wires new modules/exports, introduces MAXBINSIZE, and adds RuntimeGeneratedFunctions init. |
| ext/CorleoneModelingToolkitExtension.jl | Updates MTK extension logic for timeseries parameter indexing (but see Project.toml note). |
| ext/CorleoneMakieExtension.jl | Updates plotting conversion to support variables and time-series parameters/controls. |
| ext/CorleoneComponentArraysExtension.jl | Updates ComponentArrays vectorization integration to the new WrappedFunction approach. |
| docs/src/api.md | Replaces broad autodocs with curated API docs list. |
| Project.toml | Adds RuntimeGeneratedFunctions; changes extension registration and removes ModelingToolkit weakdep/extension. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fix docstring Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
length(params) == length(t)
┌──────────────────────────┬───────┬─────┬──────┬─────┐
│ Filename │ Lines │ Hit │ Miss │ % │
├──────────────────────────┼───────┼─────┼──────┼─────┤
│ src/Corleone.jl │ 33 │ 21 │ 12 │ 64% │
│ src/controls.jl │ 132 │ 124 │ 8 │ 94% │
│ src/dynprob.jl │ 108 │ 85 │ 23 │ 79% │
│ src/initializers.jl │ 43 │ 42 │ 1 │ 98% │
│ src/multiple_shooting.jl │ 62 │ 61 │ 1 │ 98% │
│ src/parallel_shooting.jl │ 29 │ 25 │ 4 │ 86% │
│ src/single_shooting.jl │ 97 │ 94 │ 3 │ 97% │
│ src/trajectory.jl │ 35 │ 24 │ 11 │ 69% │
├──────────────────────────┼───────┼─────┼──────┼─────┤
│ TOTAL │ 539 │ 476 │ 63 │ 88% │
└──────────────────────────┴───────┴─────┴──────┴─────┘
Target coverage was met (80%) |
|
@chplate Let's open up a PR into this branch to fix OED. I do not think we need a dev branch. Its just a naming convention here. |
There was a problem hiding this comment.
Pull request overview
This PR refactors Corleone’s shooting/optimal-control stack into more composable Lux layers (initial conditions + controls), adds parallel/modernized multiple-shooting support, and updates the dynamic-optimization wrapper plus docs/tests accordingly.
Changes:
- Introduces new control layer APIs (
ControlParameter,FixedControlParameter,ControlParameters) and anInitialConditionlayer. - Reworks
SingleShootingLayer/MultipleShootingLayerinternals and addsParallelShootingLayer. - Replaces the prior dynamic optimization problem wrapper with
DynamicOptimizationLayer, updating docs and tests.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/controls.jl | New control parameter and container layer implementations. |
| src/initializers.jl | Adds InitialCondition layer and remaking behavior. |
| src/single_shooting.jl | Refactors single-shooting to compose IC + controls, adds binning-based evaluation. |
| src/parallel_shooting.jl | Adds parallel wrapper for solving multiple shooting layers concurrently. |
| src/multiple_shooting.jl | Re-implements multiple shooting as wrapper over ParallelShootingLayer + matching constraints. |
| src/trajectory.jl | Extends Trajectory to include control time series and updates indexing behavior. |
| src/dynprob.jl | Introduces DynamicOptimizationLayer and new expression-driven objective/constraints. |
| src/Corleone.jl | Wires in new modules/exports and adds RuntimeGeneratedFunctions. |
| ext/CorleoneComponentArraysExtension.jl | Updates ComponentArrays integration for the new optimization wrappers. |
| ext/CorleoneMakieExtension.jl | Updates plotting to support parameter time-series controls. |
| ext/CorleoneModelingToolkitExtension.jl | Updates MTK extension code (still present as an extension module). |
| docs/src/api.md | Updates API reference to list new types/functions explicitly. |
| Project.toml | Adds RuntimeGeneratedFunctions and adjusts extensions/weak deps. |
| test/* | Adds/reworks tests for controls, initializers, and shooting layers; trims older tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| layers = map(keys(layer.layers)) do k | ||
| layer_kwargs = get(kwargs, k, kwargs) | ||
| k, remake(layer.layers[k]; layer_kwargs...) | ||
| end |> NamedTuple | ||
| ensemble_algorithm = get(kwargs, :ensemble_algorithm, layer.ensemble_algorithm) | ||
| return ParallelShootingLayer(layer.name, layers, ensemble_algorithm) |
| module CorleoneModelingToolkitExtension | ||
|
|
||
| @info "Loading MTK Extension" | ||
|
|
||
| using Corleone | ||
| using ModelingToolkit | ||
|
|
||
| using Corleone.LuxCore | ||
| using Corleone.Random | ||
| using Corleone.DocStringExtensions | ||
| using Corleone.SciMLBase | ||
|
|
||
| using ModelingToolkit.Symbolics | ||
| using ModelingToolkit.SymbolicUtils | ||
| using ModelingToolkit.Setfield | ||
| using ModelingToolkit.SymbolicIndexingInterface | ||
| using ModelingToolkit.Symbolics.RuntimeGeneratedFunctions | ||
|
|
||
| using ModelingToolkit: IndexCache, DiscreteIndex, BufferTemplate, ParameterTimeseriesIndex | ||
|
|
||
| @info "Loading MTK Extension..." | ||
|
|
||
| RuntimeGeneratedFunctions.init(@__MODULE__) | ||
|
|
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Construct a SciML `OptimizationProblem` from a [`CorleoneDynamicOptProblem`](@ref). | ||
| """ | ||
| function SciMLBase.OptimizationProblem( | ||
| prob::CorleoneDynamicOptProblem, ad::SciMLBase.ADTypes.AbstractADType, vectorizer; | ||
| prob::DynamicOptimizationLayer, ad::SciMLBase.ADTypes.AbstractADType, | ||
| ps = nothing, | ||
| st = nothing; | ||
| rng::Random.AbstractRNG = Random.default_rng(), | ||
| vectorizer, | ||
| sense = nothing, | ||
| kwargs... | ||
| ) | ||
| p0, st = LuxCore.setup(rng, prob.layer) | ||
| objective, cons = wrap_functions(vectorizer, p0, prob.objective, prob.constraints) | ||
| optf = SciMLBase.OptimizationFunction{true}(objective, ad; cons, kwargs...) | ||
| u0_, lb, ub = to_vec(objective, p0, Corleone.get_bounds(prob.layer)...) | ||
| return SciMLBase.OptimizationProblem(optf, u0_, st; lb, ub, lcons = prob.lcons, ucons = prob.ucons, sense = sense) | ||
| ps = something(ps, LuxCore.initialparameters(rng, prob)) | ||
| st = something(st, LuxCore.initialstates(rng, prob)) | ||
| optf = SciMLBase.OptimizationFunction(prob, ad; vectorizer, rng, ps, st, kwargs...) | ||
| u0, lb, ub = map(Base.Fix1(to_vec, vectorizer), (ps, Corleone.get_bounds(prob)...)) | ||
| return SciMLBase.OptimizationProblem(optf, u0, st; lb, ub, lcons = prob.lcons, ucons = prob.ucons, sense = sense) | ||
| end | ||
|
|
||
| function SciMLBase.OptimizationProblem( | ||
| layer::Union{SingleShootingLayer, MultipleShootingLayer}, | ||
| ad::SciMLBase.ADTypes.AbstractADType, vectorizer; | ||
| loss::Union{Symbol, Expr}, | ||
| constraints = [], | ||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Construct a SciML `OptimizationFunction` from a [`CorleoneDynamicOptProblem`](@ref). | ||
| """ | ||
| function SciMLBase.OptimizationFunction( |
| reduce(vcat, _collect_tspans(st_.tspans...)) | ||
| end | ||
| ) | ||
| throw(error("The operator $(op) is not supported to define constraints. Only ==, <=, and >= are supported.")) |
| Parameter indexing through `getindex` is deprecated; use `A.ps[sym]` instead. | ||
| """ | ||
| function Base.getindex(A::Trajectory, sym) | ||
| if is_parameter(A, sym) | ||
| error("Indexing with parameters is deprecated. Use `sol.ps[$sym]` for parameter indexing.") |
Checklist
contributor guidelines, in particular the SciML Style Guide and
COLPRAC.
Additional context
This effectively replaces #38.