Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusing error message in nonlinear #3235

Closed
odow opened this issue Feb 23, 2023 · 3 comments · Fixed by #3236
Closed

Confusing error message in nonlinear #3235

odow opened this issue Feb 23, 2023 · 3 comments · Fixed by #3236
Labels
Category: Nonlinear Related to nonlinear programming Type: Bug

Comments

@odow
Copy link
Member

odow commented Feb 23, 2023

Reported on slack:

julia> using JuMP, Ipopt, LinearAlgebra

julia> model = Model(Ipopt.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Ipopt

julia> @variable(model, K[1:2,1:5])
2×5 Matrix{VariableRef}:
 K[1,1]  K[1,2]  K[1,3]  K[1,4]  K[1,5]
 K[2,1]  K[2,2]  K[2,3]  K[2,4]  K[2,5]

julia> A, B = rand(5, 5), rand(5, 2)
([0.8069977376091964 0.6161158349878504  0.46291003291226973 0.6360012232068746; 0.52213926623547 0.9495143399637247  0.07360503427198917 0.4978696526920816;  ; 0.14586717136824756 0.0003306031458678582  0.5010140965992376 0.4367748246176837; 0.4658645107067667 0.6366232080273633  0.4371067511526787 0.17266344404530498], [0.671429492429769 0.8062021626377329; 0.31489671797256236 0.02573618075020523;  ; 0.23639100794402879 0.7547242181976781; 0.7930804839731864 0.8228698868125954])

julia> @NLobjective(model, Min, sum(abs.(eigvals(A+B*K))))
ERROR: sqrt is not defined for type GenericQuadExpr. Are you trying to build a nonlinear problem? Make sure you use @NLconstraint/@NLobjective.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] sqrt(#unused#::QuadExpr)
   @ JuMP ~/.julia/packages/JuMP/bofhg/src/operators.jl:472
 [3] eigtype(T::Type)
   @ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/eigen.jl:302
 [4] eigvals(A::Matrix{AffExpr}; kws::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/eigen.jl:326
 [5] eigvals(A::Matrix{AffExpr})
   @ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/eigen.jl:326
 [6] macro expansion
   @ ~/.julia/packages/JuMP/bofhg/src/macros.jl:1867 [inlined]
 [7] top-level scope
   @ REPL[43]:1

The issue is that we try to eagerly evaluate the contents inside sum:

julia> @macroexpand @NLobjective(model, Min, sum(abs.(eigvals(A+B*K))))
quote
    #= REPL[44]:1 =#
    JuMP._valid_model(model, :model)
    begin
        #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:2390 =#
        begin
            #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:1867 =#
            JuMP._init_NLP(model)
            var"#24###309" = JuMP.Expr(:call, :sum, abs.(eigvals(A + B * K)))
            var"#25###310" = model.nlp_model.operators
            begin
                #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:1911 =#
                try
                    #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:1912 =#
                    (JuMP.MOI).Nonlinear.register_operator_if_needed(var"#25###310", :sum, 1, sum)
                catch
                end
                #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:1920 =#
                (JuMP.MOI).Nonlinear.assert_registered(var"#25###310", :sum, 1)
            end
        end
        #= /Users/oscar/.julia/packages/JuMP/bofhg/src/macros.jl:2391 =#
        JuMP.set_nonlinear_objective(model, JuMP._throw_error_for_invalid_sense(JuMP.var"#_error#97"{LineNumberNode, Symbol, Symbol, Expr}(:(#= REPL[44]:1 =#), :model, :Min, :(sum(abs.(eigvals(A + B * K))))), MathOptInterface.MIN_SENSE), var"#24###309")
    end
end
@odow odow added Type: Bug Category: Nonlinear Related to nonlinear programming labels Feb 23, 2023
@odow
Copy link
Member Author

odow commented Feb 23, 2023

MWE:

julia> using JuMP

julia> model = Model();

julia> @variable(model, x[1:2]);

julia> @NLobjective(model, Min, sum(sin.(x)))
ERROR: sin is not defined for type AbstractVariableRef. Are you trying to build a nonlinear problem? Make sure you use @NLconstraint/@NLobjective.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] sin(#unused#::VariableRef)
   @ JuMP ~/.julia/dev/JuMP/src/operators.jl:472
 [3] _broadcast_getindex_evalf
   @ ./broadcast.jl:648 [inlined]
 [4] _broadcast_getindex
   @ ./broadcast.jl:621 [inlined]
 [5] getindex
   @ ./broadcast.jl:575 [inlined]
 [6] copy
   @ ./broadcast.jl:922 [inlined]
 [7] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(sin), Tuple{Vector{VariableRef}}})
   @ Base.Broadcast ./broadcast.jl:883
 [8] macro expansion
   @ ~/.julia/dev/JuMP/src/macros.jl:1867 [inlined]
 [9] top-level scope
   @ REPL[24]:1

@odow
Copy link
Member Author

odow commented Feb 23, 2023

So the issue is the broadcast sin.(. It's likely been an issue in JuMP forever. Here's v1.0.0 (prior to the nonlinear changes)

(jmp) pkg> st
      Status `/private/tmp/jmp/Project.toml`
  [4076af6c] JuMP v1.0.0

julia> using JuMP

julia> model = Model();

julia> @variable(model, x[1:2]);

julia> @NLobjective(model, Min, sum(sin.(x)))
ERROR: sum() can appear in nonlinear expressions  only if the argument is a generator statement, for example, sum(x[i] for i in 1:N).
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] macro expansion
   @ ~/.julia/packages/JuMP/0C6kd/src/parse_nlp.jl:544 [inlined]
 [3] macro expansion
   @ ~/.julia/packages/JuMP/0C6kd/src/macros.jl:2057 [inlined]
 [4] top-level scope
   @ REPL[17]:1

julia> @NLobjective(model, Min, sin.(x)' * (1:2))
ERROR: sin is not defined for type AbstractVariableRef. Are you trying to build a nonlinear problem? Make sure you use @NLconstraint/@NLobjective.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] sin(#unused#::VariableRef)
    @ JuMP ~/.julia/packages/JuMP/0C6kd/src/operators.jl:409
  [3] _broadcast_getindex_evalf
    @ ./broadcast.jl:648 [inlined]
  [4] _broadcast_getindex
    @ ./broadcast.jl:621 [inlined]
  [5] getindex
    @ ./broadcast.jl:575 [inlined]
  [6] copy
    @ ./broadcast.jl:922 [inlined]
  [7] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(sin), Tuple{Vector{VariableRef}}})
    @ Base.Broadcast ./broadcast.jl:883
  [8] macro expansion
    @ ~/.julia/packages/JuMP/0C6kd/src/parse_nlp.jl:544 [inlined]
  [9] macro expansion
    @ ~/.julia/packages/JuMP/0C6kd/src/macros.jl:2057 [inlined]
 [10] top-level scope
    @ REPL[18]:1

@odow
Copy link
Member Author

odow commented Feb 23, 2023

This is actually quite hard to fix, because we currently support things like:

using JuMP
model = Model();
@variable(model, x);
a = 1
@NLobjective(model, Min, x * sin.(a))

In this case, we eagerly evaluate sin.(a), which, despite being a broadcast, returns a scalar:

julia> @macroexpand @NLobjective(model, Min, x * sin.(a))
quote
    #= REPL[51]:1 =#
    JuMP._valid_model(model, :model)
    begin
        #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2390 =#
        begin
            #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:1867 =#
            JuMP._init_NLP(model)
            var"#121###337" = JuMP.Expr(:call, :*, x, sin.(a))
        end
        #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2391 =#
        JuMP.set_nonlinear_objective(model, JuMP._throw_error_for_invalid_sense(JuMP.var"#_error#97"{LineNumberNode, Symbol, Symbol, Expr}(:(#= REPL[51]:1 =#), :model, :Min, :(x * sin.(a))), MathOptInterface.MIN_SENSE), var"#121###337")
    end
end

So it's breaking to now disallow all broadcasts. We could potentially check if any of the arguments to a broadcast are variables. But that might also cause issues. Perhaps we just need to improve the error message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Nonlinear Related to nonlinear programming Type: Bug
Development

Successfully merging a pull request may close this issue.

1 participant