Adding nonlinear constraints in JuMP without hard-coding


I am trying to do some kind of cutting-plan algorithm in JuMP.

I currently have the following example:

function generate_model(ydisc :: Vector{Vector{Float64}})
    model = Model(SCIP.Optimizer)

    @variable(model, 0 <= x[1:2] <= 6)
    @variable(model,0 <=z<=1)

     @objective(model, Min, 10-x[1])
     for (i,ydisc_i) in enumerate(ydisc)
         @NLconstraint(model, ((ydisc_i[1]^2/(1+exp(-40*(x[1]-ydisc_i[1])))+x[1]-ydisc_i[1]-2))<=0)

    return model

As you can see, the expression for the constraint is hard-coded into the model.
Is there a way that I can define this model for a general user defined function?

#define g outside, perhaps even as a lambda generated by another function
@NLconstraint(model, g(x,y_disc_i)<=0)

Here it says that “All nonlinear expressions must be inside of macros.” Does that mean, that I have to hard-code the functions. (I am new to Julia, usually use more Python or C++). Surprisingly, the EAGO.jl solver seems to have some operatoroverloading, so some experiments I tried only worked with that solver.


You can use user-defined functions in JuMP, but you have to register them first: Nonlinear Modeling · JuMP. You may want to look at the warnings about raw expressions in the link, if you need more flexibility.

Thanks blob,

thanks for your help.
I already saw that part of the documentation, but there are two problems for me

  1. I want to use global solvers, but e.g.
using JuMP;
using Ipopt;
using AmplNLWriter
using Couenne_jll;

square(x) = x^2
f(x, y) = (x - 1)^2 + (y - 2)^2

function run()
#model = Model(Ipopt.Optimizer)
model = Model(() -> AmplNLWriter.Optimizer(Couenne_jll.amplexe))
register(model, :square, 1, square; autodiff = true)
register(model, :my_f, 2, f; autodiff = true)

@variable(model, 0.5<=x[1:2]<=2)
@NLobjective(model, Min, my_f(x[1], square(x[2])))
@show value.(model[:x])


Does not work. Register only seems to work for methods that only require access to function evaluations and gradients.

  1. In my use case, I would need something akin to anonymous registered functions. Giving the functions a predefined unique name (like my_f) is not possible. I tried generating a unique name (like my_f_1 in the first iteration and my_f_2 in the second), but my knowledge about Julia Macros is far too shallow to succeed.

How about this example: Nonlinear Modeling · JuMP ? It creates names f_1, f_2.,… for functions that come from a vector of functions.

And what is the error you are getting with Couenne?

1 Like

That’s correct.

If you’re using a solver that requires expression graphs as part of the specification of the input problem (most global solvers do, including SCIP and Couenne), then JuMP needs to see the expressions. This is not possible with JuMP.register. You may specify the constraints using macros or raw expression input.