ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
te_utils.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 by Michele Dolfi <dolfim@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 APP_TE_UTILS_H
28 #define APP_TE_UTILS_H
29 
30 #include "dmrg/models/model.h"
31 #include "dmrg/models/lattice.h"
32 
33 #include "utils/traits.hpp"
39 
41 
42 #include <vector>
43 #include <set>
44 #include <algorithm>
45 
46 // Return: Bond terms are allowed to be in the same Hamiltonian object if they do not overlap
47 // Site terms are splitted among all Hamiltonian objects using that site
48 template <typename T>
49 std::vector<std::vector<term_descriptor<T> > > separate_hamil_terms(std::vector<term_descriptor<T> > const & hamil_terms)
50 {
51  typedef std::map<std::size_t, std::set<std::size_t> > pos_where_t;
52  typedef term_descriptor<T> term_t;
53  typedef std::map<std::size_t, std::vector<term_t> > pos_terms_t;
54 
55  std::vector<std::vector<term_t> > ret;
56  pos_where_t pos_where;
57  pos_terms_t pos_terms;
58 
59  for (int i=0; i<hamil_terms.size(); ++i)
60  {
61  if (hamil_terms[i].size() == 1) {
62  pos_terms[hamil_terms[i].position(0)].push_back(hamil_terms[i]);
63  continue;
64  }
65 
66  term_t term = hamil_terms[i];
67  term.canonical_order(); // TODO: check and fix for fermions!!
68  bool used = false;
69  for (int n=0; n<ret.size() && !used; ++n)
70  {
71  bool overlap = false;
72  for (int j=0; j<ret[n].size() && !overlap; ++j)
73  {
74  if ( ret[n][j].site_match(term) ) break;
75  overlap = ret[n][j].overlap(term);
76  }
77 
78  if (!overlap) {
79  ret[n].push_back(term);
80  for (int k=0; k<term.size(); ++k)
81  pos_where[term.position(k)].insert(n);
82  used = true;
83  }
84  }
85 
86  if (!used) {
87  ret.push_back( std::vector<term_t>(1, term) );
88 
89  for (int k=0; k<term.size(); ++k)
90  pos_where[term.position(k)].insert(ret.size()-1);
91  }
92  }
93 
94  // Adding site terms to all Hamiltonians acting on site i
95  for (typename pos_terms_t::const_iterator it = pos_terms.begin();
96  it != pos_terms.end(); ++it)
97  {
98  double coeff = 1. / pos_where[it->first].size();
99 
100  for (typename std::set<std::size_t>::const_iterator it2 = pos_where[it->first].begin();
101  it2 != pos_where[it->first].end(); ++it2)
102  for (int k=0; k<it->second.size(); ++k)
103  {
104  term_t tmp_term = it->second[k];
105  tmp_term.coeff *= coeff;
106  ret[*it2].push_back(tmp_term);
107  }
108  }
109 
110  // Sorting individual Hamiltonians
111  for (int n=0; n<ret.size(); ++n)
112  std::sort(ret[n].begin(), ret[n].end());
113 
114  return ret;
115 }
116 
117 
118 template <class Matrix, class SymmGroup>
119 block_matrix<Matrix, SymmGroup> term2block(typename Matrix::value_type const& scale,
120  block_matrix<Matrix, SymmGroup> const & op1, Index<SymmGroup> const & phys1_i,
121  block_matrix<Matrix, SymmGroup> const & op2, Index<SymmGroup> const & phys2_i)
122 {
124  op_kron(phys1_i, phys2_i, op1, op2, bond_op);
125  bond_op *= scale;
126  return bond_op;
127 }
128 
129 template <class Matrix, class SymmGroup>
130 std::vector<block_matrix<Matrix, SymmGroup> > hamil_to_blocks(Lattice const& lat, Model<Matrix, SymmGroup> const& model)
131 {
132  std::size_t L = lat.size();
133  std::vector<block_matrix<Matrix, SymmGroup> > ret_blocks(L-1);
134 
135  typename Model<Matrix, SymmGroup>::table_ptr tag_handler = model.operators_table();
136 
138  std::vector<term_t> const& hamil_terms = model.hamiltonian_terms();
139  for (int i=0; i<hamil_terms.size(); ++i)
140  {
141  term_t term = hamil_terms[i];
142  term.canonical_order(); // TODO: check and fix for fermions!!
143  std::size_t pos1 = term.position(0);
144  int type = lat.get_prop<int>("type", pos1);
145  int type_p1, type_m1;
146  if (pos1 < L-1) type_p1 = lat.get_prop<int>("type", pos1+1);
147  if (pos1 > 0) type_m1 = lat.get_prop<int>("type", pos1-1);
148  if (term.size() == 1) {
149  if (pos1 != 0 && pos1 != L-1)
150  term.coeff /= 2.;
151  if (pos1 < L-1)
152  ret_blocks[pos1] += term2block(term.coeff,
153  tag_handler->get_op(term.operator_tag(0)), model.phys_dim(type),
154  model.identity_matrix(type_p1), model.phys_dim(type_p1));
155  if (pos1 > 0)
156  ret_blocks[pos1-1] += term2block(term.coeff,
157  model.identity_matrix(type_m1), model.phys_dim(type_m1),
158  tag_handler->get_op(term.operator_tag(0)), model.phys_dim(type));
159  } else if (term.size() == 2) {
160  assert( std::abs(term.position(0)-term.position(1)) == 1 );
161  ret_blocks[pos1] += term2block(term.coeff,
162  tag_handler->get_op(term.operator_tag(0)), model.phys_dim(type),
163  tag_handler->get_op(term.operator_tag(1)), model.phys_dim(type_p1));
164  }
165  }
166 
167  return ret_blocks;
168 }
169 
170 template <class Matrix, class SymmGroup>
173 
176  typedef boost::shared_ptr<op_table_t> op_table_ptr;
177  typedef typename op_table_t::tag_type tag_type;
178 
179  typedef boost::tuple<std::size_t, std::size_t, tag_type, typename Matrix::value_type> pretensor_value;
180  typedef std::vector<pretensor_value> pretensor_t;
181  typedef std::vector<pretensor_t> prempo_t;
182 
183 public:
185  std::size_t pos1_, std::size_t pos2_, Lattice const& lat_)
186  : phys1(phys1_), phys2(phys2_)
187  , pos1(pos1_), pos2(pos2_), L(pos2-pos1+1)
188  , lattice(lat_)
189  , type1(lattice.get_prop<int>("type", pos1))
190  , type2(lattice.get_prop<int>("type", pos2))
191  , n_boso(0), n_ferm(0)
192  { }
193 
194  void add_term(term_t const& term, Model<Matrix, SymmGroup> const& model)
195  {
196  if (term.size() > 2)
197  throw std::runtime_error("time evolution requires at max two-site bond term.");
198 
199  op_table_ptr op_table = model.operators_table()->get_operator_table();
200 
201  /// kron product of operators
202  op_t bond_op;
203  if (term.size() == 2)
204  op_kron(model.phys_dim(type1), model.phys_dim(type2), (*op_table)[term.operator_tag(0)], (*op_table)[term.operator_tag(1)], bond_op);
205  else if (term.position(0) == pos1)
206  op_kron(model.phys_dim(type1), model.phys_dim(type2), (*op_table)[term.operator_tag(0)], model.identity_matrix(type2), bond_op);
207  else if (term.position(0) == pos2)
208  op_kron(model.phys_dim(type1), model.phys_dim(type2), model.identity_matrix(type1), (*op_table)[term.operator_tag(0)], bond_op);
209  else
210  throw std::runtime_error("Operator k not matching any valid position.");
211 
212  if (term.is_fermionic) {
213  fermionic_bond += term.coeff * bond_op;
214  n_ferm += 1;
215  } else {
216  bosonic_bond += term.coeff * bond_op;
217  n_boso += 1;
218  }
219  }
220 
221  MPO<Matrix, SymmGroup> exp_mpo(typename Matrix::value_type const & alpha,
222  std::vector<tag_type> const& ident, std::vector<tag_type> const& fill,
223  op_table_ptr op_table) const
224  {
225  std::size_t maximum_b = 0;
226  prempo_t prempo(L);
227 
228  if (n_boso > 0) {
229  std::vector<op_t> left_ops, right_ops;
230  exp_and_split(bosonic_bond, alpha, left_ops, right_ops);
231 
232  maximum_b = add_to_mpo(prempo, maximum_b, left_ops, right_ops, 1., ident, op_table);
233  }
234 
235  if (n_ferm > 0) {
236  /// exp(alpha * op1 \otimes op2)
237  {
238  std::vector<op_t> left_ops, right_ops;
239  exp_and_split(fermionic_bond, alpha, left_ops, right_ops);
240 
241  maximum_b = add_to_mpo(prempo, maximum_b, left_ops, right_ops, .5, ident, op_table);
242  maximum_b = add_to_mpo(prempo, maximum_b, left_ops, right_ops, .5, fill, op_table);
243  }
244 
245  /// exp(-alpha * op1 \otimes op2)
246  {
247  std::vector<op_t> left_ops, right_ops;
248  exp_and_split(fermionic_bond, -alpha, left_ops, right_ops);
249 
250  maximum_b = add_to_mpo(prempo, maximum_b, left_ops, right_ops, .5, ident, op_table);
251  maximum_b = add_to_mpo(prempo, maximum_b, left_ops, right_ops, -.5, fill, op_table);
252  }
253  }
254 
255 
256  MPO<Matrix, SymmGroup> mpo(L);
257  for (size_t p=0; p<L; ++p) {
258  size_t nrows, ncols;
259  using generate_mpo::rcdim;
260  boost::tie(nrows, ncols) = rcdim(prempo[p]);
261  MPOTensor<Matrix, SymmGroup> tmp(nrows, ncols, prempo[p], op_table);
262  using std::swap;
263  swap(mpo[p], tmp);
264  }
265 
266  return mpo;
267  }
268 
269 private:
270 
271  void exp_and_split(op_t const& bond_op, typename Matrix::value_type const & alpha,
272  std::vector<op_t> & left_ops, std::vector<op_t> & right_ops) const
273  {
274  op_t bond_exp;
275  bond_exp = op_exp_hermitian(phys1*phys2, bond_op, alpha);
276  bond_exp = reshape_2site_op(phys1, phys2, bond_exp);
277  typedef typename alps::numeric::associated_real_diagonal_matrix<Matrix>::type diag_matrix;
278  block_matrix<Matrix, SymmGroup> U, V, left, right;
280  svd(bond_exp, U, V, S);
281  Ssqrt = sqrt(S);
282  gemm(U, Ssqrt, left);
283  gemm(Ssqrt, V, right);
284 
285  for(std::size_t k = 0; k < S.n_blocks(); ++k){
286  int keep = std::find_if(S[k].diagonal().first, S[k].diagonal().second, boost::lambda::_1 < 1e-10)-S[k].diagonal().first;
287 
288  left.resize_block(left.left_basis()[k].first, left.right_basis()[k].first,
289  left.left_basis()[k].second, keep);
290  right.resize_block(right.left_basis()[k].first, right.right_basis()[k].first,
291  keep, right.right_basis()[k].second);
292  }
293 
294  left_ops = reshape_right_to_list(phys1, left);
295  right_ops = reshape_left_to_list(phys2, right);
296  assert(left_ops.size() == right_ops.size());
297  }
298 
299  std::size_t add_to_mpo(prempo_t & prempo, std::size_t maximum_b,
300  std::vector<op_t> const& left_ops, std::vector<op_t> const& right_ops,
301  typename Matrix::value_type s, std::vector<tag_type> fill, op_table_ptr op_table) const
302  {
303  for (std::size_t i=0; i<left_ops.size(); ++i)
304  {
305  std::size_t b = (maximum_b++);
306 
307  std::pair<tag_type, typename Matrix::value_type> left_tag, right_tag;
308  left_tag = op_table->checked_register(left_ops[i]);
309  right_tag = op_table->checked_register(right_ops[i]);
310 
311  s *= left_tag.second * right_tag.second;
312 
313  prempo[0].push_back ( pretensor_value(0, b, left_tag.first, s ) );
314  prempo[L-1].push_back( pretensor_value(b, 0, right_tag.first, 1.) );
315  for (std::size_t p=1; p<L-1; ++p)
316  prempo[p].push_back( pretensor_value(b, b, fill[lattice.get_prop<int>("prop",pos1+p)], 1.) );
317  }
318  return maximum_b;
319  }
320 
321  Index<SymmGroup> phys1, phys2;
322  std::size_t pos1, pos2, L;
323  Lattice lattice;
324  int type1, type2;
325  std::size_t n_boso, n_ferm;
326  op_t bosonic_bond, fermionic_bond;
327 };
328 
329 // Precondition: Hamiltonian has to be sorted with bond terms coming before site terms (default behaviour of Operator_Term::operator<())
330 template <class Matrix, class SymmGroup>
332  std::vector<term_descriptor<typename Matrix::value_type> > const& hamil_terms,
333  typename Matrix::value_type const & alpha = 1)
334 {
336  typedef OPTable<Matrix, SymmGroup> op_table_t;
337  typedef boost::shared_ptr<op_table_t> op_table_ptr;
338  typedef typename op_table_t::tag_type tag_type;
339  typedef boost::tuple<std::size_t, std::size_t, tag_type, typename Matrix::value_type> pretensor_value;
340  typedef std::vector<pretensor_value> pretensor_t;
341 
342  op_table_ptr original_op_table = model.operators_table()->get_operator_table();
343  op_table_ptr new_op_table( new op_table_t() );
344 
345  size_t length = lat.size();
346 
347  std::vector<tag_type> ident(lat.maximum_vertex_type()+1), fill(lat.maximum_vertex_type()+1);
348  for (int type=0; type<ident.size(); ++type) {
349  ident[type] = new_op_table->register_op( model.identity_matrix(type) );
350  fill[type] = new_op_table->register_op( model.filling_matrix(type) );
351  }
352 
353  MPO<Matrix, SymmGroup> mpo(length);
354  std::vector<bool> used_p(length, false);
355 
356  for (int n=0; n<hamil_terms.size(); )
357  {
358  if (hamil_terms[n].size() != 2) throw std::runtime_error("hamiltonian terms have to be sorted with two-site bond terms before site terms.");
359  int pos1 = hamil_terms[n].position(0);
360  int pos2 = hamil_terms[n].position(1);
361 
362  int type1 = lat.get_prop<int>("type", pos1);
363  int type2 = lat.get_prop<int>("type", pos2);
364 
365  exp_mpo_maker<Matrix, SymmGroup> maker(model.phys_dim(type1), model.phys_dim(type2), pos1, pos2, lat);
366 
367  maker.add_term(hamil_terms[n], model);
368 
369  int k = n+1;
370  for (; k<hamil_terms.size() && hamil_terms[n].site_match(hamil_terms[k]); ++k)
371  maker.add_term(hamil_terms[k], model);
372 
373  MPO<Matrix, SymmGroup> block_mpo = maker.exp_mpo(alpha, ident, fill, new_op_table);
374  for (size_t p=0; p<pos2-pos1+1; ++p) {
375  using std::swap;
376  swap(mpo[pos1+p], block_mpo[p]);
377  used_p[pos1+p] = true;
378  }
379 
380  n = k;
381  }
382 
383 
384  // Filling missing identities
385  for (std::size_t p=0; p<length; ++p) {
386  if (!used_p[p]) {
387  pretensor_t preident(1, pretensor_value(0, 0, ident[lat.get_prop<int>("type", p)], 1.) );
388  MPOTensor<Matrix, SymmGroup> r(1, 1, preident, new_op_table);
389  using std::swap;
390  swap(mpo[p], r);
391  used_p[p] = true;
392  }
393  }
394 
395  return mpo;
396 }
397 
398 #endif
std::vector< std::vector< term_descriptor< T > > > separate_hamil_terms(std::vector< term_descriptor< T > > const &hamil_terms)
Definition: te_utils.hpp:49
op_t const & filling_matrix(size_t type=0) const
Definition: model.h:126
definition of Lattice base class
functions to compress the MPS
terms_type const & hamiltonian_terms() const
Definition: model.h:131
impl_type::table_ptr table_ptr
Definition: model.h:103
pimpl for Model
Definition: model.h:96
void add_term(term_t const &term, Model< Matrix, SymmGroup > const &model)
Definition: te_utils.hpp:194
size_type n_blocks() const
definition of Model base class
tag_detail::tag_type tag_type
Definition: op_handler.h:46
std::vector< block_matrix< Matrix, SymmGroup > > hamil_to_blocks(Lattice const &lat, Model< Matrix, SymmGroup > const &model)
Definition: te_utils.hpp:130
op_t const & identity_matrix(size_t type=0) const
Definition: model.h:124
void swap(MPSTensor< Matrix, SymmGroup > &x, MPSTensor< Matrix, SymmGroup > &y)
functions to manipulate MPOs
declaration of block_matrix class
exp_mpo_maker(Index< SymmGroup > phys1_, Index< SymmGroup > phys2_, std::size_t pos1_, std::size_t pos2_, Lattice const &lat_)
Definition: te_utils.hpp:184
std::vector< block_matrix< Matrix, SymmGroup > > reshape_right_to_list(Index< SymmGroup > const &phys, block_matrix< Matrix, SymmGroup > const &A)
Definition: reshapes.h:498
block_matrix< Matrix, SymmGroup > reshape_2site_op(Index< SymmGroup > const &phys1, Index< SymmGroup > const &phys2, block_matrix< Matrix, SymmGroup > const &A)
Definition: reshapes.h:417
void op_kron(Index< SymmGroup > const &phys_A, Index< SymmGroup > const &phys_B, block_matrix< Matrix1, SymmGroup > const &A, block_matrix< Matrix1, SymmGroup > const &B, block_matrix< Matrix2, SymmGroup > &C)
tag_type operator_tag(size_type i) const
Definition: mpo.h:36
block_matrix< Matrix, SymmGroup > sqrt(block_matrix< Matrix, SymmGroup > m)
void resize_block(charge r, charge c, size_type new_r, size_type new_c, bool pretend=false)
int maximum_vertex_type() const
Definition: lattice.h:116
MPS< Matrix, SymmGroup >::scalar_type overlap(MPS< Matrix, SymmGroup > const &mps1, MPS< Matrix, SymmGroup > const &mps2)
Definition: mps_mpo_ops.h:136
std::vector< block_matrix< Matrix, SymmGroup > > reshape_left_to_list(Index< SymmGroup > const &phys, block_matrix< Matrix, SymmGroup > const &A)
Definition: reshapes.h:562
T get_prop(std::string property, pos_t site) const
Definition: lattice.h:103
void svd(block_matrix< Matrix, SymmGroup > const &M, block_matrix< Matrix, SymmGroup > &U, block_matrix< Matrix, SymmGroup > &V, block_matrix< DiagMatrix, SymmGroup > &S)
Index< SymmGroup > const & right_basis() const
std::pair< size_t, size_t > rcdim(Vector const &pm)
Definition: utils.hpp:212
block_matrix< Matrix, SymmGroup > term2block(typename Matrix::value_type const &scale, block_matrix< Matrix, SymmGroup > const &op1, Index< SymmGroup > const &phys1_i, block_matrix< Matrix, SymmGroup > const &op2, Index< SymmGroup > const &phys2_i)
Definition: te_utils.hpp:119
table_ptr operators_table() const
Definition: model.h:137
MPO< Matrix, SymmGroup > exp_mpo(typename Matrix::value_type const &alpha, std::vector< tag_type > const &ident, std::vector< tag_type > const &fill, op_table_ptr op_table) const
Definition: te_utils.hpp:221
Index< SymmGroup > const & phys_dim(size_t type=0) const
Definition: model.h:123
pos_type position(size_type i) const
void canonical_order()
utilities
functions to reshape the representation of data in MPSTensor
void gemm(block_matrix< Matrix1, SymmGroup > const &A, block_matrix< Matrix2, SymmGroup > const &B, block_matrix< Matrix3, SymmGroup > &C)
unsigned tag_type
Definition: tag_detail.h:36
block_matrix< Matrix, SymmGroup > op_exp_hermitian(Index< SymmGroup > const &phys, block_matrix< Matrix, SymmGroup > M, A const &alpha=1.)
Index< SymmGroup > const & left_basis() const
MPO< Matrix, SymmGroup > make_exp_mpo(Lattice const &lat, Model< Matrix, SymmGroup > const &model, std::vector< term_descriptor< typename Matrix::value_type > > const &hamil_terms, typename Matrix::value_type const &alpha=1)
Definition: te_utils.hpp:331
pimpl resolved Lattice
Definition: lattice.h:84
pos_t size() const
Definition: lattice.h:115