Automatic generation user-defined functions and NLexpression

Hi everyone!
I’m trying to create a non-linear expression for a non-linear problem.
I need to automatically register some user-defined functions (in the MWE func1 and func2) and use them in the NLexpression.
In particular, I would like to obtain a 4x2 non-linear expression. The first column should contain the first function (func1) and the second column the second function(func2).
I get the following error: ‘UndefVarError: i not defined’, but I don’t understand why.

I thank you and apologize if I have not been clear enough.

using Ipopt
using JuMP

model = Model(optimizer_with_attributes(Ipopt.Optimizer))
@variable(model,x[1:6])

#create 2 functions func1=(tanh(z-1)+1)/2 and func2=(tanh(z-1)+2)/2
for j in 1:2
    @eval ($(Symbol("func$j")))(z) = (tanh(z-j)+1)/2
    register(model, (Symbol("func$j")), 1, @eval ($(Symbol("func$j"))); autodiff = true)
end

#create a non linear expression (4 rows and 2 columns)
#[1,1] (func1(x[1]))*x[1]              #[1,2] (func2(x[2]))*x[2]
#[2,1] (func1(x[2]))*x[2]              #[2,2] (func2(x[3]))*x[3]
#[3,1] (func1(x[3]))*x[3]              #[3,2] (func2(x[4]))*x[4]
#[4,1] (func1(x[4]))*x[4]              #[4,2] (func2(x[5]))*x[4]
#[5,1] (func1(x[5]))*x[5]              #[5,2] (func2(x[6]))*x[6]

#more in detail
#[1,1]   ((tanh(x[1]-1)+1)/2)*x[1]     #[1,2]   ((tanh(x[2]-1)+2)/2)*x[2]
#[2,1]   ((tanh(x[2]-1)+1)/2)*x[2]     #[2,2]   ((tanh(x[3]-1)+2)/2)*x[3]
#[3,1]   ((tanh(x[3]-1)+1)/2)*x[3]     #[3,2]   ((tanh(x[4]-1)+2)/2)*x[4]
#[4,1]   ((tanh(x[4]-1)+1)/2)*x[4]     #[4,2]   ((tanh(x[5]-1)+2)/2)*x[5]
#[5,1]   ((tanh(x[5]-1)+1)/2)*x[5]     #[5,2]   ((tanh(x[6]-1)+2)/2)*x[6]

@NLexpression(model,con[i = 1:5, j=1:2], (@eval ($(Symbol("func$j")))(x[(i-1)+j]))*(x[(i-1)+j]))

#UndefVarError: i not defined

I’ve recently re-written the documentation for this: Nonlinear Modeling · JuMP (It isn’t in the released docs yet, still in dev.) Take a read, and post back if things are still unclear.

Unfortunately, you can’t create expressions using the raw-expression syntax, so you’ll have to create the objectives or constraints instead: https://github.com/jump-dev/JuMP.jl/issues/2506

As a general rule, using @eval is warning sign that things are incorrect. @eval runs thing in the global scope, which is why it doesn’t have access to the variable I.

1 Like