Skip to content

Commit 03dcebf

Browse files
authored
first version of a bugfix (#172)
* Bugfixes in Indicator constraint with table constraint * all impl functions including `update_best_bound`
1 parent 9cfe01c commit 03dcebf

16 files changed

+442
-142
lines changed

CHANGELOG.md

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

3+
## Unreleased
4+
- Bugfixes in indicator constraint [#170](https://github.com/Wikunia/ConstraintSolver.jl/issues/170)
5+
- Calling finished constraints and other functions for i.e `TableConstraint` as an inner constraint
6+
- Use correct best bound when inactive vs active
7+
38
## v0.2.0 (17th of June 2020)
49
- Bugfix for indicator constraints
510
- support for TableConstraint in Indicator

src/ConstraintSolver.jl

+12-6
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,10 @@ function fulfills_constraints(com::CS.CoM, index, value)
107107
for ci in com.subscription[index]
108108
constraint = com.constraints[ci]
109109
# only call if the function got initialized already
110-
if constraint.std.impl.init
110+
if constraint.std.is_initialized
111111
feasible =
112112
still_feasible(com, constraint, constraint.std.fct, constraint.std.set, value, index)
113-
if !feasible
114-
break
115-
end
113+
!feasible && break
116114
end
117115
end
118116
return feasible
@@ -389,7 +387,7 @@ function reverse_pruning!(com::CS.CoM, backtrack_idx::Int)
389387
constraint = com.constraints[ci]
390388
if constraint.std.impl.single_reverse_pruning
391389
single_reverse_pruning_constraint!(com, constraint, constraint.std.fct, constraint.std.set,
392-
var.idx, var.changes[backtrack_idx])
390+
var, backtrack_idx)
393391
end
394392
end
395393
end
@@ -799,7 +797,7 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting = true)
799797

800798
# there is no better node => return best solution
801799
if length(com.bt_solution_ids) > 0 &&
802-
obj_factor * com.best_bound >= obj_factor * com.best_sol && !find_more_solutions
800+
obj_factor * com.best_bound >= obj_factor * com.best_sol && !find_more_solutions
803801
break
804802
end
805803

@@ -834,6 +832,9 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting = true)
834832
if com.sense != MOI.FEASIBILITY_SENSE
835833
feasible, further_pruning = update_best_bound!(backtrack_obj, com, constraints)
836834
if !feasible
835+
# need to call as some function might have pruned something.
836+
# Just need to be sure that we save the latest states
837+
call_finished_pruning!(com)
837838
com.input[:logs] && log_node_state!(com.logs[last_backtrack_id], backtrack_vec[last_backtrack_id], com.search_space; feasible=false)
838839
com.info.backtrack_reverses += 1
839840
continue
@@ -849,6 +850,8 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting = true)
849850
com.input[:logs] && log_node_state!(com.logs[last_backtrack_id], backtrack_vec[last_backtrack_id], com.search_space; feasible=false)
850851
continue
851852
end
853+
else
854+
call_finished_pruning!(com)
852855
end
853856

854857
if log_table
@@ -1095,6 +1098,8 @@ function solve!(com::CS.CoM, options::SolverOptions)
10951098
com.traverse_strategy = get_traverse_strategy(;options = options)
10961099
com.branch_split = get_branch_split(;options = options)
10971100

1101+
set_impl_functions!(com)
1102+
10981103
if :Info in com.options.logging
10991104
print_info(com)
11001105
end
@@ -1118,6 +1123,7 @@ function solve!(com::CS.CoM, options::SolverOptions)
11181123
if length(added_con_idxs) > 0
11191124
set_in_all_different!(com; constraints=com.constraints[added_con_idxs])
11201125
set_constraint_hashes!(com; constraints=com.constraints[added_con_idxs])
1126+
set_impl_functions!(com; constraints=com.constraints[added_con_idxs])
11211127
!init_constraints!(com; constraints=com.constraints[added_con_idxs]) && return :Infeasible
11221128
end
11231129

src/MOI_wrapper/MOI_wrapper.jl

-4
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,6 @@ function MOI.optimize!(model::Optimizer)
121121
set_pvals!(model)
122122

123123
create_lp_model!(model)
124-
set_update_best_bound!(model.inner)
125-
set_finished_pruning!(model.inner)
126-
set_restore_pruning!(model.inner)
127-
set_reverse_pruning!(model.inner)
128124

129125
status = solve!(model)
130126
set_status!(model, status)

src/MOI_wrapper/constraints.jl

+116-88
Original file line numberDiff line numberDiff line change
@@ -412,119 +412,142 @@ end
412412
function init_constraints!(com::CS.CoM; constraints=com.constraints)
413413
feasible = true
414414
for constraint in constraints
415-
c_type = typeof(constraint)
416-
c_fct_type = typeof(constraint.std.fct)
417-
c_set_type = typeof(constraint.std.set)
418-
if hasmethod(init_constraint!, (CS.CoM, c_type, c_fct_type, c_set_type))
415+
if constraint.std.impl.init
419416
feasible = init_constraint!(com, constraint, constraint.std.fct, constraint.std.set)
420417
!feasible && break
421418
end
422-
constraint.std.impl.init = true
419+
constraint.std.is_initialized = true
423420
end
424421
return feasible
425422
end
426423

424+
"""
425+
set_impl_functions!(com, constraint::Constraint)
426+
427+
Set std.impl.[] for each constraint
428+
"""
429+
function set_impl_functions!(com, constraint::Constraint)
430+
if com.sense != MOI.FEASIBILITY_SENSE
431+
set_impl_update_best_bound!(constraint)
432+
end
433+
set_impl_init!(constraint)
434+
set_impl_finished_pruning!(constraint)
435+
set_impl_restore_pruning!(constraint)
436+
set_impl_reverse_pruning!(constraint)
437+
end
438+
439+
"""
440+
set_impl_functions!(com::CS.CoM)
441+
442+
Set std.impl.[] for each constraint
443+
"""
444+
function set_impl_functions!(com::CS.CoM; constraints=com.constraints)
445+
for constraint in constraints
446+
set_impl_functions!(com, constraint)
447+
end
448+
end
449+
427450
"""
428-
set_update_best_bound!(com::CS.CoM)
429-
Sets `update_best_bound` in each constraint if we have an objective function and:
430-
- the constraint type has a function `update_best_bound_constraint!`
451+
set_impl_init!(constraint::Constraint)
452+
Sets `std.impl.init` if the constraint type has a `init_constraint!` method
431453
"""
432-
function set_update_best_bound!(com::CS.CoM)
433-
if com.sense == MOI.FEASIBILITY_SENSE
434-
return
435-
end
436-
objective_type = typeof(com.objective)
437-
for ci = 1:length(com.constraints)
438-
constraint = com.constraints[ci]
439-
c_type = typeof(constraint)
440-
c_fct_type = typeof(constraint.std.fct)
441-
c_set_type = typeof(constraint.std.set)
442-
if hasmethod(
443-
update_best_bound_constraint!,
444-
(CS.CoM, c_type, c_fct_type, c_set_type, Int, Int, Int),
445-
)
446-
constraint.std.impl.update_best_bound = true
447-
else # just to be sure => set it to false otherwise
448-
constraint.std.impl.update_best_bound = false
449-
end
450-
end
454+
function set_impl_init!(constraint::Constraint)
455+
c_type = typeof(constraint)
456+
c_fct_type = typeof(constraint.std.fct)
457+
c_set_type = typeof(constraint.std.set)
458+
if hasmethod(init_constraint!, (CS.CoM, c_type, c_fct_type, c_set_type))
459+
constraint.std.impl.init = true
460+
end
451461
end
452462

453463
"""
454-
set_reverse_pruning!(com::CS.CoM)
455-
Sets `std.impl.single_reverse_pruning` and `std.impl.reverse_pruning` in each constraint
456-
if `single_reverse_pruning_constraint!`, `reverse_pruning_constraint!` are implemented for the constraint.
464+
set_impl_update_best_bound!(constraint::Constraint)
465+
466+
Sets `update_best_bound` if the constraint type has a `update_best_bound_constraint!` method
457467
"""
458-
function set_reverse_pruning!(com::CS.CoM)
459-
for ci = 1:length(com.constraints)
460-
constraint = com.constraints[ci]
461-
c_type = typeof(constraint)
462-
c_fct_type = typeof(constraint.std.fct)
463-
c_set_type = typeof(constraint.std.set)
464-
if hasmethod(
465-
single_reverse_pruning_constraint!,
466-
(CS.CoM, c_type, c_fct_type, c_set_type, Int, Vector{Tuple{Symbol,Int,Int,Int}}),
467-
)
468-
constraint.std.impl.single_reverse_pruning = true
469-
else # just to be sure => set it to false otherwise
470-
constraint.std.impl.single_reverse_pruning = false
471-
end
472-
473-
if hasmethod(
474-
reverse_pruning_constraint!,
475-
(CS.CoM, c_type, c_fct_type, c_set_type, Int),
476-
)
477-
constraint.std.impl.reverse_pruning = true
478-
else # just to be sure => set it to false otherwise
479-
constraint.std.impl.reverse_pruning = false
480-
end
468+
function set_impl_update_best_bound!(constraint::Constraint)
469+
c_type = typeof(constraint)
470+
c_fct_type = typeof(constraint.std.fct)
471+
c_set_type = typeof(constraint.std.set)
472+
if hasmethod(
473+
update_best_bound_constraint!,
474+
(CS.CoM, c_type, c_fct_type, c_set_type, Int, Int, Int),
475+
)
476+
constraint.std.impl.update_best_bound = true
477+
else # just to be sure => set it to false otherwise
478+
constraint.std.impl.update_best_bound = false
481479
end
482480
end
483481

484482
"""
485-
set_finished_pruning!(com::CS.CoM)
486-
Sets `std.impl.finished_pruning` in each constraint
487-
if `finished_pruning_constraint!` is implemented for the constraint.
483+
set_impl_reverse_pruning!(constraint::Constraint)
484+
Sets `std.impl.single_reverse_pruning` and `std.impl.reverse_pruning`
485+
if `single_reverse_pruning_constraint!`, `reverse_pruning_constraint!` are implemented for `constraint`.
488486
"""
489-
function set_finished_pruning!(com::CS.CoM)
490-
for ci = 1:length(com.constraints)
491-
constraint = com.constraints[ci]
492-
c_type = typeof(constraint)
493-
c_fct_type = typeof(constraint.std.fct)
494-
c_set_type = typeof(constraint.std.set)
495-
if hasmethod(
496-
finished_pruning_constraint!,
497-
(CS.CoM, c_type, c_fct_type, c_set_type)
498-
)
499-
constraint.std.impl.finished_pruning = true
500-
else # just to be sure => set it to false otherwise
501-
constraint.std.impl.finished_pruning = false
502-
end
487+
function set_impl_reverse_pruning!(constraint::Constraint)
488+
c_type = typeof(constraint)
489+
c_fct_type = typeof(constraint.std.fct)
490+
c_set_type = typeof(constraint.std.set)
491+
if hasmethod(
492+
single_reverse_pruning_constraint!,
493+
(CS.CoM, c_type, c_fct_type, c_set_type, CS.Variable, Int),
494+
)
495+
constraint.std.impl.single_reverse_pruning = true
496+
else # just to be sure => set it to false otherwise
497+
constraint.std.impl.single_reverse_pruning = false
498+
end
499+
500+
if hasmethod(
501+
reverse_pruning_constraint!,
502+
(CS.CoM, c_type, c_fct_type, c_set_type, Int),
503+
)
504+
constraint.std.impl.reverse_pruning = true
505+
else # just to be sure => set it to false otherwise
506+
constraint.std.impl.reverse_pruning = false
503507
end
504508
end
505509

506510
"""
507-
set_restore_pruning!(com::CS.CoM)
508-
Sets `std.impl.restore_pruning` in each constraint
509-
if `restore_pruning_constraint!` is implemented for the constraint.
511+
set_impl_finished_pruning!(constraint::Constraint)
512+
Sets `std.impl.finished_pruning` if `finished_pruning_constraint!` is implemented for `constraint`.
510513
"""
511-
function set_restore_pruning!(com::CS.CoM)
512-
for ci = 1:length(com.constraints)
513-
constraint = com.constraints[ci]
514-
c_type = typeof(constraint)
515-
c_fct_type = typeof(constraint.std.fct)
516-
c_set_type = typeof(constraint.std.set)
517-
if hasmethod(
518-
restore_pruning_constraint!,
519-
(CS.CoM, c_type, c_fct_type, c_set_type, Union{Int, Vector{Int}})
520-
)
521-
constraint.std.impl.restore_pruning = true
522-
else # just to be sure => set it to false otherwise
523-
constraint.std.impl.restore_pruning = false
524-
end
525-
end
514+
function set_impl_finished_pruning!(constraint::Constraint)
515+
c_type = typeof(constraint)
516+
c_fct_type = typeof(constraint.std.fct)
517+
c_set_type = typeof(constraint.std.set)
518+
if hasmethod(
519+
finished_pruning_constraint!,
520+
(CS.CoM, c_type, c_fct_type, c_set_type)
521+
)
522+
constraint.std.impl.finished_pruning = true
523+
else # just to be sure => set it to false otherwise
524+
constraint.std.impl.finished_pruning = false
525+
end
526+
end
527+
528+
"""
529+
set_impl_restore_pruning!(constraint::Constraint)
530+
Sets `std.impl.restore_pruning` if `restore_pruning_constraint!` is implemented for the `constraint`.
531+
"""
532+
function set_impl_restore_pruning!(constraint::Constraint)
533+
c_type = typeof(constraint)
534+
c_fct_type = typeof(constraint.std.fct)
535+
c_set_type = typeof(constraint.std.set)
536+
if hasmethod(
537+
restore_pruning_constraint!,
538+
(CS.CoM, c_type, c_fct_type, c_set_type, Union{Int, Vector{Int}})
539+
)
540+
constraint.std.impl.restore_pruning = true
541+
else # just to be sure => set it to false otherwise
542+
constraint.std.impl.restore_pruning = false
543+
end
526544
end
527545

546+
"""
547+
call_finished_pruning!(com)
548+
549+
Call `finished_pruning_constraint!` for every constraint which implements that function as saved in `constraint.std.impl.finished_pruning`
550+
"""
528551
function call_finished_pruning!(com)
529552
for constraint in com.constraints
530553
if constraint.std.impl.finished_pruning
@@ -533,6 +556,11 @@ function call_finished_pruning!(com)
533556
end
534557
end
535558

559+
"""
560+
call_restore_pruning!(com, prune_steps)
561+
562+
Call `call_restore_pruning!` for every constraint which implements that function as saved in `constraint.std.impl.restore_pruning`
563+
"""
536564
function call_restore_pruning!(com, prune_steps)
537565
for constraint in com.constraints
538566
if constraint.std.impl.restore_pruning

src/constraints/all_different.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@ function init_constraint_struct(::Type{AllDifferentSetInternal}, internals)
4242
end
4343

4444
"""
45-
init_constraint!(com::CS.CoM, constraint::AllDifferentConstraint, fct::MOI.VectorOfVariables, set::AllDifferentSetInternal)
45+
init_constraint!(com::CS.CoM, constraint::AllDifferentConstraint, fct::MOI.VectorOfVariables, set::AllDifferentSetInternal;
46+
active = true)
4647
4748
Initialize the AllDifferentConstraint by filling matching_init
4849
"""
4950
function init_constraint!(
5051
com::CS.CoM,
5152
constraint::AllDifferentConstraint,
5253
fct::MOI.VectorOfVariables,
53-
set::AllDifferentSetInternal,
54+
set::AllDifferentSetInternal;
55+
active = true
5456
)
5557
pvals = constraint.std.pvals
5658
nindices = length(constraint.std.indices)

src/constraints/equal.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ function init_constraint!(
4545
com::CS.CoM,
4646
constraint::EqualConstraint,
4747
fct::MOI.VectorOfVariables,
48-
set::CS.EqualSetInternal,
48+
set::CS.EqualSetInternal;
49+
active = true
4950
)
5051
indices = constraint.std.indices
5152
search_space = com.search_space
5253
intersect_vals = Set(intersect(CS.values.(search_space[indices])...))
54+
!active && return true
5355
if isempty(intersect_vals)
5456
return false
5557
end

0 commit comments

Comments
 (0)