Quinn Xie
Quinn Xie

Reputation: 41

Define a correct constraint, like outside a 2-D rectangle in Julia with JuMP

I would like to define a constraint in an optimization problem as follows: (x,y) not in {(x,y)|1.0 < x < 2.0, 3.0 < y < 4.0}.

what I tried is @constraint(model, (1.0 < x < 2.0 + 3.0 < y < 4.0)!=2), but failed. It seems that boolen operation is not allowed. such that I have no idea about it. Any advice is appreciated!

Upvotes: 4

Views: 157

Answers (2)

Dan Getz
Dan Getz

Reputation: 18227

UPDATE: The previous solution in this answer turned out to be wrong (exclude parts of the admissable region), and so I felt obligated to provide another 'right' solution. This solution partitions the admissable region into parts and solves different optimization problems for each part. Keeping the best solution. This is not a nice solution, but if one does not have a good solver (those commercial ones) it is one way. The commercial solvers usually go through a more efficient similar process by the name of branch-and-bound.

using JuMP, Ipopt

function solveopt()
    bestobj = Inf
    bestx, besty = 0.0,0.0
    for (ltside, xvar, val) in (
      (true, true, 2.0),(false, true, 3.0),
      (true, false, 3.0),(false, false, 4.0))
        m = Model(Ipopt.Optimizer)
        @variable(m, x)
        @variable(m, y)
        add_constraint(m, ScalarConstraint(xvar ? x : y,
          ltside ? MOI.LessThan(val) : MOI.GreaterThan(val)))

        # following is an objective optimal inside the box
        @NLobjective(m, Min, (x-2.5)^2+(y-3.5)^2)

        optimize!(m)
        if objective_value(m) < bestobj
            bestx, besty = value(x), value(y)
        end
    end
    return bestx, besty
end

The solution for this example problem is:

julia> solveopt()
:
: lots of solver output...
:
(2.5, 3.9999999625176965)

Lastly, I benchmarked this crude method against a non-commercial solver (Pajarito) with the method from other answer and this one is 2X faster (because of simplicity, I suppose). Commercial solvers would beat both times.

Upvotes: 0

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42244

You should avoid introducing quadratic constraints (as in the other answer) and rather introduce binary variables. This increase number of available solvers and generally linear models take shorter time to solve.

Hence you should note that !(1.0 < x < 2.0) is an equivalent of x <= 1 || x >= 2 which can be written in a linear form as:

@variable(model, bx, Bin)
const M = 1000 # number "big enough"
@constraint(model, x <= 1 + M*bx)
@constraint(model, x >=2 - M*(1-bx))

bx is here a "switcher" variable that makes either first or second constraint obligatory.

I am not sure what you want about y as you have 3.0 < y < 3.0 but basically the pattern to formulate the would be the same. Just note you cannot have a constraint such as y != 3 as solvers obviously have some numerical accuracy and you would need rather to represent this is as for an example !(3-0.01 < y < 3+0.01) (still using the same pattern as above)

Upvotes: 2

Related Questions