C++ Reference

C++ Reference: CP-SAT

sorted_interval_list.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <iterator>
18 #include <ostream>
19 #include <set>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/container/inlined_vector.h"
25 #include "absl/types/span.h"
26 #include "ortools/base/integral_types.h"
27 #include "ortools/base/logging.h"
28 
29 namespace 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  int64_t start = 0; // Inclusive.
54  int64_t end = 0; // Inclusive.
55 };
56 
57 std::ostream& operator<<(std::ostream& out, const ClosedInterval& interval);
58 std::ostream& operator<<(std::ostream& out,
59  const std::vector<ClosedInterval>& intervals);
60 
70  absl::Span<const ClosedInterval> intervals);
71 
82 class Domain {
83  public:
85  Domain() {}
86 
87 #if !defined(SWIG)
89  Domain(const Domain& other) : intervals_(other.intervals_) {}
90 
92  Domain& operator=(const Domain& other) {
93  intervals_ = other.intervals_;
94  return *this;
95  }
96 
98  Domain(Domain&& other) : intervals_(std::move(other.intervals_)) {}
99 
101  Domain& operator=(Domain&& other) {
102  intervals_ = std::move(other.intervals_);
103  return *this;
104  }
105 #endif // !defined(SWIG)
106 
108  explicit Domain(int64_t value);
109 
114  Domain(int64_t left, int64_t right);
115 
119  static Domain AllValues();
120 
125  static Domain FromValues(std::vector<int64_t> values);
126 
130  static Domain FromIntervals(absl::Span<const ClosedInterval> intervals);
131 
137  absl::Span<const int64_t> flat_intervals);
138 
145  const std::vector<std::vector<int64_t> >& intervals);
146 
152  static Domain FromFlatIntervals(const std::vector<int64_t>& flat_intervals);
153 
161  std::vector<int64_t> FlattenedIntervals() const;
162 
163 #if !defined(SWIG)
172  public:
173  explicit DomainIterator(
174  const absl::InlinedVector<ClosedInterval, 1>& intervals)
175  : value_(intervals.empty() ? int64_t{0} : intervals.front().start),
176  it_(intervals.begin()),
177  end_(intervals.end()) {}
178 
179  int64_t operator*() const { return value_; }
180 
181  void operator++() {
182  if (value_ == it_->end) {
183  ++it_;
184  if (it_ != end_) value_ = it_->start;
185  } else {
186  ++value_;
187  }
188  }
189 
191  absl::InlinedVector<ClosedInterval, 1>::const_iterator end) const {
192  return it_ != end;
193  }
194 
195  private:
196  int64_t value_;
197  absl::InlinedVector<ClosedInterval, 1>::const_iterator it_;
198  absl::InlinedVector<ClosedInterval, 1>::const_iterator end_;
199  };
202  absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
203  return intervals.end();
204  }
205  const absl::InlinedVector<ClosedInterval, 1>& intervals;
206  };
209  absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
210  return intervals.end();
211  }
212  absl::InlinedVector<ClosedInterval, 1> intervals;
213  };
214  DomainIteratorBeginEnd Values() const& { return {this->intervals_}; }
216  return {std::move(this->intervals_)};
217  }
218 #endif // !defined(SWIG)
219 
223  bool IsEmpty() const;
224 
228  int64_t Size() const;
229 
234  int64_t Min() const;
235 
240  int64_t Max() const;
241 
245  int64_t SmallestValue() const;
246 
251  int64_t ValueAtOrBefore(int64_t input) const;
252  int64_t ValueAtOrAfter(int64_t input) const;
253 
258  bool IsFixed() const;
259 
265  int64_t FixedValue() const;
266 
270  bool Contains(int64_t value) const;
271 
275  bool IsIncludedIn(const Domain& domain) const;
276 
281 
288  Domain Negation() const;
289 
293  Domain IntersectionWith(const Domain& domain) const;
294 
298  Domain UnionWith(const Domain& domain) const;
299 
303  Domain AdditionWith(const Domain& domain) const;
304 
316  Domain MultiplicationBy(int64_t coeff, bool* exact = nullptr) const;
317 
322 
335  Domain ContinuousMultiplicationBy(int64_t coeff) const;
336 
350 
356  Domain DivisionBy(int64_t coeff) const;
357 
363  Domain InverseMultiplicationBy(const int64_t coeff) const;
364 
373  Domain PositiveModuloBySuperset(const Domain& modulo) const;
374 
381  Domain PositiveDivisionBySuperset(const Domain& divisor) const;
382 
387 
408  Domain SimplifyUsingImpliedDomain(const Domain& implied_domain) const;
409 
413  std::string ToString() const;
414 
418  bool operator<(const Domain& other) const;
419 
420  bool operator==(const Domain& other) const {
421  return intervals_ == other.intervals_;
422  }
423 
424  bool operator!=(const Domain& other) const {
425  return intervals_ != other.intervals_;
426  }
427 
433  int NumIntervals() const { return intervals_.size(); }
434  ClosedInterval front() const { return intervals_.front(); }
435  ClosedInterval back() const { return intervals_.back(); }
436  ClosedInterval operator[](int i) const { return intervals_[i]; }
437  absl::InlinedVector<ClosedInterval, 1>::const_iterator begin() const {
438  return intervals_.begin();
439  }
440  absl::InlinedVector<ClosedInterval, 1>::const_iterator end() const {
441  return intervals_.end();
442  }
443 
444  // Deprecated.
445  //
446  // TODO(user): remove, this makes a copy and is of a different type that our
447  // internal InlinedVector() anyway.
448  std::vector<ClosedInterval> intervals() const {
449  return {intervals_.begin(), intervals_.end()};
450  }
451 
452  private:
453  // Same as Negation() but modify the current domain.
454  void NegateInPlace();
455 
456  // Some functions relax the domain when its "complexity" (i.e NumIntervals())
457  // become too large.
458  static constexpr int kDomainComplexityLimit = 100;
459 
460  // Invariant: will always satisfy IntervalsAreSortedAndNonAdjacent().
461  //
462  // Note that we use InlinedVector for the common case of single internal
463  // interval. This provide a good performance boost when working with a
464  // std::vector<Domain>.
465  absl::InlinedVector<ClosedInterval, 1> intervals_;
466 };
467 
468 std::ostream& operator<<(std::ostream& out, const Domain& domain);
469 
470 // Returns the sum of smallest k values in the domain.
471 int64_t SumOfKMinValueInDomain(const Domain& domain, int k);
472 
473 // Returns the sum of largest k values in the domain.
474 int64_t SumOfKMaxValueInDomain(const Domain& domain, int k);
475 
483 // TODO(user): Templatize the class on the type of the bounds.
485  public:
487  bool operator()(const ClosedInterval& a, const ClosedInterval& b) const {
488  return a.start != b.start ? a.start < b.start : a.end < b.end;
489  }
490  };
491  typedef std::set<ClosedInterval, IntervalComparator> IntervalSet;
492  typedef IntervalSet::iterator Iterator;
493  typedef IntervalSet::const_iterator ConstIterator;
494 
497  const std::vector<ClosedInterval>& intervals);
498 
504  // TODO(user): Explain why we favored this API to the more natural
505  // input std::vector<ClosedInterval> or std::vector<std::pair<int, int>>.
506  SortedDisjointIntervalList(const std::vector<int64_t>& starts,
507  const std::vector<int64_t>& ends);
508  SortedDisjointIntervalList(const std::vector<int>& starts,
509  const std::vector<int>& ends);
510 
515  int64_t end);
516 
526  Iterator InsertInterval(int64_t start, int64_t end);
527 
537  Iterator GrowRightByOne(int64_t value, int64_t* newly_covered);
538 
545  void InsertIntervals(const std::vector<int64_t>& starts,
546  const std::vector<int64_t>& ends);
547  void InsertIntervals(const std::vector<int>& starts,
548  const std::vector<int>& ends);
549 
553  int NumIntervals() const { return intervals_.size(); }
554 
563  Iterator FirstIntervalGreaterOrEqual(int64_t value) const;
564  Iterator LastIntervalLessOrEqual(int64_t value) const;
565 
566  std::string DebugString() const;
567 
578  ConstIterator begin() const { return intervals_.begin(); }
579  ConstIterator end() const { return intervals_.end(); }
580 
584  const ClosedInterval& last() const { return *intervals_.rbegin(); }
585 
586  void clear() { intervals_.clear(); }
588  intervals_.swap(other.intervals_);
589  }
590 
591  private:
592  template <class T>
593  void InsertAll(const std::vector<T>& starts, const std::vector<T>& ends);
594 
595  IntervalSet intervals_;
596 };
597 
598 } // namespace operations_research
599 
600 #endif // OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
Allows to iterate over all values of a domain in order with for (const int64_t v : domain....
bool operator!=(absl::InlinedVector< ClosedInterval, 1 >::const_iterator end) const
DomainIterator(const absl::InlinedVector< ClosedInterval, 1 > &intervals)
We call domain any subset of Int64 = [kint64min, kint64max].
Domain(Domain &&other)
Move constructor.
static Domain FromValues(std::vector< int64_t > values)
Creates a domain from the union of an unsorted list of integer values.
Domain InverseMultiplicationBy(const int64_t coeff) const
Returns {x ∈ Int64, ∃ e ∈ D, x * coeff = e}.
std::string ToString() const
Returns a compact string of a vector of intervals like "[1,4][6][10,20]".
Domain Negation() const
Returns {x ∈ Int64, ∃ e ∈ D, x = -e}.
Domain Complement() const
Returns the set Int64 ∖ D.
bool IsIncludedIn(const Domain &domain) const
Returns true iff D is included in the given domain.
bool Contains(int64_t value) const
Returns true iff value is in Domain.
Domain ContinuousMultiplicationBy(int64_t coeff) const
Returns a superset of MultiplicationBy() to avoid the explosion in the representation size.
Domain & operator=(Domain &&other)
Move operator.
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
static Domain FromFlatIntervals(const std::vector< int64_t > &flat_intervals)
This method is available in Python, Java and .NET.
std::vector< int64_t > FlattenedIntervals() const
This method returns the flattened list of interval bounds of the domain.
DomainIteratorBeginEndWithOwnership Values() const &&
int NumIntervals() const
Basic read-only std::vector<> wrapping to view a Domain as a sorted list of non-adjacent intervals.
int64_t FixedValue() const
Returns the value of a fixed domain.
Domain ContinuousMultiplicationBy(const Domain &domain) const
Returns a superset of MultiplicationBy() to avoid the explosion in the representation size.
bool operator<(const Domain &other) const
Lexicographic order on the intervals() representation.
Domain AdditionWith(const Domain &domain) const
Returns {x ∈ Int64, ∃ a ∈ D, ∃ b ∈ domain, x = a + b}.
static Domain FromIntervals(absl::Span< const ClosedInterval > intervals)
Creates a domain from the union of an unsorted list of intervals.
ClosedInterval front() const
static Domain AllValues()
Returns the full domain Int64.
int64_t Size() const
Returns the number of elements in the domain.
bool operator!=(const Domain &other) const
Domain UnionWith(const Domain &domain) const
Returns the union of D and domain.
ClosedInterval operator[](int i) const
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
Returns {x ∈ Int64, ∃ e ∈ D, x = e * coeff}.
bool IsFixed() const
Returns true iff the domain is reduced to a single value.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
Domain PositiveDivisionBySuperset(const Domain &divisor) const
Returns a superset of {x ∈ Int64, ∃ e ∈ D, ∃ d ∈ divisor, x = e / d }.
std::vector< ClosedInterval > intervals() const
bool operator==(const Domain &other) const
Domain()
By default, Domain will be empty.
int64_t SmallestValue() const
Returns the value closest to zero.
Domain(const Domain &other)
Copy constructor (mandatory as we define the move constructor).
int64_t Max() const
Returns the max value of the domain.
Domain RelaxIfTooComplex() const
If NumIntervals() is too large, this return a superset of the domain.
static Domain FromFlatSpanOfIntervals(absl::Span< const int64_t > flat_intervals)
Same as FromIntervals() for a flattened representation (start, end, start, end, .....
Domain(int64_t value)
Constructor for the common case of a singleton domain.
Domain SquareSuperset() const
Returns a superset of {x ∈ Int64, ∃ y ∈ D, x = y * y }.
absl::InlinedVector< ClosedInterval, 1 >::const_iterator begin() const
Domain & operator=(const Domain &other)
Copy operator (mandatory as we define the move operator).
Domain DivisionBy(int64_t coeff) const
Returns {x ∈ Int64, ∃ e ∈ D, x = e / coeff}.
static Domain FromVectorIntervals(const std::vector< std::vector< int64_t > > &intervals)
This method is available in Python, Java and .NET.
Domain(int64_t left, int64_t right)
Constructor for the common case of a single interval [left, right].
DomainIteratorBeginEnd Values() const &
int64_t ValueAtOrAfter(int64_t input) const
Domain PositiveModuloBySuperset(const Domain &modulo) const
Returns a superset of {x ∈ Int64, ∃ e ∈ D, ∃ m ∈ modulo, x = e % m }.
Domain SimplifyUsingImpliedDomain(const Domain &implied_domain) const
Advanced usage.
int64_t ValueAtOrBefore(int64_t input) const
Returns the closest value in the domain that is <= (resp.
This class represents a sorted list of disjoint, closed intervals.
SortedDisjointIntervalList(const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)
Creates a SortedDisjointIntervalList and fills it with intervals [starts[i]..ends[i]].
const ClosedInterval & last() const
Returns a const& to the last interval.
void InsertIntervals(const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)
Adds all intervals [starts[i]..ends[i]].
int NumIntervals() const
Returns the number of disjoint intervals in the list.
void swap(SortedDisjointIntervalList &other)
SortedDisjointIntervalList(const std::vector< int > &starts, const std::vector< int > &ends)
Iterator InsertInterval(int64_t start, int64_t end)
Adds the interval [start..end] to the list, and merges overlapping or immediately adjacent intervals ...
std::set< ClosedInterval, IntervalComparator > IntervalSet
ConstIterator begin() const
Const iterators for SortedDisjoinIntervalList.
SortedDisjointIntervalList BuildComplementOnInterval(int64_t start, int64_t end)
Builds the complement of the interval list on the interval [start, end].
Iterator LastIntervalLessOrEqual(int64_t value) const
Iterator FirstIntervalGreaterOrEqual(int64_t value) const
Returns an iterator to either:
SortedDisjointIntervalList(const std::vector< ClosedInterval > &intervals)
Iterator GrowRightByOne(int64_t value, int64_t *newly_covered)
If value is in an interval, increase its end by one, otherwise insert the interval [value,...
void InsertIntervals(const std::vector< int > &starts, const std::vector< int > &ends)
std::ostream & operator<<(std::ostream &out, const ClosedInterval &interval)
int64_t SumOfKMinValueInDomain(const Domain &domain, int k)
bool IntervalsAreSortedAndNonAdjacent(absl::Span< const ClosedInterval > intervals)
Returns true iff we have:
int64_t SumOfKMaxValueInDomain(const Domain &domain, int k)
Represents a closed interval [start, end].
bool operator==(const ClosedInterval &other) const
bool operator<(const ClosedInterval &other) const
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
const absl::InlinedVector< ClosedInterval, 1 > & intervals
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
bool operator()(const ClosedInterval &a, const ClosedInterval &b) const