forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathset_cover_invariant.h
292 lines (235 loc) · 11.6 KB
/
set_cover_invariant.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Copyright 2010-2024 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_
#define OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_
#include <tuple>
#include <vector>
#include "absl/log/check.h"
#include "absl/types/span.h"
#include "ortools/algorithms/set_cover.pb.h"
#include "ortools/algorithms/set_cover_model.h"
namespace operations_research {
// A helper class used to store the decisions made during a search.
class SetCoverDecision {
public:
SetCoverDecision() : decision_(0) {}
SetCoverDecision(SubsetIndex subset, bool value) {
static_assert(sizeof(subset) == sizeof(decision_));
DCHECK_GE(subset.value(), 0);
decision_ = value ? subset.value() : ~subset.value();
}
SubsetIndex subset() const {
return SubsetIndex(decision_ >= 0 ? decision_ : ~decision_);
}
bool decision() const { return decision_ >= 0; }
private:
BaseInt decision_;
};
// SetCoverInvariant does the bookkeeping for a solution to the
// SetCoverModel passed as argument.
// The state of a SetCoverInvariant instance is uniquely defined by a
// SubsetBoolVector representing whether a subset is selected in the solution
// or not.
//
// See https://cs.brown.edu/research/pubs/pdfs/1999/Michel-1999-LML.pdf
// for an explanation of the terminology.
//
// A SetCoverInvariant is (relatively) small:
// is_selected_: a partial solution, vector of Booleans of size #subsets.
// From this, the following can be computed:
// coverage_ : number of times an element is covered;
// num_free_elements_: number of elements in a subset that are uncovered.
// num_non_overcovered_elements_: the number of elements of a subset that
// are covered 1 time or less (not overcovered) in the current solution;
// is_redundant_, whether a subset can be removed from the solution.
// is_redundant_[subset] == (num_non_overcovered_elements_[subet] == 0).
class SetCoverInvariant {
public:
// The consistency level of the invariant.
// The values denote the level of consistency of the invariant.
// There is an order between the levels, and the invariant is consistent at
// level k if it is consistent at all levels lower than k.
// The consistency level that is the most natural is to use kFreeAndUncovered,
// since it enables to implement most heuristics.
// kCostAndCoverage is used by LazyElementDegree, a fast greedy heuristic.
// kRedundancy is used for GuidedLocalSearch, because knowing whether a
// subset is redundant incrementally is faster than recomputing the
// information over and over again.
// Below, the quantities that are maintained at each level are listed.
enum class ConsistencyLevel {
kInconsistent = 0, // The invariant is not consistent.
kCostAndCoverage, // cost_ and coverage_.
kFreeAndUncovered, // num_free_elements_ and num_uncovered_elements_.
kRedundancy // is_redundant_ and num_non_overcovered_elements_.
};
// Constructs an empty weighted set covering solver state.
// The model may not change after the invariant was built.
explicit SetCoverInvariant(SetCoverModel* m) : model_(m) { Initialize(); }
// Initializes the solver once the data is set. The model cannot be changed
// afterwards.
void Initialize();
// Clears the invariant. Also called by Initialize.
void Clear();
// Returns the weighted set covering model to which the state applies.
SetCoverModel* model() const { return model_; }
const SetCoverModel* const_model() const { return model_; }
// Returns the cost of current solution.
Cost cost() const { return cost_; }
// Returns the number of uncovered elements.
BaseInt num_uncovered_elements() const { return num_uncovered_elements_; }
// Returns the subset assignment vector.
const SubsetBoolVector& is_selected() const { return is_selected_; }
// Returns vector containing the number of elements in each subset that are
// not covered in the current solution.
const SubsetToIntVector& num_free_elements() const {
return num_free_elements_;
}
// Returns the vector of numbers of free or exactly covered elements for
// each subset.
const SubsetToIntVector& num_coverage_le_1_elements() const {
return num_non_overcovered_elements_;
}
// Returns vector containing number of subsets covering each element.
const ElementToIntVector& coverage() const { return coverage_; }
// Returns a vector containing the number of subsets within `focus` covering
// each element. Subsets that are without `focus` are not considered.
ElementToIntVector ComputeCoverageInFocus(
absl::Span<const SubsetIndex> focus) const;
// Returns vector of Booleans telling whether each subset can be removed from
// the solution.
const SubsetBoolVector& is_redundant() const { return is_redundant_; }
// Returns the vector of the decisions which have led to the current solution.
const std::vector<SetCoverDecision>& trace() const { return trace_; }
// Clears the trace.
void ClearTrace() { trace_.clear(); }
// Clear the removability information.
void ClearRemovabilityInformation() {
newly_removable_subsets_.clear();
newly_non_removable_subsets_.clear();
}
// Returns the subsets that become removable after the last update.
const std::vector<SubsetIndex>& newly_removable_subsets() const {
return newly_removable_subsets_;
}
// Returns the subsets that become non removable after the last update.
const std::vector<SubsetIndex>& newly_non_removable_subsets() const {
return newly_non_removable_subsets_;
}
// Compresses the trace so that:
// - each subset appears only once,
// - there are only "positive" decisions.
// This trace is equivalent to the original trace in the sense that the cost
// and the covered elements are the same.
// This can be used to recover the solution by indices after local search.
void CompressTrace();
// Loads the solution and recomputes the data in the invariant.
void LoadSolution(const SubsetBoolVector& solution);
// Checks the consistency of the invariant at the given consistency level.
bool CheckConsistency(ConsistencyLevel consistency) const;
// Recomputes the invariant to the given consistency level.
void Recompute(ConsistencyLevel target_consistency);
// Returns true if the subset is redundant within the current solution, i.e.
// when all its elements are already covered twice. Note that the set need
// not be selected for this to happen.
// TODO(user): Implement this using AVX-512?
bool ComputeIsRedundant(SubsetIndex subset) const;
// Computes the number of free (uncovered) elements in the given subset.
BaseInt ComputeNumFreeElements(SubsetIndex subset) const;
// Includes subset in the solution by setting is_selected_[subset] to true
// without updating the invariant. Only updates the cost and the coverage.
// TODO(user): Merge with Select. Introduce consistency levels and maybe split
// the invariant into three.
void SelectNoUpdate(SubsetIndex subset);
// Flips is_selected_[subset] to its negation, by calling Select or Deselect
// depending on value. Updates the invariant incrementally to the given
// consistency level.
void Flip(SubsetIndex subset, ConsistencyLevel consistency);
// Includes subset in the solution by setting is_selected_[subset] to true
// and incrementally updating the invariant to the given consistency level.
void Select(SubsetIndex subset, ConsistencyLevel consistency);
// Excludes subset from the solution by setting is_selected_[subset] to false
// and incrementally updating the invariant to the given consistency level.
void Deselect(SubsetIndex subset, ConsistencyLevel consistency);
// Returns the current solution as a proto.
SetCoverSolutionResponse ExportSolutionAsProto() const;
// Imports the solution from a proto.
void ImportSolutionFromProto(const SetCoverSolutionResponse& message);
private:
// Computes the cost and the coverage vector for the given choices.
// Temporarily uses |E| BaseInts.
std::tuple<Cost, ElementToIntVector> ComputeCostAndCoverage(
const SubsetBoolVector& choices) const;
// Computes the global number of uncovered elements and the
// vector containing the number of free elements for each subset from
// a coverage vector.
// Temporarily uses |S| BaseInts.
std::tuple<BaseInt, // Number of uncovered elements,
SubsetToIntVector> // Vector of number of free elements.
ComputeNumUncoveredAndFreeElements(const ElementToIntVector& cvrg) const;
// Computes the vector containing the number of non-overcovered elements per
// subset and the Boolean vector telling whether a subset is redundant w.r.t.
// the current solution.
// Temporarily uses |S| BaseInts.
std::tuple<SubsetToIntVector, // Number of non-overcovered elements,
SubsetBoolVector> // Redundancy for each of the subsets.
ComputeRedundancyInfo(const ElementToIntVector& cvrg) const;
// Returns true if the current consistency level consistency_ is lower than
// cheched_consistency and the desired consistency is higher than
// cheched_consistency.
bool NeedToRecompute(ConsistencyLevel cheched_consistency,
ConsistencyLevel target_consistency);
// The weighted set covering model on which the solver is run.
SetCoverModel* model_;
// Current cost.
Cost cost_;
// The number of uncovered (or free) elements in the current solution.
BaseInt num_uncovered_elements_;
// Current assignment.
// Takes |S| bits.
SubsetBoolVector is_selected_;
// A trace of the decisions, i.e. a list of decisions (subset, Boolean) that
// lead to the current solution.
// Takes at most |S| BaseInts.
std::vector<SetCoverDecision> trace_;
// The coverage of an element is the number of used subsets which contains
// the said element.
// Takes |E| BaseInts
ElementToIntVector coverage_;
// A vector that for each subset gives the number of free elements, i.e.
// elements whose coverage is 0.
// problem.
// Takes |S| BaseInts.
SubsetToIntVector num_free_elements_;
// Counts the number of free or exactly covered elements, i.e. whose coverage
// is 0 or 1.
// Takes at most |S| BaseInts. (More likely a few percent of that).
SubsetToIntVector num_non_overcovered_elements_;
// True if the subset is redundant, i.e. can be removed from the solution
// without making it infeasible.
// Takes |S| bits.
SubsetBoolVector is_redundant_;
// Subsets that became removable after the last update.
// Takes at most |S| BaseInts. (More likely a few percent of that).
std::vector<SubsetIndex> newly_removable_subsets_;
// Subsets that became non removable after the last update.
// Takes at most |S| BaseInts. (More likely a few percent of that).
std::vector<SubsetIndex> newly_non_removable_subsets_;
// Denotes the consistency level of the invariant.
// Some algorithms may need to recompute the invariant to a higher consistency
// level.
// TODO(user): think of making the enforcement of the consistency level
// automatic at the constructor level of the heuristic algorithms.
ConsistencyLevel consistency_level_;
};
} // namespace operations_research
#endif // OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_