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