Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
bop_portfolio.h
Go to the documentation of this file.
1// Copyright 2010-2024 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"
25#include "ortools/bop/bop_lns.h"
26#include "ortools/bop/bop_parameters.pb.h"
30#include "ortools/sat/boolean_problem.pb.h"
33#include "ortools/util/stats.h"
36
37namespace operations_research {
38namespace bop {
39
41const OptimizerIndex kInvalidOptimizerIndex(-1);
42
43// Forward declaration.
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 absl::string_view 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 optimizers);
115
116 // Selects the next optimizer to run based on the user defined order and
117 // history of success. Returns kInvalidOptimizerIndex if no optimizer is
118 // selectable and runnable (see the functions below).
119 //
120 // The optimizer is selected using the following algorithm (L being the
121 // sorted list of optimizers, and l the position of the last selected
122 // optimizer):
123 // a- If a new solution has been found by optimizer l, select the first
124 // optimizer l' in L, l' >= 0, that can run.
125 // b- If optimizer l didn't find a new solution, select the first
126 // optimizer l', with l' > l, such that its deterministic time spent
127 // since last solution is smaller than the deterministic time spent
128 // by any runnable optimizer in 1..l since last solution.
129 // If no such optimizer is available, go to option a.
130 OptimizerIndex SelectOptimizer();
131
132 // Updates the internal metrics to decide which optimizer to select.
133 // This method should be called each time the selected optimizer is run.
134 //
135 // The gain corresponds to the reward to assign to the solver; It could for
136 // instance be the difference in cost between the last and the current
137 // solution.
138 //
139 // The time spent corresponds to the time the optimizer spent; To make the
140 // behavior deterministic, it is recommended to use the deterministic time
141 // instead of the elapsed time.
142 //
143 // The optimizers are sorted based on their score each time a new solution is
144 // found.
145 void UpdateScore(int64_t gain, double time_spent);
146
147 // Marks the given optimizer as not selectable until UpdateScore() is called
148 // with a positive gain. In which case, all optimizer will become selectable
149 // again.
150 void TemporarilyMarkOptimizerAsUnselectable(OptimizerIndex optimizer_index);
151
152 // Sets whether or not an optimizer is "runnable". Like a non-selectable one,
153 // a non-runnable optimizer will never be returned by SelectOptimizer().
154 //
155 // TODO(user): Maybe we should simply have the notion of selectability here
156 // and let the client handle the logic to decide what optimizer are selectable
157 // or not.
158 void SetOptimizerRunnability(OptimizerIndex optimizer_index, bool runnable);
159
160 // Returns statistics about the given optimizer.
161 std::string PrintStats(OptimizerIndex optimizer_index) const;
162 int NumCallsForOptimizer(OptimizerIndex optimizer_index) const;
163
164 // Prints some debug information. Should not be used in production.
165 void DebugPrint() const;
166
167 private:
168 // Updates internals when a solution has been found using the selected
169 // optimizer.
170 void NewSolutionFound(int64_t gain);
171
172 // Updates the deterministic time spent by the selected optimizer.
173 void UpdateDeterministicTime(double time_spent);
174
175 // Sorts optimizers based on their scores.
176 void UpdateOrder();
177
178 struct RunInfo {
179 RunInfo(OptimizerIndex i, absl::string_view n)
180 : optimizer_index(i),
181 name(n),
182 num_successes(0),
183 num_calls(0),
184 total_gain(0),
185 time_spent(0.0),
186 time_spent_since_last_solution(0),
187 runnable(true),
188 selectable(true),
189 score(0.0) {}
190
191 bool RunnableAndSelectable() const { return runnable && selectable; }
192
193 OptimizerIndex optimizer_index;
194 std::string name;
195 int num_successes;
196 int num_calls;
197 int64_t total_gain;
198 double time_spent;
199 double time_spent_since_last_solution;
200 bool runnable;
201 bool selectable;
202 double score;
203 };
204
205 std::vector<RunInfo> run_infos_;
207 int selected_index_;
208};
209
210} // namespace bop
211} // namespace operations_research
212#endif // OR_TOOLS_BOP_BOP_PORTFOLIO_H_
const std::string & name() const
Returns the name given at construction.
Definition bop_base.h:54
std::string PrintStats(OptimizerIndex optimizer_index) const
Returns statistics about the given optimizer.
void TemporarilyMarkOptimizerAsUnselectable(OptimizerIndex optimizer_index)
void SetOptimizerRunnability(OptimizerIndex optimizer_index, bool runnable)
void UpdateScore(int64_t gain, double time_spent)
int NumCallsForOptimizer(OptimizerIndex optimizer_index) const
void DebugPrint() const
Prints some debug information. Should not be used in production.
OptimizerSelector(const util_intops::StrongVector< OptimizerIndex, BopOptimizerBase * > &optimizers)
bool ShouldBeRun(const ProblemState &problem_state) const override
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, absl::string_view name)
SatParameters parameters
time_limit
Definition solve.cc:22
const OptimizerIndex kInvalidOptimizerIndex(-1)
In SWIG mode, we don't want anything besides these top-level includes.
std::mt19937_64 random_engine_t
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)