Repository navigation
Description
Agents: read the guide for agents in #310 first (order, difficulty, how to claim an issue, working method). The specification is in this description and in the comments below.
Goal
Port OptimalControlProblems.jl to OptimalControl v2 and change its interface: a problem function returns the continuous problem and its initial guess, instead of a problem already discretized with the trapezoidal rule. The scheme, grid, modeler, solver and CPU/GPU choice are then made in solve, which is what the benchmark paper needs.
What we know
origin/mainis 0.5.0 and depends on OptimalControl 1, CTDirect 0.17, CTModels 0.6, CTBase 0.16, ADNLPModels 0.8, ExaModels 0.9. OptimalControl is at 2.2.1-beta (inct-registry).- The 22 files in
ext/OptimalControlModels/(and the 22 inext/OptimalControlModels_s/) end withdirect_transcription(ocp, description...; lagrange_to_mayer=false, init=init, grid_size=…, disc_method=:trapeze, …). In v2,direct_transcription,build_OCP_solutionandset_initial_guessare gone (seeBREAKING.mdin OptimalControl:discretize,ocp_solution,@init). - The initial guess is a
NamedTuple(state=…, control=…, variable=…), still accepted by v2. src/OptimalControlProblems.jlgenerates the stubs of every problem witheval; the real methods live in theOptimalControlModelsandJuMPModelsextensions.- If problems no longer discretize, CTDirect, ADNLPModels, ExaModels and SolverCore are no longer needed as direct dependencies (this also answers the stale CT* versions reported in [Doc] review of examples published on the website #229).
Proposal (to be discussed)
pb = beam(OptimalControlBackend(); parameters=(tf=2,)) # continuous problem
sol = solve(pb.ocp, :exa, :madnlp, :gpu; init=pb.init, grid_size=2000, scheme=:midpoint)
model = beam(JuMPBackend(); grid_size=500, scheme=:midpoint) # JuMP stays discretizedOpen questions
- Returned object:
NamedTuple(name, ocp, init)or a small struct that can also carry metadata (see the metadata theme)? - Does the package keep a dependency on CTModels (JuMP accessors extend its functions), or does everything go through the OptimalControl extension?
- Keep an
nlp_model-like convenience? (Proposal: no, that is OptimalControl's job.) merge/parameters_datauseCTBase.UnauthorizedCall: check it still exists in CTBase 0.30.
Also in scope
Update compat; rewrite test/ for the v2 API; rewrite the tutorials tutorial-get.md and tutorial-solve.md; fix the docstring problems (#172, #173) and the website review (#229); publish 0.6.0-beta in ct-registry.
Related issues
#257 (roadmap), #136 (Exa and problems, solved by v2), #174 (description vs symbol; _s as standard), #151 (initial guess documentation), #229, #172, #173.
How to work on this theme
This is a theme issue: it describes the work to do and what is known so far, it is not meant to be closed by a single PR.
- Whoever takes it first defines the work precisely and splits it into sub-issues (they can live in any repository of the organization).
- Work proceeds through the sub-issues; tick the checklist below as they are closed.
- Close the theme when everything is done or explicitly dropped.
Context: tracking issue control-toolbox/CTBenchmarks.jl#200; planning notes: objectives and directions and updating OptimalControlProblems and CTBenchmarks (in control-toolbox/benchmark-paper).
Sub-issues
- to be created when the theme is taken
Activity
ocots commentedon Nov 4, 2026
Decisions taken in #310 that concern this theme:
Returned object: a struct
(name, ocp, init, metadata)holding the continuous (mathematical) problem. This package no longer discretizes for OptimalControl (direct_transcriptionno longer exists in v2). The user discretizes throughsolve, in descriptive or explicit mode, or throughdiscretize:No convenience function for discretizing in this package: modeler and solver options belong to the
solvecall, not to the retrieval of the problem.Branch: no long-lived branch. The port goes to
mainthrough PRs, with the version set to 0.6.0-beta (published inct-registry) anduse_ct_registry: truein the workflows. The per-modeling lists ([Dev] Per-modeling lists of problems, discovered automatically, with a status per modeling #303) land onmainfirst, on the 0.5 API.ocots commentedon Nov 4, 2026
Specification
Detailed in #310 (step 2). This comment is the reference for whoever implements the port; it supersedes the "Proposal" and "Open questions" of the description. Depends on #313, #312, #303 and #304 (test layout per environment already in place).
Facts found in the v2 stack
Local versions: OptimalControl 2.2.1-beta, CTBase 0.30.13, CTModels 0.21.1, CTDirect 1.1.6-beta, CTSolvers 0.7.0, CTParser 0.8.17-beta.
CTBase.UnauthorizedCallno longer exists (OptimalControlBREAKING.md).mergeandparameters_datause it: replace byCTBase.PreconditionErrororCTBase.IncorrectArgument, and updatetest_parameters.CTModels.matrix2vecandCTModels.ctinterpolateno longer exist: the JuMP accessors (state,control,costateinext/JuMPModels.jl) must be rewritten.objectiveandvariableare imported from ExaModels (src/OptimalControlProblems.jl:15) and exported, and the JuMP extension extendsExaModels.objective. In v2, extend the CTModels functions that OptimalControl reexports, so thatusing OptimalControl, OptimalControlProblemsgives no name conflict andstate(jump_model)andstate(sol)are the same function.discretize(ocp, Collocation(grid_size=…, scheme=…)),nlp_model(dm, init, modeler),ocp_solution, modelersADNLP/Exa,@init.docs/src/tutorial-get.md,tutorial-solve.md) calldirect_transcription: the docs break with the port.Decisions
Problem(OptimalControlProblems.Problem) with fieldsname::Symbol,ocp(continuous problem, the@defmodel),init(NamedTuple(state=…, control=…, variable=…), shared initial guess comes with [Metadata] Computed features, reference objective, shared initial guess #306),metadata; ashowmethod.name(pb),ocp(pb),initial_guess(pb),metadata(pb)(exact names to settle against existing exports and the conventions). Direct field access stays possible but is not the documented way.direct_transcription(…); they return theProblem. Discretization, modeler, solver, CPU/GPU are chosen by the user insolve(descriptive or explicit mode) or throughdiscretize. No convenience function for that here.CTModels.Solution(first step towards JuMP support in OptimalControl):CTModels.build_solution(ocp, T_state, T_control, T_costate, T_path, X, U, v, P; objective, iterations, successful, status, message, …)takes the continuousocpfirst. So a fullSolutioncan be built from a solved JuMP model when the problem is also available in OptimalControl, using itsocp; thenplot,state(sol),control(sol),costate(sol),objective(sol),iterations(sol)and the comparisons work as for OptimalControl.Problem, returning aCTModels.Solution(name to settle; must not be type piracy: one argument type must be ours or CTModels'). Use the four-grid form: grids differ per scheme (number of controls, see [Paper] JuMP models for Euler, trapeze and midpoint, and NLP equivalence tests #284); setcontrol_interpolationaccordingly.time_grid,state,control,costate,variable,objective,iterations), with a small linear interpolation written here.build_solution), DocStringExtensions, OrderedCollections. Compat: OptimalControl 2.2, CTModels 0.21, CTBase 0.30, following theRELrules for betas (pre-release compat bounds).Project.tomlat 0.6.0-beta, withCHANGELOG.mdandBREAKING.mdentries ([Chore] Release and CI infrastructure: CHANGELOG, BREAKING, release workflows, label-gated CI #312). No release for now: CTBenchmarks is not worked on yet.Tests
The layout of #304 is in place; port the content to v2:
test/common/configs.jlin explicit mode, e.g.Collocation(grid_size, scheme=:trapeze)+ADNLP()+Ipopt(…),Exa()+MadNLP(…),Exa{GPU}()+MadNLP{GPU}(…);OptimalControlandOptimalControlScalarizedenvironments (Exa on GPU), and the GPU jobs ofCI.ymlannounced in [Tests] Test layout per environment and consistency tests #304 (run ci kkt-runner,run ci occidata-runner,ci-gpu.ymlonmain); GPU needsMadNLPGPU,CUDAandCUDSSloaded;ProblemAPI and of the JuMP →Solutionconstruction (compare with the OptimalControl solution on trapezoid);discretize+nlp_modelon the OptimalControl side and the JuMP model on the other.Documentation
Only what keeps the docs building: port the tutorials' code to v2. The full rewrite is #307; the move to VitePress is #311.
Closes
#136 (Exa and GPU through
solve). The "description" part of #174 disappears (the_spart stays in #174).Done when
Problem; nodirect_transcriptionleft.showprints name, dimensions and status.CTModels.Solutionwhen the problem exists in OptimalControl, andplot(sol)works on it.UnauthorizedCall, no import from ExaModels;using OptimalControl, OptimalControlProblemsgives no ambiguity warning.[deps]; version 0.6.0-beta; changelog entries.kktoroccidata); docs build.ocots commentedon Nov 4, 2026
Update to the specification above, about the JuMP solution:
CTModels.Solutionstores the continuous model (model(sol)), used by plots, warm start, duals andshow. Proposed upstream: [Feature] build_solution from model information, without a full continuous Model CTModels.jl#515,build_solutionfrom model information without a fullModel.Solutionfrom theocpof theProblemwhen the problem exists in OptimalControl (works today); keep the per-component accessors for JuMP-only problems.:state_components,:time_grid, …), so JuMP-only problems get aSolutiontoo.ocots commentedon Nov 4, 2026
Clarification on the JuMP solution, in stages; the goal is only to have what is needed to show and plot a JuMP result like an OptimalControl solution:
time_grid,state,control,costate,variable,objective,iterations), noSolution.Solutionfrom the information stored in the JuMP model (components, time grid, …).Solutionfrom itsocp(possible today; this issue does it).No dynamics on the JuMP side for this: flows need a continuous model, and the long-term direction is to obtain JuMP models from an OptimalControl
ocp, not the reverse.ocots commentedon Nov 4, 2026
Documentation of OptimalControl v2: read the dev site, https://control-toolbox.org/OptimalControl.jl/dev/ (or
docs/src/onmainof OptimalControl.jl); the stable site is not up to date. In particular, explicit mode: https://control-toolbox.org/OptimalControl.jl/dev/solve/explicit-mode.test: follow the suite/cron layout of the conventions
test: add a provisional test runner and shared test options
test: follow the suite/cron layout of the conventions
test: add a provisional test runner and shared test options
test: follow the suite/cron layout of the conventions
test: bound ExaModels in the OptimalControl environment until the por…
feat: read the continuous problem with model(pb), drop name(pb)
ocots commentedon Nov 4, 2026
Taken by an agent; draft PR to follow.
ocots commentedon Nov 4, 2026
Progress and deviations from the specification.
Draft PR: #331 (part 1). The theme is split in three sub-issues: #328 (port:
Problemtype, continuous problems, CPU tests; this PR), #329 (CTModels.Solutionfrom a solved JuMP model), #330 (GPU tests).Deviations from the specification, argued in #331:
CTModels = "0.19", so 0.21 cannot be resolved with it. Compat follows OptimalControl.metadata(:beam)becomesproblem_metadata(:beam). OptimalControl reexportsCTBase.Strategies.metadata; a method onSymbolwould be type piracy.metadata(pb)on aProblemextends it.model(pb),initial_guess(pb),metadata(pb).modelextendsCTModels.Solutions.model(already exported by OptimalControl,model(sol)returns the problem of a solution): no new exported name. Noname(pb)(it repeats what the user called, and conflicts withJuMP.name) and noocp(pb)(on Julia 1.10,ocp = @def …fails once an importedocphas been used).Problemhas amodelingfield beyond the four of the specification, so thatshowcan print the status, which depends on the modeling.Still to do in #331: the tests of the modeling environments, after #324 (which rewrites them), and the CI of the PR.
Deferred: the costate and dual signs of JuMP versus OptimalControl, in #326 (waits for the work on multipliers, discussion #68).
test: core tests after the merge of #324: problem_metadata, no proble…
test: port the modeling environments to OptimalControl v2
ocots commentedon Nov 5, 2026
From #304 (PRs #319, #324) — what the port to v2 inherits in the tests:
ExaModels = "0.9 - 0.9.4"oftest/suite/OptimalControl/Project.toml: it works around a conflict of the v1 stack on Julia 1.13 (CTParser 0.8.2 redefines azeromethod of ExaModels ≥ 0.9.5; precompilation fails). The v2 stack has no such conflict.test/common/configs.jl(Main.TestConfigs.CONFIGS) is the single matrix read by every test; extend it with the v2 modelers/solvers rather than writing options in test files. Solvers are one module each intest/common/solve_*.jl(an environment only includes what it loads).test/common/runner.jl(LocalTestRunner) is provisional; replace it byCTBase.run_tests(CTBase ≥ 0.30) when CTBase is bumped. Keepselect_environmentssemantics (tested incore).Main.TestStatus.for_each_problem(f, test, backends...);:validfails,:draftis reported (test/reports/). New v2-specific failures go through statuses, not@test_broken.CI.yml(run ci kkt-runner,run ci occidata-runner, one GPU run onmainviaci-gpu.yml) and the environment contractTST6(GPU must be functional on a GPU runner), once Exa GPU tests exist.test_modelingsloadsREPL: since Julia 1.13Base.Docs.dochas no method without it.fix: documentation links and release gate
ocots commentedon Nov 5, 2026
Progress of the theme (2026-11-05).
Problem(continuous problem and initial guess); CTDirect, ADNLPModels, ExaModels and SolverCore are no longer dependencies; docs and tutorials ported; tests ported on the layout of [Tests] Test layout per environment and consistency tests #304. Deviations (CTModels 0.19,problem_metadata,modelingfield, version kept at 0.5.0) are argued in feat: port to OptimalControl v2, Problem type and continuous problems #331 and in the closing comment of [Dev] Port to OptimalControl v2: Problem type, continuous problems, CPU tests #328.CTModels.Solutionfrom a solved JuMP model (part 2).ct-registry: release PR (release.jl), after [Dev] Build a CTModels.Solution from a solved JuMP model #329 and [Tests] GPU tests for the OptimalControl modelings (Exa + MadNLP on GPU) #330.This issue stays open until #329, #330 and the release are done, or explicitly dropped.
ocots commentedon Nov 5, 2026
Closing the theme
The port to OptimalControl v2 and the new problem interface are done.
Delivered
Problem(continuous problem, initial guess, metadata); CTDirect, ADNLPModels, ExaModels and SolverCore are no longer dependencies; tutorials and tests ported.CTModels.Solutioncan be built from a solved JuMP model.Not done here, on purpose
Project.tomlstays at 0.5.0. It will be prepared when wanted, after the full CI matrix of Restore the full CI matrix (Julia 1.10, macOS, Windows) after the reorganisation #344 has run once.Tracked elsewhere, no longer part of this theme
Closed as completed.