Google OR-Tools v9.9
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
set_cover_model.cc
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
15
16#include <algorithm>
17#include <cmath>
18
19#include "absl/log/check.h"
20#include "ortools/algorithms/set_cover.pb.h"
22#include "ortools/lp_data/lp_types.h" // For StrictITIVector.
23
24namespace operations_research {
25
26void SetCoverModel::UpdateAllSubsetsList() {
27 const SubsetIndex new_size = columns_.size();
28 const SubsetIndex old_size(all_subsets_.size());
29 DCHECK_LE(old_size, new_size);
30 all_subsets_.resize(new_size.value());
31 for (SubsetIndex subset(old_size); subset < new_size; ++subset) {
32 all_subsets_[subset.value()] = subset;
33 }
34}
35
37 subset_costs_.push_back(cost);
38 columns_.push_back(SparseColumn());
39 const SubsetIndex num_subsets(all_subsets_.size());
40 all_subsets_.push_back(num_subsets);
41 CHECK_EQ(all_subsets_.size(), columns_.size());
42 CHECK_EQ(all_subsets_.size(), subset_costs_.size());
43 row_view_is_valid_ = false;
44}
45
46void SetCoverModel::AddElementToLastSubset(const ElementIndex element) {
47 columns_.back().push_back(element);
48 num_elements_ = std::max(num_elements_, element + 1);
49 // No need to update the list all_subsets_.
50 row_view_is_valid_ = false;
51}
52
54 AddElementToLastSubset(ElementIndex(element));
55}
56
57void SetCoverModel::SetSubsetCost(int subset, Cost cost) {
58 CHECK(std::isfinite(cost));
59 DCHECK_GE(subset, 0);
60 const SubsetIndex subset_index(subset);
61 const SubsetIndex num_subsets = columns_.size();
62 const SubsetIndex new_size = std::max(num_subsets, subset_index + 1);
63 columns_.resize(new_size, SparseColumn());
64 subset_costs_.resize(new_size, 0.0);
65 subset_costs_[subset_index] = cost;
66 UpdateAllSubsetsList();
67 row_view_is_valid_ = false; // Probably overkill, but better safe than sorry.
68}
69
70void SetCoverModel::AddElementToSubset(int element, int subset) {
71 const SubsetIndex subset_index(subset);
72 const SubsetIndex new_size = std::max(columns_.size(), subset_index + 1);
73 subset_costs_.resize(new_size, 0.0);
74 columns_.resize(new_size, SparseColumn());
75 UpdateAllSubsetsList();
76 const ElementIndex new_element(element);
77 columns_[subset_index].push_back(new_element);
78 num_elements_ = std::max(num_elements_, new_element + 1);
79 row_view_is_valid_ = false;
80}
81
82// Reserves num_subsets columns in the model.
83void SetCoverModel::ReserveNumSubsets(int num_subsets) {
84 SubsetIndex size(num_subsets);
85 columns_.resize(size, SparseColumn());
86 subset_costs_.resize(size, 0.0);
87}
88
89// Reserves num_elements rows in the column indexed by subset.
90void SetCoverModel::ReserveNumElementsInSubset(int num_elements, int subset) {
91 const SubsetIndex size = std::max(columns_.size(), SubsetIndex(subset + 1));
92 subset_costs_.resize(size, 0.0);
93 columns_.resize(size, SparseColumn());
94 const EntryIndex num_entries(num_elements);
95 columns_[SubsetIndex(subset)].reserve(num_entries);
96}
97
99 if (row_view_is_valid_) {
100 return;
101 }
102 rows_.resize(num_elements_, SparseRow());
103 glop::StrictITIVector<ElementIndex, int> row_sizes(num_elements_, 0);
104 for (SubsetIndex subset(0); subset < columns_.size(); ++subset) {
105 std::sort(columns_[subset].begin(), columns_[subset].end());
106 for (const ElementIndex element : columns_[subset]) {
107 ++row_sizes[element];
108 }
109 }
110 for (ElementIndex element(0); element < num_elements_; ++element) {
111 rows_[element].reserve(EntryIndex(row_sizes[element]));
112 }
113 for (SubsetIndex subset(0); subset < columns_.size(); ++subset) {
114 for (const ElementIndex element : columns_[subset]) {
115 rows_[element].push_back(subset);
116 }
117 }
118 row_view_is_valid_ = true;
119}
120
122 CHECK_GT(num_elements_, 0);
123 CHECK_GT(columns_.size(), 0);
124 CHECK_EQ(columns_.size(), subset_costs_.size());
125
126 ElementToSubsetVector coverage(num_elements_, SubsetIndex(0));
127 for (const Cost cost : subset_costs_) {
128 CHECK_GT(cost, 0.0);
129 }
130 for (const SparseColumn& column : columns_) {
131 CHECK_GT(column.size(), 0);
132 for (const ElementIndex element : column) {
133 ++coverage[element];
134 }
135 }
136 for (ElementIndex element(0); element < num_elements_; ++element) {
137 CHECK_GE(coverage[element], 0);
138 if (coverage[element] == 0) {
139 return false;
140 }
141 }
142 VLOG(1) << "Max possible coverage = "
143 << *std::max_element(coverage.begin(), coverage.end());
144 for (SubsetIndex subset(0); subset < columns_.size(); ++subset) {
145 CHECK_EQ(all_subsets_[subset.value()], subset) << "subset = " << subset;
146 }
147 return true;
148}
149
151 SetCoverProto message;
152 for (SubsetIndex subset(0); subset < columns_.size(); ++subset) {
153 SetCoverProto::Subset* subset_proto = message.add_subset();
154 subset_proto->set_cost(subset_costs_[subset]);
155 std::sort(columns_[subset].begin(), columns_[subset].end());
156 for (const ElementIndex element : columns_[subset]) {
157 subset_proto->add_element(element.value());
158 }
159 }
160 return message;
161}
162
164 columns_.clear();
165 subset_costs_.clear();
166 ReserveNumSubsets(message.subset_size());
167 SubsetIndex subset_index(0);
168 for (const SetCoverProto::Subset& subset_proto : message.subset()) {
169 subset_costs_[SubsetIndex(subset_index)] = subset_proto.cost();
170 if (subset_proto.element_size() > 0) {
171 columns_[subset_index].reserve(EntryIndex(subset_proto.element_size()));
172 for (auto element : subset_proto.element()) {
173 columns_[subset_index].push_back(ElementIndex(element));
174 num_elements_ =
175 ElementIndex(std::max(num_elements_.value(), element + 1));
176 }
177 ++subset_index;
178 }
179 }
180 UpdateAllSubsetsList();
182}
183
184} // namespace operations_research
void push_back(const value_type &x)
void ImportModelFromProto(const SetCoverProto &message)
Imports the model from a SetCoverProto.
void SetSubsetCost(int subset, Cost cost)
void ReserveNumElementsInSubset(int num_elements, int subset)
Reserves num_elements rows in the column indexed by subset.
void AddElementToSubset(int element, int subset)
Adds 'element' to and already existing 'subset'.
void ReserveNumSubsets(int num_subsets)
Reserves num_subsets columns in the model.
void CreateSparseRowView()
Creates the sparse ("dual") representation of the problem.
In SWIG mode, we don't want anything besides these top-level includes.
glop::StrictITIVector< EntryIndex, ElementIndex > SparseColumn
glop::StrictITIVector< EntryIndex, SubsetIndex > SparseRow
double Cost
Basic non-strict type for cost.
int column
std::optional< int64_t > end
*vec begin()+0)
std::string message
Definition trace.cc:397