diff --git a/ortools/set_cover/python/set_cover.cc b/ortools/set_cover/python/set_cover.cc index 82d0b4e2f4..46490a9ff2 100644 --- a/ortools/set_cover/python/set_cover.cc +++ b/ortools/set_cover/python/set_cover.cc @@ -72,7 +72,8 @@ using ::py::make_iterator; std::vector VectorIntToVectorSubsetIndex( absl::Span ints) { std::vector subs; - std::transform(ints.begin(), ints.end(), subs.begin(), + subs.reserve(ints.size()); + std::transform(ints.begin(), ints.end(), std::back_inserter(subs), [](int subset) -> SubsetIndex { return SubsetIndex(subset); }); return subs; } @@ -197,17 +198,21 @@ PYBIND11_MODULE(set_cover, m) { return make_iterator<>(IntIterator::begin(model.num_elements()), IntIterator::end(model.num_elements())); }) - .def_property_readonly("all_subsets", - [](SetCoverModel& model) -> std::vector { - std::vector subsets; - std::transform( - model.all_subsets().begin(), - model.all_subsets().end(), subsets.begin(), - [](const SubsetIndex element) -> BaseInt { - return element.value(); - }); - return subsets; - }) + .def_property_readonly( + "all_subsets", + [](SetCoverModel& model) -> std::vector { + // all_subsets() returns by value, so it must be + // bound to a local: calling it twice would give + // begin() and end() of two distinct temporaries. + const std::vector all = model.all_subsets(); + std::vector subsets; + subsets.reserve(all.size()); + std::transform(all.begin(), all.end(), std::back_inserter(subsets), + [](const SubsetIndex element) -> BaseInt { + return element.value(); + }); + return subsets; + }) .def("set_name", &SetCoverModel::SetName) .def("add_empty_subset", &SetCoverModel::AddEmptySubset, arg("cost")) .def( diff --git a/ortools/set_cover/python/set_cover_test.py b/ortools/set_cover/python/set_cover_test.py index 220e2cee51..5832dc430e 100644 --- a/ortools/set_cover/python/set_cover_test.py +++ b/ortools/set_cover/python/set_cover_test.py @@ -222,6 +222,12 @@ def test_knights_cover_trivial(self): inv.check_consistency(set_cover.consistency_level.FREE_AND_UNCOVERED) ) + def test_all_subsets_property(self): + model = create_knights_cover_model(4, 4) + all_subsets = model.all_subsets + self.assertLen(all_subsets, model.num_subsets) + self.assertEqual(all_subsets, list(range(model.num_subsets))) + # TODO(user): KnightsCoverGreedyAndTabu, KnightsCoverGreedyRandomClear, # KnightsCoverElementDegreeRandomClear, KnightsCoverRandomClearMip, # KnightsCoverMip