27 #include "ortools/sat/sat_parameters.pb.h"
37 : parameters_(*(
model->GetOrCreate<SatParameters>())),
42 const int old_num_variables = activities_.
size();
43 DCHECK_GE(num_variables, activities_.
size());
45 activities_.
resize(num_variables, parameters_.initial_variables_activity());
46 tie_breakers_.
resize(num_variables, 0.0);
48 pq_need_update_for_var_at_trail_index_.
IncreaseSize(num_variables);
50 weighted_sign_.
resize(num_variables, 0.0);
52 has_forced_polarity_.
resize(num_variables,
false);
53 forced_polarity_.
resize(num_variables);
54 has_target_polarity_.
resize(num_variables,
false);
55 target_polarity_.
resize(num_variables);
56 var_polarity_.
resize(num_variables);
58 ResetInitialPolarity(old_num_variables);
62 var_ordering_.
Reserve(num_variables);
63 if (var_ordering_is_initialized_) {
64 for (BooleanVariable
var(old_num_variables);
var < num_variables; ++
var) {
65 var_ordering_.
Add({
var, 0.0, activities_[
var]});
71 if (parameters_.use_erwa_heuristic()) {
73 num_conflicts_stack_.push_back({trail_.
Index(), 1});
76 if (trail_index > target_length_) {
77 target_length_ = trail_index;
78 has_target_polarity_.
assign(has_target_polarity_.
size(),
false);
79 for (
int i = 0; i < trail_index; ++i) {
81 has_target_polarity_[l.
Variable()] =
true;
86 if (trail_index > best_partial_assignment_.size()) {
87 best_partial_assignment_.assign(trail_.
IteratorAt(0),
91 --num_conflicts_until_rephase_;
95 void SatDecisionPolicy::RephaseIfNeeded() {
96 if (parameters_.polarity_rephase_increment() <= 0)
return;
97 if (num_conflicts_until_rephase_ > 0)
return;
99 VLOG(1) <<
"End of polarity phase " << polarity_phase_
100 <<
" target_length: " << target_length_
101 <<
" best_length: " << best_partial_assignment_.size();
104 num_conflicts_until_rephase_ =
105 parameters_.polarity_rephase_increment() * (polarity_phase_ + 1);
109 has_target_polarity_.
assign(has_target_polarity_.
size(),
false);
114 switch (polarity_phase_ % 8) {
116 ResetInitialPolarity(0);
119 UseLongestAssignmentAsInitialPolarity();
122 ResetInitialPolarity(0,
true);
125 UseLongestAssignmentAsInitialPolarity();
128 RandomizeCurrentPolarity();
131 UseLongestAssignmentAsInitialPolarity();
134 FlipCurrentPolarity();
137 UseLongestAssignmentAsInitialPolarity();
143 const int num_variables = activities_.
size();
144 variable_activity_increment_ = 1.0;
145 activities_.
assign(num_variables, parameters_.initial_variables_activity());
146 tie_breakers_.
assign(num_variables, 0.0);
148 var_ordering_.
Clear();
151 num_conflicts_until_rephase_ = parameters_.polarity_rephase_increment();
153 ResetInitialPolarity(0);
154 has_target_polarity_.
assign(num_variables,
false);
155 has_forced_polarity_.
assign(num_variables,
false);
156 best_partial_assignment_.clear();
159 num_conflicts_stack_.clear();
161 var_ordering_is_initialized_ =
false;
164 void SatDecisionPolicy::ResetInitialPolarity(
int from,
bool inverted) {
172 const int num_variables = activities_.
size();
173 for (BooleanVariable
var(from);
var < num_variables; ++
var) {
174 switch (parameters_.initial_polarity()) {
175 case SatParameters::POLARITY_TRUE:
176 var_polarity_[
var] = inverted ? false :
true;
178 case SatParameters::POLARITY_FALSE:
179 var_polarity_[
var] = inverted ? true :
false;
181 case SatParameters::POLARITY_RANDOM:
182 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
184 case SatParameters::POLARITY_WEIGHTED_SIGN:
185 var_polarity_[
var] = weighted_sign_[
var] > 0;
187 case SatParameters::POLARITY_REVERSE_WEIGHTED_SIGN:
188 var_polarity_[
var] = weighted_sign_[
var] < 0;
194 void SatDecisionPolicy::UseLongestAssignmentAsInitialPolarity() {
198 for (
const Literal l : best_partial_assignment_) {
199 var_polarity_[l.Variable()] = l.IsPositive();
201 best_partial_assignment_.
clear();
204 void SatDecisionPolicy::FlipCurrentPolarity() {
205 const int num_variables = var_polarity_.
size();
206 for (BooleanVariable
var;
var < num_variables; ++
var) {
207 var_polarity_[
var] = !var_polarity_[
var];
211 void SatDecisionPolicy::RandomizeCurrentPolarity() {
212 const int num_variables = var_polarity_.
size();
213 for (BooleanVariable
var;
var < num_variables; ++
var) {
214 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
218 void SatDecisionPolicy::InitializeVariableOrdering() {
219 const int num_variables = activities_.
size();
223 var_ordering_.
Clear();
224 tmp_variables_.clear();
225 for (BooleanVariable
var(0);
var < num_variables; ++
var) {
227 if (activities_[
var] > 0.0) {
229 {
var,
static_cast<float>(tie_breakers_[
var]), activities_[
var]});
231 tmp_variables_.push_back(
var);
242 switch (parameters_.preferred_variable_order()) {
243 case SatParameters::IN_ORDER:
245 case SatParameters::IN_REVERSE_ORDER:
246 std::reverse(tmp_variables_.begin(), tmp_variables_.end());
248 case SatParameters::IN_RANDOM_ORDER:
249 std::shuffle(tmp_variables_.begin(), tmp_variables_.end(), *random_);
254 for (
const BooleanVariable
var : tmp_variables_) {
255 var_ordering_.
Add({
var,
static_cast<float>(tie_breakers_[
var]), 0.0});
259 pq_need_update_for_var_at_trail_index_.
ClearAndResize(num_variables);
261 var_ordering_is_initialized_ =
true;
266 if (!parameters_.use_optimization_hints())
return;
270 has_forced_polarity_[
literal.Variable()] =
true;
276 var_ordering_is_initialized_ =
false;
281 std::vector<std::pair<Literal, double>> prefs;
282 for (BooleanVariable
var(0);
var < var_polarity_.
size(); ++
var) {
294 const std::vector<LiteralWithCoeff>& terms,
Coefficient rhs) {
296 const double weight =
static_cast<double>(term.coefficient.value()) /
297 static_cast<double>(rhs.value());
298 weighted_sign_[term.literal.Variable()] +=
304 const std::vector<Literal>& literals) {
305 if (parameters_.use_erwa_heuristic()) {
306 if (num_bumps_.
size() != activities_.
size()) {
313 ++num_bumps_[
literal.Variable()];
318 const double max_activity_value = parameters_.max_variable_activity_value();
320 const BooleanVariable
var =
literal.Variable();
322 if (level == 0)
continue;
323 activities_[
var] += variable_activity_increment_;
325 if (activities_[
var] > max_activity_value) {
326 RescaleVariableActivities(1.0 / max_activity_value);
331 void SatDecisionPolicy::RescaleVariableActivities(
double scaling_factor) {
332 variable_activity_increment_ *= scaling_factor;
333 for (BooleanVariable
var(0);
var < activities_.
size(); ++
var) {
334 activities_[
var] *= scaling_factor;
348 var_ordering_is_initialized_ =
false;
352 variable_activity_increment_ *= 1.0 / parameters_.variable_activity_decay();
357 if (!var_ordering_is_initialized_) {
358 InitializeVariableOrdering();
363 const double ratio = parameters_.random_branches_ratio();
364 auto zero_to_one = [
this]() {
365 return std::uniform_real_distribution<double>()(*random_);
371 std::uniform_int_distribution<int> index_dist(0,
372 var_ordering_.
Size() - 1);
380 DCHECK(!var_ordering_.
IsEmpty());
381 var = var_ordering_.
Top().var;
385 DCHECK(!var_ordering_.
IsEmpty());
386 var = var_ordering_.
Top().var;
391 const double random_ratio = parameters_.random_polarity_ratio();
392 if (random_ratio != 0.0 && zero_to_one() < random_ratio) {
393 return Literal(
var, std::uniform_int_distribution<int>(0, 1)(*random_));
397 if (in_stable_phase_ && has_target_polarity_[
var]) {
403 void SatDecisionPolicy::PqInsertOrUpdate(BooleanVariable
var) {
404 const WeightedVarQueueElement element{
405 var,
static_cast<float>(tie_breakers_[
var]), activities_[
var]};
410 var_ordering_.
Add(element);
416 if (maybe_enable_phase_saving_ && parameters_.use_phase_saving()) {
417 for (
int i = target_trail_index; i < trail_.
Index(); ++i) {
423 DCHECK_LT(target_trail_index, trail_.
Index());
424 if (parameters_.use_erwa_heuristic()) {
425 if (num_bumps_.
size() != activities_.
size()) {
431 const double alpha =
std::max(0.06, 0.4 - 1e-6 * num_conflicts_);
435 int num_conflicts = 0;
436 int next_num_conflicts_update =
437 num_conflicts_stack_.empty() ? -1
438 : num_conflicts_stack_.back().trail_index;
440 int trail_index = trail_.
Index();
441 while (trail_index > target_trail_index) {
442 if (next_num_conflicts_update == trail_index) {
443 num_conflicts += num_conflicts_stack_.back().count;
444 num_conflicts_stack_.pop_back();
445 next_num_conflicts_update =
446 num_conflicts_stack_.empty()
448 : num_conflicts_stack_.back().trail_index;
450 const BooleanVariable
var = trail_[--trail_index].Variable();
454 if (num_conflicts > 0) {
455 const int64_t num_bumps = num_bumps_[
var];
456 double new_rate = 0.0;
459 new_rate =
static_cast<double>(num_bumps) / num_conflicts;
461 activities_[
var] = alpha * new_rate + (1 - alpha) * activities_[
var];
463 if (var_ordering_is_initialized_) PqInsertOrUpdate(
var);
465 if (num_conflicts > 0) {
466 if (!num_conflicts_stack_.empty() &&
467 num_conflicts_stack_.back().trail_index == trail_.
Index()) {
468 num_conflicts_stack_.back().count += num_conflicts;
470 num_conflicts_stack_.push_back({trail_.
Index(), num_conflicts});
474 if (!var_ordering_is_initialized_)
return;
477 int to_update = pq_need_update_for_var_at_trail_index_.
Top();
478 while (to_update >= target_trail_index) {
479 DCHECK_LT(to_update, trail_.
Index());
480 PqInsertOrUpdate(trail_[to_update].Variable());
481 pq_need_update_for_var_at_trail_index_.
ClearTop();
482 to_update = pq_need_update_for_var_at_trail_index_.
Top();
487 if (
DEBUG_MODE && var_ordering_is_initialized_) {
488 for (
int trail_index = trail_.
Index() - 1; trail_index > target_trail_index;
490 const BooleanVariable
var = trail_[trail_index].Variable();
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
void IncreaseSize(int size)
void ClearAndResize(int size)
bool Contains(int index) const
Element QueueElement(int i) const
void Add(Element element)
void IncreasePriority(Element element)
Element GetElement(int index) const
BooleanVariable Variable() const
Class that owns everything related to a particular optimization model.
std::vector< std::pair< Literal, double > > AllPreferences() const
void IncreaseNumVariables(int num_variables)
void ResetDecisionHeuristic()
void UpdateVariableActivityIncrement()
void SetAssignmentPreference(Literal literal, double weight)
void Untrail(int target_trail_index)
void BumpVariableActivities(const std::vector< Literal > &literals)
void BeforeConflict(int trail_index)
void UpdateWeightedSign(const std::vector< LiteralWithCoeff > &terms, Coefficient rhs)
SatDecisionPolicy(Model *model)
const AssignmentInfo & Info(BooleanVariable var) const
const VariablesAssignment & Assignment() const
const std::vector< Literal >::const_iterator IteratorAt(int index) const
bool VariableIsAssigned(BooleanVariable var) const
std::tuple< int64_t, int64_t, const double > Coefficient
Collection of objects used to extend the Constraint Solver library.
#define VLOG(verboselevel)