[Doc] Examples for the sign convention of duals and costate (min/max, writing of constraints, direct vs indirect)

Abierto
#1,016 1 comentario 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@ocots ya está trabajando en esto.

Desde el 23/10/2026.

Evaluación

Este issue todavía no se ha evaluado.

Descripción

Follow-up of #1014 (the convention) and companion of #1015 (the page that states it). This issue lists the examples to add to the documentation, so that a user can see that the signs do not depend on the solver, on the sense of the criterion, or on the way a constraint is written. Each example should also become a test: run in a docs page, it fails loudly if a convention moves.

The implementation is in three draft PRs:

  • control-toolbox/CTSolvers.jl#289: one multiplier convention for every NLP solver. min f and max -f have the same multipliers; a constraint with a single bound has a nonnegative multiplier; equalities keep their sign.
  • control-toolbox/CTFlows.jl#494: the solution of Flow(ocp, law; constraint=:label, multiplier=μ) carries dual(sol, ocp, :label), in the same convention.
  • control-toolbox/CTModels.jl#483: dual on a solution that holds the duals of some constraints only, and the jumps of the duals in the plots of a multi-phase solution.

The convention, as the user should read it (for #1015)

  • The dual of an inequality constraint is nonnegative, whatever the constraint and the sense of the criterion. g(x) ≤ 0 and -g(x) ≥ 0, or x(t) ≥ 0.1 and 0.1 - x(t) ≤ 0, are the same constraint and have the same dual.
  • An equality keeps its sign: c = 0 and -c = 0 have opposite duals.
  • min J and max -J are the same problem: they have the same duals and the same costate p. Only the objective changes sign.
  • Indirect method: the pseudo-Hamiltonian H = p·f + p⁰ℓ + μ·g (g ≥ 0, μ ≥ 0) is always maximised, with p⁰ = -1 for a minimisation and +1 for a maximisation. dual(sol, ocp, :label) of a flow solution is the μ given to the flow (0 off the boundary arc).
  • A constraint with two finite bounds, lb ≤ c ≤ ub, has a signed dual: +μ when the upper side is active, -μ when the lower side is.

Examples to add

  1. The signs do not change with min/max. Solve ẋ = u, x(0) = -1, x(t) + u(t) ≤ 0, 0 ≤ u(t):

    • once as ∫ -u(t) dt → min, once as ∫ u(t) dt → max;
    • with Ipopt and with MadNLP.

    Show that costate(sol) and dual(sol, ocp, :mixed) are the same in the four cases. The closed form is p(t) = e^{t-1} - 1 and dual = e^{t-1}.

  2. The signs do not change with the way a constraint is written. The same problem with x(t) + u(t) ≤ 0 written as -x(t) - u(t) ≥ 0: the same dual.

  3. Direct and indirect give the same duals. Rebuild the solution of example 1 with Flow(ocp, (x, p) -> -x; constraint=:mixed, multiplier=(x, p) -> p + 1), then compare dual(sol_direct, ocp, :mixed) and dual(sol_flow, ocp, :mixed) on one plot. They agree up to the discretisation error.

  4. A boundary arc in a multi-phase indirect solution. The problem of control-toolbox/CTFlows.jl#440 (x ≥ 0.1, three arcs). plot(sol) shows the dual, 0 then 2x = 0.2 on the boundary arc then 0, with its jumps at the junctions and the phase labels. Compare with a direct solve of the same problem.

  5. Why the label matters. In a flow, a constraint given as a function has no label: its dual cannot be placed in the solution, the flow warns, and dual throws. Show the labelled form, constraint=:label or :label => :upper.

Possible tests (OptimalControl test suite, the cross-package level): examples 1 to 3, with Ipopt and MadNLP (and Uno), as @test on the closed form.

Still open (not for the user page)

  • Box constraints. The dual of a box (0 ≤ u(t) ≤ 1 declared as a box) has the opposite sign to the same constraint written as a path constraint, and it is not divided by the step (control-toolbox/CTDirect.jl#639). The page should say so until it is fixed, or wait for it.
  • Boundary and box duals of a flow solution are not rebuilt (dual throws a PreconditionError).
  • Two-sided constraints: the signed value is kept. Is that what the page should present, or a pair (lower, upper)?

🤖 Generated with Claude Code

Lenguaje dominante
Julia
Estrellas
135
Forks
11
Merge medio
7 h 51 min
PR fusionados (30 d)
22

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de control-toolbox/OptimalControl.jl

Todos los issues de control-toolbox/OptimalControl.jl

Issues similares

Más issues de Julia

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.