OR-Tools  9.2
bop_portfolio.h
Go to the documentation of this file.
1 // Copyright 2010-2021 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_BOP_BOP_PORTFOLIO_H_
15 #define OR_TOOLS_BOP_BOP_PORTFOLIO_H_
16 
17 #include <cstdint>
18 
20 #include "ortools/bop/bop_base.h"
21 #include "ortools/bop/bop_lns.h"
24 #include "ortools/bop/bop_types.h"
25 #include "ortools/glop/lp_solver.h"
27 #include "ortools/sat/sat_solver.h"
29 #include "ortools/util/stats.h"
31 
32 namespace operations_research {
33 namespace bop {
34 
35 DEFINE_INT_TYPE(OptimizerIndex, int);
36 const OptimizerIndex kInvalidOptimizerIndex(-1);
37 
38 // Forward declaration.
39 class OptimizerSelector;
40 
41 // This class implements a portfolio optimizer.
42 // The portfolio currently includes all the following optimizers:
43 // - SAT_CORE_BASED
44 // - SAT_LINEAR_SEARCH
45 // - LINEAR_RELAXATION
46 // - LOCAL_SEARCH
47 // - RANDOM_FIRST_SOLUTION
48 // - RANDOM_CONSTRAINT_LNS
49 // - RANDOM_VARIABLE_LNS
50 // - COMPLETE_LNS
51 // - LP_FIRST_SOLUTION
52 // - OBJECTIVE_FIRST_SOLUTION
53 // - USER_GUIDED_FIRST_SOLUTION
54 // - FEASIBILITY_PUMP_FIRST_SOLUTION
55 // - RANDOM_CONSTRAINT_LNS_GUIDED_BY_LP
56 // - RANDOM_VARIABLE_LNS_GUIDED_BY_LP
57 // - RELATION_GRAPH_LNS
58 // - RELATION_GRAPH_LNS_GUIDED_BY_LP
59 //
60 // At each call of Optimize(), the portfolio optimizer selects the next
61 // optimizer to run and runs it. The selection is auto-adaptative, meaning that
62 // optimizers that succeeded more in the previous calls to Optimizer() are more
63 // likely to be selected.
65  public:
66  PortfolioOptimizer(const ProblemState& problem_state,
68  const BopSolverOptimizerSet& optimizer_set,
69  const std::string& name);
70  ~PortfolioOptimizer() override;
71 
72  bool ShouldBeRun(const ProblemState& problem_state) const override {
73  return true;
74  }
76  const ProblemState& problem_state, LearnedInfo* learned_info,
77  TimeLimit* time_limit) override;
78 
79  private:
80  BopOptimizerBase::Status SynchronizeIfNeeded(
81  const ProblemState& problem_state);
82  void AddOptimizer(const sat::LinearBooleanProblem& problem,
84  const BopOptimizerMethod& optimizer_method);
85  void CreateOptimizers(const sat::LinearBooleanProblem& problem,
87  const BopSolverOptimizerSet& optimizer_set);
88 
89  random_engine_t random_;
90  int64_t state_update_stamp_;
91  BopConstraintTerms objective_terms_;
92  std::unique_ptr<OptimizerSelector> selector_;
94  sat::SatSolver sat_propagator_;
95  BopParameters parameters_;
96  double lower_bound_;
97  double upper_bound_;
98  int number_of_consecutive_failing_optimizers_;
99 };
100 
101 // This class is providing an adaptative selector for optimizers based on
102 // their past successes and deterministic time spent.
104  public:
105  // Note that the list of optimizers is only used to get the names for
106  // debug purposes, the ownership of the optimizers is not transferred.
107  explicit OptimizerSelector(
109 
110  // Selects the next optimizer to run based on the user defined order and
111  // history of success. Returns kInvalidOptimizerIndex if no optimizer is
112  // selectable and runnable (see the functions below).
113  //
114  // The optimizer is selected using the following algorithm (L being the
115  // sorted list of optimizers, and l the position of the last selected
116  // optimizer):
117  // a- If a new solution has been found by optimizer l, select the first
118  // optimizer l' in L, l' >= 0, that can run.
119  // b- If optimizer l didn't find a new solution, select the first
120  // optimizer l', with l' > l, such that its deterministic time spent
121  // since last solution is smaller than the deterministic time spent
122  // by any runnable optimizer in 1..l since last solution.
123  // If no such optimizer is available, go to option a.
124  OptimizerIndex SelectOptimizer();
125 
126  // Updates the internal metrics to decide which optimizer to select.
127  // This method should be called each time the selected optimizer is run.
128  //
129  // The gain corresponds to the reward to assign to the solver; It could for
130  // instance be the difference in cost between the last and the current
131  // solution.
132  //
133  // The time spent corresponds to the time the optimizer spent; To make the
134  // behavior deterministic, it is recommended to use the deterministic time
135  // instead of the elapsed time.
136  //
137  // The optimizers are sorted based on their score each time a new solution is
138  // found.
139  void UpdateScore(int64_t gain, double time_spent);
140 
141  // Marks the given optimizer as not selectable until UpdateScore() is called
142  // with a positive gain. In which case, all optimizer will become selectable
143  // again.
144  void TemporarilyMarkOptimizerAsUnselectable(OptimizerIndex optimizer_index);
145 
146  // Sets whether or not an optimizer is "runnable". Like a non-selectable one,
147  // a non-runnable optimizer will never be returned by SelectOptimizer().
148  //
149  // TODO(user): Maybe we should simply have the notion of selectability here
150  // and let the client handle the logic to decide what optimizer are selectable
151  // or not.
152  void SetOptimizerRunnability(OptimizerIndex optimizer_index, bool runnable);
153 
154  // Returns statistics about the given optimizer.
155  std::string PrintStats(OptimizerIndex optimizer_index) const;
156  int NumCallsForOptimizer(OptimizerIndex optimizer_index) const;
157 
158  // Prints some debug information. Should not be used in production.
159  void DebugPrint() const;
160 
161  private:
162  // Updates internals when a solution has been found using the selected
163  // optimizer.
164  void NewSolutionFound(int64_t gain);
165 
166  // Updates the deterministic time spent by the selected optimizer.
167  void UpdateDeterministicTime(double time_spent);
168 
169  // Sorts optimizers based on their scores.
170  void UpdateOrder();
171 
172  struct RunInfo {
173  RunInfo(OptimizerIndex i, const std::string& n)
174  : optimizer_index(i),
175  name(n),
176  num_successes(0),
177  num_calls(0),
178  total_gain(0),
179  time_spent(0.0),
180  time_spent_since_last_solution(0),
181  runnable(true),
182  selectable(true),
183  score(0.0) {}
184 
185  bool RunnableAndSelectable() const { return runnable && selectable; }
186 
187  OptimizerIndex optimizer_index;
188  std::string name;
189  int num_successes;
190  int num_calls;
191  int64_t total_gain;
192  double time_spent;
193  double time_spent_since_last_solution;
194  bool runnable;
195  bool selectable;
196  double score;
197  };
198 
199  std::vector<RunInfo> run_infos_;
201  int selected_index_;
202 };
203 
204 } // namespace bop
205 } // namespace operations_research
206 #endif // OR_TOOLS_BOP_BOP_PORTFOLIO_H_
void SetOptimizerRunnability(OptimizerIndex optimizer_index, bool runnable)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
ModelSharedTimeLimit * time_limit
PortfolioOptimizer(const ProblemState &problem_state, const BopParameters &parameters, const BopSolverOptimizerSet &optimizer_set, const std::string &name)
int NumCallsForOptimizer(OptimizerIndex optimizer_index) const
const std::string name
const OptimizerIndex kInvalidOptimizerIndex(-1)
std::string PrintStats(OptimizerIndex optimizer_index) const
std::mt19937 random_engine_t
Definition: random_engine.h:23
OptimizerSelector(const absl::StrongVector< OptimizerIndex, BopOptimizerBase * > &optimizers)
void UpdateScore(int64_t gain, double time_spent)
void TemporarilyMarkOptimizerAsUnselectable(OptimizerIndex optimizer_index)
const std::string & name() const
Definition: bop_base.h:49
DEFINE_INT_TYPE(OptimizerIndex, int)
Status Optimize(const BopParameters &parameters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
Collection of objects used to extend the Constraint Solver library.
SatParameters parameters
bool ShouldBeRun(const ProblemState &problem_state) const override
Definition: bop_portfolio.h:72