How to set up NLconstraints from multi-output user-defined function?

It will call your function twice.

The suggested work-around is to use memoization like so:

using JuMP
using Ipopt

function myfun(x)
    return sum(xi for xi in x), sum(xi^2 for xi in x)
end

function memoized()
    cache = Dict{UInt, Any}()
    fi = (i, x) -> begin
        h = hash((x, typeof(x)))
        if !haskey(cache, h)
            cache[h] = myfun(x)
        end
        return cache[h][i]::Real
    end
    return (x...) -> fi(1, x), (x...) -> fi(2, x)
end

model = Model(Ipopt.Optimizer)
f1, f2 = memoized()
register(model, :f1, 3, f1; autodiff = true)
register(model, :f2, 3, f2; autodiff = true)
@variable(model, x[1:3] >= 0, start = 0.1)
@NLconstraint(model, f1(x...) <= 2)
@NLconstraint(model, f2(x...) <= 1)
@objective(model, Max, sum(x))
optimize!(model)
2 Likes