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

Document that nonlinear expressions cannot be built outside of a macro #2060

Closed
xtalax opened this issue Sep 11, 2019 · 4 comments · Fixed by #2470
Closed

Document that nonlinear expressions cannot be built outside of a macro #2060

xtalax opened this issue Sep 11, 2019 · 4 comments · Fixed by #2470

Comments

@xtalax
Copy link

xtalax commented Sep 11, 2019

Hello,

I'm trying to optimize an Array of parameters to minimize the norm between a function of these parameters and some measured data - here is an example of what I am trying to do:

function ξ(x̄::AbstractArray) = norm(true_func(x, y) .- test_func(x̄, x, y)) #Declare objective func

x = y = range(0.0, stop = 1.0, length = 30)
m = Model()
@variable(m, x̄[1:30, 1:30] >= 1) # Setup parameters

register(m, :ξ, 1, ξ, autodiff=true) #Register function

@objective(m, Min, ξ(x̄))
optimize!(model)

I get a stack overflow error which seems to be triggered by taking the norm of an Array{VariableRef} or an Array{GenericAffExpr}.

Minimum reproducible example:

using JuMP, LinearAlgebra
m = Model()
@variable(m, x̄[1:30,1:30]) # Setup parameters
norm(x̄)
@odow
Copy link
Member

odow commented Sep 11, 2019

There are multiple things going on

  1. You cannot define a nonlinear function with vector inputs, see: https://www.juliaopt.org/JuMP.jl/v0.20.0/nlp/#User-defined-functions-with-vector-inputs-1
  2. You need to use @NLobjective(m, Min, ξ(x̄)) instead of @objective(m, Min, ξ(x̄)). This would have yielded the error related to the first point:
julia> @NLobjective(m, Min, f(x))
ERROR: Unexpected array VariableRef[x[1,1] x[1,2]; x[2,1] x[2,2]] in nonlinear expression. Nonlinear expressions may contain only scalar expressions.
  1. norm(x) is a bit meaningless if x is an Array{VariableRef} because we can't create nonlinear expressions directly.

It's unfortunate that we don't throw a better error message, but we can't expect to catch every error thrown by arbitrary functions in Julia that are operated on VariableRef instead of their values.

The syntax you're looking for is something like

julia> f(x...) = LinearAlgebra.norm(reshape(collect(x), 2, 2))
f (generic function with 1 method)

julia> m = Model(with_optimizer(Ipopt.Optimizer))
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: SolverName() attribute not implemented by the optimizer.

julia> @variable(m, x[1:2, 1:2] >= 0)
2×2 Array{VariableRef,2}:
 x[1,1]  x[1,2]
 x[2,1]  x[2,2]

julia> register(m, :f, 4, f, autodiff=true)

julia> @NLobjective(m, Min, f(x...))

@odow odow changed the title Taking norm of an array of JuMP variables for use in objective function throws StackOverflow Document that nonlinear expressions cannot be built outside of a macro Jul 1, 2020
@odow
Copy link
Member

odow commented Jul 1, 2020

This has come up a few times: https://stackoverflow.com/questions/62622919/jump-constraints-involving-matrix-inverse

Task for the sprint:

  • Add a warning to the NLP documentation that all nonlinear expressions must be inside macros.

@grishabh147
Copy link

grishabh147 commented Nov 23, 2020

I am sorry if this is something very trivial, but I am trying to run the following code:

using JuMP, Ipopt, LinearAlgebra
FP = Model(solver=IpoptSolver())
@variable(FP, x[1:2,1:2] >= 0)
@objective(FP, Max, 0)

@NLconstraint(FP, inv(x) <= 0.5*I)

status = solve(FP)

But it raises the following error:

ERROR: LoadError: Unexpected object x[i,j] >= 0 for all i in {1,2}, j in {1,2} in nonlinear expression.

I understand that this is related to not being able to define nonlinear expressions with vector inputs. I have tried the workaround mentioned above by defining a f(x...) first, but it still doesn't work for me and throws the following error:

ERROR: Incorrect number of arguments for "f" in nonlinear expression.

My code for the second case is as follows:

using JuMP, Ipopt, LinearAlgebra
f(x...) = LinearAlgebra.inv(reshape(collect(x), 2, 2))
FP = Model(solver=IpoptSolver())
@variable(FP, x[1:2,1:2] >= 0)
@objective(FP, Max, 0)
JuMP.register(FP, :f, 4, f, autodiff=true)
@NLconstraint(FP, f(x...) <= 0.5*I)

status = solve(FP)

Could you please help me figure out the problem here?

@grishabh147
Copy link

This seems to be working after upgrading to the latest version of JuMP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants