Google OR-Tools v9.9
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
pseudo_costs.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <cstdint>
18#include <limits>
19#include <tuple>
20#include <vector>
21
22#include "absl/log/check.h"
24#include "ortools/sat/integer.h"
25#include "ortools/sat/model.h"
27#include "ortools/sat/sat_parameters.pb.h"
28#include "ortools/sat/util.h"
30
31namespace operations_research {
32namespace sat {
33
35 : parameters_(*model->GetOrCreate<SatParameters>()),
36 integer_trail_(model->GetOrCreate<IntegerTrail>()),
37 encoder_(model->GetOrCreate<IntegerEncoder>()) {
38 const int num_vars = integer_trail_->NumIntegerVariables().value();
39 pseudo_costs_.resize(num_vars);
40 is_relevant_.resize(num_vars, false);
41 scores_.resize(num_vars, 0.0);
42}
43
45 const std::vector<VariableBoundChange>& bound_changes,
46 const IntegerValue obj_bound_improvement) {
47 DCHECK_GE(obj_bound_improvement, 0);
48 if (obj_bound_improvement == IntegerValue(0)) return;
49
50 const double epsilon = 1e-6;
51 for (const auto [var, lb_change] : bound_changes) {
52 if (lb_change == IntegerValue(0)) continue;
53
54 if (var >= pseudo_costs_.size()) {
55 // Create space for new variable and its negation.
56 const int new_size = std::max(var, NegationOf(var)).value() + 1;
57 is_relevant_.resize(new_size, false);
58 scores_.resize(new_size, 0.0);
59 pseudo_costs_.resize(new_size, IncrementalAverage(0.0));
60 }
61
62 pseudo_costs_[var].AddData(ToDouble(obj_bound_improvement) /
63 ToDouble(lb_change));
64
65 const IntegerVariable positive_var = PositiveVariable(var);
66 const IntegerVariable negative_var = NegationOf(positive_var);
67 const int64_t count = pseudo_costs_[positive_var].NumRecords() +
68 pseudo_costs_[negative_var].NumRecords();
69 if (count >= parameters_.pseudo_cost_reliability_threshold()) {
70 scores_[positive_var] = std::max(GetCost(positive_var), epsilon) *
71 std::max(GetCost(negative_var), epsilon);
72
73 if (!is_relevant_[positive_var]) {
74 is_relevant_[positive_var] = true;
75 relevant_variables_.push_back(positive_var);
76 }
77 }
78 }
79}
80
81// TODO(user): Supports search randomization tolerance.
82// TODO(user): Implement generic class to choose the randomized
83// solution, and supports sub-linear variable selection.
85 IntegerVariable chosen_var = kNoIntegerVariable;
86 double best_score = -std::numeric_limits<double>::infinity();
87
88 // TODO(user): Avoid the O(num_relevant_variable) loop.
89 // In practice since a variable only become relevant after 100 records, this
90 // list might be small compared to the number of variable though.
91 for (const IntegerVariable positive_var : relevant_variables_) {
92 const IntegerValue lb = integer_trail_->LowerBound(positive_var);
93 const IntegerValue ub = integer_trail_->UpperBound(positive_var);
94 if (lb >= ub) continue;
95 if (scores_[positive_var] > best_score) {
96 chosen_var = positive_var;
97 best_score = scores_[positive_var];
98 }
99 }
100
101 // Pick the direction with best pseudo cost.
102 if (chosen_var != kNoIntegerVariable &&
103 GetCost(chosen_var) < GetCost(NegationOf(chosen_var))) {
104 chosen_var = NegationOf(chosen_var);
105 }
106 return chosen_var;
107}
108
109std::vector<PseudoCosts::VariableBoundChange> PseudoCosts::GetBoundChanges(
110 Literal decision) {
111 std::vector<PseudoCosts::VariableBoundChange> bound_changes;
112
113 for (const IntegerLiteral l : encoder_->GetIntegerLiterals(decision)) {
114 PseudoCosts::VariableBoundChange var_bound_change;
115 var_bound_change.var = l.var;
116 var_bound_change.lower_bound_change =
117 l.bound - integer_trail_->LowerBound(l.var);
118 bound_changes.push_back(var_bound_change);
119 }
120
121 // NOTE: We ignore literal associated to var != value.
122 for (const auto [var, value] : encoder_->GetEqualityLiterals(decision)) {
123 {
124 PseudoCosts::VariableBoundChange var_bound_change;
125 var_bound_change.var = var;
126 var_bound_change.lower_bound_change =
127 value - integer_trail_->LowerBound(var);
128 bound_changes.push_back(var_bound_change);
129 }
130
131 // Also do the negation.
132 {
133 PseudoCosts::VariableBoundChange var_bound_change;
134 var_bound_change.var = NegationOf(var);
135 var_bound_change.lower_bound_change =
136 (-value) - integer_trail_->LowerBound(NegationOf(var));
137 bound_changes.push_back(var_bound_change);
138 }
139 }
140
141 return bound_changes;
142}
143
144} // namespace sat
145} // namespace operations_research
void resize(size_type new_size)
Manages incremental averages.
Definition util.h:486
const InlinedIntegerValueVector & GetEqualityLiterals(Literal lit) const
Definition integer.h:592
const InlinedIntegerLiteralVector & GetIntegerLiterals(Literal lit) const
Returns the IntegerLiterals that were associated with the given Literal.
Definition integer.h:583
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
Definition integer.h:1617
IntegerValue UpperBound(IntegerVariable i) const
Definition integer.h:1621
IntegerVariable NumIntegerVariables() const
Definition integer.h:782
IntegerVariable GetBestDecisionVar()
Returns the variable with best reliable pseudo cost that is not fixed.
std::vector< VariableBoundChange > GetBoundChanges(Literal decision)
void UpdateCost(const std::vector< VariableBoundChange > &bound_changes, IntegerValue obj_bound_improvement)
Updates the pseudo costs for the given decision.
double GetCost(IntegerVariable var) const
Returns the pseudo cost of given variable. Currently used for testing only.
int64_t value
IntVar * var
GRBmodel * model
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
Definition integer.cc:51
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
Definition integer.h:193
double ToDouble(IntegerValue value)
Definition integer.h:73
In SWIG mode, we don't want anything besides these top-level includes.