Google OR-Tools v9.9
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
bop_solver.cc
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
15
16#include <cstdlib>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "absl/log/check.h"
22#include "absl/status/status.h"
23#include "absl/strings/str_format.h"
24#include "google/protobuf/text_format.h"
28#include "ortools/bop/bop_parameters.pb.h"
34#include "ortools/sat/boolean_problem.pb.h"
36#include "ortools/util/stats.h"
38
39namespace operations_research {
40namespace bop {
41
42using ::operations_research::sat::LinearBooleanProblem;
43
44namespace {
45
46using ::operations_research::glop::ColIndex;
47using ::operations_research::glop::DenseRow;
48
49// Updates the problem_state when the solution is proved optimal or the problem
50// is proved infeasible.
51// Returns true when the problem_state has been changed.
52bool UpdateProblemStateBasedOnStatus(BopOptimizerBase::Status status,
53 ProblemState* problem_state) {
54 CHECK(nullptr != problem_state);
55
57 problem_state->MarkAsOptimal();
58 return true;
59 }
60
62 problem_state->MarkAsInfeasible();
63 return true;
64 }
65
66 return false;
67}
68} // anonymous namespace
69
70//------------------------------------------------------------------------------
71// BopSolver
72//------------------------------------------------------------------------------
73BopSolver::BopSolver(const LinearBooleanProblem& problem)
74 : problem_(problem),
75 problem_state_(problem),
76 parameters_(),
77 stats_("BopSolver") {
78 SCOPED_TIME_STAT(&stats_);
79}
80
81BopSolver::~BopSolver() { IF_STATS_ENABLED(VLOG(1) << stats_.StatString()); }
82
84 std::unique_ptr<TimeLimit> time_limit =
90 CHECK(time_limit != nullptr);
92
93 absl::Status valid = sat::ValidateBooleanProblem(problem_);
94 if (!valid.ok()) {
95 LOG(ERROR) << "Invalid Boolean problem: " << valid.message();
97 }
98
99 UpdateParameters();
100
101 return parameters_.number_of_solvers() > 1
102 ? InternalMultithreadSolver(time_limit)
103 : InternalMonothreadSolver(time_limit);
104}
105
106BopSolveStatus BopSolver::InternalMonothreadSolver(TimeLimit* time_limit) {
107 CHECK(time_limit != nullptr);
108 LearnedInfo learned_info(problem_state_.original_problem());
109 PortfolioOptimizer optimizer(problem_state_, parameters_,
110 parameters_.solver_optimizer_sets(0),
111 "Portfolio");
112 while (!time_limit->LimitReached()) {
113 const BopOptimizerBase::Status optimization_status = optimizer.Optimize(
114 parameters_, problem_state_, &learned_info, time_limit);
115 problem_state_.MergeLearnedInfo(learned_info, optimization_status);
116
117 if (optimization_status == BopOptimizerBase::SOLUTION_FOUND) {
118 CHECK(problem_state_.solution().IsFeasible());
119 VLOG(1) << problem_state_.solution().GetScaledCost()
120 << " New solution! ";
121 }
122
123 if (problem_state_.IsOptimal()) {
124 CHECK(problem_state_.solution().IsFeasible());
126 } else if (problem_state_.IsInfeasible()) {
128 }
129
130 if (optimization_status == BopOptimizerBase::ABORT) {
131 break;
132 }
133 learned_info.Clear();
134 }
135
136 return problem_state_.solution().IsFeasible()
139}
140
141BopSolveStatus BopSolver::InternalMultithreadSolver(TimeLimit* time_limit) {
142 CHECK(time_limit != nullptr);
143 // Not implemented.
145}
146
147BopSolveStatus BopSolver::Solve(const BopSolution& first_solution) {
148 std::unique_ptr<TimeLimit> time_limit =
150 return SolveWithTimeLimit(first_solution, time_limit.get());
151}
152
156
157 if (first_solution.IsFeasible()) {
158 VLOG(1) << "First solution is feasible.";
159 LearnedInfo learned_info(problem_);
160 learned_info.solution = first_solution;
161 if (problem_state_.MergeLearnedInfo(learned_info,
163 problem_state_.IsOptimal()) {
165 }
166 } else {
167 VLOG(1)
168 << "First solution is infeasible. Using it as assignment preference.";
169 std::vector<bool> assignment_preference;
170 for (int i = 0; i < first_solution.Size(); ++i) {
171 assignment_preference.push_back(first_solution.Value(VariableIndex(i)));
172 }
173 problem_state_.set_assignment_preference(assignment_preference);
174 }
176}
177
178double BopSolver::GetScaledBestBound() const {
180 problem_, sat::Coefficient(problem_state_.lower_bound()));
181}
182
183double BopSolver::GetScaledGap() const {
184 return 100.0 *
185 std::abs(problem_state_.solution().GetScaledCost() -
187 std::abs(problem_state_.solution().GetScaledCost());
188}
189
190void BopSolver::UpdateParameters() {
191 if (parameters_.solver_optimizer_sets_size() == 0) {
192 // No user defined optimizers, use the default string to define the
193 // behavior.
194 CHECK(::google::protobuf::TextFormat::ParseFromString(
195 parameters_.default_solver_optimizer_sets(),
196 parameters_.add_solver_optimizer_sets()));
197 }
198
199 problem_state_.SetParameters(parameters_);
200}
201} // namespace bop
202} // namespace operations_research
std::string StatString() const
Definition stats.cc:77
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Definition time_limit.h:135
@ ABORT
There is no need to call this optimizer again on the same problem state.
Definition bop_base.h:87
bool Value(VariableIndex var) const
BopSolveStatus Solve()
Returns the status of the optimization.
Definition bop_solver.cc:85
BopSolveStatus SolveWithTimeLimit(TimeLimit *time_limit)
Runs the solver with an external time limit.
Definition bop_solver.cc:91
BopSolver(const sat::LinearBooleanProblem &problem)
Definition bop_solver.cc:75
void set_assignment_preference(const std::vector< bool > &a)
Definition bop_base.h:136
const BopSolution & solution() const
Definition bop_base.h:205
void SetParameters(const BopParameters &parameters)
Sets parameters, used for instance to get the tolerance, the gap limit...
Definition bop_base.h:128
bool MergeLearnedInfo(const LearnedInfo &learned_info, BopOptimizerBase::Status optimization_status)
Definition bop_base.cc:108
bool IsInfeasible() const
Returns true when the problem is proved to be infeasible.
Definition bop_base.h:180
const sat::LinearBooleanProblem & original_problem() const
Definition bop_base.h:210
absl::Status status
Definition g_gurobi.cc:44
time_limit
Definition solve.cc:22
BopSolveStatus
Status of the solve of Bop.
Definition bop_types.h:34
@ NO_SOLUTION_FOUND
The solver didn't find any solution.
@ OPTIMAL_SOLUTION_FOUND
The solver found the proven optimal solution.
@ INFEASIBLE_PROBLEM
The problem is infeasible.
@ INVALID_PROBLEM
The problem is invalid.
double AddOffsetAndScaleObjectiveValue(const LinearBooleanProblem &problem, Coefficient v)
Adds the offset and returns the scaled version of the given objective value.
absl::Status ValidateBooleanProblem(const LinearBooleanProblem &problem)
In SWIG mode, we don't want anything besides these top-level includes.
#define IF_STATS_ENABLED(instructions)
Definition stats.h:416
#define SCOPED_TIME_STAT(stats)
Definition stats.h:417