Skip to content

Commit 3e11d24

Browse files
authored
check if inner violated and not just fixed (#266)
* 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
1 parent 1edcb16 commit 3e11d24

16 files changed

+86
-25
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ConstrainSolver.jl - Changelog
22

3+
## v0.6.9 (17th of July 2021)
4+
- set activator to false when inner violated [PR #266](https://github.com/Wikunia/ConstraintSolver.jl/pull/266)
5+
36
## v0.6.8 (14th of June 2021)
47
- support for xor and xnor constraints
58
- better bridge structure for boolean constraints

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ConstraintSolver"
22
uuid = "e0e52ebd-5523-408d-9ca3-7641f1cd1405"
33
authors = ["Ole Kröger <[email protected]>"]
4-
version = "0.6.8"
4+
version = "0.6.9"
55

66
[deps]
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"

src/constraints/boolset.jl

+8
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,11 @@ function finished_pruning_constraint!(
298298
end
299299
end
300300
end
301+
302+
303+
function changed!(com::CS.CoM, constraint::BoolConstraint, fct, set)
304+
lhs = constraint.lhs
305+
changed!(com, lhs, lhs.fct, lhs.set)
306+
rhs = constraint.rhs
307+
changed!(com, rhs, rhs.fct, rhs.set)
308+
end

src/constraints/indicator.jl

+5
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,9 @@ function is_constraint_violated(
229229
)
230230
end
231231
return false
232+
end
233+
234+
function changed!(com::CS.CoM, constraint::IndicatorConstraint, fct, set)
235+
inner_constraint = constraint.inner_constraint
236+
changed!(com, inner_constraint, inner_constraint.fct, inner_constraint.set)
232237
end

src/constraints/linear_constraints.jl

+18-6
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function init_constraint!(
8282
constraint.strict_rhs = set.set.upper - fct.constant
8383
constraint.is_strict = true
8484
is_no_variable_constraint(constraint) && return fct.constant < set.set.upper
85-
85+
recompute_lc_extrema!(com, constraint, fct)
8686
return true
8787
end
8888

@@ -100,6 +100,7 @@ function init_constraint!(
100100
) where {T<:Real}
101101
constraint.rhs = set.upper - fct.constant
102102
is_no_variable_constraint(constraint) && return fct.constant <= set.upper
103+
recompute_lc_extrema!(com, constraint, fct)
103104
return true
104105
end
105106

@@ -111,9 +112,14 @@ function init_constraint!(
111112
) where {T<:Real}
112113
constraint.rhs = set.value - fct.constant
113114
is_no_variable_constraint(constraint) && return fct.constant == set.value
115+
recompute_lc_extrema!(com, constraint, fct)
114116
return true
115117
end
116118

119+
function changed!(com::CS.CoM, constraint::LinearConstraint, fct, set)
120+
recompute_lc_extrema!(com, constraint, fct)
121+
end
122+
117123
"""
118124
get_new_extrema_and_sum(search_space, vidx, i, terms, full_min, full_max, pre_mins, pre_maxs)
119125
@@ -232,8 +238,7 @@ function prune_constraint!(
232238
search_space = com.search_space
233239
rhs = constraint.rhs
234240

235-
# compute max and min values for each index
236-
recompute_lc_extrema!(com, constraint, fct)
241+
# reuse calculated max and min values for each index
237242
maxs = constraint.maxs
238243
mins = constraint.mins
239244
pre_maxs = constraint.pre_maxs
@@ -530,7 +535,6 @@ function is_constraint_solved(
530535
fct::SAF{T},
531536
set::MOI.LessThan{T},
532537
) where T
533-
recompute_lc_extrema!(com, constraint, fct)
534538
sum_maxs = sum(constraint.maxs)
535539
return sum_maxs <= MOI.constant(set)
536540
end
@@ -551,7 +555,6 @@ function is_constraint_solved(
551555
fct::SAF{T},
552556
set::Strictly{T, MOI.LessThan{T}},
553557
) where T
554-
recompute_lc_extrema!(com, constraint, fct)
555558
sum_maxs = sum(constraint.maxs)
556559
return sum_maxs < MOI.constant(set)
557560
end
@@ -611,7 +614,6 @@ function is_constraint_violated(
611614
)
612615
end
613616
# check if it can be feasible using the minimum sum
614-
recompute_lc_extrema!(com, constraint, fct)
615617
return !min_sum_feasible(com, sum(constraint.mins), set)
616618
end
617619

@@ -629,4 +631,14 @@ function min_sum_feasible(com, min_sum, set::Strictly{T, MOI.LessThan{T}}) where
629631
return get_approx_discrete(min_sum) < get_approx_discrete(MOI.constant(set))
630632
end
631633
return min_sum <= MOI.constant(set) + com.options.atol
634+
end
635+
636+
function reverse_pruning_constraint!(
637+
com::CoM,
638+
constraint::LinearConstraint,
639+
fct::SAF{T},
640+
set::Union{MOI.LessThan, MOI.EqualTo, Strictly{T, MOI.LessThan{T}}},
641+
backtrack_id::Int,
642+
) where {T <: Real}
643+
recompute_lc_extrema!(com, constraint, fct)
632644
end

src/constraints/reified.jl

+30-14
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function prune_constraint!(
5050
logs = true,
5151
) where {A,T<:Real,RS<:ReifiedSet{A}}
5252
# 1. if the inner constraint is solved then the reified variable can be set to activate_on
53-
# 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
53+
# 2. if the inner constraint is infeasible the reified variable can be set to !activate_on
5454
# 3. if the reified constraint is active then prune can be called for the inner constraint
5555
# 4. if the reified constraint is fixed to inactive one can complement prune
5656

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

64-
# 1
65-
if is_constraint_solved(
66-
com,
67-
inner_constraint,
68-
inner_constraint.fct,
69-
inner_constraint.set,
70-
)
71-
!fix!(com, variables[rei_vidx], activate_on) && return false
72-
# 2
73-
elseif all(isfixed(variables[vidx]) for vidx in inner_constraint.indices)
74-
!fix!(com, variables[rei_vidx], activate_off) && return false
75-
# 3
76-
elseif issetto(variables[rei_vidx], activate_on)
64+
65+
# 3
66+
if issetto(variables[rei_vidx], activate_on)
7767
!activate_inner!(com, constraint) && return false
7868
return prune_constraint!(
7969
com,
8070
inner_constraint,
8171
inner_constraint.fct,
8272
inner_constraint.set,
8373
)
74+
# 4
8475
elseif issetto(variables[rei_vidx], activate_off) && complement_constraint !== nothing
8576
!activate_complement_inner!(com, constraint) && return false
8677
return prune_constraint!(
@@ -89,6 +80,22 @@ function prune_constraint!(
8980
complement_constraint.fct,
9081
complement_constraint.set,
9182
)
83+
# 1
84+
elseif is_constraint_solved(
85+
com,
86+
inner_constraint,
87+
inner_constraint.fct,
88+
inner_constraint.set,
89+
)
90+
!fix!(com, variables[rei_vidx], activate_on) && return false
91+
# 2
92+
elseif is_constraint_violated(
93+
com,
94+
inner_constraint,
95+
inner_constraint.fct,
96+
inner_constraint.set,
97+
)
98+
!fix!(com, variables[rei_vidx], activate_off) && return false
9299
end
93100
return true
94101
end
@@ -199,3 +206,12 @@ function is_constraint_violated(
199206
end
200207
return false
201208
end
209+
210+
function changed!(com::CS.CoM, constraint::ReifiedConstraint, fct, set)
211+
inner_constraint = constraint.inner_constraint
212+
changed!(com, inner_constraint, inner_constraint.fct, inner_constraint.set)
213+
if constraint.complement_constraint !== nothing
214+
complement_constraint = constraint.complement_constraint
215+
changed!(com, complement_constraint, complement_constraint.fct, complement_constraint.set)
216+
end
217+
end

src/pruning.jl

+3-4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ function prune!(
7878

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

94+
changed!(com, constraint, constraint.fct, constraint.set)
9695
feasible =
9796
prune_constraint!(com, constraint, constraint.fct, constraint.set; logs = false)
9897
if !pre_backtrack
@@ -118,11 +117,11 @@ function prune!(
118117
inner_constraint = com.constraints[ci]
119118
# if initial check or don't add constraints => update only those which already have open possibilities
120119
if (only_once || initial_check) &&
121-
constraint_idxs_vec[inner_constraint.idx] == N
120+
constraint_idxs_vec[inner_constraint.idx] == N
122121
continue
123122
end
124123
constraint_idxs_vec[inner_constraint.idx] =
125-
open_possibilities(search_space, inner_constraint.indices)
124+
open_possibilities(search_space, inner_constraint.indices)
126125
end
127126
end
128127
end

src/util.jl

+4
Original file line numberDiff line numberDiff line change
@@ -370,4 +370,8 @@ function view_changes(v::Variable, step_nr::Int)
370370
idx_begin = v.changes.indices[step_nr]
371371
idx_end = v.changes.indices[step_nr+1]-1
372372
return @views v.changes.changes[idx_begin:idx_end]
373+
end
374+
375+
function changed!(com::CS.CoM, constraint::Constraint, fct, set)
376+
return
373377
end

test/unit/constraints/and.jl

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ end
162162

163163
constr_indices = constraint.indices
164164
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
165+
CS.changed!(com, constraint, constraint.fct, constraint.set)
165166
@test !CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
166167
end
167168

test/unit/constraints/complement.jl

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
constraint = com.constraints[1]
1010
@test CS.fix!(com, variables[constraint.indices[1]], 1; check_feasibility = false)
1111
@test CS.fix!(com, variables[constraint.indices[2]], 2; check_feasibility = false)
12+
CS.changed!(com, constraint, constraint.fct, constraint.set)
1213
@test CS.is_constraint_solved(com, constraint, constraint.fct, constraint.set)
1314

1415
#################
@@ -23,6 +24,7 @@
2324
constraint = com.constraints[1]
2425
@test CS.fix!(com, variables[constraint.indices[1]], 1; check_feasibility = false)
2526
@test CS.fix!(com, variables[constraint.indices[2]], 1; check_feasibility = false)
27+
CS.changed!(com, constraint, constraint.fct, constraint.set)
2628
@test CS.is_constraint_solved(com, constraint, constraint.fct, constraint.set)
2729

2830
#################
@@ -39,6 +41,7 @@
3941
xor_constraint = com.constraints[1].inner_constraint
4042
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
4143
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
44+
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
4245
@test CS.is_constraint_solved(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
4346

4447
#################
@@ -55,6 +58,7 @@
5558
xor_constraint = com.constraints[1].inner_constraint
5659
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
5760
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
61+
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
5862
@test CS.is_constraint_solved(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
5963

6064

test/unit/constraints/less_than.jl

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
@test sort(CS.values(com.search_space[3])) == -4:5
7474

7575
@test CS.fix!(com, com.search_space[constr_indices[3]], -4)
76+
CS.changed!(com, constraint, constraint.fct, constraint.set)
7677
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
7778
@test CS.value(com.search_space[1]) == -1
7879
@test CS.value(com.search_space[2]) == -1

test/unit/constraints/or.jl

+2
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ end
165165

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

185186
constr_indices = constraint.indices
186187
@test CS.fix!(com, variables[constraint.indices[2]], 0; check_feasibility = false)
188+
CS.changed!(com, constraint, constraint.fct, constraint.set)
187189
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
188190
for v in 0:2
189191
@test !CS.has(variables[constraint.indices[4]], v)

test/unit/constraints/reified.jl

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ end
254254
@test CS.fix!(com, variables[constr_indices[1]], 0; check_feasibility = false)
255255
@test CS.fix!(com, variables[constr_indices[2]], 0; check_feasibility = false)
256256
@test CS.fix!(com, variables[constr_indices[3]], 5; check_feasibility = false)
257+
CS.changed!(com, constraint, constraint.fct, constraint.set)
257258
# should prune complement
258259
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
259260

test/unit/constraints/strictly_less_than.jl

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
@test sort(CS.values(com.search_space[3])) == -5:5 # 6 not possible
7474

7575
@test CS.fix!(com, com.search_space[constr_indices[3]], 5)
76+
CS.changed!(com, constraint, constraint.fct, constraint.set)
7677
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
7778
@test CS.value(com.search_space[1]) == -1
7879
@test CS.value(com.search_space[2]) == -1
@@ -199,6 +200,7 @@ end
199200
@test sort(CS.values(com.search_space[3])) == -5:6 # -6 not possible
200201

201202
@test CS.fix!(com, com.search_space[constr_indices[3]], -5)
203+
CS.changed!(com, constraint, constraint.fct, constraint.set)
202204
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
203205
@test CS.value(com.search_space[1]) == -5
204206
@test CS.value(com.search_space[2]) == 5

test/unit/constraints/xnor.jl

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ end
180180

181181
constr_indices = constraint.indices
182182
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
183+
CS.changed!(com, constraint, constraint.fct, constraint.set)
183184
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
184185
@test sort(CS.values(m, x[1])) == [0,1,2]
185186
end

test/unit/constraints/xor.jl

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ end
148148
xor_constraint = com.constraints[1].inner_constraint
149149
@test CS.fix!(com, variables[xor_constraint.indices[1]], 0; check_feasibility = false)
150150
@test CS.fix!(com, variables[xor_constraint.indices[2]], 2; check_feasibility = false)
151+
CS.changed!(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
151152
@test CS.is_constraint_violated(com, xor_constraint, xor_constraint.fct, xor_constraint.set)
152153

153154
##################
@@ -180,6 +181,7 @@ end
180181

181182
constr_indices = constraint.indices
182183
@test CS.fix!(com, variables[constraint.indices[3]], 0; check_feasibility = false)
184+
CS.changed!(com, constraint, constraint.fct, constraint.set)
183185
@test CS.prune_constraint!(com, constraint, constraint.fct, constraint.set)
184186
@test sort(CS.values(m, x[1])) == [3,4,5]
185187
end

0 commit comments

Comments
 (0)