<T>LAPACK 0.1.1
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
svd22.hpp
Go to the documentation of this file.
1
5//
6// Copyright (c) 2021-2023, University of Colorado Denver. All rights reserved.
7//
8// This file is part of <T>LAPACK.
9// <T>LAPACK is free software: you can redistribute it and/or modify it under
10// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
11
12#ifndef TLAPACK_SVD22_HH
13#define TLAPACK_SVD22_HH
14
16
17namespace tlapack {
18
54template <typename T, enable_if_t<!is_complex<T>, bool> = true>
55void svd22(const T& f,
56 const T& g,
57 const T& h,
58 T& ssmin,
59 T& ssmax,
60 T& csl,
61 T& snl,
62 T& csr,
63 T& snr)
64{
65 const T eps = ulp<T>();
66 const T zero(0);
67 const T one(1);
68 const T two(2);
69 const T half(0.5);
70 const T four(4);
71
72 T ft = f;
73 T fa = abs(ft);
74 T ht = h;
75 T ha = abs(h);
76
77 // PMAX points to the maximum absolute element of matrix
78 // PMAX = 1 if F largest in absolute values
79 // PMAX = 2 if G largest in absolute values
80 // PMAX = 3 if H largest in absolute values
81 int pmax = 1;
82
83 bool swap = (ha > fa);
84 if (swap) {
85 pmax = 3;
86 auto temp = ft;
87 ft = ht;
88 ht = temp;
89 temp = fa;
90 fa = ha;
91 ha = temp;
92 // Now FA > HA
93 }
94 T gt = g;
95 T ga = abs(gt);
96
97 T clt, crt, slt, srt;
98 if (ga == zero) {
99 // Diagonal matrix
100 ssmin = ha;
101 ssmax = fa;
102 clt = one;
103 crt = one;
104 slt = zero;
105 srt = zero;
106 }
107 else {
108 bool gasmal = true;
109 if (ga > fa) {
110 pmax = 2;
111 if ((fa / ga) < eps) {
112 // ga is very large
113 gasmal = false;
114 ssmax = ga;
115 if (ha > one) {
116 ssmin = fa / (ga / ha);
117 }
118 else {
119 ssmin = (fa / ga) * ha;
120 }
121 clt = one;
122 slt = ht / gt;
123 srt = one;
124 crt = ft / gt;
125 }
126 }
127 if (gasmal) {
128 // Normal case
129 T d, l;
130 d = fa - ha;
131 // Note that 0 < l < 1
132 if (d == fa) {
133 l = one;
134 }
135 else {
136 l = d / fa;
137 }
138 // Note that abs(m) < 1/eps
139 T m = gt / ft;
140 // Note that t >= 1
141 T t = two - l;
142 T mm = m * m;
143 T tt = t * t;
144 // Note that 1 <= s <= 1 + 1/eps
145 T s = sqrt(tt + mm);
146 // Note that 0 <= r <= 1 + 1/eps
147 T r;
148 if (l == zero) {
149 r = abs(m);
150 }
151 else {
152 r = sqrt(l * l + mm);
153 }
154 // Note that 1 <= a <= 1 + abs(m)
155 T a = half * (s + r);
156 ssmin = ha / a;
157 ssmax = fa * a;
158 if (mm == zero) {
159 // m is very tiny, so m*m has underflowed
160 if (l == zero) {
161 t = two * T(sgn(ft)) * T(sgn(gt));
162 }
163 else {
164 t = gt / (abs(d) * T(sgn(ft))) + m / t;
165 }
166 }
167 else {
168 t = (m / (s + t) + m / (r + l)) * (one + a);
169 }
170 l = sqrt(t * t + four);
171 crt = two / l;
172 srt = t / l;
173 clt = (crt + srt * m) / a;
174 slt = (ht / ft) * srt / a;
175 }
176 }
177 if (swap) {
178 csl = srt;
179 snl = crt;
180 csr = slt;
181 snr = clt;
182 }
183 else {
184 csl = clt;
185 snl = slt;
186 csr = crt;
187 snr = srt;
188 }
189 //
190 // Correct signs of SSMAX and SSMIN
191 //
192 T tsign;
193 if (pmax == 1)
194 tsign = T(sgn(csr)) * T(sgn(csl)) * T(sgn(f));
195 else if (pmax == 2)
196 tsign = T(sgn(snr)) * T(sgn(csl)) * T(sgn(g));
197 else
198 tsign = T(sgn(snr)) * T(sgn(snl)) * T(sgn(h));
199 ssmax = ssmax * T(sgn(tsign));
200 ssmin = ssmin * T(sgn(tsign * T(sgn(f)) * T(sgn(h))));
201}
202
203} // namespace tlapack
204
205#endif // TLAPACK_SVD22_HH
constexpr int sgn(const T &val)
Type-safe sgn function.
Definition utils.hpp:109
void svd22(const T &f, const T &g, const T &h, T &ssmin, T &ssmax, T &csl, T &snl, T &csr, T &snr)
Computes the singular value decomposition of a 2-by-2 real triangular matrix.
Definition svd22.hpp:55
void swap(vectorX_t &x, vectorY_t &y)
Swap vectors, .
Definition swap.hpp:31
typename traits::real_type_traits< Types..., int >::type real_type
The common real type of the list of types.
Definition scalar_type_traits.hpp:113