ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
indexing_unsorted.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>
81  class is_first_equal
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>
97 class basis_iterator_;
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 = false;
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  typename pos_t::const_iterator it = positions.find(c);
136  if (position_check && it == positions.end())
137  return 0;
138  return (*this)[it->second].second;
139  }
140 
141  std::size_t position(charge c) const
142  {
143  typename pos_t::const_iterator it = positions.find(c);
144  if (it == positions.end())
145  return this->size();
146  else
147  return it->second;
148  }
149 
150  std::size_t position(std::pair<charge, std::size_t> x) const
151  {
152  assert( has(x.first) );
153  assert( x.second < size_of_block(x.first) );
154  const_iterator to = this->begin()+position(x.first);
155  return x.second + std::accumulate(this->begin(), to, 0,
156  boost::lambda::_1 + boost::lambda::bind(index_detail::get_second<SymmGroup>, boost::lambda::_2)
157  );
158  }
159 
160  bool has(charge c) const
161  {
162  return positions.count(c) > 0;
163  }
164 
165  void sort()
166  {
167  std::sort(this->begin(), this->end(), index_detail::gt<SymmGroup>());
168  calc_positions();
169  }
170 
171  std::size_t insert(std::pair<charge, std::size_t> const & x)
172  {
173  push_back(x);
174  std::size_t d = base_t::size()-1;
175  positions[x.first] = d;
176  return d;
177  }
178 
179  void insert(std::size_t position, std::pair<charge, std::size_t> const & x)
180  {
181  std::vector<std::pair<charge, std::size_t> >::insert(this->begin() + position, x);
182  calc_positions();
183  }
184 
185  void shift(charge diff)
186  {
187  for (std::size_t k = 0; k < this->size(); ++k)
188  (*this)[k].first = SymmGroup::fuse((*this)[k].first, diff);
189  calc_positions();
190  }
191 
192  bool operator==(Index const & o) const
193  {
194  return (this->size() == o.size()) && std::equal(this->begin(), this->end(), o.begin());
195  }
196 
197  bool operator!=(Index const & o) const
198  {
199  return !( *this == o );
200  }
201 
203  {
204  assert( this->size() > 0 );
205  return basis_iterator(*this);
206  }
207 
208  std::vector<charge> charges() const
209  {
210  std::vector<charge> ret(this->size());
211  for (std::size_t k = 0; k < this->size(); ++k) ret[k] = (*this)[k].first;
212  return ret;
213  }
214 
215  std::vector<std::size_t> sizes() const
216  {
217  std::vector<std::size_t> ret(this->size());
218  for (std::size_t k = 0; k < this->size(); ++k) ret[k] = (*this)[k].second;
219  return ret;
220  }
221 
222  std::size_t sum_of_sizes() const
223  {
224  return std::accumulate(this->begin(), this->end(), 0,
225  boost::lambda::_1 + boost::lambda::bind(index_detail::get_second<SymmGroup>, boost::lambda::_2));
226  }
227 
228  // This is mostly forwarding of the std::vector
229  iterator begin() { return base_t::begin(); }
230  iterator end() { return base_t::end(); }
231  const_iterator begin() const { return base_t::begin(); }
232  const_iterator end() const { return base_t::end(); }
233 
234  reverse_iterator rbegin() { return base_t::rbegin(); }
235  reverse_iterator rend() { return base_t::rend(); }
236  const_reverse_iterator rbegin() const { return base_t::rbegin(); }
237  const_reverse_iterator rend() const { return base_t::rend(); }
238 
239  value_type & operator[](std::size_t p) { return static_cast<base_t&>(*this)[p]; }
240  value_type const & operator[](std::size_t p) const { return static_cast<base_t const&>(*this)[p]; }
241 
242  boost::tuple<charge, std::size_t> element(std::size_t p) const
243  {
244  std::size_t i=0;
245  while (p >= (*this)[i].second) {
246  p -= (*this)[i].second;
247  ++i;
248  }
249  return boost::make_tuple( (*this)[i].first, p );
250  }
251 
252  std::size_t size() const { return base_t::size(); }
253 
254  iterator erase(iterator p) { iterator r = base_t::erase(p); calc_positions(); return r; }
255  iterator erase(iterator a, iterator b) { iterator r = base_t::erase(a,b); calc_positions(); return r; }
256 
257 private:
258  pos_t positions;
259 
260  void push_back(std::pair<charge, std::size_t> const & x){
261  base_t::push_back(x);
262  }
263 
264  void calc_positions() {
265  positions.clear();
266  for (const_iterator it = this->begin(); it != this->end(); ++it)
267  positions[it->first] = it-this->begin();
268  }
269 
270 public:
271 #ifdef PYTHON_EXPORTS
272  std::size_t py_insert(wrapped_pair<SymmGroup> p)
273  {
274  return this->insert(p.data_);
275  }
276 #endif /* PYTHON_EXPORTS */
277 
278  template<class Archive>
279  void load(Archive & ar)
280  {
281  typedef std::vector<std::pair<typename SymmGroup::charge, std::size_t> > my_type;
282  ar["Index"] >> static_cast<my_type&>(*this);
283  calc_positions();
284  }
285  template<class Archive>
286  void save(Archive & ar) const
287  {
288  typedef std::vector<std::pair<typename SymmGroup::charge, std::size_t> > my_type;
289  ar["Index"] << static_cast<my_type const &>(*this);
290  }
291 
292  friend class boost::serialization::access;
293 
294  template <class Archive>
295  void load(Archive & ar, const unsigned int version)
296  {
297  ar & boost::serialization::base_object<base_t>(*this);
298  calc_positions();
299  }
300  template <class Archive>
301  void save(Archive & ar, const unsigned int version) const
302  {
303  ar & boost::serialization::base_object<base_t>(*this);
304  }
305 
306  BOOST_SERIALIZATION_SPLIT_MEMBER()
307 };
308 
309 template<class SymmGroup>
310 class ProductBasis
311 {
312 public:
313  typedef typename SymmGroup::charge charge;
314  typedef std::size_t size_t;
315 
317  Index<SymmGroup> const & b)
318  {
319  init(a, b, static_cast<charge(*)(charge, charge)>(SymmGroup::fuse));
320  }
321 
322  template<class Fusion>
324  Index<SymmGroup> const & b,
325  Fusion f)
326  {
327  init(a, b, f);
328  }
329 
330 private:
331  template<class Fusion>
332  void init(Index<SymmGroup> const & a,
333  Index<SymmGroup> const & b,
334  Fusion f)
335  {
336  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
337  for (typename Index<SymmGroup>::const_iterator it1 = a.begin(); it1 != a.end(); ++it1)
338  for (typename Index<SymmGroup>::const_iterator it2 = b.begin(); it2 != b.end(); ++it2)
339  {
340  charge pc = f(it1->first, it2->first);
341  keys_vals_[std::make_pair(it1->first, it2->first)] = size_[pc];
342  // keys_vals_.insert(std::make_pair(std::make_pair(it1->first, it2->first),size_[pc]));
343  size_[pc] += it1->second * it2->second;
344  }
345  }
346 
347 public:
348  size_t operator()(charge a, charge b) const
349  {
350  typedef typename boost::unordered_map<std::pair<charge, charge>, size_t>::const_iterator match_type;
351  match_type match = keys_vals_.find(std::make_pair(a,b));
352  assert( match != keys_vals_.end() );
353  return match->second;
354  }
355 
356  inline size_t size(charge pc) const
357  {
358  assert(size_.count(pc) > 0);
359  return size_[pc];
360  }
361 
362  // for the moment let's avoid the default template argument (C++11)
363  inline size_t size(charge a, charge b) const
364  {
365  return size(a, b, static_cast<charge(*)(charge, charge)>(SymmGroup::fuse));
366  }
367  template<class Fusion>
368  size_t size(charge a, charge b, Fusion f) const
369  {
370  charge pc = f(a, b);
371  assert(size_.count(pc) > 0);
372  return size_[pc];
373  }
374 
375 private:
376  mutable boost::unordered_map<charge, size_t> size_;
377  boost::unordered_map<std::pair<charge, charge>, size_t> keys_vals_;
378 };
379 
380 template<class SymmGroup>
381 class basis_iterator_
382 {
383 public:
384  typedef typename SymmGroup::charge charge;
385 
386  basis_iterator_(Index<SymmGroup> const & idx, bool at_end = false)
387  : idx_(idx)
388  , cur_block(idx.begin())
389  , cur_i(0)
390  , max_i(cur_block->second)
391  { }
392 
393  std::pair<charge, std::size_t> operator*() const
394  {
395  return std::make_pair(cur_block->first, cur_i);
396  }
397 
398  boost::shared_ptr<std::pair<charge, std::size_t> > operator->() const
399  {
400  return boost::shared_ptr<std::pair<charge, std::size_t> >(new std::pair<charge, std::size_t>(cur_block->first, cur_i));
401  }
402 
404  {
405  ++cur_i;
406  if (cur_i != max_i)
407  return *this;
408  else {
409  ++cur_block;
410  if (cur_block != idx_.end()) {
411  cur_i = 0;
412  max_i = cur_block->second;
413  }
414  return *this;
415  }
416  }
417 
419  {
420  assert( k >= 0 );
421  basis_iterator_ r = *this;
422  for ( ; k > 0; --k)
423  ++r;
424  return r;
425  }
426 
427  bool end() const
428  {
429  return cur_block == idx_.end();
430  }
431 
432 private:
433  Index<SymmGroup> const & idx_;
434  typename Index<SymmGroup>::const_iterator cur_block;
435  std::size_t cur_i, max_i;
436 };
437 
438 template<class SymmGroup>
440 {
441  for ( ; p > 0; --p)
442  ++it;
443  return it;
444 }
445 
446 // This is a workaround for MSVC++
447 // It can be removed as soon as this bug is fixed:
448 // http://social.msdn.microsoft.com/Forums/en/vclanguage/thread/bab04536-8a8d-4b5e-9a49-e10144688667
449 
450 #if defined(WIN32) || defined(WIN64)
451 template<class A, class B> std::pair<A, B> mypair(A & a, B & b) { return std::pair<A,B>(a,b); }
452 #endif
453 
454 template<class SymmGroup>
455 bool weak_equal(Index<SymmGroup> const & a, Index<SymmGroup> const & b)
456 {
457  if (a.size() != b.size())
458  return false;
459  bool ret = true;
460  for (std::size_t i=0; i<a.size() && ret; ++i)
461  ret = (a[i] == b[b.position(a[i].first)]);
462  return ret;
463 }
464 
465 template<class SymmGroup>
467 {
468  typedef typename SymmGroup::charge charge;
469 
470  std::vector<charge> oc = inp.charges(), nc = inp.charges();
471  std::transform(nc.begin(), nc.end(), nc.begin(), std::negate<charge>());
472 // std::sort(nc.begin(), nc.end());
473  std::reverse(nc.begin(), nc.end());
474 
475  std::vector<std::size_t> nd(inp.size()), od = inp.sizes();
476  for (unsigned int i = 0; i < nd.size(); ++i)
477  nd[i] = od[std::find(oc.begin(), oc.end(),
478  -nc[i])-oc.begin()];
479 
480  Index<SymmGroup> ret;
481  for (size_t i=0; i<nc.size(); ++i)
482 #if not defined(WIN32) && not defined(WIN64)
483  ret.insert(std::make_pair(nc[i], nd[i]));
484 #else
485  ret.insert(mypair(nc[i], nd[i]));
486 #endif
487  return ret;
488 }
489 
490 template<class SymmGroup>
491 std::ostream& operator<<(std::ostream& os, Index<SymmGroup> const & idx)
492 {
493  os << "|";
494  for (typename Index<SymmGroup>::const_iterator it = idx.begin();
495  it != idx.end();
496  ++it)
497  {
498  os << "( " << it->first << ": " << it->second << " )";
499  }
500  os << "|";
501 
502  return os;
503 }
504 
505 template<class SymmGroup>
507  Index<SymmGroup> const & i2)
508 {
509  typedef typename SymmGroup::charge charge;
510 
511  Index<SymmGroup> ret;
512  for (typename Index<SymmGroup>::const_iterator it1 = i1.begin(); it1 != i1.end(); ++it1)
513  for (typename Index<SymmGroup>::const_iterator it2 = i2.begin(); it2 != i2.end(); ++it2)
514  {
515  charge pdc = SymmGroup::fuse(it1->first, it2->first);
516  std::size_t ps = it1->second * it2->second;
517  std::size_t match = ret.position(pdc);
518  if (match < ret.size())
519  ret[match].second += ps;
520  else
521  ret.insert(std::make_pair(pdc, ps));
522  }
523  return ret;
524 }
525 
526 template<class SymmGroup>
528  Index<SymmGroup> & b)
529 {
530  a.erase(std::remove_if(a.begin(), a.end(),
531  !boost::lambda::bind(&Index<SymmGroup>::has, b,
532  boost::lambda::bind(index_detail::get_first<SymmGroup>, boost::lambda::_1))),
533  a.end());
534 
535  b.erase(std::remove_if(b.begin(), b.end(),
536  !boost::lambda::bind(&Index<SymmGroup>::has, a,
537  boost::lambda::bind(index_detail::get_first<SymmGroup>, boost::lambda::_1))),
538  b.end());
539  return a;
540 }
541 
542 template<class charge>
543 std::pair<charge, std::size_t> operator-(std::pair<charge, std::size_t> const & p)
544 {
545  return std::make_pair(-p.first, p.second);
546 }
547 
548 template<class T> boost::array<T, 1> _(T const & a)
549 {
550  boost::array<T, 1> r;
551  r[0] = a;
552  return r;
553 }
554 
555 template<class T> boost::array<T, 2> _(T const & a, T const & b)
556 {
557  boost::array<T, 2> r;
558  r[0] = a;
559  r[1] = b;
560  return r;
561 }
562 
563 #define IMPL_COMMA(tpl, type) \
564 tpl boost::array<type, 2> operator^(type const & a, type const & b) { \
565  boost::array<type, 2> ret; \
566  ret[0] = a; \
567  ret[1] = b; \
568  return ret; \
569 }
570 #define IMPL_COMMA_2(tpl, type) \
571 tpl boost::array<type, L+1> operator^(boost::array<type, L> const & a, type const & b) { \
572  boost::array<type, L+1> ret; \
573  std::copy(a.begin(), a.end(), ret.begin()); \
574  ret[L] = b; \
575  return ret; \
576 }
577 
578 #define CO ,
579 
580 IMPL_COMMA(template<class SymmGroup>, Index<SymmGroup>)
581 IMPL_COMMA(template<class charge>, std::pair<charge CO std::size_t>)
582 
583 #undef CO
584 #undef IMPL_COMMA
585 #undef IMPL_COMMA_2
586 
587 template<class T, unsigned long L>
588 boost::array<T, L+1> operator^(boost::array<T, L> const & a, T const & b)
589 {
590  boost::array<T, L+1> ret;
591  std::copy(a.begin(), a.end(), ret.begin());
592  ret[L] = b;
593  return ret;
594 }
595 
596 template<class T, unsigned long L>
597 boost::array<T, L+1> operator^(T const & a, boost::array<T, L> const & b)
598 {
599  boost::array<T, L+1> ret;
600  ret[0] = a;
601  for (int i = 0; i < L; i++)
602  ret[i+1] = b[i];
603  return ret;
604 }
605 
606 
607 #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
bool weak_equal(Index< SymmGroup > const &a, Index< SymmGroup > const &b)
const_iterator end() const
SymmGroup::charge charge
const_reverse_iterator rbegin() const
void insert(std::size_t position, std::pair< charge, std::size_t > const &x)
boost::array< T, 1 > _(T const &a)
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)
Index< SymmGroup > adjoin(Index< SymmGroup > const &inp)
iterator begin()
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)
Index< SymmGroup > common_subset(Index< SymmGroup > &a, Index< SymmGroup > &b)
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++()
#define IMPL_COMMA(tpl, type)
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_ operator+(int k)
SymmGroup::charge get_first(std::pair< typename SymmGroup::charge, std::size_t > const &x)
reverse_iterator rbegin()
std::pair< charge, std::size_t > operator-(std::pair< charge, std::size_t > const &p)
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()
#define CO
std::size_t position(charge c) const
value_type & operator[](std::size_t p)
iterator erase(iterator a, iterator b)
Index< SymmGroup > operator*(Index< SymmGroup > const &i1, Index< SymmGroup > const &i2)
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
boost::array< T, L+1 > operator^(boost::array< T, L > const &a, T const &b)
base_t::value_type value_type
std::size_t insert(std::pair< charge, std::size_t > const &x)
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
bool operator!=(Index const &o) const
size_t operator()(charge a, charge b) const
basis_iterator_< SymmGroup > operator+(basis_iterator_< SymmGroup > it, std::size_t p)
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