A library for working with phylogenetic and population genetic data.
v0.27.0
interval.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_CONTAINERS_INTERVAL_TREE_INTERVAL_H_
2 #define GENESIS_UTILS_CONTAINERS_INTERVAL_TREE_INTERVAL_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2022 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lczech@carnegiescience.edu>
23  Department of Plant Biology, Carnegie Institution For Science
24  260 Panama Street, Stanford, CA 94305, USA
25 */
26 
27 /*
28  The code below is adapted from https://github.com/5cript/interval-tree
29  which was published under the CC0-1.0 License (Creative Commons Zero v1.0 Universal).
30  We modified the code to fit our needs and formatting, but the functionality is the same.
31  */
32 
40 #include <cassert>
41 #include <cstdio>
42 #include <iostream>
43 #include <iterator>
44 #include <memory>
45 #include <stdexcept>
46 #include <string>
47 #include <type_traits>
48 
50 
51 namespace genesis {
52 namespace utils {
53 
54 // =================================================================================================
55 // Helper Types
56 // =================================================================================================
57 
62 
71 {};
72 
73 // =================================================================================================
74 // Interval Types
75 // =================================================================================================
76 
77 // -------------------------------------------------------------------------
78 // left open `(]` interval
79 // -------------------------------------------------------------------------
80 
85 {
86  template <typename NumericalType>
87  static inline bool within(NumericalType b, NumericalType e, NumericalType p)
88  {
89  assert( b <= e );
90  return (b < p) && (p <= e);
91  }
92 
93  template <typename NumericalType>
94  static inline std::string to_string(NumericalType b, NumericalType e, bool narrow = false)
95  {
96  if( narrow ) {
97  return "(" + std::to_string(b) + "," + std::to_string(e) + "]";
98  } else {
99  return "( " + std::to_string(b) + ", " + std::to_string(e) + " ]";
100  }
101  }
102 
103  template<typename NumericalType>
104  static inline size_t length(NumericalType b, NumericalType e)
105  {
106  assert( b <= e );
107  return e - b;
108  }
109 };
110 
111 // -------------------------------------------------------------------------
112 // right open `[)` interval
113 // -------------------------------------------------------------------------
114 
119 {
120  template <typename NumericalType>
121  static inline bool within(NumericalType b, NumericalType e, NumericalType p)
122  {
123  assert( b <= e );
124  return (b <= p) && (p < e);
125  }
126 
127  template <typename NumericalType>
128  static inline std::string to_string(NumericalType b, NumericalType e, bool narrow = false)
129  {
130  if( narrow ) {
131  return "[" + std::to_string(b) + "," + std::to_string(e) + ")";
132  } else {
133  return "[ " + std::to_string(b) + ", " + std::to_string(e) + " )";
134  }
135  }
136 
137  template<typename NumericalType>
138  static inline size_t length(NumericalType b, NumericalType e)
139  {
140  assert( b <= e );
141  return e - b;
142  }
143 };
144 
145 // -------------------------------------------------------------------------
146 // open `()` interval
147 // -------------------------------------------------------------------------
148 
153 {
154  template <typename NumericalType>
155  static inline bool within(NumericalType b, NumericalType e, NumericalType p)
156  {
157  assert( b <= e );
158  return (b < p) && (p < e);
159  }
160 
161  template <typename NumericalType>
162  static inline std::string to_string(NumericalType b, NumericalType e, bool narrow = false)
163  {
164  if( narrow ) {
165  return "(" + std::to_string(b) + "," + std::to_string(e) + ")";
166  } else {
167  return "( " + std::to_string(b) + ", " + std::to_string(e) + " )";
168  }
169  }
170 
171  template<
172  typename NumericalType,
173  typename std::enable_if< std::is_integral<NumericalType>::value >::type = 0
174  >
175  static inline size_t length(NumericalType b, NumericalType e)
176  {
177  // implementation for integer types.
178 
179  if( b == e ) {
180  throw std::invalid_argument(
181  "Invalid open interval with the same integer for the low and high values."
182  );
183  }
184  assert( b <= e );
185  return e - b - 1;
186  }
187 
188  template<
189  typename NumericalType,
190  typename std::enable_if< ! std::is_integral<NumericalType>::value >::type = 0
191  >
192  static inline size_t length(NumericalType b, NumericalType e)
193  {
194  // implementation for floating point types.
195 
196  assert( b <= e );
197  return e - b;
198  }
199 };
200 
201 // -------------------------------------------------------------------------
202 // closed `[]` interval
203 // -------------------------------------------------------------------------
204 
209 {
210  template <typename NumericalType>
211  static inline bool within(NumericalType b, NumericalType e, NumericalType p)
212  {
213  assert( b <= e );
214  return (b <= p) && (p <= e);
215  }
216 
217  template <typename NumericalType>
218  static inline std::string to_string(NumericalType b, NumericalType e, bool narrow = false)
219  {
220  if( narrow ) {
221  return "[" + std::to_string(b) + "," + std::to_string(e) + "]";
222  } else {
223  return "[ " + std::to_string(b) + ", " + std::to_string(e) + " ]";
224  }
225  }
226 
227  template<
228  typename NumericalType,
229  typename std::enable_if< std::is_integral<NumericalType>::value >::type = 0
230  >
231  static inline size_t length(NumericalType b, NumericalType e)
232  {
233  // implementation for integer types.
234 
235  assert( b <= e );
236  return e - b + 1;
237  }
238 
239  template<
240  typename NumericalType,
241  typename std::enable_if< ! std::is_integral<NumericalType>::value >::type = 0
242  >
243  static inline size_t length(NumericalType b, NumericalType e)
244  {
245  // implementation for floating point types.
246 
247  assert( b <= e );
248  return e - b;
249  }
250 };
251 
252 // =================================================================================================
253 // Interval
254 // =================================================================================================
255 
266 template <
267  typename DataType = EmptyIntervalData,
268  typename NumericalType = DefaultIntervalNumericalType,
269  typename IntervalKind = IntervalClosed
270 >
271 struct Interval
272 {
273 public:
274 
275  // -------------------------------------------------------------------------
276  // Member Types
277  // -------------------------------------------------------------------------
278 
279  using data_type = DataType;
280  using numerical_type = NumericalType;
281  using value_type = NumericalType;
282  using interval_kind = IntervalKind;
283 
284  static_assert(
285  std::is_arithmetic<numerical_type>::value,
286  "Interval can only be constructued with an arithmetic numerical type."
287  );
288 
289  // -------------------------------------------------------------------------
290  // Constructors and Rule of Five
291  // -------------------------------------------------------------------------
292 
298  #if __cplusplus >= 201703L
299  constexpr
300  #endif
302  : Interval{ low, high, data_type{} }
303  {}
304 
305  // Save version. See make_safe_interval() for a function to achieve this.
306  // Interval(numerical_type low, numerical_type high)
307  // : low_{std::min(low, high)}
308  // , high_{std::max(low, high)}
309  // {}
310 
318  : Interval{ low, high, data_type{ data }}
319  {}
320 
328  : low_{low}
329  , high_{high}
330  , data_{std::move(data)}
331  {
332  if( low > high ){
333  throw std::invalid_argument( "Cannot construct Interval with low > high." );
334  }
335  }
336 
337  ~Interval() = default;
338 
339  Interval( Interval const& ) = default;
340  Interval( Interval&& ) = default;
341 
342  Interval& operator= ( Interval const& ) = default;
343  Interval& operator= ( Interval&& ) = default;
344 
345  // -------------------------------------------------------------------------
346  // Data Accessors
347  // -------------------------------------------------------------------------
348 
349  data_type const& data() const
350  {
351  return data;
352  }
353 
355  {
356  return data;
357  }
358 
359  // -------------------------------------------------------------------------
360  // Comparators
361  // -------------------------------------------------------------------------
362 
366  friend bool operator==( Interval const& lhs, Interval const& rhs )
367  {
368  assert( lhs.low_ <= lhs.high_ );
369  assert( rhs.low_ <= rhs.high_ );
370  return lhs.low_ == rhs.low_ && lhs.high_ == rhs.high_;
371  }
372 
376  friend bool operator!=( Interval const& lhs, Interval const& rhs )
377  {
378  assert( lhs.low_ <= rhs.high_ );
379  assert( rhs.low_ <= rhs.high_ );
380  return lhs.low_ != rhs.low_ || lhs.high_ != rhs.high_;
381  }
382 
388  {
389  assert( low_ <= high_ );
390  return low_ <= h && l <= high_;
391  }
392 
398  {
399  assert( low_ <= high_ );
400  return low_ < h && l < high_;
401  }
402 
406  bool overlaps(Interval const& other) const
407  {
408  return overlaps(other.low_, other.high_);
409  }
410 
414  bool overlaps_exclusive(Interval const& other) const
415  {
416  return overlaps_exclusive(other.low_, other.high_);
417  }
418 
422  bool within(numerical_type value) const
423  {
424  assert( low_ <= high_ );
425  return interval_kind::within(low_, high_, value);
426  }
427 
431  bool within(Interval const& other) const
432  {
433  assert( low_ <= high_ );
434  assert( other.low_ <= other.high_ );
435  return low_ <= other.low_ && high_ >= other.high_;
436  }
437 
438  // -------------------------------------------------------------------------
439  // Operators
440  // -------------------------------------------------------------------------
441 
446  numerical_type operator-( Interval const& other ) const
447  {
448  if( overlaps(other) ) {
449  return 0;
450  }
451 
452  assert( low_ <= high_ );
453  assert( other.low_ <= other.high_ );
454  if( high_ < other.low_ ) {
455  return other.low_ - high_;
456  } else {
457  return low_ - other.high_;
458  }
459  }
460 
465  {
466  return low_;
467  }
468 
473  {
474  return high_;
475  }
476 
481  {
482  assert( low_ <= high_ );
483  return high_ - low_;
484  }
485 
501  {
502  assert( low_ <= high_ );
503  return interval_kind::length( low_, high_ );
504  }
505 
506  std::string to_string( bool narrow = false ) const
507  {
508  return interval_kind::to_string( low_, high_, narrow );
509  }
510 
511  operator std::string() const
512  {
513  return to_string();
514  }
515 
516  // -------------------------------------------------------------------------
517  // Member Variables
518  // -------------------------------------------------------------------------
519 
520 private:
521 
522  numerical_type low_;
523  numerical_type high_;
524  data_type data_;
525 };
526 
527 } // namespace utils
528 } // namespace genesis
529 
530 #endif // include guard
genesis::utils::Interval::data_type
DataType data_type
Definition: interval.hpp:279
genesis::utils::Interval
Type to store an interval (range) between two numbers, as used in the IntervalTree.
Definition: fwd.hpp:42
genesis::utils::Interval::within
bool within(numerical_type value) const
Return whether the given value is in this.
Definition: interval.hpp:422
genesis::utils::DefaultIntervalNumericalType
int DefaultIntervalNumericalType
Default numerical type to use in an Interval.
Definition: interval.hpp:61
genesis::utils::IntervalOpen::length
static size_t length(NumericalType b, NumericalType e)
Definition: interval.hpp:175
genesis::utils::Interval< EmptyIntervalData, DefaultIntervalNumericalType, IntervalClosed >::value_type
DefaultIntervalNumericalType value_type
Definition: interval.hpp:281
genesis::utils::IntervalRightOpen::to_string
static std::string to_string(NumericalType b, NumericalType e, bool narrow=false)
Definition: interval.hpp:128
genesis::utils::Interval::size
numerical_type size() const
Return the size of the interval, that is, the distance between low and high.
Definition: interval.hpp:480
genesis::utils::EmptyIntervalData
Empty class used as default for Interval data.
Definition: interval.hpp:70
genesis::utils::Interval::operator=
Interval & operator=(Interval const &)=default
genesis::utils::IntervalLeftOpen::within
static bool within(NumericalType b, NumericalType e, NumericalType p)
Definition: interval.hpp:87
fwd.hpp
genesis::utils::Interval::within
bool within(Interval const &other) const
Return whether the given interval is in this.
Definition: interval.hpp:431
genesis::utils::IntervalOpen::to_string
static std::string to_string(NumericalType b, NumericalType e, bool narrow=false)
Definition: interval.hpp:162
genesis::utils::Interval::overlaps
bool overlaps(Interval const &other) const
Return whether the intervals overlap.
Definition: interval.hpp:406
genesis::utils::IntervalClosed::to_string
static std::string to_string(NumericalType b, NumericalType e, bool narrow=false)
Definition: interval.hpp:218
genesis::tree::length
double length(Tree const &tree)
Get the length of the tree, i.e., the sum of all branch lengths.
Definition: tree/common_tree/functions.cpp:160
genesis::utils::Interval::operator==
friend bool operator==(Interval const &lhs, Interval const &rhs)
Return if both intervals equal.
Definition: interval.hpp:366
genesis::utils::Interval::Interval
Interval(numerical_type low, numerical_type high, data_type &&data)
Construct an interval.
Definition: interval.hpp:327
genesis::utils::Interval::overlaps_exclusive
bool overlaps_exclusive(Interval const &other) const
Return whether the intervals overlap, excluding border.
Definition: interval.hpp:414
genesis::utils::Interval::~Interval
~Interval()=default
genesis::utils::IntervalRightOpen::within
static bool within(NumericalType b, NumericalType e, NumericalType p)
Definition: interval.hpp:121
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: functions/genome_locus.hpp:48
genesis::utils::Interval::data
data_type & data()
Definition: interval.hpp:354
genesis::utils::IntervalClosed::within
static bool within(NumericalType b, NumericalType e, NumericalType p)
Definition: interval.hpp:211
genesis::utils::Interval::high
numerical_type high() const
Return the upper bound of the interval.
Definition: interval.hpp:472
genesis::utils::Interval::to_string
std::string to_string(bool narrow=false) const
Definition: interval.hpp:506
genesis::utils::IntervalClosed
Helper type to define a closed [] Interval.
Definition: interval.hpp:208
genesis::utils::IntervalClosed::length
static size_t length(NumericalType b, NumericalType e)
Definition: interval.hpp:231
genesis::utils::Interval::low
numerical_type low() const
Return the lower bound of the interval.
Definition: interval.hpp:464
genesis::utils::Interval::data
data_type const & data() const
Definition: interval.hpp:349
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::Interval::overlaps_exclusive
bool overlaps_exclusive(numerical_type l, numerical_type h) const
Return whether the intervals overlap, excluding border. For when at least one interval is open (l&r).
Definition: interval.hpp:397
genesis::utils::Interval< EmptyIntervalData, DefaultIntervalNumericalType, IntervalClosed >::numerical_type
DefaultIntervalNumericalType numerical_type
Definition: interval.hpp:280
genesis::utils::IntervalLeftOpen::length
static size_t length(NumericalType b, NumericalType e)
Definition: interval.hpp:104
genesis::utils::IntervalLeftOpen
Helper type to define a left open (] Interval.
Definition: interval.hpp:84
genesis::utils::Interval::Interval
Interval(numerical_type low, numerical_type high, data_type const &data)
Construct an interval.
Definition: interval.hpp:317
genesis::utils::IntervalRightOpen::length
static size_t length(NumericalType b, NumericalType e)
Definition: interval.hpp:138
genesis::utils::Interval::overlaps
bool overlaps(numerical_type l, numerical_type h) const
Return whether the intervals overlap. For when both intervals are closed.
Definition: interval.hpp:387
genesis::utils::IntervalLeftOpen::to_string
static std::string to_string(NumericalType b, NumericalType e, bool narrow=false)
Definition: interval.hpp:94
genesis::utils::Interval::Interval
Interval(numerical_type low, numerical_type high)
Construct an interval.
Definition: interval.hpp:301
genesis::utils::IntervalOpen
Helper type to define an open () Interval.
Definition: interval.hpp:152
genesis::utils::IntervalOpen::within
static bool within(NumericalType b, NumericalType e, NumericalType p)
Definition: interval.hpp:155
genesis::utils::IntervalRightOpen
Helper type to define a right open [) Interval.
Definition: interval.hpp:118
genesis::utils::Interval::length
numerical_type length() const
Return the length of the interval.
Definition: interval.hpp:500
genesis::utils::Interval::operator!=
friend bool operator!=(Interval const &lhs, Interval const &rhs)
Return if both intervals are different.
Definition: interval.hpp:376
genesis::utils::Interval::operator-
numerical_type operator-(Interval const &other) const
Calculates the distance between the two intervals. Overlapping intervals have 0 distance.
Definition: interval.hpp:446