Google OR-Tools v9.15
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-2025 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/log/log.h"
23#include "absl/status/status.h"
24#include "absl/strings/str_format.h"
25#include "google/protobuf/text_format.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;
48} // anonymous namespace
49
50//------------------------------------------------------------------------------
51// BopSolver
52//------------------------------------------------------------------------------
54 : problem_(problem),
55 problem_state_(problem),
56 parameters_(),
57 stats_("BopSolver") {
58 SCOPED_TIME_STAT(&stats_);
59}
60
61BopSolver::~BopSolver() { IF_STATS_ENABLED(VLOG(1) << stats_.StatString()); }
62
64 std::unique_ptr<TimeLimit> time_limit =
66 return SolveWithTimeLimit(time_limit.get());
67}
68
70 CHECK(time_limit != nullptr);
72
73 absl::Status valid = sat::ValidateBooleanProblem(problem_);
74 if (!valid.ok()) {
75 LOG(ERROR) << "Invalid Boolean problem: " << valid.message();
77 }
78
79 UpdateParameters();
80
81 return parameters_.number_of_solvers() > 1
82 ? InternalMultithreadSolver(time_limit)
83 : InternalMonothreadSolver(time_limit);
84}
85
86BopSolveStatus BopSolver::InternalMonothreadSolver(TimeLimit* time_limit) {
87 CHECK(time_limit != nullptr);
88 LearnedInfo learned_info(problem_state_.original_problem());
89 PortfolioOptimizer optimizer(problem_state_, parameters_,
90 parameters_.solver_optimizer_sets(0),
91 "Portfolio");
92 while (!time_limit->LimitReached()) {
93 const BopOptimizerBase::Status optimization_status = optimizer.Optimize(
94 parameters_, problem_state_, &learned_info, time_limit);
95 problem_state_.MergeLearnedInfo(learned_info, optimization_status);
96
97 if (optimization_status == BopOptimizerBase::SOLUTION_FOUND) {
98 CHECK(problem_state_.solution().IsFeasible());
99 VLOG(1) << problem_state_.solution().GetScaledCost()
100 << " New solution! ";
101 }
102
103 if (problem_state_.IsOptimal()) {
104 CHECK(problem_state_.solution().IsFeasible());
106 } else if (problem_state_.IsInfeasible()) {
108 }
109
110 if (optimization_status == BopOptimizerBase::ABORT) {
111 break;
112 }
113 learned_info.Clear();
114 }
115
116 return problem_state_.solution().IsFeasible()
119}
120
121BopSolveStatus BopSolver::InternalMultithreadSolver(TimeLimit* time_limit) {
122 CHECK(time_limit != nullptr);
123 // Not implemented.
125}
126
127BopSolveStatus BopSolver::Solve(const BopSolution& first_solution) {
128 std::unique_ptr<TimeLimit> time_limit =
130 return SolveWithTimeLimit(first_solution, time_limit.get());
131}
132
134 TimeLimit* time_limit) {
136
137 if (first_solution.IsFeasible()) {
138 VLOG(1) << "First solution is feasible.";
139 LearnedInfo learned_info(problem_);
140 learned_info.solution = first_solution;
141 if (problem_state_.MergeLearnedInfo(learned_info,
143 problem_state_.IsOptimal()) {
145 }
146 } else {
147 VLOG(1)
148 << "First solution is infeasible. Using it as assignment preference.";
149 std::vector<bool> assignment_preference;
150 assignment_preference.reserve(first_solution.Size());
151 for (int i = 0; i < first_solution.Size(); ++i) {
152 assignment_preference.push_back(first_solution.Value(VariableIndex(i)));
153 }
154 problem_state_.set_assignment_preference(assignment_preference);
155 }
156 return SolveWithTimeLimit(time_limit);
157}
158
159double BopSolver::GetScaledBestBound() const {
161 problem_, sat::Coefficient(problem_state_.lower_bound()));
162}
163
164double BopSolver::GetScaledGap() const {
165 return 100.0 *
166 std::abs(problem_state_.solution().GetScaledCost() -
168 std::abs(problem_state_.solution().GetScaledCost());
169}
170
171void BopSolver::UpdateParameters() {
172 if (parameters_.solver_optimizer_sets_size() == 0) {
173 // No user defined optimizers, use the default string to define the
174 // behavior.
175 CHECK(::google::protobuf::TextFormat::ParseFromString(
176 parameters_.default_solver_optimizer_sets(),
177 parameters_.add_solver_optimizer_sets()));
178 }
179
180 problem_state_.SetParameters(parameters_);
181}
182} // namespace bop
183} // namespace operations_research
std::string StatString() const
Definition stats.cc:95
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Definition time_limit.h:143
::operations_research::bop::BopSolverOptimizerSet *PROTOBUF_NONNULL add_solver_optimizer_sets()
const ::operations_research::bop::BopSolverOptimizerSet & solver_optimizer_sets(int index) const
const ::std::string & default_solver_optimizer_sets() const
bool Value(VariableIndex var) const
BopSolveStatus SolveWithTimeLimit(TimeLimit *time_limit)
Definition bop_solver.cc:71
BopSolver(const sat::LinearBooleanProblem &problem)
Definition bop_solver.cc:55
void set_assignment_preference(const std::vector< bool > &a)
Definition bop_base.h:135
const BopSolution & solution() const
Definition bop_base.h:204
void SetParameters(const BopParameters &parameters)
Definition bop_base.h:127
bool MergeLearnedInfo(const LearnedInfo &learned_info, BopOptimizerBase::Status optimization_status)
Definition bop_base.cc:108
const sat::LinearBooleanProblem & original_problem() const
Definition bop_base.h:209
StrictITIVector< ColIndex, Fractional > DenseRow
Definition lp_types.h:351
double AddOffsetAndScaleObjectiveValue(const LinearBooleanProblem &problem, Coefficient v)
absl::Status ValidateBooleanProblem(const LinearBooleanProblem &problem)
OR-Tools root namespace.
#define IF_STATS_ENABLED(instructions)
Definition stats.h:412
#define SCOPED_TIME_STAT(stats)
Definition stats.h:419