CbmRoot
Loading...
Searching...
No Matches
KfUtils.cxx
Go to the documentation of this file.
1/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergey Gorbunov, Sergei Zharko [committer] */
4
5#include "KfUtils.h"
6
10{
12 template<typename DataT>
13 void PrintSIMDmsg(std::stringstream& msg, DataT& v)
14 {
15 if constexpr (std::is_same_v<DataT, float> or std::is_same_v<DataT, double>) {
16 msg << v;
17 }
18 else {
19 msg << "[";
20 for (size_t i = 0; i < DataT::size() - 1; i++)
21 msg << v[i] << ",";
22 msg << v[DataT::size() - 1] << "]";
23 }
24 }
25
28 template<>
29 void CheckSimdVectorEquality(fvec v, const char* name)
30 {
31 bool ok = true;
32 for (size_t i = 1; i < fvec::size(); i++) {
33 ok = ok && (v[i] == v[0]);
34 }
35 if (!ok) {
36 std::stringstream msg;
37 msg << name << " SIMD vector is inconsistent, not all of the words are equal each other: ";
38 PrintSIMDmsg(msg, v);
39 throw std::logic_error(msg.str());
40 }
41 }
42} // namespace cbm::algo::kf::utils
43
44// TODO: SZh 06.06.2024: Move to another source (e.g. KfMath.cxx)
46{
47
48 void CholeskyFactorization(const double a[], const int n, int nn, double u[], int* nullty, int* ifault)
49 {
50 // TODO: move to KfMath.h
51 //
52 // Purpose:
53 //
54 // CHOLESKY computes the Cholesky factorization of a PDS matrix.
55 //
56 // Discussion:
57 //
58 // For a positive definite symmetric matrix A, the Cholesky factor U
59 // is an upper triangular matrix such that A = U' * U.
60 //
61 // This routine was originally named "CHOL", but that conflicted with
62 // a built in MATLAB routine name.
63 //
64 // The missing initialization "II = 0" has been added to the code.
65 //
66 // Licensing:
67 //
68 // This code is distributed under the GNU LGPL license.
69 //
70 // Modified:
71 //
72 // 12 February 2008
73 //
74 // Author:
75 //
76 // Original FORTRAN77 version by Michael Healy.
77 // Modifications by AJ Miller.
78 // C++ version by John Burkardt.
79 //
80 // Reference:
81 //
82 // Michael Healy,
83 // Algorithm AS 6:
84 // Triangular decomposition of a symmetric matrix,
85 // Applied Statistics,
86 // Volume 17, Number 2, 1968, pages 195-197.
87 //
88 // Parameters:
89 //
90 // Input, double A((N*(N+1))/2), a positive definite matrix
91 // stored by rows in lower triangular form as a one dimensional array,
92 // in the sequence
93 // A(1,1),
94 // A(2,1), A(2,2),
95 // A(3,1), A(3,2), A(3,3), and so on.
96 //
97 // Input, int N, the order of A.
98 //
99 // Input, int NN, the dimension of the array used to store A,
100 // which should be at least (N*(N+1))/2.
101 //
102 // Output, double U((N*(N+1))/2), an upper triangular matrix,
103 // stored by columns, which is the Cholesky factor of A. The program is
104 // written in such a way that A and U can share storage.
105 //
106 // Output, int NULLTY, the rank deficiency of A. If NULLTY is zero,
107 // the matrix is judged to have full rank.
108 //
109 // Output, int IFAULT, an error indicator.
110 // 0, no error was detected;
111 // 1, if N < 1;
112 // 2, if A is not positive semi-definite.
113 // 3, if NN < (N*(N+1))/2.
114 //
115 // Local Parameters:
116 //
117 // Local, double ETA, should be set equal to the smallest positive
118 // value such that 1.0 + ETA is calculated as being greater than 1.0 in the
119 // accuracy being used.
120 //
121
122 double eta = 1.0E-09;
123 int i;
124 int icol;
125 int ii;
126 int irow;
127 int j;
128 int k;
129 int kk;
130 int l;
131 int m;
132 double w;
133 double x;
134
135 *ifault = 0;
136 *nullty = 0;
137
138 if (n <= 0) {
139 *ifault = 1;
140 return;
141 }
142
143 if (nn < (n * (n + 1)) / 2) {
144 *ifault = 3;
145 return;
146 }
147
148 j = 1;
149 k = 0;
150 ii = 0;
151 //
152 // Factorize column by column, ICOL = column number.
153 //
154 for (icol = 1; icol <= n; icol++) {
155 ii = ii + icol;
156 x = eta * eta * a[ii - 1];
157 l = 0;
158 kk = 0;
159 //
160 // IROW = row number within column ICOL.
161 //
162 for (irow = 1; irow <= icol; irow++) {
163 kk = kk + irow;
164 k = k + 1;
165 w = a[k - 1];
166 m = j;
167
168 for (i = 1; i < irow; i++) {
169 l = l + 1;
170 w = w - u[l - 1] * u[m - 1];
171 m = m + 1;
172 }
173
174 l = l + 1;
175
176 if (irow == icol) {
177 break;
178 }
179
180 if (u[l - 1] != 0.0) {
181 u[k - 1] = w / u[l - 1];
182 }
183 else {
184 u[k - 1] = 0.0;
185
186 if (fabs(x * a[k - 1]) < w * w) {
187 *ifault = 2;
188 return;
189 }
190 }
191 }
192 //
193 // End of row, estimate relative accuracy of diagonal element.
194 //
195 if (fabs(w) <= fabs(eta * a[k - 1])) {
196 u[k - 1] = 0.0;
197 *nullty = *nullty + 1;
198 }
199 else {
200 if (w < 0.0) {
201 *ifault = 2;
202 return;
203 }
204 u[k - 1] = sqrt(w);
205 }
206 j = j + icol;
207 }
208
209 } // CholeskyFactorization
210
211
212 void SymInv(const double a[], const int n, double c[], double w[], int* nullty, int* ifault)
213 {
214 // TODO: move to KfMath.h
215 //
216 // Purpose:
217 //
218 // SYMINV computes the inverse of a symmetric matrix.
219 //
220 // Licensing:
221 //
222 // This code is distributed under the GNU LGPL license.
223 //
224 // Modified:
225 //
226 // 11 February 2008
227 //
228 // Author:
229 //
230 // Original FORTRAN77 version by Michael Healy.
231 // C++ version by John Burkardt.
232 //
233 // Reference:
234 //
235 // Michael Healy,
236 // Algorithm AS 7:
237 // Inversion of a Positive Semi-Definite Symmetric Matrix,
238 // Applied Statistics,
239 // Volume 17, Number 2, 1968, pages 198-199.
240 //
241 // Parameters:
242 //
243 // Input, double A((N*(N+1))/2), a positive definite matrix stored
244 // by rows in lower triangular form as a one dimensional array, in the sequence
245 // A(1,1),
246 // A(2,1), A(2,2),
247 // A(3,1), A(3,2), A(3,3), and so on.
248 //
249 // Input, int N, the order of A.
250 //
251 // Output, double C((N*(N+1))/2), the inverse of A, or generalized
252 // inverse if A is singular, stored using the same storage scheme employed
253 // for A. The program is written in such a way that A and U can share storage.
254 //
255 // Workspace, double W(N).
256 //
257 // Output, int *NULLTY, the rank deficiency of A. If NULLTY is zero,
258 // the matrix is judged to have full rank.
259 //
260 // Output, int *IFAULT, error indicator.
261 // 0, no error detected.
262 // 1, N < 1.
263 // 2, A is not positive semi-definite.
264 //
265
266 int i;
267 int icol;
268 int irow;
269 int j;
270 int jcol;
271 int k;
272 int l;
273 int mdiag;
274 int ndiag;
275 int nn;
276 int nrow;
277 double x;
278
279 *ifault = 0;
280
281 if (n <= 0) {
282 *ifault = 1;
283 return;
284 }
285
286 nrow = n;
287 //
288 // Compute the Cholesky factorization of A.
289 // The result is stored in C.
290 //
291 nn = (n * (n + 1)) / 2;
292
293 CholeskyFactorization(a, n, nn, c, nullty, ifault);
294
295 if (*ifault != 0) {
296 return;
297 }
298 //
299 // Invert C and form the product (Cinv)' * Cinv, where Cinv is the inverse
300 // of C, row by row starting with the last row.
301 // IROW = the row number,
302 // NDIAG = location of last element in the row.
303 //
304 irow = nrow;
305 ndiag = nn;
306 //
307 // Special case, zero diagonal element.
308 //
309 for (;;) {
310 if (c[ndiag - 1] == 0.0) {
311 l = ndiag;
312 for (j = irow; j <= nrow; j++) {
313 c[l - 1] = 0.0;
314 l = l + j;
315 }
316 }
317 else {
318 l = ndiag;
319 for (i = irow; i <= nrow; i++) {
320 w[i - 1] = c[l - 1];
321 l = l + i;
322 }
323
324 icol = nrow;
325 jcol = nn;
326 mdiag = nn;
327
328 for (;;) {
329 l = jcol;
330
331 if (icol == irow) {
332 x = 1.0 / w[irow - 1];
333 }
334 else {
335 x = 0.0;
336 }
337
338 k = nrow;
339
340 while (irow < k) {
341 x = x - w[k - 1] * c[l - 1];
342 k = k - 1;
343 l = l - 1;
344
345 if (mdiag < l) {
346 l = l - k + 1;
347 }
348 }
349
350 c[l - 1] = x / w[irow - 1];
351
352 if (icol <= irow) {
353 break;
354 }
355 mdiag = mdiag - icol;
356 icol = icol - 1;
357 jcol = jcol - 1;
358 }
359 }
360
361 ndiag = ndiag - irow;
362 irow = irow - 1;
363
364 if (irow <= 0) {
365 break;
366 }
367 }
368
369 } // SymInv
370
371} // namespace cbm::algo::kf::utils::math
friend fvec sqrt(const fvec &a)
fscal v[fmask::Size]
Definition KfSimdPseudo.h:4
void SymInv(const double a[], const int n, double c[], double w[], int *nullty, int *ifault)
Definition KfUtils.cxx:212
void CholeskyFactorization(const double a[], const int n, int nn, double u[], int *nullty, int *ifault)
Definition KfUtils.cxx:48
void PrintSIMDmsg(std::stringstream &msg, DataT &v)
Stingstream output operation for simd data.
Definition KfUtils.cxx:13
void CheckSimdVectorEquality(fvec v, const char *name)
Checks, if a SIMD vector horizontally equal TODO: Find this method in the VC!
Definition KfUtils.cxx:29
fvec fabs(const fvec &v)
Definition KfUtils.h:30