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