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