OR-Tools  8.1
sat/util.h
Go to the documentation of this file.
1 // Copyright 2010-2018 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 
14 #ifndef OR_TOOLS_SAT_UTIL_H_
15 #define OR_TOOLS_SAT_UTIL_H_
16 
17 #include <deque>
18 
19 #include "absl/random/random.h"
20 #include "ortools/sat/model.h"
21 #include "ortools/sat/sat_base.h"
24 
25 #if !defined(__PORTABLE_PLATFORM__)
26 #include "google/protobuf/descriptor.h"
27 #endif // __PORTABLE_PLATFORM__
28 
29 namespace operations_research {
30 namespace sat {
31 
32 // The model "singleton" random engine used in the solver.
34  // We seed the strategy at creation only. This should be enough for our use
35  // case since the SatParameters is set first before the solver is created. We
36  // also never really need to change the seed afterwards, it is just used to
37  // diversify solves with identical parameters on different Model objects.
39  seed(model->GetOrCreate<SatParameters>()->random_seed());
40  }
41 };
42 
43 // Randomizes the decision heuristic of the given SatParameters.
44 template <typename URBG>
45 void RandomizeDecisionHeuristic(URBG* random, SatParameters* parameters);
46 
47 // Context: this function is not really generic, but required to be unit-tested.
48 // It is used in a clause minimization algorithm when we try to detect if any of
49 // the clause literals can be propagated by a subset of the other literal being
50 // false. For that, we want to enqueue in the solver all the subset of size n-1.
51 //
52 // This moves one of the unprocessed literal from literals to the last position.
53 // The function tries to do that while preserving the longest possible prefix of
54 // literals "amortized" through the calls assuming that we want to move each
55 // literal to the last position once.
56 //
57 // For a vector of size n, if we want to call this n times so that each literal
58 // is last at least once, the sum of the size of the changed suffixes will be
59 // O(n log n). If we were to use a simpler algorithm (like moving the last
60 // unprocessed literal to the last position), this sum would be O(n^2).
61 //
62 // Returns the size of the common prefix of literals before and after the move,
63 // or -1 if all the literals are already processed. The argument
64 // relevant_prefix_size is used as a hint when keeping more that this prefix
65 // size do not matter. The returned value will always be lower or equal to
66 // relevant_prefix_size.
67 int MoveOneUnprocessedLiteralLast(const std::set<LiteralIndex>& processed,
68  int relevant_prefix_size,
69  std::vector<Literal>* literals);
70 
71 // ============================================================================
72 // Implementation.
73 // ============================================================================
74 
75 template <typename URBG>
76 inline void RandomizeDecisionHeuristic(URBG* random,
77  SatParameters* parameters) {
78 #if !defined(__PORTABLE_PLATFORM__)
79  // Random preferred variable order.
80  const google::protobuf::EnumDescriptor* order_d =
81  SatParameters::VariableOrder_descriptor();
82  parameters->set_preferred_variable_order(
83  static_cast<SatParameters::VariableOrder>(
84  order_d->value(absl::Uniform(*random, 0, order_d->value_count()))
85  ->number()));
86 
87  // Random polarity initial value.
88  const google::protobuf::EnumDescriptor* polarity_d =
89  SatParameters::Polarity_descriptor();
90  parameters->set_initial_polarity(static_cast<SatParameters::Polarity>(
91  polarity_d->value(absl::Uniform(*random, 0, polarity_d->value_count()))
92  ->number()));
93 #endif // __PORTABLE_PLATFORM__
94  // Other random parameters.
95  parameters->set_use_phase_saving(absl::Bernoulli(*random, 0.5));
96  parameters->set_random_polarity_ratio(absl::Bernoulli(*random, 0.5) ? 0.01
97  : 0.0);
98  parameters->set_random_branches_ratio(absl::Bernoulli(*random, 0.5) ? 0.01
99  : 0.0);
100 }
101 
102 // Manages incremental averages.
104  public:
105  // Initializes the average with 'initial_average' and number of records to 0.
106  explicit IncrementalAverage(double initial_average)
107  : average_(initial_average) {}
109 
110  // Sets the number of records to 0 and average to 'reset_value'.
111  void Reset(double reset_value);
112 
113  double CurrentAverage() const { return average_; }
114  int64 NumRecords() const { return num_records_; }
115 
116  void AddData(double new_record);
117 
118  private:
119  double average_ = 0.0;
120  int64 num_records_ = 0;
121 };
122 
123 // Manages exponential moving averages defined as
124 // new_average = decaying_factor * old_average
125 // + (1 - decaying_factor) * new_record.
126 // where 0 < decaying_factor < 1.
128  public:
129  explicit ExponentialMovingAverage(double decaying_factor)
130  : decaying_factor_(decaying_factor) {
131  DCHECK_GE(decaying_factor, 0.0);
132  DCHECK_LE(decaying_factor, 1.0);
133  }
134 
135  // Returns exponential moving average for all the added data so far.
136  double CurrentAverage() const { return average_; }
137 
138  // Returns the total number of added records so far.
139  int64 NumRecords() const { return num_records_; }
140 
141  void AddData(double new_record);
142 
143  private:
144  double average_ = 0.0;
145  int64 num_records_ = 0;
146  const double decaying_factor_;
147 };
148 
149 // Utility to calculate percentile (First variant) for limited number of
150 // records. Reference: https://en.wikipedia.org/wiki/Percentile
151 //
152 // After the vector is sorted, we assume that the element with index i
153 // correspond to the percentile 100*(i+0.5)/size. For percentiles before the
154 // first element (resp. after the last one) we return the first element (resp.
155 // the last). And otherwise we do a linear interpolation between the two element
156 // around the asked percentile.
157 class Percentile {
158  public:
159  explicit Percentile(int record_limit) : record_limit_(record_limit) {}
160 
161  void AddRecord(double record);
162 
163  // Returns number of stored records.
164  int64 NumRecords() const { return records_.size(); }
165 
166  // Note that this is not fast and runs in O(n log n) for n records.
167  double GetPercentile(double percent);
168 
169  private:
170  std::deque<double> records_;
171  const int record_limit_;
172 };
173 
174 // This method tries to compress a list of tuples by merging complementary
175 // tuples, that is a set of tuples that only differ on one variable, and that
176 // cover the domain of the variable. In that case, it will keep only one tuple,
177 // and replace the value for variable by any_value, the equivalent of '*' in
178 // regexps.
179 //
180 // This method is exposed for testing purposes.
181 void CompressTuples(absl::Span<const int64> domain_sizes, int64 any_value,
182  std::vector<std::vector<int64>>* tuples);
183 
184 } // namespace sat
185 } // namespace operations_research
186 
187 #endif // OR_TOOLS_SAT_UTIL_H_
operations_research::sat::MoveOneUnprocessedLiteralLast
int MoveOneUnprocessedLiteralLast(const std::set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
Definition: sat/util.cc:24
operations_research::sat::Percentile::GetPercentile
double GetPercentile(double percent)
Definition: sat/util.cc:87
operations_research::sat::Percentile
Definition: sat/util.h:157
operations_research::sat::ModelRandomGenerator
Definition: sat/util.h:33
operations_research::sat::IncrementalAverage::NumRecords
int64 NumRecords() const
Definition: sat/util.h:114
model.h
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::IncrementalAverage::CurrentAverage
double CurrentAverage() const
Definition: sat/util.h:113
random_engine.h
sat_base.h
operations_research::sat::ExponentialMovingAverage
Definition: sat/util.h:127
operations_research::sat::ExponentialMovingAverage::AddData
void AddData(double new_record)
Definition: sat/util.cc:73
operations_research::sat::IncrementalAverage
Definition: sat/util.h:103
operations_research::sat::ExponentialMovingAverage::CurrentAverage
double CurrentAverage() const
Definition: sat/util.h:136
sat_parameters.pb.h
operations_research::sat::ExponentialMovingAverage::ExponentialMovingAverage
ExponentialMovingAverage(double decaying_factor)
Definition: sat/util.h:129
operations_research::sat::ModelRandomGenerator::ModelRandomGenerator
ModelRandomGenerator(Model *model)
Definition: sat/util.h:38
operations_research::sat::IncrementalAverage::AddData
void AddData(double new_record)
Definition: sat/util.cc:68
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
operations_research::sat::Percentile::Percentile
Percentile(int record_limit)
Definition: sat/util.h:159
operations_research::sat::IncrementalAverage::Reset
void Reset(double reset_value)
Definition: sat/util.cc:63
DCHECK_GE
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:889
model
GRBmodel * model
Definition: gurobi_interface.cc:269
operations_research::sat::IncrementalAverage::IncrementalAverage
IncrementalAverage()
Definition: sat/util.h:108
operations_research::sat::CompressTuples
void CompressTuples(absl::Span< const int64 > domain_sizes, int64 any_value, std::vector< std::vector< int64 >> *tuples)
Definition: sat/util.cc:112
operations_research::sat::Percentile::AddRecord
void AddRecord(double record)
Definition: sat/util.cc:80
DCHECK_LE
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:887
operations_research::sat::RandomizeDecisionHeuristic
void RandomizeDecisionHeuristic(URBG *random, SatParameters *parameters)
Definition: sat/util.h:76
operations_research::sat::ExponentialMovingAverage::NumRecords
int64 NumRecords() const
Definition: sat/util.h:139
parameters
SatParameters parameters
Definition: cp_model_fz_solver.cc:108
operations_research::sat::Percentile::NumRecords
int64 NumRecords() const
Definition: sat/util.h:164
operations_research::sat::IncrementalAverage::IncrementalAverage
IncrementalAverage(double initial_average)
Definition: sat/util.h:106
operations_research::random_engine_t
std::mt19937 random_engine_t
Definition: random_engine.h:23