Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
set_cover_lagrangian.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_ALGORITHMS_SET_COVER_LAGRANGIAN_H_
15#define OR_TOOLS_ALGORITHMS_SET_COVER_LAGRANGIAN_H_
16
17#include <memory>
18#include <tuple>
19#include <vector>
20
24
25namespace operations_research {
26
27// The SetCoverLagrangian class implements the Lagrangian relaxation of the set
28// cover problem.
29
30// In the following, we refer to the following articles:
31// [1] Caprara, Alberto, Matteo Fischetti, and Paolo Toth. 1999. “A Heuristic
32// Method for the Set Covering Problem.” Operations Research 47 (5): 730–43.
33// https://www.jstor.org/stable/223097
34// [2] Fisher, Marshall L. 1981. “The Lagrangian Relaxation Method for Solving
35// Integer Programming Problems.” Management Science 27 (1): 1–18.
36// https://www.jstor.org/stable/2631139
37// [3] Held, M., Karp, R.M. The traveling-salesman problem and minimum spanning
38// trees: Part II. Mathematical Programming 1, 6–25 (1971).
39// https://link.springer.com/article/10.1007/BF01584070
40// [4] Williamson, David P. 2002. “The Primal-Dual Method for Approximation
41// Algorithms.” Mathematical Programming, 91 (3): 447–78.
42// https://link.springer.com/article/10.1007/s101070100262
43
45 public:
46 explicit SetCoverLagrangian(SetCoverInvariant* inv, int num_threads = 1)
47 : inv_(inv), model_(*inv->model()), num_threads_(num_threads) {}
48
49 // Returns true if a solution was found.
50 // TODO(user): Add time-outs and exit with a partial solution. This seems
51 // unlikely, though.
53
54 // Computes the next partial solution considering only the subsets whose
55 // indices are in focus.
56 bool NextSolution(const std::vector<SubsetIndex>& focus);
57
58 // Initializes the multipliers vector (u) based on the cost per subset.
60
61 // Computes the Lagrangian (row-)cost vector.
62 // For a subset j, c_j(u) = c_j - sum_{i \in I_j} u_i.
63 // I_j denotes the indices of elements present in subset j.
65 const SubsetCostVector& costs,
66 const ElementCostVector& multipliers) const;
67
68 // Same as above, but parallelized, using the number of threads specified in
69 // the constructor.
71 const SubsetCostVector& costs,
72 const ElementCostVector& multipliers) const;
73
74 // Computes the subgradient (column-)cost vector.
75 // For all element indices i, s_i(u) = 1 - sum_{j \in J_i} x_j(u),
76 // where J_i denotes the set of indices of subsets j covering element i.
78 const SubsetCostVector& reduced_costs) const;
79
80 // Same as above, but parallelized, using the number of threads specified in
81 // the constructor.
83 const SubsetCostVector& reduced_costs) const;
84
85 // Computes the value of the Lagrangian L(u).
86 // L(u) = min \sum_{j \in N} c_j(u) x_j + \sum{i \in M} u_i.
87 // If c_j(u) < 0: x_j(u) = 1, if c_j(u) > 0: x_j(u) = 0,
88 // otherwise x_j(u) is unbound, it can take any value in {0, 1}.
89 Cost ComputeLagrangianValue(const SubsetCostVector& reduced_costs,
90 const ElementCostVector& multipliers) const;
91
92 // Same as above, but parallelized, using the number of threads specified in
93 // the constructor.
95 const SubsetCostVector& reduced_costs,
96 const ElementCostVector& multipliers) const;
97
98 // Updates the multipliers vector (u) with the given step size.
99 // Following [3], each of the coordinates is defined as: u^{k+1}_i =
100 // max(u^k_i + lambda_k * (UB - L(u^k)) / |s^k(u)|^2 * s^k_i(u), 0).
101 // lambda_k is step_size in the function signature below. UB is upper_bound.
102 void UpdateMultipliers(double step_size, Cost lagrangian_value,
104 const SubsetCostVector& reduced_costs,
105 ElementCostVector* multipliers) const;
106
107 // Same as above, but parallelized, using the number of threads specified in
108 // the constructor.
109 void ParallelUpdateMultipliers(double step_size, Cost lagrangian_value,
111 const SubsetCostVector& reduced_costs,
112 ElementCostVector* multipliers) const;
113
114 // Computes the gap between the current solution and the optimal solution.
115 // This is the sum of the multipliers for the elements that are not covered
116 // by the current solution.
117 Cost ComputeGap(const SubsetCostVector& reduced_costs,
119 const ElementCostVector& multipliers) const;
120
121 // Performs the three-phase algorithm.
123
124 // Computes a lower bound on the optimal cost.
125 // The returned value is the lower bound, the reduced costs, and the
126 // multipliers.
127 std::tuple<Cost, SubsetCostVector, ElementCostVector> ComputeLowerBound(
128 const SubsetCostVector& costs, Cost upper_bound);
129
130 private:
131 // The invariant on which the algorithm will run.
132 SetCoverInvariant* inv_;
133
134 // The model on which the invariant is defined.
135 const SetCoverModel& model_;
136
137 // The number of threads to use for parallelization.
138 int num_threads_;
139
140 // Total (scalar) Lagrangian cost.
141 Cost lagrangian_;
142
143 // Lagrangian cost vector, per subset.
144 SubsetCostVector lagrangians_;
145
146 // Computes the delta vector.
147 // This is definition (9) in [1].
148 SubsetCostVector ComputeDelta(const SubsetCostVector& reduced_costs,
149 const ElementCostVector& multipliers) const;
150};
151
152} // namespace operations_research
153
154#endif // OR_TOOLS_ALGORITHMS_SET_COVER_LAGRANGIAN_H_
void UpdateMultipliers(double step_size, Cost lagrangian_value, Cost upper_bound, const SubsetCostVector &reduced_costs, ElementCostVector *multipliers) const
Cost ComputeLagrangianValue(const SubsetCostVector &reduced_costs, const ElementCostVector &multipliers) const
ElementCostVector ComputeSubgradient(const SubsetCostVector &reduced_costs) const
void ThreePhase(Cost upper_bound)
Performs the three-phase algorithm.
void ParallelUpdateMultipliers(double step_size, Cost lagrangian_value, Cost upper_bound, const SubsetCostVector &reduced_costs, ElementCostVector *multipliers) const
ElementCostVector ParallelComputeSubgradient(const SubsetCostVector &reduced_costs) const
SubsetCostVector ParallelComputeReducedCosts(const SubsetCostVector &costs, const ElementCostVector &multipliers) const
Computes the reduced costs for all subsets in parallel using ThreadPool.
bool NextSolution(const std::vector< SubsetIndex > &focus)
Cost ParallelComputeLagrangianValue(const SubsetCostVector &reduced_costs, const ElementCostVector &multipliers) const
SetCoverLagrangian(SetCoverInvariant *inv, int num_threads=1)
ElementCostVector InitializeLagrangeMultipliers() const
Initializes the multipliers vector (u) based on the cost per subset.
std::tuple< Cost, SubsetCostVector, ElementCostVector > ComputeLowerBound(const SubsetCostVector &costs, Cost upper_bound)
Computes a lower bound on the optimal cost.
SubsetCostVector ComputeReducedCosts(const SubsetCostVector &costs, const ElementCostVector &multipliers) const
Cost ComputeGap(const SubsetCostVector &reduced_costs, const SubsetBoolVector &solution, const ElementCostVector &multipliers) const
Main class for describing a weighted set-covering problem.
double upper_bound
GRBmodel * model
double solution
In SWIG mode, we don't want anything besides these top-level includes.
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.