1 /* linalg/luc.c
2 *
3 * Copyright (C) 2001, 2007, 2009 Brian Gough
4 * Copyright (C) 2019 Patrick Alken
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gsl/gsl_math.h>
25 #include <gsl/gsl_vector.h>
26 #include <gsl/gsl_matrix.h>
27 #include <gsl/gsl_complex.h>
28 #include <gsl/gsl_complex_math.h>
29 #include <gsl/gsl_permute_vector.h>
30 #include <gsl/gsl_blas.h>
31 #include <gsl/gsl_complex_math.h>
32 #include <gsl/gsl_linalg.h>
33
34 #include "recurse.h"
35
36 static int LU_decomp_L2 (gsl_matrix_complex * A, gsl_vector_uint * ipiv);
37 static int LU_decomp_L3 (gsl_matrix_complex * A, gsl_vector_uint * ipiv);
38 static int singular (const gsl_matrix_complex * LU);
39 static int apply_pivots(gsl_matrix_complex * A, const gsl_vector_uint * ipiv);
40
41 /* Factorise a general N x N complex matrix A into,
42 *
43 * P A = L U
44 *
45 * where P is a permutation matrix, L is unit lower triangular and U
46 * is upper triangular.
47 *
48 * L is stored in the strict lower triangular part of the input
49 * matrix. The diagonal elements of L are unity and are not stored.
50 *
51 * U is stored in the diagonal and upper triangular part of the
52 * input matrix.
53 *
54 * P is stored in the permutation p. Column j of P is column k of the
55 * identity matrix, where k = permutation->data[j]
56 *
57 * signum gives the sign of the permutation, (-1)^n, where n is the
58 * number of interchanges in the permutation.
59 *
60 * See Golub & Van Loan, Matrix Computations, Algorithm 3.4.1 (Gauss
61 * Elimination with Partial Pivoting).
62 */
63
64 int
gsl_linalg_complex_LU_decomp(gsl_matrix_complex * A,gsl_permutation * p,int * signum)65 gsl_linalg_complex_LU_decomp (gsl_matrix_complex * A, gsl_permutation * p, int *signum)
66 {
67 const size_t M = A->size1;
68
69 if (p->size != M)
70 {
71 GSL_ERROR ("permutation length must match matrix size1", GSL_EBADLEN);
72 }
73 else
74 {
75 int status;
76 const size_t N = A->size2;
77 const size_t minMN = GSL_MIN(M, N);
78 gsl_vector_uint * ipiv = gsl_vector_uint_alloc(minMN);
79 gsl_matrix_complex_view AL = gsl_matrix_complex_submatrix(A, 0, 0, M, minMN);
80 size_t i;
81
82 status = LU_decomp_L3 (&AL.matrix, ipiv);
83
84 /* process remaining right matrix */
85 if (M < N)
86 {
87 gsl_matrix_complex_view AR = gsl_matrix_complex_submatrix(A, 0, M, M, N - M);
88
89 /* apply pivots to AR */
90 apply_pivots(&AR.matrix, ipiv);
91
92 /* AR = AL^{-1} AR */
93 gsl_blas_ztrsm(CblasLeft, CblasLower, CblasNoTrans, CblasUnit, GSL_COMPLEX_ONE, &AL.matrix, &AR.matrix);
94 }
95
96 /* convert ipiv array to permutation */
97
98 gsl_permutation_init(p);
99 *signum = 1;
100
101 for (i = 0; i < minMN; ++i)
102 {
103 unsigned int pivi = gsl_vector_uint_get(ipiv, i);
104
105 if (p->data[pivi] != p->data[i])
106 {
107 size_t tmp = p->data[pivi];
108 p->data[pivi] = p->data[i];
109 p->data[i] = tmp;
110 *signum = -(*signum);
111 }
112 }
113
114 gsl_vector_uint_free(ipiv);
115
116 return status;
117 }
118 }
119
120 /*
121 LU_decomp_L2
122 LU decomposition with partial pivoting using Level 2 BLAS
123
124 Inputs: A - on input, matrix to be factored; on output, L and U factors
125 ipiv - (output) array containing row swaps
126
127 Notes:
128 1) Based on LAPACK ZGETF2
129 */
130
131 static int
LU_decomp_L2(gsl_matrix_complex * A,gsl_vector_uint * ipiv)132 LU_decomp_L2 (gsl_matrix_complex * A, gsl_vector_uint * ipiv)
133 {
134 const size_t M = A->size1;
135 const size_t N = A->size2;
136 const size_t minMN = GSL_MIN(M, N);
137
138 if (ipiv->size != minMN)
139 {
140 GSL_ERROR ("ipiv length must equal MIN(M,N)", GSL_EBADLEN);
141 }
142 else
143 {
144 size_t i, j;
145
146 for (j = 0; j < minMN; ++j)
147 {
148 /* find maximum in the j-th column */
149 gsl_vector_complex_view v = gsl_matrix_complex_subcolumn(A, j, j, M - j);
150 size_t j_pivot = j + gsl_blas_izamax(&v.vector);
151 gsl_vector_complex_view v1, v2;
152
153 gsl_vector_uint_set(ipiv, j, j_pivot);
154
155 if (j_pivot != j)
156 {
157 /* swap rows j and j_pivot */
158 v1 = gsl_matrix_complex_row(A, j);
159 v2 = gsl_matrix_complex_row(A, j_pivot);
160 gsl_blas_zswap(&v1.vector, &v2.vector);
161 }
162
163 if (j < M - 1)
164 {
165 gsl_complex Ajj = gsl_matrix_complex_get(A, j, j);
166 gsl_complex Ajjinv = gsl_complex_inverse(Ajj);
167
168 if (gsl_complex_abs(Ajj) >= GSL_DBL_MIN)
169 {
170 v1 = gsl_matrix_complex_subcolumn(A, j, j + 1, M - j - 1);
171 gsl_blas_zscal(Ajjinv, &v1.vector);
172 }
173 else
174 {
175 for (i = 1; i < M - j; ++i)
176 {
177 gsl_complex * ptr = gsl_matrix_complex_ptr(A, j + i, j);
178 *ptr = gsl_complex_mul(*ptr, Ajjinv);
179 }
180 }
181 }
182
183 if (j < minMN - 1)
184 {
185 gsl_matrix_complex_view A22 = gsl_matrix_complex_submatrix(A, j + 1, j + 1, M - j - 1, N - j - 1);
186 v1 = gsl_matrix_complex_subcolumn(A, j, j + 1, M - j - 1);
187 v2 = gsl_matrix_complex_subrow(A, j, j + 1, N - j - 1);
188
189 gsl_blas_zgeru(GSL_COMPLEX_NEGONE, &v1.vector, &v2.vector, &A22.matrix);
190 }
191 }
192
193 return GSL_SUCCESS;
194 }
195 }
196
197 /*
198 LU_decomp_L3
199 LU decomposition with partial pivoting using Level 3 BLAS
200
201 Inputs: A - on input, matrix to be factored; on output, L and U factors
202 ipiv - (output) array containing row swaps
203
204 Notes:
205 1) Based on ReLAPACK DGETRF
206 */
207
208 static int
LU_decomp_L3(gsl_matrix_complex * A,gsl_vector_uint * ipiv)209 LU_decomp_L3 (gsl_matrix_complex * A, gsl_vector_uint * ipiv)
210 {
211 const size_t M = A->size1;
212 const size_t N = A->size2;
213
214 if (M < N)
215 {
216 GSL_ERROR ("matrix must have M >= N", GSL_EBADLEN);
217 }
218 else if (ipiv->size != GSL_MIN(M, N))
219 {
220 GSL_ERROR ("ipiv length must equal MIN(M,N)", GSL_EBADLEN);
221 }
222 else if (N <= CROSSOVER_LU)
223 {
224 /* use Level 2 algorithm */
225 return LU_decomp_L2(A, ipiv);
226 }
227 else
228 {
229 /*
230 * partition matrix:
231 *
232 * N1 N2
233 * N1 [ A11 A12 ]
234 * M2 [ A21 A22 ]
235 *
236 * and
237 * N1 N2
238 * M [ AL AR ]
239 */
240 int status;
241 const size_t N1 = GSL_LINALG_SPLIT_COMPLEX(N);
242 const size_t N2 = N - N1;
243 const size_t M2 = M - N1;
244 gsl_matrix_complex_view A11 = gsl_matrix_complex_submatrix(A, 0, 0, N1, N1);
245 gsl_matrix_complex_view A12 = gsl_matrix_complex_submatrix(A, 0, N1, N1, N2);
246 gsl_matrix_complex_view A21 = gsl_matrix_complex_submatrix(A, N1, 0, M2, N1);
247 gsl_matrix_complex_view A22 = gsl_matrix_complex_submatrix(A, N1, N1, M2, N2);
248
249 gsl_matrix_complex_view AL = gsl_matrix_complex_submatrix(A, 0, 0, M, N1);
250 gsl_matrix_complex_view AR = gsl_matrix_complex_submatrix(A, 0, N1, M, N2);
251
252 /*
253 * partition ipiv = [ ipiv1 ] N1
254 * [ ipiv2 ] N2
255 */
256 gsl_vector_uint_view ipiv1 = gsl_vector_uint_subvector(ipiv, 0, N1);
257 gsl_vector_uint_view ipiv2 = gsl_vector_uint_subvector(ipiv, N1, N2);
258
259 size_t i;
260
261 /* recursion on (AL, ipiv1) */
262 status = LU_decomp_L3(&AL.matrix, &ipiv1.vector);
263 if (status)
264 return status;
265
266 /* apply ipiv1 to AR */
267 apply_pivots(&AR.matrix, &ipiv1.vector);
268
269 /* A12 = A11^{-1} A12 */
270 gsl_blas_ztrsm(CblasLeft, CblasLower, CblasNoTrans, CblasUnit, GSL_COMPLEX_ONE, &A11.matrix, &A12.matrix);
271
272 /* A22 = A22 - A21 * A12 */
273 gsl_blas_zgemm(CblasNoTrans, CblasNoTrans, GSL_COMPLEX_NEGONE, &A21.matrix, &A12.matrix, GSL_COMPLEX_ONE, &A22.matrix);
274
275 /* recursion on (A22, ipiv2) */
276 status = LU_decomp_L3(&A22.matrix, &ipiv2.vector);
277 if (status)
278 return status;
279
280 /* apply pivots to A21 */
281 apply_pivots(&A21.matrix, &ipiv2.vector);
282
283 /* shift pivots */
284 for (i = 0; i < N2; ++i)
285 {
286 unsigned int * ptr = gsl_vector_uint_ptr(&ipiv2.vector, i);
287 *ptr += N1;
288 }
289
290 return GSL_SUCCESS;
291 }
292 }
293
294 int
gsl_linalg_complex_LU_solve(const gsl_matrix_complex * LU,const gsl_permutation * p,const gsl_vector_complex * b,gsl_vector_complex * x)295 gsl_linalg_complex_LU_solve (const gsl_matrix_complex * LU, const gsl_permutation * p, const gsl_vector_complex * b, gsl_vector_complex * x)
296 {
297 if (LU->size1 != LU->size2)
298 {
299 GSL_ERROR ("LU matrix must be square", GSL_ENOTSQR);
300 }
301 else if (LU->size1 != p->size)
302 {
303 GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
304 }
305 else if (LU->size1 != b->size)
306 {
307 GSL_ERROR ("matrix size must match b size", GSL_EBADLEN);
308 }
309 else if (LU->size2 != x->size)
310 {
311 GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
312 }
313 else if (singular (LU))
314 {
315 GSL_ERROR ("matrix is singular", GSL_EDOM);
316 }
317 else
318 {
319 int status;
320
321 /* copy x <- b */
322 gsl_vector_complex_memcpy (x, b);
323
324 /* solve for x */
325 status = gsl_linalg_complex_LU_svx (LU, p, x);
326
327 return status;
328 }
329 }
330
331
332 int
gsl_linalg_complex_LU_svx(const gsl_matrix_complex * LU,const gsl_permutation * p,gsl_vector_complex * x)333 gsl_linalg_complex_LU_svx (const gsl_matrix_complex * LU, const gsl_permutation * p, gsl_vector_complex * x)
334 {
335 if (LU->size1 != LU->size2)
336 {
337 GSL_ERROR ("LU matrix must be square", GSL_ENOTSQR);
338 }
339 else if (LU->size1 != p->size)
340 {
341 GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
342 }
343 else if (LU->size1 != x->size)
344 {
345 GSL_ERROR ("matrix size must match solution/rhs size", GSL_EBADLEN);
346 }
347 else if (singular (LU))
348 {
349 GSL_ERROR ("matrix is singular", GSL_EDOM);
350 }
351 else
352 {
353 /* apply permutation to RHS */
354 gsl_permute_vector_complex (p, x);
355
356 /* solve for c using forward-substitution, L c = P b */
357 gsl_blas_ztrsv (CblasLower, CblasNoTrans, CblasUnit, LU, x);
358
359 /* perform back-substitution, U x = c */
360 gsl_blas_ztrsv (CblasUpper, CblasNoTrans, CblasNonUnit, LU, x);
361
362 return GSL_SUCCESS;
363 }
364 }
365
366
367 int
gsl_linalg_complex_LU_refine(const gsl_matrix_complex * A,const gsl_matrix_complex * LU,const gsl_permutation * p,const gsl_vector_complex * b,gsl_vector_complex * x,gsl_vector_complex * work)368 gsl_linalg_complex_LU_refine (const gsl_matrix_complex * A, const gsl_matrix_complex * LU, const gsl_permutation * p, const gsl_vector_complex * b, gsl_vector_complex * x, gsl_vector_complex * work)
369 {
370 if (A->size1 != A->size2)
371 {
372 GSL_ERROR ("matrix a must be square", GSL_ENOTSQR);
373 }
374 if (LU->size1 != LU->size2)
375 {
376 GSL_ERROR ("LU matrix must be square", GSL_ENOTSQR);
377 }
378 else if (A->size1 != LU->size2)
379 {
380 GSL_ERROR ("LU matrix must be decomposition of a", GSL_ENOTSQR);
381 }
382 else if (LU->size1 != p->size)
383 {
384 GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
385 }
386 else if (LU->size1 != b->size)
387 {
388 GSL_ERROR ("matrix size must match b size", GSL_EBADLEN);
389 }
390 else if (LU->size1 != x->size)
391 {
392 GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
393 }
394 else if (LU->size1 != work->size)
395 {
396 GSL_ERROR ("matrix size must match workspace size", GSL_EBADLEN);
397 }
398 else if (singular (LU))
399 {
400 GSL_ERROR ("matrix is singular", GSL_EDOM);
401 }
402 else
403 {
404 int status;
405
406 /* Compute residual = (A * x - b) */
407
408 gsl_vector_complex_memcpy (work, b);
409
410 {
411 gsl_complex one = GSL_COMPLEX_ONE;
412 gsl_complex negone = GSL_COMPLEX_NEGONE;
413 gsl_blas_zgemv (CblasNoTrans, one, A, x, negone, work);
414 }
415
416 /* Find correction, delta = - (A^-1) * residual, and apply it */
417
418 status = gsl_linalg_complex_LU_svx (LU, p, work);
419
420 {
421 gsl_complex negone= GSL_COMPLEX_NEGONE;
422 gsl_blas_zaxpy (negone, work, x);
423 }
424
425 return status;
426 }
427 }
428
429 int
gsl_linalg_complex_LU_invert(const gsl_matrix_complex * LU,const gsl_permutation * p,gsl_matrix_complex * inverse)430 gsl_linalg_complex_LU_invert (const gsl_matrix_complex * LU, const gsl_permutation * p, gsl_matrix_complex * inverse)
431 {
432 if (LU->size1 != LU->size2)
433 {
434 GSL_ERROR ("LU matrix must be square", GSL_ENOTSQR);
435 }
436 else if (LU->size1 != p->size)
437 {
438 GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
439 }
440 else if (inverse->size1 != LU->size1 || inverse->size2 != LU->size2)
441 {
442 GSL_ERROR ("inverse matrix must match LU matrix dimensions", GSL_EBADLEN);
443 }
444 else
445 {
446 gsl_matrix_complex_memcpy(inverse, LU);
447 return gsl_linalg_complex_LU_invx(inverse, p);
448 }
449 }
450
451 int
gsl_linalg_complex_LU_invx(gsl_matrix_complex * LU,const gsl_permutation * p)452 gsl_linalg_complex_LU_invx (gsl_matrix_complex * LU, const gsl_permutation * p)
453 {
454 if (LU->size1 != LU->size2)
455 {
456 GSL_ERROR ("LU matrix must be square", GSL_ENOTSQR);
457 }
458 else if (LU->size1 != p->size)
459 {
460 GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN);
461 }
462 else if (singular (LU))
463 {
464 GSL_ERROR ("matrix is singular", GSL_EDOM);
465 }
466 else
467 {
468 int status;
469 const size_t N = LU->size1;
470 size_t i;
471
472 /* compute U^{-1} */
473 status = gsl_linalg_complex_tri_invert(CblasUpper, CblasNonUnit, LU);
474 if (status)
475 return status;
476
477 /* compute L^{-1} */
478 status = gsl_linalg_complex_tri_invert(CblasLower, CblasUnit, LU);
479 if (status)
480 return status;
481
482 /* compute U^{-1} L^{-1} */
483 status = gsl_linalg_complex_tri_UL(LU);
484 if (status)
485 return status;
486
487 /* apply permutation to columns of A^{-1} */
488 for (i = 0; i < N; ++i)
489 {
490 gsl_vector_complex_view v = gsl_matrix_complex_row(LU, i);
491 gsl_permute_vector_complex_inverse(p, &v.vector);
492 }
493
494 return GSL_SUCCESS;
495 }
496 }
497
498 gsl_complex
gsl_linalg_complex_LU_det(gsl_matrix_complex * LU,int signum)499 gsl_linalg_complex_LU_det (gsl_matrix_complex * LU, int signum)
500 {
501 size_t i, n = LU->size1;
502
503 gsl_complex det = gsl_complex_rect((double) signum, 0.0);
504
505 for (i = 0; i < n; i++)
506 {
507 gsl_complex zi = gsl_matrix_complex_get (LU, i, i);
508 det = gsl_complex_mul (det, zi);
509 }
510
511 return det;
512 }
513
514
515 double
gsl_linalg_complex_LU_lndet(gsl_matrix_complex * LU)516 gsl_linalg_complex_LU_lndet (gsl_matrix_complex * LU)
517 {
518 size_t i, n = LU->size1;
519
520 double lndet = 0.0;
521
522 for (i = 0; i < n; i++)
523 {
524 gsl_complex z = gsl_matrix_complex_get (LU, i, i);
525 lndet += log (gsl_complex_abs (z));
526 }
527
528 return lndet;
529 }
530
531
532 gsl_complex
gsl_linalg_complex_LU_sgndet(gsl_matrix_complex * LU,int signum)533 gsl_linalg_complex_LU_sgndet (gsl_matrix_complex * LU, int signum)
534 {
535 size_t i, n = LU->size1;
536
537 gsl_complex phase = gsl_complex_rect((double) signum, 0.0);
538
539 for (i = 0; i < n; i++)
540 {
541 gsl_complex z = gsl_matrix_complex_get (LU, i, i);
542
543 double r = gsl_complex_abs(z);
544
545 if (r == 0)
546 {
547 phase = gsl_complex_rect(0.0, 0.0);
548 break;
549 }
550 else
551 {
552 z = gsl_complex_div_real(z, r);
553 phase = gsl_complex_mul(phase, z);
554 }
555 }
556
557 return phase;
558 }
559
560 static int
singular(const gsl_matrix_complex * LU)561 singular (const gsl_matrix_complex * LU)
562 {
563 size_t i, n = LU->size1;
564
565 for (i = 0; i < n; i++)
566 {
567 gsl_complex u = gsl_matrix_complex_get (LU, i, i);
568 if (GSL_REAL(u) == 0 && GSL_IMAG(u) == 0) return 1;
569 }
570
571 return 0;
572 }
573
574 static int
apply_pivots(gsl_matrix_complex * A,const gsl_vector_uint * ipiv)575 apply_pivots(gsl_matrix_complex * A, const gsl_vector_uint * ipiv)
576 {
577 if (A->size1 < ipiv->size)
578 {
579 GSL_ERROR("matrix does not match pivot vector", GSL_EBADLEN);
580 }
581 else
582 {
583 size_t i;
584
585 for (i = 0; i < ipiv->size; ++i)
586 {
587 size_t pi = gsl_vector_uint_get(ipiv, i);
588
589 if (i != pi)
590 {
591 /* swap rows i and pi */
592 gsl_vector_complex_view v1 = gsl_matrix_complex_row(A, i);
593 gsl_vector_complex_view v2 = gsl_matrix_complex_row(A, pi);
594 gsl_blas_zswap(&v1.vector, &v2.vector);
595 }
596 }
597
598 return GSL_SUCCESS;
599 }
600 }
601