Skip to content

Commit

Permalink
table constraint and bugfix when vars not created (#169)
Browse files Browse the repository at this point in the history
* table constraint and bugfix when vars not created
* v0.2.0
  • Loading branch information
Wikunia authored Jun 17, 2020
1 parent 587dbc8 commit 62f6b65
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 48 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# ConstrainSolver.jl - Changelog

## v0.2.0 (17th of June 2020)
- Bugfix for indicator constraints
- support for TableConstraint in Indicator

## v0.1.8 (15th of June 2020)
- Support for indicator constraints
- i.e. `@constraint(m, b => { x + y <= 10 })`
Expand Down
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name = "ConstraintSolver"
uuid = "e0e52ebd-5523-408d-9ca3-7641f1cd1405"
authors = ["Ole Kröger <[email protected]>"]
version = "0.1.8"
version = "0.2.0"

[deps]
Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0"
GMP_jll = "781609d7-10c4-51f6-84f2-b8444358ff6d"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Expand All @@ -13,6 +14,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
Formatting = "^0.4.1"
GMP_jll = "=6.1.2"
JSON = "~0.18, ~0.19, ~0.20, ~0.21"
JuMP = "^0.21.0"
MathOptInterface = "^0.9.1"
Expand Down
4 changes: 4 additions & 0 deletions src/ConstraintSolver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ function set_pvals!(com::CS.CoM, constraint::Constraint)
pvals = vcat(pvals, collect(interval.from:interval.to))
end
constraint.std.pvals = pvals
if constraint isa IndicatorConstraint
# TODO: This will always include 0/1 even if not in the inner constraint
constraint.inner_constraint.std.pvals = pvals
end
end

"""
Expand Down
2 changes: 1 addition & 1 deletion src/MOI_wrapper/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Copy constructor for the optimizer
"""
MOIU.supports_default_copy_to(model::Optimizer, copy_names::Bool) = !copy_names
function MOI.copy_to(model::Optimizer, src::MOI.ModelLike; kws...)
return MOI.Utilities.automatic_copy_to(model, src; kws...)
return MOIU.automatic_copy_to(model, src; kws...)
end

MOI.supports(::Optimizer, ::MOI.RawParameter) = true
Expand Down
57 changes: 11 additions & 46 deletions src/MOI_wrapper/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ function JuMP._build_indicator_constraint(
_error::Function, variable::JuMP.AbstractVariableRef,
constraint::JuMP.VectorConstraint, ::Type{MOI.IndicatorSet{A}}) where A

variable_indices = [v.index for v in constraint.func]
set = CS.IndicatorSet{A}(variable, MOI.VectorOfVariables(variable_indices), constraint.set, 0)
set = CS.IndicatorSet{A}(variable, MOI.VectorOfVariables(constraint.func), constraint.set, 1+length(constraint.func))
vov = VariableRef[variable]
append!(vov, constraint.func)
return JuMP.VectorConstraint(vov, set)
Expand Down Expand Up @@ -248,16 +247,7 @@ function MOI.add_constraint(
Int[v.value for v in vars.variables]
)

constraint = AllDifferentConstraint(
internals,
Int[], # pval_mapping will be filled later
Int[], # vertex_mapping => later
Int[], # vertex_mapping_bw => later
Int[], # di_ei => later
Int[], # di_ej => later
MatchingInit(),
Int[]
)
constraint = init_constraint_struct(AllDifferentSetInternal, internals)

push!(com.constraints, constraint)
for (i, ind) in enumerate(constraint.std.indices)
Expand All @@ -282,18 +272,7 @@ function MOI.add_constraint(
Int[v.value for v in vars.variables]
)

constraint = TableConstraint(
internals,
RSparseBitSet(),
TableSupport(), # will be filled in init_constraint!
Int[], # will be changes later as it needs the number of words
TableResidues(),
Vector{TableBacktrackInfo}(),
Int[], # changed_vars
Int[], # unfixed_vars
Int[], # sum_min
Int[] # sum_max
)
constraint = init_constraint_struct(TableSetInternal, internals)

push!(com.constraints, constraint)
for (i, ind) in enumerate(constraint.std.indices)
Expand Down Expand Up @@ -399,28 +378,14 @@ function MOI.add_constraint(
Int[v.value for v in vars.variables]
)

inner_constraint = nothing
if set.set isa CS.AllDifferentSetInternal
inner_internals = ConstraintInternals(
0,
MOI.VectorOfVariables(vars.variables[2:end]),
set.set,
Int[v.value for v in vars.variables[2:end]]
)

inner_constraint = AllDifferentConstraint(
inner_internals,
Int[], # pval_mapping will be filled later
Int[], # vertex_mapping => later
Int[], # vertex_mapping_bw => later
Int[], # di_ei => later
Int[], # di_ej => later
MatchingInit(),
Int[]
)
end


inner_internals = ConstraintInternals(
0,
MOI.VectorOfVariables(vars.variables[2:end]),
set.set,
Int[v.value for v in vars.variables[2:end]]
)
inner_constraint = init_constraint_struct(typeof(set.set), inner_internals)

con = IndicatorConstraint(internals, A, inner_constraint)

push!(com.constraints, con)
Expand Down
13 changes: 13 additions & 0 deletions src/constraints/all_different.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ function all_different(variables::Vector{Variable})
return constraint
end

function init_constraint_struct(::Type{AllDifferentSetInternal}, internals)
AllDifferentConstraint(
internals,
Int[], # pval_mapping will be filled later
Int[], # vertex_mapping => later
Int[], # vertex_mapping_bw => later
Int[], # di_ei => later
Int[], # di_ej => later
MatchingInit(),
Int[]
)
end

"""
init_constraint!(com::CS.CoM, constraint::AllDifferentConstraint, fct::MOI.VectorOfVariables, set::AllDifferentSetInternal)
Expand Down
27 changes: 27 additions & 0 deletions src/constraints/indicator.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
"""
init_constraint!(
com::CS.CoM,
constraint::IndicatorConstraint,
fct::Union{MOI.VectorOfVariables, VAF{T}},
set::IS
) where {A, T<:Real, ASS<:MOI.AbstractScalarSet, IS<:Union{IndicatorSet{A}, MOI.IndicatorSet{A, ASS}}}
Initialize the inner constraint if it needs to be initialized
"""
function init_constraint!(
com::CS.CoM,
constraint::IndicatorConstraint,
fct::Union{MOI.VectorOfVariables, VAF{T}},
set::IS
) where {A, T<:Real, ASS<:MOI.AbstractScalarSet, IS<:Union{IndicatorSet{A}, MOI.IndicatorSet{A, ASS}}}
inner_constraint = constraint.inner_constraint
if hasmethod(
init_constraint!,
(CS.CoM, typeof(inner_constraint), typeof(inner_constraint.std.fct), typeof(inner_constraint.std.set)),
)
return init_constraint!(com, inner_constraint, inner_constraint.std.fct, inner_constraint.std.set)
end
# still feasible
return true
end

"""
prune_constraint!(
com::CS.CoM,
Expand Down
15 changes: 15 additions & 0 deletions src/constraints/table.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ include("table/support.jl")
include("table/residues.jl")
include("table/RSparseBitSet.jl")

function init_constraint_struct(::Type{TableSetInternal}, internals)
TableConstraint(
internals,
RSparseBitSet(),
TableSupport(), # will be filled in init_constraint!
Int[], # will be changes later as it needs the number of words
TableResidues(),
Vector{TableBacktrackInfo}(),
Int[], # changed_vars
Int[], # unfixed_vars
Int[], # sum_min
Int[] # sum_max
)
end

"""
init_constraint!(com::CS.CoM, constraint::TableConstraint, fct::MOI.VectorOfVariables, set::TableSetInternal)
Expand Down
21 changes: 21 additions & 0 deletions test/constraints/indicator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,25 @@ end
com = JuMP.backend(m).optimizer.model.inner
@test is_solved(com)
end

@testset "Basic Table" begin
m = Model(CSJuMPTestOptimizer())
@variable(m, 0 <= x <= 1, Int)
@variable(m, 0 <= y <= 1, Int)
@variable(m, a, Bin)
@constraint(m, x +y <= 1)
@constraint(m, a => {[x,y] in CS.TableSet([
0 1;
1 1
])})
@objective(m, Max, a)
optimize!(m)
@test JuMP.termination_status(m) == MOI.OPTIMAL
@test JuMP.objective_value(m) 1.0
@test JuMP.value(a) 1.0
@test JuMP.value(y) 1.0
@test JuMP.value(x) 0.0
com = JuMP.backend(m).optimizer.model.inner
@test is_solved(com)
end
end

0 comments on commit 62f6b65

Please sign in to comment.