OptimalControl.jl icon indicating copy to clipboard operation
OptimalControl.jl copied to clipboard

[Bug] Flow example

Open jbcaillau opened this issue 10 months ago • 2 comments

hi @oameye (cc @ocots @PierreMartinon); moving your separate example here (different issue compared to https://github.com/control-toolbox/OptimalControl.jl/issues/369). The example below converges with the commented version of the cost, not with the uncommented one (which is not exactly what you posted), but runs without any AD error:

  • can you please confirm which (new) cost you want to minimise?
  • in any case, I suggest to replace your mysqrt by the asqrt function below (smoothed and symmetrised)
using OptimalControl
using NLPModelsIpopt
using LinearAlgebra

T = 50  # Time horizon

# Define the vector field
f(u, v) = [u - u^3 - 10*u*v^2,  -(1 - u^2)*v]
f(x) = f(x...)

asqrt(x; ε=1e-9) = sqrt(sqrt(x^2 + ε^2))

@def action begin
    t ∈ [0, T], time
    x ∈ R², state
    u ∈ R², control
    x(0) == [-1, 0]    # Starting point (left well)
    x(T) == [1, 0]     # End point (right well)
    ẋ(t) == u(t)       # Path dynamics
    #∫( sum((u(t) - f(x(t))).^2) ) → min  # Minimize deviation from deterministic flow
    ∫( asqrt(sum((u(t) - f(x(t))).^2)) ) → min  # Minimize deviation from deterministic flow
end

# Linear interpolation for x₁
x1(t) = -(1 - t/T) + t/T
# Parabolic guess for x₂
x2(t) = 0.3(-x1(t)^2 + 1)
x(t) = [x1(t), x2(t)]
u(t) = f(x(t))
init = (state=x, control=u)

sol = solve(action; init=init, grid_size=50)

jbcaillau avatar Jan 20 '25 15:01 jbcaillau

Hi, I would like to perform a geometric minimal action optimization, which is a variant of the now added tutorial here. It has the advantage, one does not have to additionally minimise for the arrival time T.

The integral function is modified to: $\int_0^T \lVert u(s)\rVert \lVert f(x(s))\rVert - u(s)\cdot f(x(s)) \mathrm{d}s$

When I run with the modified integral and asqrt I get

using OptimalControl, LinearAlgebra
using NLPModelsIpopt

T = 50  # Time horizon

# Define the vector field
f(u, v) = [u - u^3 - 10*u*v^2,  -(1 - u^2)*v]
f(x) = f(x...)


asqrt(x; ε=1e-9) = sqrt(sqrt(x^2 + ε^2))

@def action begin
    t ∈ [0, T], time
    x ∈ R², state
    u ∈ R², control
    x(0) == [-1, 0]    # Starting point (left well)
    x(T) == [1, 0]     # End point (right well)
    ẋ(t) == u(t)       # Path dynamics
    ∫(asqrt(dot(u(t),u(t))*dot(f(x(t)),f(x(t)))) - dot(u(t),f(x(t)))) → min
end
# Linear interpolation for x₁
x1(t) = -(1 - t/T) + t/T
# Parabolic guess for x₂
x2(t) = 0.3(-x1(t)^2 + 1)
x(t) = [x1(t), x2(t)]
u(t) = f(x(t))
init = (state=x, control=u)

sol = solve(action; init=init, grid_size=50)
ERROR: Cannot determine ordering of Dual tags ForwardDiff.Tag{ReverseDiff.var"#131#134"{typeof(+), ForwardDiff.Dual{ForwardDiff.Tag{ADNLPModels.var"#ψ#72"{CTDirect.var"#34#36"{CTDirect.DOCP}}, Float64}, Float64, 1}}, ForwardDiff.Dual{ForwardDiff.Tag{ADNLPModels.var"#ψ#72"{CTDirect.var"#34#36"{CTDirect.DOCP}}, Float64}, Float64, 1}} and ForwardDiff.Tag{ADNLPModels.var"#ψ#72"{CTDirect.var"#34#36"{CTDirect.DOCP}}, Float64}
Stacktrace:
  [1] value
    @ C:\Users\User\.julia\packages\ForwardDiff\UBbGT\src\dual.jl:98 [inlined]
  [2] (::ForwardDiff.var"#76#77"{ForwardDiff.Tag{…}})(d::ForwardDiff.Dual{ForwardDiff.Tag{…}, ForwardDiff.Dual{…}, 1})
    @ ForwardDiff C:\Users\User\.julia\packages\ForwardDiff\UBbGT\src\apiutils.jl:6
  [3] value!(f::ForwardDiff.var"#76#77"{…}, r::DiffResults.ImmutableDiffResult{…}, x::ForwardDiff.Dual{…})
    @ DiffResults C:\Users\User\.julia\packages\DiffResults\YLo25\src\DiffResults.jl:168
  [4] extract_value!
    @ C:\Users\User\.julia\packages\ForwardDiff\UBbGT\src\apiutils.jl:5 [inlined]
  [5] derivative!
    @ C:\Users\User\.julia\packages\ForwardDiff\UBbGT\src\derivative.jl:49 [inlined]
  [6] binary_scalar_forward_exec!(f::typeof(+), output::ReverseDiff.TrackedReal{…}, input::Tuple{…}, cache::Base.RefValue{…})
    @ ReverseDiff C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\derivatives\scalars.jl:116
  [7] scalar_forward_exec!(instruction::ReverseDiff.ScalarInstruction{…})
    @ ReverseDiff C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\derivatives\scalars.jl:88
  [8] forward_exec!(instruction::ReverseDiff.ScalarInstruction{…})
    @ ReverseDiff C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\tape.jl:82
  [9] ForwardExecutor
    @ C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\api\tape.jl:76 [inlined]
 [10] (::FunctionWrappers.CallWrapper{Nothing})(f::ReverseDiff.ForwardExecutor{ReverseDiff.ScalarInstruction{…}})
    @ FunctionWrappers C:\Users\User\.julia\packages\FunctionWrappers\Q5cBx\src\FunctionWrappers.jl:65
 [11] macro expansion
    @ C:\Users\User\.julia\packages\FunctionWrappers\Q5cBx\src\FunctionWrappers.jl:137 [inlined]
 [12] do_ccall
    @ C:\Users\User\.julia\packages\FunctionWrappers\Q5cBx\src\FunctionWrappers.jl:125 [inlined]
 [13] FunctionWrapper
    @ C:\Users\User\.julia\packages\FunctionWrappers\Q5cBx\src\FunctionWrappers.jl:144 [inlined]
 [14] forward_pass!(compiled_tape::ReverseDiff.CompiledTape{ReverseDiff.GradientTape{…}})
    @ ReverseDiff C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\api\tape.jl:124
 [15] seeded_forward_pass!
    @ C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\api\tape.jl:42 [inlined]
 [16] gradient!(result::Tuple{…}, tape::ReverseDiff.CompiledTape{…}, input::Tuple{…})
    @ ReverseDiff C:\Users\User\.julia\packages\ReverseDiff\p1MzG\src\api\gradients.jl:79
 [17] ∇l!
    @ C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\sparse_hessian.jl:194 [inlined]
 [18] ∇l!
    @ C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\sparse_hessian.jl:193 [inlined]
 [19] sparse_hess_coord!(b::ADNLPModels.SparseReverseADHessian{…}, x::Vector{…}, obj_weight::Float64, y::SubArray{…}, vals::Vector{…})
    @ ADNLPModels C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\sparse_hessian.jl:328
 [20] hess_coord!(b::ADNLPModels.SparseReverseADHessian{…}, nlp::ADNLPModels.ADNLPModel{…}, x::Vector{…}, y::SubArray{…}, obj_weight::Float64, vals::Vector{…})
    @ ADNLPModels C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\sparse_hessian.jl:352
 [21] hess_coord!(nlp::ADNLPModels.ADNLPModel{…}, x::Vector{…}, y::Vector{…}, vals::Vector{…}; obj_weight::Float64)
    @ ADNLPModels C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\nlp.jl:706
 [22] hess_coord!
    @ C:\Users\User\.julia\packages\ADNLPModels\bOFzz\src\nlp.jl:695 [inlined]
 [23] (::NLPModelsIpopt.var"#eval_h#5"{…})(x::Vector{…}, rows::Vector{…}, cols::Vector{…}, σ::Float64, λ::Vector{…}, values::Vector{…})
    @ NLPModelsIpopt C:\Users\User\.julia\packages\NLPModelsIpopt\0YgvC\src\NLPModelsIpopt.jl:109
 [24] _Eval_H_CB(n::Int32, x_ptr::Ptr{…}, ::Int32, obj_factor::Float64, m::Int32, lambda_ptr::Ptr{…}, ::Int32, nele_hess::Int32, iRow::Ptr{…}, jCol::Ptr{…}, values_ptr::Ptr{…}, user_data::Ptr{…})
    @ Ipopt C:\Users\User\.julia\packages\Ipopt\gCQtM\src\C_wrapper.jl:129
 [25] IpoptSolve(prob::Ipopt.IpoptProblem)
    @ Ipopt C:\Users\User\.julia\packages\Ipopt\gCQtM\src\C_wrapper.jl:399
 [26] solve!(solver::IpoptSolver, nlp::ADNLPModels.ADNLPModel{…}, stats::SolverCore.GenericExecutionStats{…}; callback::Function, kwargs::@Kwargs{…})
    @ NLPModelsIpopt C:\Users\User\.julia\packages\NLPModelsIpopt\0YgvC\src\NLPModelsIpopt.jl:240
 [27] solve!
    @ C:\Users\User\.julia\packages\NLPModelsIpopt\0YgvC\src\NLPModelsIpopt.jl:161 [inlined]
 [28] #solve!#16
    @ C:\Users\User\.julia\packages\SolverCore\vTpnV\src\solver.jl:40 [inlined]
 [29] solve!
    @ C:\Users\User\.julia\packages\SolverCore\vTpnV\src\solver.jl:38 [inlined]
 [30] solve_docp(tag::CTDirect.IpoptTag, docp::CTDirect.DOCP, nlp::ADNLPModels.ADNLPModel{…}; display::Bool, max_iter::Int64, tol::Float64, print_level::Int64, mu_strategy::String, linear_solver::String, kwargs::@Kwargs{})
    @ CTSolveExtIpopt C:\Users\User\.julia\packages\CTDirect\1ZEiU\ext\CTSolveExtIpopt.jl:54
 [31] solve_docp
    @ C:\Users\User\.julia\packages\CTDirect\1ZEiU\ext\CTSolveExtIpopt.jl:15 [inlined]
 [32] direct_solve(::OptimalControlModel{…}; init::@NamedTuple{…}, grid_size::Int64, time_grid::Nothing, kwargs::@Kwargs{})
    @ CTDirect C:\Users\User\.julia\packages\CTDirect\1ZEiU\src\solve.jl:119
 [33] solve(::OptimalControlModel{Autonomous, Fixed}; kwargs::@Kwargs{init::@NamedTuple{…}, grid_size::Int64})
    @ OptimalControl C:\Users\User\.julia\packages\OptimalControl\6SuFg\src\solve.jl:61
 [34] top-level scope
    @ Untitled-1:30
Some type information was truncated. Use `show(err)` to see complete types.

oameye avatar Jan 20 '25 16:01 oameye

I do not understand why but if you remove dot(f(x(t)),f(x(t))), this error does not show up.

ocots avatar Jan 20 '25 17:01 ocots

closing in favour of https://github.com/control-toolbox/OptimalControl.jl/issues/481

jbcaillau avatar Oct 03 '25 17:10 jbcaillau