22#include "absl/log/check.h"
28#include "ortools/sat/sat_parameters.pb.h"
38 : parameters_(*(
model->GetOrCreate<SatParameters>())),
43 const int old_num_variables = activities_.size();
44 DCHECK_GE(num_variables, activities_.size());
46 activities_.
resize(num_variables, parameters_.initial_variables_activity());
47 tie_breakers_.
resize(num_variables, 0.0);
49 pq_need_update_for_var_at_trail_index_.
IncreaseSize(num_variables);
51 has_forced_polarity_.
resize(num_variables,
false);
52 forced_polarity_.
resize(num_variables);
53 has_target_polarity_.
resize(num_variables,
false);
54 target_polarity_.
resize(num_variables);
55 var_polarity_.
resize(num_variables);
57 ResetInitialPolarity(old_num_variables);
61 var_ordering_.
Reserve(num_variables);
62 if (var_ordering_is_initialized_) {
63 for (BooleanVariable
var(old_num_variables);
var < num_variables; ++
var) {
64 var_ordering_.
Add({
var, 0.0, activities_[
var]});
70 if (parameters_.use_erwa_heuristic()) {
72 num_conflicts_stack_.push_back({trail_.
Index(), 1});
75 if (trail_index > target_length_) {
76 target_length_ = trail_index;
77 has_target_polarity_.
assign(has_target_polarity_.size(),
false);
78 for (
int i = 0;
i < trail_index; ++
i) {
80 has_target_polarity_[l.
Variable()] =
true;
85 if (trail_index > best_partial_assignment_.size()) {
86 best_partial_assignment_.assign(trail_.
IteratorAt(0),
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);
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) {
165 const int num_variables = activities_.size();
166 for (BooleanVariable
var(from);
var < num_variables; ++
var) {
167 switch (parameters_.initial_polarity()) {
168 case SatParameters::POLARITY_TRUE:
169 var_polarity_[
var] = inverted ? false :
true;
171 case SatParameters::POLARITY_FALSE:
172 var_polarity_[
var] = inverted ? true :
false;
174 case SatParameters::POLARITY_RANDOM:
175 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
181void SatDecisionPolicy::UseLongestAssignmentAsInitialPolarity() {
185 for (
const Literal l : best_partial_assignment_) {
186 var_polarity_[l.Variable()] = l.IsPositive();
188 best_partial_assignment_.clear();
191void SatDecisionPolicy::FlipCurrentPolarity() {
192 const int num_variables = var_polarity_.size();
193 for (BooleanVariable
var;
var < num_variables; ++
var) {
194 var_polarity_[
var] = !var_polarity_[
var];
198void SatDecisionPolicy::RandomizeCurrentPolarity() {
199 const int num_variables = var_polarity_.size();
200 for (BooleanVariable
var;
var < num_variables; ++
var) {
201 var_polarity_[
var] = std::uniform_int_distribution<int>(0, 1)(*random_);
205void SatDecisionPolicy::InitializeVariableOrdering() {
206 const int num_variables = activities_.size();
210 var_ordering_.
Clear();
211 tmp_variables_.clear();
212 for (BooleanVariable
var(0);
var < num_variables; ++
var) {
214 if (activities_[
var] > 0.0) {
215 var_ordering_.
Add({
var, tie_breakers_[
var], activities_[
var]});
217 tmp_variables_.push_back(
var);
228 switch (parameters_.preferred_variable_order()) {
229 case SatParameters::IN_ORDER:
231 case SatParameters::IN_REVERSE_ORDER:
232 std::reverse(tmp_variables_.begin(), tmp_variables_.end());
234 case SatParameters::IN_RANDOM_ORDER:
235 std::shuffle(tmp_variables_.begin(), tmp_variables_.end(), *random_);
240 for (
const BooleanVariable
var : tmp_variables_) {
241 var_ordering_.
Add({
var, tie_breakers_[
var], 0.0});
245 pq_need_update_for_var_at_trail_index_.
ClearAndResize(num_variables);
247 var_ordering_is_initialized_ =
true;
251 if (!parameters_.use_optimization_hints())
return;
255 has_forced_polarity_[
literal.Variable()] =
true;
261 var_ordering_is_initialized_ =
false;
266 std::vector<std::pair<Literal, float>> prefs;
267 for (BooleanVariable
var(0);
var < var_polarity_.size(); ++
var) {
279 absl::Span<const Literal> literals) {
280 if (parameters_.use_erwa_heuristic()) {
281 if (num_bumps_.size() != activities_.size()) {
282 num_bumps_.
resize(activities_.size(), 0);
288 ++num_bumps_[
literal.Variable()];
293 const double max_activity_value = parameters_.max_variable_activity_value();
295 const BooleanVariable
var =
literal.Variable();
297 if (level == 0)
continue;
298 activities_[
var] += variable_activity_increment_;
300 if (activities_[
var] > max_activity_value) {
301 RescaleVariableActivities(1.0 / max_activity_value);
306void SatDecisionPolicy::RescaleVariableActivities(
double scaling_factor) {
307 variable_activity_increment_ *= scaling_factor;
308 for (BooleanVariable
var(0);
var < activities_.size(); ++
var) {
309 activities_[
var] *= scaling_factor;
323 var_ordering_is_initialized_ =
false;
327 variable_activity_increment_ *= 1.0 / parameters_.variable_activity_decay();
332 if (!var_ordering_is_initialized_) {
333 InitializeVariableOrdering();
338 const double ratio = parameters_.random_branches_ratio();
339 auto zero_to_one = [
this]() {
340 return std::uniform_real_distribution<double>()(*random_);
346 std::uniform_int_distribution<int> index_dist(0,
347 var_ordering_.
Size() - 1);
355 DCHECK(!var_ordering_.
IsEmpty());
356 var = var_ordering_.
Top().var;
360 DCHECK(!var_ordering_.
IsEmpty());
361 var = var_ordering_.
Top().var;
366 const double random_ratio = parameters_.random_polarity_ratio();
367 if (random_ratio != 0.0 && zero_to_one() < random_ratio) {
368 return Literal(
var, std::uniform_int_distribution<int>(0, 1)(*random_));
372 if (in_stable_phase_ && has_target_polarity_[
var]) {
378void SatDecisionPolicy::PqInsertOrUpdate(BooleanVariable
var) {
379 const WeightedVarQueueElement element{
var, tie_breakers_[
var],
385 var_ordering_.
Add(element);
391 if (maybe_enable_phase_saving_ && parameters_.use_phase_saving()) {
392 for (
int i = target_trail_index;
i < trail_.
Index(); ++
i) {
398 DCHECK_LT(target_trail_index, trail_.
Index());
399 if (parameters_.use_erwa_heuristic()) {
400 if (num_bumps_.size() != activities_.size()) {
401 num_bumps_.
resize(activities_.size(), 0);
406 const double alpha = std::max(0.06, 0.4 - 1e-6 * num_conflicts_);
410 int num_conflicts = 0;
411 int next_num_conflicts_update =
412 num_conflicts_stack_.empty() ? -1
413 : num_conflicts_stack_.back().trail_index;
415 int trail_index = trail_.
Index();
416 while (trail_index > target_trail_index) {
417 if (next_num_conflicts_update == trail_index) {
418 num_conflicts += num_conflicts_stack_.back().count;
419 num_conflicts_stack_.pop_back();
420 next_num_conflicts_update =
421 num_conflicts_stack_.empty()
423 : num_conflicts_stack_.back().trail_index;
425 const BooleanVariable
var = trail_[--trail_index].Variable();
429 if (num_conflicts > 0) {
430 const int64_t num_bumps = num_bumps_[
var];
431 double new_rate = 0.0;
434 new_rate =
static_cast<double>(num_bumps) / num_conflicts;
436 activities_[
var] = alpha * new_rate + (1 - alpha) * activities_[
var];
438 if (var_ordering_is_initialized_) PqInsertOrUpdate(
var);
440 if (num_conflicts > 0) {
441 if (!num_conflicts_stack_.empty() &&
442 num_conflicts_stack_.back().trail_index == trail_.
Index()) {
443 num_conflicts_stack_.back().count += num_conflicts;
445 num_conflicts_stack_.push_back({trail_.
Index(), num_conflicts});
449 if (!var_ordering_is_initialized_)
return;
452 int to_update = pq_need_update_for_var_at_trail_index_.
Top();
453 while (to_update >= target_trail_index) {
454 DCHECK_LT(to_update, trail_.
Index());
455 PqInsertOrUpdate(trail_[to_update].Variable());
456 pq_need_update_for_var_at_trail_index_.
ClearTop();
457 to_update = pq_need_update_for_var_at_trail_index_.
Top();
462 if (
DEBUG_MODE && var_ordering_is_initialized_) {
463 for (
int trail_index = trail_.
Index() - 1; trail_index > target_trail_index;
465 const BooleanVariable
var = trail_[trail_index].Variable();
int Top() const
Returns the position of the highest bit set in O(1) or -1 if no bit is set.
void ClearAndResize(int size)
void ClearTop()
Clears the Top() bit and recomputes the position of the next Top().
void IncreaseSize(int size)
void SetAllBefore(int i)
Sets all the bits from 0 up to i-1 to 1.
void Add(Element element)
Element QueueElement(int i) const
void IncreasePriority(Element element)
Optimized version of ChangePriority() when we know the direction.
int Size() const
Returns the number of elements currently present.
Element GetElement(int index) const
Returns the element with given index.
bool Contains(int index) const
Returns true if the element with given index is currently in the queue.
BooleanVariable Variable() const
void BumpVariableActivities(absl::Span< const Literal > literals)
std::vector< std::pair< Literal, float > > AllPreferences() const
Returns the vector of the current assignment preferences.
void SetAssignmentPreference(Literal literal, float weight)
void Untrail(int target_trail_index)
Called on Untrail() so that we can update the set of possible decisions.
void IncreaseNumVariables(int num_variables)
void ResetDecisionHeuristic()
SatDecisionPolicy(Model *model)
void UpdateVariableActivityIncrement()
void BeforeConflict(int trail_index)
std::vector< Literal >::const_iterator IteratorAt(int index) const
const AssignmentInfo & Info(BooleanVariable var) const
const VariablesAssignment & Assignment() const
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
In SWIG mode, we don't want anything besides these top-level includes.
int32_t trail_index
The index of this assignment in the trail.