MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
complex_densemat.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "complex_densemat.hpp"
13#include <complex>
14
15#ifdef MFEM_USE_LAPACK
16#ifdef MFEM_USE_SINGLE
17extern "C" void
18cgetrf_(int *, int *, std::complex<float> *, int *, int *, int *);
19extern "C" void
20cgetrs_(char *, int *, int *, std::complex<float> *, int *, int *,
21 std::complex<float> *, int *, int *);
22extern "C" void
23cgetri_(int *, std::complex<float> *, int *, int *,
24 std::complex<float> *, int *, int *);
25extern "C" void
26ctrsm_(char *, char *, char *, char *, int *, int *, std::complex<float> *,
27 std::complex<float> *, int *, std::complex<float> *, int *);
28extern "C" void
29cpotrf_(char *, int *, std::complex<float> *, int *, int *);
30
31extern "C" void
32ctrtrs_(char *, char*, char *, int *, int *, std::complex<float> *, int *,
33 std::complex<float> *, int *, int *);
34extern "C" void
35cpotri_(char *, int *, std::complex<float> *, int*, int *);
36
37extern "C" void
38cpotrs_(char *, int *, int *, std::complex<float> *, int *,
39 std::complex<float> *, int *, int *);
40#elif defined MFEM_USE_DOUBLE
41extern "C" void
42zgetrf_(int *, int *, std::complex<double> *, int *, int *, int *);
43extern "C" void
44zgetrs_(char *, int *, int *, std::complex<double> *, int *, int *,
45 std::complex<double> *, int *, int *);
46extern "C" void
47zgetri_(int *, std::complex<double> *, int *, int *,
48 std::complex<double> *, int *, int *);
49extern "C" void
50ztrsm_(char *, char *, char *, char *, int *, int *, std::complex<double> *,
51 std::complex<double> *, int *, std::complex<double> *, int *);
52extern "C" void
53zpotrf_(char *, int *, std::complex<double> *, int *, int *);
54
55extern "C" void
56ztrtrs_(char *, char*, char *, int *, int *, std::complex<double> *, int *,
57 std::complex<double> *, int *, int *);
58extern "C" void
59zpotri_(char *, int *, std::complex<double> *, int*, int *);
60
61extern "C" void
62zpotrs_(char *, int *, int *, std::complex<double> *, int *,
63 std::complex<double> *, int *, int *);
64#endif
65#endif
66
67namespace mfem
68{
69
71{
72 MFEM_ASSERT(Op_Real_, "ComplexDenseMatrix has no real part!");
73 return dynamic_cast<DenseMatrix &>(*Op_Real_);
74}
75
77{
78 MFEM_ASSERT(Op_Imag_, "ComplexDenseMatrix has no imaginary part!");
79 return dynamic_cast<DenseMatrix &>(*Op_Imag_);
80}
81
83{
84 MFEM_ASSERT(Op_Real_, "ComplexDenseMatrix has no real part!");
85 return dynamic_cast<const DenseMatrix &>(*Op_Real_);
86}
87
89{
90 MFEM_ASSERT(Op_Imag_, "ComplexDenseMatrix has no imaginary part!");
91 return dynamic_cast<const DenseMatrix &>(*Op_Imag_);
92}
93
95{
96 int h = height/2;
97 int w = width/2;
98 DenseMatrix * A = new DenseMatrix(2*h,2*w);
99 real_t * data = A->Data();
100 real_t * data_r = nullptr;
101 real_t * data_i = nullptr;
102
103 const real_t factor = (convention_ == HERMITIAN) ? 1.0 : -1.0;
104 *A = 0.;
105 if (hasRealPart())
106 {
107 data_r = real().Data();
108 for (int j = 0; j<w; j++)
109 {
110 for (int i = 0; i<h; i++)
111 {
112 data[i+j*height] = data_r[i+j*h];
113 data[i+h+(j+h)*height] = factor*data_r[i+j*h];
114 }
115 }
116 }
117 if (hasImagPart())
118 {
119 data_i = imag().Data();
120 for (int j = 0; j<w; j++)
121 {
122 for (int i = 0; i<h; i++)
123 {
124 data[i+h+j*height] = factor*data_i[i+j*h];
125 data[i+(j+h)*height] = -data_i[i+j*h];
126 }
127 }
128 }
129 return A;
130}
131
133{
134 MFEM_VERIFY(height == width, "Matrix has to be square");
135
136 // complex data
137 int h = height/2;
138 int w = width/2;
139 std::complex<real_t> * data = new std::complex<real_t>[h*w];
140
141 // copy data
142 if (hasRealPart() && hasImagPart())
143 {
144 real_t * data_r = real().Data();
145 real_t * data_i = imag().Data();
146 for (int i = 0; i < h*w; i++)
147 {
148 data[i] = std::complex<real_t> (data_r[i], data_i[i]);
149 }
150 }
151 else if (hasRealPart())
152 {
153 real_t * data_r = real().Data();
154 for (int i = 0; i < h*w; i++)
155 {
156 data[i] = std::complex<real_t> (data_r[i], 0.);
157 }
158 }
159 else if (hasImagPart())
160 {
161 real_t * data_i = imag().Data();
162 for (int i = 0; i < h*w; i++)
163 {
164 data[i] = std::complex<real_t> (0., data_i[i]);
165 }
166 }
167 else
168 {
169 MFEM_ABORT("ComplexDenseMatrix has neither only a real nor an imag part");
170 }
171
172#ifdef MFEM_USE_LAPACK
173 int *ipiv = new int[w];
174 int lwork = -1;
175 std::complex<real_t> qwork, *work;
176 int info;
177
178#ifdef MFEM_USE_SINGLE
179 cgetrf_(&w, &w, data, &w, ipiv, &info);
180#elif defined MFEM_USE_DOUBLE
181 zgetrf_(&w, &w, data, &w, ipiv, &info);
182#else
183 MFEM_ABORT("Floating point type undefined");
184#endif
185 if (info)
186 {
187 mfem_error("DenseMatrix::Invert() : Error in ZGETRF");
188 }
189
190#ifdef MFEM_USE_SINGLE
191 cgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
192#elif defined MFEM_USE_DOUBLE
193 zgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
194#else
195 MFEM_ABORT("Floating point type undefined");
196#endif
197 lwork = (int) qwork.real();
198 work = new std::complex<real_t>[lwork];
199
200#ifdef MFEM_USE_SINGLE
201 cgetri_(&w, data, &w, ipiv, work, &lwork, &info);
202#elif defined MFEM_USE_DOUBLE
203 zgetri_(&w, data, &w, ipiv, work, &lwork, &info);
204#else
205 MFEM_ABORT("Floating point type undefined");
206#endif
207 if (info)
208 {
209 mfem_error("DenseMatrix::Invert() : Error in ZGETRI");
210 }
211
212 delete [] work;
213 delete [] ipiv;
214
215#else
216 // compiling without LAPACK
217 int c, i, j, n = w;
218 real_t a, b;
219 Array<int> piv(n);
220 std::complex<real_t> ac,bc;
221
222 for (c = 0; c < n; c++)
223 {
224 a = std::abs(data[c+c*h]);
225 i = c;
226 for (j = c + 1; j < n; j++)
227 {
228 b = std::abs(data[j+c*h]);
229 if (a < b)
230 {
231 a = b;
232 i = j;
233 }
234 }
235 if (a == 0.0)
236 {
237 mfem_error("DenseMatrix::Invert() : singular matrix");
238 }
239 piv[c] = i;
240 for (j = 0; j < n; j++)
241 {
242 mfem::Swap<std::complex<real_t>>(data[c+j*h], data[i+j*h]);
243 }
244
245 real_t fone = 1.0; // TODO: why?
246 ac = data[c+c*h] = fone / data[c+c*h];
247 for (j = 0; j < c; j++)
248 {
249 data[c+j*h] *= ac;
250 }
251 for (j++; j < n; j++)
252 {
253 data[c+j*h] *= ac;
254 }
255 for (i = 0; i < c; i++)
256 {
257 data[i+c*h] = ac * (bc = -data[i+c*h]);
258 for (j = 0; j < c; j++)
259 {
260 data[i+j*h] += bc * data[c+j*h];
261 }
262 for (j++; j < n; j++)
263 {
264 data[i+j*h] += bc * data[c+j*h];
265 }
266 }
267 for (i++; i < n; i++)
268 {
269 data[i+c*h] = ac * (bc = -data[i+c*h]);
270 for (j = 0; j < c; j++)
271 {
272 data[i+j*h] += bc * data[c+j*h];
273 }
274 for (j++; j < n; j++)
275 {
276 data[i+j*h] += bc * data[c+j*h];
277 }
278 }
279 }
280
281 for (c = n - 1; c >= 0; c--)
282 {
283 j = piv[c];
284 for (i = 0; i < n; i++)
285 {
286 mfem::Swap<std::complex<real_t>>(data[i+c*h], data[i+j*h]);
287 }
288 }
289
290#endif
291
292 DenseMatrix * C_r = new DenseMatrix(h);
293 DenseMatrix * C_i = new DenseMatrix(h);
294
295 real_t * datac_r = C_r->Data();
296 real_t * datac_i = C_i->Data();
297
298 for (int k = 0; k < h*w; k++)
299 {
300 datac_r[k] = data[k].real();
301 datac_i[k] = data[k].imag();
302 }
303 delete [] data;
304 return new ComplexDenseMatrix(C_r,C_i,true,true);
305
306}
307
309 const ComplexDenseMatrix &B)
310{
311 // C = C_r + i C_i = (A_r + i * A_i) * (B_r + i * B_i)
312 // = A_r * B_r - A_i B_i + i (A_r * B_i + A_i * B_r)
313
314 int h = A.Height()/2;
315 int w = B.Width()/2;
316
317 MFEM_VERIFY(A.Width() == B.Height(), "Incompatible matrix dimensions");
318
319 //only real case (imag is null)
320 DenseMatrix * C_r = nullptr;
321 DenseMatrix * C_i = nullptr;
322 if ((A.hasRealPart() && B.hasRealPart()) ||
323 (A.hasImagPart() && B.hasImagPart()))
324 {
325 C_r = new DenseMatrix(h,w);
326 }
327 if ((A.hasRealPart() && B.hasImagPart()) ||
328 (A.hasImagPart() && B.hasRealPart()))
329 {
330 C_i = new DenseMatrix(h,w);
331 }
332
333 MFEM_VERIFY(C_r || C_i, "Both real and imag parts are null");
334
335 if (A.hasRealPart() && B.hasRealPart())
336 {
337 Mult(A.real(), B.real(),*C_r);
338 }
339 if (A.hasImagPart() && B.hasImagPart())
340 {
341 if (A.hasRealPart() && B.hasRealPart())
342 {
343 AddMult_a(-1.,A.imag(), B.imag(),*C_r);
344 }
345 else
346 {
347 Mult(A.imag(), B.imag(),*C_r);
348 }
349 }
350
351 if (A.hasRealPart() && B.hasImagPart())
352 {
353 Mult(A.real(), B.imag(),*C_i);
354 }
355
356 if (A.hasImagPart() && B.hasRealPart())
357 {
358 if (A.hasRealPart() && B.hasImagPart())
359 {
360 AddMult(A.imag(), B.real(),*C_i);
361 }
362 else
363 {
364 Mult(A.imag(), B.real(),*C_i);
365 }
366 }
367
368 return new ComplexDenseMatrix(C_r,C_i,true,true);
369}
370
372 const ComplexDenseMatrix &B)
373{
374 // C = C_r + i C_i = (A_r^t - i * A_i^t) * (B_r + i * B_i)
375 // = A_r^t * B_r + A_i^t * B_i + i (A_r^t * B_i - A_i^t * B_r)
376
377 int h = A.Width()/2;
378 int w = B.Width()/2;
379
380 MFEM_VERIFY(A.Height() == B.Height(), "Incompatible matrix dimensions");
381
382 //only real case (imag is null)
383 DenseMatrix * C_r = nullptr;
384 DenseMatrix * C_i = nullptr;
385 if ((A.hasRealPart() && B.hasRealPart()) ||
386 (A.hasImagPart() && B.hasImagPart()))
387 {
388 C_r = new DenseMatrix(h,w);
389 }
390 if ((A.hasRealPart() && B.hasImagPart()) ||
391 (A.hasImagPart() && B.hasRealPart()))
392 {
393 C_i = new DenseMatrix(h,w);
394 }
395
396 MFEM_VERIFY(C_r || C_i, "Both real and imag parts are null");
397
398 if (A.hasRealPart() && B.hasRealPart())
399 {
400 MultAtB(A.real(), B.real(),*C_r);
401 }
402 if (A.hasImagPart() && B.hasImagPart())
403 {
404 if (A.hasRealPart() && B.hasRealPart())
405 {
406 DenseMatrix tempC_r(h,w);
407 MultAtB(A.imag(), B.imag(),tempC_r);
408 (*C_r) += tempC_r;
409 }
410 else
411 {
412 MultAtB(A.imag(), B.imag(),*C_r);
413 }
414 }
415
416 if (A.hasRealPart() && B.hasImagPart())
417 {
418 MultAtB(A.real(), B.imag(),*C_i);
419 }
420
421 if (A.hasImagPart() && B.hasRealPart())
422 {
423 if (A.hasRealPart() && B.hasImagPart())
424 {
425 DenseMatrix tempC_i(h,w);
426 MultAtB(A.imag(), B.real(),tempC_i);
427 (*C_i) -= tempC_i;
428 }
429 else
430 {
431 MultAtB(A.imag(), B.real(),*C_i);
432 }
433 }
434
435 return new ComplexDenseMatrix(C_r,C_i,true,true);
436}
437
438std::complex<real_t> * ComplexFactors::RealToComplex
439(int m, const real_t * x_r, const real_t * x_i) const
440{
441 std::complex<real_t> * x = new std::complex<real_t>[m];
442 if (x_r && x_i)
443 {
444 for (int i = 0; i<m; i++)
445 {
446 x[i] = std::complex<real_t>(x_r[i], x_i[i]);
447 }
448 }
449 else if (data_r)
450 {
451 for (int i = 0; i<m; i++)
452 {
453 x[i] = std::complex<real_t>(x_r[i], 0.);
454 }
455 }
456 else if (data_i)
457 {
458 for (int i = 0; i<m; i++)
459 {
460 x[i] = std::complex<real_t>(0., x_i[i]);
461 }
462 }
463 else
464 {
465 MFEM_ABORT("ComplexFactors::RealToComplex:both real and imag part are null");
466 return nullptr;
467 }
468 return x;
469}
470
471void ComplexFactors::ComplexToReal(int m, const std::complex<real_t> * x,
472 real_t * x_r, real_t * x_i) const
473{
474 for (int i = 0; i<m; i++)
475 {
476 x_r[i] = x[i].real();
477 x_i[i] = x[i].imag();
478 }
479}
480
481
483{
484 if (data) { return; }
485 MFEM_VERIFY(data_r || data_i, "ComplexFactors data not set");
487}
488
489
491{
492 SetComplexData(m*m);
493#ifdef MFEM_USE_LAPACK
494 int info = 0;
495 MFEM_VERIFY(data, "Matrix data not set");
496#ifdef MFEM_USE_SINGLE
497 if (m) { cgetrf_(&m, &m, data, &m, ipiv, &info); }
498#elif defined MFEM_USE_DOUBLE
499 if (m) { zgetrf_(&m, &m, data, &m, ipiv, &info); }
500#endif
501 return info == 0;
502#else
503 // compiling without LAPACK
504 std::complex<real_t> *data_ptr = this->data;
505 for (int i = 0; i < m; i++)
506 {
507 // pivoting
508 {
509 int piv = i;
510 real_t a = std::abs(data_ptr[piv+i*m]);
511 for (int j = i+1; j < m; j++)
512 {
513 const real_t b = std::abs(data_ptr[j+i*m]);
514 if (b > a)
515 {
516 a = b;
517 piv = j;
518 }
519 }
520 ipiv[i] = piv;
521 if (piv != i)
522 {
523 // swap rows i and piv in both L and U parts
524 for (int j = 0; j < m; j++)
525 {
526 mfem::Swap<std::complex<real_t>>(data_ptr[i+j*m], data_ptr[piv+j*m]);
527 }
528 }
529 }
530
531 if (abs(data_ptr[i + i*m]) <= TOL)
532 {
533 return false; // failed
534 }
535
536 real_t fone = 1.0; // TODO: why?
537 const std::complex<real_t> a_ii_inv = fone / data_ptr[i+i*m];
538 for (int j = i+1; j < m; j++)
539 {
540 data_ptr[j+i*m] *= a_ii_inv;
541 }
542 for (int k = i+1; k < m; k++)
543 {
544 const std::complex<real_t> a_ik = data_ptr[i+k*m];
545 for (int j = i+1; j < m; j++)
546 {
547 data_ptr[j+k*m] -= a_ik * data_ptr[j+i*m];
548 }
549 }
550 }
551#endif
552
553 return true; // success
554}
555
556std::complex<real_t> ComplexLUFactors::Det(int m) const
557{
558 std::complex<real_t> det(1.0,0.);
559 for (int i=0; i<m; i++)
560 {
561 if (ipiv[i] != i-ipiv_base)
562 {
563 det *= -data[m * i + i];
564 }
565 else
566 {
567 det *= data[m * i + i];
568 }
569 }
570 return det;
571}
572
573void ComplexLUFactors::Mult(int m, int n, real_t *X_r, real_t * X_i) const
574{
575 std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
576 for (int k = 0; k < n; k++)
577 {
578 // X <- U X
579 for (int i = 0; i < m; i++)
580 {
581 std::complex<real_t> x_i = x[i] * data[i+i*m];
582 for (int j = i+1; j < m; j++)
583 {
584 x_i += x[j] * data[i+j*m];
585 }
586 x[i] = x_i;
587 }
588 // X <- L X
589 for (int i = m-1; i >= 0; i--)
590 {
591 std::complex<real_t> x_i = x[i];
592 for (int j = 0; j < i; j++)
593 {
594 x_i += x[j] * data[i+j*m];
595 }
596 x[i] = x_i;
597 }
598 // X <- P^{-1} X
599 for (int i = m-1; i >= 0; i--)
600 {
602 }
603 x += m;
604 }
605 ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
606 delete [] x;
607}
608
609void ComplexLUFactors::LSolve(int m, int n, real_t *X_r, real_t * X_i) const
610{
611 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
612 std::complex<real_t> *x = X;
613 for (int k = 0; k < n; k++)
614 {
615 // X <- P X
616 for (int i = 0; i < m; i++)
617 {
619 }
620 // X <- L^{-1} X
621 for (int j = 0; j < m; j++)
622 {
623 const std::complex<real_t> x_j = x[j];
624 for (int i = j+1; i < m; i++)
625 {
626 x[i] -= data[i+j*m] * x_j;
627 }
628 }
629 x += m;
630 }
631 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
632 delete [] X;
633}
634
635void ComplexLUFactors::USolve(int m, int n, real_t *X_r, real_t * X_i) const
636{
637 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
638 std::complex<real_t> *x = X;
639 // X <- U^{-1} X
640 for (int k = 0; k < n; k++)
641 {
642 for (int j = m-1; j >= 0; j--)
643 {
644 const std::complex<real_t> x_j = ( x[j] /= data[j+j*m] );
645 for (int i = 0; i < j; i++)
646 {
647 x[i] -= data[i+j*m] * x_j;
648 }
649 }
650 x += m;
651 }
652 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
653 delete [] X;
654}
655
656void ComplexLUFactors::Solve(int m, int n, real_t *X_r, real_t * X_i) const
657{
658#ifdef MFEM_USE_LAPACK
659 std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
660 char trans = 'N';
661 int info = 0;
662#ifdef MFEM_USE_SINGLE
663 if (m > 0 && n > 0) { cgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
664#elif defined MFEM_USE_DOUBLE
665 if (m > 0 && n > 0) { zgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
666#else
667 MFEM_ABORT("Floating point type undefined");
668#endif
669 MFEM_VERIFY(!info, "LAPACK: error in ZGETRS");
670 ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
671 delete [] x;
672#else
673 // compiling without LAPACK
674 LSolve(m, n, X_r, X_i);
675 USolve(m, n, X_r, X_i);
676#endif
677}
678
679void ComplexLUFactors::RightSolve(int m, int n, real_t *X_r, real_t * X_i) const
680{
681 std::complex<real_t> * X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
682 std::complex<real_t> * x = X;
683#ifdef MFEM_USE_LAPACK
684 char n_ch = 'N', side = 'R', u_ch = 'U', l_ch = 'L';
685 if (m > 0 && n > 0)
686 {
687 std::complex<real_t> alpha(1.0,0.0);
688#ifdef MFEM_USE_SINGLE
689 ctrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
690 ctrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
691#elif defined MFEM_USE_DOUBLE
692 ztrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
693 ztrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
694#else
695 MFEM_ABORT("Floating point type undefined");
696#endif
697 }
698#else
699 // compiling without LAPACK
700 // X <- X U^{-1}
701 for (int k = 0; k < n; k++)
702 {
703 for (int j = 0; j < m; j++)
704 {
705 const std::complex<real_t> x_j = ( x[j*n] /= data[j+j*m]);
706 for (int i = j+1; i < m; i++)
707 {
708 x[i*n] -= data[j + i*m] * x_j;
709 }
710 }
711 ++x;
712 }
713
714 // X <- X L^{-1}
715 x = X;
716 for (int k = 0; k < n; k++)
717 {
718 for (int j = m-1; j >= 0; j--)
719 {
720 const std::complex<real_t> x_j = x[j*n];
721 for (int i = 0; i < j; i++)
722 {
723 x[i*n] -= data[j + i*m] * x_j;
724 }
725 }
726 ++x;
727 }
728#endif
729 // X <- X P
730 x = X;
731 for (int k = 0; k < n; k++)
732 {
733 for (int i = m-1; i >= 0; --i)
734 {
736 }
737 ++x;
738 }
739 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
740 delete [] X;
741}
742
744{
745 // A^{-1} = U^{-1} L^{-1} P
746 // X <- U^{-1} (set only the upper triangular part of X)
747 std::complex<real_t> * X = ComplexFactors::RealToComplex(m*m,X_r,X_i);
748 std::complex<real_t> * x = X;
749 real_t fone = 1.0; // TODO: why?
750 for (int k = 0; k < m; k++)
751 {
752 const std::complex<real_t> minus_x_k = -( x[k] = fone/data[k+k*m] );
753 for (int i = 0; i < k; i++)
754 {
755 x[i] = data[i+k*m] * minus_x_k;
756 }
757 for (int j = k-1; j >= 0; j--)
758 {
759 const std::complex<real_t> x_j = ( x[j] /= data[j+j*m] );
760 for (int i = 0; i < j; i++)
761 {
762 x[i] -= data[i+j*m] * x_j;
763 }
764 }
765 x += m;
766 }
767 // X <- X L^{-1} (use input only from the upper triangular part of X)
768 {
769 int k = m-1;
770 for (int j = 0; j < k; j++)
771 {
772 const std::complex<real_t> minus_L_kj = -data[k+j*m];
773 for (int i = 0; i <= j; i++)
774 {
775 X[i+j*m] += X[i+k*m] * minus_L_kj;
776 }
777 for (int i = j+1; i < m; i++)
778 {
779 X[i+j*m] = X[i+k*m] * minus_L_kj;
780 }
781 }
782 }
783 for (int k = m-2; k >= 0; k--)
784 {
785 for (int j = 0; j < k; j++)
786 {
787 const std::complex<real_t> L_kj = data[k+j*m];
788 for (int i = 0; i < m; i++)
789 {
790 X[i+j*m] -= X[i+k*m] * L_kj;
791 }
792 }
793 }
794 // X <- X P
795 for (int k = m-1; k >= 0; k--)
796 {
797 const int piv_k = ipiv[k]-ipiv_base;
798 if (k != piv_k)
799 {
800 for (int i = 0; i < m; i++)
801 {
802 Swap<std::complex<real_t>>(X[i+k*m], X[i+piv_k*m]);
803 }
804 }
805 }
806 ComplexFactors::ComplexToReal(m*m,X,X_r,X_i);
807 delete [] X;
808}
809
810
812{
813 SetComplexData(m*m);
814#ifdef MFEM_USE_LAPACK
815 int info = 0;
816 char uplo = 'L';
817 MFEM_VERIFY(data, "Matrix data not set");
818#ifdef MFEM_USE_SINGLE
819 if (m) {cpotrf_(&uplo, &m, data, &m, &info);}
820#elif defined MFEM_USE_DOUBLE
821 if (m) {zpotrf_(&uplo, &m, data, &m, &info);}
822#else
823 MFEM_ABORT("Floating point type undefined");
824#endif
825 return info == 0;
826#else
827 // Cholesky–Crout algorithm
828 real_t fone = 1.0; // TODO: why?
829 for (int j = 0; j<m; j++)
830 {
831 std::complex<real_t> a(0.,0.);
832 for (int k = 0; k<j; k++)
833 {
834 a+=data[j+k*m]*std::conj(data[j+k*m]);
835 }
836
837 MFEM_VERIFY((data[j+j*m] - a).real() > 0.,
838 "CholeskyFactors::Factor: The matrix is not SPD");
839
840 data[j+j*m] = std::sqrt((data[j+j*m] - a).real());
841
842 if (data[j + j*m].real() <= TOL) { return false; }
843
844 for (int i = j+1; i<m; i++)
845 {
846 a = std::complex<real_t>(0.,0.);
847 for (int k = 0; k<j; k++)
848 {
849 a+= data[i+k*m]*std::conj(data[j+k*m]);
850 }
851 data[i+j*m] = fone/data[j+m*j]*(data[i+j*m] - a);
852 }
853 }
854 return true; // success
855#endif
856}
857
858std::complex<real_t> ComplexCholeskyFactors::Det(int m) const
859{
860 std::complex<real_t> det(1.0,0.0);
861 for (int i=0; i<m; i++)
862 {
863 det *= data[i + i*m];
864 }
865 return det;
866}
867
868void ComplexCholeskyFactors::LMult(int m, int n, real_t * X_r,
869 real_t * X_i) const
870{
871 // X <- L X
872 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
873 std::complex<real_t> *x = X;
874 for (int k = 0; k < n; k++)
875 {
876 for (int j = m-1; j >= 0; j--)
877 {
878 std::complex<real_t> x_j = x[j] * data[j+j*m];
879 for (int i = 0; i < j; i++)
880 {
881 x_j += x[i] * data[j+i*m];
882 }
883 x[j] = x_j;
884 }
885 x += m;
886 }
887 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
888 delete [] X;
889}
890
891void ComplexCholeskyFactors::UMult(int m, int n, real_t * X_r,
892 real_t * X_i) const
893{
894 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
895 std::complex<real_t> *x = X;
896 for (int k = 0; k < n; k++)
897 {
898 for (int i = 0; i < m; i++)
899 {
900 std::complex<real_t> x_i = x[i] * data[i+i*m];
901 for (int j = i+1; j < m; j++)
902 {
903 x_i += x[j] * std::conj(data[j+i*m]);
904 }
905 x[i] = x_i;
906 }
907 x += m;
908 }
909 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
910 delete [] X;
911}
912
913void ComplexCholeskyFactors::LSolve(int m, int n, real_t * X_r,
914 real_t * X_i) const
915{
916 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
917 std::complex<real_t> *x = X;
918#ifdef MFEM_USE_LAPACK
919 char uplo = 'L';
920 char trans = 'N';
921 char diag = 'N';
922 int info = 0;
923
924#ifdef MFEM_USE_SINGLE
925 ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
926#elif defined MFEM_USE_DOUBLE
927 ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
928#else
929 MFEM_ABORT("Floating point type undefined");
930#endif
931 MFEM_VERIFY(!info, "ComplexCholeskyFactors:LSolve:: info");
932#else
933 for (int k = 0; k < n; k++)
934 {
935 // X <- L^{-1} X
936 for (int j = 0; j < m; j++)
937 {
938 const std::complex<real_t> x_j = (x[j] /= data[j+j*m]);
939 for (int i = j+1; i < m; i++)
940 {
941 x[i] -= data[i+j*m] * x_j;
942 }
943 }
944 x += m;
945 }
946#endif
947 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
948 delete [] X;
949}
950
951void ComplexCholeskyFactors::USolve(int m, int n, real_t * X_r,
952 real_t * X_i) const
953{
954 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
955 std::complex<real_t> *x = X;
956#ifdef MFEM_USE_LAPACK
957
958 char uplo = 'L';
959 char trans = 'C';
960 char diag = 'N';
961 int info = 0;
962
963#ifdef MFEM_USE_SINGLE
964 ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
965#elif defined MFEM_USE_DOUBLE
966 ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
967#else
968 MFEM_ABORT("Floating point type undefined");
969#endif
970 MFEM_VERIFY(!info, "ComplexCholeskyFactors:USolve:: info");
971#else
972 // X <- L^{-t} X
973 for (int k = 0; k < n; k++)
974 {
975 for (int j = m-1; j >= 0; j--)
976 {
977 const std::complex<real_t> x_j = ( x[j] /= data[j+j*m] );
978 for (int i = 0; i < j; i++)
979 {
980 x[i] -= std::conj(data[j+i*m]) * x_j;
981 }
982 }
983 x += m;
984 }
985#endif
986 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
987 delete [] X;
988}
989
990void ComplexCholeskyFactors::Solve(int m, int n, real_t * X_r,
991 real_t * X_i) const
992{
993#ifdef MFEM_USE_LAPACK
994 char uplo = 'L';
995 int info = 0;
996 std::complex<real_t> *x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
997#ifdef MFEM_USE_SINGLE
998 cpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
999#elif defined MFEM_USE_DOUBLE
1000 zpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
1001#else
1002 MFEM_ABORT("Floating point type undefined");
1003#endif
1004 MFEM_VERIFY(!info, "ComplexCholeskyFactors:Solve:: info");
1005 ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
1006 delete x;
1007#else
1008 LSolve(m, n, X_r,X_i);
1009 USolve(m, n, X_r,X_i);
1010#endif
1011}
1012
1014 real_t * X_i) const
1015{
1016
1017 std::complex<real_t> *X = ComplexFactors::RealToComplex(m*n,X_r,X_i);
1018 std::complex<real_t> *x = X;
1019#ifdef MFEM_USE_LAPACK
1020 char side = 'R';
1021 char uplo = 'L';
1022 char transt = 'C';
1023 char trans = 'N';
1024 char diag = 'N';
1025
1026 std::complex<real_t> alpha(1.0,0.0);
1027 if (m > 0 && n > 0)
1028 {
1029#ifdef MFEM_USE_SINGLE
1030 ctrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
1031 ctrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
1032#elif defined MFEM_USE_DOUBLE
1033 ztrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
1034 ztrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
1035#else
1036 MFEM_ABORT("Floating point type undefined");
1037#endif
1038 }
1039#else
1040 // X <- X L^{-H}
1041 for (int k = 0; k < n; k++)
1042 {
1043 for (int j = 0; j < m; j++)
1044 {
1045 const std::complex<real_t> x_j = ( x[j*n] /= data[j+j*m]);
1046 for (int i = j+1; i < m; i++)
1047 {
1048 x[i*n] -= std::conj(data[i + j*m]) * x_j;
1049 }
1050 }
1051 ++x;
1052 }
1053 // X <- X L^{-1}
1054 x = X;
1055 for (int k = 0; k < n; k++)
1056 {
1057 for (int j = m-1; j >= 0; j--)
1058 {
1059 const std::complex<real_t> x_j = (x[j*n] /= data[j+j*m]);
1060 for (int i = 0; i < j; i++)
1061 {
1062 x[i*n] -= data[j + i*m] * x_j;
1063 }
1064 }
1065 ++x;
1066 }
1067#endif
1068 ComplexFactors::ComplexToReal(m*n,X,X_r,X_i);
1069 delete [] X;
1070}
1071
1073 real_t * X_i) const
1074{
1075 // A^{-1} = L^{-t} L^{-1}
1076 std::complex<real_t> * X = new std::complex<real_t>[m*m];
1077#ifdef MFEM_USE_LAPACK
1078 // copy the lower triangular part of L to X
1079 for (int i = 0; i<m; i++)
1080 {
1081 for (int j = i; j<m; j++)
1082 {
1083 X[j+i*m] = data[j+i*m];
1084 }
1085 }
1086 char uplo = 'L';
1087 int info = 0;
1088#ifdef MFEM_USE_SINGLE
1089 cpotri_(&uplo, &m, X, &m, &info);
1090#elif defined MFEM_USE_DOUBLE
1091 zpotri_(&uplo, &m, X, &m, &info);
1092#else
1093 MFEM_ABORT("Floating point type undefined");
1094#endif
1095 MFEM_VERIFY(!info, "ComplexCholeskyFactors:GetInverseMatrix:: info");
1096 // fill in the upper triangular part
1097 for (int i = 0; i<m; i++)
1098 {
1099 for (int j = i+1; j<m; j++)
1100 {
1101 X[i+j*m] = std::conj(X[j+i*m]);
1102 }
1103 }
1104#else
1105 // L^-t * L^-1 (in place)
1106 real_t fone = 1.0; // TODO: why?
1107 for (int k = 0; k<m; k++)
1108 {
1109 X[k+k*m] = fone/data[k+k*m];
1110 for (int i = k+1; i < m; i++)
1111 {
1112 std::complex<real_t> s(0.,0.);
1113 for (int j=k; j<i; j++)
1114 {
1115 s -= data[i+j*m] * X[j+k*m]/data[i+i*m];
1116 }
1117 X[i+k*m] = s;
1118 }
1119 }
1120 for (int i = 0; i < m; i++)
1121 {
1122 for (int j = i; j < m; j++)
1123 {
1124 std::complex<real_t> s(0.,0.);
1125 for (int k=j; k<m; k++)
1126 {
1127 s += X[k+i*m] * std::conj(X[k+j*m]);
1128 }
1129 X[j+i*m] = s;
1130 X[i+j*m] = std::conj(s);
1131 }
1132 }
1133#endif
1134 ComplexFactors::ComplexToReal(m*m,X,X_r,X_i);
1135 delete [] X;
1136}
1137
1138} // mfem namespace
void UMult(int m, int n, real_t *X_r, real_t *X_i) const
void LSolve(int m, int n, real_t *X_r, real_t *X_i) const
virtual void GetInverseMatrix(int m, real_t *X_r, real_t *X_i) const
Assuming L.L^H = A factored data of size (m x m), compute X <- A^{-1}.
virtual void Solve(int m, int n, real_t *X_r, real_t *X_i) const
void USolve(int m, int n, real_t *X_r, real_t *X_i) const
virtual std::complex< real_t > Det(int m) const
void RightSolve(int m, int n, real_t *X_r, real_t *X_i) const
virtual bool Factor(int m, real_t TOL=0.0)
Compute the Cholesky factorization of the current matrix.
void LMult(int m, int n, real_t *X_r, real_t *X_i) const
Specialization of the ComplexOperator built from a pair of Dense Matrices. The purpose of this specia...
ComplexDenseMatrix(DenseMatrix *A_Real, DenseMatrix *A_Imag, bool ownReal, bool ownImag, Convention convention=HERMITIAN)
DenseMatrix * GetSystemMatrix() const
ComplexDenseMatrix * ComputeInverse()
virtual DenseMatrix & real()
Real or imaginary part accessor methods.
virtual DenseMatrix & imag()
std::complex< real_t > * data
void ComplexToReal(int m, const std::complex< real_t > *x, real_t *x_r, real_t *x_i) const
std::complex< real_t > * RealToComplex(int m, const real_t *x_r, const real_t *x_i) const
virtual void GetInverseMatrix(int m, real_t *X_r, real_t *X_i) const
Assuming L.U = P.A factored data of size (m x m), compute X <- A^{-1}.
void LSolve(int m, int n, real_t *X_r, real_t *X_i) const
void USolve(int m, int n, real_t *X_r, real_t *X_i) const
void RightSolve(int m, int n, real_t *X_r, real_t *X_i) const
virtual bool Factor(int m, real_t TOL=0.0)
Compute the LU factorization of the current matrix.
virtual void Solve(int m, int n, real_t *X_r, real_t *X_i) const
virtual std::complex< real_t > Det(int m) const
void Mult(int m, int n, real_t *X_r, real_t *X_i) const
bool hasRealPart() const
Check for existence of real or imaginary part of the operator.
@ HERMITIAN
Native convention for Hermitian operators.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
real_t * Data() const
Returns the matrix data array.
Definition densemat.hpp:111
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
void zgetrf_(int *, int *, std::complex< double > *, int *, int *, int *)
void ctrtrs_(char *, char *, char *, int *, int *, std::complex< float > *, int *, std::complex< float > *, int *, int *)
void cgetrf_(int *, int *, std::complex< float > *, int *, int *, int *)
void ztrsm_(char *, char *, char *, char *, int *, int *, std::complex< double > *, std::complex< double > *, int *, std::complex< double > *, int *)
void cpotrf_(char *, int *, std::complex< float > *, int *, int *)
void zpotri_(char *, int *, std::complex< double > *, int *, int *)
void zgetri_(int *, std::complex< double > *, int *, int *, std::complex< double > *, int *, int *)
void ztrtrs_(char *, char *, char *, int *, int *, std::complex< double > *, int *, std::complex< double > *, int *, int *)
void zpotrf_(char *, int *, std::complex< double > *, int *, int *)
void cpotri_(char *, int *, std::complex< float > *, int *, int *)
void cgetrs_(char *, int *, int *, std::complex< float > *, int *, int *, std::complex< float > *, int *, int *)
void ctrsm_(char *, char *, char *, char *, int *, int *, std::complex< float > *, std::complex< float > *, int *, std::complex< float > *, int *)
void cpotrs_(char *, int *, int *, std::complex< float > *, int *, std::complex< float > *, int *, int *)
void cgetri_(int *, std::complex< float > *, int *, int *, std::complex< float > *, int *, int *)
void zgetrs_(char *, int *, int *, std::complex< double > *, int *, int *, std::complex< double > *, int *, int *)
void zpotrs_(char *, int *, int *, std::complex< double > *, int *, std::complex< double > *, int *, int *)
const real_t alpha
Definition ex15.cpp:369
void trans(const Vector &u, Vector &x)
Definition ex27.cpp:412
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void Swap(Array< T > &, Array< T > &)
Definition array.hpp:648
void mfem_error(const char *msg)
Definition error.cpp:154
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:476
void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += alpha * B * C.
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
float real_t
Definition config.hpp:43
void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += B * C.
RefCoord s[3]