Skip to content

[Dev] Per-modeling lists of problems, discovered automatically, with a status per modeling #303

Closed
2 of 2 issues completed

Description

@ocots

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

Each modeling has its own list of problems, discovered automatically, and each problem has a status per modeling (:draft or :valid). A problem is provided to users in a modeling only when it is valid there, and consistent with every other modeling where it is valid. Nothing that can be computed is written by hand.

Part of #310. Lands on main on the current API; no release needed (0.6.0-beta will follow with #283).

Current state (code to change)

  • src/OptimalControlProblems.jl
    • make_list_of_problems() (l. 49–69): list from readdir(ext/MetaData) minus a hard-coded problems_to_exclude = [:bioreactor, :cart_pendulum, :moonlander].
    • l. 73–112: for each problem, eval generates p(backend, args...; kwargs...) and p_s(...), which throw ExtensionError(weakdeps[T]); weakdeps = Dict(OptimalControlBackend => :OptimalControl, JuMPBackend => :JuMP).
    • Their docstrings are broken: a stray ``` line ([Doc] Typo in the docstrings #172) and $(TYPEDSIGNATURES) interpolated into a plain string, printed as DocStringExtensions.TypedMethodSignatures() ([Doc] Examples are not displayed correctly in the REPL #173).
  • ext/JuMPModels.jl:25 and ext/OptimalControlModels.jl:9,14,21 include one file per problem of problems(), in JuMPModels/, OptimalControlModels/ and OptimalControlModels_s/.
  • The three excluded problems are most likely excluded because of this rule: they have OptimalControl and JuMP files but no _s file, and the OptimalControl extension includes $(problem)_s.jl for every problem.
  • Users of the list: both extensions; every test file (LIST_OF_PROBLEMS, eval(f), eval(Symbol(f, :_s))); docs/problems.jl:429; CTBenchmarks (__problems() = OptimalControlProblems.problems()).
  • Docstrings of the 66 problem methods are hand-written; examples use N=100 instead of grid_size=100.

Design

Modelings

Three backends, each a dispatch tag, described by one table (the only place to edit to add a modeling, e.g. Corleone in #308):

Backend Directory Weak dependency
OptimalControlBackend ext/OptimalControlModels/ OptimalControl
OptimalControlScalarizedBackend (new) ext/OptimalControlScalarizedModels/ (renamed from OptimalControlModels_s/, files renamed <p>.jl) OptimalControl
JuMPBackend ext/JuMPModels/ JuMP
  • The _s variants become the OptimalControlScalarizedBackend modeling: beam(OptimalControlScalarizedBackend()) replaces beam_s(OptimalControlBackend()). No more p_s functions. If Description and problems #174 drops them, delete one directory and one table entry.
  • Generate the per-problem functions with the existing @eval loop (no @generated: nothing depends on argument types).

Existence and status

  • A problem exists if ext/MetaData/<p>.jl exists. It exists in a modeling if the file of that modeling exists.

  • Its status is declared in the metadata, per modeling, for the modelings where it exists:

    :status => (OptimalControl=:valid, OptimalControlScalarized=:valid, JuMP=:draft)
    Status Meaning Tests ([Tests] Test layout per environment and consistency tests #304, [Tests] Crons per scope for the slow tests, with reports #305)
    :draft written, not validated yet run, failures reported but do not fail CI
    :valid passes its own tests and is consistent with every other modeling where it is :valid failures fail CI
  • :notes (optional String): why a problem is a draft.

  • The three excluded problems: remove the exclusion list, try them in each modeling; :valid where their tests pass, :draft with :notes otherwise.

API

problems()                                        # problems valid in at least one modeling
problems(JuMPBackend())                           # valid in JuMP
problems(OptimalControlBackend(), JuMPBackend())  # valid in both (comparison tests)
problems(JuMPBackend(); status=:draft)            # drafts in JuMP
problems(; status=:all)                           # every existing problem
status(:beam)                                     # (OptimalControl=:valid, …), from the metadata

Return sorted Vector{Symbol}.

Generic method of each problem (in src)

  • Problem has no file for this modeling → CTBase.IncorrectArgument("beam is not available for JuMPBackend; see problems(JuMPBackend())").
  • File present but extension not loaded → CTBase.ExtensionError(<weakdep>), as today.
  • Calling a draft works but emits a warning (@warn "beam is a draft for JuMPBackend: …" with :notes), so drafts stay easy to develop on.

Generated docstrings

The 66 hand-written docstrings are replaced by docstrings generated from one template, per problem and per modeling:

  • one sentence (first sentence of ext/Descriptions/<p>.md);
  • a usage example for that modeling (OptimalControl: get the problem and solve; JuMP: get the model, set_optimizer, optimize!), in non-executed ```julia-repl fences, with grid_size, not N;
  • the default parameters (from the metadata) and the status;
  • a link to the online page of the problem.

The generic method gets a docstring that lists the modelings where the problem exists and their status. This closes #172 and #173.

Stale precompilation cache

The lists are computed with readdir at precompile time; adding a file to ext/JuMPModels/ does not invalidate the cache (the same is already true for ext/MetaData/). Make the directories precompilation dependencies (include_dependency), or compute availability at run time, and add a test that shows it. Check behaviour on Julia 1.10 and 1.12.

Out of scope

Done when

  • No list of problems written by hand in src/, ext/, test/.
  • Adding ext/MetaData/foo.jl and ext/JuMPModels/foo.jl with JuMP=:draft makes foo appear in problems(JuMPBackend(); status=:draft) and be tested, without touching src/; switching it to :valid makes it appear in problems(JuMPBackend()).
  • Three backends; no p_s function left; OptimalControlModels_s/ renamed.
  • bioreactor, cart_pendulum, moonlander are back, as :valid or :draft with notes.
  • Error messages and draft warning tested.
  • help?> beam renders correctly ([Doc] Typo in the docstrings #172, [Doc] Examples are not displayed correctly in the REPL #173).
  • Precompilation cache test passes on Julia 1.10 and 1.12.
  • Follow-up issue opened in CTBenchmarks.

Activity

  1. added
    featureNew feature or request
    devInternal change, no user-facing impact
    on Nov 4, 2026
  2. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Decision (see #310): availability in a modeling is deduced from file presence: ext/<Modeling>/<p>.jl exists ⇔ p ∈ problems(<Backend>()). It is the single source of truth; nothing is declared by hand in the metadata. The consistency tests (#304) check the correspondence between model files, metadata and descriptions.

    This issue does not break the 0.5 API: it goes to main directly, before the port to v2 (#283).

  3. changed the title [-][Dev] Per-modeling lists of problems, discovered automatically[/-] [+][Dev] Per-modeling lists of problems, discovered automatically, with a status per modeling[/+] on Nov 4, 2026
  4. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Addition to the modeling table (decided in #310, used by #308): ModelingToolkitBackend, directory ext/ModelingToolkitModels/, weak dependency ModelingToolkit. The problem is a continuous ModelingToolkit system; solving it (e.g. with Corleone) is not part of the modeling. Not needed in this issue, but the table must make adding it a one-line change.

  5. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Taken by an agent; draft PR to follow.

  6. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Documentation (decision in #307): this issue also writes ext/README.md (main README: the plan of the extensions, availability = file presence, :draft → :valid, how to add a problem, how to add a modeling = table entry + documentation adapter) and the README of each ext/<Modeling>/, ext/MetaData/ and ext/Descriptions/ directory it touches. Procedures only, no hand-written list of problems or modelings. Add it to the 'Done when' checklist.

  7. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Implementation is in draft PR #320. The full Julia 1.12 package test suite passes; Julia 1.10 verification remains pending because that local channel is not installed.

  8. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Implementation complete.

    PR #320 is ready for review. It implements the three modeling backends, file-discovered problem lists, per-modeling statuses, draft warnings, generated docstrings, scalarized backend rename, and the associated test adaptations.

    Validation completed:

    The existing mountain_car scalarized comparison remains an expected broken test; the complete suite exits successfully.

  9. ocots commented on Nov 4, 2026

    @ocots
    MemberAuthor

    Closing: done in #320 (with #319, #321, #322)

    Done

    • One modeling table (OptimalControlBackend, OptimalControlScalarizedBackend, JuMPBackend); availability read from the model files, status (:valid/:draft) from the metadata; problems(), problems(backend; status=…), problems(b1, b2, …) (intersections) and OptimalControlProblems.status(:p).
    • No hand-written list of problems in src/, ext/, test/ (the former exclusion list is gone; the modeling tests name no problem).
    • OptimalControlModels_s/ renamed to OptimalControlScalarizedModels/, p_s replaced by the scalarized backend.
    • bioreactor, cart_pendulum, moonlander are back as :valid; checked against each other (JuMP vs OptimalControl, grid_size=20, same objectives to 1e-15).
    • Missing modeling → CTBase.IncorrectArgument; draft → warning (with :notes). Both tested, as is the absence of a warning on a valid problem and the file ⇔ status-key consistency.
    • Docstrings no longer show the TYPEDSIGNATURES defect ([Doc] Typo in the docstrings #172, [Doc] Examples are not displayed correctly in the REPL #173), tested for every problem. The AbstractModelBackend docstring (a code block by mistake) is fixed.
    • status is not exported (MOD8); the docs generator uses problems(OptimalControlBackend(), JuMPBackend(); status=:all).
    • CTBenchmarks follow-up: [Dev] Use per-modeling problem lists from OptimalControlProblems CTBenchmarks.jl#219.
    • CI passed on 1.10 and 1.12 for the PR; the matrix is now 1.10 and 1.13 (ci: test on Julia 1.10 and 1.13 #322). CI.yml now fires on labeled (fix(ci): trigger CI when the run label is added #321).

    Not done, tracked in #323

    • Test that adding a problem (metadata + model file) makes it appear without touching src/, and that the precompilation cache is invalidated (include_dependency is in place, no test shows it).

    Left as is

    Discovered

    • mountain_car with the scalarized backend and MadNLP is infeasible at grid_size=20 but solves at its default grid; it stays :valid. At the default grid its objective differs from JuMP/OptimalControl by 1.6e-4 (tolerance 1e-4): to investigate ([Metadata] Computed features, reference objective, shared initial guess #306 :known_failures if intended).
    • The OptimalControlModels extension does not precompile in a clean environment (ExaModels 0.9 ExaModelsLinearAlgebra and CTParser both define zero(::Type{<:ExaModels.AbstractNode})); it predates this work and costs load time.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

devInternal change, no user-facing impactfeatureNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions