xerus
a general purpose tensor library
als.cpp
Go to the documentation of this file.
1 // Xerus - A General Purpose Tensor Library
2 // Copyright (C) 2014-2017 Benjamin Huber and Sebastian Wolf.
3 //
4 // Xerus is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as published
6 // by the Free Software Foundation, either version 3 of the License,
7 // or (at your option) any later version.
8 //
9 // Xerus is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
13 //
14 // You should have received a copy of the GNU Affero General Public License
15 // along with Xerus. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // For further information on Xerus visit https://libXerus.org
18 // or contact us at contact@libXerus.org.
19 
25 #include <xerus/misc/math.h>
26 
27 #include <xerus/algorithms/als.h>
28 #include <xerus/basic.h>
29 #include <xerus/index.h>
31 #include <xerus/tensorNetwork.h>
32 #include <xerus/misc/internal.h>
33 
36 
37 namespace xerus {
38 
39  // -------------------------------------------------------------------------------------------------------------------------
40  // local solvers
41  // -------------------------------------------------------------------------------------------------------------------------
42 
43  void ALSVariant::lapack_solver(const TensorNetwork& _A, std::vector<Tensor>& _x, const TensorNetwork& _b, const ALSAlgorithmicData& _data) {
44  Tensor A(_A);
45  Tensor b(_b);
46  Tensor x;
47 
48  xerus::solve(x, A, b);
49 
50  Index i,j,k,l;
51  if (_data.direction == Increasing) {
52  for (size_t p = 0; p+1 < _data.ALS.sites; ++p) {
53  Tensor U, S;
54 // calculate_svd(U, S, x, x, 2, _data.targetRank[_data.currIndex+p], EPSILON); TODO
55  (U(i^2,j), S(j,k), x(k,l&1)) = SVD(x(i^2,l&2), _data.targetRank[_data.currIndex+p]);
56  _x[p] = std::move(U);
57  x(j,l&1) = S(j,k) * x(k,l&1);
58  }
59  _x.back() = std::move(x);
60  } else {
61  // direction: decreasing index
62  for (size_t p = _data.ALS.sites-1; p>0; --p) {
63  Tensor S, Vt;
64 // calculate_svd(x, S, Vt, x, x.degree()-1, _data.targetRank[_data.currIndex+p-1], EPSILON); TODO
65  (x(i&1,j), S(j,k), Vt(k,l&1)) = SVD(x(i&2,l^2), _data.targetRank[_data.currIndex+p-1]);
66  _x[p] = std::move(Vt);
67  x(i&1,k) = x(i&1,j) * S(j,k);
68  }
69  _x[0] = std::move(x);
70  }
71  }
72 
73  void ALSVariant::ASD_solver(const TensorNetwork &_A, std::vector<Tensor> &_x, const TensorNetwork &_b, const ALSAlgorithmicData &_data) {
74  // performs a single gradient step, so
75  // x = x + alpha * P( A^t (b - Ax) ) or for SPD: x = x + alpha * P( b - Ax )
76  // where the projection P is already part of the stacks
77  // and alpha is the exact stepsize for quadratic functionals
78  REQUIRE(_data.ALS.sites == 1, "ASD only defined for single site alternation at the moment");
79  Tensor grad;
80  Index i,j,k;
81  grad(i&0) = _b(i&0) - _A(i/2,j/2) * _x[0](j&0);
82  value_t alpha;
83  if (_data.ALS.assumeSPD) {
84  // stepsize alpha = <y,y>/<y,Ay>
85  alpha = misc::sqr(frob_norm(grad)) / value_t(grad(i&0) * _A(i/2,j/2) * grad(j&0));
86  } else {
87  grad(i&0) = _A(j/2,i/2) * grad(j&0);
88  // stepsize alpha = <y,y>/<Ay,Ay>
89  alpha = frob_norm(grad) / frob_norm(_A(i/2,j/2) * grad(j&0));
90  }
91  _x[0] += alpha * grad;
92  }
93 
94  // -------------------------------------------------------------------------------------------------------------------------
95  // helper functions
96  // -------------------------------------------------------------------------------------------------------------------------
97 
106  const size_t d = x.degree();
107  Index r1,r2,n1,cr1;
108 
109  size_t firstOptimizedIndex = 0;
110  size_t dimensionProd = 1;
111  while (firstOptimizedIndex + 1 < d) {
112  const size_t localDim = x.dimensions[firstOptimizedIndex];
113  size_t newDimensionProd = dimensionProd * localDim;
114  if (x.rank(firstOptimizedIndex) < newDimensionProd) {
115  break;
116  }
117 
118  Tensor& curComponent = x.component(firstOptimizedIndex);
119  curComponent.reinterpret_dimensions({curComponent.dimensions[0]*curComponent.dimensions[1], curComponent.dimensions[2]});
120  curComponent(r1,n1,r2) = curComponent(r1,cr1) * x.get_component(firstOptimizedIndex+1)(cr1,n1,r2);
121  x.set_component(firstOptimizedIndex+1, std::move(curComponent));
122 
123  //TODO sparse
124  x.set_component(firstOptimizedIndex, Tensor(
125  {dimensionProd, localDim, newDimensionProd},
126  [&](const std::vector<size_t> &_idx){
127  if (_idx[0]*localDim + _idx[1] == _idx[2]) {
128  return 1.0;
129  }
130  return 0.0;
131  })
132  );
133 
134  x.require_correct_format();
135 
136  firstOptimizedIndex += 1;
137  dimensionProd = newDimensionProd;
138  }
139 
140  size_t firstNotOptimizedIndex = d;
141  dimensionProd = 1;
142  while (firstNotOptimizedIndex > firstOptimizedIndex+ALS.sites) {
143  const size_t localDim = x.dimensions[firstNotOptimizedIndex-1];
144  size_t newDimensionProd = dimensionProd * localDim;
145  if (x.rank(firstNotOptimizedIndex-2) < newDimensionProd) {
146  break;
147  }
148 
149  Tensor& curComponent = x.component(firstNotOptimizedIndex-1);
150  curComponent.reinterpret_dimensions({curComponent.dimensions[0], curComponent.dimensions[1] * curComponent.dimensions[2]});
151  curComponent(r1,n1,r2) = x.get_component(firstNotOptimizedIndex-2)(r1,n1,cr1) * curComponent(cr1,r2);
152  x.set_component(firstNotOptimizedIndex-2, std::move(curComponent));
153 
154  //TODO sparse
155  x.set_component(firstNotOptimizedIndex-1, Tensor(
156  {newDimensionProd, localDim, dimensionProd},
157  [&](const std::vector<size_t> &_idx){
158  if (_idx[0] == _idx[1]*dimensionProd + _idx[2]) {
159  return 1.0;
160  }
161  return 0.0;
162  })
163  );
164 
165  x.require_correct_format();
166 
167  firstNotOptimizedIndex -= 1;
168  dimensionProd = newDimensionProd;
169  }
170 
171  if (canonicalizeAtTheEnd && corePosAtTheEnd < firstOptimizedIndex) {
172  x.assume_core_position(firstOptimizedIndex);
173  } else {
174  if (canonicalizeAtTheEnd && corePosAtTheEnd >= firstNotOptimizedIndex) {
175  x.assume_core_position(firstNotOptimizedIndex-1);
176  }
177 
178  x.move_core(firstOptimizedIndex, true);
179  }
180 
181  optimizedRange = std::pair<size_t, size_t>(firstOptimizedIndex, firstNotOptimizedIndex);
182  }
183 
185  //TODO optimization: create these networks without indices
186  Index cr1, cr2, cr3, cr4, r1, r2, r3, r4, n1, n2, n3;
187  TensorNetwork res;
188  INTERNAL_CHECK(A, "ie");
189  if (ALS.assumeSPD) {
190  res(r1,r2,r3, cr1,cr2,cr3) = x.get_component(_pos)(r1, n1, cr1)
191  * A->get_component(_pos)(r2, n1, n2, cr2)
192  * x.get_component(_pos)(r3, n2, cr3);
193  } else {
194  res(r1,r2,r3,r4, cr1,cr2,cr3, cr4) = x.get_component(_pos)(r1, n1, cr1)
195  * A->get_component(_pos)(r2, n2, n1, cr2)
196  * A->get_component(_pos)(r3, n2, n3, cr3)
197  * x.get_component(_pos)(r4, n3, cr4);
198  }
199  return res;
200  }
201 
203  //TODO optimization: create these networks without indices
204  Index cr1, cr2, cr3, r1, r2, r3, n1, n2;
205  TensorNetwork res;
206  if (ALS.assumeSPD || (A == nullptr)) {
207  res(r1,r2, cr1,cr2) = b.get_component(_pos)(r1, n1, cr1)
208  * x.get_component(_pos)(r2, n1, cr2);
209  } else {
210  res(r1,r2,r3, cr1,cr2,cr3) = b.get_component(_pos)(r1, n1, cr1)
211  * A->get_component(_pos)(r2, n1, n2, cr2)
212  * x.get_component(_pos)(r3, n2, cr3);
213  }
214  return res;
215  }
216 
218  const size_t d = x.degree();
219  Index r1,r2;
220 
221  Tensor tmpA;
222  Tensor tmpB;
223  if (ALS.assumeSPD || (A == nullptr)) {
224  tmpA = Tensor::ones({1,1,1});
225  tmpB = Tensor::ones({1,1});
226  } else {
227  tmpA = Tensor::ones({1,1,1,1});
228  tmpB = Tensor::ones({1,1,1});
229  }
230 
231 
232  localOperatorCache.left.emplace_back(tmpA);
233  localOperatorCache.right.emplace_back(tmpA);
234  rhsCache.left.emplace_back(tmpB);
235  rhsCache.right.emplace_back(tmpB);
236 
237  for (size_t i = d-1; i > optimizedRange.first + ALS.sites - 1; --i) {
238  if (A != nullptr) {
239  tmpA(r1&0) = localOperatorCache.right.back()(r2&0) * localOperatorSlice(i)(r1/2, r2/2);
240  localOperatorCache.right.emplace_back(tmpA);
241  }
242  tmpB(r1&0) = rhsCache.right.back()(r2&0) * localRhsSlice(i)(r1/2, r2/2);
243  rhsCache.right.emplace_back(tmpB);
244  }
245  for (size_t i = 0; i < optimizedRange.first; ++i) {
246  if (A != nullptr) {
247  tmpA(r2&0) = localOperatorCache.left.back()(r1&0) * localOperatorSlice(i)(r1/2, r2/2);
248  localOperatorCache.left.emplace_back((tmpA));
249  }
250  tmpB(r2&0) = rhsCache.left.back()(r1&0) * localRhsSlice(i)(r1/2, r2/2);
251  rhsCache.left.emplace_back(tmpB);
252  }
253  }
254 
256  if (A != nullptr) {
257  if (ALS.assumeSPD) {
258  residual_f = [&](){
259  Index n1, n2;
260  return frob_norm((*A)(n1/2,n2/2)*x(n2&0) - b(n1&0))/normB;
261  };
263  energy_f = residual_f;
264  } else {
265  energy_f = [&](){
266  Index r1,r2;
267  Tensor res;
268  // 0.5*<x,Ax> - <x,b>
269  TensorNetwork xAx = localOperatorCache.left.back();
270  TensorNetwork bx = rhsCache.left.back();
271  for (size_t i=0; i<ALS.sites; ++i) {
272  xAx(r2&0) = xAx(r1&0) * localOperatorSlice(currIndex+i)(r1/2, r2/2);
273  bx(r2&0) = bx(r1&0) * localRhsSlice(currIndex+i)(r1/2, r2/2);
274  }
275  res() = 0.5*xAx(r1&0) * localOperatorCache.right.back()(r1&0)
276  - bx(r1&0) * rhsCache.right.back()(r1&0);
277  return res.frob_norm();
278  };
279  }
280  } else {
281  // not Symmetric pos def
282  residual_f = [&](){
283  Index r1,r2;
284  Tensor res;
285  // <Ax,Ax> - 2 * <Ax,b> + <b,b>
286  TensorNetwork xAtAx = localOperatorCache.left.back();
287  TensorNetwork bAx = rhsCache.left.back();
288  for (size_t i=0; i<ALS.sites; ++i) {
289  xAtAx(r2&0) = xAtAx(r1&0) * localOperatorSlice(currIndex+i)(r1/2, r2/2);
290  bAx(r2&0) = bAx(r1&0) * localRhsSlice(currIndex+i)(r1/2, r2/2);
291  }
292  res() = xAtAx(r1&0) * localOperatorCache.right.back()(r1&0)
293  - 2 * bAx(r1&0) * rhsCache.right.back()(r1&0);
294  return std::sqrt(res[0] + misc::sqr(normB))/normB;
295  };
296  energy_f = residual_f;
297  }
298  } else {
299  // no operator A given
300  residual_f = [&](){
301  return frob_norm(x - b);
302  };
304  energy_f = residual_f;
305  } else {
306  energy_f = [&](){
307  Index r1,r2;
308  Tensor res;
309  // 0.5*<x,Ax> - <x,b> = 0.5*|x_i|^2 - <x,b>
310  TensorNetwork bx = rhsCache.left.back();
311  for (size_t i=0; i<ALS.sites; ++i) {
312  bx(r2&0) = bx(r1&0) * localRhsSlice(currIndex+i)(r1/2, r2/2);
313  }
314  res() = 0.5*x.get_component(currIndex)(r1&0) * x.get_component(currIndex)(r1&0)
315  - bx(r1&0) * rhsCache.right.back()(r1&0);
316  return res[0];
317  };
318  }
319  }
320  }
321 
323  : ALS(_ALS), A(_A), x(_x), b(_b)
324  , targetRank(_x.ranks())
325  , normB(frob_norm(_b))
326  , canonicalizeAtTheEnd(_x.canonicalized)
327  , corePosAtTheEnd(_x.corePosition)
328  , lastEnergy2(1e102)
329  , lastEnergy(1e101)
330  , energy(1e100)
331  , halfSweepCount(0)
332  , direction(Increasing)
333  {
335  prepare_stacks();
336  currIndex = optimizedRange.first;
338  }
339 
341  Index r1,r2;
342  Tensor tmpA, tmpB;
343  if (direction == Increasing) {
344  INTERNAL_CHECK(currIndex+ALS.sites < optimizedRange.second, "ie " << currIndex << " " << ALS.sites << " " << optimizedRange.first << " " << optimizedRange.second);
345  // Move core to next position (assumed to be done by the solver if sites > 1)
346  if (ALS.sites == 1) {
347  x.move_core(currIndex+1, true);
348  }
349 
350  // Move one site to the right
351  if (A != nullptr) {
352  localOperatorCache.right.pop_back();
353  tmpA(r2&0) = localOperatorCache.left.back()(r1&0) * localOperatorSlice(currIndex)(r1/2, r2/2);
354  localOperatorCache.left.emplace_back(std::move(tmpA));
355  }
356 
357  rhsCache.right.pop_back();
358  tmpB(r2&0) = rhsCache.left.back()(r1&0) * localRhsSlice(currIndex)(r1/2, r2/2);
359  rhsCache.left.emplace_back(std::move(tmpB));
360  currIndex++;
361  } else {
362  INTERNAL_CHECK(currIndex > optimizedRange.first, "ie");
363  // Move core to next position (assumed to be done by the solver if sites > 1)
364  if (ALS.sites == 1) {
365  x.move_core(currIndex-1, true);
366  }
367 
368  // move one site to the left
369  if (A != nullptr) {
370  localOperatorCache.left.pop_back();
371  tmpA(r1&0) = localOperatorCache.right.back()(r2&0) * localOperatorSlice(currIndex)(r1/2, r2/2);
372  localOperatorCache.right.emplace_back(std::move(tmpA));
373  }
374 
375  rhsCache.left.pop_back();
376  tmpB(r1&0) = rhsCache.right.back()(r2&0) * localRhsSlice(currIndex)(r1/2, r2/2);
377  rhsCache.right.emplace_back(std::move(tmpB));
378  currIndex--;
379  }
380  }
381 
382 
384  INTERNAL_CHECK(_data.A, "IE");
385  Index cr1, cr2, cr3, cr4, r1, r2, r3, r4, n1, n2, n3, n4, x;
386  TensorNetwork ATilde = _data.localOperatorCache.left.back();
387  if (assumeSPD) {
388  for (size_t p=0; p<sites; ++p) {
389  ATilde(n1^(p+1), n2, r2, n3^(p+1), n4) = ATilde(n1^(p+1), r1, n3^(p+1)) * _data.A->get_component(_data.currIndex+p)(r1, n2, n4, r2);
390  }
391  ATilde(n1^(sites+1), n2, n3^(sites+1), n4) = ATilde(n1^(sites+1), r1, n3^(sites+1)) * _data.localOperatorCache.right.back()(n2, r1, n4);
392  } else {
393  for (size_t p=0; p<sites; ++p) {
394  ATilde(n1^(p+1),n2, r3,r4, n3^(p+1),n4) = ATilde(n1^(p+1), r1,r2, n3^(p+1))
395  * _data.A->get_component(_data.currIndex+p)(r1, x, n2, r3)
396  * _data.A->get_component(_data.currIndex+p)(r2, x, n4, r4);
397  }
398  ATilde(n1^(sites+1), n2, n3^(sites+1), n4) = ATilde(n1^(sites+1), r1^2, n3^(sites+1)) * _data.localOperatorCache.right.back()(n2, r1^2, n4);
399  }
400  return ATilde;
401  }
402 
403 
405  Index cr1, cr2, cr3, cr4, r1, r2, r3, r4, n1, n2, n3, n4, x;
406  TensorNetwork BTilde;
407  if (assumeSPD || (_data.A == nullptr)) {
408  BTilde(n1,r1) = _data.rhsCache.left.back()(r1,n1);
409  for (size_t p=0; p<sites; ++p) {
410  BTilde(n1^(p+1), n2, cr1) = BTilde(n1^(p+1), r1) * _data.b.get_component(_data.currIndex+p)(r1, n2, cr1);
411  }
412  BTilde(n1^(sites+1),n2) = BTilde(n1^(sites+1), r1) * _data.rhsCache.right.back()(r1,n2);
413  } else {
414  BTilde(n1,r1^2) = _data.rhsCache.left.back()(r1^2,n1);
415  for (size_t p=0; p<sites; ++p) {
416  BTilde(n1^(p+1), n3, cr1, cr2) = BTilde(n1^(p+1), r1, r2)
417  * _data.b.get_component(_data.currIndex+p)(r1, n2, cr1)
418  * _data.A->get_component(_data.currIndex+p)(r2, n2, n3, cr2);
419  }
420  BTilde(n1^(sites+1),n2) = BTilde(n1^(sites+1), r1^2) * _data.rhsCache.right.back()(r1^2,n2);
421  }
422  return BTilde;
423  }
424 
425 
426  bool ALSVariant::check_for_end_of_sweep(ALSAlgorithmicData& _data, size_t _numHalfSweeps, value_t _convergenceEpsilon, PerformanceData &_perfData) const {
427  if ((_data.direction == Decreasing && _data.currIndex==_data.optimizedRange.first)
428  || (_data.direction == Increasing && _data.currIndex==_data.optimizedRange.second-sites))
429  {
430  LOG(ALS, "Sweep Done");
431  _data.halfSweepCount += 1;
432 
433  _data.lastEnergy2 = _data.lastEnergy;
434  _data.lastEnergy = _data.energy;
435  _data.energy = _data.energy_f();
436 
437  if (_perfData) {
440  _perfData.stop_timer();
441  value_t residual = _data.residual_f();
442  _perfData.continue_timer();
443  _perfData.add(residual, _data.x, flags);
444  } else {
445  _perfData.add(_data.energy, _data.x, flags);
446  }
447  }
448 
449  // Conditions for loop termination
450  if (_data.halfSweepCount == _numHalfSweeps
451  || std::abs(_data.lastEnergy-_data.energy) < _convergenceEpsilon
452  || std::abs(_data.lastEnergy2-_data.energy) < _convergenceEpsilon
453  || (_data.optimizedRange.second - _data.optimizedRange.first<=sites))
454  {
455  // we are done! yay
456  LOG(ALS, "ALS done, " << _data.energy << " " << _data.lastEnergy << " " << std::abs(_data.lastEnergy2-_data.energy) << " " << std::abs(_data.lastEnergy-_data.energy) << " < " << _convergenceEpsilon);
458  _data.x.move_core(_data.corePosAtTheEnd, true);
459  }
460  return true;
461  }
462 
463  // change walk direction
464  _data.direction = _data.direction == Increasing ? Decreasing : Increasing;
465  } else {
466  // we are not done with the sweep, just calculate data for the perfdata
467  if (_perfData) {
468  _perfData.stop_timer();
469  value_t residual = _data.residual_f();
470  _perfData.continue_timer();
471  _perfData.add(residual, _data.x, 0);
472  }
473  }
474  return false;
475  }
476 
477 
478  // -------------------------------------------------------------------------------------------------------------------------
479  // the actual algorithm
480  // -------------------------------------------------------------------------------------------------------------------------
481 
482 
483  double ALSVariant::solve(const TTOperator *_Ap, TTTensor &_x, const TTTensor &_b, size_t _numHalfSweeps, value_t _convergenceEpsilon, PerformanceData &_perfData) const {
484  LOG(ALS, "ALS("<< sites <<") called");
485  #ifndef XERUS_DISABLE_RUNTIME_CHECKS
488  REQUIRE(_x.degree() > 0, "");
489  REQUIRE(_x.dimensions == _b.dimensions, "");
490 
491  if (_Ap != nullptr) {
492  _Ap->require_correct_format();
493  REQUIRE(_Ap->dimensions.size() == _b.dimensions.size()*2, "");
494  for (size_t i=0; i<_x.dimensions.size(); ++i) {
495  REQUIRE(_Ap->dimensions[i] == _x.dimensions[i], "");
496  REQUIRE(_Ap->dimensions[i+_Ap->degree()/2] == _x.dimensions[i], "");
497  }
498  }
499  #endif
500 
501  if (_Ap != nullptr) {
502  _perfData << "ALS for ||A*x - b||^2, x.dimensions: " << _x.dimensions << '\n'
503  << "A.ranks: " << _Ap->ranks() << '\n'
504  << "x.ranks: " << _x.ranks() << '\n'
505  << "b.ranks: " << _b.ranks() << '\n'
506  << "maximum number of half sweeps: " << _numHalfSweeps << '\n'
507  << "convergence epsilon: " << _convergenceEpsilon << '\n';
508  } else {
509  _perfData << "ALS for ||x - b||^2, x.dimensions: " << _x.dimensions << '\n'
510  << "x.ranks: " << _x.ranks() << '\n'
511  << "b.ranks: " << _b.ranks() << '\n'
512  << "maximum number of half sweeps: " << _numHalfSweeps << '\n'
513  << "convergence epsilon: " << _convergenceEpsilon << '\n';
514  }
515  _perfData.start();
516 
517  ALSAlgorithmicData data(*this, _Ap, _x, _b);
518 
519  data.energy = data.energy_f();
520 
521  if (_perfData) {
522  _perfData.stop_timer();
523  value_t residual = data.residual_f();
524  _perfData.continue_timer();
525  _perfData.add(residual, _x, FLAG_FINISHED_FULLSWEEP);
526  }
527 
528  while (true) {
529  LOG(ALS, "Starting to optimize index " << data.currIndex);
530 
531  // update current component tensor
532  if (_Ap != nullptr) {
533  std::vector<Tensor> tmpX;
534  for (size_t p=0; p<sites; ++p) {
535  tmpX.emplace_back(_x.get_component(data.currIndex+p));
536  }
537  localSolver(construct_local_operator(data), tmpX, construct_local_RHS(data), data);
538  for (size_t p=0; p<sites; ++p) {
539  _x.set_component(data.currIndex+p, std::move(tmpX[p]));
540  }
541  } else {
542  //TODO?
543  REQUIRE(sites==1, "approximation dmrg not implemented yet");
544  _x.component(data.currIndex) = Tensor(construct_local_RHS(data));
545  }
546 
547  if(check_for_end_of_sweep(data, _numHalfSweeps, _convergenceEpsilon, _perfData)) {
548  return data.energy; // TODO residual?
549  }
550 
551  data.move_to_next_index();
552  }
553  }
554 
555 
556  const ALSVariant ALS(1, 0, ALSVariant::lapack_solver, false);
557  const ALSVariant ALS_SPD(1, 0, ALSVariant::lapack_solver, true);
558 
559  const ALSVariant DMRG(2, 0, ALSVariant::lapack_solver, false);
560  const ALSVariant DMRG_SPD(2, 0, ALSVariant::lapack_solver, true);
561 
562  const ALSVariant ASD(1, 0, ALSVariant::ASD_solver, false);
563  const ALSVariant ASD_SPD(1, 0, ALSVariant::ASD_solver, true);
564 } // namespace xerus
Header file for some additional math functions.
LocalSolver localSolver
Definition: als.h:124
Helper class to allow an intuitive syntax for SVD factorisations.
TensorNetwork construct_local_operator(ALSAlgorithmicData &_data) const
Definition: als.cpp:383
value_t lastEnergy2
energy at the end of last full sweep
Definition: als.h:63
static void lapack_solver(const TensorNetwork &_A, std::vector< Tensor > &_x, const TensorNetwork &_b, const ALSAlgorithmicData &_data)
local solver that calls the corresponding lapack routines (LU solver)
Definition: als.cpp:43
const ALSVariant ASD
default variant of the alternating steepest descent for non-symmetric operators
value_t frob_norm() const
Calculates the frobenious norm of the tensor.
Definition: tensor.cpp:286
const ALSVariant ASD_SPD
default variant of the alternating steepest descent for symmetric positive-definite operators ...
Header file for the Index class.
Header file for the IndexedTensorMoveable class.
Header file defining lists of indexed tensors.
value_t energy
current value of the energy residual
Definition: als.h:65
#define REQUIRE
Definition: internal.h:33
Tensor & component(const size_t _idx)
Complete access to a specific component of the TT decomposition.
Definition: ttNetwork.cpp:457
Very general class used to represent arbitary tensor networks.
Definition: tensorNetwork.h:42
std::function< value_t()> energy_f
the energy functional used for this calculation
Definition: als.h:59
#define LOG
Definition: internal.h:38
TensorNetwork localOperatorSlice(size_t _pos)
Definition: als.cpp:184
ContractedTNCache rhsCache
stacks for the right-hand-side (either xb or xAtb)
Definition: als.h:54
const ALSVariant ALS
default variant of the single-site ALS algorithm for non-symmetric operators using the lapack solver ...
DimensionTuple dimensions
Vector containing the individual dimensions of the tensor.
Definition: tensor.h:99
Header file for the classes defining factorisations of Tensors.
const size_t FLAG_FINISHED_HALFSWEEP
Definition: als.h:109
Specialized TensorNetwork class used to represent TTTensor and TToperators.
size_t halfSweepCount
current count of halfSweeps
Definition: als.h:66
The main namespace of xerus.
Definition: basic.h:37
Class that handles simple (non-decomposed) tensors in a dense or sparse representation.
Definition: tensor.h:70
Header file for the ALS algorithm and its variants.
size_t corePosAtTheEnd
core position that should be restored at the end of the algorithm
Definition: als.h:58
void prepare_stacks()
prepares the initial stacks for the local operator and local right-hand-side
Definition: als.cpp:217
void move_to_next_index()
performs one step in direction, updating all stacks
Definition: als.cpp:340
void prepare_x_for_als()
Finds the range of notes that need to be optimized and orthogonalizes _x properly.
Definition: als.cpp:105
Storage class for the performance data collected during an algorithm (typically iteration count...
std::pair< size_t, size_t > optimizedRange
range of indices for the nodes of _x that need to be optimized
Definition: als.h:56
uint sites
the number of sites that are simultaneously optimized
Definition: als.h:112
static Tensor XERUS_warn_unused ones(DimensionTuple _dimensions)
: Returns a Tensor with all entries equal to one.
Definition: tensor.cpp:122
std::function< value_t()> residual_f
the functional to calculate the current residual
Definition: als.h:60
void reinterpret_dimensions(DimensionTuple _newDimensions)
Reinterprets the dimensions of the tensor.
Definition: tensor.cpp:620
Wrapper class for all ALS variants (dmrg etc.)
Definition: als.h:37
void solve(internal::IndexedTensorWritable< Tensor > &&_x, internal::IndexedTensorReadOnly< Tensor > &&_A, internal::IndexedTensorReadOnly< Tensor > &&_b)
const TTTensor & b
global right-hand-side
Definition: als.h:51
size_t degree() const
Gets the degree of the TensorNetwork.
bool preserveCorePosition
if true the core will be moved to its original position at the end
Definition: als.h:117
TensorNetwork construct_local_RHS(ALSAlgorithmicData &_data) const
Definition: als.cpp:404
void move_core(const size_t _position, const bool _keepRank=false)
Move the core to a new position.
Definition: ttNetwork.cpp:582
const TTOperator * A
global operator A
Definition: als.h:49
std::vector< size_t > ranks() const
Gets the ranks of the TTNetwork.
Definition: ttNetwork.cpp:717
bool assumeSPD
if true the operator A will be assumed to be symmetric positive definite
Definition: als.h:118
size_t currIndex
position that is currently being optimized
Definition: als.h:62
double solve(const TTOperator *_Ap, TTTensor &_x, const TTTensor &_b, size_t _numHalfSweeps, value_t _convergenceEpsilon, PerformanceData &_perfData=NoPerfData) const
Definition: als.cpp:483
std::vector< size_t > targetRank
rank for the final x
Definition: als.h:52
void set_component(const size_t _idx, Tensor _T)
Sets a specific component of the TT decomposition.
Definition: ttNetwork.cpp:471
value_t lastEnergy
energy at the end of last halfsweep
Definition: als.h:64
Header file for comfort functions and macros that should not be exported in the library.
void choose_energy_functional()
chooses the fitting energy functional according to settings and whether an operator A was given ...
Definition: als.cpp:255
static XERUS_force_inline value_t frob_norm(const Tensor &_tensor)
Calculates the frobenius norm of the given tensor.
Definition: tensor.h:931
bool check_for_end_of_sweep(ALSAlgorithmicData &_data, size_t _numHalfSweeps, value_t _convergenceEpsilon, PerformanceData &_perfData) const
Definition: als.cpp:426
bool useResidualForEndCriterion
calculates the residual to decide if the ALS converged. recommended if _perfdata is given...
Definition: als.h:116
constexpr T sqr(const T &_a) noexcept
: Calculates _a*_a.
Definition: math.h:43
TTTensor & x
current iterate x
Definition: als.h:50
Header file for shorthand notations that are xerus specific but used throughout the library...
double value_t
The type of values to be used by xerus.
Definition: basic.h:43
TensorNetwork localRhsSlice(size_t _pos)
Definition: als.cpp:202
static void ASD_solver(const TensorNetwork &_A, std::vector< Tensor > &_x, const TensorNetwork &_b, const ALSAlgorithmicData &_data)
Definition: als.cpp:73
const ALSVariant & ALS
the algorithm this data belongs to
Definition: als.h:48
virtual void require_correct_format() const override
Tests whether the network resembles that of a TTTensor and checks consistency with the underlying ten...
Definition: ttNetwork.cpp:290
const ALSVariant DMRG
default variant of the two-site DMRG algorithm for non-symmetric operators using the lapack solver ...
Class used to represent indices that can be used to write tensor calculations in index notation...
Definition: index.h:43
bool canonicalizeAtTheEnd
whether _x should be canonicalized at the end
Definition: als.h:57
const size_t FLAG_FINISHED_FULLSWEEP
Definition: als.h:110
#define INTERNAL_CHECK
Definition: internal.h:37
ALSAlgorithmicData(const ALSVariant &, const TTOperator *, TTTensor &, const TTTensor &)
Definition: als.cpp:322
Direction direction
direction of current sweep
Definition: als.h:67
const ALSVariant DMRG_SPD
default variant of the two-site DMRG algorithm for symmetric positive-definite operators using the la...
Header file for the TensorNetwork class.
const ALSVariant ALS_SPD
default variant of the single-site ALS algorithm for symmetric positive-definite operators using the ...
void add(const size_t _itrCount, const value_t _residual, const TensorNetwork::RankTuple _ranks=TensorNetwork::RankTuple(), const size_t _flags=0)
const Tensor & get_component(const size_t _idx) const
Read access to a specific component of the TT decomposition.
Definition: ttNetwork.cpp:464
ContractedTNCache localOperatorCache
stacks for the local operator (either xAx or xAtAx)
Definition: als.h:53
std::vector< size_t > dimensions
Dimensions of the external indices, i.e. the dimensions of the tensor represented by the network...