Skip to content

Commit

Permalink
check if inner violated and not just fixed (#266)
Browse files Browse the repository at this point in the history
* check if inner violated and not just fixed
* changed! functionality to avoid recomputation of recompute_lc_extrema
* call changed directly before prune
* v0.6.9
  • Loading branch information
Wikunia authored Jul 17, 2021
1 parent 1edcb16 commit 3e11d24
Show file tree
Hide file tree
Showing 16 changed files with 86 additions and 25 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# ConstrainSolver.jl - Changelog

## v0.6.9 (17th of July 2021)
- set activator to false when inner violated [PR #266](https://github.com/Wikunia/ConstraintSolver.jl/pull/266)

## v0.6.8 (14th of June 2021)
- support for xor and xnor constraints
- better bridge structure for boolean constraints
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ConstraintSolver"
uuid = "e0e52ebd-5523-408d-9ca3-7641f1cd1405"
authors = ["Ole Kröger <[email protected]>"]
version = "0.6.8"
version = "0.6.9"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Expand Down
8 changes: 8 additions & 0 deletions src/constraints/boolset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,11 @@ function finished_pruning_constraint!(
end
end
end


function changed!(com::CS.CoM, constraint::BoolConstraint, fct, set)
lhs = constraint.lhs
changed!(com, lhs, lhs.fct, lhs.set)
rhs = constraint.rhs
changed!(com, rhs, rhs.fct, rhs.set)
end
5 changes: 5 additions & 0 deletions src/constraints/indicator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,9 @@ function is_constraint_violated(
)
end
return false
end

function changed!(com::CS.CoM, constraint::IndicatorConstraint, fct, set)
inner_constraint = constraint.inner_constraint
changed!(com, inner_constraint, inner_constraint.fct, inner_constraint.set)
end
24 changes: 18 additions & 6 deletions src/constraints/linear_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function init_constraint!(
constraint.strict_rhs = set.set.upper - fct.constant
constraint.is_strict = true
is_no_variable_constraint(constraint) && return fct.constant < set.set.upper

recompute_lc_extrema!(com, constraint, fct)
return true
end

Expand All @@ -100,6 +100,7 @@ function init_constraint!(
) where {T<:Real}
constraint.rhs = set.upper - fct.constant
is_no_variable_constraint(constraint) && return fct.constant <= set.upper
recompute_lc_extrema!(com, constraint, fct)
return true
end

Expand All @@ -111,9 +112,14 @@ function init_constraint!(
) where {T<:Real}
constraint.rhs = set.value - fct.constant
is_no_variable_constraint(constraint) && return fct.constant == set.value
recompute_lc_extrema!(com, constraint, fct)
return true
end

function changed!(com::CS.CoM, constraint::LinearConstraint, fct, set)
recompute_lc_extrema!(com, constraint, fct)
end

"""
get_new_extrema_and_sum(search_space, vidx, i, terms, full_min, full_max, pre_mins, pre_maxs)
Expand Down Expand Up @@ -232,8 +238,7 @@ function prune_constraint!(
search_space = com.search_space
rhs = constraint.rhs

# compute max and min values for each index
recompute_lc_extrema!(com, constraint, fct)
# reuse calculated max and min values for each index
maxs = constraint.maxs
mins = constraint.mins
pre_maxs = constraint.pre_maxs
Expand Down Expand Up @@ -530,7 +535,6 @@ function is_constraint_solved(
fct::SAF{T},
set::MOI.LessThan{T},
) where T
recompute_lc_extrema!(com, constraint, fct)
sum_maxs = sum(constraint.maxs)
return sum_maxs <= MOI.constant(set)
end
Expand All @@ -551,7 +555,6 @@ function is_constraint_solved(
fct::SAF{T},
set::Strictly{T, MOI.LessThan{T}},
) where T
recompute_lc_extrema!(com, constraint, fct)
sum_maxs = sum(constraint.maxs)
return sum_maxs < MOI.constant(set)
end
Expand Down Expand Up @@ -611,7 +614,6 @@ function is_constraint_violated(
)
end
# check if it can be feasible using the minimum sum
recompute_lc_extrema!(com, constraint, fct)
return !min_sum_feasible(com, sum(constraint.mins), set)
end

Expand All @@ -629,4 +631,14 @@ function min_sum_feasible(com, min_sum, set::Strictly{T, MOI.LessThan{T}}) where
return get_approx_discrete(min_sum) < get_approx_discrete(MOI.constant(set))
end
return min_sum <= MOI.constant(set) + com.options.atol
end

function reverse_pruning_constraint!(
com::CoM,
constraint::LinearConstraint,
fct::SAF{T},
set::Union{MOI.LessThan, MOI.EqualTo, Strictly{T, MOI.LessThan{T}}},
backtrack_id::Int,
) where {T <: Real}
recompute_lc_extrema!(com, constraint, fct)
end
44 changes: 30 additions & 14 deletions src/constraints/reified.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function prune_constraint!(
logs = true,
) where {A,T<:Real,RS<:ReifiedSet{A}}
# 1. if the inner constraint is solved then the reified variable can be set to activate_on
# 2. if the complement of the inner constraint is solved (all fixed but don't fulfill) the reified variable can be set to !activate_on
# 2. if the inner constraint is infeasible the reified variable can be set to !activate_on
# 3. if the reified constraint is active then prune can be called for the inner constraint
# 4. if the reified constraint is fixed to inactive one can complement prune

Expand All @@ -61,26 +61,17 @@ function prune_constraint!(
activate_on = Int(constraint.activate_on)
activate_off = activate_on == 1 ? 0 : 1

# 1
if is_constraint_solved(
com,
inner_constraint,
inner_constraint.fct,
inner_constraint.set,
)
!fix!(com, variables[rei_vidx], activate_on) && return false
# 2
elseif all(isfixed(variables[vidx]) for vidx in inner_constraint.indices)
!fix!(com, variables[rei_vidx], activate_off) && return false
# 3
elseif issetto(variables[rei_vidx], activate_on)

# 3
if issetto(variables[rei_vidx], activate_on)
!activate_inner!(com, constraint) && return false
return prune_constraint!(
com,
inner_constraint,
inner_constraint.fct,
inner_constraint.set,
)
# 4
elseif issetto(variables[rei_vidx], activate_off) && complement_constraint !== nothing
!activate_complement_inner!(com, constraint) && return false
return prune_constraint!(
Expand All @@ -89,6 +80,22 @@ function prune_constraint!(
complement_constraint.fct,
complement_constraint.set,
)
# 1
elseif is_constraint_solved(
com,
inner_constraint,
inner_constraint.fct,
inner_constraint.set,
)
!fix!(com, variables[rei_vidx], activate_on) && return false
# 2
elseif is_constraint_violated(
com,
inner_constraint,
inner_constraint.fct,
inner_constraint.set,
)
!fix!(com, variables[rei_vidx], activate_off) && return false
end
return true
end
Expand Down Expand Up @@ -199,3 +206,12 @@ function is_constraint_violated(
end
return false
end

function changed!(com::CS.CoM, constraint::ReifiedConstraint, fct, set)
inner_constraint = constraint.inner_constraint
changed!(com, inner_constraint, inner_constraint.fct, inner_constraint.set)
if constraint.complement_constraint !== nothing
complement_constraint = constraint.complement_constraint
changed!(com, complement_constraint, complement_constraint.fct, complement_constraint.set)
end
end
7 changes: 3 additions & 4 deletions src/pruning.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ function prune!(

# while we haven't called every constraint
while true
b_open_constraint = false
# will be changed or b_open_constraint => false
open_pos, ci = get_next_prune_constraint(com, constraint_idxs_vec)
# no open values => don't need to call again
if open_pos == 0 && !initial_check
Expand All @@ -93,6 +91,7 @@ function prune!(
constraint_idxs_vec[ci] = N
constraint = com.constraints[ci]

changed!(com, constraint, constraint.fct, constraint.set)
feasible =
prune_constraint!(com, constraint, constraint.fct, constraint.set; logs = false)
if !pre_backtrack
Expand All @@ -118,11 +117,11 @@ function prune!(
inner_constraint = com.constraints[ci]
# if initial check or don't add constraints => update only those which already have open possibilities
if (only_once || initial_check) &&
constraint_idxs_vec[inner_constraint.idx] == N
constraint_idxs_vec[inner_constraint.idx] == N
continue
end
constraint_idxs_vec[inner_constraint.idx] =
open_possibilities(search_space, inner_constraint.indices)
open_possibilities(search_space, inner_constraint.indices)
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,8 @@ function view_changes(v::Variable, step_nr::Int)
idx_begin = v.changes.indices[step_nr]
idx_end = v.changes.indices[step_nr+1]-1
return @views v.changes.changes[idx_begin:idx_end]
end

function changed!(com::CS.CoM, constraint::Constraint, fct, set)
return
end
1 change: 1 addition & 0 deletions test/unit/constraints/and.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ end

constr_indices = constraint.indices
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test !CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
end

Expand Down
4 changes: 4 additions & 0 deletions test/unit/constraints/complement.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
constraint = com.constraints[1]
@test CS.fix!(com, variables[constraint.indices[1]], 1; check_feasibility = false)
@test CS.fix!(com, variables[constraint.indices[2]], 2; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.is_constraint_solved(com, constraint, constraint.fct, constraint.set)

#################
Expand All @@ -23,6 +24,7 @@
constraint = com.constraints[1]
@test CS.fix!(com, variables[constraint.indices[1]], 1; check_feasibility = false)
@test CS.fix!(com, variables[constraint.indices[2]], 1; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.is_constraint_solved(com, constraint, constraint.fct, constraint.set)

#################
Expand All @@ -39,6 +41,7 @@
xor_constraint = com.constraints[1].inner_constraint
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
@test CS.is_constraint_solved(com, xor_constraint, xor_constraint.fct, xor_constraint.set)

#################
Expand All @@ -55,6 +58,7 @@
xor_constraint = com.constraints[1].inner_constraint
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
@test CS.is_constraint_solved(com, xor_constraint, xor_constraint.fct, xor_constraint.set)


Expand Down
1 change: 1 addition & 0 deletions test/unit/constraints/less_than.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
@test sort(CS.values(com.search_space[3])) == -4:5

@test CS.fix!(com, com.search_space[constr_indices[3]], -4)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
@test CS.value(com.search_space[1]) == -1
@test CS.value(com.search_space[2]) == -1
Expand Down
2 changes: 2 additions & 0 deletions test/unit/constraints/or.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ end

constr_indices = constraint.indices
@test CS.fix!(com, variables[constraint.indices[2]], 0; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
for v in 0:2
@test !CS.has(variables[constraint.indices[3]], v)
Expand All @@ -184,6 +185,7 @@ end

constr_indices = constraint.indices
@test CS.fix!(com, variables[constraint.indices[2]], 0; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
for v in 0:2
@test !CS.has(variables[constraint.indices[4]], v)
Expand Down
1 change: 1 addition & 0 deletions test/unit/constraints/reified.jl
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ end
@test CS.fix!(com, variables[constr_indices[1]], 0; check_feasibility = false)
@test CS.fix!(com, variables[constr_indices[2]], 0; check_feasibility = false)
@test CS.fix!(com, variables[constr_indices[3]], 5; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
# should prune complement
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)

Expand Down
2 changes: 2 additions & 0 deletions test/unit/constraints/strictly_less_than.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
@test sort(CS.values(com.search_space[3])) == -5:5 # 6 not possible

@test CS.fix!(com, com.search_space[constr_indices[3]], 5)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
@test CS.value(com.search_space[1]) == -1
@test CS.value(com.search_space[2]) == -1
Expand Down Expand Up @@ -199,6 +200,7 @@ end
@test sort(CS.values(com.search_space[3])) == -5:6 # -6 not possible

@test CS.fix!(com, com.search_space[constr_indices[3]], -5)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
@test CS.value(com.search_space[1]) == -5
@test CS.value(com.search_space[2]) == 5
Expand Down
1 change: 1 addition & 0 deletions test/unit/constraints/xnor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ end

constr_indices = constraint.indices
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
@test sort(CS.values(m, x[1])) == [0,1,2]
end
Expand Down
2 changes: 2 additions & 0 deletions test/unit/constraints/xor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ end
xor_constraint = com.constraints[1].inner_constraint
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
@test CS.is_constraint_violated(com, xor_constraint, xor_constraint.fct, xor_constraint.set)

##################
Expand Down Expand Up @@ -180,6 +181,7 @@ end

constr_indices = constraint.indices
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
CS.changed!(com, constraint, constraint.fct, constraint.set)
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
@test sort(CS.values(m, x[1])) == [3,4,5]
end
Expand Down

0 comments on commit 3e11d24

Please sign in to comment.