Search code examples
julia-jump

Julia JuMP array variable constraint


I am trying to model a non-linear problem involving vector rotation using JuMP in Julia. I need a constraint, which looks something like v[1:3] == rotate(v) If I write it like this, it does not work, since "Nonlinear expressions may contain only scalar expressions". How can I work around this?

I could say something like v[1] == rotate(v)[1] and same for v[2] and v[3], but then I would have to compute rotate(v) three times as often. I could also try to split the rotate function into three functions which compute one element each, but the actual constraint is a bit more complicated than a simple rotation, so this could prove to be tricky.

Are there any other ways to do this? Maybe to have something like an auxiliary variable which can be computed as a vector and then in the constraint only compare the elements of the two vectors (essentialy the first approach, but without computing the function three times)?


Solution

  • See here for a suggested work-around:

    https://discourse.julialang.org/t/how-to-set-up-nlconstraints-from-multi-output-user-defined-function/42309/5?u=odow

    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)