xerus
a general purpose tensor library
retractions.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.h>
26 #include <xerus/misc/internal.h>
27 
28 namespace xerus {
29 
30  void HOSVDRetraction::operator()(TTTensor &_U, const TTTensor &_change) const {
31  Index i;
32  _U(i&0) = _U(i&0) + _change(i&0);
33  if (roundByVector) {
34  _U.round(rankVector);
35  } else {
36  _U.round(rank);
37  }
38  }
39 
40  void HOSVDRetraction::operator()(TTTensor &_U, const TTTangentVector &_change) const {
41  Index i;
42  _U = _change.added_to_base();
43  if (roundByVector) {
44  _U.round(rankVector);
45  } else {
46  _U.round(rank);
47  }
48  }
49 
50  void HOSVDRetractionII(TTTensor &_U, const TTTensor &_change) {
51  std::vector<size_t> oldRank = _U.ranks();
52  _U = _U + _change;
53  _U.round(oldRank);
54  }
55 
56  void HOSVDRetractionI(TTTensor &_U, const TTTangentVector &_change) {
57  std::vector<size_t> oldRank = _U.ranks();
58  _U = _change.added_to_base();
59  _U.round(oldRank);
60  }
61 
62  void ALSRetractionII(TTTensor &_U, const TTTensor &_change) {
63  static const ALSVariant roundingALS(1, 2, ALSVariant::lapack_solver, false);
64  TTTensor target = _U + _change;
65  roundingALS(_U, target);
66 // _U.move_core(0);
67  }
68 
69  void ALSRetractionI(TTTensor &_U, const TTTangentVector &_change) {
70  static const ALSVariant roundingALS(1, 2, ALSVariant::lapack_solver, false);
71  TTTensor target = _change.added_to_base();
72  roundingALS(_U, target);
73 // _U.move_core(0);
74  }
75 
76  void TTTangentVector::set_base(const TTTensor &_newBase) {
77  REQUIRE(_newBase.dimensions == baseL.dimensions, "");
78  baseL = _newBase;
79  baseL.move_core(0, true);
80  }
81 
82  TTTangentVector::TTTangentVector(const TTTensor& _base, const TTTensor& _direction) {
83  REQUIRE(_base.canonicalized && _base.corePosition == 0, "projection onto tangent plane is only implemented for core position 0 at the moment");
84  REQUIRE(_base.dimensions == _direction.dimensions, "");
85 
86  baseL = _base;
87  baseL.move_core(0, true);
88 
89  Index i1,i2,j1,j2,r,s, s2;
90  std::vector<Tensor> leftStackUV;
91  std::vector<Tensor> leftStackUU;
92  Tensor tmp({1,1}, [](){return 1.0;});
93  leftStackUV.push_back(tmp);
94  leftStackUU.push_back(tmp);
95  for (size_t i=0; i<baseL.degree()-1; ++i) {
96  Tensor newLeft;
97  newLeft(j1,j2) = leftStackUV.back()(i1,i2) * baseL.get_component(i)(i1,r,j1) * _direction.get_component(i)(i2,r,j2);
98  leftStackUV.emplace_back(std::move(newLeft));
99  newLeft(j1,j2) = leftStackUU.back()(i1,i2) * baseL.get_component(i)(i1,r,j1) * baseL.get_component(i)(i2,r,j2);
100  leftStackUU.emplace_back(std::move(newLeft));
101  }
102  Tensor right(tmp);
103  Tensor UTV;
104  std::vector<Tensor> tmpComponents;
105  for (size_t i=baseL.degree(); i>0; --i) {
106  const size_t currIdx = i-1;
107  std::unique_ptr<Tensor> newComponent(new Tensor);
108  const Tensor &UComp = baseL.get_component(currIdx);
109  Tensor V;
110  Tensor uuInv = pseudo_inverse(leftStackUU.back(), 1);
111  V(i1,r,j1) = uuInv(i1,s)* leftStackUV.back()(s,i2) * _direction.get_component(currIdx)(i2,r,j2) * right(j1,j2);
112 // if (i!=baseL.degree()) {
113 // V(i1,r,j1) = V(i1,r,j1) + UComp(i1,r,s)*UTV(s,j1);
114 // }
115  if (currIdx!=0) {
116  UTV(i1,i2) = V(i1,r,j1) * UComp(i2,r,j1);
117  V(i1,r,j1) = V(i1,r,j1) - UTV(i1,s) * UComp(s,r,j1);
118  }
119  tmpComponents.emplace_back(std::move(V));
120  if (currIdx != 0) {
121  right(j1,j2) = UComp(j1,r,i1) * _direction.get_component(currIdx)(j2,r,i2) * right(i1,i2);
122  }
123  leftStackUV.pop_back();
124  leftStackUU.pop_back();
125  }
126  while (!tmpComponents.empty()) {
127  components.emplace_back(std::move(tmpComponents.back()));
128  tmpComponents.pop_back();
129  }
130  }
131 
133  REQUIRE(components.size() == _rhs.components.size(), "");
134  for (size_t i=0; i<components.size(); ++i) {
135  components[i] += _rhs.components[i];
136  }
137  return *this;
138  }
139 
141  REQUIRE(components.size() == _rhs.components.size(), "");
142  for (size_t i=0; i<components.size(); ++i) {
143  components[i] -= _rhs.components[i];
144  }
145  return *this;
146  }
147 
149  for (auto &c : components) {
150  c *= _alpha;
151  }
152  return *this;
153  }
154 
156  TTTangentVector result(*this);
157  result *= _alpha;
158  return result;
159  }
160 
162  TTTangentVector result(_rhs);
163  result *= _alpha;
164  return result;
165  }
166 
168  REQUIRE(components.size() == _other.components.size(), "");
169  Index i1,i2,r,j1,j2;
170  value_t result = 0;
171  Tensor left({1,1}, [](){return 1.0;});
172  for (size_t i=0; i<components.size(); ++i) {
173  result += value_t(left(i1,i2)*components[i](i1,r,j1)*_other.components[i](i2,r,j1));
174  if (i < components.size()-1) {
175  left(j1,j2) = left(i1,i2) * baseL.get_component(i)(i1,r,j1) * baseL.get_component(i)(i2,r,j2);
176  }
177  }
178  return result;
179  }
180 
182  return std::sqrt(scalar_product(*this));
183  }
184 
185 
186  TTTensor TTTangentVector::change_direction_incomplete() const {
187  TTTensor result(baseL.degree());
188  Index i1,i2,n,r1,r2;
189  for (size_t i=1; i<components.size(); ++i) {
190  const Tensor &baseComponent = baseL.get_component(i);
191  REQUIRE(baseComponent.dimensions == components[i].dimensions, "illegal base tensor for this tangent vector (ranks or external dimension do not coincide)");
192  if (i < components.size()-1) {
193  Tensor newComponent;
194  newComponent(i1,r1,n,i2,r2) = Tensor::dirac({2,2},{0,0})(i1,i2) * baseComponent(r1,n,r2)
195  +Tensor::dirac({2,2},{0,1})(i1,i2) * components[i](r1,n,r2)
196  +Tensor::dirac({2,2},{1,1})(i1,i2) * baseComponent(r1,n,r2);
197  newComponent.reinterpret_dimensions({components[i].dimensions[0]*2, components[i].dimensions[1], components[i].dimensions[2]*2});
198  result.set_component(i, newComponent);
199  } else {
200  Tensor newComponent;
201  newComponent(i1,r1,n,r2) = Tensor::dirac({2},0)(i1) * components[i](r1,n,r2)
202  +Tensor::dirac({2},1)(i1) * baseComponent(r1,n,r2);
203  newComponent.reinterpret_dimensions({components[i].dimensions[0]*2, components[i].dimensions[1], 1});
204  result.set_component(i, newComponent);
205  }
206  }
207  return result;
208  }
209 
210  TTTangentVector::operator TTTensor() const {
211  if (components.size() == 1) {
212  TTTensor result(1);
213  result.set_component(0, components[0]);
214  return result;
215  }
216  TTTensor result = change_direction_incomplete();
217  Index i1,i2,n,r1,r2;
218  Tensor newComponent;
219  newComponent(r1,n,i2,r2) = Tensor::dirac({2},0)(i2) * baseL.get_component(0)(r1,n,r2)
220  +Tensor::dirac({2},1)(i2) * components[0](r1,n,r2);
221  newComponent.reinterpret_dimensions({1, components[0].dimensions[1], components[0].dimensions[2]*2});
222  result.set_component(0, newComponent);
223  result.move_core(0);
224  return result;
225 // TTTensor result(baseL);
226 // result.set_component(0, components[0]);
227 // for (size_t i=1; i<components.size(); ++i) {
228 // TTTensor tmp(baseL);
229 // tmp.set_component(i, components[i]);
230 // result += tmp;
231 // }
232 // result.move_core(0);
233 // return result;
234  }
235 
237  if (components.size() == 1) {
238  TTTensor result(1);
239  result.set_component(0, components[0]);
240  result = result + baseL;
241  return result;
242  }
243  TTTensor result = change_direction_incomplete();
244  Tensor newComponent;
245  Index i1,i2,n,r1,r2;
246  newComponent(r1,n,i2,r2) = Tensor::dirac({2},0)(i2) * baseL.get_component(0)(r1,n,r2)
247  +Tensor::dirac({2},1)(i2) * (baseL.get_component(0)(r1,n,r2) + components[0](r1,n,r2));
248  newComponent.reinterpret_dimensions({1, components[0].dimensions[1], components[0].dimensions[2]*2});
249  result.set_component(0, newComponent);
250  result.move_core(0);
251  return result;
252 // TTTensor result(baseL);
253 // for (size_t i=0; i<components.size(); ++i) {
254 // TTTensor tmp(baseL);
255 // tmp.set_component(i, components[i]);
256 // result += tmp;
257 // }
258 // result.move_core(0);
259 // return result;
260  }
261 
262 
263 
264  void SubmanifoldRetractionII(TTTensor &_U, const TTTensor &_change) {
265  TTTangentVector W(_U, _change);
266  SubmanifoldRetractionI(_U, W);
267  }
268 
269  void SubmanifoldRetractionI(TTTensor &_U, const TTTangentVector &_change) {
270  static const Index i1,j1,r;
271  for (size_t i=0; i<_U.degree(); ++i) { XERUS_REQUIRE_TEST;
272  std::unique_ptr<Tensor> newComponent(new Tensor);
273  (*newComponent)(i1,r,j1) = _U.get_component(i)(i1,r,j1) + _change.components[i](i1,r,j1);
274  _U.set_component(i, std::move(*newComponent));
275  }
276  _U.move_core(0, true);
277  }
278 
279 
280 
281 
282  // TODO do this without creating the change_direction tensor?
283  void ProjectiveVectorTransport(const TTTensor &_newBase, TTTangentVector &_tangentVector) {
284  REQUIRE(_newBase.canonicalized && _newBase.corePosition == 0, "Tangent vectors only implemented for core position 0 atm");
285 
286  _tangentVector = TTTangentVector(_newBase, TTTensor(_tangentVector));
287  }
288 } // namespace xerus
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
TTTangentVector operator*(value_t _alpha) const
void pseudo_inverse(Tensor &_inverse, const Tensor &_input, const size_t _splitPos)
Low-Level calculation of the pseudo inverse of a given Tensor.
Definition: tensor.cpp:1568
TTTensor added_to_base() const
#define XERUS_REQUIRE_TEST
Definition: check.h:51
#define REQUIRE
Definition: internal.h:33
DimensionTuple dimensions
Vector containing the individual dimensions of the tensor.
Definition: tensor.h:99
class to compactly represent tangent vectors of the manifold of constant TT-rank
Definition: retractions.h:33
void set_base(const TTTensor &_newBase)
Definition: retractions.cpp:76
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
void ProjectiveVectorTransport(const TTTensor &_newBase, TTTangentVector &_tangentVector)
simple vector transport by projecting onto the new tangent plane
bool canonicalized
Flag indicating whether the TTNetwork is canonicalized.
Definition: ttNetwork.h:51
Tensor operator*(const value_t _factor, Tensor _tensor)
Calculates the entrywise multiplication of the Tensor _tensor with the constant _factor.
Definition: tensor.cpp:1233
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
size_t degree() const
Gets the degree of the TensorNetwork.
void operator()(TTTensor &_U, const TTTensor &_change) const
Definition: retractions.cpp:30
value_t frob_norm() const
static Tensor XERUS_warn_unused dirac(DimensionTuple _dimensions, const MultiIndex &_position)
: Returns a Tensor with a single entry equals one and all other zero.
Definition: tensor.cpp:173
void move_core(const size_t _position, const bool _keepRank=false)
Move the core to a new position.
Definition: ttNetwork.cpp:582
TTNetwork< false > TTTensor
std::vector< size_t > ranks() const
Gets the ranks of the TTNetwork.
Definition: ttNetwork.cpp:717
void SubmanifoldRetractionI(TTTensor &_U, const TTTangentVector &_change)
retraction that performs componentwise addition of and where is the i-th component of the riemanni...
void set_component(const size_t _idx, Tensor _T)
Sets a specific component of the TT decomposition.
Definition: ttNetwork.cpp:471
Default include file for the xerus library.
TTTangentVector & operator+=(const TTTangentVector &_rhs)
Header file for comfort functions and macros that should not be exported in the library.
void ALSRetractionII(TTTensor &_U, const TTTensor &_change)
retraction that performs an ALS half-sweep to project back onto the Manifold. Automatically retains t...
Definition: retractions.cpp:62
void HOSVDRetractionII(TTTensor &_U, const TTTensor &_change)
Definition: retractions.cpp:50
std::vector< size_t > rankVector
Definition: retractions.h:63
double value_t
The type of values to be used by xerus.
Definition: basic.h:43
Class used to represent indices that can be used to write tensor calculations in index notation...
Definition: index.h:43
void HOSVDRetractionI(TTTensor &_U, const TTTangentVector &_change)
retraction that performs a HOSVD to project back onto the Manifold
Definition: retractions.cpp:56
value_t scalar_product(const TTTangentVector &_other) const
std::vector< Tensor > components
Definition: retractions.h:40
void ALSRetractionI(TTTensor &_U, const TTTangentVector &_change)
retraction that performs an ALS half-sweep to project back onto the Manifold. Automatically retains t...
Definition: retractions.cpp:69
TTTangentVector & operator*=(value_t _alpha)
void SubmanifoldRetractionII(TTTensor &_U, const TTTensor &_change)
retraction that performs componentwise addition of and where is the i-th component of the riemanni...
TTTangentVector & operator-=(const TTTangentVector &_rhs)
void round(const std::vector< size_t > &_maxRanks, const double _eps=EPSILON)
Reduce all ranks up to a given accuracy and maximal number.
Definition: ttNetwork.cpp:644
const Tensor & get_component(const size_t _idx) const
Read access to a specific component of the TT decomposition.
Definition: ttNetwork.cpp:464
size_t corePosition
The position of the core.
Definition: ttNetwork.h:58
std::vector< size_t > dimensions
Dimensions of the external indices, i.e. the dimensions of the tensor represented by the network...