All notable changes to OptimalControl.jl are documented here.
The format follows Keep a Changelog. Versions follow Semantic Versioning.
- Documentation improvements:
- Added scalar vs vector convention warning in functional API documentation explaining that callbacks always receive vectors (use x[1], u[1], v[1] for dim 1), while solution access returns scalars for dim 1 components (consistent with @def)
- Added example demonstrating scalar return from control(sol)(t) after solving dim-1 control problem
- Added modeler compatibility warning in functional API documentation: :exa modeler requires @def, only :adnlp is compatible with functional API
- Updated solve manual :exa description to mention incompatibility with functional API
- Documentation:
- Added ExampleSizeThresholdFilter logger in make.jl to silence harmless warning about @example blocks exceeding example_size_threshold (SVG fallback is used automatically)
- Added manual-macro-free.md to size_threshold_ignore in HTML configuration
- Removed redundant section separators (---) between examples in manual-macro-free.md
- Fixed heading level in index.md (### -> **) for "Free times and extra variables" section
- Functional API:
- New macro-free functional API for defining optimal control problems programmatically
- Uses
OptimalControl.PreModelas a mutable builder with setter functions:time!,state!,control!,variable!,dynamics!,objective!,constraint!,time_dependence!,build - Complete mathematical formulation correspondence table between math and functional API
- Six comprehensive examples comparing @def syntax with functional API:
- Double integrator: energy minimisation
- Double integrator: time minimisation (free final time)
- Control-free problems (parameter estimation)
- Problems mixing control and variable
- Singular control (three-dimensional state, state and control box constraints)
- State constraint (velocity upper bound)
- API Reference section documenting all functional API functions
-
Documentation:
- Restructured documentation TOC with "Define a problem" section containing both abstract syntax and functional API
- Fixed constraint dimension functions in CTModels v0.9.15-beta API compatibility
- Updated CTModels dependency to v0.10 (widening support)
-
Dependencies:
- Updated CTModels from v0.9.15-beta to v0.10
-
Documentation examples:
- New comprehensive state constraint example (
example-state-constraint.md) demonstrating first-order and second-order (Bryson-Denham) state constraints - Direct method implementation with parametric OCP for both touch point and boundary arc cases
- Indirect methods for touch point (2-arc) and boundary arc (3-arc) cases with shooting functions
- Theoretical references: Bryson et al. (1963), Jacobson et al. (1971), Bryson & Ho (1975)
- Hamiltonian-based adjoint chain explanations for boundary arc dynamics
- New example for problems mixing control and variable (
example-control-and-variable.md) with two examples:- Exponential growth rate estimation with control (non-autonomous problem)
- Harmonic oscillator pulsation optimization with control (autonomous problem)
- Demonstrates optimal control problems with both control variables and constant parameters to optimize
- Indirect methods with augmented Hamiltonian and maximising control laws
- New comprehensive state constraint example (
-
Documentation improvements:
- Added "Syntax rules" subsection to
@initmacro documentation explaining LHS/RHS rules, default component names (x₁, x₂), and prohibition of indexed syntax xi - Added "Cross-spec substitution" section to
@initmacro documentation with examples: temporal→temporal, transitive chain, constant→temporal, constant→constant, and mixing with aliases - Updated "Component labels and time variable" callout to mention default subscripted component names
- Added "Syntax rules" subsection to
-
Documentation organization:
- Extracted state constraint section from
example-double-integrator-energy.mdinto dedicated example file - Added cross-references between energy minimization and state constraint examples
- Added "Control and variable" example to Basic Examples section in documentation navigation
- Fixed heading level in
example-control-free.md(## -> ###) for proper hierarchy
- Extracted state constraint section from
-
Dependencies:
- Updated UnoSolver from v0.2 to v0.3
-
Exports:
build_initial_guessis now explicitly reexported with@reexport importfor better visibility
-
Documentation improvements:
- Added anchor link to "Strategy options" section in manual-solve.md for better navigation
- Updated
route_todocumentation to support multi-strategy routing with positional syntax - Changed
route_tosyntax examples from keyword arguments (route_to(exa=12)) to positional arguments (route_to(:exa, 12)) - Added documentation for routing the same option to multiple strategies with different values using alternating strategy-value pairs
Major version release with complete solve architecture redesign. This release introduces breaking changes from v1.1.6 (last stable release). See BREAKING.md for detailed migration guide.
-
Removed functions from v1.1.6:
direct_transcription→ replaced bydiscretizeset_initial_guess→ replaced by@initmacrobuild_OCP_solution→ replaced byocp_solution
-
Changed exports:
- CTBase exceptions: removed
IncorrectMethod,IncorrectOutput,UnauthorizedCall; addedPreconditionError - CTFlows types:
VectorField,Hamiltonian,HamiltonianLift,HamiltonianVectorFieldno longer exported (use qualified access)
- CTBase exceptions: removed
-
New solve architecture:
methods()now returns 4-tuples(discretizer, modeler, solver, parameter)instead of 3-tuples- Parameter (
:cpuor:gpu) is now required for complete method specification
-
Complete solve architecture redesign:
-
Descriptive mode:
solve(ocp, :collocation, :adnlp, :ipopt, :cpu)with symbolic strategy specification -
Explicit mode:
solve(ocp; discretizer=Collocation(), modeler=ADNLP(), solver=Ipopt())with typed components - Partial specification: Auto-completion of missing strategies using first matching method
-
Method introspection:
methods()lists all available solving methods
-
Descriptive mode:
-
GPU/CPU parameter system:
- 4th parameter in method tuples for execution backend (
:cpuor:gpu) - Explicit GPU support via
:gpuparameter with ExaModels + MadNLP/MadNCL - 12 total methods: 10 CPU methods + 2 GPU methods
- 4th parameter in method tuples for execution backend (
-
Advanced option routing system:
-
describe(strategy): Display available options for any strategy (discretizer, modeler, solver) -
route_to(strategy=option=>value): Disambiguate shared options between strategies -
bypass(strategy=option=>value): Pass undeclared options to strategies - Automatic option routing to appropriate components
- Option introspection:
options(),option_names(),option_type(),option_description(),option_default()
-
-
Initial guess with @init macro:
- New
@initmacro for constructing initial guesses - Alias
initforinitial_guesskeyword argument in solve - Replaces functional initial guess construction from v1.1.6
- New
-
Control-free problems support:
- Optimal control problems without control variables
- Optimization of constant parameters in dynamical systems
- Full integration with solve pipeline
-
Augmented Hamiltonian approach:
augment=truefeature in CTFlows for automatic costate computation -
Simplified flow creation:
Flow(ocp)directly creates Hamiltonian flow from control-free problems - Mathematical framework: Complete transversality conditions for variable parameters
- Documentation: Comprehensive examples with exponential growth and harmonic oscillator
-
New solvers:
-
Uno: CPU-only nonlinear optimization solver (methods with
:uno) -
MadNCL: GPU-capable solver (methods with
:madncl) - Total of 5 solvers: Ipopt, MadNLP, Uno, MadNCL, Knitro
-
Uno: CPU-only nonlinear optimization solver (methods with
-
Additional discretization schemes:
- Basic schemes:
:trapeze,:midpoint,:euler(and aliases),:euler_implicit(and aliases) - ADNLP-specific schemes:
:gauss_legendre_2,:gauss_legendre_3(high-order collocation)
- Basic schemes:
-
Comprehensive documentation rewrite:
- New solve manual with descriptive/explicit modes
- Advanced options guide with routing and disambiguation
- GPU solving guide
- Initial guess guide with
@initmacro - Differential geometry tools manual
- Control-free problems example
-
Modernized reexport system:
- Using
@reexport importfrom Reexport.jl - Organized by source package (ctbase.jl, ctdirect.jl, ctflows.jl, ctmodels.jl, ctparser.jl, ctsolvers.jl)
- Cleaner separation between imported and exported symbols
- Using
-
CTFlows enhancements:
-
Augmented Hamiltonian computation:
augment=trueautomatically computes costates for variable parameters -
Direct OCP flow creation:
Flow(ocp)creates Hamiltonian flow without manual Hamiltonian definition -
Transversality conditions: Automatic handling of
$p_\lambda(t_f) = 0$ for Lagrange costs and$p_\omega(t_f) = -2\omega$ for Mayer costs - Mathematical rigor: Complete augmented system dynamics with proper initial conditions
-
Augmented Hamiltonian computation:
-
Strategy registry system:
-
StrategyRegistrywith metadata for all strategies -
StrategyMetadatawith id, options, and parameter support -
OptionDefinitionwith type, default, description, and aliases - Dependency injection support for testing
-
-
Solve function signatures:
- Layer 3 (canonical):
solve(ocp, strategies...; kwargs...) - Layer 2 descriptive:
solve_descriptive(ocp, strategies...; kwargs...) - Layer 2 explicit:
solve_explicit(ocp; discretizer, modeler, solver, kwargs...) - Automatic mode detection based on argument types
- Layer 3 (canonical):
-
Component completion:
- Intelligent completion of missing strategies using registry
- First-match priority from
methods()list - Support for partial method specifications
-
Display system:
- Configuration box showing applied strategies and options
- Option source tracking (user, default, computed)
- Parameter display for GPU/CPU distinction
- Improved formatting and clarity
-
Test infrastructure:
- Comprehensive test suite for solve pipeline (422+ tests)
- Integration tests with real strategies
- Mock registry for dispatch testing
- Parametric mocks for strategy testing
- Level 3 signature freezing tests for API stability
- CTBase: 0.18.x (was 0.16-0.17)
- CTModels: 0.9.x (was 0.6.x)
- CTDirect: 1.x (was 0.x)
- CTSolvers: 0.4.x (new dependency)
- CTParser: 0.8.x (was 0.7-0.8)
- CTFlows: 0.8.x
New dependency: CTSolvers.jl handles NLP modeling, solving, and strategy orchestration.
This release consolidates all beta versions (1.2.0-beta through 1.3.1-beta) into a stable 2.0.0 release. The comparison is made against v1.1.6, the last stable release before the architectural redesign.
For users migrating from v1.1.6, please consult BREAKING.md for detailed migration instructions and examples.
-
Uno solver integration: Full support for the Uno nonlinear optimization solver
- Added to solver registry with CPU-only support
- Added methods
(:collocation, :adnlp, :uno, :cpu)and(:collocation, :exa, :uno, :cpu)to available methods - Uno compatible with both ADNLP and Exa modelers
- Comprehensive test coverage with Beam and Goddard problems
- Extension error handling when
UnoSolverpackage not loaded
-
Solver requirements documentation: Clear documentation of required imports for each solver
- New "Solver requirements" section in
manual-solve.md - Updated examples in
manual-solve-explicit.mdwith import instructions - GPU requirements clarification in
manual-solve-gpu.md - Based on CTSolvers extension triggers:
- Ipopt:
using NLPModelsIpopt - MadNLP:
using MadNLP(CPU) orusing MadNLPGPU(GPU) - Uno:
using UnoSolver - MadNCL:
using MadNCLandusing MadNLP - Knitro:
using NLPModelsKnitro(commercial license)
- Ipopt:
- New "Solver requirements" section in
-
Solver output detection:
will_solver_print(::CTSolvers.Uno)method to check if Uno will produce output based onloggeroption (silent whenlogger="SILENT")
- Solver count: Updated from 4 to 5 available solvers (Ipopt, MadNLP, Uno, MadNCL, Knitro)
- Method count: Updated from 10 to 12 available methods (10 CPU + 2 GPU)
- Test structure: Restructured canonical tests to use modeler-solver pairs, Uno now works with both ADNLP and Exa
- Documentation: Updated solver lists and examples throughout documentation to include Uno
Unreleased — branch action-options
- Action options routing:
initial_guessanddisplayare now routed throughCTSolvers.route_all_options, enabling alias support and a cleaner separation of concerns between action-level and strategy-level options. - Alias
initforinitial_guessin all solve modes:solve(ocp, :collocation; init=x0)
_extract_action_kwarghelper insrc/helpers/kwarg_extraction.jl: alias-aware extraction with conflict detection (raisesCTBase.IncorrectArgumentwhen two aliases are provided simultaneously).- DRY constants in
src/helpers/descriptive_routing.jl:_DEFAULT_DISPLAY = true_DEFAULT_INITIAL_GUESS = nothing_INITIAL_GUESS_ALIASES_ONLY = (:init,)— used inOptionDefinition_INITIAL_GUESS_ALIASES = (:initial_guess, :init)— used in_extract_action_kwarg
- Docstring for the Layer 3
CommonSolve.solvemethod insrc/solve/canonical.jl.
CommonSolve.solvetop-level signature simplified:initial_guessanddisplayare no longer explicit named arguments — they are extracted fromkwargs...by the routing layer.solve_descriptiveno longer acceptsinitial_guessanddisplayas explicit named arguments; they are extracted fromkwargs...via_build_components_from_routed.solve_explicitextractsinitial_guess(with aliasinit) anddisplayfromkwargs...using_extract_action_kwarg._build_components_from_routednow receivesocpas first argument to callCTModels.build_initial_guess.
- Alias
:iforinitial_guess(too short, risk of collision with user variables).
- Level 3 signature freezing tests for reexport API across all CTX packages:
- Type hierarchy checks for inheritance relationships (e.g.,
Collocation <: AbstractDiscretizer) - Method signature checks with
hasmethod()for key functions (e.g.,discretize,solve,ocp_model) - Missing symbols
solveandplot!now properly tested - 503 reexport tests passing, up from 497
- Type hierarchy checks for inheritance relationships (e.g.,
- Simplified ExaModels documentation: removed warnings about coordinate-by-coordinate
dynamics and scalar nonlinear constraints requirements, improving user experience
when using the
:examodeler for GPU solving - Removed outdated API documentation:
docs/src/api/private.mddeleted
- API breakage detection: tests now detect when CTX packages modify their APIs, preventing silent breakages in OptimalControl.jl
-
Comprehensive unit tests for display helper functions (29 new tests):
- Parameter extraction tests
- Display strategy determination tests
- Source tag building tests
- Component formatting tests
-
Helper functions for improved code architecture:
_extract_strategy_parameters: Extract parameters from strategies_determine_parameter_display_strategy: Decide parameter display logic_print_component_with_param: Format components with parameters_build_source_tag: Build option source tags (DRY elimination)
-
Refactored
display_ocp_configurationto follow SOLID principles:- Extracted focused helper functions (Single Responsibility)
- Eliminated code duplication (DRY)
- Improved testability and maintainability
- Reduced function length from ~180 to ~120 lines
-
Enhanced test coverage: 75 tests for print helpers (46 existing + 29 new)
-
Adjust allocation limits in component completion tests for realistic bounds
- Parameter extraction now correctly handles real strategies with default parameters
- Source tag building properly handles empty parameter arrays
- All 1215 tests pass with improved architecture
- Complete GPU/CPU parameter system with 4-tuple methods returning parameter
- Strategy builders with ResolvedMethod support and parameter-aware mapping
- Comprehensive test coverage: 422 tests total across all helper modules
- Registry enhancements for parameter-based strategy routing
- Dependency handling for both provided and build strategy construction paths
- Methods API:
Base.methods()now returns 4-tuples with parameter symbol - Registry: Parameter-aware strategy mapping and resolution
- Strategy builders: Enhanced with parameter support and ResolvedMethod integration
- Test infrastructure: Comprehensive test suites for all helper functions
- Initial GPU/CPU parameter infrastructure
- Parameter-aware method resolution system
- Basic strategy registry with parameter support
- Foundation for GPU solving via ExaModels backend
- Internal architecture preparation for parameter system
- Test structure for parameter-aware components
1.1.8-beta — 2026-01-17
- Widened compat for CTParser to accept
0.7and0.8(preparation for CTParser v0.8.x migration, tracked in control-toolbox/CTParser.jl#207). - Widened compat for CTBase to accept
0.16and0.17.
1.1.7-beta — 2026-01-17
- Added compat for CTBase v0.17.
- Merged test dependencies into the main
Project.toml(previously in a separatetest/Project.toml).
1.1.6 — 2025-10-31
RecipesBaseadded as a direct dependency, enabling plot recipes for solutions without requiringPlots.jlto be loaded.
- Improved error handling for the
Plots.jlextension: a clearCTBase.IncorrectArgumentis now raised when plotting is attempted withoutPlots.jlloaded (#653). - Fixed maximisation objective sign for ExaModels backend (#663).
- Replaced
MinpackbyNonlinearSolvein the shooting extension.
- Bumped compat for NLPModelsIpopt to
0.11.
1.1.5 — 2025-10-23
- AI assistant buttons in the documentation to try examples interactively.
- Spell-check CI workflow (
SpellCheck.yml).
1.1.4 — 2025-10-05
- Improved error handling for the
Plots.jlextension (#653): raises a descriptive error instead of a crypticMethodErrorwhenPlotsis not loaded.
- JuliaCon Paris 2025 documentation page.
- Responsive CSS columns (math vs code) in documentation.
1.1.3 — 2025-09-25
- Documentation for AI-assisted problem description generation (
manual-ai-ded.md). - Documentation for GPU solving (
manual-solve-gpu.mdupdate). - Usage of
MadNLPMumpsin documentation examples.
1.1.2 — 2025-09-25
- Trapeze scheme support via CTDirect v0.17 (
scheme=:trapeze). - ExaModels v0.9 compat.
- Indirect method examples in documentation.
- Detailed solver options documentation.
- Bumped compat for CTDirect to
0.17. - Bumped compat for CTParser to
0.7. - Default scheme documented explicitly.
1.1.1 — 2025-08-06
- Bumped compat for ExaModels to
0.9. - Updated GPU solve documentation.
1.1.0 — 2025-08-05
ADNLPModelsandExaModelsadded as direct dependencies, enabling GPU solving via ExaModels backend out of the box.- GPU solving documentation (
manual-solve-gpu.md). - Export of
dualfunction. - Flow with state constraints support (CTFlows update).
- Non-autonomous flow tutorial.
displayoption forsolve: shows a compact configuration table before solving.- MadNLP solver added to the registry and available methods.
- Documentation for the
solvefunction arguments (tutorial-solve.md). - Manual pages for OCP model interaction and solution inspection.
- JLESC17 and JuliaCon 2025 conference documentation.
- Bumped compat for CTBase to
0.16. - Bumped compat for CTDirect to
0.16. - Bumped compat for CTModels to
0.6. - Bumped compat for CTParser to
0.6. - Bumped compat for ADNLPModels to
0.8. - Bumped compat for ExaModels to
0.8.
1.0.3 — 2025-05-08
- Bumped compat for CTModels to
0.3. - Bumped compat for CTBase to
0.16. - Removed tutorials from the documentation (moved to separate repositories).
- Pretty URLs in documentation.
1.0.2 — 2025-05-05
- Renamed
export/importkeyword (internal change following CTBase update). - Bumped compat for CTBase.
- Added
Breakage.ymlCI workflow.
1.0.1 — 2025-05-04
- Scalar vs dimension-one variable handling improvement (#478).
- Documentation updates: dependency graph, tutorials, README.
- Typo in tutorial (#475, @oameye).
1.0.0 — 2025-04-18
Initial stable release.
| Package | Compat |
|---|---|
| CTBase | 0.15 |
| CTDirect | 0.14 |
| CTFlows | 0.8 |
| CTModels | 0.2 |
| CTParser | 0.2 |
| CommonSolve | 0.2 |
| Julia | ≥ 1.10 |
This section summarises all breaking changes since v1.0.0 for users upgrading across multiple versions.
solvesignature change:initial_guessanddisplayare no longer positional or explicitly named keyword arguments in the top-levelCommonSolve.solve,solve_descriptive, andsolve_explicit. They are now extracted fromkwargs.... Existing call sites usingsolve(ocp; initial_guess=x0, display=false)continue to work unchanged — only internal dispatch signatures changed.- Alias
:iremoved:solve(ocp; i=x0)now raisesCTBase.IncorrectArgument. Useinit=x0orinitial_guess=x0instead.
- CTBase v0.16 required (from v0.15): users of CTBase directly may need to update.
- CTModels v0.6 required (from v0.2–v0.3): significant internal API changes in CTModels; users relying on internal CTModels types should review the CTModels changelog.
- CTParser v0.6 required (from v0.2): parser API updated.
- CTDirect v0.16 required (from v0.14): discretization API updated.
ADNLPModelsandExaModelsare now direct dependencies: they will be installed automatically. This should not break existing code but increases installation size.
export/importkeyword renamed: if you usedexport=...orimport=...as keyword arguments to any OptimalControl function, rename to the new keyword (see CTBase changelog for details).