Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
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_ORTOOLS_SET_COVER_VIEWS_H
15#define OR_TOOLS_ORTOOLS_SET_COVER_VIEWS_H
16
17#include <absl/meta/type_traits.h>
18#include <absl/types/span.h>
19
20#include <cstddef>
21
23
24// NOTE: It may be unexpected, but views provide a subscript operator that
25// directly accesses the underlying original container using the original
26// indices. This behavior is particularly relevant in the context of the Set
27// Cover problem, where we often work with subsets of columns or rows. Despite
28// this, each column or row still contains the original indices, which are
29// used for referring to other columns/rows.
30//
31// This design abstracts access to the underlying container, ensuring consistent
32// behavior across the following scenarios:
33// 1. Directly using the original container.
34// 2. Accessing a subset of the original items via a view.
35// 3. Using a new container with a compacted subset of items, indexing them with
36// the position the have in the new container and not in the original one.
37// This also need the old indices stored in rows/columns to be mapped into
38// the new ones.
39
40namespace util_intops {
41
42namespace util {
43
44template <typename RangeT>
46 absl::remove_cvref_t<decltype(std::declval<const RangeT>().begin())>;
47template <typename RangeT>
48using range_value_type = absl::remove_cvref_t<
49 decltype(*std::declval<range_const_iterator_type<RangeT>>())>;
50
51// Enable compatibility with STL algorithms.
52template <typename IterT, typename ValueT>
54 using iterator_category = std::input_iterator_tag;
55 using value_type = ValueT;
56 using difference_type = std::ptrdiff_t;
57 using pointer = IterT;
59 bool operator==(const IterT& other) const {
60 return !(*static_cast<const IterT*>(this) != other);
61 }
62 pointer operator->() const { return static_cast<const IterT*>(this); }
63};
64
65template <typename ValueRangeT, typename IndexT>
66decltype(auto) at(const ValueRangeT* container, IndexT index) {
67 DCHECK(IndexT(0) <= index && index < IndexT(container->size()));
68 return (*container)[index];
69}
70
71} // namespace util
72
73// View exposing only the indices of a container that are marked as active.
74// Looping over this view is equivalent to:
75//
76// for (IntT index; index < IntT<is_active_->size()); ++index) {
77// if (is_active[index]) {
78// your_code(index);
79// }
80// }
81//
82template <typename IntT, typename EnableVectorT>
84 public:
86 : util::IteratorCRTP<FilterIndicesViewIterator, IntT> {
87 FilterIndicesViewIterator(IntT index, const EnableVectorT* is_active)
88 : index_(index), is_active_(is_active) {
89 AdjustToValidValue();
90 std::vector<bool> vb;
91 }
93 return index_ != other.index_;
94 }
96 ++index_;
97 AdjustToValidValue();
98 return *this;
99 }
100 IntT operator*() const { return index_; }
101
102 private:
103 void AdjustToValidValue() {
104 while (index_ < IntT(is_active_->size()) &&
105 !util::at(is_active_, index_)) {
106 ++index_;
107 }
108 }
109
110 IntT index_;
111 const EnableVectorT* is_active_;
112 };
113
114 FilterIndexRangeView(const EnableVectorT* is_active)
115 : is_active_(is_active) {}
117 return FilterIndicesViewIterator(IntT(0), is_active_);
118 }
120 return FilterIndicesViewIterator(IntT(is_active_->size()), is_active_);
121 }
122
123 private:
124 const EnableVectorT* is_active_;
125};
126
127// View exposing only the elements of a container that are indexed by a list of
128// indices.
129// Looping over this view is equivalent to:
130//
131// for (decltype(auto) index : indices) {
132// your_code(container[index]);
133// }
134//
135template <typename ValueT, typename IndexT>
137 public:
138 using value_type = const ValueT;
139 using index_type = const IndexT;
140 using value_iterator = typename absl::Span<value_type>::iterator;
141 using index_iterator = typename absl::Span<index_type>::iterator;
142
144 : util::IteratorCRTP<IndexListViewIterator, value_type> {
145 IndexListViewIterator(absl::Span<value_type> values, index_iterator iter)
146 : values_(values), index_iter_(iter) {}
147 bool operator!=(const IndexListViewIterator& other) const {
148 DCHECK_EQ(values_.data(), other.values_.data());
149 return index_iter_ != other.index_iter_;
150 }
152 ++index_iter_;
153 return *this;
154 }
155 decltype(auto) operator*() const {
156 return values_[static_cast<size_t>(*index_iter_)];
157 }
158
159 private:
160 absl::Span<value_type> values_;
161 index_iterator index_iter_;
162 };
163
164 IndexListView() = default;
165
166 template <typename ValueRangeT, typename IndexRangeT>
167 IndexListView(const ValueRangeT* values, const IndexRangeT* indices)
168 : values_(absl::MakeConstSpan(*values)),
169 indices_(absl::MakeConstSpan(*indices)) {}
170
171 auto size() const { return indices_.size(); }
172 bool empty() const { return indices_.empty(); }
173
174 // NOTE: uses indices of the original container, not the filtered one
175 decltype(auto) operator[](index_type index) const {
176 // TODO(user): we could check that index is in indices_, but that's is O(n).
177 return values_[static_cast<size_t>(index)];
178 }
180 return IndexListViewIterator(values_, indices_.begin());
181 }
183 return IndexListViewIterator(values_, indices_.end());
184 }
185 absl::Span<value_type> base() const { return values_; }
186
187 private:
188 absl::Span<value_type> values_;
189 absl::Span<index_type> indices_;
190};
191
192// This view provides access to elements of a container of integral types, which
193// are used as indices to a filter (in) vector.
194// The view filters and returns only those elements that, when used a subscript
195// to the filter vector, are evaluated to a true value.
196// Looping over this view is equivalent to:
197//
198// for (decltype(auto) item : container) {
199// if (is_active[item]) {
200// your_code(iter);
201// }
202// }
203//
204template <typename ValueT, typename EnableVectorT>
206 public:
207 using value_type = const ValueT;
208 using value_iterator = typename absl::Span<value_type>::iterator;
209
211 : util::IteratorCRTP<ValueFilterViewIterator, value_type> {
213 const EnableVectorT* is_active)
214 : iterator_(iterator), end_(end), is_active_(is_active) {
215 AdjustToValidValue();
216 }
217 bool operator!=(const ValueFilterViewIterator& other) const {
218 DCHECK_EQ(is_active_, other.is_active_);
219 return iterator_ != other.iterator_;
220 }
222 ++iterator_;
223 AdjustToValidValue();
224 return *this;
225 }
226 decltype(auto) operator*() const { return *iterator_; }
227
228 private:
229 void AdjustToValidValue() {
230 while (iterator_ != end_ && !util::at(is_active_, *iterator_)) {
231 ++iterator_;
232 }
233 }
234
235 value_iterator iterator_;
236 value_iterator end_;
237 const EnableVectorT* is_active_;
238 };
239
240 template <typename ValueRangeT>
241 ValueFilterView(const ValueRangeT* values, const EnableVectorT* is_active)
242 : values_(absl::MakeConstSpan(*values)), is_active_(is_active) {
243 DCHECK(values != nullptr);
244 DCHECK(is_active != nullptr);
245 }
246 ValueFilterViewIterator begin() const {
247 return ValueFilterViewIterator(values_.begin(), values_.end(), is_active_);
248 }
249 ValueFilterViewIterator end() const {
250 return ValueFilterViewIterator(values_.end(), values_.end(), is_active_);
251 }
252
253 // NOTE: uses indices of the original container, not the filtered one
254 template <typename IndexT>
255 decltype(auto) operator[](IndexT index) const {
256 decltype(auto) value = values_[static_cast<size_t>(index)];
257 DCHECK(util::at(is_active_, value))
258 << "Inactive value. Are you using relative indices?";
259 return value;
260 }
261 absl::Span<value_type> base() const { return values_; }
262
263 private:
264 absl::Span<value_type> values_;
265 const EnableVectorT* is_active_;
266};
267
268// Somewhat equivalent to ValueFilterView<StrongIntRange, EnableVectorT>
269// Looping over this view is equivalent to:
270//
271// auto c_it = container.begin();
272// auto active_it = is_active.begin();
273// for (; active_it != is_active.end(); ++active_it, ++c_it) {
274// if (*active_it) {
275// your_code(*c_it);
276// }
277// }
278//
279template <typename ValueT, typename EnableVectorT>
281 public:
282 using value_type = const ValueT;
283 using value_iterator = typename absl::Span<value_type>::iterator;
285
287 : util::IteratorCRTP<IndexFilterViewIterator, value_type> {
289 enable_iterator is_active_begin,
290 enable_iterator is_active_end)
291 : iterator_(iterator),
292 is_active_iter_(is_active_begin),
293 is_active_end_(is_active_end) {
294 AdjustToValidValue();
295 }
296 bool operator!=(const IndexFilterViewIterator& other) const {
297 DCHECK(is_active_end_ == other.is_active_end_);
298 return iterator_ != other.iterator_;
299 }
301 ++is_active_iter_;
302 ++iterator_;
303 AdjustToValidValue();
304 return *this;
305 }
306 decltype(auto) operator*() const { return *iterator_; }
307
308 private:
309 void AdjustToValidValue() {
310 while (is_active_iter_ != is_active_end_ && !*is_active_iter_) {
311 ++is_active_iter_;
312 ++iterator_;
313 }
314 }
315
316 value_iterator iterator_;
317 enable_iterator is_active_iter_;
318 enable_iterator is_active_end_;
319 };
320
321 template <typename ValueRangeT>
322 IndexFilterView(const ValueRangeT* values, const EnableVectorT* is_active_)
323 : values_(absl::MakeConstSpan(*values)), is_active_(is_active_) {
324 DCHECK(values != nullptr);
325 DCHECK(is_active_ != nullptr);
326 DCHECK_EQ(values->size(), is_active_->size());
327 }
329 return IndexFilterViewIterator(values_.begin(), is_active_->begin(),
330 is_active_->end());
331 }
333 return IndexFilterViewIterator(values_.end(), is_active_->end(),
334 is_active_->end());
335 }
336 absl::Span<value_type> base() const { return values_; }
337
338 // NOTE: uses indices of the original container, not the filtered one
339 template <typename IndexT>
340 decltype(auto) operator[](IndexT index) const {
341 DCHECK(util::at(is_active_, index))
342 << "Inactive value. Are you using relative indices?";
343 return values_[static_cast<size_t>(index)];
344 }
345
346 private:
347 absl::Span<value_type> values_;
348 const EnableVectorT* is_active_;
349};
350
351// This view provides a mechanism to access and filter elements in a 2D
352// container. The filtering is applied in two stages:
353// 1. The first dimension is generic and can be both and index-list or
354// bool-vector based view.
355// 2. The second dimension (items of each sub-container) is further filtered
356// using a boolean-vector-like object, which determines which elements within
357// the sub-container are included in the view.
358template <typename Lvl1ViewT, typename EnableVectorT>
359class TwoLevelsView : public Lvl1ViewT {
360 public:
365
367 : util::IteratorCRTP<TwoLevelsViewIterator, level2_type> {
369 const EnableVectorT* active_items)
370 : iter_(iter), active_items_(active_items) {}
371 bool operator!=(const TwoLevelsViewIterator& other) const {
372 DCHECK_EQ(active_items_, other.active_items_);
373 return iter_ != other.iter_;
374 }
376 ++iter_;
377 return *this;
378 }
380 return level2_type(&(*iter_), active_items_);
381 }
382 const Lvl1ViewT& base() const { return *this; }
383
384 private:
385 level1_iterator iter_;
386 const EnableVectorT* active_items_;
387 };
388
389 TwoLevelsView() = default;
390 TwoLevelsView(Lvl1ViewT lvl1_view, const EnableVectorT* active_items)
391 : Lvl1ViewT(lvl1_view), active_items_(active_items) {}
393 return TwoLevelsViewIterator(Lvl1ViewT::begin(), active_items_);
394 }
396 return TwoLevelsViewIterator(Lvl1ViewT::end(), active_items_);
397 }
398
399 template <typename indexT>
400 level2_type operator[](indexT i) const {
401 auto& level2_container = Lvl1ViewT::operator[](i);
402 return level2_type(&level2_container, active_items_);
403 }
404
405 private:
406 const EnableVectorT* active_items_;
407};
408
410 template <typename T>
411 T&& operator()(T&& value) const {
412 return std::forward<T>(value);
413 }
414};
415
416template <typename FromT, typename ToT>
418 ToT operator()(FromT value) const { return static_cast<ToT>(value); }
419};
420
421// View applying stateless transformation to the values of a continugous
422// container. Looping over this view is equivalent to:
423//
424// for (IndexT i(0); i < IndexT(container.size()); ++i) {
425// your_code(ValueTransformT()(values_[static_cast<size_t>(i)]));
426// }
427//
428template <typename ValueT, typename IndexT,
429 typename ValueTransformT = NoTransform>
431 public:
432 using value_type = const ValueT;
433 using value_iterator = typename absl::Span<value_type>::iterator;
434
436 : util::IteratorCRTP<TransformViewIterator, value_type> {
437 TransformViewIterator(value_iterator iterator) : iterator_(iterator) {}
438 bool operator!=(const TransformViewIterator& other) const {
439 return iterator_ != other.iterator_;
440 }
442 ++iterator_;
443 return *this;
444 }
445 decltype(auto) operator*() const { return ValueTransformT()(*iterator_); }
446
447 private:
448 value_iterator iterator_;
449 };
450
451 TransformView() = default;
452
453 template <typename ValueRangeT>
454 TransformView(const ValueRangeT* values)
455 : values_(absl::MakeConstSpan(*values)) {}
456
457 auto size() const { return values_.size(); }
458 bool empty() const { return values_.empty(); }
459
460 decltype(auto) operator[](IndexT index) const {
461 return ValueTransformT()(values_[static_cast<size_t>(index)]);
462 }
464 return TransformViewIterator(values_.begin());
465 }
467 return TransformViewIterator(values_.end());
468 }
469 absl::Span<value_type> base() const { return values_; }
470
471 private:
472 absl::Span<value_type> values_;
473};
474
475} // namespace util_intops
476
477#endif /* OR_TOOLS_ORTOOLS_SET_COVER_VIEWS_H */
FilterIndexRangeView(const EnableVectorT *is_active)
Definition views.h:114
FilterIndicesViewIterator end() const
Definition views.h:119
FilterIndicesViewIterator begin() const
Definition views.h:116
IndexFilterViewIterator end() const
Definition views.h:332
IndexFilterViewIterator begin() const
Definition views.h:328
IndexFilterView(const ValueRangeT *values, const EnableVectorT *is_active_)
Definition views.h:322
absl::Span< value_type > base() const
Definition views.h:336
typename absl::Span< value_type >::iterator value_iterator
Definition views.h:283
const ValueT value_type
Definition views.h:282
util::range_const_iterator_type< EnableVectorT > enable_iterator
Definition views.h:284
IndexListViewIterator end() const
Definition views.h:182
typename absl::Span< index_type >::iterator index_iterator
Definition views.h:141
const IndexT index_type
Definition views.h:139
typename absl::Span< value_type >::iterator value_iterator
Definition views.h:140
IndexListViewIterator begin() const
Definition views.h:179
const ValueT value_type
Definition views.h:138
absl::Span< value_type > base() const
Definition views.h:185
IndexListView(const ValueRangeT *values, const IndexRangeT *indices)
Definition views.h:167
TransformViewIterator begin() const
Definition views.h:463
typename absl::Span< value_type >::iterator value_iterator
Definition views.h:433
absl::Span< value_type > base() const
Definition views.h:469
TransformViewIterator end() const
Definition views.h:466
const ValueT value_type
Definition views.h:432
TransformView(const ValueRangeT *values)
Definition views.h:454
ValueFilterView< level2_value, EnableVectorT > level2_type
Definition views.h:364
util::range_const_iterator_type< Lvl1ViewT > level1_iterator
Definition views.h:361
util::range_value_type< level1_value > level2_value
Definition views.h:363
TwoLevelsViewIterator end() const
Definition views.h:395
TwoLevelsViewIterator begin() const
Definition views.h:392
level2_type operator[](indexT i) const
Definition views.h:400
util::range_value_type< Lvl1ViewT > level1_value
Definition views.h:362
TwoLevelsView(Lvl1ViewT lvl1_view, const EnableVectorT *active_items)
Definition views.h:390
ValueFilterViewIterator begin() const
Definition views.h:246
absl::Span< value_type > base() const
Definition views.h:261
ValueFilterViewIterator end() const
Definition views.h:249
const ValueT value_type
Definition views.h:207
typename absl::Span< value_type >::iterator value_iterator
Definition views.h:208
ValueFilterView(const ValueRangeT *values, const EnableVectorT *is_active)
Definition views.h:241
absl::remove_cvref_t< decltype(std::declval< const RangeT >().begin())> range_const_iterator_type
Definition views.h:45
decltype(auto) at(const ValueRangeT *container, IndexT index)
Definition views.h:66
absl::remove_cvref_t< decltype(*std::declval< range_const_iterator_type< RangeT > >())> range_value_type
Definition views.h:48
A collections of i/o utilities for the Graph classes in ./graph.h.
bool operator!=(FilterIndicesViewIterator other) const
Definition views.h:92
FilterIndicesViewIterator(IntT index, const EnableVectorT *is_active)
Definition views.h:87
bool operator!=(const IndexFilterViewIterator &other) const
Definition views.h:296
IndexFilterViewIterator(value_iterator iterator, enable_iterator is_active_begin, enable_iterator is_active_end)
Definition views.h:288
bool operator!=(const IndexListViewIterator &other) const
Definition views.h:147
IndexListViewIterator(absl::Span< value_type > values, index_iterator iter)
Definition views.h:145
T && operator()(T &&value) const
Definition views.h:411
bool operator!=(const TransformViewIterator &other) const
Definition views.h:438
TransformViewIterator(value_iterator iterator)
Definition views.h:437
bool operator!=(const TwoLevelsViewIterator &other) const
Definition views.h:371
TwoLevelsViewIterator(level1_iterator iter, const EnableVectorT *active_items)
Definition views.h:368
ToT operator()(FromT value) const
Definition views.h:418
bool operator!=(const ValueFilterViewIterator &other) const
Definition views.h:217
ValueFilterViewIterator(value_iterator iterator, value_iterator end, const EnableVectorT *is_active)
Definition views.h:212
Enable compatibility with STL algorithms.
Definition views.h:53
std::input_iterator_tag iterator_category
Definition views.h:54
pointer operator->() const
Definition views.h:62
std::ptrdiff_t difference_type
Definition views.h:56
bool operator==(const IterT &other) const
Definition views.h:59