Google OR-Tools v9.14
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/log/log.h"
21#include "absl/types/span.h"
27
28namespace operations_research {
29
30namespace {
31// Returns the vector a - b.
33 const ElementToIntVector& b) {
34 ElementToIntVector delta(a.size());
35 DCHECK_EQ(a.size(), b.size());
36 for (const ElementIndex i : a.index_range()) {
37 delta[i] = a[i] - b[i];
38 }
39 return delta;
40}
41} // namespace
42
43template <typename IndexType, typename ValueType>
45
46bool SetCoverMip::NextSolution(absl::Span<const SubsetIndex> focus) {
47 inv()->ReportLowerBound(0.0, true);
48 StopWatch stop_watch(&run_time_);
49 const SubsetIndex num_subsets(model()->num_subsets());
50 const ElementIndex num_elements(model()->num_elements());
51 SubsetBoolVector choices = inv()->is_selected();
53 switch (mip_solver_) {
56 break;
58 if (use_integers_) {
60 } else {
62 }
63 break;
65 if (!use_integers_) {
66 VLOG(1) << "Defaulting to integer variables with SAT";
67 use_integers_ = true;
68 }
70 break;
72 VLOG(1) << "Defaulting to linear relaxation with GLOP";
73 use_integers_ = false;
75 break;
77 if (use_integers_) {
78 VLOG(1) << "Defaulting to linear relaxation with PDLP";
79 use_integers_ = false;
80 }
82 break;
83 default:
84 LOG(WARNING) << "Unknown solver value, defaulting to SCIP";
86 }
87 // We are using MPSolver, which is deprecated, because MathOpt does not
88 // provide an interface without using protobufs.
89 // We construct a restricted MIP, omitting all the parts of the problem
90 // that are already fixed in the invariant. The goal is to not spend time
91 // sending data, and having the MIP solver re-discover fixed variables.
92 MPSolver solver("set cover mip", problem_type);
93 solver.SuppressOutput();
94 MPObjective* const objective = solver.MutableObjective();
95 objective->SetMinimization();
96
97 StrictVector<ElementIndex, MPConstraint*> constraints(num_elements, nullptr);
99 ElementToIntVector coverage_outside_focus =
100 Subtract(inv()->coverage(), inv()->ComputeCoverageInFocus(focus));
101 for (const SubsetIndex subset : focus) {
102 vars[subset] = solver.MakeVar(0, 1, use_integers_, "");
103 objective->SetCoefficient(vars[subset], model()->subset_costs()[subset]);
104 for (const ElementIndex element : model()->columns()[subset]) {
105 // The model should only contain elements that are not forcibly covered
106 // by subsets outside the focus.
107 if (coverage_outside_focus[element] != 0) continue;
108 if (constraints[element] == nullptr) {
109 constexpr double kInfinity = std::numeric_limits<double>::infinity();
110 constraints[element] = solver.MakeRowConstraint(1.0, kInfinity);
111 }
112 constraints[element]->SetCoefficient(vars[subset], 1);
113 }
114 }
115 // set_time_limit takes milliseconds as a unit.
116 solver.set_time_limit(static_cast<int64_t>(time_limit_in_seconds() * 1000));
117
118 // Call the solver.
119 solve_status_ = solver.Solve();
120 switch (solve_status_) {
122 break;
124 break;
126 LOG(ERROR) << "Did not find solution. Problem is infeasible.";
127 break;
129 LOG(ERROR) << "Did not find solution. Problem is unbounded.";
130 break;
131 default:
132 LOG(ERROR) << "Solving resulted in an error.";
133 return false;
134 }
135 if (use_integers_) {
137 for (const SubsetIndex subset : focus) {
138 if (vars[subset]->solution_value() > 0.9 &&
139 !inv()->is_selected()[subset]) {
140 inv()->Select(subset, CL::kCostAndCoverage);
141 }
142 }
143 } else {
144 // Report the objective value as a lower bound, and mention that the cost is
145 // not consistent with the solution.
146 inv()->ReportLowerBound(solver.Objective().Value(), false);
147 }
148 return true;
149}
150
151} // 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)
const SubsetBoolVector & is_selected() const
Returns the subset assignment vector.
void ReportLowerBound(Cost lower_bound, bool is_cost_consistent)
bool Select(SubsetIndex subset, ConsistencyLevel consistency)
bool NextSolution() final
Virtual methods that must be implemented by derived classes.
absl::Duration run_time_
run_time_ is an abstract duration for the time spent in NextSolution().
double time_limit_in_seconds() const
The time limit in seconds.
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
Definition base_types.h:64
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
Definition base_types.h:71
glop::StrictITIVector< IndexType, ValueType > StrictVector