ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
super_mpo.h
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-2012 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 SUPER_MPO_H
28 #define SUPER_MPO_H
29 
30 #include "dmrg/mp_tensors/mps.h"
31 #include "dmrg/mp_tensors/mpo.h"
33 
34 #include <boost/function.hpp>
35 
36 /*
37  * Building Super MPS from an MPO object
38  *
39  * When the code is used for density matrix `rho` evolution, measurements are
40  * computed as overlap with a Super MPS.
41  * The Super MPS is equivalent to an MPO where the two physical indexes are
42  * fused together.
43  *
44  * Since the MPO doesn't use symmetries for the auxiliary legs, they are mapped
45  * to a single block with charge SymmGroup::IdentityCharge.
46  *
47  * Operators in the MPO are supposed to be in the form:
48  * O_{s1,s2}
49  * where s1 is the input state, and s2 the output.
50  * (transpose of conventional matrix form)
51  * The indexes are fused according to
52  s = s1 \otimes adjoin(s2),
53  * so that s2 (output) is the most frequent running index.
54  *
55  * Note: the above mapping is in disagreement with block_to_mpo, but the two
56  * functions are anyway not used together.
57  */
58 
59 template <class Matrix, class SymmGroup>
61 {
62  typedef typename SymmGroup::charge charge;
63  typedef boost::unordered_map<size_t,std::pair<charge,size_t> > bond_charge_map;
64  typedef typename MPOTensor<Matrix, SymmGroup>::row_proxy row_proxy;
65 
66  MPS<Matrix, SymmGroup> mps(mpo.size());
67 
68  boost::function<charge (charge, charge)> phys_fuse = boost::lambda::bind(static_cast<charge(*)(charge, charge)>(SymmGroup::fuse),
69  boost::lambda::_1, -boost::lambda::_2);
70 
71  Index<SymmGroup> phys2_i = phys_i*adjoin(phys_i);
72  ProductBasis<SymmGroup> phys_prod(phys_i, phys_i, phys_fuse);
73  Index<SymmGroup> left_i, right_i;
74  left_i.insert( std::make_pair(SymmGroup::IdentityCharge, 1) );
75 
76  bond_charge_map left_map, right_map;
77  left_map[0] = std::make_pair(SymmGroup::IdentityCharge, 0);
78 
79  for (int i=0; i<mpo.size(); ++i) {
80 
81  ProductBasis<SymmGroup> left_out(phys2_i, left_i);
82  boost::unordered_map<charge, size_t> right_sizes;
83 
85 
86  /// run=0 computes the sizes of right blocks
87  for (int run=0; run<=1; ++run)
88  for (size_t b1=0; b1<mpo[i].row_dim(); ++b1)
89  {
90  //for (size_t b2=0; b2<mpo[i].col_dim(); ++b2)
91  row_proxy row_b1 = mpo[i].row(b1);
92  for (typename row_proxy::const_iterator it = row_b1.begin(); it != row_b1.end(); ++it)
93  {
94  size_t b2 = it.index();
95 
96  /// note: this has to be here, because we don't know if b1 exists
97  charge l_charge; size_t ll;
98  boost::tie(l_charge, ll) = left_map[b1];
99  size_t l_size = left_i[left_i.position(l_charge)].second;
100 
101  typename Matrix::value_type scale = mpo[i].at(b1, b2).scale;
102  block_matrix<Matrix, SymmGroup> const& in_block = mpo[i].at(b1, b2).op;
103  for (size_t n=0; n<in_block.n_blocks(); ++n)
104  {
105  charge s1_charge; size_t size1;
106  boost::tie(s1_charge, size1) = in_block.left_basis()[n];
107  charge s2_charge; size_t size2;
108  boost::tie(s2_charge, size2) = in_block.right_basis()[n];
109 
110  charge s_charge = phys_fuse(s1_charge, s2_charge);
111  charge out_l_charge = SymmGroup::fuse(s_charge, l_charge);
112  charge out_r_charge = out_l_charge;
113 
114  if (false && run==0) {
115  maquis::cout << "s1: " << s1_charge << std::endl;
116  maquis::cout << "s2: " << s2_charge << std::endl;
117  maquis::cout << "s: " << s_charge << std::endl;
118  maquis::cout << "b1: " << b1 << std::endl;
119  maquis::cout << "b2: " << b2 << std::endl;
120  maquis::cout << "l: " << l_charge << std::endl;
121  maquis::cout << "r: " << out_r_charge << std::endl;
122 
123  maquis::cout << " ------ " << std::endl;
124  }
125 
126  if ( run == 0) {
127  typename bond_charge_map::const_iterator match = right_map.find(b2);
128  if (match == right_map.end()) {
129  right_map[b2] = std::make_pair(out_r_charge, right_sizes[out_r_charge]++);
130  } else
131  assert(match->second.first == out_r_charge);
132 
133  continue;
134  }
135 
136 
137  if (!out_block.has_block(out_l_charge, out_r_charge))
138  out_block.insert_block(Matrix(left_out.size(s_charge,l_charge), right_sizes[out_r_charge], 0.),
139  out_l_charge, out_r_charge);
140 
141  size_t phys_offset = phys_prod(s1_charge, s2_charge);
142  size_t left_offset = left_out(s_charge, l_charge);
143 
144  size_t rr = right_map[b2].second;
145 
146  Matrix & out_m = out_block(out_l_charge, out_r_charge);
147  Matrix const& in_m = in_block[n];
148 
149  for (size_t ss2=0; ss2<size2; ++ss2)
150  for (size_t ss1=0; ss1<size1; ++ss1)
151  {
152  size_t ss = ss2 + ss1*size2 + phys_offset;
153  // TODO: Sebastian thinks, this is correct but should be checked
154  out_m(left_offset + ss*l_size + ll, rr) = in_m(ss1, ss2) * scale;
155  }
156  }
157  }
158  }
159 
160  right_i = out_block.right_basis();
161 
162  mps[i] = MPSTensor<Matrix, SymmGroup>(phys2_i, left_i, right_i,
163  out_block, LeftPaired);
164  std::swap(left_i, right_i);
165  std::swap(left_map, right_map);
166  right_map.clear();
167  }
168 
169  return mps;
170 }
171 
172 
173 
174 /*
175  * Building Super MPS from an MPO object
176  *
177  * When the code is used for density matrix `rho` evolution, measurements are
178  * computed as overlap with a Super MPS.
179  * The Super MPS is equivalent to an MPO where the two physical indexes are
180  * fused together.
181  *
182  * Since the MPO doesn't use symmetries for the auxiliary legs, they are mapped
183  * to a single block with charge SymmGroup::IdentityCharge.
184  *
185  * Operators in the MPO are supposed to be in the form:
186  * O_{s1,s2}
187  * where s1 is the input state, and s2 the output.
188  * (transpose of conventional matrix form)
189  * The indexes are fused/grouped according to
190  s = <s1, adjoin(s2)>,
191  * so that s2 (output) is the most frequent running index.
192  */
193 
194 template <class Matrix, class InSymm>
196  std::vector<Index<typename grouped_symmetry<InSymm>::type> > const& allowed)
197 {
198  typedef typename grouped_symmetry<InSymm>::type OutSymm;
199  typedef typename InSymm::charge in_charge;
200  typedef typename OutSymm::charge out_charge;
201  typedef boost::unordered_map<size_t,std::pair<out_charge,size_t> > bond_charge_map;
202  typedef typename MPOTensor<Matrix, InSymm>::row_proxy row_proxy;
203 
204  MPS<Matrix, OutSymm> mps(mpo.size());
205 
206  boost::function<out_charge (in_charge, in_charge)> phys_group = boost::lambda::bind(static_cast<out_charge(*)(in_charge, in_charge)>(group),
207  boost::lambda::_1, -boost::lambda::_2);
208 
209  Index<OutSymm> phys2_i = group(phys_i, adjoin(phys_i));
210  Index<OutSymm> left_i, right_i;
211  left_i.insert( std::make_pair(OutSymm::IdentityCharge, 1) );
212 
213  for (int i=0; i<mpo.size(); ++i) {
214  ProductBasis<OutSymm> left_out(phys2_i, left_i);
215 
217  //for (size_t b1=0; b1<mpo[i].row_dim(); ++b1)
218  //{
219  // for (size_t b2=0; b2<mpo[i].col_dim(); ++b2)
220  // {
221  // if (!mpo[i].has(b1, b2))
222  // continue;
223 
224  for (size_t b1=0; b1<mpo[i].row_dim(); ++b1)
225  {
226  row_proxy row_b1 = mpo[i].row(b1);
227  for (typename row_proxy::const_iterator it = row_b1.begin(); it != row_b1.end(); ++it)
228  {
229  size_t b2 = it.index();
230 
231  for (size_t l=0; l<left_i.size(); ++l)
232  {
233  out_charge l_charge = left_i[l].first;
234  size_t l_size = left_i[l].second;
235  size_t ll = b1;
236 
237  typename Matrix::value_type scale = mpo[i].at(b1, b2).scale;
238  block_matrix<Matrix, InSymm> const& in_block = mpo[i].at(b1, b2).op;
239  for (size_t n=0; n<in_block.n_blocks(); ++n)
240  {
241  in_charge s1_charge; size_t size1;
242  boost::tie(s1_charge, size1) = in_block.left_basis()[n];
243  in_charge s2_charge; size_t size2;
244  boost::tie(s2_charge, size2) = in_block.right_basis()[n];
245 
246  out_charge s_charge = phys_group(s1_charge, s2_charge);
247  out_charge out_l_charge = OutSymm::fuse(s_charge, l_charge);
248  out_charge out_r_charge = out_l_charge;
249 
250  if (! allowed[i+1].has(out_r_charge) )
251  continue;
252 
253  if (!out_block.has_block(out_l_charge, out_r_charge))
254  out_block.insert_block(Matrix(left_out.size(s_charge,l_charge), mpo[i].col_dim(), 0.),
255  out_l_charge, out_r_charge);
256 
257  size_t phys_offset = 0;
258  size_t left_offset = left_out(s_charge, l_charge);
259 
260  size_t rr = b2;
261 
262  Matrix & out_m = out_block(out_l_charge, out_r_charge);
263  Matrix const& in_m = in_block[n];
264 
265  for (size_t ss2=0; ss2<size2; ++ss2)
266  for (size_t ss1=0; ss1<size1; ++ss1)
267  {
268  size_t ss = ss2 + ss1*size2 + phys_offset;
269  // TODO: Sebastian thinks, this is correct but should be checked
270  out_m(left_offset + ss*l_size + ll, rr) = in_m(ss1, ss2) * scale;
271  }
272  }
273  }
274  }
275  }
276 
277  right_i = out_block.right_basis();
278 
279  mps[i] = MPSTensor<Matrix, OutSymm>(phys2_i, left_i, right_i,
280  out_block, LeftPaired);
281  std::swap(left_i, right_i);
282  }
283 
284  return mps;
285 }
286 
287 #endif
void run(std::string const &chkp1, std::string const &chkp2)
Definition: main.cpp:52
TrivialGroup::charge group(TrivialGroup::charge c1, TrivialGroup::charge c2)
MPS< Matrix, typename grouped_symmetry< InSymm >::type > mpo_to_smps_group(MPO< Matrix, InSymm > const &mpo, Index< InSymm > const &phys_i, std::vector< Index< typename grouped_symmetry< InSymm >::type > > const &allowed)
Definition: super_mpo.h:195
size_type n_blocks() const
declaration of the MPS class (vector of MPSTensor)
void swap(MPSTensor< Matrix, SymmGroup > &x, MPSTensor< Matrix, SymmGroup > &y)
size_t size(charge pc) const
size_type insert_block(Matrix const &, charge, charge)
Definition: mpo.h:36
block_matrix< Matrix, SymmGroup > adjoin(block_matrix< Matrix, SymmGroup > const &m)
definition of MPO class (vector of MPOTensor)
Definition: mps.h:40
bool has_block(charge r, charge c) const
MPS< Matrix, SymmGroup > mpo_to_smps(MPO< Matrix, SymmGroup > const &mpo, Index< SymmGroup > const &phys_i)
Definition: super_mpo.h:60
Index< SymmGroup > const & right_basis() const
std::size_t position(charge c) const
std::size_t insert(std::pair< charge, std::size_t > const &x)
Index< SymmGroup > const & left_basis() const
std::size_t size() const
T fuse(const A &ind, T d)
Fuse indices n[i] into one p = n[i] d^i.