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