I’m trying to define a nonlinear constraint programmatically via expressions. Specifically, I have a function f that takes in arguments x (a JuMP Variable), i (the index of the variable), and p (some parameters). The real function f is somewhat involved, so I’d like to be able to pass it indices/parameters and return an expression that I can use in JuMP constraints. So far, the below attempts haven’t worked for me. What I’m hung up on is splicing the JuMP Variable into the expression.
using JuMP
##
## parameter and function
##
p = Dict()
p[:a] = 10.0
function f(x, i, p)
return :( $(x[i])^2 + $(p[:a]) )
end
The final constraint expression I’m trying to build must look something like
:( $(x[i])^2 + 10.0 == 0)
I first tried using the @NLconstraint macro
##
## attempt
##
M = Model()
@variable(M, x[1:3])
for i in 1:3
@NLconstraint(M, :(0 == $(Expr(:call, f, x, $(i), p))))
end
but got the error
ERROR: LoadError: in @NLconstraint ($(Expr(:quote, :(0 == $(Expr(:$, :(Expr(:call, f, x, $(Expr(:$, :i)), p)))))))): constraints must be in one of the following forms:
expr1 <= expr2
expr1 >= expr2
expr1 == expr2
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] @NLconstraint(::LineNumberNode, ::Module, ::Any, ::Any, ::Vararg{Any,N} where N) at /Users/jakeroth/.julia/packages/JuMP/PbnIJ/src/macros.jl:1375
in expression starting at REPL[18]:2
The issue with how I’ve written the constraint is that the JuMP Variable x isn’t spliced in, that is, I need the final expression to contain :( $(x[i]) ... ) but I only have :( x[i] ... ).
It seems that my function f is to blame – is there a way to rewrite it to get $ to stop interpolating in f? Alternatively, is there a better way to define programmatic constraints still using expressions?