ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tagged_mpo_maker_optim.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  * 2013-2013 by Sebastian Keller <sebkelle@phys.ethz.ch>
7  * Michele Dolfi <dolfim@phys.ethz.ch>
8  *
9  * This software is part of the ALPS Applications, published under the ALPS
10  * Application License; you can use, redistribute it and/or modify it under
11  * the terms of the license, either version 1 or (at your option) any later
12  * version.
13  *
14  * You should have received a copy of the ALPS Application License along with
15  * the ALPS Applications; see the file LICENSE.txt. If not, the license is also
16  * available from http://alps.comp-phys.org/.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  *****************************************************************************/
27 
28 #ifndef GENERATE_MPO_TAGGED_MPO_MAKER_H
29 #define GENERATE_MPO_TAGGED_MPO_MAKER_H
30 
32 
36 
37 #include "dmrg/mp_tensors/mpo.h"
39 
40 #include "dmrg/models/lattice.h"
41 #include "dmrg/models/model.h"
42 
43 #include <boost/bind.hpp>
44 #include <string>
45 #include <sstream>
46 
47 namespace generate_mpo
48 {
49 
50  namespace detail {
51 
52  template <typename pos_t, typename tag_type, typename index_type>
53  struct prempo_key {
54 // typedef Lattice::pos_t pos_t;
55 // typedef tag_detail::tag_type tag_type;
56 // typedef unsigned index_type;
57  typedef std::pair<pos_t, tag_type> pos_op_type;
59 
61  std::vector<pos_op_type> pos_op;
62  index_type offset;
63 
64  prempo_key(kind_type k_=bulk, index_type o_=0) : kind(k_), offset(o_) { }
65  prempo_key(std::vector<pos_op_type> const& po_, index_type o_=0) : kind(bulk), pos_op(po_), offset(o_) { }
66 
67  bool operator==(prempo_key const& lhs) const
68  {
69  if (kind != lhs.kind)
70  return false;
71  if (kind == trivial_left)
72  return true;
73  if (kind == trivial_right)
74  return true;
75 
76  return (pos_op == lhs.pos_op) && (offset == lhs.offset);
77  }
78 
79  bool operator<(prempo_key const& lhs) const
80  {
81  if (kind != lhs.kind) return kind < lhs.kind;
82  return (pos_op == lhs.pos_op) ? offset < lhs.offset : pos_op < lhs.pos_op;
83  }
84  };
85  }
86 
87  template <typename T, typename U>
88  std::pair<T,U> to_pair(boost::tuple<T,U> const& t)
89  {
90  return std::make_pair( boost::get<0>(t), boost::get<1>(t) );
91  }
92 
93  template<class Matrix, class SymmGroup>
95  {
96  typedef typename Matrix::value_type scale_type;
97  typedef typename MPOTensor<Matrix, SymmGroup>::index_type index_type;
99 
100  typedef Lattice::pos_t pos_t;
101  typedef typename Operator_Tag_Term<Matrix, SymmGroup>::tag_type tag_type;
102  typedef typename Operator_Tag_Term<Matrix, SymmGroup>::op_pair_t pos_op_type;
103  typedef boost::tuple<std::size_t, std::size_t, tag_type, scale_type> tag_block;
104 
105  typedef ::term_descriptor<typename Matrix::value_type> term_descriptor;
106 
108  typedef std::pair<tag_type, scale_type> prempo_value_type;
109  // TODO: consider moving to hashmap
110  typedef std::map<std::pair<prempo_key_type, prempo_key_type>, prempo_value_type> prempo_map_type;
111 
112  enum merge_kind {attach, detach};
113 
114  public:
115  TaggedMPOMaker(Lattice const& lat_, Model<Matrix,SymmGroup> const& model_)
116  : lat(lat_)
117  , model(model_)
118  , length(lat.size())
119  , tag_handler(model.operators_table())
120  , prempo(length)
121  , trivial_left(prempo_key_type::trivial_left)
122  , trivial_right(prempo_key_type::trivial_right)
123  , leftmost_right(length)
124  , finalized(false)
125  {
126  for (size_t p = 0; p < length-1; ++p)
127  prempo[p][make_pair(trivial_left,trivial_left)] = prempo_value_type(model.identity_matrix_tag(lat.get_prop<int>("type",p)), 1.);
128 
129  typename Model<Matrix, SymmGroup>::terms_type const& terms = model.hamiltonian_terms();
130  std::for_each(terms.begin(), terms.end(), boost::bind(&TaggedMPOMaker<Matrix,SymmGroup>::add_term, this, _1));
131  }
132 
134  {
135  std::sort(term.begin(), term.end(), pos_tag_lt());
136  index_type nops = term.size();
137 
138  switch (nops) {
139  case 1:
140  add_1term(term);
141  break;
142  case 2:
143  add_2term(term);
144  break;
145  case 3:
146  add_3term(term);
147  break;
148  case 4:
149  add_4term(term);
150  break;
151  default:
152  add_nterm(term); /// here filling has to be done manually
153  break;
154  }
155 
156  leftmost_right = std::min(leftmost_right, boost::get<0>(*term.rbegin()));
157  }
158 
160  {
161  if (!finalized) finalize();
162  MPO<Matrix, SymmGroup> mpo; mpo.reserve(length);
163 
164  typedef std::map<prempo_key_type, index_type> index_map;
165  typedef typename index_map::iterator index_iterator;
166  index_map left;
167  left[trivial_left] = 0;
168 
169  for (pos_t p = 0; p < length; ++p) {
170  std::vector<tag_block> pre_tensor; pre_tensor.reserve(prempo[p].size());
171 
172  index_map right;
173  index_type r = 2;
174  for (typename prempo_map_type::const_iterator it = prempo[p].begin();
175  it != prempo[p].end(); ++it) {
176  prempo_key_type const& k1 = it->first.first;
177  prempo_key_type const& k2 = it->first.second;
178  prempo_value_type const& val = it->second;
179 
180  index_iterator ll = left.find(k1);
181  if (ll == left.end())
182  throw std::runtime_error("k1 not found!");
183 
184  index_iterator rr = right.find(k2);
185  if (k2 == trivial_left && rr == right.end())
186  boost::tie(rr, boost::tuples::ignore) = right.insert( make_pair(k2, 0) );
187  else if (k2 == trivial_right && rr == right.end())
188  boost::tie(rr, boost::tuples::ignore) = right.insert( make_pair(k2, 1) );
189  else if (rr == right.end())
190  boost::tie(rr, boost::tuples::ignore) = right.insert( make_pair(k2, r++) );
191 
192  pre_tensor.push_back( tag_block(ll->second, rr->second, val.first, val.second) );
193  }
194 
195  std::pair<std::size_t, std::size_t> rcd = rcdim(pre_tensor);
196  if (p == 0)
197  mpo.push_back( MPOTensor<Matrix, SymmGroup>(1, rcd.second, pre_tensor, tag_handler->get_operator_table()) );
198  else if (p == length - 1)
199  mpo.push_back( MPOTensor<Matrix, SymmGroup>(rcd.first, 1, pre_tensor, tag_handler->get_operator_table()) );
200  else
201  mpo.push_back( MPOTensor<Matrix, SymmGroup>(rcd.first, rcd.second, pre_tensor, tag_handler->get_operator_table()) );
202 
203  swap(left, right);
204  }
205 
206  return mpo;
207  }
208 
209  private:
210  void add_1term(term_descriptor const& term)
211  {
212  assert(term.size() == 1);
213 
214  /// retrieve the actual operator from the tag table
215  // TODO implement plus operation
216  op_t current_op = tag_handler->get_op(term.operator_tag(0));
217  current_op *= term.coeff;
218  site_terms[term.position(0)] += current_op;
219  }
220 
221  void add_2term(term_descriptor const& term)
222  {
223  assert(term.size() == 2);
224 
225  prempo_key_type k1 = trivial_left;
226  {
227  int i = 0;
228  prempo_key_type k2;
229  k2.pos_op.push_back(to_pair(term[i+1]));
230  k1 = insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), term.coeff), detach);
231  }
232  bool trivial_fill = !tag_handler->is_fermionic(term.operator_tag(1));
233  insert_filling(term.position(0)+1, term.position(1), k1, trivial_fill); // todo: check with long-range n_i*n_j
234  {
235  int i = 1;
236  prempo_key_type k2 = trivial_right;
237  insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), 1.), detach);
238  }
239  }
240 
241  void add_3term(term_descriptor const& term)
242  {
243  assert(term.size() == 3);
244  int nops = term.size();
245 
246  /// number of fermionic operators
247  int nferm = 0;
248  for (int i = 0; i < nops; ++i) {
249  if (tag_handler->is_fermionic(term.operator_tag(i)))
250  nferm += 1;
251  }
252 
253  prempo_key_type k1 = trivial_left;
254  std::vector<pos_op_type> ops_left;
255 
256  /// op_0
257  {
258  int i = 0;
259  prempo_key_type k2;
260  k2.pos_op.push_back(to_pair(term[i])); // k2: applied operator
261  k1 = insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), 1.), attach);
262 
263  if (tag_handler->is_fermionic(term.operator_tag(i)))
264  nferm -= 1;
265  bool trivial_fill = (nferm % 2 == 0);
266  insert_filling(term.position(i)+1, term.position(i+1), k1, trivial_fill);
267  }
268  /// op_1
269  {
270  int i = 1;
271  prempo_key_type k2;
272  k2.pos_op.push_back(to_pair(term[i+1])); // k2: future operators
273  k1 = insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), term.coeff), detach);
274 
275  if (tag_handler->is_fermionic(term.operator_tag(i)))
276  nferm -= 1;
277  bool trivial_fill = (nferm % 2 == 0);
278  insert_filling(term.position(i)+1, term.position(i+1), k1, trivial_fill);
279  }
280  /// op_2
281  {
282  int i = 2;
283  insert_operator(term.position(i), make_pair(k1, trivial_right), prempo_value_type(term.operator_tag(i), 1.), detach);
284  }
285  }
286 
287  void add_4term(term_descriptor const& term)
288  {
289  assert(term.size() == 4);
290  int nops = term.size();
291 
292  /// number of fermionic operators
293  int nferm = 0;
294  for (int i = 0; i < nops; ++i) {
295  if (tag_handler->is_fermionic(term.operator_tag(i)))
296  nferm += 1;
297  }
298 
299  prempo_key_type k1 = trivial_left;
300  std::vector<pos_op_type> ops_left;
301 
302  /// op_0, op_1
303  for (int i = 0; i < 2; ++i) {
304  ops_left.push_back(to_pair(term[i])); prempo_key_type k2(ops_left);
305  k1 = insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), 1.), attach);
306 
307  if (tag_handler->is_fermionic(term.operator_tag(i)))
308  nferm -= 1;
309  bool trivial_fill = (nferm % 2 == 0);
310  insert_filling(term.position(i)+1, term.position(i+1), k1, trivial_fill);
311  }
312  /// op_2
313  {
314  int i = 2;
315  prempo_key_type k2;
316  k2.pos_op.push_back(to_pair(term[3]));
317  k1 = insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), term.coeff), detach);
318 
319  if (tag_handler->is_fermionic(term.operator_tag(i)))
320  nferm -= 1;
321  bool trivial_fill = (nferm % 2 == 0);
322  insert_filling(term.position(i)+1, term.position(i+1), k1, trivial_fill);
323  }
324 
325  /// op_3
326  {
327  int i = 3;
328  insert_operator(term.position(i), make_pair(k1, trivial_right), prempo_value_type(term.operator_tag(i), 1.), detach);
329  }
330  }
331 
332  void add_nterm(term_descriptor const& term)
333  {
334  int nops = term.size();
335  assert( nops > 2 );
336 
337  static index_type next_offset = 0;
338  index_type current_offset = (next_offset++);
339 
340  prempo_key_type k1 = trivial_left;
341  prempo_key_type k2(prempo_key_type::bulk_no_merge, current_offset);
342  k2.pos_op.push_back( to_pair(term[nops-1]) );
343 
344  {
345  int i = 0;
346  insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), term.coeff), detach);
347  k1 = k2;
348 
349  if (i < nops-1 && term.position(i)+1 != term.position(i+1))
350  throw std::runtime_error("for n > 4 operators filling is assumed to be done manually. the list of operators contains empty sites.");
351  }
352 
353 
354  for (int i = 1; i < nops; ++i) {
355  if (i == nops-1)
356  k2 = trivial_right;
357 
358  insert_operator(term.position(i), make_pair(k1, k2), prempo_value_type(term.operator_tag(i), 1.), detach);
359 
360  if (i < nops-1 && term.position(i)+1 != term.position(i+1))
361  throw std::runtime_error("for n > 4 operators filling is assumed to be done manually. the list of operators contains empty sites.");
362  }
363 
364  }
365 
366  void insert_filling(pos_t i, pos_t j, prempo_key_type k, bool trivial_fill)
367  {
368  for (; i < j; ++i) {
369  tag_type op = (trivial_fill) ? model.identity_matrix_tag(lat.get_prop<int>("type",i)) : model.filling_matrix_tag(lat.get_prop<int>("type",i));
370  std::pair<typename prempo_map_type::iterator,bool> ret = prempo[i].insert( make_pair(make_pair(k,k), prempo_value_type(op, 1.)) );
371  if (!ret.second && ret.first->second.first != op)
372  throw std::runtime_error("Pre-existing term at site "+boost::lexical_cast<std::string>(i)
373  + ". Needed "+boost::lexical_cast<std::string>(op)
374  + ", found "+boost::lexical_cast<std::string>(ret.first->second.first));
375  }
376  }
377 
378  prempo_key_type insert_operator(pos_t p, std::pair<prempo_key_type, prempo_key_type> kk, prempo_value_type val,
379  merge_kind merge_behavior=detach)
380  {
381  /// merge_behavior == detach: a new branch will be created, in case op already exist, an offset is used
382  /// merge_behavior == attach: if operator tags match, keep the same branch
383  std::pair<typename prempo_map_type::iterator,bool> match = prempo[p].insert( make_pair(kk, val) );
384  if (merge_behavior == detach) {
385  if (!match.second) {
386  std::pair<prempo_key_type, prempo_key_type> kk_max = kk;
387  kk_max.second.offset = std::numeric_limits<index_type>::max();
388 
389  typename prempo_map_type::iterator highest_offset = prempo[p].upper_bound(kk_max);
390  highest_offset--;
391  kk.second.offset = highest_offset->first.second.offset + 1;
392  prempo[p].insert(highest_offset, make_pair(kk, val));
393  }
394  }
395  else {
396  // still slow, but seems never to be used
397  while (!match.second && match.first->second != val) {
398  kk.second.offset += 1;
399  match = prempo[p].insert( make_pair(kk, val) );
400  }
401  }
402  return kk.second;
403  }
404 
405  void finalize()
406  {
407  /// site terms
408  std::pair<prempo_key_type,prempo_key_type> kk = make_pair(trivial_left,trivial_right);
409  for (typename std::map<pos_t, op_t>::const_iterator it = site_terms.begin();
410  it != site_terms.end(); ++it) {
411  tag_type site_tag = tag_handler->register_op(it->second, tag_detail::bosonic);
412  std::pair<typename prempo_map_type::iterator,bool> ret;
413  ret = prempo[it->first].insert( make_pair( kk, prempo_value_type(site_tag,1.) ) );
414  if (!ret.second)
415  throw std::runtime_error("another site term already existing!");
416  }
417 
418  /// fill with ident until the end
419  bool trivial_fill = true;
420  insert_filling(leftmost_right+1, length, trivial_right, trivial_fill);
421 
422  finalized = true;
423  }
424 
425 
426  private:
427  Lattice const& lat;
428  Model<Matrix,SymmGroup> const& model;
429 
430  pos_t length;
431 
432  boost::shared_ptr<TagHandler<Matrix, SymmGroup> > tag_handler;
433  std::vector<prempo_map_type> prempo;
434  prempo_key_type trivial_left, trivial_right;
435  std::map<pos_t, op_t> site_terms;
436 
437  pos_t leftmost_right;
438  bool finalized;
439  };
440 
441 }
442 
443 #endif
std::pair< pos_t, tag_type > op_pair_t
Definition: utils.hpp:49
definition of Lattice base class
void add_term(term_descriptor term)
pimpl for Model
Definition: model.h:96
include all symmetry definitions
OPTable< Matrix, SymmGroup >::tag_type tag_type
Definition: utils.hpp:47
definition of Model base class
void swap(MPSTensor< Matrix, SymmGroup > &x, MPSTensor< Matrix, SymmGroup > &y)
declaration of block_matrix class
prempo_key(std::vector< pos_op_type > const &po_, index_type o_=0)
std::pair< T, U > to_pair(boost::tuple< T, U > const &t)
tag_type operator_tag(size_type i) const
Definition: mpo.h:36
prempo_key(kind_type k_=bulk, index_type o_=0)
bool operator<(prempo_key const &lhs) const
utility functions for the MPO
TaggedMPOMaker(Lattice const &lat_, Model< Matrix, SymmGroup > const &model_)
std::size_t index_type
Definition: mpotensor.h:52
definition of MPO class (vector of MPOTensor)
std::pair< pos_t, tag_type > pos_op_type
T get_prop(std::string property, pos_t site) const
Definition: lattice.h:103
bool operator==(prempo_key const &lhs) const
impl_type::pos_t pos_t
Definition: lattice.h:88
std::pair< size_t, size_t > rcdim(Vector const &pm)
Definition: utils.hpp:212
algorithms for block_matrix (gemm, svd, etc.)
MPO< Matrix, SymmGroup > create_mpo()
pos_type position(size_type i) const
pimpl resolved Lattice
Definition: lattice.h:84
impl_type::terms_type terms_type
Definition: model.h:107