Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
set_cover_mip.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 <cstdint>
17#include <limits>
18
19#include "absl/log/check.h"
20#include "absl/types/span.h"
26
27namespace operations_research {
28
29namespace {
30// Returns the vector a - b.
32 const ElementToIntVector& b) {
33 ElementToIntVector delta(a.size());
34 DCHECK_EQ(a.size(), b.size());
35 for (const ElementIndex i : a.index_range()) {
36 delta[i] = a[i] - b[i];
37 }
38 return delta;
39}
40} // namespace
41
42template <typename IndexType, typename ValueType>
44
45bool SetCoverMip::NextSolution(bool use_integers,
46 double time_limit_in_seconds) {
47 return NextSolution(inv_->model()->all_subsets(), use_integers,
48 time_limit_in_seconds);
49}
50
51bool SetCoverMip::NextSolution(absl::Span<const SubsetIndex> focus,
52 bool use_integers,
53 double time_limit_in_seconds) {
54 SetCoverModel* model = inv_->model();
55 const SubsetIndex num_subsets(model->num_subsets());
56 const ElementIndex num_elements(model->num_elements());
57 SubsetBoolVector choices = inv_->is_selected();
59 switch (mip_solver_) {
62 break;
64 if (use_integers) {
66 } else {
68 }
69 break;
71 if (!use_integers) {
72 LOG(INFO) << "Defaulting to integer variables with SAT";
73 use_integers = true;
74 }
76 break;
78 LOG(INFO) << "Defaulting to linear relaxation with GLOP";
79 use_integers = false;
81 break;
83 if (use_integers) {
84 LOG(INFO) << "Defaulting to linear relaxation with PDLP";
85 use_integers = false;
86 }
88 break;
89 default:
90 LOG(WARNING) << "Unknown solver value, defaulting to SCIP";
92 }
93 // We are using MPSolver, which is deprecated, because MathOpt does not
94 // provide an interface without using protobufs.
95 // We construct a restricted MIP, omitting all the parts of the problem
96 // that are already fixed in the invariant. The goal is to not spend time
97 // sending data, and having the MIP solver re-discover fixed variables.
98 MPSolver solver("set cover mip", problem_type);
99 solver.SuppressOutput();
100 MPObjective* const objective = solver.MutableObjective();
101 objective->SetMinimization();
102
103 StrictVector<ElementIndex, MPConstraint*> constraints(num_elements, nullptr);
104 StrictVector<SubsetIndex, MPVariable*> vars(num_subsets, nullptr);
105 ElementToIntVector coverage_outside_focus =
106 Subtract(inv_->coverage(), inv_->ComputeCoverageInFocus(focus));
107 for (const SubsetIndex subset : focus) {
108 vars[subset] = solver.MakeVar(0, 1, use_integers, "");
109 objective->SetCoefficient(vars[subset], model->subset_costs()[subset]);
110 for (const ElementIndex element : model->columns()[subset]) {
111 // The model should only contain elements that are not forcibly covered by
112 // subsets outside the focus.
113 if (coverage_outside_focus[element] != 0) continue;
114 if (constraints[element] == nullptr) {
115 constexpr double kInfinity = std::numeric_limits<double>::infinity();
116 constraints[element] = solver.MakeRowConstraint(1.0, kInfinity);
117 }
118 constraints[element]->SetCoefficient(vars[subset], 1);
119 }
120 }
121 // set_time_limit takes milliseconds as a unit.
122 solver.set_time_limit(static_cast<int64_t>(time_limit_in_seconds * 1000));
123
124 // Call the solver.
125 const MPSolver::ResultStatus solve_status = solver.Solve();
126 switch (solve_status) {
128 break;
130 break;
132 LOG(ERROR) << "Did not find solution. Problem is infeasible.";
133 break;
135 LOG(ERROR) << "Did not find solution. Problem is unbounded.";
136 break;
137 default:
138 LOG(ERROR) << "Solving resulted in an error.";
139 return false;
140 }
141 if (use_integers) {
143 for (const SubsetIndex subset : focus) {
144 if (vars[subset]->solution_value() > 0.9) {
145 inv_->Select(subset, CL::kCostAndCoverage);
146 }
147 }
148 } else {
149 lower_bound_ = solver.Objective().Value();
150 }
151 return true;
152}
153
154} // namespace operations_research
A class to express a linear objective.
void SetCoefficient(const MPVariable *var, double coeff)
void SetMinimization()
Sets the optimization direction to minimize.
MPVariable * MakeVar(double lb, double ub, bool integer, const std::string &name)
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
ResultStatus Solve()
Solves the problem using the default parameter values.
const MPObjective & Objective() const
@ SCIP_MIXED_INTEGER_PROGRAMMING
Recommended default value for MIP problems.
@ GUROBI_LINEAR_PROGRAMMING
Commercial software (need license).
MPObjective * MutableObjective()
Returns the mutable objective object.
void SuppressOutput()
Suppresses solver logging.
MPConstraint * MakeRowConstraint(double lb, double ub)
void set_time_limit(int64_t time_limit_milliseconds)
bool NextSolution(bool use_integers, double time_limit_in_seconds)
Main class for describing a weighted set-covering problem.
const SubsetCostVector & subset_costs() const
Vector of costs for each subset.
const SparseColumnView & columns() const
Column view of the set covering problem.
In SWIG mode, we don't want anything besides these top-level includes.
static constexpr double kInfinity
SetCoverInvariant::ConsistencyLevel CL
util_intops::StrongVector< ElementIndex, BaseInt > ElementToIntVector
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
glop::StrictITIVector< IndexType, ValueType > StrictVector