ConstraintSolver.jl icon indicating copy to clipboard operation
ConstraintSolver.jl copied to clipboard

Another constraint request: modulo (%)

Open hakank opened this issue 3 years ago • 4 comments

Would it be possible to add a modulo constraint (as mod(x,y) or x % y or x mod y)?

The mod constraint is quite handy for certain CSP problems. e.g. puzzles and special algorithms.

hakank avatar Dec 08 '20 07:12 hakank

I'll focus on the element constraints for not but this should be fairly easy to add I think. For now you might want to solve it using the TableConstraint

Wikunia avatar Dec 08 '20 08:12 Wikunia

BTW if you're interested in special constraints please feel free to open a PR yourself if interested. I can guide you through the necessary steps.

Wikunia avatar Dec 08 '20 08:12 Wikunia

I'll focus on the element constraints for not but this should be fairly easy to add I think. For now you might want to solve it using the TableConstraint

Thanks, I'll test implementing modulo with Table constraint. (And I agree that element is more important than modulo.)

And thanks for the offer about PR:s regarding constraints. However, I want to implement "all" my models before doing more advanced stuff in Julia.

I guess that you mean "proper" constraints and not just decompositions. I've already write some decompositions that I've needed, e.g. increasing, decreasing, scalar_product, and to_num (the last converts between an array of digits in some base and a number).

hakank avatar Dec 08 '20 15:12 hakank

FYI: Here's a simple decomposition using TableConstraint, but I think the creation of the table can be a little better with some more thoughts. I'll test it with some proper models later on.

#
# modulo(model, x, y, z)
#
# Ensures that  x mod y == z
#
function modulo(model, x, y, z)
    lbx = round(Int, JuMP.lower_bound(x))
    ubx = round(Int, JuMP.upper_bound(x))
    lby = round(Int, JuMP.lower_bound(y))
    uby = round(Int, JuMP.upper_bound(y))

    table = resize_matrix([ [i,j,i % j] for i in lbx:ubx, j in lby:uby if j != 0])
    @constraint(model, [x, y, z] in CS.TableSet(table))
end

I first tried to port my ECLiPSe modulo propagator (http://hakank.org/eclipse/modulo_propagator.ecl ) to ConstraintSolver.jl:

function modulo2(model, x, y, z)
    @constraint(model, y != 0)
    lbx = round(Int, JuMP.lower_bound(x))
    ubx = round(Int, JuMP.lower_bound(x))
    lbx_neg = -lbx
    ubx_neg = -ubx
    min_x = min(lbx,ubx_neg)
    max_x = max(ubx,lbx_neg)
    @variable(model, min_x <= d <= max_x,Int)
    @constraint(model, x == y*d + z)

    @constraint(model,-abs(Y) <= z ) # should be < but it's not supported
    @constraint(model,-abs(Y) != z )

    @constraint(model, z <= abs(Y))  # should be < but it's not supported
    @constraint(model, z != abs(Y))

    @constraint(model, min_x <= d)
    @constraint(model, d <= max_x)

end

abs constraint is not supported (I realized), and is was a very messy error regarding ScalarQuadraticFunction.

hakank avatar Dec 08 '20 19:12 hakank