forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathset_cover_invariant.h
209 lines (160 loc) · 8.22 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
// 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 <sys/types.h>
#include <vector>
#include "absl/types/span.h"
#include "ortools/algorithms/set_cover.pb.h"
#include "ortools/algorithms/set_cover_model.h"
namespace operations_research {
using SubsetCountVector = glop::StrictITIVector<SubsetIndex, int>;
using SubsetBoolVector = glop::StrictITIVector<SubsetIndex, bool>;
// 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_, the number of times an elememt is covered;
// marginal_impacts_, the number of elements of a subset still uncovered;
// is_removable_, whether a subset can be removed from the solution.
// Note that is_removable_[subset] implies is_selected_[subset], and thus
// (is_removable_[subset] <= is_selected_[subset]) == true.
class SetCoverInvariant {
public:
// Constructs an empty weighted set covering solver state.
// The model may not change after the ledger 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();
// Recomputes all the invariants for the current solution.
void MakeDataConsistent() {
cost_ = ComputeCost(is_selected_);
coverage_ = ComputeCoverage(is_selected_);
is_removable_ = ComputeIsRemovable(coverage_);
marginal_impacts_ = ComputeMarginalImpacts(coverage_);
num_elements_covered_ = ComputeNumElementsCovered(coverage_);
}
// Returns the weighted set covering model to which the state applies.
SetCoverModel* model() const { return model_; }
// Returns the cost of current solution.
Cost cost() const { return cost_; }
// 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 SubsetToElementVector& marginal_impacts() const {
return marginal_impacts_;
}
// Returns vector containing number of subsets covering each element.
const ElementToSubsetVector& coverage() const { return coverage_; }
// Returns vector of Booleans telling whether each subset can be removed from
// the solution.
const SubsetBoolVector& is_removable() const { return is_removable_; }
// Returns the number of elements covered.
ElementIndex num_elements_covered() const { return num_elements_covered_; }
// Stores the solution and recomputes the data in the ledger.
void LoadSolution(const SubsetBoolVector& c);
// Returns true if the data stored in the ledger is consistent.
bool CheckConsistency() const;
// Computes is_removable_ from scratch for every subset.
// TODO(user): reconsider exposing this.
void RecomputeIsRemovable() { is_removable_ = ComputeIsRemovable(coverage_); }
// Returns the subsets that share at least one element with subset.
// TODO(user): is it worth to precompute this?
std::vector<SubsetIndex> ComputeImpactedSubsets(SubsetIndex subset) const;
// Toggles is_selected_[subset] to value, and incrementally updates the
// ledger.
// Returns a vector of subsets impacted by the change, in case they need
// to be reconsidered in a solution geneator or a local search algorithm.
// Calls UnsafeToggle, with the added checks:
// If value is true, DCHECKs that subset is removable.
// If value is true, DCHECKs that marginal impact of subset is removable.
std::vector<SubsetIndex> Toggle(SubsetIndex subset, bool value);
// Same as Toggle, with less DCHECKS.
// Useful for some meta-heuristics that allow to go through infeasible
// solutions.
// Only checks that value is different from is_selected_[subset].
std::vector<SubsetIndex> UnsafeToggle(SubsetIndex subset, bool value);
// Update coverage_ for subset when setting is_selected_[subset] to value.
void UpdateCoverage(SubsetIndex subset, bool value);
// Returns true if the elements selected in the current solution cover all
// the elements of the set.
bool CheckSolution() const;
// Checks that coverage_ and marginal_impacts_ are consistent with choices.
bool CheckCoverageAndMarginalImpacts(const SubsetBoolVector& choices) const;
// Returns the subsets that are unused that could be used to cover the still
// uncovered subsets.
std::vector<SubsetIndex> ComputeSettableSubsets() const;
std::vector<SubsetIndex> ComputeResettableSubsets() const;
// Returns the current solution as a proto.
SetCoverSolutionResponse ExportSolutionAsProto() const;
// Imports the solution from a proto.
void ImportSolutionFromProto(const SetCoverSolutionResponse& message);
private:
// Recomputes the cost from scratch from c.
Cost ComputeCost(const SubsetBoolVector& c) const;
// Computes is_removable based on a coverage cvrg.
SubsetBoolVector ComputeIsRemovable(const ElementToSubsetVector& cvrg) const;
// Computes marginal impacts based on a coverage cvrg.
SubsetToElementVector ComputeMarginalImpacts(
const ElementToSubsetVector& cvrg) const;
// Updates marginal_impacts_ for each subset in impacted_subsets.
void UpdateMarginalImpacts(absl::Span<const SubsetIndex> impacted_subsets);
// Computes the number of elements covered based on coverage vector 'cvrg'.
ElementIndex ComputeNumElementsCovered(
const ElementToSubsetVector& cvrg) const;
// Returns true if subset can be removed from the solution, i.e. it is
// redundant to cover all the elements.
// This function is used to check that is_removable[subset] is consistent.
bool ComputeIsRemovable(SubsetIndex subset) const;
// Updates is_removable_ for each subset in impacted_subsets.
void UpdateIsRemovable(absl::Span<const SubsetIndex> impacted_subsets);
// Returns the number of elements currently covered by subset.
ElementToSubsetVector ComputeSingleSubsetCoverage(SubsetIndex subset) const;
// Returns a vector containing the number of subsets covering each element.
ElementToSubsetVector ComputeCoverage(const SubsetBoolVector& choices) const;
// Checks that the value of coverage_ is correct by recomputing and comparing.
bool CheckSingleSubsetCoverage(SubsetIndex subset) const;
// Checks that coverage_ is consistent with choices.
bool CheckCoverageAgainstSolution(const SubsetBoolVector& choices) const;
// Returns true if is_removable_ is consistent.
bool CheckIsRemovable() const;
// The weighted set covering model on which the solver is run.
SetCoverModel* model_;
// Current cost.
Cost cost_;
// The number of elements covered in the current solution.
ElementIndex num_elements_covered_;
// Current assignment.
SubsetBoolVector is_selected_;
// The marginal impact of a subset is the number of elements in that subset
// that are not covered in the current solution.
SubsetToElementVector marginal_impacts_;
// The coverage of an element is the number of used subsets which contains
// the said element.
ElementToSubsetVector coverage_;
// True if the subset can be removed from the solution without making it
// infeasible.
SubsetBoolVector is_removable_;
};
} // namespace operations_research
#endif // OR_TOOLS_ALGORITHMS_SET_COVER_INVARIANT_H_