index_list.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_EXPRESSIONS_INDEX_LIST_H__INCLUDED
21 #define TILEDARRAY_EXPRESSIONS_INDEX_LIST_H__INCLUDED
22 
23 #include <algorithm>
24 #include <iosfwd>
25 #include <set>
26 #include <string>
27 #include "TiledArray/permutation.h"
29 
30 namespace TiledArray {
31 namespace expressions {
32 
33 class IndexList;
34 IndexList operator*(const ::TiledArray::Permutation&, const IndexList&);
35 void swap(IndexList&, IndexList&);
36 
37 class BipartiteIndexList;
38 BipartiteIndexList operator*(const ::TiledArray::Permutation&,
39  const BipartiteIndexList&);
40 void swap(BipartiteIndexList&, BipartiteIndexList&);
41 
42 namespace detail {
44 
69 template <typename InIter1, typename InIter2>
70 void find_common(InIter1 first1, const InIter1 last1, InIter2 first2,
71  const InIter2 last2, std::pair<InIter1, InIter1>& common1,
72  std::pair<InIter2, InIter2>& common2) {
73  common1.first = last1;
74  common1.second = last1;
75  common2.first = last2;
76  common2.second = last2;
77 
78  // find the first common element in the in the two ranges
79  for (; first1 != last1; ++first1) {
80  common2.first = std::find(first2, last2, *first1);
81  if (common2.first != last2) break;
82  }
83  common1.first = first1;
84  first2 = common2.first;
85 
86  // find the last common element in the two ranges
87  while ((first1 != last1) && (first2 != last2)) {
88  if (*first1 != *first2) break;
89  ++first1;
90  ++first2;
91  }
92  common1.second = first1;
93  common2.second = first2;
94 }
95 
96 inline Permutation var_perm(const IndexList& l, const IndexList& r);
98  const BipartiteIndexList& r);
99 
100 } // namespace detail
101 
103 
107 class IndexList {
108  public:
110  using const_iterator = typename container_type::const_iterator;
111 
113  IndexList() : indices_() {}
114 
116 
120  explicit IndexList(const std::string& str) {
121  if (!str.empty()) init_(str);
122  }
123 
125 
131  template <typename InIter>
132  IndexList(InIter first, InIter last) {
134  "IndexList constructor requires an input iterator");
135 
136  for (; first != last; ++first)
137  indices_.push_back(trim_spaces_(first->begin(), first->end()));
138  }
139 
141 
145  IndexList(const container_type& indices)
146  : IndexList(indices.begin(), indices.end()) {}
147 
148  IndexList(const IndexList& other) : indices_(other.indices_) {}
149 
150  IndexList& operator=(const IndexList& other) {
151  indices_ = other.indices_;
152 
153  return *this;
154  }
155 
156  IndexList& operator=(const std::string& str) {
157  init_(str);
158  return *this;
159  }
160 
162  TA_ASSERT(p.size() == size());
163  indices_ *= p;
164  return *this;
165  }
166 
168 
170  explicit operator bool() const { return !indices_.empty(); }
171 
173 
175  bool operator!() const { return indices_.empty(); }
176 
178  const_iterator begin() const { return indices_.begin(); }
179 
181  const_iterator end() const { return indices_.end(); }
182 
184  const std::string& at(const std::size_t n) const { return indices_.at(n); }
185 
187  const std::string& operator[](const std::size_t n) const {
188  return indices_[n];
189  }
190 
192  [[deprecated("use IndexList::size()")]] unsigned int dim() const {
193  return indices_.size();
194  }
195 
197  unsigned int size() const { return indices_.size(); }
198 
199  const auto& data() const { return indices_; }
200 
202  std::string string() const {
203  std::string result;
204  using std::cbegin;
205  auto it = cbegin(indices_);
206  if (it == indices_.end()) return result;
207 
208  for (result = *it++; it != indices_.end(); ++it) {
209  result += "," + *it;
210  }
211 
212  return result;
213  }
214 
215  void swap(IndexList& other) { std::swap(indices_, other.indices_); }
216 
220  auto count(const std::string& x) const {
221  return std::count(begin(), end(), x);
222  }
223 
230  auto positions(const std::string& x) const {
232  for (std::size_t i = 0; i < size(); ++i)
233  if ((*this)[i] == x) rv.push_back(i);
234  return rv;
235  }
236 
238 
244  template <typename V,
245  typename = std::enable_if_t<TiledArray::detail::is_range_v<V>>>
246  Permutation permutation(const V& other) const {
247  return detail::var_perm(*this, other);
248  }
249 
251 
254  bool is_permutation(const IndexList& other) const {
255  if (indices_.size() != other.indices_.size()) return false;
256 
257  for (const_iterator it = begin(); it != end(); ++it) {
258  const_iterator other_it = other.begin();
259  for (; other_it != other.end(); ++other_it)
260  if (*it == *other_it) break;
261  if (other_it == other.end()) return false;
262  }
263 
264  return true;
265  }
266 
267  private:
269  void init_(const std::string& str) {
270  std::string::const_iterator start = str.begin();
271  std::string::const_iterator finish = str.begin();
272  for (; finish != str.end(); ++finish) {
273  if (*finish == ',') {
274  indices_.push_back(trim_spaces_(start, finish));
275  start = finish + 1;
276  }
277  }
278  indices_.push_back(trim_spaces_(start, finish));
279  }
280 
283  static std::string trim_spaces_(std::string::const_iterator first,
284  std::string::const_iterator last) {
285  TA_ASSERT(first != last);
286  std::string result = "";
287  for (; first != last; ++first) {
288  TA_ASSERT(valid_char_(*first));
289  if (*first != ' ' && *first != '\0') result.append(1, *first);
290  }
291 
292  TA_ASSERT(result.length() != 0);
293 
294  return result;
295  }
296 
298  template <typename InIter>
299  bool unique_(InIter first, InIter last) const {
300  for (; first != last; ++first) {
301  InIter it2 = first;
302  for (++it2; it2 != last; ++it2)
303  if (first->compare(*it2) == 0) return false;
304  }
305 
306  return true;
307  }
308 
309  static bool valid_char_(char c) {
310  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
311  (c >= '0' && c <= '9') || (c == ' ') || (c == ',') || (c == '\0') ||
312  (c == '\'') || (c == '_');
313  }
314 
315  friend void swap(IndexList&, IndexList&);
316 
317  container_type indices_;
318 
319  friend IndexList operator*(const ::TiledArray::Permutation&,
320  const IndexList&);
321 
322 }; // class IndexList
323 
325 inline void swap(IndexList& v0, IndexList& v1) {
326  std::swap(v0.indices_, v1.indices_);
327 }
328 
329 inline bool operator==(const IndexList& v0, const IndexList& v1) {
330  return (v0.size() == v1.size()) &&
331  std::equal(v0.begin(), v0.end(), v1.begin());
332 }
333 
334 inline bool operator!=(const IndexList& v0, const IndexList& v1) {
335  return !operator==(v0, v1);
336 }
337 
338 inline IndexList operator*(const ::TiledArray::Permutation& p,
339  const IndexList& v) {
340  TA_ASSERT(p.size() == v.size());
341  IndexList result;
342  result.indices_ = p * v.indices_;
343 
344  return result;
345 }
346 
348 inline std::ostream& operator<<(std::ostream& out, const IndexList& v) {
349  out << "(";
350  std::size_t d;
351  std::size_t n = v.size() - 1;
352  for (d = 0; d < n; ++d) {
353  out << v[d] << ", ";
354  }
355  out << v[d];
356  out << ")";
357  return out;
358 }
359 
361 
365  private:
367  using container_type = typename IndexList::container_type;
368 
370  using container_pair = std::pair<container_type, container_type>;
371 
372  public:
374  typedef std::string value_type;
375 
377  typedef const value_type& const_reference;
378 
380  typedef container_type::const_iterator const_iterator;
381 
383  typedef std::size_t size_type;
384 
394  BipartiteIndexList() = default;
395 
417  explicit BipartiteIndexList(const std::string str)
418  : BipartiteIndexList(TiledArray::detail::split_index(str)) {}
419 
423  BipartiteIndexList(const BipartiteIndexList& other) = default;
424 
438 
444  BipartiteIndexList& operator=(const std::string& str) {
445  BipartiteIndexList(str).swap(*this);
446  return *this;
447  }
448 
459  TA_ASSERT(p.size() == size());
460  indices_ *= p;
461  return *this;
462  }
463 
476  bool operator==(const BipartiteIndexList& other) const {
477  return std::tie(second_size_, indices_) ==
478  std::tie(other.second_size_, other.indices_);
479  }
480 
482 
484  explicit operator bool() const { return !indices_.empty(); }
485 
487 
489  bool operator!() const { return indices_.empty(); }
490 
514  const_iterator begin() const { return indices_.begin(); }
515 
538  const_iterator end() const { return indices_.end(); }
539 
550  const_reference at(const size_type n) const { return indices_.at(n); }
551 
561  const_reference operator[](const size_type n) const { return indices_[n]; }
562 
578  auto positions(const std::string& x) const {
580  for (size_type i = 0; i < size(); ++i)
581  if ((*this)[i] == x) rv.push_back(i);
582  return rv;
583  }
584 
595  size_type count(const std::string& x) const {
596  return std::count(begin(), end(), x);
597  }
598 
606  [[deprecated("use BipartiteIndexList::size()")]] size_type dim() const {
607  return size();
608  }
609 
611  size_type first_size() const { return size() - second_size(); }
612 
625  size_type second_size() const { return second_size_; }
626 
627  IndexList first() const { return IndexList(begin(), begin() + first_size()); }
628 
629  IndexList second() const { return IndexList(begin() + first_size(), end()); }
630 
642  size_type size() const { return indices_.size(); }
643 
644  const auto& data() const { return indices_; }
645 
652  explicit operator value_type() const;
653 
659  void swap(BipartiteIndexList& other) noexcept {
660  std::swap(second_size_, other.second_size_);
661  std::swap(indices_, other.indices_);
662  }
663 
665 
682  template <typename V,
683  typename = std::enable_if_t<TiledArray::detail::is_range_v<V>>>
684  BipartitePermutation permutation(const V& other) const {
685  return detail::var_perm(*this, other);
686  }
687 
689 
692  bool is_permutation(const BipartiteIndexList& other) const {
693  if (other.size() != size()) return false;
694  return std::is_permutation(begin(), end(), other.begin());
695  }
696 
698  template <typename OuterType, typename InnerType>
699  BipartiteIndexList(OuterType&& outer, InnerType&& inner);
700 
701  private:
703  template <typename First, typename Second>
704  explicit BipartiteIndexList(const std::pair<First, Second>& tot_idx)
705  : BipartiteIndexList(tot_idx.first, tot_idx.second) {}
706 
708  size_type second_size_ = 0;
709 
711  container_type indices_;
712 
713  friend BipartiteIndexList operator*(const ::TiledArray::Permutation&,
714  const BipartiteIndexList&);
715 
716 }; // class BipartiteIndexList
717 
719 template <typename T, typename... Args>
720 auto all_annotations(T&& v, Args&&... args) {
721  std::set<std::string> rv;
722  if constexpr (sizeof...(Args) > 0) {
723  rv = all_annotations(std::forward<Args>(args)...);
724  }
725  rv.insert(v.begin(), v.end());
726  return rv;
727 }
728 
730 template <typename T, typename... Args>
731 auto common_annotations(T&& v, Args&&... args) {
732  std::set<std::string> rv;
733  if constexpr (sizeof...(Args) > 0) {
734  rv = common_annotations(std::forward<Args>(args)...);
735  // Remove all annotations not found in v
736  decltype(rv) buffer(rv);
737  for (const auto& x : buffer)
738  if (!v.count(x)) rv.erase(x);
739  } else {
740  // Initialize rv to all annotations in v
741  rv.insert(v.begin(), v.end());
742  }
743  return rv;
744 }
745 
746 template <typename IndexList_, typename... Args>
747 auto bound_annotations(const IndexList_& out, Args&&... args) {
748  // Get all indices in the input tensors
749  auto rv = all_annotations(std::forward<Args>(args)...);
750 
751  // Remove those found in the output tensor
752  decltype(rv) buffer(rv);
753  for (const auto& x : buffer)
754  if (out.count(x)) rv.erase(x);
755  return rv;
756 }
757 
760  v0.swap(v1);
761 }
762 
775 inline bool operator!=(const BipartiteIndexList& v0,
776  const BipartiteIndexList& v1) {
777  return !(v0 == v1);
778 }
779 
780 inline BipartiteIndexList operator*(const ::TiledArray::Permutation& p,
781  const BipartiteIndexList& v) {
782  TA_ASSERT(p.size() == v.size());
783  BipartiteIndexList result(v);
784  return result *= p;
785 }
786 
795 inline std::ostream& operator<<(std::ostream& out,
796  const BipartiteIndexList& v) {
797  const std::string str = "(" + static_cast<std::string>(v) + ")";
798  return out << str;
799 }
800 
801 //------------------------------------------------------------------------------
802 // Implementations
803 //------------------------------------------------------------------------------
804 
805 inline BipartiteIndexList::operator value_type() const {
806  value_type result;
807  for (size_type i = 0; i < size(); ++i) {
808  if (i == first_size())
809  result += ";";
810  else if (i > 0)
811  result += ",";
812  result += at(i);
813  }
814 
815  return result;
816 }
817 
818 template <typename OuterType, typename InnerType>
820  InnerType&& inner)
821  : second_size_(inner.size()), indices_(outer.size() + inner.size()) {
822  for (size_type i = 0; i < outer.size(); ++i) indices_[i] = outer[i];
823  for (size_type i = 0; i < inner.size(); ++i)
824  indices_[i + outer.size()] = inner[i];
825 }
826 
827 namespace detail {
828 
829 inline Permutation var_perm(const IndexList& l, const IndexList& r) {
830  using std::size;
831  TA_ASSERT(size(l) == size(r));
832  container::svector<size_t> a(size(l));
833  using std::begin;
834  using std::end;
835  auto rit = begin(r);
836  for (auto it = begin(a); it != end(a); ++it) {
837  auto lit = std::find(begin(l), end(l), *rit++);
838  TA_ASSERT(lit != end(l));
839  *it = std::distance(begin(l), lit);
840  }
841  return Permutation(std::move(a));
842 }
843 
845  const BipartiteIndexList& r) {
846  using std::size;
847  TA_ASSERT(size(l) == size(r));
848  TA_ASSERT(l.first_size() == r.first_size());
849  container::svector<size_t> a(size(l));
850  using std::begin;
851  using std::end;
852  auto rit = begin(r);
853  for (auto it = begin(a); it != end(a); ++it) {
854  auto lit = std::find(begin(l), end(l), *rit++);
855  TA_ASSERT(lit != end(l));
856  *it = std::distance(begin(l), lit);
857  }
858  // Make sure this permutation doesn't mix outer and inner tensors
859  if (l.second_size() > 0) {
860  auto outer_size = l.first_size();
861  for (decltype(outer_size) i = 0; i < outer_size; ++i)
862  TA_ASSERT(a[i] < outer_size);
863  for (auto i = outer_size; i < a.size(); ++i) TA_ASSERT(a[i] >= outer_size);
864  }
865  return BipartitePermutation(std::move(a), l.second_size());
866 }
867 
868 } // namespace detail
869 
871 
872 inline auto inner(const IndexList& p) {
873  abort();
874  return IndexList{};
875 }
876 
877 // N.B. can't return ref here due to possible dangling ref when p is bound to
878 // temporary
879 inline auto outer(const IndexList& p) { return p; }
880 
881 inline auto inner_size(const IndexList& p) { return 0; }
882 
883 inline auto outer_size(const IndexList& p) { return p.size(); }
884 
885 inline auto inner(const BipartiteIndexList& p) { return p.second(); }
886 
887 inline auto outer(const BipartiteIndexList& p) { return p.first(); }
888 
889 inline auto inner_size(const BipartiteIndexList& p) { return p.second_size(); }
890 
891 inline auto outer_size(const BipartiteIndexList& p) { return p.first_size(); }
892 
893 } // namespace expressions
894 
895 } // namespace TiledArray
896 
897 #endif // TILEDARRAY_EXPRESSIONS_INDEX_LIST_H__INCLUDED
size_type count(const std::string &x) const
Definition: index_list.h:595
auto outer_size(const IndexList &p)
Definition: index_list.h:883
boost::container::small_vector< T, N > svector
Definition: vector.h:43
bool operator!() const
Not operator.
Definition: index_list.h:175
IndexList(const container_type &indices)
constructs from a container of index labels
Definition: index_list.h:145
BipartiteIndexList(const std::string str)
Definition: index_list.h:417
index_type size() const
Domain size accessor.
Definition: permutation.h:214
bool is_permutation(const IndexList &other) const
Check that this index list is a permutation of other.
Definition: index_list.h:254
BipartiteIndexList & operator=(const std::string &str)
Definition: index_list.h:444
void find_common(InIter1 first1, const InIter1 last1, InIter2 first2, const InIter2 last2, std::pair< InIter1, InIter1 > &common1, std::pair< InIter2, InIter2 > &common2)
Finds the range of common elements for two sets of iterators.
Definition: index_list.h:70
container_type::const_iterator const_iterator
A read-only random-access iterator.
Definition: index_list.h:380
container::svector< std::string > container_type
Definition: index_list.h:109
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:130
bool operator==(const IndexList &v0, const IndexList &v1)
Definition: index_list.h:329
auto outer(const IndexList &p)
Definition: index_list.h:879
std::string string() const
comma-separated concatenator of indices
Definition: index_list.h:202
void swap(BipartiteIndexList &other) noexcept
Definition: index_list.h:659
IndexList()
Constructs an empty index list.
Definition: index_list.h:113
friend IndexList operator*(const ::TiledArray::Permutation &, const IndexList &)
Definition: index_list.h:338
const std::string & operator[](const std::size_t n) const
Returns the n-th index.
Definition: index_list.h:187
auto positions(const std::string &x) const
Definition: index_list.h:578
const_reference operator[](const size_type n) const
Definition: index_list.h:561
std::enable_if< TiledArray::detail::is_numeric_v< Scalar >, ScalAddExpr< Left, Right, Scalar > >::type operator*(const AddExpr< Left, Right > &expr, const Scalar &factor)
Scaled-addition expression factor.
Definition: add_expr.h:191
IndexList & operator=(const std::string &str)
Definition: index_list.h:156
bool operator!=(const IndexList &v0, const IndexList &v1)
Definition: index_list.h:334
const_iterator begin() const
Returns an iterator to the first index.
Definition: index_list.h:178
auto split_index(const std::string &idx)
Definition: annotation.h:191
std::size_t size_type
Type used for indexing and offsets.
Definition: index_list.h:383
auto common_annotations(T &&v, Args &&... args)
Returns the set of annotations found in all of the index lists.
Definition: index_list.h:731
auto inner(const IndexList &p)
Definition: index_list.h:872
typename container_type::const_iterator const_iterator
Definition: index_list.h:110
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
void swap(BipartiteIndexList &, BipartiteIndexList &)
Exchange the content of the two index lists.
Definition: index_list.h:759
const std::string & at(const std::size_t n) const
Returns the n-th index.
Definition: index_list.h:184
Permutation permutation(const V &other) const
Computes permutation that converts an index list to this list.
Definition: index_list.h:246
BipartiteIndexList & operator*=(const Permutation &p)
Definition: index_list.h:458
const value_type & const_reference
A read-only reference to a string index.
Definition: index_list.h:377
IndexList(const std::string &str)
constructs from a string
Definition: index_list.h:120
Permutation var_perm(const IndexList &l, const IndexList &r)
Definition: index_list.h:829
bool operator==(const BipartiteIndexList &other) const
Definition: index_list.h:476
auto all_annotations(T &&v, Args &&... args)
Returns a set of each annotation found in at least one of the index lists.
Definition: index_list.h:720
const_reference at(const size_type n) const
Definition: index_list.h:550
IndexList(InIter first, InIter last)
constructs from a range of index labels
Definition: index_list.h:132
auto bound_annotations(const IndexList_ &out, Args &&... args)
Definition: index_list.h:747
friend BipartiteIndexList operator*(const ::TiledArray::Permutation &, const BipartiteIndexList &)
Definition: index_list.h:780
void swap(IndexList &, IndexList &)
Exchange the content of the two index lists.
Definition: index_list.h:325
BipartiteIndexList & operator=(const BipartiteIndexList &other)=default
std::string value_type
Type used to store the individual string indices.
Definition: index_list.h:374
unsigned int size() const
Returns the number of elements in the index list.
Definition: index_list.h:197
IndexList & operator*=(const Permutation &p)
Definition: index_list.h:161
bool is_permutation(const BipartiteIndexList &other) const
Check that this index list is a permutation of other.
Definition: index_list.h:692
BipartiteIndexList(const BipartiteIndexList &other)=default
const_iterator end() const
Returns an iterator to the end of the index list.
Definition: index_list.h:181
bool operator!() const
Not operator.
Definition: index_list.h:489
auto count(const std::string &x) const
Definition: index_list.h:220
auto positions(const std::string &x) const
Definition: index_list.h:230
decltype(auto) at(GeneralizedPair &&v, std::size_t idx)
at(pair, i) extracts i-th element from gpair
Definition: type_traits.h:1268
unsigned int dim() const
Returns the number of elements in the index list.
Definition: index_list.h:192
Permutation of a bipartite set.
Definition: permutation.h:610
auto inner_size(const IndexList &p)
Definition: index_list.h:881
ExprTraceTarget operator<<(std::ostream &os, const TsrExpr< A, Alias > &tsr)
Expression trace factory function.
Definition: expr_trace.h:130
BipartitePermutation permutation(const V &other) const
Computes the permutation to go from other to this instance.
Definition: index_list.h:684
IndexList & operator=(const IndexList &other)
Definition: index_list.h:150
IndexList(const IndexList &other)
Definition: index_list.h:148
void swap(IndexList &other)
Definition: index_list.h:215