Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
set_cover_invariant.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_INVARIANT_H_
15#define OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_
16
17#include <tuple>
18#include <vector>
19
20#include "absl/log/check.h"
21#include "ortools/algorithms/set_cover.pb.h"
24
25namespace operations_research {
26
27// A helper class used to store the decisions made during a search.
29 public:
30 SetCoverDecision() : decision_(0) {}
31
32 SetCoverDecision(SubsetIndex subset, bool value) {
33 static_assert(sizeof(subset) == sizeof(decision_));
34 DCHECK_GE(subset.value(), 0);
35 decision_ = value ? subset.value() : ~subset.value();
36 }
37
38 SubsetIndex subset() const {
39 return SubsetIndex(decision_ >= 0 ? decision_ : ~decision_);
40 }
41
42 bool decision() const { return decision_ >= 0; }
43
44 private:
45 BaseInt decision_;
46};
47
48// SetCoverInvariant does the bookkeeping for a solution to the
49// SetCoverModel passed as argument.
50// The state of a SetCoverInvariant instance is uniquely defined by a
51// SubsetBoolVector representing whether a subset is selected in the solution
52// or not.
53//
54// See https://cs.brown.edu/research/pubs/pdfs/1999/Michel-1999-LML.pdf
55// for an explanation of the terminology.
56//
57// A SetCoverInvariant is (relatively) small:
58// is_selected_: a partial solution, vector of Booleans of size #subsets.
59// From this, the following can be computed:
60// coverage_ : number of times an element is covered;
61// num_free_elements_: number of elements in a subset that are uncovered.
62// num_non_overcovered_elements_: the number of elements of a subset that
63// are covered 1 time or less (not overcovered) in the current solution;
64// is_redundant_, whether a subset can be removed from the solution.
65// is_redundant_[subset] == (num_non_overcovered_elements_[subet] == 0).
66
68 public:
69 // Constructs an empty weighted set covering solver state.
70 // The model may not change after the invariant was built.
71 explicit SetCoverInvariant(SetCoverModel* m) : model_(m) { Initialize(); }
72
73 // Initializes the solver once the data is set. The model cannot be changed
74 // afterwards.
75 void Initialize();
76
77 void Clear() {
78 is_selected_.assign(model_->num_subsets(), false);
80 }
81
82 // Recomputes all the invariants for the current solution.
83 void RecomputeInvariant();
84
85 // Returns the weighted set covering model to which the state applies.
86 SetCoverModel* model() const { return model_; }
87
88 const SetCoverModel* const_model() const { return model_; }
89
90 // Returns the cost of current solution.
91 Cost cost() const { return cost_; }
92
93 // Returns the number of uncovered elements.
94 BaseInt num_uncovered_elements() const { return num_uncovered_elements_; }
95
96 // Returns the subset assignment vector.
97 const SubsetBoolVector& is_selected() const { return is_selected_; }
98
99 // Returns vector containing the number of elements in each subset that are
100 // not covered in the current solution.
102 return num_free_elements_;
103 }
104
105 // Returns the vector of numbers of free or exactly covered elements for
106 // each subset.
108 return num_non_overcovered_elements_;
109 }
110 // Returns vector containing number of subsets covering each element.
111 const ElementToIntVector& coverage() const { return coverage_; }
112
113 // Returns a vector containing the number of subsets within `focus` covering
114 // each element. Subsets that are without `focus` are not considered.
116 absl::Span<const SubsetIndex> focus) const;
117
118 // Returns vector of Booleans telling whether each subset can be removed from
119 // the solution.
120 const SubsetBoolVector& is_redundant() const { return is_redundant_; }
121
122 // Returns the vector of the decisions which has led to the current solution.
123 const std::vector<SetCoverDecision>& trace() const { return trace_; }
124
125 // Clears the trace.
126 void ClearTrace() { trace_.clear(); }
127
128 // Clear the removability information.
130 new_removable_subsets_.clear();
131 new_non_removable_subsets_.clear();
132 }
133
134 // Returns the subsets that become removable after the last update.
135 const std::vector<SubsetIndex>& new_removable_subsets() const {
136 return new_removable_subsets_;
137 }
138
139 // Returns the subsets that become non removable after the last update.
140 const std::vector<SubsetIndex>& new_non_removable_subsets() const {
141 return new_non_removable_subsets_;
142 }
143
144 // Compresses the trace so that:
145 // - each subset appears only once,
146 // - there are only "positive" decisions.
147 // This trace is equivalent to the original trace in the sense that the cost
148 // and the covered elements are the same.
149 // This can be used to recover the solution by indices after local search.
150 void CompressTrace();
151
152 // Loads the solution and recomputes the data in the invariant.
154
155 // Returns true if the data stored in the invariant is consistent.
156 // The body of the function will CHECK-fail the first time an inconsistency
157 // is encountered.
158 bool CheckConsistency() const;
159
160 // Returns true if the subset is redundant within the current solution, i.e.
161 // when all its elements are already covered twice. Note that the set need
162 // not be selected for this to happen.
163 // TODO(user): Implement this using AVX-512?
164 bool ComputeIsRedundant(SubsetIndex subset) const;
165
166 // Updates the invariant fully, so that is_redundant_ can be updated
167 // incrementally later with SelectAndFullyUpdate and
168 // DeselectSelectAndFullyUpdate.
169 void MakeFullyUpdated();
170
171 // Flips is_selected_[subset] to its negation, by calling Select or Deselect
172 // depending on value. Updates the invariant incrementally.
173 // FlipAndFullyUpdate performs a full incremental update of the invariant,
174 // including num_non_overcovered_elements_, is_redundant_,
175 // new_removable_subsets_, new_non_removable_subsets_. This is useful for some
176 // meta-heuristics.
177 void Flip(SubsetIndex subset) { Flip(subset, false); }
178 void FlipAndFullyUpdate(SubsetIndex subset) { Flip(subset, true); }
179
180 // Includes subset in the solution by setting is_selected_[subset] to true
181 // and incrementally updating the invariant.
182 // SelectAndFullyUpdate also updates the invariant in a more thorough way as
183 // explained with FlipAndFullyUpdate.
184 void Select(SubsetIndex subset) { Select(subset, false); }
185 void SelectAndFullyUpdate(SubsetIndex subset) { Select(subset, true); }
186
187 // Excludes subset from the solution by setting is_selected_[subset] to false
188 // and incrementally updating the invariant.
189 // DeselectAndFullyUpdate also updates the invariant in a more thorough way as
190 // explained with FlipAndFullyUpdate.
191 void Deselect(SubsetIndex subset) { Deselect(subset, false); }
192 void DeselectAndFullyUpdate(SubsetIndex subset) { Deselect(subset, true); }
193
194 // Returns the current solution as a proto.
195 SetCoverSolutionResponse ExportSolutionAsProto() const;
196
197 // Imports the solution from a proto.
198 void ImportSolutionFromProto(const SetCoverSolutionResponse& message);
199
200 private:
201 // Computes the cost and the coverage vector for the given choices.
202 // Temporarily uses |E| BaseInts.
203 std::tuple<Cost, ElementToIntVector> ComputeCostAndCoverage(
204 const SubsetBoolVector& choices) const;
205
206 // Computes the global number of uncovered elements and the
207 // vector containing the number of free elements for each subset from
208 // a coverage vector.
209 // Temporarily uses |S| BaseInts.
210 std::tuple<BaseInt, // Number of uncovered elements,
211 SubsetToIntVector> // Vector of number of free elements.
212 ComputeNumUncoveredAndFreeElements(const ElementToIntVector& cvrg) const;
213
214 // Computes the vector containing the number of non-overcovered elements per
215 // subset and the Boolean vector telling whether a subset is redundant w.r.t.
216 // the current solution.
217 // Temporarily uses |S| BaseInts.
218 std::tuple<SubsetToIntVector, // Number of non-overcovered elements,
219 SubsetBoolVector> // Redundancy for each of the subsets.
220 ComputeNumNonOvercoveredElementsAndIsRedundant(
221 const ElementToIntVector& cvrg) const;
222
223 // Flips is_selected_[subset] to its negation, by calling Select or Deselect
224 // depending on value. Updates the invariant incrementally.
225 // When incremental_full_update is true, the following fields are also
226 // updated: num_non_overcovered_elements_, is_redundant_,
227 // new_removable_subsets_, new_non_removable_subsets_. This is useful for some
228 // meta-heuristics.
229 void Flip(SubsetIndex, bool incremental_full_update);
230
231 // Sets is_selected_[subset] to true and incrementally updates the invariant.
232 // Parameter incremental_full_update has the same meaning as with Flip.
233 void Select(SubsetIndex subset, bool incremental_full_update);
234
235 // Sets is_selected_[subset] to false and incrementally updates the invariant.
236 // Parameter incremental_full_update has the same meaning as with Flip.
237 void Deselect(SubsetIndex subset, bool incremental_full_update);
238
239 // Helper function for Select when AVX-512 is supported by the processor.
240 void SelectAvx512(SubsetIndex subset);
241
242 // Helper function for Deselect when AVX-512 is supported by the processor.
243 void DeselectAvx512(SubsetIndex subset);
244
245 // The weighted set covering model on which the solver is run.
246 SetCoverModel* model_;
247
248 // Current cost.
249 Cost cost_;
250
251 // The number of uncovered (or free) elements in the current solution.
252 BaseInt num_uncovered_elements_;
253
254 // Current assignment.
255 // Takes |S| bits.
256 SubsetBoolVector is_selected_;
257
258 // A trace of the decisions, i.e. a list of decisions (subset, Boolean) that
259 // lead to the current solution.
260 // Takes at most |S| BaseInts.
261 std::vector<SetCoverDecision> trace_;
262
263 // The coverage of an element is the number of used subsets which contains
264 // the said element.
265 // Takes |E| BaseInts
266 ElementToIntVector coverage_;
267
268 // A vector that for each subset gives the number of free elements, i.e.
269 // elements whose coverage is 0.
270 // problem.
271 // Takes |S| BaseInts.
272 SubsetToIntVector num_free_elements_;
273
274 // Counts the number of free or exactly covered elements, i.e. whose coverage
275 // is 0 or 1.
276 // Takes at most |S| BaseInts. (More likely a few percent of that).
277 SubsetToIntVector num_non_overcovered_elements_;
278
279 // True if the subset is redundant, i.e. can be removed from the solution
280 // without making it infeasible.
281 // Takes |S| bits.
282 SubsetBoolVector is_redundant_;
283
284 // Subsets that become removable after the last update.
285 // Takes at most |S| BaseInts. (More likely a few percent of that).
286 std::vector<SubsetIndex> new_removable_subsets_;
287
288 // Subsets that become non removable after the last update.
289 // Takes at most |S| BaseInts. (More likely a few percent of that).
290 std::vector<SubsetIndex> new_non_removable_subsets_;
291
292 // Denotes whether is_redundant_ and num_non_overcovered_elements_ have been
293 // updated. Initially true, it becomes false as soon as Flip,
294 // Select and Deselect are called with incremental_full_update = false. The
295 // fully updated status can be achieved again with a call to FullUpdate(),
296 // which can be expensive,
297 bool is_fully_updated_;
298
299 // True if the CPU supports the AVX-512 instruction set.
300 bool supports_avx512_;
301};
302
303} // namespace operations_research
304#endif // OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_
A helper class used to store the decisions made during a search.
SetCoverDecision(SubsetIndex subset, bool value)
const SetCoverModel * const_model() const
bool ComputeIsRedundant(SubsetIndex subset) const
const SubsetBoolVector & is_redundant() const
const SubsetToIntVector & num_free_elements() const
SetCoverSolutionResponse ExportSolutionAsProto() const
Returns the current solution as a proto.
const std::vector< SetCoverDecision > & trace() const
Returns the vector of the decisions which has led to the current solution.
void RecomputeInvariant()
Recomputes all the invariants for the current solution.
void LoadSolution(const SubsetBoolVector &solution)
Loads the solution and recomputes the data in the invariant.
const std::vector< SubsetIndex > & new_non_removable_subsets() const
Returns the subsets that become non removable after the last update.
void ImportSolutionFromProto(const SetCoverSolutionResponse &message)
Imports the solution from a proto.
const SubsetToIntVector & num_coverage_le_1_elements() const
const SubsetBoolVector & is_selected() const
Returns the subset assignment vector.
SetCoverModel * model() const
Returns the weighted set covering model to which the state applies.
void DeselectAndFullyUpdate(SubsetIndex subset)
const ElementToIntVector & coverage() const
Returns vector containing number of subsets covering each element.
const std::vector< SubsetIndex > & new_removable_subsets() const
Returns the subsets that become removable after the last update.
Cost cost() const
Returns the cost of current solution.
ElementToIntVector ComputeCoverageInFocus(absl::Span< const SubsetIndex > focus) const
void ClearRemovabilityInformation()
Clear the removability information.
BaseInt num_uncovered_elements() const
Returns the number of uncovered elements.
Main class for describing a weighted set-covering problem.
void assign(size_type n, const value_type &val)
int64_t value
double solution
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< SubsetIndex, BaseInt, IntAllocator > SubsetToIntVector
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.
std::string message
Definition trace.cc:397