GM2Calc 2.3.0
Loading...
Searching...
No Matches
gm2_linalg.hpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU 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// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#ifndef GM2_LINALG_HPP
20#define GM2_LINALG_HPP
21
22#include <limits>
23#include <cctype>
24#include <cmath>
25#include <complex>
26#include <algorithm>
27#include <stdexcept>
28#include <Eigen/Core>
29#include <Eigen/SVD>
30#include <Eigen/Eigenvalues>
31#include <unsupported/Eigen/MatrixFunctions>
32
33namespace gm2calc {
34
35#define MAX_(i, j) (((i) > (j)) ? (i) : (j))
36#define MIN_(i, j) (((i) < (j)) ? (i) : (j))
37
38template<class Real, class Scalar, int M, int N>
40(const Eigen::Matrix<Scalar, M, N>& m,
41 Eigen::Array<Real, MIN_(M, N), 1>& s,
42 Eigen::Matrix<Scalar, M, M> *u,
43 Eigen::Matrix<Scalar, N, N> *vh)
44{
45 Eigen::JacobiSVD<Eigen::Matrix<Scalar, M, N> >
46 svd(m, (u ? Eigen::ComputeFullU : 0) | (vh ? Eigen::ComputeFullV : 0));
47 s = svd.singularValues();
48 if (u) { *u = svd.matrixU(); }
49 if (vh) { *vh = svd.matrixV().adjoint(); }
50}
51
52template<class Real, class Scalar, int N>
54(const Eigen::Matrix<Scalar, N, N>& m,
55 Eigen::Array<Real, N, 1>& w,
56 Eigen::Matrix<Scalar, N, N> *z)
57{
58 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<Scalar,N,N> > es;
59 if (N == 2 || N == 3) {
60 es.computeDirect(m, z ? Eigen::ComputeEigenvectors : Eigen::EigenvaluesOnly);
61 } else {
62 es.compute(m, z ? Eigen::ComputeEigenvectors : Eigen::EigenvaluesOnly);
63 }
64 w = es.eigenvalues();
65 if (z) { *z = es.eigenvectors(); }
66}
67
68/**
69 * Template version of DDISNA from LAPACK.
70 */
71template<int M, int N, class Real>
72void disna(const char& JOB, const Eigen::Array<Real, MIN_(M, N), 1>& D,
73 Eigen::Array<Real, MIN_(M, N), 1>& SEP, int& INFO)
74{
75// -- LAPACK computational routine (version 3.4.0) --
76// -- LAPACK is a software package provided by Univ. of Tennessee, --
77// -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
78// November 2011
79//
80// =====================================================================
81
82// .. Parameters ..
83 const Real ZERO = 0;
84// .. Local Scalars ..
85 bool DECR, EIGEN, INCR, LEFT, RIGHT, SINGUL;
86 int I, K;
87 Real ANORM, EPS, NEWGAP, OLDGAP, SAFMIN, THRESH;
88//
89// Test the input arguments
90//
91 INFO = 0;
92 EIGEN = std::toupper(JOB) == 'E';
93 LEFT = std::toupper(JOB) == 'L';
94 RIGHT = std::toupper(JOB) == 'R';
95 SINGUL = LEFT || RIGHT;
96 if (EIGEN) {
97 K = M;
98 } else if (SINGUL) {
99 K = MIN_(M, N);
100 }
101 if (!EIGEN && !SINGUL) {
102 INFO = -1;
103 } else if (M < 0) {
104 INFO = -2;
105 } else if (K < 0) {
106 INFO = -3;
107 } else {
108 INCR = true;
109 DECR = true;
110 for (I = 0; I < K - 1; I++) {
111 if (INCR) {
112 INCR = INCR && D(I) <= D(I+1);
113 }
114 if (DECR) {
115 DECR = DECR && D(I) >= D(I+1);
116 }
117 }
118 if (SINGUL && K > 0) {
119 if (INCR) {
120 INCR = INCR && ZERO <= D(0);
121 }
122 if (DECR) {
123 DECR = DECR && D(K-1) >= ZERO;
124 }
125 }
126 if (!(INCR || DECR)) {
127 INFO = -4;
128 }
129 }
130 if (INFO != 0) {
131 // CALL XERBLA( 'DDISNA', -INFO )
132 return;
133 }
134//
135// Quick return if possible
136//
137 if (K == 0) {
138 return;
139 }
140//
141// Compute reciprocal condition numbers
142//
143 if (K == 1) {
144 SEP(0) = std::numeric_limits<Real>::max();
145 } else {
146 OLDGAP = std::fabs(D(1) - D(0));
147 SEP(0) = OLDGAP;
148 for (I = 1; I < K - 1; I++) {
149 NEWGAP = std::fabs(D(I+1) - D(I));
150 SEP(I) = std::min(OLDGAP, NEWGAP);
151 OLDGAP = NEWGAP;
152 }
153 SEP(K-1) = OLDGAP;
154 }
155 if (SINGUL) {
156 if ((LEFT && M > N) || (RIGHT && M < N)) {
157 if (INCR) {
158 SEP( 0 ) = std::min(SEP( 0 ), D( 0 ));
159 }
160 if (DECR) {
161 SEP(K-1) = std::min(SEP(K-1), D(K-1));
162 }
163 }
164 }
165//
166// Ensure that reciprocal condition numbers are not less than
167// threshold, in order to limit the size of the error bound
168//
169 // Note std::numeric_limits<double>::epsilon() == 2 * DLAMCH('E')
170 // since the former is the smallest eps such that 1.0 + eps > 1.0
171 // while DLAMCH('E') is the smallest eps such that 1.0 - eps < 1.0
172 EPS = std::numeric_limits<Real>::epsilon();
173 SAFMIN = std::numeric_limits<Real>::min();
174 ANORM = std::max(std::fabs(D(0)), std::fabs(D(K-1)));
175 if (ANORM == ZERO) {
176 THRESH = EPS;
177 } else {
178 THRESH = std::max(EPS*ANORM, SAFMIN);
179 }
180 for (I = 0; I < K; I++) {
181 SEP(I) = std::max(SEP(I), THRESH);
182 }
183}
184
185
186template<class Real, class Scalar, int M, int N>
188(const Eigen::Matrix<Scalar, M, N>& m,
189 Eigen::Array<Real, MIN_(M, N), 1>& s,
190 Eigen::Matrix<Scalar, M, M> *u,
191 Eigen::Matrix<Scalar, N, N> *vh)
192{
194}
195
196template<class Real, class Scalar, int M, int N>
198(const Eigen::Matrix<Scalar, M, N>& m,
199 Eigen::Array<Real, MIN_(M, N), 1>& s,
200 Eigen::Matrix<Scalar, M, M> *u = 0,
201 Eigen::Matrix<Scalar, N, N> *vh = 0,
202 Real *s_errbd = 0,
203 Eigen::Array<Real, MIN_(M, N), 1> *u_errbd = 0,
204 Eigen::Array<Real, MIN_(M, N), 1> *v_errbd = 0)
205{
207
208 // see http://www.netlib.org/lapack/lug/node96.html
209 if (!s_errbd) { return; }
210 const Real EPSMCH = std::numeric_limits<Real>::epsilon();
211 *s_errbd = EPSMCH * s[0];
212
213 Eigen::Array<Real, MIN_(M, N), 1> RCOND;
214 int INFO;
215 if (u_errbd) {
216 disna<M, N>('L', s, RCOND, INFO);
217 u_errbd->fill(*s_errbd);
218 *u_errbd /= RCOND;
219 }
220 if (v_errbd) {
221 disna<M, N>('R', s, RCOND, INFO);
222 v_errbd->fill(*s_errbd);
223 *v_errbd /= RCOND;
224 }
225}
226
227/**
228 * Singular value decomposition of M-by-N matrix m such that
229 *
230 * sigma.setZero(); sigma.diagonal() = s;
231 * m == u * sigma * vh // LAPACK convention
232 *
233 * and `(s >= 0).all()`. Elements of s are in descending order. The
234 * above decomposition can be put in the form
235 *
236 * m == u * s.matrix().asDiagonal() * vh
237 *
238 * if `M == N`.
239 *
240 * @tparam Real type of real and imaginary parts of Scalar
241 * @tparam Scalar type of elements of m, u, and vh
242 * @tparam M number of rows in m
243 * @tparam N number of columns in m
244 * @param[in] m M-by-N matrix to be decomposed
245 * @param[out] s array of length min(M,N) to contain singular values
246 * @param[out] u M-by-M unitary matrix
247 * @param[out] vh N-by-N unitary matrix
248 */
249template<class Real, class Scalar, int M, int N>
250void svd
251(const Eigen::Matrix<Scalar, M, N>& m,
252 Eigen::Array<Real, MIN_(M, N), 1>& s,
253 Eigen::Matrix<Scalar, M, M>& u,
254 Eigen::Matrix<Scalar, N, N>& vh)
255{
257}
258
259/**
260 * Same as svd(m, s, u, vh) except that an approximate error bound for
261 * the singular values is returned as well. The error bound is
262 * estimated following the method presented at
263 * http://www.netlib.org/lapack/lug/node96.html.
264 *
265 * @param[out] s_errbd approximate error bound for the elements of s
266 *
267 * See the documentation of svd(m, s, u, vh) for the other parameters.
268 */
269template<class Real, class Scalar, int M, int N>
270void svd
271(const Eigen::Matrix<Scalar, M, N>& m,
272 Eigen::Array<Real, MIN_(M, N), 1>& s,
273 Eigen::Matrix<Scalar, M, M>& u,
274 Eigen::Matrix<Scalar, N, N>& vh,
275 Real& s_errbd)
276{
278}
279
280/**
281 * Same as svd(m, s, u, vh, s_errbd) except that approximate error
282 * bounds for the singular vectors are returned as well. The error
283 * bounds are estimated following the method presented at
284 * http://www.netlib.org/lapack/lug/node96.html.
285 *
286 * @param[out] u_errbd array of approximate error bounds for u
287 * @param[out] v_errbd array of approximate error bounds for vh
288 *
289 * See the documentation of svd(m, s, u, vh, s_errbd) for the other
290 * parameters.
291 */
292template<class Real, class Scalar, int M, int N>
293void svd
294(const Eigen::Matrix<Scalar, M, N>& m,
295 Eigen::Array<Real, MIN_(M, N), 1>& s,
296 Eigen::Matrix<Scalar, M, M>& u,
297 Eigen::Matrix<Scalar, N, N>& vh,
298 Real& s_errbd,
299 Eigen::Array<Real, MIN_(M, N), 1>& u_errbd,
300 Eigen::Array<Real, MIN_(M, N), 1>& v_errbd)
301{
303}
304
305/**
306 * Returns singular values of M-by-N matrix m via s such that
307 * `(s >= 0).all()`. Elements of s are in descending order.
308 *
309 * @tparam Real type of real and imaginary parts of Scalar
310 * @tparam Scalar type of elements of m, u, and vh
311 * @tparam M number of rows in m
312 * @tparam N number of columns in m
313 * @param[in] m M-by-N matrix to be decomposed
314 * @param[out] s array of length min(M,N) to contain singular values
315 */
316template<class Real, class Scalar, int M, int N>
317void svd
318(const Eigen::Matrix<Scalar, M, N>& m,
319 Eigen::Array<Real, MIN_(M, N), 1>& s)
320{
322}
323
324/**
325 * Same as svd(m, s) except that an approximate error bound for the
326 * singular values is returned as well. The error bound is estimated
327 * following the method presented at
328 * http://www.netlib.org/lapack/lug/node96.html.
329 *
330 * @param[out] s_errbd approximate error bound for the elements of s
331 *
332 * See the documentation of svd(m, s) for the other parameters.
333 */
334template<class Real, class Scalar, int M, int N>
335void svd
336(const Eigen::Matrix<Scalar, M, N>& m,
337 Eigen::Array<Real, MIN_(M, N), 1>& s,
338 Real& s_errbd)
339{
341}
342
343// Eigen::SelfAdjointEigenSolver seems to be faster than ZHEEV of ATLAS
344
345template<class Real, class Scalar, int N>
347(const Eigen::Matrix<Scalar, N, N>& m,
348 Eigen::Array<Real, N, 1>& w,
349 Eigen::Matrix<Scalar, N, N> *z)
350{
352}
353
354template<class Real, class Scalar, int N>
356(const Eigen::Matrix<Scalar, N, N>& m,
357 Eigen::Array<Real, N, 1>& w,
358 Eigen::Matrix<Scalar, N, N> *z = 0,
359 Real *w_errbd = 0,
360 Eigen::Array<Real, N, 1> *z_errbd = 0)
361{
363
364 // see http://www.netlib.org/lapack/lug/node89.html
365 if (!w_errbd) { return; }
366 const Real EPSMCH = std::numeric_limits<Real>::epsilon();
367 Real mnorm = std::max(std::abs(w[0]), std::abs(w[N-1]));
368 *w_errbd = EPSMCH * mnorm;
369
370 if (!z_errbd) { return; }
371 Eigen::Array<Real, N, 1> RCONDZ;
372 int INFO;
373 disna<N, N>('E', w, RCONDZ, INFO);
374 z_errbd->fill(*w_errbd);
375 *z_errbd /= RCONDZ;
376}
377
378/**
379 * Diagonalizes N-by-N hermitian matrix m so that
380 *
381 * m == z * w.matrix().asDiagonal() * z.adjoint()
382 *
383 * Elements of w are in ascending order.
384 *
385 * @tparam Real type of real and imaginary parts of Scalar
386 * @tparam Scalar type of elements of m and z
387 * @tparam N number of rows and columns in m and z
388 * @param[in] m N-by-N matrix to be diagonalized
389 * @param[out] w array of length N to contain eigenvalues
390 * @param[out] z N-by-N unitary matrix
391 */
392template<class Real, class Scalar, int N>
394(const Eigen::Matrix<Scalar, N, N>& m,
395 Eigen::Array<Real, N, 1>& w,
396 Eigen::Matrix<Scalar, N, N>& z)
397{
399}
400
401/**
402 * Same as diagonalize_hermitian(m, w, z) except that an approximate
403 * error bound for the eigenvalues is returned as well. The error
404 * bound is estimated following the method presented at
405 * http://www.netlib.org/lapack/lug/node89.html.
406 *
407 * @param[out] w_errbd approximate error bound for the elements of w
408 *
409 * See the documentation of diagonalize_hermitian(m, w, z) for the
410 * other parameters.
411 */
412template<class Real, class Scalar, int N>
414(const Eigen::Matrix<Scalar, N, N>& m,
415 Eigen::Array<Real, N, 1>& w,
416 Eigen::Matrix<Scalar, N, N>& z,
417 Real& w_errbd)
418{
420}
421
422/**
423 * Same as diagonalize_hermitian(m, w, z, w_errbd) except that
424 * approximate error bounds for the eigenvectors are returned as well.
425 * The error bounds are estimated following the method presented at
426 * http://www.netlib.org/lapack/lug/node89.html.
427 *
428 * @param[out] z_errbd array of approximate error bounds for z
429 *
430 * See the documentation of diagonalize_hermitian(m, w, z, w_errbd)
431 * for the other parameters.
432 */
433template<class Real, class Scalar, int N>
435(const Eigen::Matrix<Scalar, N, N>& m,
436 Eigen::Array<Real, N, 1>& w,
437 Eigen::Matrix<Scalar, N, N>& z,
438 Real& w_errbd,
439 Eigen::Array<Real, N, 1>& z_errbd)
440{
442}
443
444/**
445 * Returns eigenvalues of N-by-N hermitian matrix m via w.
446 * Elements of w are in ascending order.
447 *
448 * @tparam Real type of real and imaginary parts of Scalar
449 * @tparam Scalar type of elements of m and z
450 * @tparam N number of rows and columns in m and z
451 * @param[in] m N-by-N matrix to be diagonalized
452 * @param[out] w array of length N to contain eigenvalues
453 */
454template<class Real, class Scalar, int N>
456(const Eigen::Matrix<Scalar, N, N>& m,
457 Eigen::Array<Real, N, 1>& w)
458{
460}
461
462/**
463 * Same as diagonalize_hermitian(m, w) except that an approximate
464 * error bound for the eigenvalues is returned as well. The error
465 * bound is estimated following the method presented at
466 * http://www.netlib.org/lapack/lug/node89.html.
467 *
468 * @param[out] w_errbd approximate error bound for the elements of w
469 *
470 * See the documentation of diagonalize_hermitian(m, w) for the other
471 * parameters.
472 */
473template<class Real, class Scalar, int N>
475(const Eigen::Matrix<Scalar, N, N>& m,
476 Eigen::Array<Real, N, 1>& w,
477 Real& w_errbd)
478{
480}
481
482template<class Real, int N>
484(const Eigen::Matrix<std::complex<Real>, N, N>& m,
485 Eigen::Array<Real, N, 1>& s,
486 Eigen::Matrix<std::complex<Real>, N, N> *u = 0,
487 Real *s_errbd = 0,
488 Eigen::Array<Real, N, 1> *u_errbd = 0)
489{
490 if (!u) {
492 return;
493 }
494 Eigen::Matrix<std::complex<Real>, N, N> vh;
496 // see Eq. (5) of https://doi.org/10.1016/j.amc.2014.01.170
497 Eigen::Matrix<std::complex<Real>, N, N> const Z = u->adjoint() * vh.transpose();
498 Eigen::Matrix<std::complex<Real>, N, N> Zsqrt = Z.sqrt().eval();
499 if (!Zsqrt.isUnitary()) {
500 // The formula assumes that sqrt of a unitary matrix is also unitary.
501 // This is not always true when using Eigen's build in sqrt function
502 // so we use a more generic matrixFunction in those cases.
503 // n-th derivative of sqrt(x)
504 const auto sqrtfn =
505 [](std::complex<Real> x, int n) {
506 static constexpr Real pi = 3.141592653589793238462643383279503L;
507 return std::sqrt(0.25*pi*x)/(std::tgamma(static_cast<Real>(1.5) - n)*std::pow(x, n));
508 };
509 Zsqrt = Z.matrixFunction(sqrtfn).eval();
510 if (!Zsqrt.isUnitary()) {
511 std::runtime_error("Zsqrt matrix must be unitary");
512 }
513 }
514 *u *= Zsqrt;
515}
516
517/**
518 * Diagonalizes N-by-N complex symmetric matrix m so that
519 *
520 * m == u * s.matrix().asDiagonal() * u.transpose()
521 *
522 * and `(s >= 0).all()`. Elements of s are in descending order.
523 *
524 * @tparam Real type of real and imaginary parts
525 * @tparam N number of rows and columns in m and u
526 * @param[in] m N-by-N complex symmetric matrix to be decomposed
527 * @param[out] s array of length N to contain singular values
528 * @param[out] u N-by-N complex unitary matrix
529 */
530template<class Real, int N>
532(const Eigen::Matrix<std::complex<Real>, N, N>& m,
533 Eigen::Array<Real, N, 1>& s,
534 Eigen::Matrix<std::complex<Real>, N, N>& u)
535{
537}
538
539/**
540 * Same as diagonalize_symmetric(m, s, u) except that an approximate
541 * error bound for the singular values is returned as well. The error
542 * bound is estimated following the method presented at
543 * http://www.netlib.org/lapack/lug/node96.html.
544 *
545 * @param[out] s_errbd approximate error bound for the elements of s
546 *
547 * See the documentation of diagonalize_symmetric(m, s, u) for the
548 * other parameters.
549 */
550template<class Real, int N>
552(const Eigen::Matrix<std::complex<Real>, N, N>& m,
553 Eigen::Array<Real, N, 1>& s,
554 Eigen::Matrix<std::complex<Real>, N, N>& u,
555 Real& s_errbd)
556{
558}
559
560/**
561 * Same as diagonalize_symmetric(m, s, u, s_errbd) except that
562 * approximate error bounds for the singular vectors are returned as
563 * well. The error bounds are estimated following the method
564 * presented at http://www.netlib.org/lapack/lug/node96.html.
565 *
566 * @param[out] u_errbd array of approximate error bounds for u
567 *
568 * See the documentation of diagonalize_symmetric(m, s, u, s_errbd)
569 * for the other parameters.
570 */
571template<class Real, int N>
573(const Eigen::Matrix<std::complex<Real>, N, N>& m,
574 Eigen::Array<Real, N, 1>& s,
575 Eigen::Matrix<std::complex<Real>, N, N>& u,
576 Real& s_errbd,
577 Eigen::Array<Real, N, 1>& u_errbd)
578{
580}
581
582/**
583 * Returns singular values of N-by-N complex symmetric matrix m via s
584 * such that `(s >= 0).all()`. Elements of s are in descending order.
585 *
586 * @tparam Real type of real and imaginary parts
587 * @tparam N number of rows and columns in m and u
588 * @param[in] m N-by-N complex symmetric matrix to be decomposed
589 * @param[out] s array of length N to contain singular values
590 */
591template<class Real, int N>
593(const Eigen::Matrix<std::complex<Real>, N, N>& m,
594 Eigen::Array<Real, N, 1>& s)
595{
597}
598
599/**
600 * Same as diagonalize_symmetric(m, s) except that an approximate
601 * error bound for the singular values is returned as well. The error
602 * bound is estimated following the method presented at
603 * http://www.netlib.org/lapack/lug/node96.html.
604 *
605 * @param[out] s_errbd approximate error bound for the elements of s
606 *
607 * See the documentation of diagonalize_symmetric(m, s) for the other
608 * parameters.
609 */
610template<class Real, int N>
612(const Eigen::Matrix<std::complex<Real>, N, N>& m,
613 Eigen::Array<Real, N, 1>& s,
614 Real& s_errbd)
615{
617}
618
619template<class Real>
620struct Flip_sign {
621 std::complex<Real> operator() (const std::complex<Real>& z) const {
622 return z.real() < 0 ? std::complex<Real>(0,1) :
623 std::complex<Real>(1,0);
624 }
625};
626
627template<class Real, int N>
629(const Eigen::Matrix<Real, N, N>& m,
630 Eigen::Array<Real, N, 1>& s,
631 Eigen::Matrix<std::complex<Real>, N, N> *u = 0,
632 Real *s_errbd = 0,
633 Eigen::Array<Real, N, 1> *u_errbd = 0)
634{
635 Eigen::Matrix<Real, N, N> z;
637 // see http://forum.kde.org/viewtopic.php?f=74&t=62606
638 if (u) {
639 *u = z * s.template cast<std::complex<Real>>()
641 .matrix()
642 .asDiagonal();
643 }
644 s = s.abs();
645}
646
647/**
648 * Diagonalizes N-by-N real symmetric matrix m so that
649 *
650 * m == u * s.matrix().asDiagonal() * u.transpose()
651 *
652 * and `(s >= 0).all()`. Order of elements of s is *unspecified*.
653 *
654 * @tparam Real type of real and imaginary parts
655 * @tparam N number of rows and columns of m
656 * @param[in] m N-by-N real symmetric matrix to be decomposed
657 * @param[out] s array of length N to contain singular values
658 * @param[out] u N-by-N complex unitary matrix
659 *
660 * @note Use diagonalize_hermitian() unless sign of `s[i]` matters.
661 */
662template<class Real, int N>
664(const Eigen::Matrix<Real, N, N>& m,
665 Eigen::Array<Real, N, 1>& s,
666 Eigen::Matrix<std::complex<Real>, N, N>& u)
667{
669}
670
671/**
672 * Same as diagonalize_symmetric(m, s, u) except that an approximate
673 * error bound for the singular values is returned as well. The error
674 * bound is estimated following the method presented at
675 * http://www.netlib.org/lapack/lug/node89.html.
676 *
677 * @param[out] s_errbd approximate error bound for the elements of s
678 *
679 * See the documentation of diagonalize_symmetric(m, s, u) for the
680 * other parameters.
681 */
682template<class Real, int N>
684(const Eigen::Matrix<Real, N, N>& m,
685 Eigen::Array<Real, N, 1>& s,
686 Eigen::Matrix<std::complex<Real>, N, N>& u,
687 Real& s_errbd)
688{
690}
691
692/**
693 * Same as diagonalize_symmetric(m, s, u, s_errbd) except that
694 * approximate error bounds for the singular vectors are returned as
695 * well. The error bounds are estimated following the method
696 * presented at http://www.netlib.org/lapack/lug/node89.html.
697 *
698 * @param[out] u_errbd array of approximate error bounds for u
699 *
700 * See the documentation of diagonalize_symmetric(m, s, u, s_errbd)
701 * for the other parameters.
702 */
703template<class Real, int N>
705(const Eigen::Matrix<Real, N, N>& m,
706 Eigen::Array<Real, N, 1>& s,
707 Eigen::Matrix<std::complex<Real>, N, N>& u,
708 Real& s_errbd,
709 Eigen::Array<Real, N, 1>& u_errbd)
710{
712}
713
714/**
715 * Returns singular values of N-by-N real symmetric matrix m via s
716 * such that `(s >= 0).all()`. Order of elements of s is
717 * *unspecified*.
718 *
719 * @tparam Real type of elements of m and s
720 * @tparam N number of rows and columns of m
721 * @param[in] m N-by-N real symmetric matrix to be decomposed
722 * @param[out] s array of length N to contain singular values
723 *
724 * @note Use diagonalize_hermitian() unless sign of `s[i]` matters.
725 */
726template<class Real, int N>
728(const Eigen::Matrix<Real, N, N>& m,
729 Eigen::Array<Real, N, 1>& s)
730{
732}
733
734/**
735 * Same as diagonalize_symmetric(m, s) except that an approximate
736 * error bound for the singular values is returned as well. The error
737 * bound is estimated following the method presented at
738 * http://www.netlib.org/lapack/lug/node89.html.
739 *
740 * @param[out] s_errbd approximate error bound for the elements of s
741 *
742 * See the documentation of diagonalize_symmetric(m, s) for the other
743 * parameters.
744 */
745template<class Real, int N>
747(const Eigen::Matrix<Real, N, N>& m,
748 Eigen::Array<Real, N, 1>& s,
749 Real& s_errbd)
750{
752}
753
754template<class Real, class Scalar, int M, int N>
756(const Eigen::Matrix<Scalar, M, N>& m,
757 Eigen::Array<Real, MIN_(M, N), 1>& s,
758 Eigen::Matrix<Scalar, M, M> *u = 0,
759 Eigen::Matrix<Scalar, N, N> *vh = 0,
760 Real *s_errbd = 0,
761 Eigen::Array<Real, MIN_(M, N), 1> *u_errbd = 0,
762 Eigen::Array<Real, MIN_(M, N), 1> *v_errbd = 0)
763{
765 s.reverseInPlace();
766 if (u) {
767 Eigen::PermutationMatrix<M> p;
768 p.setIdentity();
769 p.indices().template segment<MIN_(M, N)>(0).reverseInPlace();
770 *u *= p;
771 }
772 if (vh) {
773 Eigen::PermutationMatrix<N> p;
774 p.setIdentity();
775 p.indices().template segment<MIN_(M, N)>(0).reverseInPlace();
776 vh->transpose() *= p;
777 }
778 if (u_errbd) { u_errbd->reverseInPlace(); }
779 if (v_errbd) { v_errbd->reverseInPlace(); }
780}
781
782/**
783 * Singular value decomposition of M-by-N matrix m such that
784 *
785 * sigma.setZero(); sigma.diagonal() = s;
786 * m == u * sigma * vh // LAPACK convention
787 *
788 * and `(s >= 0).all()`. Elements of s are in ascending order. The
789 * above decomposition can be put in the form
790 *
791 * m == u * s.matrix().asDiagonal() * vh
792 *
793 * if `M == N`.
794 *
795 * @tparam Real type of real and imaginary parts of Scalar
796 * @tparam Scalar type of elements of m, u, and vh
797 * @tparam M number of rows in m
798 * @tparam N number of columns in m
799 * @param[in] m M-by-N matrix to be decomposed
800 * @param[out] s array of length min(M,N) to contain singular values
801 * @param[out] u M-by-M unitary matrix
802 * @param[out] vh N-by-N unitary matrix
803 */
804template<class Real, class Scalar, int M, int N>
806(const Eigen::Matrix<Scalar, M, N>& m,
807 Eigen::Array<Real, MIN_(M, N), 1>& s,
808 Eigen::Matrix<Scalar, M, M>& u,
809 Eigen::Matrix<Scalar, N, N>& vh)
810{
812}
813
814/**
815 * Same as reorder_svd(m, s, u, vh) except that an approximate error
816 * bound for the singular values is returned as well. The error bound
817 * is estimated following the method presented at
818 * http://www.netlib.org/lapack/lug/node96.html.
819 *
820 * @param[out] s_errbd approximate error bound for the elements of s
821 *
822 * See the documentation of reorder_svd(m, s, u, vh) for the other
823 * parameters.
824 */
825template<class Real, class Scalar, int M, int N>
827(const Eigen::Matrix<Scalar, M, N>& m,
828 Eigen::Array<Real, MIN_(M, N), 1>& s,
829 Eigen::Matrix<Scalar, M, M>& u,
830 Eigen::Matrix<Scalar, N, N>& vh,
831 Real& s_errbd)
832{
834}
835
836/**
837 * Same as reorder_svd(m, s, u, vh, s_errbd) except that approximate
838 * error bounds for the singular vectors are returned as well. The
839 * error bounds are estimated following the method presented at
840 * http://www.netlib.org/lapack/lug/node96.html.
841 *
842 * @param[out] u_errbd array of approximate error bounds for u
843 * @param[out] v_errbd array of approximate error bounds for vh
844 *
845 * See the documentation of reorder_svd(m, s, u, vh, s_errbd) for the
846 * other parameters.
847 */
848template<class Real, class Scalar, int M, int N>
850(const Eigen::Matrix<Scalar, M, N>& m,
851 Eigen::Array<Real, MIN_(M, N), 1>& s,
852 Eigen::Matrix<Scalar, M, M>& u,
853 Eigen::Matrix<Scalar, N, N>& vh,
854 Real& s_errbd,
855 Eigen::Array<Real, MIN_(M, N), 1>& u_errbd,
856 Eigen::Array<Real, MIN_(M, N), 1>& v_errbd)
857{
859}
860
861/**
862 * Returns singular values of M-by-N matrix m via s such that
863 * `(s >= 0).all()`. Elements of s are in ascending order.
864 *
865 * @tparam Real type of real and imaginary parts of Scalar
866 * @tparam Scalar type of elements of m, u, and vh
867 * @tparam M number of rows in m
868 * @tparam N number of columns in m
869 * @param[in] m M-by-N matrix to be decomposed
870 * @param[out] s array of length min(M,N) to contain singular values
871 */
872template<class Real, class Scalar, int M, int N>
874(const Eigen::Matrix<Scalar, M, N>& m,
875 Eigen::Array<Real, MIN_(M, N), 1>& s)
876{
878}
879
880/**
881 * Same as reorder_svd(m, s) except that an approximate error bound
882 * for the singular values is returned as well. The error bound is
883 * estimated following the method presented at
884 * http://www.netlib.org/lapack/lug/node96.html.
885 *
886 * @param[out] s_errbd approximate error bound for the elements of s
887 *
888 * See the documentation of reorder_svd(m, s) for the other
889 * parameters.
890 */
891template<class Real, class Scalar, int M, int N>
893(const Eigen::Matrix<Scalar, M, N>& m,
894 Eigen::Array<Real, MIN_(M, N), 1>& s,
895 Real& s_errbd)
896{
898}
899
900template<class Real, int N>
902(const Eigen::Matrix<std::complex<Real>, N, N>& m,
903 Eigen::Array<Real, N, 1>& s,
904 Eigen::Matrix<std::complex<Real>, N, N> *u = 0,
905 Real *s_errbd = 0,
906 Eigen::Array<Real, N, 1> *u_errbd = 0)
907{
909 s.reverseInPlace();
910 if (u) { *u = u->rowwise().reverse().eval(); }
911 if (u_errbd) { u_errbd->reverseInPlace(); }
912}
913
914template<class Real, int N>
916(const Eigen::Matrix<Real, N, N>& m,
917 Eigen::Array<Real, N, 1>& s,
918 Eigen::Matrix<std::complex<Real>, N, N> *u = 0,
919 Real *s_errbd = 0,
920 Eigen::Array<Real, N, 1> *u_errbd = 0)
921{
923 Eigen::PermutationMatrix<N> p;
924 p.setIdentity();
925 std::sort(p.indices().data(), p.indices().data() + p.indices().size(),
926 [&s] (int i, int j) { return s[i] < s[j]; });
927#if EIGEN_VERSION_AT_LEAST(3,1,4)
928 s.matrix().transpose() *= p;
929 if (u_errbd) { u_errbd->matrix().transpose() *= p; }
930#else
931 Eigen::Map<Eigen::Matrix<Real, N, 1> >(s.data()).transpose() *= p;
932 if (u_errbd) {
933 Eigen::Map<Eigen::Matrix<Real, N, 1>>(u_errbd->data()).transpose() *= p;
934 }
935#endif
936 if (u) { *u *= p; }
937}
938
939/**
940 * Diagonalizes N-by-N symmetric matrix m so that
941 *
942 * m == u * s.matrix().asDiagonal() * u.transpose()
943 *
944 * and `(s >= 0).all()`. Elements of s are in ascending order.
945 *
946 * @tparam Real type of real and imaginary parts of Scalar
947 * @tparam Scalar type of elements of m
948 * @tparam N number of rows and columns in m and u
949 * @param[in] m N-by-N symmetric matrix to be decomposed
950 * @param[out] s array of length N to contain singular values
951 * @param[out] u N-by-N complex unitary matrix
952 */
953template<class Real, class Scalar, int N>
955(const Eigen::Matrix<Scalar, N, N>& m,
956 Eigen::Array<Real, N, 1>& s,
957 Eigen::Matrix<std::complex<Real>, N, N>& u)
958{
960}
961
962/**
963 * Same as reorder_diagonalize_symmetric(m, s, u) except that an
964 * approximate error bound for the singular values is returned as
965 * well. The error bound is estimated following the method presented
966 * at http://www.netlib.org/lapack/lug/node96.html.
967 *
968 * @param[out] s_errbd approximate error bound for the elements of s
969 *
970 * See the documentation of reorder_diagonalize_symmetric(m, s, u) for
971 * the other parameters.
972 */
973template<class Real, class Scalar, int N>
975(const Eigen::Matrix<Scalar, N, N>& m,
976 Eigen::Array<Real, N, 1>& s,
977 Eigen::Matrix<std::complex<Real>, N, N>& u,
978 Real& s_errbd)
979{
981}
982
983/**
984 * Same as reorder_diagonalize_symmetric(m, s, u, s_errbd) except that
985 * approximate error bounds for the singular vectors are returned as
986 * well. The error bounds are estimated following the method
987 * presented at http://www.netlib.org/lapack/lug/node96.html.
988 *
989 * @param[out] u_errbd array of approximate error bounds for u
990 *
991 * See the documentation of reorder_diagonalize_symmetric(m, s, u,
992 * s_errbd) for the other parameters.
993 */
994template<class Real, class Scalar, int N>
996(const Eigen::Matrix<Scalar, N, N>& m,
997 Eigen::Array<Real, N, 1>& s,
998 Eigen::Matrix<std::complex<Real>, N, N>& u,
999 Real& s_errbd,
1000 Eigen::Array<Real, N, 1>& u_errbd)
1001{
1003}
1004
1005/**
1006 * Returns singular values of N-by-N symmetric matrix m via s such
1007 * that `(s >= 0).all()`. Elements of s are in ascending order.
1008 *
1009 * @tparam Real type of real and imaginary parts of Scalar
1010 * @tparam Scalar type of elements of m
1011 * @tparam N number of rows and columns in m and u
1012 * @param[in] m N-by-N symmetric matrix to be decomposed
1013 * @param[out] s array of length N to contain singular values
1014 */
1015template<class Real, class Scalar, int N>
1017(const Eigen::Matrix<Scalar, N, N>& m,
1018 Eigen::Array<Real, N, 1>& s)
1019{
1021}
1022
1023/**
1024 * Same as reorder_diagonalize_symmetric(m, s) except that an
1025 * approximate error bound for the singular values is returned as
1026 * well. The error bound is estimated following the method presented
1027 * at http://www.netlib.org/lapack/lug/node96.html.
1028 *
1029 * @param[out] s_errbd approximate error bound for the elements of s
1030 *
1031 * See the documentation of reorder_diagonalize_symmetric(m, s) for
1032 * the other parameters.
1033 */
1034template<class Real, class Scalar, int N>
1036(const Eigen::Matrix<Scalar, N, N>& m,
1037 Eigen::Array<Real, N, 1>& s,
1038 Real& s_errbd)
1039{
1041}
1042
1043template<class Real, class Scalar, int M, int N>
1045(const Eigen::Matrix<Scalar, M, N>& m,
1046 Eigen::Array<Real, MIN_(M, N), 1>& s,
1047 Eigen::Matrix<Scalar, M, M> *u = 0,
1048 Eigen::Matrix<Scalar, N, N> *v = 0,
1049 Real *s_errbd = 0,
1050 Eigen::Array<Real, MIN_(M, N), 1> *u_errbd = 0,
1051 Eigen::Array<Real, MIN_(M, N), 1> *v_errbd = 0)
1052{
1054 if (u) { u->transposeInPlace(); }
1055}
1056
1057/**
1058 * Singular value decomposition of M-by-N matrix m such that
1059 *
1060 * sigma.setZero(); sigma.diagonal() = s;
1061 * m == u.transpose() * sigma * v
1062 * // convention of Haber and Kane, Phys. Rept. 117 (1985) 75-263
1063 *
1064 * and `(s >= 0).all()`. Elements of s are in ascending order. The
1065 * above decomposition can be put in the form
1066 *
1067 * m == u.transpose() * s.matrix().asDiagonal() * v
1068 *
1069 * if `M == N`.
1070 *
1071 * @tparam Real type of real and imaginary parts of Scalar
1072 * @tparam Scalar type of elements of m, u, and v
1073 * @tparam M number of rows in m
1074 * @tparam N number of columns in m
1075 * @param[in] m M-by-N matrix to be decomposed
1076 * @param[out] s array of length min(M,N) to contain singular values
1077 * @param[out] u M-by-M unitary matrix
1078 * @param[out] v N-by-N unitary matrix
1079 */
1080template<class Real, class Scalar, int M, int N>
1082(const Eigen::Matrix<Scalar, M, N>& m,
1083 Eigen::Array<Real, MIN_(M, N), 1>& s,
1084 Eigen::Matrix<Scalar, M, M>& u,
1085 Eigen::Matrix<Scalar, N, N>& v)
1086{
1088}
1089
1090/**
1091 * Same as fs_svd(m, s, u, v) except that an approximate error bound
1092 * for the singular values is returned as well. The error bound is
1093 * estimated following the method presented at
1094 * http://www.netlib.org/lapack/lug/node96.html.
1095 *
1096 * @param[out] s_errbd approximate error bound for the elements of s
1097 *
1098 * See the documentation of fs_svd(m, s, u, v) for the other
1099 * parameters.
1100 */
1101template<class Real, class Scalar, int M, int N>
1103(const Eigen::Matrix<Scalar, M, N>& m,
1104 Eigen::Array<Real, MIN_(M, N), 1>& s,
1105 Eigen::Matrix<Scalar, M, M>& u,
1106 Eigen::Matrix<Scalar, N, N>& v,
1107 Real& s_errbd)
1108{
1110}
1111
1112/**
1113 * Same as fs_svd(m, s, u, v, s_errbd) except that approximate error
1114 * bounds for the singular vectors are returned as well. The error
1115 * bounds are estimated following the method presented at
1116 * http://www.netlib.org/lapack/lug/node96.html.
1117 *
1118 * @param[out] u_errbd array of approximate error bounds for u
1119 * @param[out] v_errbd array of approximate error bounds for vh
1120 *
1121 * See the documentation of fs_svd(m, s, u, v, s_errbd) for the other
1122 * parameters.
1123 */
1124template<class Real, class Scalar, int M, int N>
1126(const Eigen::Matrix<Scalar, M, N>& m,
1127 Eigen::Array<Real, MIN_(M, N), 1>& s,
1128 Eigen::Matrix<Scalar, M, M>& u,
1129 Eigen::Matrix<Scalar, N, N>& v,
1130 Real& s_errbd,
1131 Eigen::Array<Real, MIN_(M, N), 1>& u_errbd,
1132 Eigen::Array<Real, MIN_(M, N), 1>& v_errbd)
1133{
1135}
1136
1137/**
1138 * Returns singular values of M-by-N matrix m via s such that
1139 * `(s >= 0).all()`. Elements of s are in ascending order.
1140 *
1141 * @tparam Real type of real and imaginary parts of Scalar
1142 * @tparam Scalar type of elements of m, u, and v
1143 * @tparam M number of rows in m
1144 * @tparam N number of columns in m
1145 * @param[in] m M-by-N matrix to be decomposed
1146 * @param[out] s array of length min(M,N) to contain singular values
1147 */
1148template<class Real, class Scalar, int M, int N>
1150(const Eigen::Matrix<Scalar, M, N>& m,
1151 Eigen::Array<Real, MIN_(M, N), 1>& s)
1152{
1154}
1155
1156/**
1157 * Same as fs_svd(m, s) except that an approximate error bound for the
1158 * singular values is returned as well. The error bound is estimated
1159 * following the method presented at
1160 * http://www.netlib.org/lapack/lug/node96.html.
1161 *
1162 * @param[out] s_errbd approximate error bound for the elements of s
1163 *
1164 * See the documentation of fs_svd(m, s) for the other parameters.
1165 */
1166template<class Real, class Scalar, int M, int N>
1168(const Eigen::Matrix<Scalar, M, N>& m,
1169 Eigen::Array<Real, MIN_(M, N), 1>& s,
1170 Real& s_errbd)
1171{
1173}
1174
1175/**
1176 * Singular value decomposition of M-by-N *real* matrix m such that
1177 *
1178 * sigma.setZero(); sigma.diagonal() = s;
1179 * m == u.transpose() * sigma * v
1180 * // convention of Haber and Kane, Phys. Rept. 117 (1985) 75-263
1181 *
1182 * and `(s >= 0).all()`. Elements of s are in ascending order. The
1183 * above decomposition can be put in the form
1184 *
1185 * m == u.transpose() * s.matrix().asDiagonal() * v
1186 *
1187 * if `M == N`.
1188 *
1189 * @tparam Real type of real and imaginary parts
1190 * @tparam M number of rows in m
1191 * @tparam N number of columns in m
1192 * @param[in] m M-by-N *real* matrix to be decomposed
1193 * @param[out] s array of length min(M,N) to contain singular values
1194 * @param[out] u M-by-M *complex* unitary matrix
1195 * @param[out] v N-by-N *complex* unitary matrix
1196 *
1197 * @note This is a convenience overload for the case where the type of
1198 * u and v (complex) differs from that of m (real). Mathematically,
1199 * real u and v are enough to accommodate SVD of any real m.
1200 */
1201template<class Real, int M, int N>
1203(const Eigen::Matrix<Real, M, N>& m,
1204 Eigen::Array<Real, MIN_(M, N), 1>& s,
1205 Eigen::Matrix<std::complex<Real>, M, M>& u,
1206 Eigen::Matrix<std::complex<Real>, N, N>& v)
1207{
1209}
1210
1211/**
1212 * Same as fs_svd(m, s, u, v) except that an approximate error bound
1213 * for the singular values is returned as well. The error bound is
1214 * estimated following the method presented at
1215 * http://www.netlib.org/lapack/lug/node96.html.
1216 *
1217 * @param[out] s_errbd approximate error bound for the elements of s
1218 *
1219 * See the documentation of fs_svd(m, s, u, v) for the other
1220 * parameters.
1221 */
1222template<class Real, int M, int N>
1224(const Eigen::Matrix<Real, M, N>& m,
1225 Eigen::Array<Real, MIN_(M, N), 1>& s,
1226 Eigen::Matrix<std::complex<Real>, M, M>& u,
1227 Eigen::Matrix<std::complex<Real>, N, N>& v,
1228 Real& s_errbd)
1229{
1231}
1232
1233/**
1234 * Same as fs_svd(m, s, u, v, s_errbd) except that approximate error
1235 * bounds for the singular vectors are returned as well. The error
1236 * bounds are estimated following the method presented at
1237 * http://www.netlib.org/lapack/lug/node96.html.
1238 *
1239 * @param[out] u_errbd array of approximate error bounds for u
1240 * @param[out] v_errbd array of approximate error bounds for vh
1241 *
1242 * See the documentation of fs_svd(m, s, u, v, s_errbd) for the other
1243 * parameters.
1244 */
1245template<class Real, int M, int N>
1247(const Eigen::Matrix<Real, M, N>& m,
1248 Eigen::Array<Real, MIN_(M, N), 1>& s,
1249 Eigen::Matrix<std::complex<Real>, M, M>& u,
1250 Eigen::Matrix<std::complex<Real>, N, N>& v,
1251 Real& s_errbd,
1252 Eigen::Array<Real, MIN_(M, N), 1>& u_errbd,
1253 Eigen::Array<Real, MIN_(M, N), 1>& v_errbd)
1254{
1256 m.template cast<std::complex<Real>>().eval(), s, u, v, s_errbd, u_errbd,
1257 v_errbd);
1258}
1259
1260template<class Real, class Scalar, int N>
1262(const Eigen::Matrix<Scalar, N, N>& m,
1263 Eigen::Array<Real, N, 1>& s,
1264 Eigen::Matrix<std::complex<Real>, N, N> *u = 0,
1265 Real *s_errbd = 0,
1266 Eigen::Array<Real, N, 1> *u_errbd = 0)
1267{
1269 if (u) { u->transposeInPlace(); }
1270}
1271
1272/**
1273 * Diagonalizes N-by-N symmetric matrix m so that
1274 *
1275 * m == u.transpose() * s.matrix().asDiagonal() * u
1276 * // convention of Haber and Kane, Phys. Rept. 117 (1985) 75-263
1277 *
1278 * and `(s >= 0).all()`. Elements of s are in ascending order.
1279 *
1280 * @tparam Real type of real and imaginary parts of Scalar
1281 * @tparam Scalar type of elements of m
1282 * @tparam N number of rows and columns in m and u
1283 * @param[in] m N-by-N symmetric matrix to be decomposed
1284 * @param[out] s array of length N to contain singular values
1285 * @param[out] u N-by-N complex unitary matrix
1286 */
1287template<class Real, class Scalar, int N>
1289(const Eigen::Matrix<Scalar, N, N>& m,
1290 Eigen::Array<Real, N, 1>& s,
1291 Eigen::Matrix<std::complex<Real>, N, N>& u)
1292{
1294}
1295
1296/**
1297 * Same as fs_diagonalize_symmetric(m, s, u) except that an
1298 * approximate error bound for the singular values is returned as
1299 * well. The error bound is estimated following the method presented
1300 * at http://www.netlib.org/lapack/lug/node96.html.
1301 *
1302 * @param[out] s_errbd approximate error bound for the elements of s
1303 *
1304 * See the documentation of fs_diagonalize_symmetric(m, s, u) for the
1305 * other parameters.
1306 */
1307template<class Real, class Scalar, int N>
1309(const Eigen::Matrix<Scalar, N, N>& m,
1310 Eigen::Array<Real, N, 1>& s,
1311 Eigen::Matrix<std::complex<Real>, N, N>& u,
1312 Real& s_errbd)
1313{
1315}
1316
1317/**
1318 * Same as fs_diagonalize_symmetric(m, s, u, s_errbd) except that
1319 * approximate error bounds for the singular vectors are returned as
1320 * well. The error bounds are estimated following the method
1321 * presented at http://www.netlib.org/lapack/lug/node96.html.
1322 *
1323 * @param[out] u_errbd array of approximate error bounds for u
1324 *
1325 * See the documentation of fs_diagonalize_symmetric(m, s, u, s_errbd)
1326 * for the other parameters.
1327 */
1328template<class Real, class Scalar, int N>
1330(const Eigen::Matrix<Scalar, N, N>& m,
1331 Eigen::Array<Real, N, 1>& s,
1332 Eigen::Matrix<std::complex<Real>, N, N>& u,
1333 Real& s_errbd,
1334 Eigen::Array<Real, N, 1>& u_errbd)
1335{
1337}
1338
1339/**
1340 * Returns singular values of N-by-N symmetric matrix m via s such
1341 * that `(s >= 0).all()`. Elements of s are in ascending order.
1342 *
1343 * @tparam Real type of real and imaginary parts of Scalar
1344 * @tparam Scalar type of elements of m
1345 * @tparam N number of rows and columns in m and u
1346 * @param[in] m N-by-N symmetric matrix to be decomposed
1347 * @param[out] s array of length N to contain singular values
1348 */
1349template<class Real, class Scalar, int N>
1351(const Eigen::Matrix<Scalar, N, N>& m,
1352 Eigen::Array<Real, N, 1>& s)
1353{
1355}
1356
1357/**
1358 * Same as fs_diagonalize_symmetric(m, s) except that an approximate
1359 * error bound for the singular values is returned as well. The error
1360 * bound is estimated following the method presented at
1361 * http://www.netlib.org/lapack/lug/node96.html.
1362 *
1363 * @param[out] s_errbd approximate error bound for the elements of s
1364 *
1365 * See the documentation of fs_diagonalize_symmetric(m, s) for the
1366 * other parameters.
1367 */
1368template<class Real, class Scalar, int N>
1370(const Eigen::Matrix<Scalar, N, N>& m,
1371 Eigen::Array<Real, N, 1>& s,
1372 Real& s_errbd)
1373{
1375}
1376
1377template<class Real, class Scalar, int N>
1379(const Eigen::Matrix<Scalar, N, N>& m,
1380 Eigen::Array<Real, N, 1>& w,
1381 Eigen::Matrix<Scalar, N, N> *z = 0,
1382 Real *w_errbd = 0,
1383 Eigen::Array<Real, N, 1> *z_errbd = 0)
1384{
1386 Eigen::PermutationMatrix<N> p;
1387 p.setIdentity();
1388 std::sort(p.indices().data(), p.indices().data() + p.indices().size(),
1389 [&w] (int i, int j) { return std::abs(w[i]) < std::abs(w[j]); });
1390#if EIGEN_VERSION_AT_LEAST(3,1,4)
1391 w.matrix().transpose() *= p;
1392 if (z_errbd) { z_errbd->matrix().transpose() *= p; }
1393#else
1394 Eigen::Map<Eigen::Matrix<Real, N, 1> >(w.data()).transpose() *= p;
1395 if (z_errbd) {
1396 Eigen::Map<Eigen::Matrix<Real, N, 1>>(z_errbd->data()).transpose() *= p;
1397 }
1398#endif
1399 if (z) { *z = (*z * p).adjoint().eval(); }
1400}
1401
1402/**
1403 * Diagonalizes N-by-N hermitian matrix m so that
1404 *
1405 * m == z.adjoint() * w.matrix().asDiagonal() * z // convention of SARAH
1406 *
1407 * w is arranged so that `abs(w[i])` are in ascending order.
1408 *
1409 * @tparam Real type of real and imaginary parts of Scalar
1410 * @tparam Scalar type of elements of m and z
1411 * @tparam N number of rows and columns in m and z
1412 * @param[in] m N-by-N matrix to be diagonalized
1413 * @param[out] w array of length N to contain eigenvalues
1414 * @param[out] z N-by-N unitary matrix
1415 */
1416template<class Real, class Scalar, int N>
1418(const Eigen::Matrix<Scalar, N, N>& m,
1419 Eigen::Array<Real, N, 1>& w,
1420 Eigen::Matrix<Scalar, N, N>& z)
1421{
1423}
1424
1425/**
1426 * Same as fs_diagonalize_hermitian(m, w, z) except that an
1427 * approximate error bound for the eigenvalues is returned as well.
1428 * The error bound is estimated following the method presented at
1429 * http://www.netlib.org/lapack/lug/node89.html.
1430 *
1431 * @param[out] w_errbd approximate error bound for the elements of w
1432 *
1433 * See the documentation of fs_diagonalize_hermitian(m, w, z) for the
1434 * other parameters.
1435 */
1436template<class Real, class Scalar, int N>
1438(const Eigen::Matrix<Scalar, N, N>& m,
1439 Eigen::Array<Real, N, 1>& w,
1440 Eigen::Matrix<Scalar, N, N>& z,
1441 Real& w_errbd)
1442{
1444}
1445
1446/**
1447 * Same as fs_diagonalize_hermitian(m, w, z, w_errbd) except that
1448 * approximate error bounds for the eigenvectors are returned as well.
1449 * The error bounds are estimated following the method presented at
1450 * http://www.netlib.org/lapack/lug/node89.html.
1451 *
1452 * @param[out] z_errbd array of approximate error bounds for z
1453 *
1454 * See the documentation of fs_diagonalize_hermitian(m, w, z, w_errbd)
1455 * for the other parameters.
1456 */
1457template<class Real, class Scalar, int N>
1459(const Eigen::Matrix<Scalar, N, N>& m,
1460 Eigen::Array<Real, N, 1>& w,
1461 Eigen::Matrix<Scalar, N, N>& z,
1462 Real& w_errbd,
1463 Eigen::Array<Real, N, 1>& z_errbd)
1464{
1466}
1467
1468/**
1469 * Returns eigenvalues of N-by-N hermitian matrix m via w.
1470 * w is arranged so that `abs(w[i])` are in ascending order.
1471 *
1472 * @tparam Real type of real and imaginary parts of Scalar
1473 * @tparam Scalar type of elements of m and z
1474 * @tparam N number of rows and columns in m and z
1475 * @param[in] m N-by-N matrix to be diagonalized
1476 * @param[out] w array of length N to contain eigenvalues
1477 */
1478template<class Real, class Scalar, int N>
1480(const Eigen::Matrix<Scalar, N, N>& m,
1481 Eigen::Array<Real, N, 1>& w)
1482{
1484}
1485
1486/**
1487 * Same as fs_diagonalize_hermitian(m, w) except that an approximate
1488 * error bound for the eigenvalues is returned as well. The error
1489 * bound is estimated following the method presented at
1490 * http://www.netlib.org/lapack/lug/node89.html.
1491 *
1492 * @param[out] w_errbd approximate error bound for the elements of w
1493 *
1494 * See the documentation of fs_diagonalize_hermitian(m, w) for the
1495 * other parameters.
1496 */
1497template<class Real, class Scalar, int N>
1499(const Eigen::Matrix<Scalar, N, N>& m,
1500 Eigen::Array<Real, N, 1>& w,
1501 Real& w_errbd)
1502{
1504}
1505
1506} // namespace gm2calc
1507
1508#endif // linalg2_hpp
#define MIN_(i, j)
double v
void reorder_svd_errbd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u=0, Eigen::Matrix< Scalar, N, N > *vh=0, Real *s_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *u_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *v_errbd=0)
void disna(const char &JOB, const Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &D, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &SEP, int &INFO)
Template version of DDISNA from LAPACK.
void diagonalize_hermitian(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > &z)
Diagonalizes N-by-N hermitian matrix m so that.
void svd_internal(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u, Eigen::Matrix< Scalar, N, N > *vh)
void svd_errbd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u=0, Eigen::Matrix< Scalar, N, N > *vh=0, Real *s_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *u_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *v_errbd=0)
void svd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > &u, Eigen::Matrix< Scalar, N, N > &vh)
Singular value decomposition of M-by-N matrix m such that.
void reorder_diagonalize_symmetric(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > &u)
Diagonalizes N-by-N symmetric matrix m so that.
void svd_eigen(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u, Eigen::Matrix< Scalar, N, N > *vh)
void reorder_diagonalize_symmetric_errbd(const Eigen::Matrix< std::complex< Real >, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > *u=0, Real *s_errbd=0, Eigen::Array< Real, N, 1 > *u_errbd=0)
void fs_diagonalize_symmetric(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > &u)
Diagonalizes N-by-N symmetric matrix m so that.
void diagonalize_hermitian_errbd(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > *z=0, Real *w_errbd=0, Eigen::Array< Real, N, 1 > *z_errbd=0)
void hermitian_eigen(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > *z)
void fs_diagonalize_symmetric_errbd(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > *u=0, Real *s_errbd=0, Eigen::Array< Real, N, 1 > *u_errbd=0)
void diagonalize_symmetric_errbd(const Eigen::Matrix< std::complex< Real >, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > *u=0, Real *s_errbd=0, Eigen::Array< Real, N, 1 > *u_errbd=0)
void fs_diagonalize_hermitian_errbd(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > *z=0, Real *w_errbd=0, Eigen::Array< Real, N, 1 > *z_errbd=0)
void reorder_svd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > &u, Eigen::Matrix< Scalar, N, N > &vh)
Singular value decomposition of M-by-N matrix m such that.
void fs_svd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > &u, Eigen::Matrix< Scalar, N, N > &v)
Singular value decomposition of M-by-N matrix m such that.
void diagonalize_hermitian_internal(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > *z)
void fs_svd_errbd(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u=0, Eigen::Matrix< Scalar, N, N > *v=0, Real *s_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *u_errbd=0, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > *v_errbd=0)
void diagonalize_symmetric(const Eigen::Matrix< std::complex< Real >, N, N > &m, Eigen::Array< Real, N, 1 > &s, Eigen::Matrix< std::complex< Real >, N, N > &u)
Diagonalizes N-by-N complex symmetric matrix m so that.
void fs_diagonalize_hermitian(const Eigen::Matrix< Scalar, N, N > &m, Eigen::Array< Real, N, 1 > &w, Eigen::Matrix< Scalar, N, N > &z)
Diagonalizes N-by-N hermitian matrix m so that.
std::complex< Real > operator()(const std::complex< Real > &z) const