Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
set_cover_views.h
Go to the documentation of this file.
1// Copyright 2025 Francesco Cavaliere
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
14#ifndef OR_TOOLS_SET_COVER_SET_COVER_VIEWS_H
15#define OR_TOOLS_SET_COVER_SET_COVER_VIEWS_H
16
17#include <absl/meta/type_traits.h>
18
21#include "views.h"
22
23namespace operations_research {
24
25// In the CFT algorithm, indices from different models are frequently used,
26// and mixing them can lead to errors. To prevent such mistakes, strong-typed
27// wrappers are employed. There are three available approaches for handling
28// these indices:
29// 1. Full-model strong-typed indices + {Subset,Element}Index for the core model
30// 2. Core-model strong-typed indices + {Subset,Element}Index for the full model
31// 3. Define new strong-typed indices both full-model and core-model
32// Introducing a new set of strong-typed indices, however, can lead to a
33// cascade of code duplication (or template proliferation). It also requires
34// additional "view" boilerplate to properly handle the different types,
35// increasing complexity.
36// Currently, the simplest approach is to define only full-model indices while
37// reusing the original strong types for the core model. The main challenge
38// arises in FullToCoreModel, where a "filtered" full-model must be handled. In
39// such cases, static casts are employed to manage the type conversions
40// effectively.
43
44// Syntactic sugar to define strong typed indices casts.
45// Note: look at `strong_int.h` for more details about `StrongIntConvert`
46#define ENABLE_EXPLICIT_STRONG_TYPE_CAST(FROM, TO) \
47 constexpr TO StrongIntConvert(FROM j, TO* /*unused*/) { \
48 return TO(static_cast<FROM::ValueType>(j)); \
49 }
50
51ENABLE_EXPLICIT_STRONG_TYPE_CAST(SubsetIndex, FullSubsetIndex);
52ENABLE_EXPLICIT_STRONG_TYPE_CAST(FullSubsetIndex, SubsetIndex);
53ENABLE_EXPLICIT_STRONG_TYPE_CAST(ElementIndex, FullElementIndex);
54ENABLE_EXPLICIT_STRONG_TYPE_CAST(FullElementIndex, ElementIndex);
55
64
65// When a sub-model is created, indicies are compacted to be consecutive and
66// strarting from 0 (to reduce memory usage). Core ElementIndex to original
67// ElementIndex mappings are stored to translate back to the original model
68// space.
73
74// The same applies to SubsetIndex, which also needs to be mapped back to the
75// original indexing space.
80
82 private:
83 // Transformations to convert between the core and full model columns.
84 struct SparseColTransform {
85 auto operator()(const SparseColumn& column) const
87 ElementIndex, ColumnEntryIndex,
89 return {&column};
90 }
91 };
92
93 // Transformations to convert between the core and full model rows.
94 struct SparseRowTransform {
95 auto operator()(const SparseRow& row) const -> util_intops::TransformView<
96 SubsetIndex, RowEntryIndex,
98 return {&row};
99 }
100 };
101
102 public:
103 StrongModelView() = default;
104 StrongModelView(const SetCoverModel* model) : model_(model) {}
105
106 BaseInt num_subsets() const { return model_->num_subsets(); }
107 BaseInt num_elements() const { return model_->num_elements(); }
108
109 auto subset_costs() const
110 -> util_intops::TransformView<Cost, FullSubsetIndex> {
111 return {&model_->subset_costs()};
112 }
113 auto columns() const
114 -> util_intops::TransformView<SparseColumn, FullSubsetIndex,
115 SparseColTransform> {
116 return {&model_->columns()};
117 }
118 auto rows() const -> util_intops::TransformView<SparseRow, FullElementIndex,
119 SparseRowTransform> {
120 return {&model_->rows()};
121 }
122 auto SubsetRange() const -> util_intops::StrongIntRange<FullSubsetIndex> {
123 return {FullSubsetIndex(), FullSubsetIndex(num_subsets())};
124 }
125 auto ElementRange() const -> util_intops::StrongIntRange<FullElementIndex> {
126 return {FullElementIndex(), FullElementIndex(num_elements())};
127 }
128 const SetCoverModel& base() const { return *model_; }
129
130 private:
131 const SetCoverModel* model_;
132};
133
135 public:
138 const SubsetToIntVector* cols_sizes,
139 const ElementToIntVector* rows_sizes,
140 const std::vector<SubsetIndex>* cols_focus,
141 const std::vector<ElementIndex>* rows_focus)
142 : model_(model),
143 cols_sizes_(cols_sizes),
144 rows_sizes_(rows_sizes),
145 cols_focus_(cols_focus),
146 rows_focus_(rows_focus) {}
147
148 BaseInt num_subsets() const { return model_->num_subsets(); }
149 BaseInt num_elements() const { return model_->num_elements(); }
150 BaseInt num_focus_subsets() const { return cols_focus_->size(); }
151 BaseInt num_focus_elements() const { return rows_focus_->size(); }
152
153 auto subset_costs() const -> util_intops::IndexListView<Cost, SubsetIndex> {
154 return {&model_->subset_costs(), cols_focus_};
155 }
156 auto columns() const -> util_intops::TwoLevelsView<
157 util_intops::IndexListView<SparseColumn, SubsetIndex>,
159 return {{&model_->columns(), cols_focus_}, rows_sizes_};
160 }
161 auto rows() const -> util_intops::TwoLevelsView<
162 util_intops::IndexListView<SparseRow, ElementIndex>, SubsetToIntVector> {
163 return {{&model_->rows(), rows_focus_}, cols_sizes_};
164 }
165 const std::vector<SubsetIndex>& SubsetRange() const { return *cols_focus_; }
166 const std::vector<ElementIndex>& ElementRange() const { return *rows_focus_; }
167 FullElementIndex MapCoreToFullElementIndex(ElementIndex core_i) const {
168 DCHECK(ElementIndex() <= core_i && core_i < ElementIndex(num_elements()));
169 return static_cast<FullElementIndex>(core_i);
170 }
171 ElementIndex MapFullToCoreElementIndex(FullElementIndex full_i) const {
172 DCHECK(FullElementIndex() <= full_i &&
173 full_i < FullElementIndex(num_elements()));
174 return static_cast<ElementIndex>(full_i);
175 }
176 FullSubsetIndex MapCoreToFullSubsetIndex(SubsetIndex core_j) const {
177 DCHECK(SubsetIndex() <= core_j && core_j < SubsetIndex(num_subsets()));
178 return static_cast<FullSubsetIndex>(core_j);
179 }
180 BaseInt column_size(SubsetIndex j) const {
181 DCHECK(SubsetIndex() <= j && j < SubsetIndex(num_subsets()));
182 return (*cols_sizes_)[j];
183 }
184 BaseInt row_size(ElementIndex i) const {
185 DCHECK(ElementIndex() <= i && i < ElementIndex(num_elements()));
186 return (*rows_sizes_)[i];
187 }
188 const SetCoverModel& base() const { return *model_; }
189
190 private:
191 const SetCoverModel* model_;
192 const SubsetToIntVector* cols_sizes_;
193 const ElementToIntVector* rows_sizes_;
194 const std::vector<SubsetIndex>* cols_focus_;
195 const std::vector<ElementIndex>* rows_focus_;
196};
197
198// A lightweight sub-model view that uses boolean vectors to enable or disable
199// specific items. Iterating over all active columns or rows is less efficient,
200// particularly when only a small subset is active.
201// NOTE: this view does **not** store any size-related information.
203 public:
204 FilterModelView() = default;
206 const SubsetBoolVector* cols_sizes,
207 const ElementBoolVector* rows_sizes, BaseInt num_subsets,
209 : model_(model),
210 is_focus_col_(cols_sizes),
211 is_focus_row_(rows_sizes),
212 num_subsets_(num_subsets),
213 num_elements_(num_elements) {}
214
215 BaseInt num_subsets() const { return model_->num_subsets(); }
216 BaseInt num_elements() const { return model_->num_elements(); }
217 BaseInt num_focus_subsets() const { return num_subsets_; }
218 BaseInt num_focus_elements() const { return num_elements_; }
219
220 auto subset_costs() const
221 -> util_intops::IndexFilterView<Cost, SubsetBoolVector> {
222 return {&model_->subset_costs(), is_focus_col_};
223 }
224 auto columns() const -> util_intops::TwoLevelsView<
225 util_intops::IndexFilterView<SparseColumn, SubsetBoolVector>,
227 return {{&model_->columns(), is_focus_col_}, is_focus_row_};
228 }
229 auto rows() const -> util_intops::TwoLevelsView<
230 util_intops::IndexFilterView<SparseRow, ElementBoolVector>,
232 return {{&model_->rows(), is_focus_row_}, is_focus_col_};
233 }
234 auto SubsetRange() const
235 -> util_intops::FilterIndexRangeView<SubsetIndex, SubsetBoolVector> {
236 return {is_focus_col_};
237 }
238 auto ElementRange() const
239 -> util_intops::FilterIndexRangeView<ElementIndex, ElementBoolVector> {
240 return {is_focus_row_};
241 }
242 bool IsFocusCol(SubsetIndex j) const { return (*is_focus_col_)[j]; }
243 bool IsFocusRow(ElementIndex i) const { return (*is_focus_row_)[i]; }
244
245 const SetCoverModel& base() const { return *model_; }
246
247 private:
248 const SetCoverModel* model_;
249 const SubsetBoolVector* is_focus_col_;
250 const ElementBoolVector* is_focus_row_;
251 BaseInt num_subsets_;
252 BaseInt num_elements_;
253};
254
255} // namespace operations_research
256
257#endif /* OR_TOOLS_SET_COVER_SET_COVER_VIEWS_H */
auto ElementRange() const -> util_intops::FilterIndexRangeView< ElementIndex, ElementBoolVector >
const SetCoverModel & base() const
bool IsFocusCol(SubsetIndex j) const
auto columns() const -> util_intops::TwoLevelsView< util_intops::IndexFilterView< SparseColumn, SubsetBoolVector >, ElementBoolVector >
FilterModelView(const SetCoverModel *model, const SubsetBoolVector *cols_sizes, const ElementBoolVector *rows_sizes, BaseInt num_subsets, BaseInt num_elements)
bool IsFocusRow(ElementIndex i) const
auto rows() const -> util_intops::TwoLevelsView< util_intops::IndexFilterView< SparseRow, ElementBoolVector >, SubsetBoolVector >
auto SubsetRange() const -> util_intops::FilterIndexRangeView< SubsetIndex, SubsetBoolVector >
auto subset_costs() const -> util_intops::IndexFilterView< Cost, SubsetBoolVector >
BaseInt column_size(SubsetIndex j) const
auto columns() const -> util_intops::TwoLevelsView< util_intops::IndexListView< SparseColumn, SubsetIndex >, ElementToIntVector >
const SetCoverModel & base() const
FullSubsetIndex MapCoreToFullSubsetIndex(SubsetIndex core_j) const
IndexListModelView(const SetCoverModel *model, const SubsetToIntVector *cols_sizes, const ElementToIntVector *rows_sizes, const std::vector< SubsetIndex > *cols_focus, const std::vector< ElementIndex > *rows_focus)
FullElementIndex MapCoreToFullElementIndex(ElementIndex core_i) const
BaseInt row_size(ElementIndex i) const
auto rows() const -> util_intops::TwoLevelsView< util_intops::IndexListView< SparseRow, ElementIndex >, SubsetToIntVector >
const std::vector< ElementIndex > & ElementRange() const
auto subset_costs() const -> util_intops::IndexListView< Cost, SubsetIndex >
const std::vector< SubsetIndex > & SubsetRange() const
ElementIndex MapFullToCoreElementIndex(FullElementIndex full_i) const
Main class for describing a weighted set-covering problem.
auto rows() const -> util_intops::TransformView< SparseRow, FullElementIndex, SparseRowTransform >
auto SubsetRange() const -> util_intops::StrongIntRange< FullSubsetIndex >
auto ElementRange() const -> util_intops::StrongIntRange< FullElementIndex >
StrongModelView(const SetCoverModel *model)
auto subset_costs() const -> util_intops::TransformView< Cost, FullSubsetIndex >
const SetCoverModel & base() const
auto columns() const -> util_intops::TransformView< SparseColumn, FullSubsetIndex, SparseColTransform >
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< FullElementIndex, BaseInt > FullElementToIntVector
util_intops::StrongVector< SubsetIndex, FullSubsetIndex > CoreToFullSubsetMapVector
util_intops::StrongVector< FullSubsetIndex, SubsetIndex > FullToCoreSubsetMapVector
util_intops::StrongVector< RowEntryIndex, SubsetIndex > SparseRow
Definition base_types.h:62
util_intops::StrongVector< FullElementIndex, ElementIndex > FullToCoreElementMapVector
util_intops::StrongVector< FullElementIndex, Cost > FullElementCostVector
util_intops::StrongVector< ElementIndex, FullElementIndex > CoreToFullElementMapVector
util_intops::StrongVector< FullSubsetIndex, bool > FullSubsetBoolVector
util_intops::StrongVector< FullSubsetIndex, BaseInt > FullSubsetToIntVector
util_intops::StrongVector< SubsetIndex, BaseInt > SubsetToIntVector
Definition base_types.h:65
util_intops::StrongVector< FullSubsetIndex, Cost > FullSubsetCostVector
util_intops::StrongVector< ElementIndex, BaseInt > ElementToIntVector
Definition base_types.h:64
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
Definition base_types.h:71
util_intops::StrongVector< FullElementIndex, bool > FullElementBoolVector
util_intops::StrongVector< ElementIndex, bool > ElementBoolVector
Definition base_types.h:72
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.
Definition base_types.h:32
util_intops::StrongVector< ColumnEntryIndex, ElementIndex > SparseColumn
Definition base_types.h:61
#define ENABLE_EXPLICIT_STRONG_TYPE_CAST(FROM, TO)
#define DEFINE_STRONG_INT_TYPE(type_name, value_type)