ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
indexing_sorted.hpp
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * ALPS MPS DMRG Project
4  *
5  * Copyright (C) 2013 Institute for Theoretical Physics, ETH Zurich
6  * 2011-2011 by Bela Bauer <bauerb@phys.ethz.ch>
7  *
8  * This software is part of the ALPS Applications, published under the ALPS
9  * Application License; you can use, redistribute it and/or modify it under
10  * the terms of the license, either version 1 or (at your option) any later
11  * version.
12  *
13  * You should have received a copy of the ALPS Application License along with
14  * the ALPS Applications; see the file LICENSE.txt. If not, the license is also
15  * available from http://alps.comp-phys.org/.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  *****************************************************************************/
26 
27 #ifndef TENSOR_INDEXING_H
28 #define TENSOR_INDEXING_H
29 
30 #include <vector>
31 #include <algorithm>
32 #include <utility>
33 
34 #include <boost/unordered_map.hpp>
35 #include <boost/container/flat_set.hpp>
36 #include <boost/container/flat_map.hpp>
37 #include <boost/array.hpp>
38 #include <boost/lambda/lambda.hpp>
39 #include <boost/lambda/bind.hpp>
40 
41 #ifdef PYTHON_EXPORTS
42 #include <mp_tensors/wrappers.h>
43 #endif
44 
45 #include <boost/serialization/serialization.hpp>
46 #include <boost/serialization/utility.hpp>
47 #include <boost/serialization/vector.hpp>
48 
49 
50 namespace index_detail
51 {
52  template<class SymmGroup>
53  bool lt(std::pair<typename SymmGroup::charge, std::size_t> const & a,
54  std::pair<typename SymmGroup::charge, std::size_t> const & b)
55  {
56  return a.first < b.first;
57  }
58 
59  template<class SymmGroup>
60  struct gt{
61  bool operator()(std::pair<typename SymmGroup::charge, std::size_t> const & a,
62  std::pair<typename SymmGroup::charge, std::size_t> const & b){
63  return a.first > b.first;
64  }
65  };
66 
67  template<class SymmGroup>
68  typename SymmGroup::charge get_first(std::pair<typename SymmGroup::charge, std::size_t> const & x)
69  {
70  return x.first;
71  }
72 
73  template<class SymmGroup>
74  std::size_t get_second(std::pair<typename SymmGroup::charge, std::size_t> const & x)
75  {
76  return x.second;
77  }
78 
79  // simpler, and potentially faster since inlining is easier for the compiler
80  template<class SymmGroup>
82  {
83  public:
84  is_first_equal(typename SymmGroup::charge c) : c_(c) { }
85 
86  bool operator()(std::pair<typename SymmGroup::charge, std::size_t> const & x) const
87  {
88  return x.first == c_;
89  }
90 
91  private:
92  typename SymmGroup::charge c_;
93  };
94 }
95 
96 template<class SymmGroup>
98 
99 template<class SymmGroup> class Index
100 : protected std::vector<std::pair<typename SymmGroup::charge, std::size_t> >
101 {
102  typedef std::vector<std::pair<typename SymmGroup::charge, std::size_t> > base_t;
103  typedef boost::container::flat_map<typename SymmGroup::charge, std::size_t> pos_t;
104 
105 public:
106  typedef typename SymmGroup::charge charge;
107  typedef typename base_t::value_type value_type;
108 
109  typedef typename base_t::iterator iterator;
110  typedef typename base_t::const_iterator const_iterator;
111 
112  typedef typename base_t::reverse_iterator reverse_iterator;
113  typedef typename base_t::const_reverse_iterator const_reverse_iterator;
114 
116 
117  static const bool sorted = true;
118 
119  // This seems to be necessary because the flat_map has weird copy/assignment semantics
121  {
122  std::swap(static_cast<base_t&>(*this), static_cast<base_t&>(rhs));
123  positions.swap(rhs.positions);
124  return *this;
125  }
126 
127  std::size_t size_of_block(charge c) const
128  {
129  assert( has(c) );
130  return (*this)[position(c)].second;
131  }
132 
133  std::size_t size_of_block(charge c, bool position_check) const
134  {
135  // I have to ignore the position_check argument because I can't dereference the end() iterator anyway
136  typename pos_t::const_iterator it = positions.find(c);
137  if (it == positions.end())
138  return 0;
139  return (*this)[it->second].second;
140  }
141 
142  std::size_t position(charge c) const
143  {
144  typename pos_t::const_iterator it = positions.find(c);
145  if (it == positions.end())
146  return this->size();
147  else
148  return positions.find(c)->second;
149  }
150 
151  std::size_t position(std::pair<charge, std::size_t> x) const
152  {
153  assert( has(x.first) );
154  assert( x.second < size_of_block(x.first) );
155  const_iterator to = this->begin()+position(x.first);
156  return x.second + std::accumulate(this->begin(), to, 0,
157  boost::lambda::_1 + boost::lambda::bind(index_detail::get_second<SymmGroup>, boost::lambda::_2)
158  );
159  }
160 
161  bool has(charge c) const
162  {
163  return positions.count(c) > 0;
164  }
165 
166  void sort()
167  {
168  std::sort(this->begin(), this->end(), index_detail::gt<SymmGroup>());
169  calc_positions();
170  }
171 
172  std::size_t insert(std::pair<charge, std::size_t> const & x)
173  {
174  std::size_t d = destination(x.first);
175  std::vector<std::pair<charge, std::size_t> >::insert(this->begin() + d, x);
176  calc_positions();
177  return d;
178  }
179 
180  void insert(std::size_t position, std::pair<charge, std::size_t> const & x)
181  {
182  std::vector<std::pair<charge, std::size_t> >::insert(this->begin() + position, x);
183  calc_positions();
184  }
185 
186  void shift(charge diff)
187  {
188  for (std::size_t k = 0; k < this->size(); ++k)
189  (*this)[k].first = SymmGroup::fuse((*this)[k].first, diff);
190  calc_positions();
191  }
192 
193  bool operator==(Index const & o) const
194  {
195  return (this->size() == o.size()) && std::equal(this->begin(), this->end(), o.begin());
196  }
197 
198  bool operator!=(Index const & o) const
199  {
200  return !( *this == o );
201  }
202 
204  {
205  assert( this->size() > 0 );
206  return basis_iterator(*this);
207  }
208 
209  std::vector<charge> charges() const
210  {
211  std::vector<charge> ret(this->size());
212  for (std::size_t k = 0; k < this->size(); ++k) ret[k] = (*this)[k].first;
213  return ret;
214  }
215 
216  std::vector<std::size_t> sizes() const
217  {
218  std::vector<std::size_t> ret(this->size());
219  for (std::size_t k = 0; k < this->size(); ++k) ret[k] = (*this)[k].second;
220  return ret;
221  }
222 
223  std::size_t sum_of_sizes() const
224  {
225  return std::accumulate(this->begin(), this->end(), 0,
226  boost::lambda::_1 + boost::lambda::bind(index_detail::get_second<SymmGroup>, boost::lambda::_2));
227  }
228 
229  // This is mostly forwarding of the std::vector
230  iterator begin() { return base_t::begin(); }
231  iterator end() { return base_t::end(); }
232  const_iterator begin() const { return base_t::begin(); }
233  const_iterator end() const { return base_t::end(); }
234 
235  reverse_iterator rbegin() { return base_t::rbegin(); }
236  reverse_iterator rend() { return base_t::rend(); }
237  const_reverse_iterator rbegin() const { return base_t::rbegin(); }
238  const_reverse_iterator rend() const { return base_t::rend(); }
239 
240  value_type & operator[](std::size_t p) { return static_cast<base_t&>(*this)[p]; }
241  value_type const & operator[](std::size_t p) const { return static_cast<base_t const&>(*this)[p]; }
242 
243  boost::tuple<charge, std::size_t> element(std::size_t p) const
244  {
245  std::size_t i=0;
246  while (p >= (*this)[i].second) {
247  p -= (*this)[i].second;
248  ++i;
249  }
250  return boost::make_tuple( (*this)[i].first, p );
251  }
252 
253  std::size_t size() const { return base_t::size(); }
254 
255  iterator erase(iterator p) { iterator r = base_t::erase(p); calc_positions(); return r; }
256  iterator erase(iterator a, iterator b) { iterator r = base_t::erase(a,b); calc_positions(); return r; }
257 
258 private:
259  pos_t positions;
260 
261  void push_back(std::pair<charge, std::size_t> const & x){
262  base_t::push_back(x);
263  }
264 
265  void calc_positions() {
266  positions.clear();
267  for (const_iterator it = this->begin(); it != this->end(); ++it)
268  positions[it->first] = it-this->begin();
269  }
270 
271  std::size_t destination(charge c) const
272  {
273  return std::find_if(this->begin(), this->end(),
274  boost::lambda::bind(index_detail::lt<SymmGroup>,
275  boost::lambda::_1,
276  std::make_pair(c, 0))) - this->begin();
277  }
278 
279 public:
280 #ifdef PYTHON_EXPORTS
281  std::size_t py_insert(wrapped_pair<SymmGroup> p)
282  {
283  return this->insert(p.data_);
284  }
285 #endif /* PYTHON_EXPORTS */
286 
287  template<class Archive>
288  void load(Archive & ar)
289  {
290  typedef std::vector<std::pair<typename SymmGroup::charge, std::size_t> > my_type;
291  ar["Index"] >> static_cast<my_type&>(*this);
292  calc_positions();
293  }
294 
295  template<class Archive>
296  void save(Archive & ar) const
297  {
298  typedef std::vector<std::pair<typename SymmGroup::charge, std::size_t> > my_type;
299  ar["Index"] << static_cast<my_type const &>(*this);
300  }
301 
302  friend class boost::serialization::access;
303 
304  template <class Archive>
305  void load(Archive & ar, const unsigned int version)
306  {
307  ar & boost::serialization::base_object<base_t>(*this);
308  calc_positions();
309  }
310  template <class Archive>
311  void save(Archive & ar, const unsigned int version) const
312  {
313  ar & boost::serialization::base_object<base_t>(*this);
314  }
315 
316  BOOST_SERIALIZATION_SPLIT_MEMBER()
317 };
318 
319 template<class SymmGroup>
321 {
322 public:
323  typedef typename SymmGroup::charge charge;
324  typedef std::size_t size_t;
325 
327  Index<SymmGroup> const & b)
328  {
329  init(a, b, static_cast<charge(*)(charge, charge)>(SymmGroup::fuse));
330  }
331 
332  template<class Fusion>
334  Index<SymmGroup> const & b,
335  Fusion f)
336  {
337  init(a, b, f);
338  }
339 
340 private:
341  template<class Fusion>
342  void init(Index<SymmGroup> const & a,
343  Index<SymmGroup> const & b,
344  Fusion f)
345  {
346  keys_vals_.rehash((keys_vals_.size() + a.size()*b.size()) / keys_vals_.max_load_factor() + 1); // from http://www.boost.org/doc/libs/1_37_0/doc/html/unordered/buckets.html
347  for (typename Index<SymmGroup>::const_iterator it1 = a.begin(); it1 != a.end(); ++it1)
348  for (typename Index<SymmGroup>::const_iterator it2 = b.begin(); it2 != b.end(); ++it2)
349  {
350  charge pc = f(it1->first, it2->first);
351  keys_vals_[std::make_pair(it1->first, it2->first)] = size_[pc];
352  // keys_vals_.insert(std::make_pair(std::make_pair(it1->first, it2->first),size_[pc]));
353  size_[pc] += it1->second * it2->second;
354  }
355  }
356 
357 public:
358  size_t operator()(charge a, charge b) const
359  {
360  typedef typename boost::unordered_map<std::pair<charge, charge>, size_t>::const_iterator match_type;
361  match_type match = keys_vals_.find(std::make_pair(a,b));
362  assert( match != keys_vals_.end() );
363  return match->second;
364  }
365 
366  inline size_t size(charge pc) const
367  {
368  assert(size_.count(pc) > 0);
369  return size_[pc];
370  }
371 
372  // for the moment let's avoid the default template argument (C++11)
373  inline size_t size(charge a, charge b) const
374  {
375  return size(a, b, static_cast<charge(*)(charge, charge)>(SymmGroup::fuse));
376  }
377  template<class Fusion>
378  size_t size(charge a, charge b, Fusion f) const
379  {
380  charge pc = f(a, b);
381  assert(size_.count(pc) > 0);
382  return size_[pc];
383  }
384 
385 private:
386  mutable boost::unordered_map<charge, size_t> size_;
387  boost::unordered_map<std::pair<charge, charge>, size_t> keys_vals_;
388 };
389 
390 template<class SymmGroup>
391 class basis_iterator_
392 {
393 public:
394  typedef typename SymmGroup::charge charge;
395 
396  basis_iterator_(Index<SymmGroup> const & idx, bool at_end = false)
397  : idx_(idx)
398  , cur_block(idx.begin())
399  , cur_i(0)
400  , max_i(cur_block->second)
401  { }
402 
403  std::pair<charge, std::size_t> operator*() const
404  {
405  return std::make_pair(cur_block->first, cur_i);
406  }
407 
408  boost::shared_ptr<std::pair<charge, std::size_t> > operator->() const
409  {
410  return boost::shared_ptr<std::pair<charge, std::size_t> >(new std::pair<charge, std::size_t>(cur_block->first, cur_i));
411  }
412 
414  {
415  ++cur_i;
416  if (cur_i != max_i)
417  return *this;
418  else {
419  ++cur_block;
420  if (cur_block != idx_.end()) {
421  cur_i = 0;
422  max_i = cur_block->second;
423  }
424  return *this;
425  }
426  }
427 
429  {
430  assert( k >= 0 );
431  basis_iterator_ r = *this;
432  for ( ; k > 0; --k)
433  ++r;
434  return r;
435  }
436 
437  bool end() const
438  {
439  return cur_block == idx_.end();
440  }
441 
442 private:
443  Index<SymmGroup> const & idx_;
444  typename Index<SymmGroup>::const_iterator cur_block;
445  std::size_t cur_i, max_i;
446 };
447 
448 template<class SymmGroup>
450 {
451  for ( ; p > 0; --p)
452  ++it;
453  return it;
454 }
455 
456 // This is a workaround for MSVC++
457 // It can be removed as soon as this bug is fixed:
458 // http://social.msdn.microsoft.com/Forums/en/vclanguage/thread/bab04536-8a8d-4b5e-9a49-e10144688667
459 
460 #if defined(WIN32) || defined(WIN64)
461 template<class A, class B> std::pair<A, B> mypair(A & a, B & b) { return std::pair<A,B>(a,b); }
462 #endif
463 
464 // with sorted index we actually impose strong equality
465 template<class SymmGroup>
466 bool weak_equal(Index<SymmGroup> const & a, Index<SymmGroup> const & b)
467 {
468  return (a == b);
469 }
470 
471 template<class SymmGroup>
473 {
474  typedef typename SymmGroup::charge charge;
475 
476  std::vector<charge> oc = inp.charges(), nc = inp.charges();
477  std::transform(nc.begin(), nc.end(), nc.begin(), std::negate<charge>());
478  std::sort(nc.begin(), nc.end());
479 
480  std::vector<std::size_t> nd(inp.size()), od = inp.sizes();
481  for (unsigned int i = 0; i < nd.size(); ++i)
482  nd[i] = od[std::find(oc.begin(), oc.end(),
483  -nc[i])-oc.begin()];
484 
485  Index<SymmGroup> ret;
486  for (size_t i=0; i<nc.size(); ++i)
487 #if not defined(WIN32) && not defined(WIN64)
488  ret.insert(std::make_pair(nc[i], nd[i]));
489 #else
490  ret.insert(mypair(nc[i], nd[i]));
491 #endif
492  return ret;
493 }
494 
495 template<class SymmGroup>
496 std::ostream& operator<<(std::ostream& os, Index<SymmGroup> const & idx)
497 {
498  os << "|";
499  for (typename Index<SymmGroup>::const_iterator it = idx.begin();
500  it != idx.end();
501  ++it)
502  {
503  os << "( " << it->first << ": " << it->second << " )";
504  }
505  os << "|";
506 
507  return os;
508 }
509 
510 template<class SymmGroup>
512  Index<SymmGroup> const & i2)
513 {
514  typedef typename SymmGroup::charge charge;
515 
516  Index<SymmGroup> ret;
517  for (typename Index<SymmGroup>::const_iterator it1 = i1.begin(); it1 != i1.end(); ++it1)
518  for (typename Index<SymmGroup>::const_iterator it2 = i2.begin(); it2 != i2.end(); ++it2)
519  {
520  charge pdc = SymmGroup::fuse(it1->first, it2->first);
521  std::size_t ps = it1->second * it2->second;
522  std::size_t match = ret.position(pdc);
523  if (match < ret.size())
524  ret[match].second += ps;
525  else
526  ret.insert(std::make_pair(pdc, ps));
527  }
528  ret.sort();
529  return ret;
530 }
531 
532 template<class SymmGroup>
534  Index<SymmGroup> & b)
535 {
536  a.erase(std::remove_if(a.begin(), a.end(),
537  !boost::lambda::bind(&Index<SymmGroup>::has, b,
538  boost::lambda::bind(index_detail::get_first<SymmGroup>, boost::lambda::_1))),
539  a.end());
540 
541  b.erase(std::remove_if(b.begin(), b.end(),
542  !boost::lambda::bind(&Index<SymmGroup>::has, a,
543  boost::lambda::bind(index_detail::get_first<SymmGroup>, boost::lambda::_1))),
544  b.end());
545  return a;
546 }
547 
548 template<class charge>
549 std::pair<charge, std::size_t> operator-(std::pair<charge, std::size_t> const & p)
550 {
551  return std::make_pair(-p.first, p.second);
552 }
553 
554 template<class T> boost::array<T, 1> _(T const & a)
555 {
556  boost::array<T, 1> r;
557  r[0] = a;
558  return r;
559 }
560 
561 template<class T> boost::array<T, 2> _(T const & a, T const & b)
562 {
563  boost::array<T, 2> r;
564  r[0] = a;
565  r[1] = b;
566  return r;
567 }
568 
569 #define IMPL_COMMA(tpl, type) \
570 tpl boost::array<type, 2> operator^(type const & a, type const & b) { \
571  boost::array<type, 2> ret; \
572  ret[0] = a; \
573  ret[1] = b; \
574  return ret; \
575 }
576 #define IMPL_COMMA_2(tpl, type) \
577 tpl boost::array<type, L+1> operator^(boost::array<type, L> const & a, type const & b) { \
578  boost::array<type, L+1> ret; \
579  std::copy(a.begin(), a.end(), ret.begin()); \
580  ret[L] = b; \
581  return ret; \
582 }
583 
584 #define CO ,
585 
586 IMPL_COMMA(template<class SymmGroup>, Index<SymmGroup>)
587 IMPL_COMMA(template<class charge>, std::pair<charge CO std::size_t>)
588 
589 #undef CO
590 #undef IMPL_COMMA
591 #undef IMPL_COMMA_2
592 
593 template<class T, unsigned long L>
594 boost::array<T, L+1> operator^(boost::array<T, L> const & a, T const & b)
595 {
596  boost::array<T, L+1> ret;
597  std::copy(a.begin(), a.end(), ret.begin());
598  ret[L] = b;
599  return ret;
600 }
601 
602 template<class T, unsigned long L>
603 boost::array<T, L+1> operator^(T const & a, boost::array<T, L> const & b)
604 {
605  boost::array<T, L+1> ret;
606  ret[0] = a;
607  for (int i = 0; i < L; i++)
608  ret[i+1] = b[i];
609  return ret;
610 }
611 
612 
613 #endif
size_t size(charge a, charge b, Fusion f) const
void load(Archive &ar, const unsigned int version)
bool operator==(Index const &o) const
basis_iterator_< SymmGroup > basis_iterator
SymmGroup::charge charge
std::vector< std::size_t > sizes() const
void sort()
const_iterator end() const
SymmGroup::charge charge
#define IMPL_COMMA(tpl, type)
const_reverse_iterator rbegin() const
bool end() const
void insert(std::size_t position, std::pair< charge, std::size_t > const &x)
base_t::const_iterator const_iterator
bool lt(std::pair< typename SymmGroup::charge, std::size_t > const &a, std::pair< typename SymmGroup::charge, std::size_t > const &b)
iterator begin()
Index< SymmGroup > adjoin(Index< SymmGroup > const &inp)
Index< SymmGroup > operator*(Index< SymmGroup > const &i1, Index< SymmGroup > const &i2)
bool has(charge c) const
const_reverse_iterator rend() const
SymmGroup::charge charge
reverse_iterator rend()
basis_iterator basis_begin() const
void swap(MPSTensor< Matrix, SymmGroup > &x, MPSTensor< Matrix, SymmGroup > &y)
boost::tuple< charge, std::size_t > element(std::size_t p) const
std::size_t size_t
boost::shared_ptr< std::pair< charge, std::size_t > > operator->() const
std::pair< charge, std::size_t > operator*() const
size_t size(charge pc) const
is_first_equal(typename SymmGroup::charge c)
std::size_t size_of_block(charge c) const
const_iterator begin() const
void save(Archive &ar, const unsigned int version) const
basis_iterator_ & operator++()
void shift(charge diff)
basis_iterator_(Index< SymmGroup > const &idx, bool at_end=false)
std::size_t size_of_block(charge c, bool position_check) const
value_type const & operator[](std::size_t p) const
base_t::reverse_iterator reverse_iterator
size_t size(charge a, charge b) const
ProductBasis(Index< SymmGroup > const &a, Index< SymmGroup > const &b)
basis_iterator_< SymmGroup > operator+(basis_iterator_< SymmGroup > it, std::size_t p)
#define CO
basis_iterator_ operator+(int k)
boost::array< T, 1 > _(T const &a)
SymmGroup::charge get_first(std::pair< typename SymmGroup::charge, std::size_t > const &x)
std::pair< charge, std::size_t > operator-(std::pair< charge, std::size_t > const &p)
bool weak_equal(Index< SymmGroup > const &a, Index< SymmGroup > const &b)
reverse_iterator rbegin()
iterator erase(iterator p)
bool operator()(std::pair< typename SymmGroup::charge, std::size_t > const &x) const
Index & operator=(Index rhs)
bool operator()(std::pair< typename SymmGroup::charge, std::size_t > const &a, std::pair< typename SymmGroup::charge, std::size_t > const &b)
std::size_t position(std::pair< charge, std::size_t > x) const
iterator end()
std::size_t position(charge c) const
value_type & operator[](std::size_t p)
iterator erase(iterator a, iterator b)
std::pair< bool, typename Matrix::value_type > equal(block_matrix< Matrix, SymmGroup > const &reference, block_matrix< Matrix, SymmGroup > const &sample)
Definition: tag_detail.h:120
base_t::value_type value_type
std::size_t insert(std::pair< charge, std::size_t > const &x)
boost::array< T, L+1 > operator^(boost::array< T, L > const &a, T const &b)
static const bool sorted
ProductBasis(Index< SymmGroup > const &a, Index< SymmGroup > const &b, Fusion f)
std::size_t get_second(std::pair< typename SymmGroup::charge, std::size_t > const &x)
_Tp accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
Definition: bindings.hpp:44
void save(Archive &ar) const
std::size_t size() const
Index< SymmGroup > common_subset(Index< SymmGroup > &a, Index< SymmGroup > &b)
bool operator!=(Index const &o) const
size_t operator()(charge a, charge b) const
base_t::iterator iterator
std::vector< charge > charges() const
std::size_t sum_of_sizes() const
void load(Archive &ar)
T fuse(const A &ind, T d)
Fuse indices n[i] into one p = n[i] d^i.
base_t::const_reverse_iterator const_reverse_iterator