range.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_RANGE_H__INCLUDED
21 #define TILEDARRAY_RANGE_H__INCLUDED
22 
23 #include <TiledArray/permutation.h>
25 #include <TiledArray/size_array.h>
26 #include <TiledArray/util/vector.h>
27 
28 namespace TiledArray {
29 
32 
46 class Range {
47  public:
48  typedef Range Range_;
49  typedef TA_1INDEX_TYPE index1_type;
53  typedef index_type index;
57  typedef index_type
59  typedef std::size_t ordinal_type;
60  typedef std::make_signed_t<ordinal_type> distance_type;
65 
66  static_assert(detail::is_range_v<index_type>); // index is a Range
67 
68  protected:
80  unsigned int rank_ = 0u;
81 
82  void init_datavec(unsigned int rank) { datavec_.resize(rank << 2); }
83  const index1_type* data() const { return datavec_.data(); }
84  index1_type* data() { return datavec_.data(); }
85 
86  index1_type* lobound_data_nc() { return data(); }
88  index1_type* extent_data_nc() { return data() + (rank_ << 1); }
90 
91  private:
93 
102  template <typename Index1, typename Index2,
103  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
104  detail::is_integral_range_v<Index2>>>
105  void init_range_data(const Index1& lower_bound, const Index2& upper_bound) {
106  // Construct temp pointers
107  auto* MADNESS_RESTRICT const lower = data();
108  auto* MADNESS_RESTRICT const upper = lower + rank_;
109  auto* MADNESS_RESTRICT const extent = upper + rank_;
110  auto* MADNESS_RESTRICT const stride = extent + rank_;
111 
112  // Set the volume seed
113  volume_ = 1ul;
114  offset_ = 0l;
115 
116  // initialize bounds and extents
117  auto lower_it = std::begin(lower_bound);
118  auto upper_it = std::begin(upper_bound);
119  auto lower_end = std::end(lower_bound);
120  auto upper_end = std::end(upper_bound);
121  for (int d = 0; lower_it != lower_end && upper_it != upper_end;
122  ++lower_it, ++upper_it, ++d) {
123  // Compute data for element d of lower, upper, and extent
124  const auto lower_bound_d = *lower_it;
125  const auto upper_bound_d = *upper_it;
126  lower[d] = lower_bound_d;
127  upper[d] = upper_bound_d;
128  // Check input dimensions
129  TA_ASSERT(lower[d] <= upper[d]);
130  extent[d] = upper[d] - lower[d];
131  TA_ASSERT(extent[d] ==
132  static_cast<index1_type>(upper_bound_d - lower_bound_d));
133  }
134 
135  // Set the volume seed
136  volume_ = 1ul;
137  offset_ = 0l;
138 
139  // Compute strides, volume, and offset, starting with last (least
140  // significant) dimension
141  for (int d = int(rank_) - 1; d >= 0; --d) {
142  stride[d] = volume_;
143  offset_ += lower[d] * stride[d];
144  volume_ *= extent[d];
145  }
146  }
147 
148  // clang-format off
150 
157  // clang-format on
158  template <typename PairRange,
159  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
160  void init_range_data(const PairRange& bounds) {
161  // Construct temp pointers
162  auto* MADNESS_RESTRICT const lower = data();
163  auto* MADNESS_RESTRICT const upper = lower + rank_;
164  auto* MADNESS_RESTRICT const extent = upper + rank_;
165  auto* MADNESS_RESTRICT const stride = extent + rank_;
166 
167  // Compute range data
168  int d = 0;
169  for (auto&& bound_d : bounds) {
170  // Compute data for element i of lower, upper, and extent
171  const auto lower_bound_d = detail::at(bound_d, 0);
172  const auto upper_bound_d = detail::at(bound_d, 1);
173  lower[d] = lower_bound_d;
174  upper[d] = upper_bound_d;
175  // Check input dimensions
176  TA_ASSERT(lower[d] <= upper[d]);
177  extent[d] = upper[d] - lower[d];
178  ++d;
179  }
180  // Compute strides, volume, and offset, starting with last (least
181  // significant) dimension
182  volume_ = 1ul;
183  offset_ = 0l;
184  for (int d = int(rank_) - 1; d >= 0; --d) {
185  stride[d] = volume_;
186  offset_ += lower[d] * stride[d];
187  volume_ *= extent[d];
188  }
189  }
190 
192 
199  template <typename Index, typename std::enable_if_t<
200  detail::is_integral_range_v<Index>>* = nullptr>
201  void init_range_data(const Index& extents) {
202  // Construct temp pointers
203  auto* MADNESS_RESTRICT const lower = data();
204  auto* MADNESS_RESTRICT const upper = lower + rank_;
205  auto* MADNESS_RESTRICT const extent = upper + rank_;
206  auto* MADNESS_RESTRICT const stride = extent + rank_;
207 
208  // Initialize extents and bounds
209  auto it = std::begin(extents);
210  auto end = std::end(extents);
211  for (int d = 0; it != end; ++it, ++d) {
212  const auto extent_d = *it;
213  lower[d] = 0ul;
214  upper[d] = extent_d;
215  extent[d] = extent_d;
216  // Check bounds of the input extent
217  TA_ASSERT(extent[d] >= 0);
218  }
219 
220  // Compute strides and volume, starting with last (least significant)
221  // dimension
222  volume_ = 1ul;
223  offset_ = 0ul;
224  for (int d = int(rank_) - 1; d >= 0; --d) {
225  stride[d] = volume_;
226  volume_ *= extent[d];
227  }
228  }
229 
231 
238  template <typename... Indices,
239  typename std::enable_if<
240  detail::is_integral_list<Indices...>::value>::type* = nullptr>
241  void init_range_data(const std::tuple<Indices...>& extents) {
242  const constexpr std::size_t rank =
243  std::tuple_size<std::tuple<Indices...>>::value;
244  TA_ASSERT(rank_ == rank);
245 
246  // Set the offset and volume initial values
247  volume_ = 1ul;
248  offset_ = 0ul;
249 
250  // initialize by recursion
251  init_range_data_helper(extents, std::make_index_sequence<rank>{});
252  }
253 
254  template <typename... Indices, std::size_t... Is>
255  void init_range_data_helper(const std::tuple<Indices...>& extents,
256  std::index_sequence<Is...>) {
257  int workers[] = {0, (init_range_data_helper_iter<Is>(extents), 0)...};
258  ++workers[0];
259  }
260 
261  template <std::size_t I, typename... Indices>
262  void init_range_data_helper_iter(const std::tuple<Indices...>& extents) {
263  // Get extent i
264  const auto extent_i = std::get<I>(extents);
265 
266  auto* MADNESS_RESTRICT const lower = data();
267  auto* MADNESS_RESTRICT const upper = lower + rank_;
268  auto* MADNESS_RESTRICT const extent = upper + rank_;
269  auto* MADNESS_RESTRICT const stride = extent + rank_;
270 
271  lower[I] = 0ul;
272  upper[I] = extent_i;
273  extent[I] = extent_i;
274  // Check bounds of the input extent
275  TA_ASSERT(extent[I] >= 0ul);
276  stride[I] = volume_;
277  volume_ *= extent[I];
278  }
279 
281 
289  void init_range_data(
290  const Permutation& perm,
291  const index1_type* MADNESS_RESTRICT const other_lower_bound,
292  const index1_type* MADNESS_RESTRICT const other_upper_bound) {
293  // Create temporary pointers to this range data
294  auto* MADNESS_RESTRICT const lower = data();
295  auto* MADNESS_RESTRICT const upper = lower + rank_;
296  auto* MADNESS_RESTRICT const extent = upper + rank_;
297  auto* MADNESS_RESTRICT const stride = extent + rank_;
298 
299  // Copy the permuted lower, upper, and extent into this range.
300  for (unsigned int i = 0u; i < rank_; ++i) {
301  const auto perm_i = perm[i];
302 
303  // Get the lower bound, upper bound, and extent from other for rank i.
304  const auto other_lower_bound_i = other_lower_bound[i];
305  const auto other_upper_bound_i = other_upper_bound[i];
306  const auto other_extent_i = other_upper_bound_i - other_lower_bound_i;
307 
308  // Store the permuted lower bound, upper bound, and extent
309  lower[perm_i] = other_lower_bound_i;
310  upper[perm_i] = other_upper_bound_i;
311  extent[perm_i] = other_extent_i;
312  }
313 
314  // Recompute stride, offset, and volume
315  volume_ = 1ul;
316  offset_ = 0ul;
317  for (int i = int(rank_) - 1; i >= 0; --i) {
318  const auto lower_i = lower[i];
319  const auto extent_i = extent[i];
320  stride[i] = volume_;
321  offset_ += lower_i * volume_;
322  volume_ *= extent_i;
323  }
324  }
325 
326  public:
328 
330  Range() {}
331 
333 
351  template <typename Index1, typename Index2,
352  typename std::enable_if_t<
353  detail::is_integral_sized_range_v<Index1> &&
354  detail::is_integral_sized_range_v<Index2>>* = nullptr>
355  Range(const Index1& lower_bound, const Index2& upper_bound) {
356  using std::size;
357  const auto n = size(lower_bound);
358  TA_ASSERT(n == size(upper_bound));
359  if (n) {
360  // Initialize array memory
361  init_datavec(n);
362  rank_ = n;
363  init_range_data(lower_bound, upper_bound);
364  } // rank-0 Range is null
365  }
366 
367  // clang-format off
369 
385  // clang-format on
386  template <typename Index1, typename Index2,
387  typename = std::enable_if_t<std::is_integral_v<Index1> &&
388  std::is_integral_v<Index2>>>
389  Range(const std::initializer_list<Index1>& lower_bound,
390  const std::initializer_list<Index2>& upper_bound) {
391  using std::size;
392  const auto n = size(lower_bound);
393  TA_ASSERT(n == size(upper_bound));
394  init_datavec(n);
395  rank_ = n;
396  if (n) {
397  init_range_data(lower_bound, upper_bound);
398  } // rank-0 Range is null
399  }
400 
402 
411  template <typename Index,
412  typename std::enable_if_t<
413  detail::is_integral_sized_range_v<Index>>* = nullptr>
414  explicit Range(const Index& extent) {
415  using std::size;
416  const auto n = size(extent);
417  if (n) {
418  // Initialize array memory
419  init_datavec(n);
420  rank_ = n;
421  init_range_data(extent);
422  } // rank-0 Range is null
423  }
424 
426 
435  template <typename Index,
436  typename = std::enable_if_t<std::is_integral_v<Index>>>
437  explicit Range(const std::initializer_list<Index>& extent) {
438  using std::size;
439  const auto n = size(extent);
440  if (n) {
441  // Initialize array memory
442  init_datavec(n);
443  rank_ = n;
444  init_range_data(extent);
445  } // rank-0 Range is null
446  }
447 
448  // clang-format off
450 
476  // clang-format on
477  template <typename PairRange,
478  typename = std::enable_if_t<detail::is_sized_range_v<PairRange> &&
479  detail::is_gpair_range_v<PairRange>>>
480  explicit Range(const PairRange& bounds) {
481  const auto n = std::size(bounds);
482  if (n) {
483  // Initialize array memory
484  init_datavec(n);
485  rank_ = n;
486  init_range_data(bounds);
487  } // rank-0 Range is null
488  }
489 
490  // clang-format off
492 
500  // clang-format on
501  template <typename GPair>
502  explicit Range(const std::initializer_list<GPair>& bounds,
503  std::enable_if_t<detail::is_gpair_v<GPair>>* = nullptr) {
504  using std::size;
505 #ifndef NDEBUG
506  if constexpr (detail::is_contiguous_range_v<GPair>) {
507  for (auto&& bound_d : bounds) {
508  TA_ASSERT(size(bound_d) == 2);
509  }
510  }
511 #endif
512  const auto n = size(bounds);
513  if (n) {
514  // Initialize array memory
515  init_datavec(n);
516  rank_ = n;
517  init_range_data(bounds);
518  } // rank-0 Range is null
519  }
520 
521  // clang-format off
523 
534  // clang-format on
535  template <typename Index,
536  typename = std::enable_if_t<std::is_integral_v<Index>>>
537  explicit Range(
538  const std::initializer_list<std::initializer_list<Index>>& bounds) {
539  using std::size;
540  const auto n = size(bounds);
541  if (n) {
542 #ifndef NDEBUG
543  for (auto&& bound_d : bounds) {
544  TA_ASSERT(size(bound_d) == 2);
545  }
546 #endif
547  // Initialize array memory
548  init_datavec(n);
549  rank_ = n;
550  init_range_data(bounds);
551  } // rank-0 Range is null
552  }
553 
555 
563  template <typename... Index, typename std::enable_if<detail::is_integral_list<
564  Index...>::value>::type* = nullptr>
565  explicit Range(const Index... extents)
566  : Range(std::array<size_t, sizeof...(Index)>{
567  {static_cast<std::size_t>(extents)...}}) {}
568 
571 
578  template <typename... IndexPairs,
579  std::enable_if_t<detail::is_integral_pair_list_v<IndexPairs...>>* =
580  nullptr>
581  explicit Range(const IndexPairs... bounds)
582  : Range(std::array<std::pair<std::size_t, std::size_t>,
583  sizeof...(IndexPairs)>{
584  {static_cast<std::pair<std::size_t, std::size_t>>(bounds)...}}) {}
585 
587 
589  Range(const Range_& other) = default;
590 
592 
594  Range(Range_&& other)
595  : datavec_(std::move(other.datavec_)),
596  offset_(other.offset_),
597  volume_(other.volume_),
598  rank_(other.rank_) {
599  // put other into null state
600  other.datavec_.clear();
601  other.datavec_.shrink_to_fit();
602  other.offset_ = 0ul;
603  other.volume_ = 0ul;
604  other.rank_ = 0u;
605  }
606 
608 
611  Range(const Permutation& perm, const Range_& other) {
612  TA_ASSERT(perm.size() == other.rank_);
613 
614  if (other.rank_ > 0ul) {
615  rank_ = other.rank_;
616 
617  if (perm) {
618  init_datavec(other.rank_);
619  init_range_data(perm, other.lobound_data(), other.upbound_data());
620  } else {
621  // Simple copy will do
622  datavec_ = other.datavec_;
623  offset_ = other.offset_;
624  volume_ = other.volume_;
625  }
626  } else // handle null and rank-0 case
627  volume_ = other.volume_;
628  }
629 
631  ~Range() = default;
632 
634 
637  Range_& operator=(const Range_& other) = default;
638 
640 
644  Range_& operator=(Range_&& other) {
645  datavec_ = std::move(other.datavec_);
646  offset_ = other.offset_;
647  volume_ = other.volume_;
648  rank_ = other.rank_;
649 
650  // put other into null state
651  other.datavec_.clear();
652  other.datavec_.shrink_to_fit();
653  other.offset_ = 0l;
654  other.volume_ = 0ul;
655  other.rank_ = 0u;
656 
657  return *this;
658  }
659 
661 
663  explicit operator bool() const { return rank() != 0; }
664 
666 
669  unsigned int rank() const { return rank_; }
670 
672 
675  std::pair<index1_type, index1_type> dim(std::size_t d) const {
676  TA_ASSERT(d < rank());
677  return std::make_pair(lobound(d), upbound(d));
678  }
679 
681 
685  const index1_type* lobound_data() const { return data(); }
686 
688 
694  }
695 
697 
700  index1_type lobound(size_t dim) const {
701  TA_ASSERT(dim < rank_);
702  return *(lobound_data() + dim);
703  }
704 
706 
710  const index1_type* upbound_data() const { return data() + rank_; }
711 
713 
719  }
720 
722 
725  index1_type upbound(size_t dim) const {
726  TA_ASSERT(dim < rank_);
727  return *(upbound_data() + dim);
728  }
729 
731 
735  const index1_type* extent_data() const { return data() + (rank_ << 1); }
736 
738 
742  return index_view_type(extent_data(), rank_);
743  }
744 
746 
749  index1_type extent(size_t dim) const {
750  TA_ASSERT(dim < rank_);
751  return *(extent_data() + dim);
752  }
753 
755 
759  const index1_type* stride_data() const { return extent_data() + rank_; }
760 
762 
767  return index_view_type(stride_data(), rank_);
768  }
769 
771 
774  index1_type stride(size_t dim) const {
775  TA_ASSERT(dim < rank_);
776  return *(stride_data() + dim);
777  }
778 
780 
783  ordinal_type volume() const { return volume_; }
784 
788  ordinal_type area() const { return volume_; }
789 
791 
795  distance_type offset() const { return offset_; }
796 
798 
804  return (volume_ > 0) ? const_iterator(lobound_data(), this) : end();
805  }
806 
808 
813  const_iterator end() const { return const_iterator(upbound_data(), this); }
814 
816 
823  template <typename Index,
824  typename std::enable_if<detail::is_integral_range_v<Index>,
825  bool>::type* = nullptr>
826  bool includes(const Index& index) const {
827  TA_ASSERT(*this);
828  const auto* MADNESS_RESTRICT const lower = lobound_data();
829  const auto* MADNESS_RESTRICT const upper = upbound_data();
830 
831  bool result = (rank_ > 0u);
832  unsigned int d = 0;
833  for (auto&& index_d : index) {
834  TA_ASSERT(d < rank_);
835  const auto lower_d = lower[d];
836  const auto upper_d = upper[d];
837  result = result && (index_d >= lower_d) && (index_d < upper_d);
838 #ifdef NDEBUG
839  if (!result) {
840  d = rank_;
841  break;
842  }
843 #endif
844  ++d;
845  }
846  TA_ASSERT(d == rank_);
847 
848  return result;
849  }
850 
852 
859  template <typename Index,
860  typename = std::enable_if_t<std::is_integral_v<Index>>>
861  bool includes(const std::initializer_list<Index>& index) const {
862  return includes<std::initializer_list<Index>>(index);
863  }
864 
866 
870  template <typename Ordinal>
871  typename std::enable_if<std::is_integral_v<Ordinal>, bool>::type includes(
872  Ordinal i) const {
873  TA_ASSERT(*this);
874  return include_ordinal_(i);
875  }
876 
877  template <typename... Index>
878  std::enable_if_t<
879  (sizeof...(Index) > 1ul) && (std::is_integral_v<Index> && ...), bool>
880  includes(const Index&... index) const {
881  const index1_type i[sizeof...(Index)] = {
882  static_cast<index1_type>(index)...};
883  return includes(i);
884  }
885 
887 
892  Range_& operator*=(const Permutation& perm);
893 
895 
904  template <
905  typename Index1, typename Index2,
906  typename = std::enable_if_t<detail::is_integral_sized_range_v<Index1> &&
907  detail::is_integral_sized_range_v<Index2>>>
908  Range_& resize(const Index1& lower_bound, const Index2& upper_bound) {
909  using std::size;
910  const auto n = size(lower_bound);
911  TA_ASSERT(n == size(upper_bound));
912 
913  // Reallocate memory for range arrays
914  if (rank_ != n) {
915  init_datavec(n);
916  rank_ = n;
917  }
918  if (n > 0ul)
919  init_range_data(lower_bound, upper_bound);
920  else
921  volume_ = 0ul;
922 
923  return *this;
924  }
925 
927 
931  template <typename Index,
932  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
933  Range_& inplace_shift(const Index& bound_shift) {
934  auto* MADNESS_RESTRICT const lower = lobound_data_nc();
935  auto* MADNESS_RESTRICT const upper = upbound_data_nc();
936  const auto* MADNESS_RESTRICT const stride = upper + rank_ + rank_;
937 
938  // update the data
939  offset_ = 0ul;
940  unsigned int d = 0;
941  for (auto&& bound_shift_d : bound_shift) {
942  TA_ASSERT(d < rank_);
943  // Load range data
944  auto lower_d = lower[d];
945  auto upper_d = upper[d];
946  const auto stride_d = stride[d];
947 
948  // Compute new range bounds
949  lower_d += bound_shift_d;
950  upper_d += bound_shift_d;
951 
952  // Update range data
953  offset_ += lower_d * stride_d;
954  lower[d] = lower_d;
955  upper[d] = upper_d;
956 
957  ++d;
958  }
959  TA_ASSERT(d == rank_);
960 
961  return *this;
962  }
963 
965 
969  template <typename Index,
970  typename = std::enable_if_t<std::is_integral_v<Index>>>
971  Range_& inplace_shift(const std::initializer_list<Index>& bound_shift) {
972  return inplace_shift<std::initializer_list<Index>>(bound_shift);
973  }
974 
976 
980  template <typename Index,
981  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
982  Range_ shift(const Index& bound_shift) {
983  Range_ result(*this);
984  result.inplace_shift(bound_shift);
985  return result;
986  }
987 
989 
993  template <typename Index,
994  typename = std::enable_if_t<std::is_integral_v<Index>>>
995  Range_ shift(const std::initializer_list<Index>& bound_shift) {
996  Range_ result(*this);
997  result.inplace_shift(bound_shift);
998  return result;
999  }
1000 
1002 
1010  return index;
1011  }
1012 
1014 
1020  template <typename Index, typename std::enable_if_t<
1021  detail::is_integral_range_v<Index>>* = nullptr>
1022  ordinal_type ordinal(const Index& index) const {
1024 
1025  auto* MADNESS_RESTRICT const stride = stride_data();
1026 
1027  ordinal_type result = 0ul;
1028  unsigned int d = 0;
1029  for (auto&& index_d : index) {
1030  TA_ASSERT(d < rank_);
1031  const auto stride_d = stride[d];
1032  result += index_d * stride_d;
1033  ++d;
1034  }
1035  TA_ASSERT(d == rank_);
1036 
1037  return result - offset_;
1038  }
1039 
1041 
1047  template <typename Index,
1048  typename = std::enable_if_t<std::is_integral_v<Index>>>
1049  ordinal_type ordinal(const std::initializer_list<Index>& index) const {
1050  return this->ordinal<std::initializer_list<Index>>(index);
1051  }
1052 
1054 
1060  template <
1061  typename... Index,
1062  typename std::enable_if_t<(sizeof...(Index) > 1ul) &&
1063  (std::is_integral_v<Index> && ...)>* = nullptr>
1064  ordinal_type ordinal(const Index&... index) const {
1065  const index1_type temp_index[sizeof...(Index)] = {
1066  static_cast<index1_type>(index)...};
1067  return ordinal(temp_index);
1068  }
1069 
1071 
1077  // Check that index is contained by range.
1078  // N.B. this will fail if any extent is zero
1080 
1081  // Construct result coordinate index object and allocate its memory.
1082  Range_::index result(rank_, 0);
1083 
1084  // Get pointers to the data
1085  auto* MADNESS_RESTRICT const result_data = result.data();
1086  const auto* MADNESS_RESTRICT const lower = lobound_data();
1087  const auto* MADNESS_RESTRICT const size = extent_data();
1088 
1089  // Compute the coordinate index of index in range.
1090  for (int i = int(rank_) - 1; i >= 0; --i) {
1091  const auto lower_i = lower[i];
1092  const auto size_i = size[i];
1093 
1094  // Compute result index element i
1095  const auto result_i = (index % size_i) + lower_i;
1096  index /= size_i;
1097 
1098  // Store result
1099  result_data[i] = result_i;
1100  }
1101 
1102  return result;
1103  }
1104 
1106 
1112  template <typename Index, typename std::enable_if_t<
1113  detail::is_integral_range_v<Index>>* = nullptr>
1114  const Index& idx(const Index& i) const {
1115  TA_ASSERT(includes(i));
1116  return i;
1117  }
1118 
1119  template <typename Archive>
1120  void serialize(Archive& ar) {
1121  ar& rank_& datavec_& offset_& volume_;
1122  }
1123 
1124  void swap(Range_& other) {
1125  // Get temp data
1126  std::swap(datavec_, other.datavec_);
1127  std::swap(offset_, other.offset_);
1128  std::swap(volume_, other.volume_);
1129  std::swap(rank_, other.rank_);
1130  }
1131 
1132  private:
1134 
1139  template <typename Index>
1140  typename std::enable_if<std::is_integral_v<Index> && std::is_signed_v<Index>,
1141  bool>::type
1142  include_ordinal_(Index i) const {
1143  return (i >= Index(0)) && (i < Index(volume_));
1144  }
1145 
1147 
1151  template <typename Index>
1152  typename std::enable_if<
1153  std::is_integral_v<Index> && !std::is_signed<Index>::value, bool>::type
1154  include_ordinal_(Index i) const {
1155  return i < volume_;
1156  }
1157 
1159 
1164  void increment(index_type& i) const {
1165  TA_ASSERT(includes(i));
1166 
1167  const auto* MADNESS_RESTRICT const lower = lobound_data();
1168  const auto* MADNESS_RESTRICT const upper = upbound_data();
1169 
1170  for (int d = int(rank_) - 1; d >= 0; --d) {
1171  // increment coordinate
1172  ++i[d];
1173 
1174  // break if done
1175  if (i[d] < upper[d]) return;
1176 
1177  // Reset current index to lower bound.
1178  i[d] = lower[d];
1179  }
1180 
1181  // if the current location was set to lower then it was at the end and
1182  // needs to be reset to equal upper.
1183  std::copy(upper, upper + rank_, i.begin());
1184  }
1185 
1187 
1193  void advance(index_type& i, std::ptrdiff_t n) const {
1194  TA_ASSERT(includes(i));
1195  const auto o = ordinal(i) + n;
1196  TA_ASSERT(includes(o));
1197  i = idx(o);
1198  }
1199 
1201 
1209  std::ptrdiff_t distance_to(const index_type& first,
1210  const index_type& last) const {
1211  TA_ASSERT(includes(first));
1212  TA_ASSERT(includes(last));
1213  return ordinal(last) - ordinal(first);
1214  }
1215 
1216 }; // class Range
1217 
1218 inline Range& Range::operator*=(const Permutation& perm) {
1219  TA_ASSERT(perm.size() == rank_);
1220  if (rank_ > 1ul) {
1221  // Copy the lower and upper bound data into a temporary array
1223  rank_ << 1);
1224  const auto* MADNESS_RESTRICT const temp_upper = temp_lower.data() + rank_;
1225  std::copy(lobound_data(), lobound_data() + (rank_ << 1), temp_lower.data());
1226 
1227  init_range_data(perm, temp_lower.data(), temp_upper);
1228  }
1229  return *this;
1230 }
1231 
1233 inline void swap(Range& r0, Range& r1) { // no throw
1234  r0.swap(r1);
1235 }
1236 
1238 
1242 inline Range operator*(const Permutation& perm, const Range& r) {
1243  return Range(perm, r);
1244 }
1245 
1247 
1252 template <typename I, typename = std::enable_if_t<std::is_integral_v<I>>>
1253 Range permute(const Range& r, std::initializer_list<I> perm) {
1254  return Permutation(perm) * r;
1255 }
1256 
1258 
1263 inline bool operator==(const Range& r1, const Range& r2) {
1264  return (r1.rank() == r2.rank()) &&
1265  !std::memcmp(r1.lobound_data(), r2.lobound_data(),
1266  r1.rank() * (2u * sizeof(Range::index1_type)));
1267 }
1268 
1270 
1275 inline bool operator!=(const Range& r1, const Range& r2) {
1276  return (r1.rank() != r2.rank()) ||
1277  std::memcmp(r1.lobound_data(), r2.lobound_data(),
1278  r1.rank() * (2u * sizeof(Range::index1_type)));
1279 }
1280 
1282 
1286 inline std::ostream& operator<<(std::ostream& os, const Range& r) {
1287  os << "[ ";
1288  detail::print_array(os, r.lobound_data(), r.rank());
1289  os << ", ";
1290  detail::print_array(os, r.upbound_data(), r.rank());
1291  os << " )";
1292  return os;
1293 }
1294 
1296 
1301 inline bool is_congruent(const Range& r1, const Range& r2) {
1302  return (r1.rank() == r2.rank()) &&
1303  std::equal(r1.extent_data(), r1.extent_data() + r1.rank(),
1304  r2.extent_data());
1305 }
1306 
1309 
1312 inline bool is_contiguous(const Range& range) { return true; }
1313 
1314 } // namespace TiledArray
1315 #endif // TILEDARRAY_RANGE_H__INCLUDED
const index1_type * lobound_data() const
Range lower bound data accessor.
Definition: range.h:685
Range_ & operator=(const Range_ &other)=default
Copy assignment operator.
Coordinate index iterate.
std::enable_if<!TiledArray::detail::is_permutation_v< Perm >, TiledArray::Range >::type permute(const TiledArray::Range &r, const Perm &p)
Definition: btas.h:803
Range_ & operator*=(const Permutation &perm)
Permute this range.
Definition: range.h:1218
boost::container::small_vector< T, N > svector
Definition: vector.h:43
index1_type * upbound_data_nc()
Definition: range.h:87
distance_type offset_
Ordinal index offset correction.
Definition: range.h:78
std::pair< index1_type, index1_type > dim(std::size_t d) const
Accessor of the d-th dimension of the range.
Definition: range.h:675
index_type size() const
Domain size accessor.
Definition: permutation.h:214
bool includes(const std::initializer_list< Index > &index) const
Check the coordinate to make sure it is within the range.
Definition: range.h:861
ordinal_type volume_
Total number of elements.
Definition: range.h:79
ordinal_type ordinal(const std::initializer_list< Index > &index) const
calculate the ordinal index of index
Definition: range.h:1049
Range(const std::initializer_list< std::initializer_list< Index >> &bounds)
Construct range defined by an initializer_list of std::initializer_list{lower,upper} bounds.
Definition: range.h:537
Range(const Index1 &lower_bound, const Index2 &upper_bound)
Construct range defined by upper and lower bound ranges.
Definition: range.h:355
const Index & idx(const Index &i) const
calculate the index of i
Definition: range.h:1114
std::make_signed_t< ordinal_type > distance_type
Distance type.
Definition: range.h:60
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:130
bool operator==(const BlockRange &r1, const BlockRange &r2)
BlockRange equality comparison.
Definition: block_range.h:433
const_iterator begin() const
Index iterator factory.
Definition: range.h:803
ordinal_type ordinal(const Index &... index) const
calculate the ordinal index of index
Definition: range.h:1064
Range(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound)
Construct range defined by the upper and lower bound ranges.
Definition: range.h:389
container::svector< index1_type > index_type
Definition: range.h:52
constexpr bool operator!=(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:382
TA_1INDEX_TYPE index1_type
Definition: range.h:49
const index1_type * upbound_data() const
Range upper bound data accessor.
Definition: range.h:710
Range(const Range_ &other)=default
Copy Constructor.
Range_ & inplace_shift(const std::initializer_list< Index > &bound_shift)
Shift the lower and upper bound of this range.
Definition: range.h:971
index1_type upbound(size_t dim) const
Range upped bound element accessor.
Definition: range.h:725
Range_ shift(const std::initializer_list< Index > &bound_shift)
Create a Range with shiften lower and upper bounds.
Definition: range.h:995
const_iterator end() const
Index iterator factory.
Definition: range.h:813
constexpr auto end(const Eigen::Matrix< _Scalar, _Rows, 1, _Options, _MaxRows, 1 > &m)
Definition: eigen.h:56
ordinal_type ordinal(const ordinal_type index) const
calculate the ordinal index of i
Definition: range.h:1008
index1_type * data()
Definition: range.h:84
std::array< T, N > operator*(const Permutation &, const std::array< T, N > &)
Permute a std::array.
Definition: permutation.h:492
ordinal_type ordinal(const Index &index) const
calculate the ordinal index of index
Definition: range.h:1022
constexpr const bool is_integral_pair_list_v
Definition: type_traits.h:939
const auto & data() const
Permutation data accessor.
Definition: permutation.h:388
index1_type * stride_data_nc()
Definition: range.h:89
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
index_view_type lobound() const
Range lower bound accessor.
Definition: range.h:692
distance_type offset() const
Range offset.
Definition: range.h:795
index_view_type extent() const
Range extent accessor.
Definition: range.h:741
bool includes(const Index &index) const
Check the coordinate to make sure it is within the range.
Definition: range.h:826
index1_type * extent_data_nc()
Definition: range.h:88
Range(const Index... extents)
Range constructor from a pack of extents for each dimension.
Definition: range.h:565
void serialize(Archive &ar)
Definition: range.h:1120
Range(const std::initializer_list< Index > &extent)
Range constructor from an initializer list of extents.
Definition: range.h:437
Range(const Permutation &perm, const Range_ &other)
Permuting copy constructor.
Definition: range.h:611
void init_datavec(unsigned int rank)
Definition: range.h:82
Range Range_
This object type.
Definition: range.h:48
Range_ & resize(const Index1 &lower_bound, const Index2 &upper_bound)
Resize range to a new upper and lower bound.
Definition: range.h:908
ordinal_type size_type
Size type (deprecated)
Definition: range.h:61
ordinal_type area() const
Definition: range.h:788
std::enable_if< std::is_integral_v< Ordinal >, bool >::type includes(Ordinal i) const
Check the ordinal index to make sure it is within the range.
Definition: range.h:871
bool is_contiguous(const BlockRange &range)
Definition: block_range.h:443
bool is_congruent(const BlockRange &r1, const BlockRange &r2)
Test that two BlockRange objects are congruent.
Definition: block_range.h:400
Range_ & operator=(Range_ &&other)
Move assignment operator.
Definition: range.h:644
index1_type extent(size_t dim) const
Range extent element accessor.
Definition: range.h:749
Range(const Index &extent)
Range constructor from a range of extents.
Definition: range.h:414
index1_type lobound(size_t dim) const
Range lower bound element accessor.
Definition: range.h:700
std::ostream & operator<<(std::ostream &os, const DistArray< Tile, Policy > &a)
Add the tensor to an output stream.
Definition: dist_array.h:1602
index_view_type stride() const
Range stride accessor.
Definition: range.h:766
container::svector< index1_type, 4 *TA_MAX_SOO_RANK_METADATA > datavec_
Definition: range.h:66
const index1_type * data() const
Definition: range.h:83
Range(const std::initializer_list< GPair > &bounds, std::enable_if_t< detail::is_gpair_v< GPair >> *=nullptr)
Construct range defined by an initializer_list of {lower,upper} bounds for each dimension given as a ...
Definition: range.h:502
const index1_type * stride_data() const
Range stride data accessor.
Definition: range.h:759
Range(const PairRange &bounds)
Construct Range defined by a range of {lower,upper} bound pairs.
Definition: range.h:480
Range()
Default constructor.
Definition: range.h:330
Range_ shift(const Index &bound_shift)
Create a Range with shiften lower and upper bounds.
Definition: range.h:982
Range(const IndexPairs... bounds)
Definition: range.h:581
void print_array(std::ostream &out, const A &a, const std::size_t n)
Print the content of an array like object.
Definition: utility.h:48
index_type extent_type
Range extent type, to conform to TWG spec.
Definition: range.h:58
std::enable_if_t<(sizeof...(Index) > 1ul) &&(std::is_integral_v< Index > &&...), bool > includes(const Index &... index) const
Definition: range.h:880
index1_type stride(size_t dim) const
Range stride element accessor.
Definition: range.h:774
ordinal_type volume() const
Range volume accessor.
Definition: range.h:783
~Range()=default
Destructor.
detail::RangeIterator< index1_type, Range_ > const_iterator
Coordinate iterator.
Definition: range.h:63
unsigned int rank_
The rank (or number of dimensions) in the range.
Definition: range.h:80
index_type idx(ordinal_type index) const
calculate the coordinate index of the ordinal index, index.
Definition: range.h:1076
decltype(auto) at(GeneralizedPair &&v, std::size_t idx)
at(pair, i) extracts i-th element from gpair
Definition: type_traits.h:1268
void swap(Range_ &other)
Definition: range.h:1124
index_view_type upbound() const
Range upper bound accessor.
Definition: range.h:717
constexpr auto begin(const Eigen::Matrix< _Scalar, _Rows, 1, _Options, _MaxRows, 1 > &m)
Definition: eigen.h:45
std::size_t ordinal_type
Ordinal type, to conform to TWG spec.
Definition: range.h:59
const index1_type * extent_data() const
Range extent data accessor.
Definition: range.h:735
Range(Range_ &&other)
Move Constructor.
Definition: range.h:594
index_type index
Coordinate index type (deprecated)
Definition: range.h:54
void swap(Range &r0, Range &r1)
Exchange the values of the give two ranges.
Definition: range.h:1233
Range_ & inplace_shift(const Index &bound_shift)
Shift the lower and upper bound of this range.
Definition: range.h:933
unsigned int rank() const
Rank accessor.
Definition: range.h:669
index1_type * lobound_data_nc()
Definition: range.h:86
A (hyperrectangular) interval on , space of integer -indices.
Definition: range.h:46
detail::SizeArray< const index1_type > index_view_type
Non-owning variant of index_type.
Definition: range.h:56