ALPS MPS Codes
Reference documentation.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-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 MPO_H
28 #define MPO_H
29 
30 #include <vector>
31 #include <set>
32 
34 
35 template<class Matrix, class SymmGroup>
36 class MPO : public std::vector<MPOTensor<Matrix, SymmGroup> >
37 {
38 public:
40 
41  MPO() { }
42 
43  MPO(std::size_t L, elem_type elem = elem_type())
44  : std::vector<elem_type>(L, elem)
45  { }
46 
47  std::size_t length() const { return this->size(); }
48 
49  void compress(double cutoff)
50  {
51  calc_charges();
52 
53  for (int p = 0; p < this->size()-1; ++p) {
54  MPOTensor<Matrix, SymmGroup> b1 = (*this)[p], b2 = (*this)[p+1];
55 
58 
60 
62  gemm(left, right, M);
63  svd_truncate(M, U, V, S, cutoff, 100000, false);
64  Sqrt = sqrt(S);
65  gemm(U, Sqrt, left);
66  gemm(Sqrt, V, right);
67 
68  maquis::cout << "MPO bond truncation: " << bond_indices[p+1].sum_of_sizes() << " -> ";
69  replace_pair(left, right, p);
70  maquis::cout << bond_indices[p+1].sum_of_sizes() << std::endl;
71  }
72  }
73 
74 private:
75  std::vector<std::map<std::size_t, typename SymmGroup::charge> > bond_index_charges;
76  std::vector<Index<SymmGroup> > bond_indices;
77 
78  void calc_charges()
79  {
80  size_t L = this->size();
81  bond_index_charges.clear();
82  bond_index_charges.resize(L+1);
83 
84  bond_index_charges[0][0] = SymmGroup::IdentityCharge;
85 
86  for (size_t p = 1; p <= L; ++p)
87  {
88  for (size_t c = 0; c < (*this)[p-1].col_dim(); ++c) {
89  std::set<typename SymmGroup::charge> charge_diffs;
90  for (size_t r = 0; r < (*this)[p-1].row_dim(); ++r) {
91  assert( bond_index_charges[p-1].count(r) > 0 );
92  if (!(*this)[p-1].has(r,c))
93  continue;
94  for (size_t b = 0; b < (*this)[p-1].at(r, c).op.n_blocks(); ++b) {
95  charge_diffs.insert(SymmGroup::fuse(bond_index_charges[p-1][r],
96  SymmGroup::fuse((*this)[p-1].at(r,c).op.left_basis()[b].first,
97  -(*this)[p-1].at(r,c).op.right_basis()[b].first)));
98 // maquis::cout << r << " " << c << std::endl;
99 // maquis::cout << bond_index_charges[p-1][r] << std::endl;
100 // maquis::cout << (*this)[p-1](r,c).left_basis()[b].first << std::endl;
101 // maquis::cout << (*this)[p-1](r,c).right_basis()[b].first << std::endl;
102 // std::copy(charge_diffs.begin(), charge_diffs.end(),
103 // std::ostream_iterator<typename SymmGroup::charge>(maquis::cout, " "));
104 // maquis::cout << std::endl << std::endl;
105  }
106  }
107 #ifndef NDEBUG
108  assert( charge_diffs.size() <= 1 );
109 #endif
110  if (charge_diffs.size() == 1)
111  bond_index_charges[p][c] = *charge_diffs.begin();
112  else
113  bond_index_charges[p][c] = SymmGroup::IdentityCharge; //bond_index_charges[p-1][c];
114  }
115  }
116 
117  bond_indices.clear();
118  bond_indices.resize(L+1);
119  for (size_t p = 0; p <= L; ++p)
120  {
121  Index<SymmGroup> & index = bond_indices[p];
122  for (typename std::map<std::size_t, typename SymmGroup::charge>::iterator it
123  = bond_index_charges[p].begin();
124  it != bond_index_charges[p].end();
125  ++it)
126  if (index.has(it->second))
127  index[index.position(it->second)] = std::make_pair(it->second, index.size_of_block(it->second)+1);
128  else
129  index.insert(std::make_pair(it->second, 1));
130  }
131  }
132 
134  {
135  typedef typename SymmGroup::charge charge;
136 
137  Index<SymmGroup> phys_i;
138  for (size_t r = 0; r < (*this)[p].row_dim(); ++r)
139  for (size_t c = 0; c < (*this)[p].col_dim(); ++c)
140  {
141  if (!(*this)[p].has(r,c))
142  continue;
143  for (size_t cs = 0; cs < (*this)[p].at(r, c).op.left_basis().size(); ++cs) {
144  std::pair<charge, size_t> sector = (*this)[p].at(r, c).op.left_basis()[cs];
145  if (! phys_i.has(sector.first))
146  phys_i.insert(sector);
147  }
148  }
149 
150  Index<SymmGroup> left_i = phys_i * adjoin(phys_i) * bond_indices[p];
151  Index<SymmGroup> right_i = bond_indices[p+1];
152 
153  left_i = common_subset(left_i, right_i);
154 
155  block_matrix<Matrix, SymmGroup> ret(left_i, right_i);
156 
157  std::map<charge, size_t> visited_c_basis;
158  for (size_t c = 0; c < (*this)[p].col_dim(); ++c) {
159  int outr = -1;
160  for (size_t r = 0; r < (*this)[p].row_dim(); ++r)
161  for (size_t ls = 0; ls < phys_i.size(); ++ls)
162  for (size_t rs = 0; rs < phys_i.size(); ++rs) {
163  charge lc = SymmGroup::fuse(bond_index_charges[p][r],
164  SymmGroup::fuse(phys_i[ls].first,
165  -phys_i[rs].first));
166  charge rc = bond_index_charges[p+1][c];
167 
168  if (lc != rc)
169  continue;
170 
171  outr++;
172 
173  if (! (*this)[p].has(r,c))
174  continue;
175  if (! (*this)[p].at(r,c).op.has_block(phys_i[ls].first, phys_i[rs].first) )
176  continue;
177 
178  std::size_t cs = (*this)[p].at(r, c).op.left_basis().position(phys_i[ls].first);
179 
180  assert( lc == rc );
181  assert( outr < left_i.size_of_block(lc) );
182 
183  // ...for now...
184  assert( num_rows((*this)[p].at(r,c).op[cs]) == 1 );
185  assert( num_cols((*this)[p].at(r,c).op[cs]) == 1 );
186 
187  ret(std::make_pair(lc, outr),
188  std::make_pair(rc, visited_c_basis[rc])) =
189  (*this)[p].at(r,c).op[cs](0,0);
190 
191 // maquis::cout << (*this)[p](r,c)[cs](0,0) << " | ";
192 // maquis::cout << r << " " << c << " " << phys_i[ls].first << " " << phys_i[rs].first;
193 // maquis::cout << " -> ";
194 // maquis::cout << "(" << lc << "," << outr << ") (" << rc << "," << visited_c_basis[rc] << ")" << std::endl;
195  }
196  visited_c_basis[bond_index_charges[p+1][c]]++;
197  }
198 
199 // maquis::cout << ret << std::endl;
200 // maquis::cout << "###" << std::endl;
201 
202  return ret;
203  }
204 
206  {
207  typedef typename SymmGroup::charge charge;
208 
209  Index<SymmGroup> phys_i;
210  for (size_t r = 0; r < (*this)[p].row_dim(); ++r)
211  for (size_t c = 0; c < (*this)[p].col_dim(); ++c)
212  {
213  if (!(*this)[p].has(r,c))
214  continue;
215  for (size_t cs = 0; cs < (*this)[p].at(r, c).op.left_basis().size(); ++cs) {
216  std::pair<charge, size_t> sector = (*this)[p].at(r, c).op.left_basis()[cs];
217  if (! phys_i.has(sector.first))
218  phys_i.insert(sector);
219  }
220  }
221 
222  Index<SymmGroup> left_i = bond_indices[p];
223  Index<SymmGroup> right_i = adjoin(phys_i) * phys_i * bond_indices[p+1];
224 
225  right_i = common_subset(right_i, left_i);
226 
227  block_matrix<Matrix, SymmGroup> ret(left_i, right_i);
228 
229  std::map<charge, size_t> visited_r_basis;
230  for (size_t r = 0; r < (*this)[p].row_dim(); ++r) {
231  int outc = -1;
232  for (size_t c = 0; c < (*this)[p].col_dim(); ++c)
233  for (size_t ls = 0; ls < phys_i.size(); ++ls)
234  for (size_t rs = 0; rs < phys_i.size(); ++rs) {
235  charge lc = bond_index_charges[p][r];
236  charge rc = SymmGroup::fuse(bond_index_charges[p+1][c],
237  SymmGroup::fuse(-phys_i[ls].first,
238  phys_i[rs].first));
239 
240  if (lc != rc)
241  continue;
242 
243  outc++;
244 
245  if (! (*this)[p].has(r,c))
246  continue;
247  if (! (*this)[p].at(r, c).op.has_block(phys_i[ls].first, phys_i[rs].first) )
248  continue;
249 
250  std::size_t cs = (*this)[p].at(r, c).op.left_basis().position(phys_i[ls].first);
251 
252  assert( lc == rc );
253  assert( outc < right_i.size_of_block(rc) );
254 
255  // ...for now...
256  assert( num_rows((*this)[p].at(r,c).op[cs]) == 1 );
257  assert( num_cols((*this)[p].at(r,c).op[cs]) == 1 );
258 
259  ret(std::make_pair(lc, visited_r_basis[lc]),
260  std::make_pair(rc, outc)) =
261  (*this)[p].at(r,c).op[cs](0,0);
262 
263 // maquis::cout << (*this)[p](r,c)[cs](0,0) << " | ";
264 // maquis::cout << r << " " << c << " " << phys_i[ls].first << " " << phys_i[rs].first;
265 // maquis::cout << " -> ";
266 // maquis::cout << "(" << lc << "," << visited_r_basis[lc] << ") (" << rc << "," << outc << ")" << std::endl;
267  }
268  visited_r_basis[bond_index_charges[p][r]]++;
269  }
270 
271 // maquis::cout << ret << std::endl;
272 // maquis::cout << "###" << std::endl;
273 
274  return ret;
275  }
276 
279  std::size_t p)
280  {
281  typedef typename SymmGroup::charge charge;
282 
283  Index<SymmGroup> phys_i;
284  for (size_t r = 0; r < (*this)[p].row_dim(); ++r)
285  for (size_t c = 0; c < (*this)[p].col_dim(); ++c)
286  {
287  for (size_t cs = 0; cs < (*this)[p].at(r, c).op.left_basis().size(); ++cs) {
288  std::pair<charge, size_t> sector = (*this)[p].at(r, c).op.left_basis()[cs];
289  if (! phys_i.has(sector.first))
290  phys_i.insert(sector);
291  }
292  }
293 
294  assert( left.right_basis() == right.left_basis() );
295  bond_indices[p+1] = left.right_basis();
296  {
297  std::size_t count = 0;
298  bond_index_charges[p+1].clear();
299  for (typename Index<SymmGroup>::basis_iterator it = left.right_basis().basis_begin();
300  !it.end(); ++it)
301  bond_index_charges[p+1][count++] = (*it).first;
302  }
303 
304  (*this)[p] = MPOTensor<Matrix, SymmGroup>((*this)[p].row_dim(),
305  bond_indices[p+1].sum_of_sizes());
306 
307  std::map<charge, size_t> visited_c_basis;
308  for (size_t c = 0; c < (*this)[p].col_dim(); ++c) {
309  int outr = -1;
310  for (size_t r = 0; r < (*this)[p].row_dim(); ++r)
311  for (size_t ls = 0; ls < phys_i.size(); ++ls)
312  for (size_t rs = 0; rs < phys_i.size(); ++rs)
313  {
314  charge lc = SymmGroup::fuse(bond_index_charges[p][r],
315  SymmGroup::fuse(phys_i[ls].first,
316  -phys_i[rs].first));
317  charge rc = bond_index_charges[p+1][c];
318 
319  if (lc != rc)
320  continue;
321 
322  outr++;
323 
324  typename Matrix::value_type val = left(std::make_pair(lc, outr),
325  std::make_pair(rc, visited_c_basis[rc]));
326 
327  if (std::abs(val) > 1e-40) {
329  charge blc = phys_i[ls].first, brc = phys_i[rs].first;
330  if ( (*this)[p].has(r,c) )
331  block = (*this)[p].at(r,c).op;
332  block.insert_block(Matrix(1, 1, val), blc, brc);
333  (*this)[p].set(r, c, block);
334 
335 // maquis::cout << val << " | ";
336 // maquis::cout << r << " " << c << " " << phys_i[ls].first << " " << phys_i[rs].first;
337 // maquis::cout << " <- ";
338 // maquis::cout << "(" << lc << "," << outr << ") (" << rc << "," << visited_c_basis[rc] << ")" << std::endl;
339  }
340  }
341  visited_c_basis[bond_index_charges[p+1][c]]++;
342  }
343 
344  (*this)[p+1] = MPOTensor<Matrix, SymmGroup>(bond_indices[p+1].sum_of_sizes(),
345  (*this)[p+1].col_dim());
346 
347  std::map<charge, size_t> visited_r_basis;
348  for (size_t r = 0; r < (*this)[p+1].row_dim(); ++r) {
349  int outc = -1;
350  for (size_t c = 0; c < (*this)[p+1].col_dim(); ++c)
351  for (size_t ls = 0; ls < phys_i.size(); ++ls)
352  for (size_t rs = 0; rs < phys_i.size(); ++rs)
353  {
354  charge lc = bond_index_charges[p+1][r];
355  charge rc = SymmGroup::fuse(bond_index_charges[p+2][c],
356  SymmGroup::fuse(-phys_i[ls].first,
357  phys_i[rs].first));
358 
359  if (lc != rc)
360  continue;
361 
362  outc++;
363 
364  typename Matrix::value_type val = right(std::make_pair(lc, visited_r_basis[lc]),
365  std::make_pair(rc, outc));
366 
367  if (std::abs(val) > 1e-40) {
369  charge blc = phys_i[ls].first, brc = phys_i[rs].first;
370  if ( (*this)[p+1].has(r,c) )
371  block = (*this)[p+1].at(r,c).op;
372  block.insert_block(Matrix(1, 1, val), blc, brc);
373  (*this)[p+1].set(r, c, block);
374 
375 // maquis::cout << val << " | ";
376 // maquis::cout << r << " " << c << " " << phys_i[ls].first << " " << phys_i[rs].first;
377 // maquis::cout << " <- ";
378 // maquis::cout << "(" << lc << "," << visited_r_basis[lc] << ") (" << rc << "," << outc << ")" << std::endl;
379  }
380  }
381  visited_r_basis[bond_index_charges[p+1][r]]++;
382  }
383  }
384 };
385 
386 #endif
block_matrix< Matrix, SymmGroup > make_right_matrix(std::size_t p)
Definition: mpo.h:205
elem
Definition: mpo.h:45
MPO()
Definition: mpo.h:41
bool has(charge c) const
size_type insert_block(Matrix const &, charge, charge)
std::size_t size_of_block(charge c) const
Definition: mpo.h:36
MPOTensor< Matrix, SymmGroup > elem_type
Definition: mpo.h:39
std::size_t num_rows(maquis::dmrg::one_matrix< T > const &m)
Definition: one_matrix.hpp:99
block_matrix< Matrix, SymmGroup > sqrt(block_matrix< Matrix, SymmGroup > m)
truncation_results svd_truncate(block_matrix< Matrix, SymmGroup > const &M, block_matrix< Matrix, SymmGroup > &U, block_matrix< Matrix, SymmGroup > &V, block_matrix< DiagMatrix, SymmGroup > &S, double rel_tol, std::size_t Mmax, bool verbose=true)
block_matrix< Matrix, SymmGroup > adjoin(block_matrix< Matrix, SymmGroup > const &m)
std::size_t num_cols(maquis::dmrg::one_matrix< T > const &m)
Definition: one_matrix.hpp:102
declaration of MPOTensor object
Index< SymmGroup > const & right_basis() const
std::vector< Index< SymmGroup > > bond_indices
Definition: mpo.h:76
std::size_t position(charge c) const
block_matrix< Matrix, SymmGroup > make_left_matrix(std::size_t p)
Definition: mpo.h:133
void calc_charges()
Definition: mpo.h:78
std::size_t insert(std::pair< charge, std::size_t > const &x)
void gemm(block_matrix< Matrix1, SymmGroup > const &A, block_matrix< Matrix2, SymmGroup > const &B, block_matrix< Matrix3, SymmGroup > &C)
Index< SymmGroup > const & left_basis() const
std::size_t size() const
Index< SymmGroup > common_subset(Index< SymmGroup > &a, Index< SymmGroup > &b)
T fuse(const A &ind, T d)
Fuse indices n[i] into one p = n[i] d^i.
void replace_pair(block_matrix< Matrix, SymmGroup > &left, block_matrix< Matrix, SymmGroup > &right, std::size_t p)
Definition: mpo.h:277