@@ -83,26 +83,60 @@ struct NotEqualSet{T} <: MOI.AbstractScalarSet
83
83
value :: T
84
84
end
85
85
86
- mutable struct LinearVariables
86
+ mutable struct LinearCombination{T <: Real }
87
87
indices :: Vector{Int}
88
- coeffs :: Vector{Int }
88
+ coeffs :: Vector{T }
89
89
end
90
90
91
- mutable struct LinearConstraint <: Constraint
91
+ mutable struct LinearConstraint{T <: Real } <: Constraint
92
92
idx :: Int
93
93
fct :: Function
94
94
indices :: Vector{Int}
95
95
pvals :: Vector{Int}
96
- coeffs :: Vector{Int }
96
+ coeffs :: Vector{T }
97
97
operator :: Symbol
98
- rhs :: Int
98
+ rhs :: T
99
99
in_all_different :: Bool
100
- mins :: Vector{Int }
101
- maxs :: Vector{Int }
102
- pre_mins :: Vector{Int }
103
- pre_maxs :: Vector{Int }
100
+ mins :: Vector{T }
101
+ maxs :: Vector{T }
102
+ pre_mins :: Vector{T }
103
+ pre_maxs :: Vector{T }
104
104
hash :: UInt64
105
- LinearConstraint () = new ()
105
+ end
106
+
107
+ function LinearConstraint (fct:: Function , operator:: Symbol , indices:: Vector{Int} , coeffs:: Vector{T} , rhs:: Real ) where T <: Real
108
+ # get common type for rhs and coeffs
109
+ promote_T = promote_type (typeof (rhs), eltype (coeffs))
110
+ if promote_T != eltype (coeffs)
111
+ coeffs = convert .(promote_T, coeffs)
112
+ end
113
+ if promote_T != typeof (rhs)
114
+ rhs = convert (promote_T, rhs)
115
+ end
116
+ maxs = zeros (promote_T, length (indices))
117
+ mins = zeros (promote_T, length (indices))
118
+ pre_maxs = zeros (promote_T, length (indices))
119
+ pre_mins = zeros (promote_T, length (indices))
120
+ # this can be changed later in `set_in_all_different!` but needs to be initialized with false
121
+ in_all_different = false
122
+ pvals = Int[]
123
+
124
+ lc = LinearConstraint (
125
+ 0 , # idx will be filled later
126
+ fct,
127
+ indices,
128
+ pvals,
129
+ coeffs,
130
+ operator,
131
+ rhs,
132
+ in_all_different,
133
+ mins,
134
+ maxs,
135
+ pre_mins,
136
+ pre_maxs,
137
+ zero (UInt64)
138
+ )
139
+ return lc
106
140
end
107
141
108
142
mutable struct BacktrackObj
@@ -147,10 +181,12 @@ mutable struct ConstraintSolverModel
147
181
info :: CSInfo
148
182
input :: Dict{Symbol,Any}
149
183
logs :: Vector{TreeLogNode}
184
+ options :: SolverOptions
150
185
end
151
186
152
187
const CoM = ConstraintSolverModel
153
188
189
+ include (" util.jl" )
154
190
include (" MOI_wrapper/MOI_wrapper.jl" )
155
191
include (" printing.jl" )
156
192
include (" logs.jl" )
@@ -185,7 +221,8 @@ function ConstraintSolverModel()
185
221
Vector {Int} (), # solutions
186
222
CSInfo (0 , false , 0 , 0 , 0 ), # info
187
223
Dict {Symbol,Any} (), # input
188
- Vector {TreeLogNode} () # logs
224
+ Vector {TreeLogNode} (), # logs
225
+ SolverOptions () # options
189
226
)
190
227
end
191
228
@@ -629,9 +666,38 @@ function update_best_bound!(backtrack_obj::BacktrackObj, com::CS.CoM, constraint
629
666
if backtrack_obj. best_bound != new_bb
630
667
further_pruning = false
631
668
end
669
+ if backtrack_obj. best_bound == com. best_bound
670
+ backtrack_obj. best_bound = new_bb
671
+ update_best_bound! (com)
672
+ else
673
+ backtrack_obj. best_bound = new_bb
674
+ end
632
675
return true , further_pruning
633
676
end
634
677
678
+ function update_best_bound! (com:: CS.CoM )
679
+ if com. sense == MOI. MIN_SENSE
680
+ max_val = typemax (Int64)
681
+ com. best_bound = minimum ([bo. status == :Open ? bo. best_bound : max_val for bo in com. backtrack_vec])
682
+ elseif com. sense == MOI. MAX_SENSE
683
+ min_val = typemin (Int64)
684
+ com. best_bound = maximum ([bo. status == :Open ? bo. best_bound : min_val for bo in com. backtrack_vec])
685
+ else
686
+ com. best_bound = 0
687
+ end
688
+ end
689
+
690
+ function set_state_to_best_sol! (com:: CS.CoM , last_backtrack_id:: Int )
691
+ obj_factor = com. sense == MOI. MIN_SENSE ? 1 : - 1
692
+ backtrack_vec = com. backtrack_vec
693
+ # find one of the best solutions
694
+ sol, sol_id = findmin ([backtrack_vec[sol_id]. best_bound* obj_factor for sol_id in com. solutions])
695
+ backtrack_id = com. solutions[sol_id]
696
+ checkout_from_to! (com, last_backtrack_id, backtrack_id)
697
+ # prune the last step as checkout_from_to! excludes the to part
698
+ prune! (com, [backtrack_id])
699
+ end
700
+
635
701
"""
636
702
backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
637
703
@@ -731,15 +797,7 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
731
797
if l <= 0 || l > length (backtrack_vec)
732
798
break
733
799
end
734
- if com. sense == MOI. MIN_SENSE
735
- max_val = typemax (Int64)
736
- com. best_bound = minimum ([bo. status == :Open ? bo. best_bound : max_val for bo in backtrack_vec])
737
- elseif com. sense == MOI. MAX_SENSE
738
- min_val = typemin (Int64)
739
- com. best_bound = maximum ([bo. status == :Open ? bo. best_bound : min_val for bo in backtrack_vec])
740
- else
741
- com. best_bound = 0
742
- end
800
+ update_best_bound! (com)
743
801
744
802
ind = backtrack_obj. variable_idx
745
803
@@ -782,7 +840,6 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
782
840
# first update the best bound (only constraints which have an index in the objective function)
783
841
if com. sense != MOI. FEASIBILITY_SENSE
784
842
feasible, further_pruning = update_best_bound! (backtrack_obj, com, constraints)
785
-
786
843
if ! feasible
787
844
com. info. backtrack_reverses += 1
788
845
continue
@@ -792,7 +849,7 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
792
849
if further_pruning
793
850
# prune completely start with all that changed by the fix or by updating best bound
794
851
feasible = prune! (com)
795
-
852
+
796
853
if ! feasible
797
854
com. info. backtrack_reverses += 1
798
855
continue
@@ -804,35 +861,36 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
804
861
# no index found => solution found
805
862
if ! found
806
863
new_sol = get_best_bound (com)
807
- if length (com. solutions) == 0
864
+ if length (com. solutions) == 0 || obj_factor* new_sol <= obj_factor* com. best_sol
865
+ push! (com. solutions, backtrack_obj. idx)
808
866
com. best_sol = new_sol
809
- elseif obj_factor* new_sol < obj_factor* com. best_sol
810
- com. best_sol = new_sol
811
- end
812
- push! (com. solutions, backtrack_obj. idx)
813
- if com. best_sol == com. best_bound
814
- return :Solved
815
- else
867
+ if com. best_sol == com. best_bound
868
+ return :Solved
869
+ end
816
870
# set all nodes to :Worse if they can't achieve a better solution
817
871
for bo in backtrack_vec
818
872
if bo. status == :Open && obj_factor* bo. best_bound >= com. best_sol
819
873
bo. status = :Worse
820
874
end
821
875
end
822
876
continue
877
+ else
878
+ if com. best_sol == com. best_bound
879
+ set_state_to_best_sol! (com, last_backtrack_id)
880
+ return :Solved
881
+ end
882
+ continue
823
883
end
824
884
end
825
885
826
886
if com. info. backtrack_fixes > max_bt_steps
827
887
return :NotSolved
828
888
end
829
889
830
-
831
-
832
890
if com. input[:logs ]
833
891
com. logs[backtrack_obj. idx] = log_one_node (com, length (com. search_space), backtrack_obj. idx, step_nr)
834
892
end
835
-
893
+
836
894
pvals = reverse! (values (com. search_space[ind]))
837
895
last_backtrack_obj = backtrack_vec[last_backtrack_id]
838
896
for pval in pvals
@@ -861,12 +919,7 @@ function backtrack!(com::CS.CoM, max_bt_steps; sorting=true)
861
919
end
862
920
end
863
921
if length (com. solutions) > 0
864
- # find one of the best solutions
865
- sol, sol_id = findmin ([backtrack_vec[sol_id]. best_bound* obj_factor for sol_id in com. solutions])
866
- backtrack_id = com. solutions[sol_id]
867
- checkout_from_to! (com, last_backtrack_id, backtrack_id)
868
- # prune the last step as checkout_from_to! excludes the to part
869
- prune! (com, [backtrack_id])
922
+ set_state_to_best_sol! (com, last_backtrack_id)
870
923
return :Solved
871
924
end
872
925
return :Infeasible
@@ -997,6 +1050,7 @@ function solve!(com::CS.CoM, options::SolverOptions)
997
1050
return :Solved
998
1051
end
999
1052
1053
+ com. options = options
1000
1054
backtrack = options. backtrack
1001
1055
max_bt_steps = options. max_bt_steps
1002
1056
backtrack_sorting = options. backtrack_sorting
0 commit comments