27#include "ortools/sat/sat_parameters.pb.h"
37 : parameters_(*(
model->GetOrCreate<SatParameters>())),
42 const int old_num_variables = activities_.
size();
45 activities_.
resize(num_variables, parameters_.initial_variables_activity());
46 tie_breakers_.
resize(num_variables, 0.0);
47 num_bumps_.
resize(num_variables, 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_[0], &trail_[trail_index]);
90 --num_conflicts_until_rephase_;
94void SatDecisionPolicy::RephaseIfNeeded() {
95 if (parameters_.polarity_rephase_increment() <= 0)
return;
96 if (num_conflicts_until_rephase_ > 0)
return;
98 VLOG(1) <<
"End of polarity phase " << polarity_phase_
99 <<
" target_length: " << target_length_
100 <<
" best_length: " << best_partial_assignment_.size();
103 num_conflicts_until_rephase_ =
104 parameters_.polarity_rephase_increment() * (polarity_phase_ + 1);
108 has_target_polarity_.
assign(has_target_polarity_.
size(),
false);
113 switch (polarity_phase_ % 8) {
115 ResetInitialPolarity(0);
118 UseLongestAssignmentAsInitialPolarity();
121 ResetInitialPolarity(0,
true);
124 UseLongestAssignmentAsInitialPolarity();
127 RandomizeCurrentPolarity();
130 UseLongestAssignmentAsInitialPolarity();
133 FlipCurrentPolarity();
136 UseLongestAssignmentAsInitialPolarity();
142 const int num_variables = activities_.
size();
143 variable_activity_increment_ = 1.0;
144 activities_.
assign(num_variables, parameters_.initial_variables_activity());
145 tie_breakers_.
assign(num_variables, 0.0);
146 num_bumps_.
assign(num_variables, 0);
147 var_ordering_.
Clear();
150 num_conflicts_until_rephase_ = parameters_.polarity_rephase_increment();
152 ResetInitialPolarity(0);
153 has_target_polarity_.
assign(num_variables,
false);
154 has_forced_polarity_.
assign(num_variables,
false);
155 best_partial_assignment_.clear();
158 num_conflicts_stack_.clear();
160 var_ordering_is_initialized_ =
false;
163void SatDecisionPolicy::ResetInitialPolarity(
int from,
bool inverted) {
171 const int num_variables = activities_.
size();
172 for (BooleanVariable
var(from);
var < num_variables; ++
var) {
173 switch (parameters_.initial_polarity()) {
174 case SatParameters::POLARITY_TRUE:
175 var_polarity_[
var] = inverted ? false :
true;
177 case SatParameters::POLARITY_FALSE:
178 var_polarity_[
var] = inverted ? true :
false;
180 case SatParameters::POLARITY_RANDOM:
181 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
183 case SatParameters::POLARITY_WEIGHTED_SIGN:
184 var_polarity_[
var] = weighted_sign_[
var] > 0;
186 case SatParameters::POLARITY_REVERSE_WEIGHTED_SIGN:
187 var_polarity_[
var] = weighted_sign_[
var] < 0;
193void SatDecisionPolicy::UseLongestAssignmentAsInitialPolarity() {
197 for (
const Literal l : best_partial_assignment_) {
198 var_polarity_[l.Variable()] = l.IsPositive();
200 best_partial_assignment_.
clear();
203void SatDecisionPolicy::FlipCurrentPolarity() {
204 const int num_variables = var_polarity_.
size();
205 for (BooleanVariable
var;
var < num_variables; ++
var) {
206 var_polarity_[
var] = !var_polarity_[
var];
210void SatDecisionPolicy::RandomizeCurrentPolarity() {
211 const int num_variables = var_polarity_.
size();
212 for (BooleanVariable
var;
var < num_variables; ++
var) {
213 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
217void SatDecisionPolicy::InitializeVariableOrdering() {
218 const int num_variables = activities_.
size();
222 var_ordering_.
Clear();
223 tmp_variables_.clear();
224 for (BooleanVariable
var(0);
var < num_variables; ++
var) {
226 if (activities_[
var] > 0.0) {
228 {
var,
static_cast<float>(tie_breakers_[
var]), activities_[
var]});
230 tmp_variables_.push_back(
var);
241 switch (parameters_.preferred_variable_order()) {
242 case SatParameters::IN_ORDER:
244 case SatParameters::IN_REVERSE_ORDER:
245 std::reverse(tmp_variables_.begin(), tmp_variables_.end());
247 case SatParameters::IN_RANDOM_ORDER:
248 std::shuffle(tmp_variables_.begin(), tmp_variables_.end(), *random_);
253 for (
const BooleanVariable
var : tmp_variables_) {
254 var_ordering_.
Add({
var,
static_cast<float>(tie_breakers_[
var]), 0.0});
258 pq_need_update_for_var_at_trail_index_.
ClearAndResize(num_variables);
260 var_ordering_is_initialized_ =
true;
265 if (!parameters_.use_optimization_hints())
return;
269 has_forced_polarity_[
literal.Variable()] =
true;
275 var_ordering_is_initialized_ =
false;
280 std::vector<std::pair<Literal, double>> prefs;
281 for (BooleanVariable
var(0);
var < var_polarity_.
size(); ++
var) {
293 const std::vector<LiteralWithCoeff>& terms,
Coefficient rhs) {
295 const double weight =
static_cast<double>(term.coefficient.value()) /
296 static_cast<double>(rhs.value());
297 weighted_sign_[term.literal.Variable()] +=
303 const std::vector<Literal>& literals) {
304 if (parameters_.use_erwa_heuristic()) {
309 ++num_bumps_[
literal.Variable()];
314 const double max_activity_value = parameters_.max_variable_activity_value();
316 const BooleanVariable
var =
literal.Variable();
318 if (level == 0)
continue;
319 activities_[
var] += variable_activity_increment_;
321 if (activities_[
var] > max_activity_value) {
322 RescaleVariableActivities(1.0 / max_activity_value);
327void SatDecisionPolicy::RescaleVariableActivities(
double scaling_factor) {
328 variable_activity_increment_ *= scaling_factor;
329 for (BooleanVariable
var(0);
var < activities_.
size(); ++
var) {
330 activities_[
var] *= scaling_factor;
344 var_ordering_is_initialized_ =
false;
348 variable_activity_increment_ *= 1.0 / parameters_.variable_activity_decay();
353 if (!var_ordering_is_initialized_) {
354 InitializeVariableOrdering();
359 const double ratio = parameters_.random_branches_ratio();
360 auto zero_to_one = [
this]() {
361 return std::uniform_real_distribution<double>()(*random_);
367 std::uniform_int_distribution<int> index_dist(0,
368 var_ordering_.
Size() - 1);
377 var = var_ordering_.
Top().var;
382 var = var_ordering_.
Top().var;
387 const double random_ratio = parameters_.random_polarity_ratio();
388 if (random_ratio != 0.0 && zero_to_one() < random_ratio) {
389 return Literal(
var, std::uniform_int_distribution<int>(0, 1)(*random_));
393 if (in_stable_phase_ && has_target_polarity_[
var]) {
399void SatDecisionPolicy::PqInsertOrUpdate(BooleanVariable
var) {
400 const WeightedVarQueueElement element{
401 var,
static_cast<float>(tie_breakers_[
var]), activities_[
var]};
406 var_ordering_.
Add(element);
412 if (maybe_enable_phase_saving_ && parameters_.use_phase_saving()) {
413 for (
int i = target_trail_index; i < trail_.
Index(); ++i) {
420 if (parameters_.use_erwa_heuristic()) {
423 const double alpha =
std::max(0.06, 0.4 - 1e-6 * num_conflicts_);
427 int num_conflicts = 0;
428 int next_num_conflicts_update =
429 num_conflicts_stack_.empty() ? -1
430 : num_conflicts_stack_.back().trail_index;
432 int trail_index = trail_.
Index();
433 while (trail_index > target_trail_index) {
434 if (next_num_conflicts_update == trail_index) {
435 num_conflicts += num_conflicts_stack_.back().count;
436 num_conflicts_stack_.pop_back();
437 next_num_conflicts_update =
438 num_conflicts_stack_.empty()
440 : num_conflicts_stack_.back().trail_index;
442 const BooleanVariable
var = trail_[--trail_index].Variable();
446 const int64_t num_bumps = num_bumps_[
var];
447 double new_rate = 0.0;
451 new_rate =
static_cast<double>(num_bumps) / num_conflicts;
453 activities_[
var] = alpha * new_rate + (1 - alpha) * activities_[
var];
454 if (var_ordering_is_initialized_) PqInsertOrUpdate(
var);
456 if (num_conflicts > 0) {
457 if (!num_conflicts_stack_.empty() &&
458 num_conflicts_stack_.back().trail_index == trail_.
Index()) {
459 num_conflicts_stack_.back().count += num_conflicts;
461 num_conflicts_stack_.push_back({trail_.
Index(), num_conflicts});
465 if (!var_ordering_is_initialized_)
return;
468 int to_update = pq_need_update_for_var_at_trail_index_.
Top();
469 while (to_update >= target_trail_index) {
471 PqInsertOrUpdate(trail_[to_update].Variable());
472 pq_need_update_for_var_at_trail_index_.
ClearTop();
473 to_update = pq_need_update_for_var_at_trail_index_.
Top();
478 if (
DEBUG_MODE && var_ordering_is_initialized_) {
479 for (
int trail_index = trail_.
Index() - 1; trail_index > target_trail_index;
481 const BooleanVariable
var = trail_[trail_index].Variable();
#define DCHECK_LE(val1, val2)
#define CHECK_EQ(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
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 VariablesAssignment & Assignment() const
const AssignmentInfo & Info(BooleanVariable var) 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.