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