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