cMHN 1.2
C++ library for learning MHNs with pRC
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
7
8namespace pRC
9{
10 template<class T>
11 requires IsValue<T> || IsComplex<T>
13 {
14 public:
15 template<IsConvertible<T> R1, IsConvertible<T> R2, IsConvertible<T> R3>
16 static constexpr auto MakeJacobi(R1 const &x, R2 const &y, R3 const &z)
17 {
19 r.makeJacobi(x, y, z);
20 return r;
21 }
22
23 template<IsConvertible<T> R1, IsConvertible<T> R2>
24 static constexpr auto MakeGivens(R1 const &x, R2 const &y)
25 {
27 r.makeGivens(x, y);
28 return r;
29 }
30
31 public:
32 ~JacobiRotation() = default;
33 constexpr JacobiRotation(JacobiRotation const &) = default;
34 constexpr JacobiRotation(JacobiRotation &&) = default;
35 constexpr JacobiRotation &operator=(JacobiRotation const &) & = default;
36 constexpr JacobiRotation &operator=(JacobiRotation &&) & = default;
37 constexpr JacobiRotation() = default;
38
39 constexpr JacobiRotation(T const &c, T const &s)
40 : mC(c)
41 , mS(s)
42 {
43 }
44
45 template<class X, IsTensorish R = RemoveReference<X>>
46 requires IsConvertible<typename R::Type, T> && (R::Dimension == 2)
47 constexpr JacobiRotation(X &&a, Index const p, Index const q)
48 {
49 if constexpr(cDebugLevel >= DebugLevel::High)
50 {
52 m(0, 0) = a(p, p);
53 m(1, 0) = a(q, p);
54 m(0, 1) = a(p, q);
55 m(1, 1) = a(q, q);
56 if(!isSelfAdjoint(m))
57 {
59 "JacobiRotation input 2x2 matrix is not self-adjoint.");
60 }
61 }
62
63 auto const &x = real(a(p, p));
64 auto const y = mean(a(p, q), conj(a(q, p)));
65 auto const &z = real(a(q, q));
66
67 makeJacobi(x, y, z);
68 }
69
70 template<class X, IsTensorish R = RemoveReference<X>>
71 requires IsConvertible<typename R::Type, T> && (R::Dimension == 1)
72 constexpr JacobiRotation(X &&a, Index const p, Index const q)
73 {
74 auto const &x = a(p);
75 auto const &y = a(q);
76
77 makeGivens(x, y);
78 }
79
80 template<IsConvertible<T> R>
81 constexpr JacobiRotation(JacobiRotation<R> const &other)
82 : mC(other.c())
83 , mS(other.s())
84 {
85 }
86
87 template<IsConvertible<T> R>
88 constexpr auto &operator=(JacobiRotation<R> const &rhs) &
89 {
90 mC = rhs.c();
91 mS = rhs.s();
92 return *this;
93 }
94
95 constexpr decltype(auto) c() &&
96 {
97 return move(mC);
98 }
99
100 constexpr decltype(auto) c() const &&
101 {
102 return move(mC);
103 }
104
105 constexpr auto &c() &
106 {
107 return mC;
108 }
109
110 constexpr auto &c() const &
111 {
112 return mC;
113 }
114
115 constexpr decltype(auto) s() &&
116 {
117 return move(mS);
118 }
119
120 constexpr decltype(auto) s() const &&
121 {
122 return move(mS);
123 }
124
125 constexpr auto &s() &
126 {
127 return mS;
128 }
129
130 constexpr auto &s() const &
131 {
132 return mS;
133 }
134
135 private:
136 template<IsConvertible<T> R1, IsConvertible<T> R2, IsConvertible<T> R3>
137 constexpr auto makeJacobi(R1 const &x, R2 const &y, R3 const &z)
138 {
139 auto denominator = identity<NonComplex<T>>(2) * abs(y);
140 if(denominator <= NumericLimits<Value<T>>::min())
141 {
142 mC = identity();
143 mS = zero();
144 }
145 else
146 {
147 auto const beta = (x - z) / denominator;
148 auto const w = sqrt(norm<2, 1>(beta) + unit<NonComplex<T>>());
149 auto const t = [&beta, &w]()
150 {
151 if(beta > zero())
152 {
153 return rcp(beta + w);
154 }
155 else
156 {
157 return rcp(beta - w);
158 }
159 }();
160
161 mC = rcp(sqrt(norm<2, 1>(t) + unit<NonComplex<T>>()));
162 mS = conj(y) / abs(y);
163 if(t > zero())
164 {
165 mS = -mS;
166 }
167 mS *= abs(t) * mC;
168 }
169 }
170
171 template<IsConvertible<T> R1, IsConvertible<T> R2>
172 constexpr auto makeGivens(R1 const &x, R2 const &y)
173 {
174 using R = Common<R1, R2>;
175
176 if(x == zero() && y == zero())
177 {
178 mC = identity();
179 mS = zero();
180 return;
181 }
182
183#ifdef __FAST_MATH__
184 auto const t = sqrt(norm<2, 1>(x) + norm<2, 1>(y));
185 mC = conj(x) / t;
186 mS = y / t;
187#else
188 if(y == zero())
189 {
190 mC = sign(conj(x));
191 mS = zero();
192 return;
193 }
194
195 if(abs(x) <= NumericLimits<Value<R>>::min())
196 {
197 mS = sign(y);
198 mC = zero();
199 return;
200 }
201
202 if constexpr(IsComplex<R>)
203 {
204 auto const x1 = norm<1>(x);
205 auto const y1 = norm<1>(y);
206
207 if(x1 >= y1)
208 {
209 auto const xS = x / x1;
210 auto const x2 = norm<2, 1>(xS);
211 auto const yS = y / x1;
212 auto const y2 = norm<2, 1>(yS);
213
214 auto const u = sqrt(unit<NonComplex<T>>() + y2 / x2);
215
216 mC = rcp(u);
217 if(x.real() < zero())
218 {
219 mC = -mC;
220 }
221 mS = yS * conj(xS) * (mC / x2);
222 }
223 else
224 {
225 auto const xS = x / y1;
226 auto const x2 = norm<2, 1>(xS);
227 auto const yS = y / y1;
228 auto const y2 = norm<2, 1>(yS);
229
230 auto const u = y1 * sqrt(x2 + y2);
231
232 mC = abs(x) / u;
233 mS = conj(x) / abs(x) * (y / u);
234
235 if(x.real() < zero())
236 {
237 mC = -mC;
238 mS = -mS;
239 }
240 }
241 }
242 else
243 {
244 if(abs(x) > abs(y))
245 {
246 auto const t = y / x;
247 auto const u = sign(x) * sqrt(unit<T>() + norm<2, 1>(t));
248 mC = rcp(u);
249 mS = t * mC;
250 }
251 else
252 {
253 auto const t = x / y;
254 auto const u = sign(y) * sqrt(unit<T>() + norm<2, 1>(t));
255 mS = rcp(u);
256 mC = t * mS;
257 }
258 }
259#endif // __FAST_MATH__
260 }
261
262 private:
263 T mC;
264 T mS;
265 };
266
267 template<class T, Size M, Size N>
268 JacobiRotation(Tensor<T, M, N> const &a, Index const p, Index const q)
270
271 template<class V, class T, Size M, Size N>
273 Index const q) -> JacobiRotation<T>;
274
275 template<class T, Size N>
276 JacobiRotation(Tensor<T, N> const &a, Index const p, Index const q)
278
279 template<class V, class T, Size N>
281 Index const q) -> JacobiRotation<T>;
282
283 template<class TA, class TB>
284 static inline constexpr auto operator==(JacobiRotation<TA> const &a,
285 JacobiRotation<TB> const &b)
286 {
287 return a.c() == b.c() && a.s() == b.s();
288 }
289
290 template<class TA, class TB>
291 static inline constexpr auto operator!=(JacobiRotation<TA> const &a,
292 JacobiRotation<TB> const &b)
293 {
294 return !(a == b);
295 }
296
297 template<class TA, class TB>
298 static inline constexpr auto operator*(JacobiRotation<TA> const &a,
299 JacobiRotation<TB> const &b)
300 {
301 return JacobiRotation(a.c() * b.c() - conj(a.s()) * b.s(),
302 conj(a.c() * conj(b.s()) + conj(a.s()) * conj(b.c())));
303 }
304
305 template<class T>
306 static inline constexpr auto transpose(JacobiRotation<T> const &a)
307 {
308 return JacobiRotation(a.c(), -conj(a.s()));
309 }
310
311 template<class T>
312 static inline constexpr auto adjoint(JacobiRotation<T> const &a)
313 {
314 return JacobiRotation(conj(a.c()), -a.s());
315 }
316
317 template<class T, class X, IsTensorish R = RemoveReference<X>>
318 requires(R::Dimension == 2) &&
319 ((IsTensor<R> && !IsReference<X>) || IsAssignable<X>)
320 static inline constexpr decltype(auto)
321 apply(JacobiRotation<T> const &r, X &&m, Index const p, Index const q)
322 {
323 auto x = chip<0>(m, p);
324 auto y = chip<0>(m, q);
325
327 [&r, &x, &y](auto const i)
328 {
329 auto const tX = x(i);
330 auto const tY = y(i);
331 x(i) = r.c() * tX + conj(r.s()) * tY;
332 y(i) = -r.s() * tX + conj(r.c()) * tY;
333 });
334
335 return forward<X>(m);
336 }
337
338 template<class T, class X, IsTensorish R = RemoveReference<X>>
339 requires(R::Dimension == 2) &&
340 ((IsTensor<R> && !IsReference<X>) || IsAssignable<X>)
341 static inline constexpr decltype(auto)
342 apply(X &&m, JacobiRotation<T> const &r, Index const p, Index const q)
343 {
344 auto x = chip<1>(m, p);
345 auto y = chip<1>(m, q);
346
348 [&r, &x, &y](auto const i)
349 {
350 auto const tX = x(i);
351 auto const tY = y(i);
352 x(i) = r.c() * tX - r.s() * tY;
353 y(i) = conj(r.s()) * tX + conj(r.c()) * tY;
354 });
355
356 return forward<X>(m);
357 }
358
359 template<class T, class X, IsTensorish R = RemoveReference<X>>
360 requires(R::Dimension == 1) &&
361 ((IsTensor<R> && !IsReference<X>) || IsAssignable<X>)
362 static inline constexpr decltype(auto)
363 apply(JacobiRotation<T> const &r, X &&v, Index const p, Index const q)
364 {
365 auto const tX = v(p);
366 auto const tY = v(q);
367
368 v(p) = r.c() * tX + conj(r.s()) * tY;
369 v(q) = -r.s() * tX + conj(r.c()) * tY;
370
371 return forward<X>(v);
372 }
373
374 template<class T, class X, IsTensorish R = RemoveReference<X>>
375 requires(R::Dimension == 1) &&
376 ((IsTensor<R> && !IsReference<X>) || IsAssignable<X>)
377 static inline constexpr decltype(auto)
378 apply(X &&v, JacobiRotation<T> const &r, Index const p, Index const q)
379 {
380 auto const tX = v(p);
381 auto const tY = v(q);
382
383 v(p) = r.c() * tX - r.s() * tY;
384 v(q) = conj(r.s()) * tX + conj(r.c()) * tY;
385
386 return forward<X>(v);
387 }
388}
389#endif // pRC_ALGORITHMS_JACOBI_ROTATION_H
Definition value.hpp:12
Definition jacobi_rotation.hpp:13
constexpr JacobiRotation()=default
constexpr JacobiRotation & operator=(JacobiRotation const &) &=default
constexpr JacobiRotation(JacobiRotation< R > const &other)
Definition jacobi_rotation.hpp:81
static constexpr auto MakeJacobi(R1 const &x, R2 const &y, R3 const &z)
Definition jacobi_rotation.hpp:16
constexpr JacobiRotation & operator=(JacobiRotation &&) &=default
static constexpr auto MakeGivens(R1 const &x, R2 const &y)
Definition jacobi_rotation.hpp:24
constexpr auto & c() &
Definition jacobi_rotation.hpp:105
constexpr decltype(auto) c() &&
Definition jacobi_rotation.hpp:95
~JacobiRotation()=default
constexpr JacobiRotation(JacobiRotation &&)=default
constexpr JacobiRotation(X &&a, Index const p, Index const q)
Definition jacobi_rotation.hpp:72
constexpr decltype(auto) s() &&
Definition jacobi_rotation.hpp:115
constexpr decltype(auto) s() const &&
Definition jacobi_rotation.hpp:120
constexpr auto & operator=(JacobiRotation< R > const &rhs) &
Definition jacobi_rotation.hpp:88
constexpr JacobiRotation(JacobiRotation const &)=default
constexpr JacobiRotation(X &&a, Index const p, Index const q)
Definition jacobi_rotation.hpp:47
constexpr JacobiRotation(T const &c, T const &s)
Definition jacobi_rotation.hpp:39
constexpr auto & s() const &
Definition jacobi_rotation.hpp:130
constexpr auto & c() const &
Definition jacobi_rotation.hpp:110
constexpr decltype(auto) c() const &&
Definition jacobi_rotation.hpp:100
constexpr auto & s() &
Definition jacobi_rotation.hpp:125
Definition sequence.hpp:29
Definition declarations.hpp:20
Definition tensor.hpp:25
Definition concepts.hpp:43
int i
Definition gmock-matchers-comparisons_test.cc:603
Uncopyable z
Definition gmock-matchers-containers_test.cc:378
const double y
Definition gmock-matchers-containers_test.cc:377
int x
Definition gmock-matchers-containers_test.cc:376
const char * p
Definition gmock-matchers-containers_test.cc:379
static void error(Xs &&...args)
Definition log.hpp:14
Definition cholesky.hpp:10
static constexpr auto unit()
Definition unit.hpp:13
static constexpr auto sqrt(T const &a)
Definition sqrt.hpp:11
static constexpr auto rcp(T const &b)
Definition rcp.hpp:12
Size Index
Definition basics.hpp:32
static constexpr auto sign(T const &a)
Definition sign.hpp:11
static constexpr decltype(auto) apply(JacobiRotation< T > const &r, X &&m, Index const p, Index const q)
Definition jacobi_rotation.hpp:321
JacobiRotation(Tensor< T, M, N > const &a, Index const p, Index const q) -> JacobiRotation< T >
static constexpr auto operator*(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:298
static constexpr auto conj(T const &a)
Definition conj.hpp:11
std::common_type_t< Ts... > Common
Definition basics.hpp:53
static constexpr auto transpose(JacobiRotation< T > const &a)
Definition jacobi_rotation.hpp:306
static constexpr auto abs(T const &a)
Definition abs.hpp:11
typename ValueType< T >::Type Value
Definition value.hpp:72
static constexpr auto adjoint(JacobiRotation< T > const &a)
Definition jacobi_rotation.hpp:312
static constexpr decltype(auto) min(X &&a)
Definition min.hpp:13
static constexpr auto chip(Sequence< T, Is... > const)
Definition sequence.hpp:584
static constexpr auto operator!=(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:291
constexpr auto cDebugLevel
Definition config.hpp:48
static constexpr auto range(F &&f, Xs &&...args)
Definition range.hpp:18
static constexpr auto operator==(JacobiRotation< TA > const &a, JacobiRotation< TB > const &b)
Definition jacobi_rotation.hpp:284
static constexpr decltype(auto) real(X &&a)
Definition real.hpp:12
RemoveConstReference< ResultOf< Eval, ResultOf< Real, T > > > NonComplex
Definition complex.hpp:201
static constexpr auto identity()
Definition identity.hpp:13
static constexpr auto zero()
Definition zero.hpp:12
static constexpr auto mean(Xs &&...args)
Definition mean.hpp:16
static constexpr auto norm(T const &a)
Definition norm.hpp:12
static constexpr auto isSelfAdjoint(X &&a, TT const &tolerance=NumericLimits< TT >::tolerance())
Definition is_self_adjoint.hpp:14
Definition limits.hpp:13