Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
sorted_interval_list.h
Go to the documentation of this file.
1// Copyright 2010-2025 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
14#ifndef OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
15#define OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
16
17#include <cstdint>
18#include <iterator>
19#include <ostream>
20#include <set>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/container/inlined_vector.h"
26#include "absl/types/span.h"
28
29namespace operations_research {
30
36 ClosedInterval(int64_t s, int64_t e) : start(s), end(e) {
37 DLOG_IF(DFATAL, s > e) << "Invalid ClosedInterval(" << s << ", " << e
38 << ")";
39 }
40
41 std::string DebugString() const;
42 bool operator==(const ClosedInterval& other) const {
43 return start == other.start && end == other.end;
44 }
45
46 // Because we mainly manipulate vector of disjoint intervals, we only need to
47 // sort by the start. We do not care about the order in which interval with
48 // the same start appear since they will always be merged into one interval.
49 bool operator<(const ClosedInterval& other) const {
50 return start < other.start;
51 }
52
53 template <typename H>
54 friend H AbslHashValue(H h, const ClosedInterval& interval) {
55 return H::combine(std::move(h), interval.start, interval.end);
56 }
57
58 int64_t start = 0; // Inclusive.
59 int64_t end = 0; // Inclusive.
60};
61
62std::ostream& operator<<(std::ostream& out, const ClosedInterval& interval);
63std::ostream& operator<<(std::ostream& out,
64 const std::vector<ClosedInterval>& intervals);
65
75 absl::Span<const ClosedInterval> intervals);
76
87class Domain {
88 public:
90 Domain() {}
91
92#if !defined(SWIG)
94 Domain(const Domain& other) : intervals_(other.intervals_) {}
95
97 Domain& operator=(const Domain& other) {
98 intervals_ = other.intervals_;
99 return *this;
100 }
101
103 Domain(Domain&& other) noexcept : intervals_(std::move(other.intervals_)) {}
104
106 Domain& operator=(Domain&& other) noexcept {
107 intervals_ = std::move(other.intervals_);
108 return *this;
109 }
110#endif // !defined(SWIG)
111
113 explicit Domain(int64_t value);
114
119 Domain(int64_t left, int64_t right);
120
124 static Domain AllValues();
125
130 static Domain FromValues(std::vector<int64_t> values);
131
138 static Domain FromIntervals(absl::Span<const ClosedInterval> intervals);
139
148 absl::Span<const int64_t> flat_intervals);
149
162 const std::vector<std::vector<int64_t> >& intervals);
163
172 static Domain FromFlatIntervals(const std::vector<int64_t>& flat_intervals);
173
181 std::vector<int64_t> FlattenedIntervals() const;
182
183#if !defined(SWIG)
192 public:
194 const absl::InlinedVector<ClosedInterval, 1>& intervals)
195 : value_(intervals.empty() ? int64_t{0} : intervals.front().start),
196 it_(intervals.begin()),
197 end_(intervals.end()) {}
198
199 int64_t operator*() const { return value_; }
200
201 void operator++() {
202 if (value_ == it_->end) {
203 ++it_;
204 if (it_ != end_) value_ = it_->start;
205 } else {
206 ++value_;
207 }
208 }
209
211 absl::InlinedVector<ClosedInterval, 1>::const_iterator end) const {
212 return it_ != end;
213 }
214
215 private:
216 int64_t value_;
217 absl::InlinedVector<ClosedInterval, 1>::const_iterator it_;
218 absl::InlinedVector<ClosedInterval, 1>::const_iterator end_;
219 };
222 absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
223 return intervals.end();
224 }
225 const absl::InlinedVector<ClosedInterval, 1>& intervals;
226 };
229 absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
230 return intervals.end();
231 }
232 absl::InlinedVector<ClosedInterval, 1> intervals;
233 };
234 DomainIteratorBeginEnd Values() const& { return {this->intervals_}; }
236 return {std::move(this->intervals_)};
237 }
238#endif // !defined(SWIG)
239
243 bool IsEmpty() const;
244
248 int64_t Size() const;
249
254 bool HasTwoValues() const {
255 if (intervals_.size() == 1) {
256 return intervals_[0].end == intervals_[0].start + 1;
257 } else if (intervals_.size() == 2) {
258 return intervals_[0].end == intervals_[0].start &&
259 intervals_[1].end == intervals_[1].start;
260 }
261 return false;
262 }
263
268 int64_t Min() const;
269
274 int64_t Max() const;
275
279 int64_t SmallestValue() const;
280
285 int64_t ClosestValue(int64_t wanted) const;
286
291 int64_t ValueAtOrBefore(int64_t input) const;
292 int64_t ValueAtOrAfter(int64_t input) const;
293
298 Domain PartAroundZero() const;
299
304 bool IsFixed() const;
305
311 int64_t FixedValue() const;
312
316 bool Contains(int64_t value) const;
317
321 int64_t Distance(int64_t value) const;
322
326 bool IsIncludedIn(const Domain& domain) const;
327
331 Domain Complement() const;
332
339 Domain Negation() const;
340
344 Domain IntersectionWith(const Domain& domain) const;
345
349 Domain UnionWith(const Domain& domain) const;
350
354 Domain AdditionWith(const Domain& domain) const;
355
367 Domain MultiplicationBy(int64_t coeff, bool* exact = nullptr) const;
368
373
386 Domain ContinuousMultiplicationBy(int64_t coeff) const;
387
400 Domain ContinuousMultiplicationBy(const Domain& domain) const;
401
407 Domain DivisionBy(int64_t coeff) const;
408
414 Domain InverseMultiplicationBy(int64_t coeff) const;
415
424 Domain PositiveModuloBySuperset(const Domain& modulo) const;
425
432 Domain PositiveDivisionBySuperset(const Domain& divisor) const;
433
437 Domain SquareSuperset() const;
438
442 Domain QuadraticSuperset(int64_t a, int64_t b, int64_t c, int64_t d) const;
443
464 Domain SimplifyUsingImpliedDomain(const Domain& implied_domain) const;
465
469 std::string ToString() const;
470
474 bool operator<(const Domain& other) const;
475
476 bool operator==(const Domain& other) const {
477 return intervals_ == other.intervals_;
478 }
479
480 bool operator!=(const Domain& other) const {
481 return intervals_ != other.intervals_;
482 }
483
484 template <typename H>
485 friend H AbslHashValue(H h, const Domain& domain) {
486 return H::combine(std::move(h), domain.intervals_);
487 }
488
494 int NumIntervals() const { return intervals_.size(); }
495 ClosedInterval front() const { return intervals_.front(); }
496 ClosedInterval back() const { return intervals_.back(); }
497 ClosedInterval operator[](int i) const { return intervals_[i]; }
498 absl::InlinedVector<ClosedInterval, 1>::const_iterator begin() const {
499 return intervals_.begin();
500 }
501 absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
502 return intervals_.end();
503 }
504
505 private:
506 // Same as Negation() but modify the current domain.
507 void NegateInPlace();
508
509 // Some functions relax the domain when its "complexity" (i.e NumIntervals())
510 // become too large.
511 static constexpr int kDomainComplexityLimit = 100;
512
513 // Invariant: will always satisfy IntervalsAreSortedAndNonAdjacent().
514 //
515 // Note that we use InlinedVector for the common case of single internal
516 // interval. This provide a good performance boost when working with a
517 // std::vector<Domain>.
518 absl::InlinedVector<ClosedInterval, 1> intervals_;
519};
520
521std::ostream& operator<<(std::ostream& out, const Domain& domain);
522
523// Returns the sum of smallest k values in the domain.
524int64_t SumOfKMinValueInDomain(const Domain& domain, int k);
525
526// Returns the sum of largest k values in the domain.
527int64_t SumOfKMaxValueInDomain(const Domain& domain, int k);
528
536// TODO(user): Templatize the class on the type of the bounds.
538 public:
540 bool operator()(const ClosedInterval& a, const ClosedInterval& b) const {
541 return a.start != b.start ? a.start < b.start : a.end < b.end;
542 }
543 };
544 typedef std::set<ClosedInterval, IntervalComparator> IntervalSet;
545 typedef IntervalSet::iterator Iterator;
546 typedef IntervalSet::const_iterator ConstIterator;
547
550 const std::vector<ClosedInterval>& intervals);
551
557 // TODO(user): Explain why we favored this API to the more natural
558 // input std::vector<ClosedInterval> or std::vector<std::pair<int, int>>.
559 SortedDisjointIntervalList(const std::vector<int64_t>& starts,
560 const std::vector<int64_t>& ends);
561 SortedDisjointIntervalList(const std::vector<int>& starts,
562 const std::vector<int>& ends);
563
568 int64_t end);
569
579 Iterator InsertInterval(int64_t start, int64_t end);
580
590 Iterator GrowRightByOne(int64_t value, int64_t* newly_covered);
591
598 void InsertIntervals(const std::vector<int64_t>& starts,
599 const std::vector<int64_t>& ends);
600 void InsertIntervals(const std::vector<int>& starts,
601 const std::vector<int>& ends);
602
606 int NumIntervals() const { return intervals_.size(); }
607
616 Iterator FirstIntervalGreaterOrEqual(int64_t value) const;
617 Iterator LastIntervalLessOrEqual(int64_t value) const;
618
619 std::string DebugString() const;
620
631 ConstIterator begin() const { return intervals_.begin(); }
632 ConstIterator end() const { return intervals_.end(); }
633
637 const ClosedInterval& last() const { return *intervals_.rbegin(); }
638
639 void clear() { intervals_.clear(); }
641 intervals_.swap(other.intervals_);
642 }
643
644 private:
645 template <class T>
646 void InsertAll(const std::vector<T>& starts, const std::vector<T>& ends);
647
648 IntervalSet intervals_;
649};
650
651} // namespace operations_research
652
653#endif // OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
DomainIterator(const absl::InlinedVector< ClosedInterval, 1 > &intervals)
bool operator!=(absl::InlinedVector< ClosedInterval, 1 >::const_iterator end) const
Domain SimplifyUsingImpliedDomain(const Domain &implied_domain) const
static Domain FromVectorIntervals(const std::vector< std::vector< int64_t > > &intervals)
DomainIteratorBeginEndWithOwnership Values() const &&
Domain(Domain &&other) noexcept
Move constructor.
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
static Domain FromValues(std::vector< int64_t > values)
bool operator<(const Domain &other) const
friend H AbslHashValue(H h, const Domain &domain)
int64_t ValueAtOrAfter(int64_t input) const
Domain(const Domain &other)
Copy constructor (mandatory as we define the move constructor).
std::vector< int64_t > FlattenedIntervals() const
Domain IntersectionWith(const Domain &domain) const
Domain QuadraticSuperset(int64_t a, int64_t b, int64_t c, int64_t d) const
static Domain FromIntervals(absl::Span< const ClosedInterval > intervals)
Domain ContinuousMultiplicationBy(int64_t coeff) const
bool Contains(int64_t value) const
DomainIteratorBeginEnd Values() const &
Domain PositiveModuloBySuperset(const Domain &modulo) const
Domain AdditionWith(const Domain &domain) const
bool IsIncludedIn(const Domain &domain) const
static Domain FromFlatIntervals(const std::vector< int64_t > &flat_intervals)
Domain()
By default, Domain will be empty.
Domain DivisionBy(int64_t coeff) const
int64_t Distance(int64_t value) const
Domain & operator=(const Domain &other)
Copy operator (mandatory as we define the move operator).
static Domain FromFlatSpanOfIntervals(absl::Span< const int64_t > flat_intervals)
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
Domain PositiveDivisionBySuperset(const Domain &divisor) const
absl::InlinedVector< ClosedInterval, 1 >::const_iterator begin() const
Domain UnionWith(const Domain &domain) const
bool operator==(const Domain &other) const
Domain & operator=(Domain &&other) noexcept
Move operator.
ClosedInterval operator[](int i) const
Domain InverseMultiplicationBy(int64_t coeff) const
int64_t ValueAtOrBefore(int64_t input) const
bool operator!=(const Domain &other) const
int64_t ClosestValue(int64_t wanted) const
void InsertIntervals(const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)
Iterator InsertInterval(int64_t start, int64_t end)
SortedDisjointIntervalList BuildComplementOnInterval(int64_t start, int64_t end)
void swap(SortedDisjointIntervalList &other)
std::set< ClosedInterval, IntervalComparator > IntervalSet
Iterator GrowRightByOne(int64_t value, int64_t *newly_covered)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t SumOfKMinValueInDomain(const Domain &domain, int k)
Returns the sum of smallest k values in the domain.
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
bool IntervalsAreSortedAndNonAdjacent(absl::Span< const ClosedInterval > intervals)
int64_t SumOfKMaxValueInDomain(const Domain &domain, int k)
Returns the sum of largest k values in the domain.
static int input(yyscan_t yyscanner)
Definition model.h:51
bool operator==(const ClosedInterval &other) const
friend H AbslHashValue(H h, const ClosedInterval &interval)
bool operator<(const ClosedInterval &other) const
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
const absl::InlinedVector< ClosedInterval, 1 > & intervals
bool operator()(const ClosedInterval &a, const ClosedInterval &b) const