Skip to content

Commit 7424711

Browse files
committed
more spans
1 parent dbe123f commit 7424711

File tree

7 files changed

+40
-11
lines changed

7 files changed

+40
-11
lines changed

ortools/algorithms/python/set_cover.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ PYBIND11_MODULE(set_cover, m) {
208208
},
209209
arg("subset"), arg("cost"))
210210
.def("create_sparse_row_view", &SetCoverModel::CreateSparseRowView)
211+
.def("sort_elements_in_subsets", &SetCoverModel::SortElementsInSubsets)
211212
.def("compute_feasibility", &SetCoverModel::ComputeFeasibility)
212213
.def(
213214
"reserve_num_subsets",

ortools/algorithms/python/set_cover_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class SetCoverTest(absltest.TestCase):
5656

5757
def test_save_reload(self):
5858
model = create_knights_cover_model(10, 10)
59+
model.sort_elements_in_subsets()
5960
proto = model.export_model_as_proto()
6061
reloaded = set_cover.SetCoverModel()
6162
reloaded.import_model_from_proto(proto)

ortools/algorithms/set_cover_heuristics.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ bool GreedySolutionGenerator::NextSolution() {
9595
}
9696

9797
bool GreedySolutionGenerator::NextSolution(
98-
const std::vector<SubsetIndex>& focus) {
98+
absl::Span<const SubsetIndex> focus) {
9999
return NextSolution(focus, inv_->model()->subset_costs());
100100
}
101101

ortools/algorithms/set_cover_heuristics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class GreedySolutionGenerator {
122122

123123
// Computes the next partial solution considering only the subsets whose
124124
// indices are in focus.
125-
bool NextSolution(const std::vector<SubsetIndex>& focus);
125+
bool NextSolution(absl::Span<const SubsetIndex> focus);
126126

127127
// Same with a different set of costs.
128128
bool NextSolution(absl::Span<const SubsetIndex> focus,

ortools/algorithms/set_cover_model.cc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ void SetCoverModel::UpdateAllSubsetsList() {
183183
}
184184

185185
void SetCoverModel::AddEmptySubset(Cost cost) {
186+
elements_in_subsets_are_sorted_ = false;
186187
subset_costs_.push_back(cost);
187188
columns_.push_back(SparseColumn());
188189
all_subsets_.push_back(SubsetIndex(num_subsets_));
@@ -194,6 +195,7 @@ void SetCoverModel::AddEmptySubset(Cost cost) {
194195
}
195196

196197
void SetCoverModel::AddElementToLastSubset(BaseInt element) {
198+
elements_in_subsets_are_sorted_ = false;
197199
columns_.back().push_back(ElementIndex(element));
198200
num_elements_ = std::max(num_elements_, element + 1);
199201
// No need to update the list all_subsets_.
@@ -206,6 +208,7 @@ void SetCoverModel::AddElementToLastSubset(ElementIndex element) {
206208
}
207209

208210
void SetCoverModel::SetSubsetCost(BaseInt subset, Cost cost) {
211+
elements_in_subsets_are_sorted_ = false;
209212
CHECK(std::isfinite(cost));
210213
DCHECK_GE(subset, 0);
211214
if (subset >= num_subsets()) {
@@ -223,6 +226,7 @@ void SetCoverModel::SetSubsetCost(SubsetIndex subset, Cost cost) {
223226
}
224227

225228
void SetCoverModel::AddElementToSubset(BaseInt element, BaseInt subset) {
229+
elements_in_subsets_are_sorted_ = false;
226230
if (subset >= num_subsets()) {
227231
num_subsets_ = subset + 1;
228232
subset_costs_.resize(num_subsets_, 0.0);
@@ -264,6 +268,13 @@ void SetCoverModel::ReserveNumElementsInSubset(ElementIndex num_elements,
264268
ReserveNumElementsInSubset(num_elements.value(), subset.value());
265269
}
266270

271+
void SetCoverModel::SortElementsInSubsets() {
272+
for (const SubsetIndex subset : SubsetRange()) {
273+
std::sort(columns_[subset].begin(), columns_[subset].end());
274+
}
275+
elements_in_subsets_are_sorted_ = true;
276+
}
277+
267278
void SetCoverModel::CreateSparseRowView() {
268279
if (row_view_is_valid_) {
269280
return;
@@ -287,6 +298,7 @@ void SetCoverModel::CreateSparseRowView() {
287298
}
288299
}
289300
row_view_is_valid_ = true;
301+
elements_in_subsets_are_sorted_ = true;
290302
}
291303

292304
bool SetCoverModel::ComputeFeasibility() const {
@@ -319,13 +331,15 @@ bool SetCoverModel::ComputeFeasibility() const {
319331
return true;
320332
}
321333

322-
SetCoverProto SetCoverModel::ExportModelAsProto() {
334+
SetCoverProto SetCoverModel::ExportModelAsProto() const {
335+
CHECK(elements_in_subsets_are_sorted_);
323336
SetCoverProto message;
324337
for (const SubsetIndex subset : SubsetRange()) {
325338
SetCoverProto::Subset* subset_proto = message.add_subset();
326339
subset_proto->set_cost(subset_costs_[subset]);
327-
std::sort(columns_[subset].begin(), columns_[subset].end());
328-
for (const ElementIndex element : columns_[subset]) {
340+
SparseColumn column = columns_[subset];
341+
std::sort(column.begin(), column.end());
342+
for (const ElementIndex element : column) {
329343
subset_proto->add_element(element.value());
330344
}
331345
}
@@ -433,8 +447,9 @@ std::vector<T> ComputeDeciles(std::vector<T> values) {
433447
const int kNumDeciles = 10;
434448
std::vector<T> deciles;
435449
deciles.reserve(kNumDeciles);
450+
const float step = values.size() / kNumDeciles;
436451
for (int i = 1; i <= kNumDeciles; ++i) {
437-
const size_t point = values.size() * i / kNumDeciles - 1;
452+
const size_t point = std::max<float>(0, i * step - 1);
438453
std::nth_element(values.begin(), values.begin() + point, values.end());
439454
deciles.push_back(values[point]);
440455
}

ortools/algorithms/set_cover_model.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class SetCoverModel {
109109
num_subsets_(0),
110110
num_nonzeros_(0),
111111
row_view_is_valid_(false),
112+
elements_in_subsets_are_sorted_(false),
112113
subset_costs_(),
113114
columns_(),
114115
rows_(),
@@ -204,7 +205,12 @@ class SetCoverModel {
204205
void AddElementToSubset(BaseInt element, BaseInt subset);
205206
void AddElementToSubset(ElementIndex element, SubsetIndex subset);
206207

207-
// Creates the sparse ("dual") representation of the problem.
208+
// Sorts the elements in each subset. Should be called before exporting the
209+
// model to a proto.
210+
void SortElementsInSubsets();
211+
212+
// Creates the sparse ("dual") representation of the problem. This also sorts
213+
// the elements in each subset.
208214
void CreateSparseRowView();
209215

210216
// Returns true if the problem is feasible, i.e. if the subsets cover all
@@ -220,10 +226,12 @@ class SetCoverModel {
220226
void ReserveNumElementsInSubset(ElementIndex num_elements,
221227
SubsetIndex subset);
222228

223-
// Returns the model as a SetCoverProto. The function is not const because
224-
// the element indices in the columns need to be sorted for the representation
225-
// as a protobuf to be canonical.
226-
SetCoverProto ExportModelAsProto();
229+
// Returns the model as a SetCoverProto. Note that the elements of each subset
230+
// are sorted locally before being exported to the proto. This is done to
231+
// ensure that the proto is deterministic. The function is const because it
232+
// does not modify the model. Therefore, the model as exported by this
233+
// function may be different from the initial model.
234+
SetCoverProto ExportModelAsProto() const;
227235

228236
// Imports the model from a SetCoverProto.
229237
void ImportModelFromProto(const SetCoverProto& message);
@@ -284,6 +292,9 @@ class SetCoverModel {
284292
// True when the SparseRowView is up-to-date.
285293
bool row_view_is_valid_;
286294

295+
// True when the elements in each subset are sorted.
296+
bool elements_in_subsets_are_sorted_;
297+
287298
// Costs for each subset.
288299

289300
SubsetCostVector subset_costs_;

ortools/algorithms/set_cover_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class KnightsCover {
123123

124124
TEST(SetCoverProtoTest, SaveReload) {
125125
SetCoverModel model = KnightsCover(10, 10).model();
126+
model.SortElementsInSubsets();
126127
SetCoverProto proto = model.ExportModelAsProto();
127128
SetCoverModel reloaded;
128129
reloaded.ImportModelFromProto(proto);

0 commit comments

Comments
 (0)