pRC
multi-purpose Tensor Train library for C++
Loading...
Searching...
No Matches
jacobi_rotation.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-2-Clause
2
3#ifndef pRC_ALGORITHMS_JACOBI_ROTATION_H
4#define pRC_ALGORITHMS_JACOBI_ROTATION_H
5
6#include <prc/config.hpp>
12
13namespace pRC
14{
15 template<class T>
17 {
18 static_assert(IsValue<T>() || IsComplex<T>(),
19 "JacobiRotation<T>: T has to be of type Value or Complex.");
20
21 public:
22 template<class R1, class R2, class R3, class R = Common<R1, R2, R3>,
23 If<IsConvertible<R, T>> = 0>
24 static constexpr auto MakeJacobi(R1 const &x, R2 const &y, R3 const &z)
25 {
27 r.makeJacobi(x, y, z);
28 return r;
29 }
30
31 template<class R1, class R2, class R = Common<R1, R2>,
32 If<IsConvertible<R, T>> = 0>
33 static constexpr auto MakeGivens(R1 const &x, R2 const &y)
34 {
36 r.makeGivens(x, y);
37 return r;
38 }
39
40 public:
41 ~JacobiRotation() = default;
42 constexpr JacobiRotation(JacobiRotation const &) = default;
43 constexpr JacobiRotation(JacobiRotation &&) = default;
44 constexpr JacobiRotation &operator=(JacobiRotation const &) & = default;
45 constexpr JacobiRotation &operator=(JacobiRotation &&) & = default;
46 constexpr JacobiRotation() = default;
47
48 constexpr JacobiRotation(T const &c, T const &s)
49 : mC(c)
50 , mS(s)
51 {
52 }
53
54 template<class X, class R = RemoveReference<X>, If<IsTensorish<R>> = 0,
55 If<IsConvertible<typename R::Type, T>> = 0,
56 If<IsSatisfied<(typename R::Dimension() == 2)>> = 0>
57 constexpr JacobiRotation(X &&a, Index const p, Index const q)
58 {
59 if constexpr(cDebugLevel >= DebugLevel::High)
60 {
62 m(0, 0) = a(p, p);
63 m(1, 0) = a(q, p);
64 m(0, 1) = a(p, q);
65 m(1, 1) = a(q, q);
66 if(!isSelfAdjoint(m))
67 {
69 "JacobiRotation input 2x2 matrix is not self-adjoint.");
70 }
71 }
72
73 auto const &x = real(a(p, p));
74 auto const y = mean(a(p, q), conj(a(q, p)));
75 auto const &z = real(a(q, q));
76
77 makeJacobi(x, y, z);
78 }
79
80 template<class X, class R = RemoveReference<X>, If<IsTensorish<R>> = 0,
81 If<IsConvertible<typename R::Type, T>> = 0,
82 If<IsSatisfied<(typename R::Dimension() == 1)>> = 0>
83 constexpr JacobiRotation(X &&a, Index const p, Index const q)
84 {
85 auto const &x = a(p);
86 auto const &y = a(q);
87
88 makeGivens(x, y);
89 }
90
91 template<class R, If<IsConvertible<R, T>> = 0>
93 : mC(other.c())
94 , mS(other.s())
95 {
96 }
97
98 template<class R, If<IsConvertible<R, T>> = 0>
99 constexpr auto &operator=(JacobiRotation<R> const &rhs) &
100 {
101 mC = rhs.c();
102 mS = rhs.s();
103 return *this;
104 }
105
106 constexpr decltype(auto) c() &&
107 {
108 return move(mC);
109 }
110
111 constexpr decltype(auto) c() const &&
112 {
113 return move(mC);
114 }
115
116 constexpr auto &c() &
117 {
118 return mC;
119 }
120
121 constexpr auto &c() const &
122 {
123 return mC;
124 }
125
126 constexpr decltype(auto) s() &&
127 {
128 return move(mS);
129 }
130
131 constexpr decltype(auto) s() const &&
132 {
133 return move(mS);
134 }
135
136 constexpr auto &s() &
137 {
138 return mS;
139 }
140
141 constexpr auto &s() const &
142 {
143 return mS;
144 }
145
146 private:
147 template<class R1, class R2, class R3, class R = Common<R1, R2, R3>,
148 If<IsConvertible<R, T>> = 0>
149 constexpr auto makeJacobi(R1 const &x, R2 const &y, R3 const &z)
150 {
153 {
154 mC = identity();
155 mS = zero();
156 }
157 else
158 {
159 auto const beta = (x - z) / denominator;
160 auto const w =
162 auto const t = [&beta, &w]()
163 {
164 if(beta > zero())
165 {
166 return rcp(beta + w);
167 }
168 else
169 {
170 return rcp(beta - w);
171 }
172 }();
173
175 mS = conj(y) / abs(y);
176 if(t > zero())
177 {
178 mS = -mS;
179 }
180 mS *= abs(t) * mC;
181 }
182 }
183
184 template<class R1, class R2, class R = Common<R1, R2>,
185 If<IsConvertible<R, T>> = 0>
186 constexpr auto makeGivens(R1 const &x, R2 const &y)
187 {
188 if(x == zero() && y == zero())
189 {
190 mC = identity();
191 mS = zero();
192 return;
193 }
194
195#ifdef __FAST_MATH__
196 auto const t = sqrt(norm<2, 1>(x) + norm<2, 1>(y));
197 mC = conj(x) / t;
198 mS = y / t;
199#else
200 if(y == zero())
201 {
202 mC = sign(conj(x));
203 mS = zero();
204 return;
205 }
206
207 if(abs(x) <= NumericLimits<typename R::Value>::min())
208 {
209 mS = sign(y);
210 mC = zero();
211 return;
212 }
213
214 if constexpr(IsComplex<R>())
215 {
216 auto const x1 = norm<1>(x);
217 auto const y1 = norm<1>(y);
218
219 if(x1 >= y1)
220 {
221 auto const xS = x / x1;
222 auto const x2 = norm<2, 1>(xS);
223 auto const yS = y / x1;
224 auto const y2 = norm<2, 1>(yS);
225
226 auto const u =
228
229 mC = rcp(u);
230 if(x.real() < zero())
231 {
232 mC = -mC;
233 }
234 mS = yS * conj(xS) * (mC / x2);
235 }
236 else
237 {
238 auto const xS = x / y1;
239 auto const x2 = norm<2, 1>(xS);
240 auto const yS = y / y1;
241 auto const y2 = norm<2, 1>(yS);
242
243 auto const u = y1 * sqrt(x2 + y2);
244
245 mC = abs(x) / u;
246 mS = conj(x) / abs(x) * (y / u);
247
248 if(x.real() < zero())
249 {
250 mC = -mC;
251 mS = -mS;
252 }
253 }
254 }
255 else
256 {
257 if(abs(x) > abs(y))
258 {
259 auto const t = y / x;
260 auto const u = sign(x) * sqrt(unit<T>() + norm<2, 1>(t));
261 mC = rcp(u);
262 mS = t * mC;
263 }
264 else
265 {
266 auto const t = x / y;
267 auto const u = sign(y) * sqrt(unit<T>() + norm<2, 1>(t));
268 mS = rcp(u);
269 mC = t * mS;
270 }
271 }
272#endif // __FAST_MATH__
273 }
274
275 private:
276 T mC;
277 T mS;
278 };
279
280 template<class T, Size M, Size N>
281 JacobiRotation(Tensor<T, M, N> const &a, Index const p, Index const q)
283
284 template<class V, class T, Size M, Size N>
286 Index const q) -> JacobiRotation<T>;
287
288 template<class T, Size N>
289 JacobiRotation(Tensor<T, N> const &a, Index const p, Index const q)
291
292 template<class V, class T, Size N>
294 Index const q) -> JacobiRotation<T>;
295
296 template<class TA, class TB>
297 static inline constexpr auto operator==(JacobiRotation<TA> const &a,
298 JacobiRotation<TB> const &b)
299 {
300 return a.c() == b.c() && a.s() == b.s();
301 }
302
303 template<class TA, class TB>
304 static inline constexpr auto operator!=(JacobiRotation<TA> const &a,
305 JacobiRotation<TB> const &b)
306 {
307 return !(a == b);
308 }
309
310 template<class TA, class TB>
311 static inline constexpr auto operator*(JacobiRotation<TA> const &a,
312 JacobiRotation<TB> const &b)
313 {
314 return JacobiRotation(a.c() * b.c() - conj(a.s()) * b.s(),
315 conj(a.c() * conj(b.s()) + conj(a.s()) * conj(b.c())));
316 }
317
318 template<class T>
319 static inline constexpr auto transpose(JacobiRotation<T> const &a)
320 {
321 return JacobiRotation(a.c(), -conj(a.s()));
322 }
323
324 template<class T>
325 static inline constexpr auto adjoint(JacobiRotation<T> const &a)
326 {
327 return JacobiRotation(conj(a.c()), -a.s());
328 }
329
330 template<class T, class X, class R = RemoveReference<X>,
331 If<Any<All<IsTensor<R>, Not<IsReference<X>>>,
332 All<IsTensorish<R>, IsAssignable<X>>>> = 0,
333 If<IsSatisfied<(typename R::Dimension() == 2)>> = 0>
334 static inline constexpr decltype(auto) apply(JacobiRotation<T> const &r,
335 X &&m, Index const p, Index const q)
336 {
337 auto x = chip<0>(m, p);
338 auto y = chip<0>(m, q);
339
341 [&r, &x, &y](auto const i)
342 {
343 auto const tX = x(i);
344 auto const tY = y(i);
345 x(i) = r.c() * tX + conj(r.s()) * tY;
346 y(i) = -r.s() * tX + conj(r.c()) * tY;
347 });
348
349 return forward<X>(m);
350 }
351
352 template<class T, class X, class R = RemoveReference<X>,
353 If<Any<All<IsTensor<R>, Not<IsReference<X>>>,
354 All<IsTensorish<R>, IsAssignable<X>>>> = 0,
355 If<IsSatisfied<(typename R::Dimension() == 2)>> = 0>
356 static inline constexpr decltype(auto) apply(X &&m,
357 JacobiRotation<T> const &r, Index const p, Index const q)
358 {
359 auto x = chip<1>(m, p);
360 auto y = chip<1>(m, q);
361
363 [&r, &x, &y](auto const i)
364 {
365 auto const tX = x(i);
366 auto const tY = y(i);
367 x(i) = r.c() * tX - r.s() * tY;
368 y(i) = conj(r.s()) * tX + conj(r.c()) * tY;
369 });
370
371 return forward<X>(m);
372 }
373
374 template<class T, class X, class R = RemoveReference<X>,
375 If<Any<All<IsTensor<R>, Not<IsReference<X>>>,
376 All<IsTensorish<R>, IsAssignable<X>>>> = 0,
377 If<IsSatisfied<(typename R::Dimension() == 1)>> = 0>
378 static inline constexpr decltype(auto) apply(JacobiRotation<T> const &r,
379 X &&v, Index const p, Index const q)
380 {
381 auto const tX = v(p);
382 auto const tY = v(q);
383
384 v(p) = r.c() * tX + conj(r.s()) * tY;
385 v(q) = -r.s() * tX + conj(r.c()) * tY;
386
387 return forward<X>(v);
388 }
389
390 template<class T, class X, class R = RemoveReference<X>,
391 If<Any<All<IsTensor<R>, Not<IsReference<X>>>,
392 All<IsTensorish<R>, IsAssignable<X>>>> = 0,
393 If<IsSatisfied<(typename R::Dimension() == 1)>> = 0>
394 static inline constexpr decltype(auto) apply(X &&v,
395 JacobiRotation<T> const &r, Index const p, Index const q)
396 {
397 auto const tX = v(p);
398 auto const tY = v(q);
399
400 v(p) = r.c() * tX - r.s() * tY;
401 v(q) = conj(r.s()) * tX + conj(r.c()) * tY;
402
403 return forward<X>(v);
404 }
405}
406#endif // pRC_ALGORITHMS_JACOBI_ROTATION_H
Definition jacobi_rotation.hpp:17
constexpr JacobiRotation(X &&a, Index const p, Index const q)
Definition jacobi_rotation.hpp:57
constexpr JacobiRotation()=default
constexpr JacobiRotation(JacobiRotation< R > const &other)
Definition jacobi_rotation.hpp:92
constexpr JacobiRotation & operator=(JacobiRotation const &) &=default
constexpr JacobiRotation & operator=(JacobiRotation &&) &=default
static constexpr auto MakeJacobi(R1 const &x, R2 const &y, R3 const &z)
Definition jacobi_rotation.hpp:24
constexpr auto & operator=(JacobiRotation< R > const &rhs) &
Definition jacobi_rotation.hpp:99
constexpr auto & c() &
Definition jacobi_rotation.hpp:116
constexpr decltype(auto) c() &&
Definition jacobi_rotation.hpp:106
~JacobiRotation()=default
constexpr JacobiRotation(JacobiRotation &&)=default
static constexpr auto MakeGivens(R1 const &x, R2 const &y)
Definition jacobi_rotation.hpp:33
constexpr decltype(auto) s() &&
Definition jacobi_rotation.hpp:126
constexpr decltype(auto) s() const &&
Definition jacobi_rotation.hpp:131
constexpr JacobiRotation(JacobiRotation const &)=default
constexpr JacobiRotation(T const &c, T const &s)
Definition jacobi_rotation.hpp:48
constexpr auto & s() const &
Definition jacobi_rotation.hpp:141
constexpr auto & c() const &
Definition jacobi_rotation.hpp:121
constexpr decltype(auto) c() const &&
Definition jacobi_rotation.hpp:111
constexpr auto & s() &
Definition jacobi_rotation.hpp:136
Definition sequence.hpp:56
Definition type_traits.hpp:32
Class storing tensors.
Definition tensor.hpp:44
static void error(Xs &&...args)
Definition log.hpp:14
Definition cholesky.hpp:18
static constexpr auto mean(Xs &&...args)
Calculates the mean of a variable ammount of pRC objects.
Definition mean.hpp:22
static constexpr decltype(auto) apply(JacobiRotation< T > const &r, X &&m, Index const p, Index const q)
Definition jacobi_rotation.hpp:334
static constexpr auto rcp(Complex< T > const &b)
Definition rcp.hpp:13
static constexpr decltype(auto) real(X &&a)
Definition real.hpp:11
static constexpr auto zero()
Definition zero.hpp:12
static constexpr auto operator*(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:311
static constexpr auto sign(Complex< T > const &a)
Definition sign.hpp:13
static constexpr auto transpose(JacobiRotation< T > const &a)
Definition jacobi_rotation.hpp:319
static constexpr auto isSelfAdjoint(X &&a, TT const &tolerance=NumericLimits< TT >::tolerance())
Checks if a Tensor is self-adjoint.
Definition is_self_adjoint.hpp:27
static constexpr auto adjoint(JacobiRotation< T > const &a)
Definition jacobi_rotation.hpp:325
static constexpr auto abs(Complex< T > const &a)
Definition abs.hpp:12
static constexpr Conditional< IsSatisfied< C >, RemoveConstReference< X >, X > copy(X &&a)
Definition copy.hpp:13
static constexpr auto operator!=(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:304
constexpr auto cDebugLevel
Definition config.hpp:46
static constexpr auto operator==(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:297
static constexpr auto sqrt(Complex< T > const &a)
Definition sqrt.hpp:12
static constexpr auto conj(Complex< T > const &a)
Definition conj.hpp:11
Size Index
Definition type_traits.hpp:21
static constexpr auto identity()
Definition identity.hpp:12
Definition type_traits.hpp:15
Definition limits.hpp:13