MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
densemat.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, 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
13// Implementation of data types dense matrix, inverse dense matrix
14
15
16#include "kernels.hpp"
17#include "vector.hpp"
18#include "matrix.hpp"
19#include "densemat.hpp"
20#include "lapack.hpp"
21#include "batched/batched.hpp"
22#include "../general/forall.hpp"
23#include "../general/table.hpp"
25
26#include <iostream>
27#include <iomanip>
28#include <limits>
29#include <algorithm>
30#include <cstdlib>
31#if defined(_MSC_VER) && (_MSC_VER < 1800)
32#include <float.h>
33#define copysign _copysign
34#endif
35
36
37namespace mfem
38{
39
40using namespace std;
41
43
45{
46 MFEM_ASSERT(s >= 0, "invalid DenseMatrix size: " << s);
47 if (s > 0)
48 {
49 data.SetSize(s*s);
50 *this = 0.0; // init with zeroes
51 }
52}
53
54DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n)
55{
56 MFEM_ASSERT(m >= 0 && n >= 0,
57 "invalid DenseMatrix size: " << m << " x " << n);
58 const int capacity = m*n;
59 if (capacity > 0)
60 {
61 data.SetSize(capacity);
62 *this = 0.0; // init with zeroes
63 }
64}
65
67 : Matrix(mat.width, mat.height)
68{
69 MFEM_CONTRACT_VAR(ch);
70 const int capacity = height*width;
71 if (capacity > 0)
72 {
73 data.SetSize(capacity);
74
75 for (int i = 0; i < height; i++)
76 {
77 for (int j = 0; j < width; j++)
78 {
79 (*this)(i,j) = mat(j,i);
80 }
81 }
82 }
83}
84
85void DenseMatrix::SetSize(int h, int w)
86{
87 MFEM_ASSERT(h >= 0 && w >= 0,
88 "invalid DenseMatrix size: " << h << " x " << w);
89 if (Height() == h && Width() == w)
90 {
91 return;
92 }
93 height = h;
94 width = w;
95 data.SetSize(h*w, 0.0);
96}
97
99{
100 return (*this)(i,j);
101}
102
103const real_t &DenseMatrix::Elem(int i, int j) const
104{
105 return (*this)(i,j);
106}
107
108void DenseMatrix::Mult(const real_t *x, real_t *y) const
109{
111}
112
113void DenseMatrix::Mult(const real_t *x, Vector &y) const
114{
115 MFEM_ASSERT(height == y.Size(), "incompatible dimensions");
116
117 Mult(x, y.HostWrite());
118}
119
120void DenseMatrix::Mult(const Vector &x, real_t *y) const
121{
122 MFEM_ASSERT(width == x.Size(), "incompatible dimensions");
123
124 Mult(x.HostRead(), y);
125}
126
127void DenseMatrix::Mult(const Vector &x, Vector &y) const
128{
129 MFEM_ASSERT(height == y.Size() && width == x.Size(),
130 "incompatible dimensions");
131
132 Mult(x.HostRead(), y.HostWrite());
133}
134
135void DenseMatrix::AbsMult(const Vector &x, Vector &y) const
136{
137 MFEM_ASSERT(height == y.Size() && width == x.Size(),
138 "incompatible dimensions");
139
141}
142
144{
145 MFEM_ASSERT(Height() == m.Height() && Width() == m.Width(),
146 "incompatible dimensions");
147
148 const int hw = height * width;
149 real_t a = 0.0;
150 for (int i = 0; i < hw; i++)
151 {
152 a += data[i] * m.data[i];
153 }
154
155 return a;
156}
157
159{
161}
162
164{
165 MFEM_ASSERT(width == y.Size(), "incompatible dimensions");
166
167 MultTranspose(x, y.HostWrite());
168}
169
171{
172 MFEM_ASSERT(height == x.Size(), "incompatible dimensions");
173
174 MultTranspose(x.HostRead(), y);
175}
176
178{
179 MFEM_ASSERT(height == x.Size() && width == y.Size(),
180 "incompatible dimensions");
181
183}
184
186{
187 MFEM_ASSERT(height == x.Size() && width == y.Size(),
188 "incompatible dimensions");
189
191 x.HostRead(), y.HostWrite());
192}
193
194void DenseMatrix::AddMult(const Vector &x, Vector &y, const real_t a) const
195{
196 if (a != 1.0)
197 {
198 AddMult_a(a, x, y);
199 return;
200 }
201 MFEM_ASSERT(height == y.Size() && width == x.Size(),
202 "incompatible dimensions");
203
204 const real_t *xp = x.GetData(), *d_col = data;
205 real_t *yp = y.GetData();
206 for (int col = 0; col < width; col++)
207 {
208 real_t x_col = xp[col];
209 for (int row = 0; row < height; row++)
210 {
211 yp[row] += x_col*d_col[row];
212 }
213 d_col += height;
214 }
215}
216
218 const real_t a) const
219{
220 if (a != 1.0)
221 {
222 AddMultTranspose_a(a, x, y);
223 return;
224 }
225 MFEM_ASSERT(height == x.Size() && width == y.Size(),
226 "incompatible dimensions");
227
228 const real_t *d_col = data;
229 for (int col = 0; col < width; col++)
230 {
231 real_t y_col = 0.0;
232 for (int row = 0; row < height; row++)
233 {
234 y_col += x[row]*d_col[row];
235 }
236 y[col] += y_col;
237 d_col += height;
238 }
239}
240
241void DenseMatrix::AddMult_a(real_t a, const Vector &x, Vector &y) const
242{
243 MFEM_ASSERT(height == y.Size() && width == x.Size(),
244 "incompatible dimensions");
245
246 HostRead();
247 x.HostRead();
248 y.HostReadWrite();
249 const real_t *xp = x.GetData(), *d_col = data;
250 real_t *yp = y.GetData();
251 for (int col = 0; col < width; col++)
252 {
253 const real_t x_col = a*xp[col];
254 for (int row = 0; row < height; row++)
255 {
256 yp[row] += x_col*d_col[row];
257 }
258 d_col += height;
259 }
260}
261
263 Vector &y) const
264{
265 MFEM_ASSERT(height == x.Size() && width == y.Size(),
266 "incompatible dimensions");
267
268 const real_t *d_col = data;
269 for (int col = 0; col < width; col++)
270 {
271 real_t y_col = 0.0;
272 for (int row = 0; row < height; row++)
273 {
274 y_col += x[row]*d_col[row];
275 }
276 y[col] += a * y_col;
277 d_col += height;
278 }
279}
280
282{
283 real_t prod = 0.0;
284
285 for (int i = 0; i < height; i++)
286 {
287 real_t Axi = 0.0;
288 for (int j = 0; j < width; j++)
289 {
290 Axi += (*this)(i,j) * x[j];
291 }
292 prod += y[i] * Axi;
293 }
294
295 return prod;
296}
297
298// LeftScaling this = diag(s) * this
300{
301 real_t * it_data = data;
302 for (int j = 0; j < width; ++j)
303 {
304 for (int i = 0; i < height; ++i)
305 {
306 *(it_data++) *= s(i);
307 }
308 }
309}
310
311// InvLeftScaling this = diag(1./s) * this
313{
314 real_t * it_data = data;
315 for (int j = 0; j < width; ++j)
316 {
317 for (int i = 0; i < height; ++i)
318 {
319 *(it_data++) /= s(i);
320 }
321 }
322}
323
324// RightScaling: this = this * diag(s);
326{
327 real_t sj;
328 real_t * it_data = data;
329 for (int j = 0; j < width; ++j)
330 {
331 sj = s(j);
332 for (int i = 0; i < height; ++i)
333 {
334 *(it_data++) *= sj;
335 }
336 }
337}
338
339// InvRightScaling: this = this * diag(1./s);
341{
342 real_t * it_data = data;
343 for (int j = 0; j < width; ++j)
344 {
345 const real_t sj = 1./s(j);
346 for (int i = 0; i < height; ++i)
347 {
348 *(it_data++) *= sj;
349 }
350 }
351}
352
353// SymmetricScaling this = diag(sqrt(s)) * this * diag(sqrt(s))
355{
356 if (height != width || s.Size() != height)
357 {
358 mfem_error("DenseMatrix::SymmetricScaling: dimension mismatch");
359 }
360
361 real_t * ss = new real_t[width];
362 real_t * it_s = s.GetData();
363 real_t * it_ss = ss;
364 for ( real_t * end_s = it_s + width; it_s != end_s; ++it_s)
365 {
366 *(it_ss++) = sqrt(*it_s);
367 }
368
369 real_t * it_data = data;
370 for (int j = 0; j < width; ++j)
371 {
372 for (int i = 0; i < height; ++i)
373 {
374 *(it_data++) *= ss[i]*ss[j];
375 }
376 }
377
378 delete[] ss;
379}
380
381// InvSymmetricScaling this = diag(sqrt(1./s)) * this * diag(sqrt(1./s))
383{
384 if (height != width || s.Size() != width)
385 {
386 mfem_error("DenseMatrix::InvSymmetricScaling: dimension mismatch");
387 }
388
389 real_t * ss = new real_t[width];
390 real_t * it_s = s.GetData();
391 real_t * it_ss = ss;
392 for (real_t * end_s = it_s + width; it_s != end_s; ++it_s)
393 {
394 *(it_ss++) = 1./sqrt(*it_s);
395 }
396
397 real_t * it_data = data;
398 for (int j = 0; j < width; ++j)
399 {
400 for (int i = 0; i < height; ++i)
401 {
402 *(it_data++) *= ss[i]*ss[j];
403 }
404 }
405
406 delete[] ss;
407}
408
410{
411#ifdef MFEM_DEBUG
412 if (Width() != Height())
413 {
414 mfem_error("DenseMatrix::Trace() : not a square matrix!");
415 }
416#endif
417
418 real_t t = 0.0;
419
420 for (int i = 0; i < width; i++)
421 {
422 t += (*this)(i, i);
423 }
424
425 return t;
426}
427
429{
430 return new DenseMatrixInverse(*this);
431}
432
434{
435 MFEM_ASSERT(Height() == Width() && Height() <= 2,
436 "The matrix must be square and "
437 << "of size less than or equal to 2."
438 << " Height() = " << Height()
439 << ", Width() = " << Width());
440
441 switch (Height())
442 {
443 case 1:
444 {
445 data[0] = std::exp(data[0]);
446 break;
447 }
448 case 2:
449 {
450 /// Formulas from Corollary 2.4 of doi:10.1109/9.233156
451 /// Note typo in the paper, in the prefactor in the equation under (i).
452 const real_t a = data[0];
453 const real_t b = data[1];
454 const real_t c = data[2];
455 const real_t d = data[3];
456 const real_t e = (a - d)*(a - d) + 4*b*c;
457 const real_t f = std::exp((a + d)/2.0);
458 const real_t g = std::sqrt(std::abs(e)) / 2.0;
459
460 if (e == 0)
461 {
462 data[0] = 1.0 + (a - d)/2.0;
463 data[3] = 1.0 - (a - d)/2.0;
464 }
465 else if (e > 0)
466 {
467 data[0] = std::cosh(g) + (a - d)/2 * std::sinh(g) / g;
468 data[1] = b * std::sinh(g) / g;
469 data[2] = c * std::sinh(g) / g;
470 data[3] = std::cosh(g) - (a - d)/2 * std::sinh(g) / g;
471 }
472 else
473 {
474 data[0] = std::cos(g) + (a - d)/2 * std::sin(g) / g;
475 data[1] = b * std::sin(g) / g;
476 data[2] = c * std::sin(g) / g;
477 data[3] = std::cos(g) - (a - d)/2 * std::sin(g) / g;
478 }
479 for (int i = 0; i < 4; i++)
480 {
481 data[i] *= f;
482 }
483 break;
484 }
485 case 3:
486 {
487 MFEM_ABORT("3x3 matrices are not currently supported");
488 }
489 default:
490 {
491 MFEM_ABORT("Only 1x1 and 2x2 matrices are currently supported");
492 }
493 }
494}
495
497{
498 MFEM_ASSERT(Height() == Width() && Height() > 0,
499 "The matrix must be square and "
500 << "sized larger than zero to compute the determinant."
501 << " Height() = " << Height()
502 << ", Width() = " << Width());
503
504 switch (Height())
505 {
506 case 1:
507 return data[0];
508
509 case 2:
510 return data[0] * data[3] - data[1] * data[2];
511
512 case 3:
513 {
514 const real_t *d = data;
515 return
516 d[0] * (d[4] * d[8] - d[5] * d[7]) +
517 d[3] * (d[2] * d[7] - d[1] * d[8]) +
518 d[6] * (d[1] * d[5] - d[2] * d[4]);
519 }
520 case 4:
521 {
522 const real_t *d = data;
523 return
524 d[ 0] * (d[ 5] * (d[10] * d[15] - d[11] * d[14]) -
525 d[ 9] * (d[ 6] * d[15] - d[ 7] * d[14]) +
526 d[13] * (d[ 6] * d[11] - d[ 7] * d[10])
527 ) -
528 d[ 4] * (d[ 1] * (d[10] * d[15] - d[11] * d[14]) -
529 d[ 9] * (d[ 2] * d[15] - d[ 3] * d[14]) +
530 d[13] * (d[ 2] * d[11] - d[ 3] * d[10])
531 ) +
532 d[ 8] * (d[ 1] * (d[ 6] * d[15] - d[ 7] * d[14]) -
533 d[ 5] * (d[ 2] * d[15] - d[ 3] * d[14]) +
534 d[13] * (d[ 2] * d[ 7] - d[ 3] * d[ 6])
535 ) -
536 d[12] * (d[ 1] * (d[ 6] * d[11] - d[ 7] * d[10]) -
537 d[ 5] * (d[ 2] * d[11] - d[ 3] * d[10]) +
538 d[ 9] * (d[ 2] * d[ 7] - d[ 3] * d[ 6])
539 );
540 }
541 default:
542 {
543 // In the general case we compute the determinant from the LU
544 // decomposition.
545 DenseMatrixInverse lu_factors(*this);
546
547 return lu_factors.Det();
548 }
549 }
550 // not reachable
551}
552
554{
555 if (Height() == Width())
556 {
557 // return fabs(Det());
558 return Det();
559 }
560 else if ((Height() == 2) && (Width() == 1))
561 {
562 return sqrt(data[0] * data[0] + data[1] * data[1]);
563 }
564 else if ((Height() == 3) && (Width() == 1))
565 {
566 return sqrt(data[0] * data[0] + data[1] * data[1] + data[2] * data[2]);
567 }
568 else if ((Height() == 3) && (Width() == 2))
569 {
570 const real_t *d = data;
571 real_t E = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
572 real_t G = d[3] * d[3] + d[4] * d[4] + d[5] * d[5];
573 real_t F = d[0] * d[3] + d[1] * d[4] + d[2] * d[5];
574 return sqrt(E * G - F * F);
575 }
576 mfem_error("DenseMatrix::Weight(): mismatched or unsupported dimensions");
577 return 0.0;
578}
579
581{
582 const int s = Width()*Height();
583 for (int i = 0; i < s; i++)
584 {
585 data[i] = alpha*A[i];
586 }
587}
588
589void DenseMatrix::Add(const real_t c, const DenseMatrix &A)
590{
591 for (int j = 0; j < Width(); j++)
592 {
593 for (int i = 0; i < Height(); i++)
594 {
595 (*this)(i,j) += c * A(i,j);
596 }
597 }
598}
599
600void DenseMatrix::Add(const real_t c, const real_t *A)
601{
602 const int s = Width()*Height();
603 for (int i = 0; i < s; i++)
604 {
605 data[i] += c*A[i];
606 }
607}
608
610{
611 const int s = Height()*Width();
612 for (int i = 0; i < s; i++)
613 {
614 data[i] = c;
615 }
616 return *this;
617}
618
620{
621 const int s = Height()*Width();
622 for (int i = 0; i < s; i++)
623 {
624 data[i] = d[i];
625 }
626 return *this;
627}
628
630{
631 kernels::Add(Height(), Width(), m, (real_t*)data);
632 return *this;
633}
634
636{
637 MFEM_ASSERT(Height() == m.Height() && Width() == m.Width(),
638 "incompatible matrix sizes.");
639 return *this += m.GetData();
640}
641
643{
644 for (int j = 0; j < width; j++)
645 {
646 for (int i = 0; i < height; i++)
647 {
648 (*this)(i, j) -= m(i, j);
649 }
650 }
651
652 return *this;
653}
654
656{
657 int s = Height()*Width();
658 for (int i = 0; i < s; i++)
659 {
660 data[i] *= c;
661 }
662 return *this;
663}
664
666{
667 const int hw = Height() * Width();
668 for (int i = 0; i < hw; i++)
669 {
670 data[i] = -data[i];
671 }
672}
673
675{
676#ifdef MFEM_DEBUG
677 if (Height() <= 0 || Height() != Width())
678 {
679 mfem_error("DenseMatrix::Invert(): dimension mismatch");
680 }
681#endif
682
683#ifdef MFEM_USE_LAPACK
684 int *ipiv = new int[width];
685 int lwork = -1;
686 real_t qwork, *work;
687 int info;
688
689 MFEM_LAPACK_PREFIX(getrf_)(&width, &width, data, &width, ipiv, &info);
690
691 if (info)
692 {
693 mfem_error("DenseMatrix::Invert() : Error in DGETRF");
694 }
695
696 MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, &qwork, &lwork, &info);
697
698 lwork = (int) qwork;
699 work = new real_t[lwork];
700
701 MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, work, &lwork, &info);
702
703 if (info)
704 {
705 mfem_error("DenseMatrix::Invert() : Error in DGETRI");
706 }
707
708 delete [] work;
709 delete [] ipiv;
710#else
711 int c, i, j, n = Width();
712 real_t a, b;
713 Array<int> piv(n);
714
715 for (c = 0; c < n; c++)
716 {
717 a = fabs((*this)(c, c));
718 i = c;
719 for (j = c + 1; j < n; j++)
720 {
721 b = fabs((*this)(j, c));
722 if (a < b)
723 {
724 a = b;
725 i = j;
726 }
727 }
728 if (a == 0.0)
729 {
730 mfem_error("DenseMatrix::Invert() : singular matrix");
731 }
732 piv[c] = i;
733 for (j = 0; j < n; j++)
734 {
735 mfem::Swap<real_t>((*this)(c, j), (*this)(i, j));
736 }
737
738 a = (*this)(c, c) = 1.0 / (*this)(c, c);
739 for (j = 0; j < c; j++)
740 {
741 (*this)(c, j) *= a;
742 }
743 for (j++; j < n; j++)
744 {
745 (*this)(c, j) *= a;
746 }
747 for (i = 0; i < c; i++)
748 {
749 (*this)(i, c) = a * (b = -(*this)(i, c));
750 for (j = 0; j < c; j++)
751 {
752 (*this)(i, j) += b * (*this)(c, j);
753 }
754 for (j++; j < n; j++)
755 {
756 (*this)(i, j) += b * (*this)(c, j);
757 }
758 }
759 for (i++; i < n; i++)
760 {
761 (*this)(i, c) = a * (b = -(*this)(i, c));
762 for (j = 0; j < c; j++)
763 {
764 (*this)(i, j) += b * (*this)(c, j);
765 }
766 for (j++; j < n; j++)
767 {
768 (*this)(i, j) += b * (*this)(c, j);
769 }
770 }
771 }
772
773 for (c = n - 1; c >= 0; c--)
774 {
775 j = piv[c];
776 for (i = 0; i < n; i++)
777 {
778 mfem::Swap<real_t>((*this)(i, c), (*this)(i, j));
779 }
780 }
781#endif
782}
783
785{
786 // Square root inverse using Denman--Beavers
787#ifdef MFEM_DEBUG
788 if (Height() <= 0 || Height() != Width())
789 {
790 mfem_error("DenseMatrix::SquareRootInverse() matrix not square.");
791 }
792#endif
793
794 DenseMatrix tmp1(Height());
795 DenseMatrix tmp2(Height());
796 DenseMatrix tmp3(Height());
797
798 tmp1 = (*this);
799 (*this) = 0.0;
800 for (int v = 0; v < Height() ; v++) { (*this)(v,v) = 1.0; }
801
802 for (int j = 0; j < 10; j++)
803 {
804 for (int i = 0; i < 10; i++)
805 {
806 tmp2 = tmp1;
807 tmp3 = (*this);
808
809 tmp2.Invert();
810 tmp3.Invert();
811
812 tmp1 += tmp3;
813 (*this) += tmp2;
814
815 tmp1 *= 0.5;
816 (*this) *= 0.5;
817 }
818 mfem::Mult((*this), tmp1, tmp2);
819 for (int v = 0; v < Height() ; v++) { tmp2(v,v) -= 1.0; }
820 if (tmp2.FNorm() < 1e-10) { break; }
821 }
822
823 if (tmp2.FNorm() > 1e-10)
824 {
825 mfem_error("DenseMatrix::SquareRootInverse not converged");
826 }
827}
828
830{
831 for (int j = 0; j < Width(); j++)
832 {
833 v[j] = 0.0;
834 for (int i = 0; i < Height(); i++)
835 {
836 v[j] += (*this)(i,j)*(*this)(i,j);
837 }
838 v[j] = sqrt(v[j]);
839 }
840}
841
843{
844 int hw = Height()*Width();
845 const real_t *d = data;
846 real_t norm = 0.0, abs_entry;
847
848 for (int i = 0; i < hw; i++)
849 {
850 abs_entry = fabs(d[i]);
851 if (norm < abs_entry)
852 {
853 norm = abs_entry;
854 }
855 }
856
857 return norm;
858}
859
860void DenseMatrix::FNorm(real_t &scale_factor, real_t &scaled_fnorm2) const
861{
862 int i, hw = Height() * Width();
863 real_t max_norm = 0.0, entry, fnorm2;
864
865 for (i = 0; i < hw; i++)
866 {
867 entry = fabs(data[i]);
868 if (entry > max_norm)
869 {
870 max_norm = entry;
871 }
872 }
873
874 if (max_norm == 0.0)
875 {
876 scale_factor = scaled_fnorm2 = 0.0;
877 return;
878 }
879
880 fnorm2 = 0.0;
881 for (i = 0; i < hw; i++)
882 {
883 entry = data[i] / max_norm;
884 fnorm2 += entry * entry;
885 }
886
887 scale_factor = max_norm;
888 scaled_fnorm2 = fnorm2;
889}
890
892{
893#ifdef MFEM_USE_LAPACK
894 ev.SetSize(a.Width());
895
896 char JOBZ = 'N';
897 char RANGE = 'A';
898 char UPLO = 'U';
899 int N = a.Width();
900 real_t *A = new real_t[N*N];
901 int LDA = N;
902 real_t VL = 0.0;
903 real_t VU = 1.0;
904 int IL = 0;
905 int IU = 1;
906 real_t ABSTOL = 0.0;
907 int M;
908 real_t *W = ev.GetData();
909 real_t *Z = NULL;
910 int LDZ = 1;
911 int *ISUPPZ = new int[2*N];
912 int LWORK = -1; // query optimal (double) workspace size
913 real_t QWORK;
914 real_t *WORK = NULL;
915 int LIWORK = -1; // query optimal (int) workspace size
916 int QIWORK;
917 int *IWORK = NULL;
918 int INFO;
919
920 if (evect) // Compute eigenvectors too
921 {
922 evect->SetSize(N);
923
924 JOBZ = 'V';
925 Z = evect->Data();
926 LDZ = N;
927 }
928
929 int hw = a.Height() * a.Width();
930 real_t *data = a.Data();
931
932 for (int i = 0; i < hw; i++)
933 {
934 A[i] = data[i];
935 }
936
937 MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
938 &IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK,
939 &LWORK, &QIWORK, &LIWORK, &INFO);
940
941 LWORK = (int) QWORK;
942 LIWORK = QIWORK;
943
944 WORK = new real_t[LWORK];
945 IWORK = new int[LIWORK];
946
947 MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
948 &IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK,
949 &LWORK, IWORK, &LIWORK, &INFO);
950
951 if (INFO != 0)
952 {
953 mfem::err << "dsyevr_Eigensystem(...): DSYEVR error code: "
954 << INFO << endl;
955 mfem_error();
956 }
957
958#ifdef MFEM_DEBUG
959 if (M < N)
960 {
961 mfem::err << "dsyevr_Eigensystem(...):\n"
962 << " DSYEVR did not find all eigenvalues "
963 << M << "/" << N << endl;
964 mfem_error();
965 }
966 if (CheckFinite(W, N) > 0)
967 {
968 mfem_error("dsyevr_Eigensystem(...): inf/nan values in W");
969 }
970 if (CheckFinite(Z, N*N) > 0)
971 {
972 mfem_error("dsyevr_Eigensystem(...): inf/nan values in Z");
973 }
974 VU = 0.0;
975 for (IL = 0; IL < N; IL++)
976 for (IU = 0; IU <= IL; IU++)
977 {
978 VL = 0.0;
979 for (M = 0; M < N; M++)
980 {
981 VL += Z[M+IL*N] * Z[M+IU*N];
982 }
983 if (IU < IL)
984 {
985 VL = fabs(VL);
986 }
987 else
988 {
989 VL = fabs(VL-1.0);
990 }
991 if (VL > VU)
992 {
993 VU = VL;
994 }
995 if (VU > 0.5)
996 {
997 mfem::err << "dsyevr_Eigensystem(...):"
998 << " Z^t Z - I deviation = " << VU
999 << "\n W[max] = " << W[N-1] << ", W[min] = "
1000 << W[0] << ", N = " << N << endl;
1001 mfem_error();
1002 }
1003 }
1004 if (VU > 1e-9)
1005 {
1006 mfem::err << "dsyevr_Eigensystem(...):"
1007 << " Z^t Z - I deviation = " << VU
1008 << "\n W[max] = " << W[N-1] << ", W[min] = "
1009 << W[0] << ", N = " << N << endl;
1010 }
1011 if (VU > 1e-5)
1012 {
1013 mfem_error("dsyevr_Eigensystem(...): ERROR: ...");
1014 }
1015 VU = 0.0;
1016 for (IL = 0; IL < N; IL++)
1017 for (IU = 0; IU < N; IU++)
1018 {
1019 VL = 0.0;
1020 for (M = 0; M < N; M++)
1021 {
1022 VL += Z[IL+M*N] * W[M] * Z[IU+M*N];
1023 }
1024 VL = fabs(VL-data[IL+N*IU]);
1025 if (VL > VU)
1026 {
1027 VU = VL;
1028 }
1029 }
1030 if (VU > 1e-9)
1031 {
1032 mfem::err << "dsyevr_Eigensystem(...):"
1033 << " max matrix deviation = " << VU
1034 << "\n W[max] = " << W[N-1] << ", W[min] = "
1035 << W[0] << ", N = " << N << endl;
1036 }
1037 if (VU > 1e-5)
1038 {
1039 mfem_error("dsyevr_Eigensystem(...): ERROR: ...");
1040 }
1041#endif
1042
1043 delete [] IWORK;
1044 delete [] WORK;
1045 delete [] ISUPPZ;
1046 delete [] A;
1047#else
1048 MFEM_CONTRACT_VAR(a);
1049 MFEM_CONTRACT_VAR(ev);
1050 MFEM_CONTRACT_VAR(evect);
1051#endif
1052}
1053
1055{
1056#ifdef MFEM_USE_LAPACK
1057 int N = a.Width();
1058 char JOBZ = 'N';
1059 char UPLO = 'U';
1060 int LDA = N;
1061 int LWORK = -1; /* query optimal workspace size */
1062 int INFO;
1063
1064 ev.SetSize(N);
1065
1066 real_t *A = NULL;
1067 real_t *W = ev.GetData();
1068 real_t *WORK = NULL;
1069 real_t QWORK;
1070
1071 if (evect)
1072 {
1073 JOBZ = 'V';
1074 evect->SetSize(N);
1075 A = evect->Data();
1076 }
1077 else
1078 {
1079 A = new real_t[N*N];
1080 }
1081
1082 int hw = a.Height() * a.Width();
1083 real_t *data = a.Data();
1084 for (int i = 0; i < hw; i++)
1085 {
1086 A[i] = data[i];
1087 }
1088
1089 MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
1090
1091 LWORK = (int) QWORK;
1092 WORK = new real_t[LWORK];
1093
1094 MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
1095
1096 if (INFO != 0)
1097 {
1098 mfem::err << "dsyev_Eigensystem: DSYEV error code: " << INFO << endl;
1099 mfem_error();
1100 }
1101
1102 delete [] WORK;
1103 if (evect == NULL) { delete [] A; }
1104#else
1105 MFEM_CONTRACT_VAR(a);
1106 MFEM_CONTRACT_VAR(ev);
1107 MFEM_CONTRACT_VAR(evect);
1108#endif
1109}
1110
1111void DenseMatrix::Eigensystem(Vector &ev, DenseMatrix *evect)
1112{
1113#ifdef MFEM_USE_LAPACK
1114
1115 // dsyevr_Eigensystem(*this, ev, evect);
1116
1117 dsyev_Eigensystem(*this, ev, evect);
1118
1119#else
1120
1121 MFEM_CONTRACT_VAR(ev);
1122 MFEM_CONTRACT_VAR(evect);
1123 mfem_error("DenseMatrix::Eigensystem: Compiled without LAPACK");
1124
1125#endif
1126}
1127
1129 DenseMatrix *evect)
1130{
1131#ifdef MFEM_USE_LAPACK
1132 int N = a.Width();
1133 int ITYPE = 1;
1134 char JOBZ = 'N';
1135 char UPLO = 'U';
1136 int LDA = N;
1137 int LDB = N;
1138 int LWORK = -1; /* query optimal workspace size */
1139 int INFO;
1140
1141 ev.SetSize(N);
1142
1143 real_t *A = NULL;
1144 real_t *B = new real_t[N*N];
1145 real_t *W = ev.GetData();
1146 real_t *WORK = NULL;
1147 real_t QWORK;
1148
1149 if (evect)
1150 {
1151 JOBZ = 'V';
1152 evect->SetSize(N);
1153 A = evect->Data();
1154 }
1155 else
1156 {
1157 A = new real_t[N*N];
1158 }
1159
1160 int hw = a.Height() * a.Width();
1161 real_t *a_data = a.Data();
1162 real_t *b_data = b.Data();
1163 for (int i = 0; i < hw; i++)
1164 {
1165 A[i] = a_data[i];
1166 B[i] = b_data[i];
1167 }
1168
1169 MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W,
1170 &QWORK, &LWORK, &INFO);
1171
1172 LWORK = (int) QWORK;
1173 WORK = new real_t[LWORK];
1174
1175 MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK,
1176 &LWORK, &INFO);
1177
1178 if (INFO != 0)
1179 {
1180 mfem::err << "dsygv_Eigensystem: DSYGV error code: " << INFO << endl;
1181 mfem_error();
1182 }
1183
1184 delete [] WORK;
1185 delete [] B;
1186 if (evect == NULL) { delete [] A; }
1187#else
1188 MFEM_CONTRACT_VAR(a);
1189 MFEM_CONTRACT_VAR(b);
1190 MFEM_CONTRACT_VAR(ev);
1191 MFEM_CONTRACT_VAR(evect);
1192#endif
1193}
1194
1195void DenseMatrix::Eigensystem(DenseMatrix &b, Vector &ev,
1196 DenseMatrix *evect)
1197{
1198#ifdef MFEM_USE_LAPACK
1199
1200 dsygv_Eigensystem(*this, b, ev, evect);
1201
1202#else
1203 MFEM_CONTRACT_VAR(b);
1204 MFEM_CONTRACT_VAR(ev);
1205 MFEM_CONTRACT_VAR(evect);
1206 mfem_error("DenseMatrix::Eigensystem(generalized): Compiled without LAPACK");
1207#endif
1208}
1209
1211{
1212#ifdef MFEM_USE_LAPACK
1213 DenseMatrix copy_of_this = *this;
1214 char jobu = 'N';
1215 char jobvt = 'N';
1216 int m = Height();
1217 int n = Width();
1218 real_t *a = copy_of_this.data;
1219 sv.SetSize(min(m, n));
1220 real_t *s = sv.GetData();
1221 real_t *u = NULL;
1222 real_t *vt = NULL;
1223 real_t *work = NULL;
1224 int lwork = -1;
1225 int info;
1226 real_t qwork;
1227
1228 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
1229 &qwork, &lwork, &info);
1230
1231 lwork = (int) qwork;
1232 work = new real_t[lwork];
1233
1234 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
1235 work, &lwork, &info);
1236
1237 delete [] work;
1238 if (info)
1239 {
1240 mfem::err << "DenseMatrix::SingularValues : info = " << info << endl;
1241 mfem_error();
1242 }
1243#else
1244 MFEM_CONTRACT_VAR(sv);
1245 // compiling without lapack
1246 mfem_error("DenseMatrix::SingularValues: Compiled without LAPACK");
1247#endif
1248}
1249
1251{
1252 int rank=0;
1253 Vector sv(min(Height(), Width()));
1254 SingularValues(sv);
1255
1256 for (int i=0; i < sv.Size(); ++i)
1257 if (sv(i) >= tol)
1258 {
1259 ++rank;
1260 }
1261
1262 return rank;
1263}
1264
1266{
1267 MFEM_ASSERT(Height() == Width() && Height() > 0 && Height() < 4,
1268 "The matrix must be square and sized 1, 2, or 3 to compute the"
1269 " singular values."
1270 << " Height() = " << Height()
1271 << ", Width() = " << Width());
1272
1273 const int n = Height();
1274 const real_t *d = data;
1275
1276 if (n == 1)
1277 {
1278 return d[0];
1279 }
1280 else if (n == 2)
1281 {
1283 }
1284 else
1285 {
1287 }
1288}
1289
1291{
1292#ifdef MFEM_DEBUG
1293 if (Height() != Width() || Height() < 2 || Height() > 3)
1294 {
1295 mfem_error("DenseMatrix::CalcEigenvalues");
1296 }
1297#endif
1298
1299 const int n = Height();
1300 const real_t *d = data;
1301
1302 if (n == 2)
1303 {
1304 kernels::CalcEigenvalues<2>(d, lambda, vec);
1305 }
1306 else
1307 {
1308 kernels::CalcEigenvalues<3>(d, lambda, vec);
1309 }
1310}
1311
1312void DenseMatrix::GetRow(int r, Vector &row) const
1313{
1314 int m = Height();
1315 int n = Width();
1316 row.SetSize(n);
1317
1318 const real_t* rp = data + r;
1319 real_t* vp = row.GetData();
1320
1321 for (int i = 0; i < n; i++)
1322 {
1323 vp[i] = *rp;
1324 rp += m;
1325 }
1326}
1327
1328void DenseMatrix::GetColumn(int c, Vector &col) const
1329{
1330 int m = Height();
1331 col.SetSize(m);
1332
1333 real_t *cp = Data() + c * m;
1334 real_t *vp = col.GetData();
1335
1336 for (int i = 0; i < m; i++)
1337 {
1338 vp[i] = cp[i];
1339 }
1340}
1341
1343{
1344 if (height != width)
1345 {
1346 mfem_error("DenseMatrix::GetDiag\n");
1347 }
1348 d.SetSize(height);
1349
1350 for (int i = 0; i < height; ++i)
1351 {
1352 d(i) = (*this)(i,i);
1353 }
1354}
1355
1357{
1358 if (height != width)
1359 {
1360 mfem_error("DenseMatrix::Getl1Diag\n");
1361 }
1362 l.SetSize(height);
1363
1364 l = 0.0;
1365
1366 for (int j = 0; j < width; ++j)
1367 for (int i = 0; i < height; ++i)
1368 {
1369 l(i) += fabs((*this)(i,j));
1370 }
1371}
1372
1374{
1375 l.SetSize(height);
1376 l = 0.0;
1377
1378 for (int j = 0; j < width; ++j)
1379 for (int i = 0; i < height; ++i)
1380 {
1381 l(i) += fabs((*this)(i,j));
1382 }
1383}
1384
1386{
1387 l.SetSize(height);
1388 l = 0.0;
1389
1390 for (int j = 0; j < width; ++j)
1391 for (int i = 0; i < height; ++i)
1392 {
1393 l[i] += operator()(i,j)*operator()(i,j);
1394 }
1395
1396 for (int i = 0; i < height; ++i)
1397 {
1398 l[i] = sqrt(l[i]);
1399 }
1400}
1401
1403{
1404 l.SetSize(height);
1405 for (int i = 0; i < height; i++)
1406 {
1407 real_t d = 0.0;
1408 for (int j = 0; j < width; j++)
1409 {
1410 d += operator()(i, j);
1411 }
1412 l(i) = d;
1413 }
1414}
1415
1417{
1418 SetSize(n);
1419
1420 const int N = n*n;
1421 for (int i = 0; i < N; i++)
1422 {
1423 data[i] = 0.0;
1424 }
1425 for (int i = 0; i < n; i++)
1426 {
1427 data[i*(n+1)] = c;
1428 }
1429}
1430
1431void DenseMatrix::Diag(real_t *diag, int n)
1432{
1433 SetSize(n);
1434
1435 int i, N = n*n;
1436 for (i = 0; i < N; i++)
1437 {
1438 data[i] = 0.0;
1439 }
1440 for (i = 0; i < n; i++)
1441 {
1442 data[i*(n+1)] = diag[i];
1443 }
1444}
1445
1447{
1448 int i, j;
1449 real_t t;
1450
1451 if (Width() == Height())
1452 {
1453 for (i = 0; i < Height(); i++)
1454 for (j = i+1; j < Width(); j++)
1455 {
1456 t = (*this)(i,j);
1457 (*this)(i,j) = (*this)(j,i);
1458 (*this)(j,i) = t;
1459 }
1460 }
1461 else
1462 {
1463 DenseMatrix T(*this,'t');
1464 (*this) = T;
1465 }
1466}
1467
1469{
1470 SetSize(A.Width(),A.Height());
1471
1472 for (int i = 0; i < Height(); i++)
1473 for (int j = 0; j < Width(); j++)
1474 {
1475 (*this)(i,j) = A(j,i);
1476 }
1477}
1478
1480{
1481#ifdef MFEM_DEBUG
1482 if (Width() != Height())
1483 {
1484 mfem_error("DenseMatrix::Symmetrize() : not a square matrix!");
1485 }
1486#endif
1488}
1489
1491{
1492 for (int i = 0; i < Height(); i++)
1493 {
1494 real_t L = 0.0;
1495 for (int j = 0; j < Width(); j++)
1496 {
1497 L += (*this)(i, j);
1498 (*this)(i, j) = 0.0;
1499 }
1500 (*this)(i, i) = L;
1501 }
1502}
1503
1505{
1506 int n = Height();
1507
1508#ifdef MFEM_DEBUG
1509 if ((Width() != 2 || curl.Width() != 1 || 2*n != curl.Height()) &&
1510 (Width() != 3 || curl.Width() != 3 || 3*n != curl.Height()))
1511 {
1512 mfem_error("DenseMatrix::GradToCurl(...): dimension mismatch");
1513 }
1514#endif
1515
1516 if (Width() == 2)
1517 {
1518 for (int i = 0; i < n; i++)
1519 {
1520 // (x,y) is grad of Ui
1521 real_t x = (*this)(i,0);
1522 real_t y = (*this)(i,1);
1523
1524 int j = i+n;
1525
1526 // curl of (Ui,0)
1527 curl(i,0) = -y;
1528
1529 // curl of (0,Ui)
1530 curl(j,0) = x;
1531 }
1532 }
1533 else
1534 {
1535 for (int i = 0; i < n; i++)
1536 {
1537 // (x,y,z) is grad of Ui
1538 real_t x = (*this)(i,0);
1539 real_t y = (*this)(i,1);
1540 real_t z = (*this)(i,2);
1541
1542 int j = i+n;
1543 int k = j+n;
1544
1545 // curl of (Ui,0,0)
1546 curl(i,0) = 0.;
1547 curl(i,1) = z;
1548 curl(i,2) = -y;
1549
1550 // curl of (0,Ui,0)
1551 curl(j,0) = -z;
1552 curl(j,1) = 0.;
1553 curl(j,2) = x;
1554
1555 // curl of (0,0,Ui)
1556 curl(k,0) = y;
1557 curl(k,1) = -x;
1558 curl(k,2) = 0.;
1559 }
1560 }
1561}
1562
1564{
1565 MFEM_VERIFY(Width() == 2,
1566 "DenseMatrix::GradToVectorCurl2D(...): dimension must be 2")
1567
1568 int n = Height();
1569 // rotate gradient
1570 for (int i = 0; i < n; i++)
1571 {
1572 curl(i,0) = (*this)(i,1);
1573 curl(i,1) = -(*this)(i,0);
1574 }
1575}
1576
1578{
1579 MFEM_ASSERT(Width()*Height() == div.Size(), "incompatible Vector 'div'!");
1580
1581 // div(dof*j+i) <-- (*this)(i,j)
1582
1583 const int n = height * width;
1584 real_t *ddata = div.GetData();
1585
1586 for (int i = 0; i < n; i++)
1587 {
1588 ddata[i] = data[i];
1589 }
1590}
1591
1592void DenseMatrix::CopyRows(const DenseMatrix &A, int row1, int row2)
1593{
1594 SetSize(row2 - row1 + 1, A.Width());
1595
1596 for (int j = 0; j < Width(); j++)
1597 {
1598 for (int i = row1; i <= row2; i++)
1599 {
1600 (*this)(i-row1,j) = A(i,j);
1601 }
1602 }
1603}
1604
1605void DenseMatrix::CopyCols(const DenseMatrix &A, int col1, int col2)
1606{
1607 SetSize(A.Height(), col2 - col1 + 1);
1608
1609 for (int j = col1; j <= col2; j++)
1610 {
1611 for (int i = 0; i < Height(); i++)
1612 {
1613 (*this)(i,j-col1) = A(i,j);
1614 }
1615 }
1616}
1617
1618void DenseMatrix::CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
1619{
1620 SetSize(m,n);
1621
1622 for (int j = 0; j < n; j++)
1623 {
1624 for (int i = 0; i < m; i++)
1625 {
1626 (*this)(i,j) = A(Aro+i,Aco+j);
1627 }
1628 }
1629}
1630
1631void DenseMatrix::CopyMN(const DenseMatrix &A, int row_offset, int col_offset)
1632{
1633 real_t *v = A.Data();
1634
1635 for (int j = 0; j < A.Width(); j++)
1636 {
1637 for (int i = 0; i < A.Height(); i++)
1638 {
1639 (*this)(row_offset+i,col_offset+j) = *(v++);
1640 }
1641 }
1642}
1643
1644void DenseMatrix::CopyMNt(const DenseMatrix &A, int row_offset, int col_offset)
1645{
1646 real_t *v = A.Data();
1647
1648 for (int i = 0; i < A.Width(); i++)
1649 {
1650 for (int j = 0; j < A.Height(); j++)
1651 {
1652 (*this)(row_offset+i,col_offset+j) = *(v++);
1653 }
1654 }
1655}
1656
1657void DenseMatrix::CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco,
1658 int row_offset, int col_offset)
1659{
1660 MFEM_VERIFY(row_offset+m <= this->Height() && col_offset+n <= this->Width(),
1661 "this DenseMatrix is too small to accommodate the submatrix. "
1662 << "row_offset = " << row_offset
1663 << ", m = " << m
1664 << ", this->Height() = " << this->Height()
1665 << ", col_offset = " << col_offset
1666 << ", n = " << n
1667 << ", this->Width() = " << this->Width()
1668 );
1669 MFEM_VERIFY(Aro+m <= A.Height() && Aco+n <= A.Width(),
1670 "The A DenseMatrix is too small to accommodate the submatrix. "
1671 << "Aro = " << Aro
1672 << ", m = " << m
1673 << ", A.Height() = " << A.Height()
1674 << ", Aco = " << Aco
1675 << ", n = " << n
1676 << ", A.Width() = " << A.Width()
1677 );
1678
1679 for (int j = 0; j < n; j++)
1680 {
1681 for (int i = 0; i < m; i++)
1682 {
1683 (*this)(row_offset+i,col_offset+j) = A(Aro+i,Aco+j);
1684 }
1685 }
1686}
1687
1688void DenseMatrix::CopyMNDiag(real_t c, int n, int row_offset, int col_offset)
1689{
1690 for (int i = 0; i < n; i++)
1691 {
1692 for (int j = i+1; j < n; j++)
1693 {
1694 (*this)(row_offset+i,col_offset+j) =
1695 (*this)(row_offset+j,col_offset+i) = 0.0;
1696 }
1697 }
1698
1699 for (int i = 0; i < n; i++)
1700 {
1701 (*this)(row_offset+i,col_offset+i) = c;
1702 }
1703}
1704
1705void DenseMatrix::CopyMNDiag(real_t *diag, int n, int row_offset,
1706 int col_offset)
1707{
1708 for (int i = 0; i < n; i++)
1709 {
1710 for (int j = i+1; j < n; j++)
1711 {
1712 (*this)(row_offset+i,col_offset+j) =
1713 (*this)(row_offset+j,col_offset+i) = 0.0;
1714 }
1715 }
1716
1717 for (int i = 0; i < n; i++)
1718 {
1719 (*this)(row_offset+i,col_offset+i) = diag[i];
1720 }
1721}
1722
1723void DenseMatrix::CopyExceptMN(const DenseMatrix &A, int m, int n)
1724{
1725 SetSize(A.Width()-1,A.Height()-1);
1726
1727 int i, j, i_off = 0, j_off = 0;
1728
1729 for (j = 0; j < A.Width(); j++)
1730 {
1731 if ( j == n )
1732 {
1733 j_off = 1;
1734 continue;
1735 }
1736 for (i = 0; i < A.Height(); i++)
1737 {
1738 if ( i == m )
1739 {
1740 i_off = 1;
1741 continue;
1742 }
1743 (*this)(i-i_off,j-j_off) = A(i,j);
1744 }
1745 i_off = 0;
1746 }
1747}
1748
1749void DenseMatrix::AddMatrix(DenseMatrix &A, int ro, int co)
1750{
1751 int h, ah, aw;
1752 real_t *p, *ap;
1753
1754 h = Height();
1755 ah = A.Height();
1756 aw = A.Width();
1757
1758#ifdef MFEM_DEBUG
1759 if (co+aw > Width() || ro+ah > h)
1760 {
1761 mfem_error("DenseMatrix::AddMatrix(...) 1 : dimension mismatch");
1762 }
1763#endif
1764
1765 p = data + ro + co * h;
1766 ap = A.data;
1767
1768 for (int c = 0; c < aw; c++)
1769 {
1770 for (int r = 0; r < ah; r++)
1771 {
1772 p[r] += ap[r];
1773 }
1774 p += h;
1775 ap += ah;
1776 }
1777}
1778
1779void DenseMatrix::AddMatrix(real_t a, const DenseMatrix &A, int ro, int co)
1780{
1781 int h, ah, aw;
1782 real_t *p, *ap;
1783
1784 h = Height();
1785 ah = A.Height();
1786 aw = A.Width();
1787
1788#ifdef MFEM_DEBUG
1789 if (co+aw > Width() || ro+ah > h)
1790 {
1791 mfem_error("DenseMatrix::AddMatrix(...) 2 : dimension mismatch");
1792 }
1793#endif
1794
1795 p = data + ro + co * h;
1796 ap = A.Data();
1797
1798 for (int c = 0; c < aw; c++)
1799 {
1800 for (int r = 0; r < ah; r++)
1801 {
1802 p[r] += a * ap[r];
1803 }
1804 p += h;
1805 ap += ah;
1806 }
1807}
1808
1810{
1811 int k = idx.Size();
1812 int idx_max = idx.Max();
1813 MFEM_VERIFY(idx.Min() >=0 && idx_max < this->height && idx_max < this->width,
1814 "DenseMatrix::GetSubMatrix: Index out of bounds");
1815 A.SetSize(k);
1816 real_t * adata = A.Data();
1817
1818 int ii, jj;
1819 for (int i = 0; i<k; i++)
1820 {
1821 ii = idx[i];
1822 for (int j = 0; j<k; j++)
1823 {
1824 jj = idx[j];
1825 adata[i+j*k] = this->data[ii+jj*height];
1826 }
1827 }
1828}
1829
1831 const Array<int> & idx_j, DenseMatrix & A) const
1832{
1833 int k = idx_i.Size();
1834 int l = idx_j.Size();
1835
1836 MFEM_VERIFY(idx_i.Min() >=0 && idx_i.Max() < this->height,
1837 "DenseMatrix::GetSubMatrix: Row index out of bounds");
1838 MFEM_VERIFY(idx_j.Min() >=0 && idx_j.Max() < this->width,
1839 "DenseMatrix::GetSubMatrix: Col index out of bounds");
1840
1841 A.SetSize(k,l);
1842 real_t * adata = A.Data();
1843
1844 int ii, jj;
1845 for (int i = 0; i<k; i++)
1846 {
1847 ii = idx_i[i];
1848 for (int j = 0; j<l; j++)
1849 {
1850 jj = idx_j[j];
1851 adata[i+j*k] = this->data[ii+jj*height];
1852 }
1853 }
1854}
1855
1856void DenseMatrix::GetSubMatrix(int ibeg, int iend, DenseMatrix & A)
1857{
1858 MFEM_VERIFY(iend >= ibeg, "DenseMatrix::GetSubMatrix: Inconsistent range");
1859 MFEM_VERIFY(ibeg >=0,
1860 "DenseMatrix::GetSubMatrix: Negative index");
1861 MFEM_VERIFY(iend <= this->height && iend <= this->width,
1862 "DenseMatrix::GetSubMatrix: Index bigger than upper bound");
1863
1864 int k = iend - ibeg;
1865 A.SetSize(k);
1866 real_t * adata = A.Data();
1867
1868 int ii, jj;
1869 for (int i = 0; i<k; i++)
1870 {
1871 ii = ibeg + i;
1872 for (int j = 0; j<k; j++)
1873 {
1874 jj = ibeg + j;
1875 adata[i+j*k] = this->data[ii+jj*height];
1876 }
1877 }
1878}
1879
1880void DenseMatrix::GetSubMatrix(int ibeg, int iend, int jbeg, int jend,
1881 DenseMatrix & A)
1882{
1883 MFEM_VERIFY(iend >= ibeg,
1884 "DenseMatrix::GetSubMatrix: Inconsistent row range");
1885 MFEM_VERIFY(jend >= jbeg,
1886 "DenseMatrix::GetSubMatrix: Inconsistent col range");
1887 MFEM_VERIFY(ibeg >=0,
1888 "DenseMatrix::GetSubMatrix: Negative row index");
1889 MFEM_VERIFY(jbeg >=0,
1890 "DenseMatrix::GetSubMatrix: Negative row index");
1891 MFEM_VERIFY(iend <= this->height,
1892 "DenseMatrix::GetSubMatrix: Index bigger than row upper bound");
1893 MFEM_VERIFY(jend <= this->width,
1894 "DenseMatrix::GetSubMatrix: Index bigger than col upper bound");
1895
1896 int k = iend - ibeg;
1897 int l = jend - jbeg;
1898 A.SetSize(k,l);
1899 real_t * adata = A.Data();
1900
1901 int ii, jj;
1902 for (int i = 0; i<k; i++)
1903 {
1904 ii = ibeg + i;
1905 for (int j = 0; j<l; j++)
1906 {
1907 jj = jbeg + j;
1908 adata[i+j*k] = this->data[ii+jj*height];
1909 }
1910 }
1911}
1912
1914{
1915 int k = idx.Size();
1916 MFEM_VERIFY(A.Height() == k && A.Width() == k,
1917 "DenseMatrix::SetSubMatrix:Inconsistent matrix dimensions");
1918
1919 int idx_max = idx.Max();
1920
1921 MFEM_VERIFY(idx.Min() >=0,
1922 "DenseMatrix::SetSubMatrix: Negative index");
1923 MFEM_VERIFY(idx_max < this->height,
1924 "DenseMatrix::SetSubMatrix: Index bigger than row upper bound");
1925 MFEM_VERIFY(idx_max < this->width,
1926 "DenseMatrix::SetSubMatrix: Index bigger than col upper bound");
1927
1928 real_t * adata = A.Data();
1929
1930 int ii, jj;
1931 for (int i = 0; i<k; i++)
1932 {
1933 ii = idx[i];
1934 for (int j = 0; j<k; j++)
1935 {
1936 jj = idx[j];
1937 this->data[ii+jj*height] = adata[i+j*k];
1938 }
1939 }
1940}
1941
1943 const Array<int> & idx_j, const DenseMatrix & A)
1944{
1945 int k = idx_i.Size();
1946 int l = idx_j.Size();
1947 MFEM_VERIFY(k == A.Height() && l == A.Width(),
1948 "DenseMatrix::SetSubMatrix:Inconsistent matrix dimensions");
1949 MFEM_VERIFY(idx_i.Min() >=0,
1950 "DenseMatrix::SetSubMatrix: Negative row index");
1951 MFEM_VERIFY(idx_j.Min() >=0,
1952 "DenseMatrix::SetSubMatrix: Negative col index");
1953 MFEM_VERIFY(idx_i.Max() < this->height,
1954 "DenseMatrix::SetSubMatrix: Index bigger than row upper bound");
1955 MFEM_VERIFY(idx_j.Max() < this->width,
1956 "DenseMatrix::SetSubMatrix: Index bigger than col upper bound");
1957
1958 real_t * adata = A.Data();
1959
1960 int ii, jj;
1961 for (int i = 0; i<k; i++)
1962 {
1963 ii = idx_i[i];
1964 for (int j = 0; j<l; j++)
1965 {
1966 jj = idx_j[j];
1967 this->data[ii+jj*height] = adata[i+j*k];
1968 }
1969 }
1970}
1971
1973{
1974 int k = A.Height();
1975
1976 MFEM_VERIFY(A.Width() == k, "DenseMatrix::SetSubmatrix: A is not square");
1977 MFEM_VERIFY(ibeg >=0,
1978 "DenseMatrix::SetSubmatrix: Negative index");
1979 MFEM_VERIFY(ibeg + k <= this->height,
1980 "DenseMatrix::SetSubmatrix: index bigger than row upper bound");
1981 MFEM_VERIFY(ibeg + k <= this->width,
1982 "DenseMatrix::SetSubmatrix: index bigger than col upper bound");
1983
1984 real_t * adata = A.Data();
1985
1986 int ii, jj;
1987 for (int i = 0; i<k; i++)
1988 {
1989 ii = ibeg + i;
1990 for (int j = 0; j<k; j++)
1991 {
1992 jj = ibeg + j;
1993 this->data[ii+jj*height] = adata[i+j*k];
1994 }
1995 }
1996}
1997
1998void DenseMatrix::SetSubMatrix(int ibeg, int jbeg, const DenseMatrix & A)
1999{
2000 int k = A.Height();
2001 int l = A.Width();
2002
2003 MFEM_VERIFY(ibeg>=0,
2004 "DenseMatrix::SetSubmatrix: Negative row index");
2005 MFEM_VERIFY(jbeg>=0,
2006 "DenseMatrix::SetSubmatrix: Negative col index");
2007 MFEM_VERIFY(ibeg + k <= this->height,
2008 "DenseMatrix::SetSubmatrix: Index bigger than row upper bound");
2009 MFEM_VERIFY(jbeg + l <= this->width,
2010 "DenseMatrix::SetSubmatrix: Index bigger than col upper bound");
2011
2012 real_t * adata = A.Data();
2013
2014 int ii, jj;
2015 for (int i = 0; i<k; i++)
2016 {
2017 ii = ibeg + i;
2018 for (int j = 0; j<l; j++)
2019 {
2020 jj = jbeg + j;
2021 this->data[ii+jj*height] = adata[i+j*k];
2022 }
2023 }
2024}
2025
2027{
2028 int k = idx.Size();
2029 MFEM_VERIFY(A.Height() == k && A.Width() == k,
2030 "DenseMatrix::AddSubMatrix:Inconsistent matrix dimensions");
2031
2032 int idx_max = idx.Max();
2033
2034 MFEM_VERIFY(idx.Min() >=0, "DenseMatrix::AddSubMatrix: Negative index");
2035 MFEM_VERIFY(idx_max < this->height,
2036 "DenseMatrix::AddSubMatrix: Index bigger than row upper bound");
2037 MFEM_VERIFY(idx_max < this->width,
2038 "DenseMatrix::AddSubMatrix: Index bigger than col upper bound");
2039
2040 real_t * adata = A.Data();
2041
2042 int ii, jj;
2043 for (int i = 0; i<k; i++)
2044 {
2045 ii = idx[i];
2046 for (int j = 0; j<k; j++)
2047 {
2048 jj = idx[j];
2049 this->data[ii+jj*height] += adata[i+j*k];
2050 }
2051 }
2052}
2053
2055 const Array<int> & idx_j, const DenseMatrix & A)
2056{
2057 int k = idx_i.Size();
2058 int l = idx_j.Size();
2059 MFEM_VERIFY(k == A.Height() && l == A.Width(),
2060 "DenseMatrix::AddSubMatrix:Inconsistent matrix dimensions");
2061
2062 MFEM_VERIFY(idx_i.Min() >=0,
2063 "DenseMatrix::AddSubMatrix: Negative row index");
2064 MFEM_VERIFY(idx_j.Min() >=0,
2065 "DenseMatrix::AddSubMatrix: Negative col index");
2066 MFEM_VERIFY(idx_i.Max() < this->height,
2067 "DenseMatrix::AddSubMatrix: Index bigger than row upper bound");
2068 MFEM_VERIFY(idx_j.Max() < this->width,
2069 "DenseMatrix::AddSubMatrix: Index bigger than col upper bound");
2070
2071 real_t * adata = A.Data();
2072
2073 int ii, jj;
2074 for (int i = 0; i<k; i++)
2075 {
2076 ii = idx_i[i];
2077 for (int j = 0; j<l; j++)
2078 {
2079 jj = idx_j[j];
2080 this->data[ii+jj*height] += adata[i+j*k];
2081 }
2082 }
2083}
2084
2086{
2087 int k = A.Height();
2088 MFEM_VERIFY(A.Width() == k, "DenseMatrix::AddSubmatrix: A is not square");
2089
2090 MFEM_VERIFY(ibeg>=0,
2091 "DenseMatrix::AddSubmatrix: Negative index");
2092 MFEM_VERIFY(ibeg + k <= this->Height(),
2093 "DenseMatrix::AddSubmatrix: Index bigger than row upper bound");
2094 MFEM_VERIFY(ibeg + k <= this->Width(),
2095 "DenseMatrix::AddSubmatrix: Index bigger than col upper bound");
2096
2097 real_t * adata = A.Data();
2098
2099 int ii, jj;
2100 for (int i = 0; i<k; i++)
2101 {
2102 ii = ibeg + i;
2103 for (int j = 0; j<k; j++)
2104 {
2105 jj = ibeg + j;
2106 this->data[ii+jj*height] += adata[i+j*k];
2107 }
2108 }
2109}
2110
2111void DenseMatrix::AddSubMatrix(int ibeg, int jbeg, const DenseMatrix & A)
2112{
2113 int k = A.Height();
2114 int l = A.Width();
2115
2116 MFEM_VERIFY(ibeg>=0,
2117 "DenseMatrix::AddSubmatrix: Negative row index");
2118 MFEM_VERIFY(jbeg>=0,
2119 "DenseMatrix::AddSubmatrix: Negative col index");
2120 MFEM_VERIFY(ibeg + k <= this->height,
2121 "DenseMatrix::AddSubmatrix: Index bigger than row upper bound");
2122 MFEM_VERIFY(jbeg + l <= this->width,
2123 "DenseMatrix::AddSubmatrix: Index bigger than col upper bound");
2124
2125 real_t * adata = A.Data();
2126
2127 int ii, jj;
2128 for (int i = 0; i<k; i++)
2129 {
2130 ii = ibeg + i;
2131 for (int j = 0; j<l; j++)
2132 {
2133 jj = jbeg + j;
2134 this->data[ii+jj*height] += adata[i+j*k];
2135 }
2136 }
2137}
2138
2139void DenseMatrix::AddToVector(int offset, Vector &v) const
2140{
2141 const int n = height * width;
2142 real_t *vdata = v.GetData() + offset;
2143
2144 for (int i = 0; i < n; i++)
2145 {
2146 vdata[i] += data[i];
2147 }
2148}
2149
2150void DenseMatrix::GetFromVector(int offset, const Vector &v)
2151{
2152 const int n = height * width;
2153 const real_t *vdata = v.GetData() + offset;
2154
2155 for (int i = 0; i < n; i++)
2156 {
2157 data[i] = vdata[i];
2158 }
2159}
2160
2162{
2163 const int n = Height();
2164
2165#ifdef MFEM_DEBUG
2166 if (dofs.Size() != n || Width() != n)
2167 {
2168 mfem_error("DenseMatrix::AdjustDofDirection(...): dimension mismatch");
2169 }
2170#endif
2171
2172 const int *dof = dofs;
2173 for (int i = 0; i < n-1; i++)
2174 {
2175 const int s = (dof[i] < 0) ? (-1) : (1);
2176 for (int j = i+1; j < n; j++)
2177 {
2178 const int t = (dof[j] < 0) ? (-s) : (s);
2179 if (t < 0)
2180 {
2181 (*this)(i,j) = -(*this)(i,j);
2182 (*this)(j,i) = -(*this)(j,i);
2183 }
2184 }
2185 }
2186}
2187
2189 Array<int> &col_dofs)
2190{
2191 const int nr = row_dofs.Size();
2192 const int nc = col_dofs.Size();
2193
2194 MFEM_VERIFY(Height() == nr && Width() == nc,
2195 "DenseMatrix::AdjustDofDirection: size mismatch.");
2196
2197 // Extract signs and convert to unsigned indices
2198 Vector rsign(nr), csign(nc);
2199
2200 for (int i = 0; i < nr; i++)
2201 {
2202 const int d = row_dofs[i];
2203 if (d >= 0) { rsign(i) = 1.0; }
2204 else { rsign(i) = -1.0; row_dofs[i] = -d - 1; continue; }
2205 row_dofs[i] = d;
2206 }
2207
2208 for (int j = 0; j < nc; j++)
2209 {
2210 const int d = col_dofs[j];
2211 if (d >= 0) { csign(j) = 1.0; }
2212 else { csign(j) = -1.0; col_dofs[j] = -d - 1; continue; }
2213 col_dofs[j] = d;
2214 }
2215
2216 // Apply row/column signs
2217 for (int i = 0; i < nr; i++)
2218 {
2219 const real_t rs = rsign(i);
2220 for (int j = 0; j < nc; j++)
2221 {
2222 (*this)(i,j) *= rs * csign(j);
2223 }
2224 }
2225}
2226
2227void DenseMatrix::SetRow(int row, real_t value)
2228{
2229 for (int j = 0; j < Width(); j++)
2230 {
2231 (*this)(row, j) = value;
2232 }
2233}
2234
2235void DenseMatrix::SetCol(int col, real_t value)
2236{
2237 for (int i = 0; i < Height(); i++)
2238 {
2239 (*this)(i, col) = value;
2240 }
2241}
2242
2243void DenseMatrix::SetRow(int r, const real_t* row)
2244{
2245 MFEM_ASSERT(row != nullptr, "supplied row pointer is null");
2246 for (int j = 0; j < Width(); j++)
2247 {
2248 (*this)(r, j) = row[j];
2249 }
2250}
2251
2252void DenseMatrix::SetRow(int r, const Vector &row)
2253{
2254 MFEM_ASSERT(Width() == row.Size(), "");
2255 SetRow(r, row.GetData());
2256}
2257
2258void DenseMatrix::SetCol(int c, const real_t* col)
2259{
2260 MFEM_ASSERT(col != nullptr, "supplied column pointer is null");
2261 for (int i = 0; i < Height(); i++)
2262 {
2263 (*this)(i, c) = col[i];
2264 }
2265}
2266
2267void DenseMatrix::SetCol(int c, const Vector &col)
2268{
2269 MFEM_ASSERT(Height() == col.Size(), "");
2270 SetCol(c, col.GetData());
2271}
2272
2274{
2275 for (int col = 0; col < Width(); col++)
2276 {
2277 for (int row = 0; row < Height(); row++)
2278 {
2279 if (std::abs(operator()(row,col)) <= eps)
2280 {
2281 operator()(row,col) = 0.0;
2282 }
2283 }
2284 }
2285}
2286
2287void DenseMatrix::Print(std::ostream &os, int width_) const
2288{
2289 // save current output flags
2290 ios::fmtflags old_flags = os.flags();
2291 // output flags = scientific + show sign
2292 os << setiosflags(ios::scientific | ios::showpos);
2293 for (int i = 0; i < height; i++)
2294 {
2295 os << "[row " << i << "]\n";
2296 for (int j = 0; j < width; j++)
2297 {
2298 os << (*this)(i,j);
2299 if (j+1 == width || (j+1) % width_ == 0)
2300 {
2301 os << '\n';
2302 }
2303 else
2304 {
2305 os << ' ';
2306 }
2307 }
2308 }
2309 // reset output flags to original values
2310 os.flags(old_flags);
2311}
2312
2313void DenseMatrix::PrintMatlab(std::ostream &os) const
2314{
2315 // save current output flags
2316 ios::fmtflags old_flags = os.flags();
2317 // output flags = scientific + show sign
2318 os << setiosflags(ios::scientific | ios::showpos);
2319 for (int i = 0; i < height; i++)
2320 {
2321 for (int j = 0; j < width; j++)
2322 {
2323 os << (*this)(i,j);
2324 os << ' ';
2325 }
2326 os << "\n";
2327 }
2328 // reset output flags to original values
2329 os.flags(old_flags);
2330}
2331
2332void DenseMatrix::PrintMathematica(std::ostream &os) const
2333{
2334 ios::fmtflags old_fmt = os.flags();
2335 os.setf(ios::scientific);
2336 std::streamsize old_prec = os.precision(14);
2337
2338 os << "(* Read file into Mathematica using: "
2339 << "myMat = Get[\"this_file_name\"] *)\n";
2340 os << "{\n";
2341
2342 for (int i = 0; i < height; i++)
2343 {
2344 os << "{\n";
2345 for (int j = 0; j < width; j++)
2346 {
2347 os << "Internal`StringToMReal[\"" << (*this)(i,j) << "\"]";
2348 if (j < width - 1) { os << ','; }
2349 os << '\n';
2350 }
2351 os << '}';
2352 if (i < height - 1) { os << ','; }
2353 os << '\n';
2354 }
2355 os << "}\n";
2356
2357 os.precision(old_prec);
2358 os.flags(old_fmt);
2359}
2360
2361void DenseMatrix::PrintT(std::ostream &os, int width_) const
2362{
2363 // save current output flags
2364 ios::fmtflags old_flags = os.flags();
2365 // output flags = scientific + show sign
2366 os << setiosflags(ios::scientific | ios::showpos);
2367 for (int j = 0; j < width; j++)
2368 {
2369 os << "[col " << j << "]\n";
2370 for (int i = 0; i < height; i++)
2371 {
2372 os << (*this)(i,j);
2373 if (i+1 == height || (i+1) % width_ == 0)
2374 {
2375 os << '\n';
2376 }
2377 else
2378 {
2379 os << ' ';
2380 }
2381 }
2382 }
2383 // reset output flags to original values
2384 os.flags(old_flags);
2385}
2386
2388{
2389 DenseMatrix copy(*this), C(width);
2390 Invert();
2391 mfem::Mult(*this, copy, C);
2392
2393 for (int i = 0; i < width; i++)
2394 {
2395 C(i,i) -= 1.0;
2396 }
2397 mfem::out << "size = " << width << ", i_max = " << C.MaxMaxNorm()
2398 << ", cond_F = " << FNorm()*copy.FNorm() << endl;
2399}
2400
2402{
2403 mfem::Swap(*this, other);
2404}
2405
2406
2407void Add(const DenseMatrix &A, const DenseMatrix &B,
2409{
2410 kernels::Add(C.Height(), C.Width(), alpha, A.Data(), B.Data(), C.Data());
2411}
2412
2413void Add(real_t alpha, const real_t *A,
2414 real_t beta, const real_t *B, DenseMatrix &C)
2415{
2416 kernels::Add(C.Height(), C.Width(), alpha, A, beta, B, C.Data());
2417}
2418
2420 real_t beta, const DenseMatrix &B, DenseMatrix &C)
2421{
2422 MFEM_ASSERT(A.Height() == C.Height(), "");
2423 MFEM_ASSERT(B.Height() == C.Height(), "");
2424 MFEM_ASSERT(A.Width() == C.Width(), "");
2425 MFEM_ASSERT(B.Width() == C.Width(), "");
2426 Add(alpha, A.GetData(), beta, B.GetData(), C);
2427}
2428
2430{
2431 MFEM_VERIFY(A.IsSquare(), "A must be a square matrix!");
2432 MFEM_ASSERT(A.NumCols() > 0, "supplied matrix, A, is empty!");
2433 MFEM_ASSERT(X != nullptr, "supplied vector, X, is null!");
2434
2435 int N = A.NumCols();
2436
2437 switch (N)
2438 {
2439 case 1:
2440 {
2441 real_t det = A(0,0);
2442 if (std::abs(det) <= TOL) { return false; } // singular
2443
2444 X[0] /= det;
2445 break;
2446 }
2447 case 2:
2448 {
2449 real_t det = A.Det();
2450 if (std::abs(det) <= TOL) { return false; } // singular
2451
2452 real_t invdet = 1. / det;
2453
2454 real_t b0 = X[0];
2455 real_t b1 = X[1];
2456
2457 X[0] = ( A(1,1)*b0 - A(0,1)*b1) * invdet;
2458 X[1] = (-A(1,0)*b0 + A(0,0)*b1) * invdet;
2459 break;
2460 }
2461 default:
2462 {
2463 // default to LU factorization for the general case
2464 Array<int> ipiv(N);
2465 LUFactors lu(A.Data(), ipiv);
2466
2467 if (!lu.Factor(N,TOL)) { return false; } // singular
2468
2469 lu.Solve(N, 1, X);
2470 }
2471
2472 } // END switch
2473
2474 return true;
2475}
2476
2477void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
2478{
2479 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2480 b.Width() == c.Height(), "incompatible dimensions");
2481
2482#ifdef MFEM_USE_LAPACK
2483 static char transa = 'N', transb = 'N';
2484 static real_t alpha = 1.0, beta = 0.0;
2485 int m = b.Height(), n = c.Width(), k = b.Width();
2486
2487 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2488 c.Data(), &k, &beta, a.Data(), &m);
2489#else
2490 const int ah = a.Height();
2491 const int aw = a.Width();
2492 const int bw = b.Width();
2493 real_t *ad = a.Data();
2494 const real_t *bd = b.Data();
2495 const real_t *cd = c.Data();
2496 kernels::Mult(ah,aw,bw,bd,cd,ad);
2497#endif
2498}
2499
2501 DenseMatrix &a)
2502{
2503 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2504 b.Width() == c.Height(), "incompatible dimensions");
2505
2506#ifdef MFEM_USE_LAPACK
2507 static char transa = 'N', transb = 'N';
2508 static real_t beta = 1.0;
2509 int m = b.Height(), n = c.Width(), k = b.Width();
2510
2511 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2512 c.Data(), &k, &beta, a.Data(), &m);
2513#else
2514 const int ah = a.Height();
2515 const int aw = a.Width();
2516 const int bw = b.Width();
2517 real_t *ad = a.Data();
2518 const real_t *bd = b.Data();
2519 const real_t *cd = c.Data();
2520 for (int j = 0; j < aw; j++)
2521 {
2522 for (int k = 0; k < bw; k++)
2523 {
2524 for (int i = 0; i < ah; i++)
2525 {
2526 ad[i+j*ah] += alpha * bd[i+k*ah] * cd[k+j*bw];
2527 }
2528 }
2529 }
2530#endif
2531}
2532
2534{
2535 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2536 b.Width() == c.Height(), "incompatible dimensions");
2537
2538#ifdef MFEM_USE_LAPACK
2539 static char transa = 'N', transb = 'N';
2540 static real_t alpha = 1.0, beta = 1.0;
2541 int m = b.Height(), n = c.Width(), k = b.Width();
2542
2543 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2544 c.Data(), &k, &beta, a.Data(), &m);
2545#else
2546 const int ah = a.Height();
2547 const int aw = a.Width();
2548 const int bw = b.Width();
2549 real_t *ad = a.Data();
2550 const real_t *bd = b.Data();
2551 const real_t *cd = c.Data();
2552 for (int j = 0; j < aw; j++)
2553 {
2554 for (int k = 0; k < bw; k++)
2555 {
2556 for (int i = 0; i < ah; i++)
2557 {
2558 ad[i+j*ah] += bd[i+k*ah] * cd[k+j*bw];
2559 }
2560 }
2561 }
2562#endif
2563}
2564
2566{
2567#ifdef MFEM_DEBUG
2568 if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 3)
2569 {
2570 mfem_error("CalcAdjugate(...): unsupported dimensions");
2571 }
2572 if (a.Width() != adja.Height() || a.Height() != adja.Width())
2573 {
2574 mfem_error("CalcAdjugate(...): dimension mismatch");
2575 }
2576#endif
2577
2578 if (a.Width() < a.Height())
2579 {
2580 const real_t *d = a.Data();
2581 real_t *ad = adja.Data();
2582 if (a.Width() == 1)
2583 {
2584 // N x 1, N = 2,3
2585 ad[0] = d[0];
2586 ad[1] = d[1];
2587 if (a.Height() == 3)
2588 {
2589 ad[2] = d[2];
2590 }
2591 }
2592 else
2593 {
2594 // 3 x 2
2595 real_t e, g, f;
2596 e = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
2597 g = d[3]*d[3] + d[4]*d[4] + d[5]*d[5];
2598 f = d[0]*d[3] + d[1]*d[4] + d[2]*d[5];
2599
2600 ad[0] = d[0]*g - d[3]*f;
2601 ad[1] = d[3]*e - d[0]*f;
2602 ad[2] = d[1]*g - d[4]*f;
2603 ad[3] = d[4]*e - d[1]*f;
2604 ad[4] = d[2]*g - d[5]*f;
2605 ad[5] = d[5]*e - d[2]*f;
2606 }
2607 return;
2608 }
2609
2610 if (a.Width() == 1)
2611 {
2612 adja(0,0) = 1.0;
2613 }
2614 else if (a.Width() == 2)
2615 {
2616 adja(0,0) = a(1,1);
2617 adja(0,1) = -a(0,1);
2618 adja(1,0) = -a(1,0);
2619 adja(1,1) = a(0,0);
2620 }
2621 else
2622 {
2623 adja(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
2624 adja(0,1) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
2625 adja(0,2) = a(0,1)*a(1,2)-a(0,2)*a(1,1);
2626
2627 adja(1,0) = a(1,2)*a(2,0)-a(1,0)*a(2,2);
2628 adja(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0);
2629 adja(1,2) = a(0,2)*a(1,0)-a(0,0)*a(1,2);
2630
2631 adja(2,0) = a(1,0)*a(2,1)-a(1,1)*a(2,0);
2632 adja(2,1) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
2633 adja(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
2634 }
2635}
2636
2638{
2639#ifdef MFEM_DEBUG
2640 if (a.Height() != a.Width() || adjat.Height() != adjat.Width() ||
2641 a.Width() != adjat.Width() || a.Width() < 1 || a.Width() > 3)
2642 {
2643 mfem_error("CalcAdjugateTranspose(...): dimension mismatch");
2644 }
2645#endif
2646 if (a.Width() == 1)
2647 {
2648 adjat(0,0) = 1.0;
2649 }
2650 else if (a.Width() == 2)
2651 {
2652 adjat(0,0) = a(1,1);
2653 adjat(1,0) = -a(0,1);
2654 adjat(0,1) = -a(1,0);
2655 adjat(1,1) = a(0,0);
2656 }
2657 else
2658 {
2659 adjat(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
2660 adjat(1,0) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
2661 adjat(2,0) = a(0,1)*a(1,2)-a(0,2)*a(1,1);
2662
2663 adjat(0,1) = a(1,2)*a(2,0)-a(1,0)*a(2,2);
2664 adjat(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0);
2665 adjat(2,1) = a(0,2)*a(1,0)-a(0,0)*a(1,2);
2666
2667 adjat(0,2) = a(1,0)*a(2,1)-a(1,1)*a(2,0);
2668 adjat(1,2) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
2669 adjat(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
2670 }
2671}
2672
2674{
2675 MFEM_ASSERT(a.Width() <= a.Height() && a.Width() >= 1 && a.Height() <= 3, "");
2676 MFEM_ASSERT(inva.Height() == a.Width(), "incorrect dimensions");
2677 MFEM_ASSERT(inva.Width() == a.Height(), "incorrect dimensions");
2678
2679 if (a.Width() < a.Height())
2680 {
2681 const real_t *d = a.Data();
2682 real_t *id = inva.Data();
2683 if (a.Height() == 2)
2684 {
2686 }
2687 else
2688 {
2689 if (a.Width() == 1)
2690 {
2692 }
2693 else
2694 {
2696 }
2697 }
2698 return;
2699 }
2700
2701#ifdef MFEM_DEBUG
2702 const real_t t = a.Det();
2703 MFEM_ASSERT(std::abs(t) > 1.0e-14 * pow(a.FNorm()/a.Width(), a.Width()),
2704 "singular matrix!");
2705#endif
2706
2707 switch (a.Height())
2708 {
2709 case 1:
2710 inva(0,0) = 1.0 / a.Det();
2711 break;
2712 case 2:
2713 kernels::CalcInverse<2>(a.Data(), inva.Data());
2714 break;
2715 case 3:
2716 kernels::CalcInverse<3>(a.Data(), inva.Data());
2717 break;
2718 }
2719}
2720
2722{
2723#ifdef MFEM_DEBUG
2724 if ( (a.Width() != a.Height()) || ( (a.Height()!= 1) && (a.Height()!= 2)
2725 && (a.Height()!= 3) ) )
2726 {
2727 mfem_error("CalcInverseTranspose(...): dimension mismatch");
2728 }
2729#endif
2730
2731 real_t t = 1. / a.Det() ;
2732
2733 switch (a.Height())
2734 {
2735 case 1:
2736 inva(0,0) = 1.0 / a(0,0);
2737 break;
2738 case 2:
2739 inva(0,0) = a(1,1) * t ;
2740 inva(1,0) = -a(0,1) * t ;
2741 inva(0,1) = -a(1,0) * t ;
2742 inva(1,1) = a(0,0) * t ;
2743 break;
2744 case 3:
2745 inva(0,0) = (a(1,1)*a(2,2)-a(1,2)*a(2,1))*t;
2746 inva(1,0) = (a(0,2)*a(2,1)-a(0,1)*a(2,2))*t;
2747 inva(2,0) = (a(0,1)*a(1,2)-a(0,2)*a(1,1))*t;
2748
2749 inva(0,1) = (a(1,2)*a(2,0)-a(1,0)*a(2,2))*t;
2750 inva(1,1) = (a(0,0)*a(2,2)-a(0,2)*a(2,0))*t;
2751 inva(2,1) = (a(0,2)*a(1,0)-a(0,0)*a(1,2))*t;
2752
2753 inva(0,2) = (a(1,0)*a(2,1)-a(1,1)*a(2,0))*t;
2754 inva(1,2) = (a(0,1)*a(2,0)-a(0,0)*a(2,1))*t;
2755 inva(2,2) = (a(0,0)*a(1,1)-a(0,1)*a(1,0))*t;
2756 break;
2757 }
2758}
2759
2760void CalcOrtho(const DenseMatrix &J, Vector &n)
2761{
2762 MFEM_ASSERT( ((J.Height() == 2 && J.Width() == 1)
2763 || (J.Height() == 3 && J.Width() == 2))
2764 && (J.Height() == n.Size()),
2765 "Matrix must be 3x2 or 2x1, "
2766 << "and the Vector must be sized with the rows. "
2767 << " J.Height() = " << J.Height()
2768 << ", J.Width() = " << J.Width()
2769 << ", n.Size() = " << n.Size()
2770 );
2771
2772 const real_t *d = J.Data();
2773 if (J.Height() == 2)
2774 {
2775 n(0) = d[1];
2776 n(1) = -d[0];
2777 }
2778 else
2779 {
2780 n(0) = d[1]*d[5] - d[2]*d[4];
2781 n(1) = d[2]*d[3] - d[0]*d[5];
2782 n(2) = d[0]*d[4] - d[1]*d[3];
2783 }
2784}
2785
2787{
2788 const int height = a.Height();
2789 const int width = a.Width();
2790 for (int i = 0; i < height; i++)
2791 {
2792 for (int j = 0; j <= i; j++)
2793 {
2794 real_t temp = 0.;
2795 for (int k = 0; k < width; k++)
2796 {
2797 temp += a(i,k) * a(j,k);
2798 }
2799 aat(j,i) = aat(i,j) = temp;
2800 }
2801 }
2802}
2803
2804void AddMultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
2805{
2806 for (int i = 0; i < A.Height(); i++)
2807 {
2808 for (int j = 0; j < i; j++)
2809 {
2810 real_t t = 0.;
2811 for (int k = 0; k < A.Width(); k++)
2812 {
2813 t += D(k) * A(i, k) * A(j, k);
2814 }
2815 ADAt(i, j) += t;
2816 ADAt(j, i) += t;
2817 }
2818 }
2819
2820 // process diagonal
2821 for (int i = 0; i < A.Height(); i++)
2822 {
2823 real_t t = 0.;
2824 for (int k = 0; k < A.Width(); k++)
2825 {
2826 t += D(k) * A(i, k) * A(i, k);
2827 }
2828 ADAt(i, i) += t;
2829 }
2830}
2831
2832void MultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
2833{
2834 for (int i = 0; i < A.Height(); i++)
2835 {
2836 for (int j = 0; j <= i; j++)
2837 {
2838 real_t t = 0.;
2839 for (int k = 0; k < A.Width(); k++)
2840 {
2841 t += D(k) * A(i, k) * A(j, k);
2842 }
2843 ADAt(j, i) = ADAt(i, j) = t;
2844 }
2845 }
2846}
2847
2848void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
2849{
2850#ifdef MFEM_DEBUG
2851 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
2852 A.Width() != B.Width())
2853 {
2854 mfem_error("MultABt(...): dimension mismatch");
2855 }
2856#endif
2857
2858#ifdef MFEM_USE_LAPACK
2859 static char transa = 'N', transb = 'T';
2860 static real_t alpha = 1.0, beta = 0.0;
2861 int m = A.Height(), n = B.Height(), k = A.Width();
2862
2863 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
2864 B.Data(), &n, &beta, ABt.Data(), &m);
2865#elif 1
2866 const int ah = A.Height();
2867 const int bh = B.Height();
2868 const int aw = A.Width();
2869 const real_t *ad = A.Data();
2870 const real_t *bd = B.Data();
2871 real_t *cd = ABt.Data();
2872
2873 kernels::MultABt(ah, aw, bh, ad, bd, cd);
2874#elif 1
2875 const int ah = A.Height();
2876 const int bh = B.Height();
2877 const int aw = A.Width();
2878 const real_t *ad = A.Data();
2879 const real_t *bd = B.Data();
2880 real_t *cd = ABt.Data();
2881
2882 for (int j = 0; j < bh; j++)
2883 for (int i = 0; i < ah; i++)
2884 {
2885 real_t d = 0.0;
2886 const real_t *ap = ad + i;
2887 const real_t *bp = bd + j;
2888 for (int k = 0; k < aw; k++)
2889 {
2890 d += (*ap) * (*bp);
2891 ap += ah;
2892 bp += bh;
2893 }
2894 *(cd++) = d;
2895 }
2896#else
2897 int i, j, k;
2898 real_t d;
2899
2900 for (i = 0; i < A.Height(); i++)
2901 for (j = 0; j < B.Height(); j++)
2902 {
2903 d = 0.0;
2904 for (k = 0; k < A.Width(); k++)
2905 {
2906 d += A(i, k) * B(j, k);
2907 }
2908 ABt(i, j) = d;
2909 }
2910#endif
2911}
2912
2913void MultADBt(const DenseMatrix &A, const Vector &D,
2914 const DenseMatrix &B, DenseMatrix &ADBt)
2915{
2916#ifdef MFEM_DEBUG
2917 if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
2918 A.Width() != B.Width() || A.Width() != D.Size())
2919 {
2920 mfem_error("MultADBt(...): dimension mismatch");
2921 }
2922#endif
2923
2924 const int ah = A.Height();
2925 const int bh = B.Height();
2926 const int aw = A.Width();
2927 const real_t *ad = A.Data();
2928 const real_t *bd = B.Data();
2929 const real_t *dd = D.GetData();
2930 real_t *cd = ADBt.Data();
2931
2932 for (int i = 0, s = ah*bh; i < s; i++)
2933 {
2934 cd[i] = 0.0;
2935 }
2936 for (int k = 0; k < aw; k++)
2937 {
2938 real_t *cp = cd;
2939 for (int j = 0; j < bh; j++)
2940 {
2941 const real_t dk_bjk = dd[k] * bd[j];
2942 for (int i = 0; i < ah; i++)
2943 {
2944 cp[i] += ad[i] * dk_bjk;
2945 }
2946 cp += ah;
2947 }
2948 ad += ah;
2949 bd += bh;
2950 }
2951}
2952
2953void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
2954{
2955#ifdef MFEM_DEBUG
2956 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
2957 A.Width() != B.Width())
2958 {
2959 mfem_error("AddMultABt(...): dimension mismatch");
2960 }
2961#endif
2962
2963#ifdef MFEM_USE_LAPACK
2964 static char transa = 'N', transb = 'T';
2965 static real_t alpha = 1.0, beta = 1.0;
2966 int m = A.Height(), n = B.Height(), k = A.Width();
2967
2968 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
2969 B.Data(), &n, &beta, ABt.Data(), &m);
2970#elif 1
2971 const int ah = A.Height();
2972 const int bh = B.Height();
2973 const int aw = A.Width();
2974 const real_t *ad = A.Data();
2975 const real_t *bd = B.Data();
2976 real_t *cd = ABt.Data();
2977
2978 for (int k = 0; k < aw; k++)
2979 {
2980 real_t *cp = cd;
2981 for (int j = 0; j < bh; j++)
2982 {
2983 const real_t bjk = bd[j];
2984 for (int i = 0; i < ah; i++)
2985 {
2986 cp[i] += ad[i] * bjk;
2987 }
2988 cp += ah;
2989 }
2990 ad += ah;
2991 bd += bh;
2992 }
2993#else
2994 int i, j, k;
2995 real_t d;
2996
2997 for (i = 0; i < A.Height(); i++)
2998 for (j = 0; j < B.Height(); j++)
2999 {
3000 d = 0.0;
3001 for (k = 0; k < A.Width(); k++)
3002 {
3003 d += A(i, k) * B(j, k);
3004 }
3005 ABt(i, j) += d;
3006 }
3007#endif
3008}
3009
3010void AddMultADBt(const DenseMatrix &A, const Vector &D,
3011 const DenseMatrix &B, DenseMatrix &ADBt)
3012{
3013#ifdef MFEM_DEBUG
3014 if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
3015 A.Width() != B.Width() || A.Width() != D.Size())
3016 {
3017 mfem_error("AddMultADBt(...): dimension mismatch");
3018 }
3019#endif
3020
3021 const int ah = A.Height();
3022 const int bh = B.Height();
3023 const int aw = A.Width();
3024 const real_t *ad = A.Data();
3025 const real_t *bd = B.Data();
3026 const real_t *dd = D.GetData();
3027 real_t *cd = ADBt.Data();
3028
3029 for (int k = 0; k < aw; k++)
3030 {
3031 real_t *cp = cd;
3032 for (int j = 0; j < bh; j++)
3033 {
3034 const real_t dk_bjk = dd[k] * bd[j];
3035 for (int i = 0; i < ah; i++)
3036 {
3037 cp[i] += ad[i] * dk_bjk;
3038 }
3039 cp += ah;
3040 }
3041 ad += ah;
3042 bd += bh;
3043 }
3044}
3045
3047 DenseMatrix &ABt)
3048{
3049#ifdef MFEM_DEBUG
3050 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
3051 A.Width() != B.Width())
3052 {
3053 mfem_error("AddMult_a_ABt(...): dimension mismatch");
3054 }
3055#endif
3056
3057#ifdef MFEM_USE_LAPACK
3058 static char transa = 'N', transb = 'T';
3059 real_t alpha = a;
3060 static real_t beta = 1.0;
3061 int m = A.Height(), n = B.Height(), k = A.Width();
3062
3063 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
3064 B.Data(), &n, &beta, ABt.Data(), &m);
3065#elif 1
3066 const int ah = A.Height();
3067 const int bh = B.Height();
3068 const int aw = A.Width();
3069 const real_t *ad = A.Data();
3070 const real_t *bd = B.Data();
3071 real_t *cd = ABt.Data();
3072
3073 for (int k = 0; k < aw; k++)
3074 {
3075 real_t *cp = cd;
3076 for (int j = 0; j < bh; j++)
3077 {
3078 const real_t bjk = a * bd[j];
3079 for (int i = 0; i < ah; i++)
3080 {
3081 cp[i] += ad[i] * bjk;
3082 }
3083 cp += ah;
3084 }
3085 ad += ah;
3086 bd += bh;
3087 }
3088#else
3089 int i, j, k;
3090 real_t d;
3091
3092 for (i = 0; i < A.Height(); i++)
3093 for (j = 0; j < B.Height(); j++)
3094 {
3095 d = 0.0;
3096 for (k = 0; k < A.Width(); k++)
3097 {
3098 d += A(i, k) * B(j, k);
3099 }
3100 ABt(i, j) += a * d;
3101 }
3102#endif
3103}
3104
3105void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
3106{
3107#ifdef MFEM_DEBUG
3108 if (A.Width() != AtB.Height() || B.Width() != AtB.Width() ||
3109 A.Height() != B.Height())
3110 {
3111 mfem_error("MultAtB(...): dimension mismatch");
3112 }
3113#endif
3114
3115#ifdef MFEM_USE_LAPACK
3116 static char transa = 'T', transb = 'N';
3117 static real_t alpha = 1.0, beta = 0.0;
3118 int m = A.Width(), n = B.Width(), k = A.Height();
3119
3120 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3121 B.Data(), &k, &beta, AtB.Data(), &m);
3122#elif 1
3123 const int ah = A.Height();
3124 const int aw = A.Width();
3125 const int bw = B.Width();
3126 const real_t *ad = A.Data();
3127 const real_t *bd = B.Data();
3128 real_t *cd = AtB.Data();
3129
3130 for (int j = 0; j < bw; j++)
3131 {
3132 const real_t *ap = ad;
3133 for (int i = 0; i < aw; i++)
3134 {
3135 real_t d = 0.0;
3136 for (int k = 0; k < ah; k++)
3137 {
3138 d += ap[k] * bd[k];
3139 }
3140 *(cd++) = d;
3141 ap += ah;
3142 }
3143 bd += ah;
3144 }
3145#else
3146 int i, j, k;
3147 real_t d;
3148
3149 for (i = 0; i < A.Width(); i++)
3150 for (j = 0; j < B.Width(); j++)
3151 {
3152 d = 0.0;
3153 for (k = 0; k < A.Height(); k++)
3154 {
3155 d += A(k, i) * B(k, j);
3156 }
3157 AtB(i, j) = d;
3158 }
3159#endif
3160}
3161
3162void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B,
3163 DenseMatrix &AtB)
3164{
3165 MFEM_ASSERT(AtB.Height() == A.Width() && AtB.Width() == B.Width() &&
3166 A.Height() == B.Height(), "incompatible dimensions");
3167
3168#ifdef MFEM_USE_LAPACK
3169 static char transa = 'T', transb = 'N';
3170 static real_t alpha = 1.0, beta = 1.0;
3171 int m = A.Width(), n = B.Width(), k = A.Height();
3172
3173 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3174 B.Data(), &k, &beta, AtB.Data(), &m);
3175#else
3176 const int ah = A.Height();
3177 const int aw = A.Width();
3178 const int bw = B.Width();
3179 const real_t *ad = A.Data();
3180 const real_t *bd = B.Data();
3181 real_t *cd = AtB.Data();
3182
3183 for (int j = 0; j < bw; j++)
3184 {
3185 const real_t *ap = ad;
3186 for (int i = 0; i < aw; i++)
3187 {
3188 real_t d = 0.0;
3189 for (int k = 0; k < ah; k++)
3190 {
3191 d += ap[k] * bd[k];
3192 }
3193 *(cd++) += d;
3194 ap += ah;
3195 }
3196 bd += ah;
3197 }
3198#endif
3199}
3200
3202 DenseMatrix &AtB)
3203{
3204 MFEM_ASSERT(AtB.Height() == A.Width() && AtB.Width() == B.Width() &&
3205 A.Height() == B.Height(), "incompatible dimensions");
3206
3207#ifdef MFEM_USE_LAPACK
3208 static char transa = 'T', transb = 'N';
3209 real_t alpha = a;
3210 static real_t beta = 1.0;
3211 int m = A.Width(), n = B.Width(), k = A.Height();
3212
3213 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3214 B.Data(), &k, &beta, AtB.Data(), &m);
3215#else
3216 const int ah = A.Height();
3217 const int aw = A.Width();
3218 const int bw = B.Width();
3219 const real_t *ad = A.Data();
3220 const real_t *bd = B.Data();
3221 real_t *cd = AtB.Data();
3222
3223 for (int j = 0; j < bw; j++)
3224 {
3225 const real_t *ap = ad;
3226 for (int i = 0; i < aw; i++)
3227 {
3228 real_t d = 0.0;
3229 for (int k = 0; k < ah; k++)
3230 {
3231 d += ap[k] * bd[k];
3232 }
3233 *(cd++) += a * d;
3234 ap += ah;
3235 }
3236 bd += ah;
3237 }
3238#endif
3239}
3240
3242{
3243 real_t d;
3244
3245 for (int i = 0; i < A.Height(); i++)
3246 {
3247 for (int j = 0; j < i; j++)
3248 {
3249 d = 0.;
3250 for (int k = 0; k < A.Width(); k++)
3251 {
3252 d += A(i,k) * A(j,k);
3253 }
3254 AAt(i, j) += (d *= a);
3255 AAt(j, i) += d;
3256 }
3257 d = 0.;
3258 for (int k = 0; k < A.Width(); k++)
3259 {
3260 d += A(i,k) * A(i,k);
3261 }
3262 AAt(i, i) += a * d;
3263 }
3264}
3265
3267{
3268 for (int i = 0; i < A.Height(); i++)
3269 {
3270 for (int j = 0; j <= i; j++)
3271 {
3272 real_t d = 0.;
3273 for (int k = 0; k < A.Width(); k++)
3274 {
3275 d += A(i,k) * A(j,k);
3276 }
3277 AAt(i, j) = AAt(j, i) = a * d;
3278 }
3279 }
3280}
3281
3282void MultVVt(const Vector &v, DenseMatrix &vvt)
3283{
3284 for (int i = 0; i < v.Size(); i++)
3285 {
3286 for (int j = 0; j <= i; j++)
3287 {
3288 vvt(i,j) = vvt(j,i) = v(i) * v(j);
3289 }
3290 }
3291}
3292
3293void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
3294{
3295#ifdef MFEM_DEBUG
3296 if (v.Size() != VWt.Height() || w.Size() != VWt.Width())
3297 {
3298 mfem_error("MultVWt(...): dimension mismatch");
3299 }
3300#endif
3301
3302 for (int i = 0; i < v.Size(); i++)
3303 {
3304 const real_t vi = v(i);
3305 for (int j = 0; j < w.Size(); j++)
3306 {
3307 VWt(i, j) = vi * w(j);
3308 }
3309 }
3310}
3311
3312void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
3313{
3314 const int m = v.Size(), n = w.Size();
3315
3316#ifdef MFEM_DEBUG
3317 if (VWt.Height() != m || VWt.Width() != n)
3318 {
3319 mfem_error("AddMultVWt(...): dimension mismatch");
3320 }
3321#endif
3322
3323 for (int i = 0; i < m; i++)
3324 {
3325 const real_t vi = v(i);
3326 for (int j = 0; j < n; j++)
3327 {
3328 VWt(i, j) += vi * w(j);
3329 }
3330 }
3331}
3332
3333void AddMultVVt(const Vector &v, DenseMatrix &VVt)
3334{
3335 const int n = v.Size();
3336
3337#ifdef MFEM_DEBUG
3338 if (VVt.Height() != n || VVt.Width() != n)
3339 {
3340 mfem_error("AddMultVVt(...): dimension mismatch");
3341 }
3342#endif
3343
3344 for (int i = 0; i < n; i++)
3345 {
3346 const real_t vi = v(i);
3347 for (int j = 0; j < i; j++)
3348 {
3349 const real_t vivj = vi * v(j);
3350 VVt(i, j) += vivj;
3351 VVt(j, i) += vivj;
3352 }
3353 VVt(i, i) += vi * vi;
3354 }
3355}
3356
3357void AddMult_a_VWt(const real_t a, const Vector &v, const Vector &w,
3358 DenseMatrix &VWt)
3359{
3360 const int m = v.Size(), n = w.Size();
3361
3362#ifdef MFEM_DEBUG
3363 if (VWt.Height() != m || VWt.Width() != n)
3364 {
3365 mfem_error("AddMult_a_VWt(...): dimension mismatch");
3366 }
3367#endif
3368
3369 for (int j = 0; j < n; j++)
3370 {
3371 const real_t awj = a * w(j);
3372 for (int i = 0; i < m; i++)
3373 {
3374 VWt(i, j) += v(i) * awj;
3375 }
3376 }
3377}
3378
3379void AddMult_a_VVt(const real_t a, const Vector &v, DenseMatrix &VVt)
3380{
3381 MFEM_ASSERT(VVt.Height() == v.Size() && VVt.Width() == v.Size(),
3382 "incompatible dimensions!");
3383
3384 const int n = v.Size();
3385 for (int i = 0; i < n; i++)
3386 {
3387 real_t avi = a * v(i);
3388 for (int j = 0; j < i; j++)
3389 {
3390 const real_t avivj = avi * v(j);
3391 VVt(i, j) += avivj;
3392 VVt(j, i) += avivj;
3393 }
3394 VVt(i, i) += avi * v(i);
3395 }
3396}
3397
3398void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix & RAP)
3399{
3400 DenseMatrix RA(P.Width(),A.Width());
3401 MultAtB(P,A,RA);
3402 RAP.SetSize(RA.Height(), P.Width());
3403 Mult(RA,P, RAP);
3404}
3405
3406void RAP(const DenseMatrix &Rt, const DenseMatrix &A,
3407 const DenseMatrix &P, DenseMatrix & RAP)
3408{
3409 DenseMatrix RA(Rt.Width(),A.Width());
3410 MultAtB(Rt,A,RA);
3411 RAP.SetSize(RA.Height(), P.Width());
3412 Mult(RA,P, RAP);
3413}
3414
3416{
3417#ifdef MFEM_USE_LAPACK
3418 int info = 0;
3419 if (m) { MFEM_LAPACK_PREFIX(getrf_)(&m, &m, data, &m, ipiv, &info); }
3420 return info == 0;
3421#else
3422 // compiling without LAPACK
3423 real_t *data_ptr = this->data;
3424 for (int i = 0; i < m; i++)
3425 {
3426 // pivoting
3427 {
3428 int piv = i;
3429 real_t a = std::abs(data_ptr[piv+i*m]);
3430 for (int j = i+1; j < m; j++)
3431 {
3432 const real_t b = std::abs(data_ptr[j+i*m]);
3433 if (b > a)
3434 {
3435 a = b;
3436 piv = j;
3437 }
3438 }
3439 ipiv[i] = piv + 1;
3440 if (piv != i)
3441 {
3442 // swap rows i and piv in both L and U parts
3443 for (int j = 0; j < m; j++)
3444 {
3445 mfem::Swap<real_t>(data_ptr[i+j*m], data_ptr[piv+j*m]);
3446 }
3447 }
3448 }
3449
3450 if (abs(data_ptr[i + i*m]) <= TOL)
3451 {
3452 return false; // failed
3453 }
3454
3455 const real_t a_ii_inv = 1.0 / data_ptr[i+i*m];
3456 for (int j = i+1; j < m; j++)
3457 {
3458 data_ptr[j+i*m] *= a_ii_inv;
3459 }
3460 for (int k = i+1; k < m; k++)
3461 {
3462 const real_t a_ik = data_ptr[i+k*m];
3463 for (int j = i+1; j < m; j++)
3464 {
3465 data_ptr[j+k*m] -= a_ik * data_ptr[j+i*m];
3466 }
3467 }
3468 }
3469#endif
3470
3471 return true; // success
3472}
3473
3475{
3476 real_t det = 1.0;
3477 for (int i=0; i<m; i++)
3478 {
3479 if (ipiv[i] != i - ipiv_base)
3480 {
3481 det *= -data[m * i + i];
3482 }
3483 else
3484 {
3485 det *= data[m * i + i];
3486 }
3487 }
3488 return det;
3489}
3490
3491void LUFactors::Mult(int m, int n, real_t *X) const
3492{
3493 real_t *x = X;
3494 for (int k = 0; k < n; k++)
3495 {
3496 // X <- U X
3497 for (int i = 0; i < m; i++)
3498 {
3499 real_t x_i = x[i] * data[i+i*m];
3500 for (int j = i+1; j < m; j++)
3501 {
3502 x_i += x[j] * data[i+j*m];
3503 }
3504 x[i] = x_i;
3505 }
3506 // X <- L X
3507 for (int i = m-1; i >= 0; i--)
3508 {
3509 real_t x_i = x[i];
3510 for (int j = 0; j < i; j++)
3511 {
3512 x_i += x[j] * data[i+j*m];
3513 }
3514 x[i] = x_i;
3515 }
3516 // X <- P^{-1} X
3517 for (int i = m-1; i >= 0; i--)
3518 {
3519 mfem::Swap<real_t>(x[i], x[ipiv[i]-ipiv_base]);
3520 }
3521 x += m;
3522 }
3523}
3524
3525void LUFactors::LSolve(int m, int n, real_t *X) const
3526{
3527 real_t *x = X;
3528 for (int k = 0; k < n; k++)
3529 {
3530 kernels::LSolve(data, m, ipiv, x);
3531 x += m;
3532 }
3533}
3534
3535void LUFactors::USolve(int m, int n, real_t *X) const
3536{
3537 real_t *x = X;
3538 for (int k = 0; k < n; k++)
3539 {
3540 kernels::USolve(data, m, x);
3541 x += m;
3542 }
3543}
3544
3545void LUFactors::Solve(int m, int n, real_t *X) const
3546{
3547#ifdef MFEM_USE_LAPACK
3548 char trans = 'N';
3549 int info = 0;
3550 if (m > 0 && n > 0)
3551 {
3552 MFEM_LAPACK_PREFIX(getrs_)(&trans, &m, &n, data, &m, ipiv, X, &m, &info);
3553 }
3554 MFEM_VERIFY(!info, "LAPACK: error in DGETRS");
3555#else
3556 // compiling without LAPACK
3557 LSolve(m, n, X);
3558 USolve(m, n, X);
3559#endif
3560}
3561
3562void LUFactors::RightSolve(int m, int n, real_t *X) const
3563{
3564 real_t *x;
3565#ifdef MFEM_USE_LAPACK
3566 char n_ch = 'N', side = 'R', u_ch = 'U', l_ch = 'L';
3567 real_t alpha = 1.0;
3568 if (m > 0 && n > 0)
3569 {
3570 MFEM_LAPACK_PREFIX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
3571 MFEM_LAPACK_PREFIX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
3572 }
3573#else
3574 // compiling without LAPACK
3575 // X <- X U^{-1}
3576 x = X;
3577 for (int k = 0; k < n; k++)
3578 {
3579 for (int j = 0; j < m; j++)
3580 {
3581 const real_t x_j = ( x[j*n] /= data[j+j*m]);
3582 for (int i = j+1; i < m; i++)
3583 {
3584 x[i*n] -= data[j + i*m] * x_j;
3585 }
3586 }
3587 ++x;
3588 }
3589
3590 // X <- X L^{-1}
3591 x = X;
3592 for (int k = 0; k < n; k++)
3593 {
3594 for (int j = m-1; j >= 0; j--)
3595 {
3596 const real_t x_j = x[j*n];
3597 for (int i = 0; i < j; i++)
3598 {
3599 x[i*n] -= data[j + i*m] * x_j;
3600 }
3601 }
3602 ++x;
3603 }
3604#endif
3605 // X <- X P
3606 x = X;
3607 for (int k = 0; k < n; k++)
3608 {
3609 for (int i = m-1; i >= 0; --i)
3610 {
3611 mfem::Swap<real_t>(x[i*n], x[(ipiv[i]-ipiv_base)*n]);
3612 }
3613 ++x;
3614 }
3615}
3616
3618{
3619 // A^{-1} = U^{-1} L^{-1} P
3620 // X <- U^{-1} (set only the upper triangular part of X)
3621 real_t *x = X;
3622 for (int k = 0; k < m; k++)
3623 {
3624 const real_t minus_x_k = -( x[k] = 1.0/data[k+k*m] );
3625 for (int i = 0; i < k; i++)
3626 {
3627 x[i] = data[i+k*m] * minus_x_k;
3628 }
3629 for (int j = k-1; j >= 0; j--)
3630 {
3631 const real_t x_j = ( x[j] /= data[j+j*m] );
3632 for (int i = 0; i < j; i++)
3633 {
3634 x[i] -= data[i+j*m] * x_j;
3635 }
3636 }
3637 x += m;
3638 }
3639 // X <- X L^{-1} (use input only from the upper triangular part of X)
3640 {
3641 int k = m-1;
3642 for (int j = 0; j < k; j++)
3643 {
3644 const real_t minus_L_kj = -data[k+j*m];
3645 for (int i = 0; i <= j; i++)
3646 {
3647 X[i+j*m] += X[i+k*m] * minus_L_kj;
3648 }
3649 for (int i = j+1; i < m; i++)
3650 {
3651 X[i+j*m] = X[i+k*m] * minus_L_kj;
3652 }
3653 }
3654 }
3655 for (int k = m-2; k >= 0; k--)
3656 {
3657 for (int j = 0; j < k; j++)
3658 {
3659 const real_t L_kj = data[k+j*m];
3660 for (int i = 0; i < m; i++)
3661 {
3662 X[i+j*m] -= X[i+k*m] * L_kj;
3663 }
3664 }
3665 }
3666 // X <- X P
3667 for (int k = m-1; k >= 0; k--)
3668 {
3669 const int piv_k = ipiv[k]-ipiv_base;
3670 if (k != piv_k)
3671 {
3672 for (int i = 0; i < m; i++)
3673 {
3674 Swap<real_t>(X[i+k*m], X[i+piv_k*m]);
3675 }
3676 }
3677 }
3678}
3679
3680void LUFactors::SubMult(int m, int n, int r, const real_t *A21,
3681 const real_t *X1, real_t *X2)
3682{
3683 kernels::SubMult(m, n, r, A21, X1, X2);
3684}
3685
3687 int m, int n, real_t *A12, real_t *A21, real_t *A22) const
3688{
3689 kernels::BlockFactor(data, m, ipiv, n, A12, A21, A22);
3690}
3691
3692void LUFactors::BlockForwSolve(int m, int n, int r, const real_t *L21,
3693 real_t *B1, real_t *B2) const
3694{
3695 // B1 <- L^{-1} P B1
3696 LSolve(m, r, B1);
3697 // B2 <- B2 - L21 B1
3698 SubMult(m, n, r, L21, B1, B2);
3699}
3700
3701void LUFactors::BlockBackSolve(int m, int n, int r, const real_t *U12,
3702 const real_t *X2, real_t *Y1) const
3703{
3704 // Y1 <- Y1 - U12 X2
3705 SubMult(n, m, r, U12, X2, Y1);
3706 // Y1 <- U^{-1} Y1
3707 USolve(m, r, Y1);
3708}
3709
3710
3712{
3713#ifdef MFEM_USE_LAPACK
3714 int info = 0;
3715 char uplo = 'L';
3716 MFEM_VERIFY(data, "Matrix data not set");
3717 if (m) { MFEM_LAPACK_PREFIX(potrf_)(&uplo, &m, data, &m, &info); }
3718 return info == 0;
3719#else
3720 // Cholesky–Crout algorithm
3721 for (int j = 0; j<m; j++)
3722 {
3723 real_t a = 0.;
3724 for (int k = 0; k<j; k++)
3725 {
3726 a+=data[j+k*m]*data[j+k*m];
3727 }
3728
3729 MFEM_VERIFY(data[j+j*m] - a > 0.,
3730 "CholeskyFactors::Factor: The matrix is not SPD");
3731
3732 data[j+j*m] = std::sqrt(data[j+j*m] - a);
3733
3734 if (data[j + j*m] <= TOL)
3735 {
3736 return false; // failed
3737 }
3738
3739 for (int i = j+1; i<m; i++)
3740 {
3741 a = 0.;
3742 for (int k = 0; k<j; k++)
3743 {
3744 a+= data[i+k*m]*data[j+k*m];
3745 }
3746 data[i+j*m] = 1./data[j+m*j]*(data[i+j*m] - a);
3747 }
3748 }
3749 return true; // success
3750#endif
3751}
3752
3754{
3755 real_t det = 1.0;
3756 for (int i=0; i<m; i++)
3757 {
3758 det *= data[i + i*m];
3759 }
3760 return det;
3761}
3762
3763void CholeskyFactors::LMult(int m, int n, real_t * X) const
3764{
3765 // X <- L X
3766 real_t *x = X;
3767 for (int k = 0; k < n; k++)
3768 {
3769 for (int j = m-1; j >= 0; j--)
3770 {
3771 real_t x_j = x[j] * data[j+j*m];
3772 for (int i = 0; i < j; i++)
3773 {
3774 x_j += x[i] * data[j+i*m];
3775 }
3776 x[j] = x_j;
3777 }
3778 x += m;
3779 }
3780}
3781
3782void CholeskyFactors::UMult(int m, int n, real_t * X) const
3783{
3784 real_t *x = X;
3785 for (int k = 0; k < n; k++)
3786 {
3787 for (int i = 0; i < m; i++)
3788 {
3789 real_t x_i = x[i] * data[i+i*m];
3790 for (int j = i+1; j < m; j++)
3791 {
3792 x_i += x[j] * data[j+i*m];
3793 }
3794 x[i] = x_i;
3795 }
3796 x += m;
3797 }
3798}
3799
3800void CholeskyFactors::LSolve(int m, int n, real_t * X) const
3801{
3802
3803#ifdef MFEM_USE_LAPACK
3804 char uplo = 'L';
3805 char trans = 'N';
3806 char diag = 'N';
3807 int info = 0;
3808
3809 MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
3810 &info);
3811 MFEM_VERIFY(!info, "CholeskyFactors:LSolve:: info");
3812
3813#else
3814 real_t *x = X;
3815 for (int k = 0; k < n; k++)
3816 {
3817 // X <- L^{-1} X
3818 for (int j = 0; j < m; j++)
3819 {
3820 const real_t x_j = (x[j] /= data[j+j*m]);
3821 for (int i = j+1; i < m; i++)
3822 {
3823 x[i] -= data[i+j*m] * x_j;
3824 }
3825 }
3826 x += m;
3827 }
3828#endif
3829}
3830
3831void CholeskyFactors::USolve(int m, int n, real_t * X) const
3832{
3833#ifdef MFEM_USE_LAPACK
3834
3835 char uplo = 'L';
3836 char trans = 'T';
3837 char diag = 'N';
3838 int info = 0;
3839
3840 MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
3841 &info);
3842 MFEM_VERIFY(!info, "CholeskyFactors:USolve:: info");
3843
3844#else
3845 // X <- L^{-t} X
3846 real_t *x = X;
3847 for (int k = 0; k < n; k++)
3848 {
3849 for (int j = m-1; j >= 0; j--)
3850 {
3851 const real_t x_j = ( x[j] /= data[j+j*m] );
3852 for (int i = 0; i < j; i++)
3853 {
3854 x[i] -= data[j+i*m] * x_j;
3855 }
3856 }
3857 x += m;
3858 }
3859#endif
3860}
3861
3862void CholeskyFactors::Solve(int m, int n, real_t * X) const
3863{
3864#ifdef MFEM_USE_LAPACK
3865 char uplo = 'L';
3866 int info = 0;
3867 MFEM_LAPACK_PREFIX(potrs_)(&uplo, &m, &n, data, &m, X, &m, &info);
3868 MFEM_VERIFY(!info, "CholeskyFactors:Solve:: info");
3869
3870#else
3871 LSolve(m, n, X);
3872 USolve(m, n, X);
3873#endif
3874}
3875
3876void CholeskyFactors::RightSolve(int m, int n, real_t * X) const
3877{
3878#ifdef MFEM_USE_LAPACK
3879 char side = 'R';
3880 char uplo = 'L';
3881 char transt = 'T';
3882 char trans = 'N';
3883 char diag = 'N';
3884
3885 real_t alpha = 1.0;
3886 if (m > 0 && n > 0)
3887 {
3888 MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
3889 MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
3890 }
3891#else
3892 // X <- X L^{-t}
3893 real_t *x = X;
3894 for (int k = 0; k < n; k++)
3895 {
3896 for (int j = 0; j < m; j++)
3897 {
3898 const real_t x_j = ( x[j*n] /= data[j+j*m]);
3899 for (int i = j+1; i < m; i++)
3900 {
3901 x[i*n] -= data[i + j*m] * x_j;
3902 }
3903 }
3904 ++x;
3905 }
3906 // X <- X L^{-1}
3907 x = X;
3908 for (int k = 0; k < n; k++)
3909 {
3910 for (int j = m-1; j >= 0; j--)
3911 {
3912 const real_t x_j = (x[j*n] /= data[j+j*m]);
3913 for (int i = 0; i < j; i++)
3914 {
3915 x[i*n] -= data[j + i*m] * x_j;
3916 }
3917 }
3918 ++x;
3919 }
3920#endif
3921}
3922
3924{
3925 // A^{-1} = L^{-t} L^{-1}
3926#ifdef MFEM_USE_LAPACK
3927 // copy the lower triangular part of L to X
3928 for (int i = 0; i<m; i++)
3929 {
3930 for (int j = i; j<m; j++)
3931 {
3932 X[j+i*m] = data[j+i*m];
3933 }
3934 }
3935 char uplo = 'L';
3936 int info = 0;
3937 MFEM_LAPACK_PREFIX(potri_)(&uplo, &m, X, &m, &info);
3938 MFEM_VERIFY(!info, "CholeskyFactors:GetInverseMatrix:: info");
3939 // fill in the upper triangular part
3940 for (int i = 0; i<m; i++)
3941 {
3942 for (int j = i+1; j<m; j++)
3943 {
3944 X[i+j*m] = X[j+i*m];
3945 }
3946 }
3947#else
3948 // L^-t * L^-1 (in place)
3949 for (int k = 0; k<m; k++)
3950 {
3951 X[k+k*m] = 1./data[k+k*m];
3952 for (int i = k+1; i < m; i++)
3953 {
3954 real_t s=0.;
3955 for (int j=k; j<i; j++)
3956 {
3957 s -= data[i+j*m] * X[j+k*m]/data[i+i*m];
3958 }
3959 X[i+k*m] = s;
3960 }
3961 }
3962 for (int i = 0; i < m; i++)
3963 {
3964 for (int j = i; j < m; j++)
3965 {
3966 real_t s = 0.;
3967 for (int k=j; k<m; k++)
3968 {
3969 s += X[k+i*m] * X[k+j*m];
3970 }
3971 X[i+j*m] = X[j+i*m] = s;
3972 }
3973 }
3974#endif
3975}
3976
3977
3978void DenseMatrixInverse::Init(int m)
3979{
3980 if (spd)
3981 {
3982 factors = new CholeskyFactors();
3983 }
3984 else
3985 {
3986 factors = new LUFactors();
3987 }
3988 if (m>0)
3989 {
3990 factors->data = new real_t[m*m];
3991 if (!spd)
3992 {
3993 dynamic_cast<LUFactors *>(factors)->ipiv = new int[m];
3994 }
3995 own_data = true;
3996 }
3997}
3998
4000 : MatrixInverse(mat), spd(spd_)
4001{
4002 MFEM_ASSERT(height == width, "not a square matrix");
4003 a = &mat;
4004 Init(width);
4005 Factor();
4006}
4007
4009 : MatrixInverse(*mat), spd(spd_)
4010{
4011 MFEM_ASSERT(height == width, "not a square matrix");
4012 a = mat;
4013 Init(width);
4014}
4015
4017{
4018 MFEM_ASSERT(a, "DenseMatrix is not given");
4019 const real_t *adata = a->data;
4020 const int s = width*width;
4021 for (int i = 0; i < s; i++)
4022 {
4023 factors->data[i] = adata[i];
4024 }
4025 factors->Factor(width);
4026}
4027
4029{
4030 Ainv.SetSize(width);
4031 factors->GetInverseMatrix(width,Ainv.Data());
4032}
4033
4035{
4036 MFEM_VERIFY(mat.height == mat.width, "DenseMatrix is not square!");
4037 if (width != mat.width)
4038 {
4039 height = width = mat.width;
4040 if (own_data) { delete [] factors->data; }
4041 factors->data = new real_t[width*width];
4042
4043 if (!spd)
4044 {
4045 LUFactors * lu = dynamic_cast<LUFactors *>(factors);
4046 if (own_data) { delete [] lu->ipiv; }
4047 lu->ipiv = new int[width];
4048 }
4049 own_data = true;
4050 }
4051 a = &mat;
4052 Factor();
4053}
4054
4056{
4057 const DenseMatrix *p = dynamic_cast<const DenseMatrix*>(&op);
4058 MFEM_VERIFY(p != NULL, "Operator is not a DenseMatrix!");
4059 Factor(*p);
4060}
4061
4063{
4064 for (int row = 0; row < height; row++)
4065 {
4066 y[row] = x[row];
4067 }
4068 factors->Solve(width, 1, y);
4069}
4070
4072{
4073 y = x;
4074 factors->Solve(width, 1, y.GetData());
4075}
4076
4078{
4079 X = B;
4080 factors->Solve(width, X.Width(), X.Data());
4081}
4082
4084{
4085 DenseMatrix C(width);
4086 Mult(*a, C);
4087 for (int i = 0; i < width; i++)
4088 {
4089 C(i,i) -= 1.0;
4090 }
4091 mfem::out << "size = " << width << ", i_max = " << C.MaxMaxNorm() << endl;
4092}
4093
4095{
4096 if (own_data)
4097 {
4098 delete [] factors->data;
4099 if (!spd)
4100 {
4101 delete [] dynamic_cast<LUFactors *>(factors)->ipiv;
4102 }
4103 }
4104 delete factors;
4105}
4106
4107#ifdef MFEM_USE_LAPACK
4108
4110 : mat(m)
4111{
4112 n = mat.Width();
4113 EVal.SetSize(n);
4114 EVect.SetSize(n);
4115 ev.SetDataAndSize(NULL, n);
4116
4117 jobz = 'V';
4118 uplo = 'U';
4119 lwork = -1;
4120 real_t qwork;
4121 MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
4122 &qwork, &lwork, &info);
4123
4124 lwork = (int) qwork;
4125 work = new real_t[lwork];
4126}
4127
4129 const DenseMatrixEigensystem &other)
4130 : mat(other.mat), EVal(other.EVal), EVect(other.EVect), ev(NULL, other.n),
4131 n(other.n)
4132{
4133 jobz = other.jobz;
4134 uplo = other.uplo;
4135 lwork = other.lwork;
4136
4137 work = new real_t[lwork];
4138}
4139
4141{
4142#ifdef MFEM_DEBUG
4143 if (mat.Width() != n)
4144 {
4145 mfem_error("DenseMatrixEigensystem::Eval(): dimension mismatch");
4146 }
4147#endif
4148
4149 EVect = mat;
4150 MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
4151 work, &lwork, &info);
4152
4153 if (info != 0)
4154 {
4155 mfem::err << "DenseMatrixEigensystem::Eval(): DSYEV error code: "
4156 << info << endl;
4157 mfem_error();
4158 }
4159}
4160
4162{
4163 delete [] work;
4164}
4165
4166
4169 bool left_eigen_vectors,
4170 bool right_eigen_vectors)
4171 : A(a), B(b)
4172{
4173 MFEM_VERIFY(A.Height() == A.Width(), "A has to be a square matrix");
4174 MFEM_VERIFY(B.Height() == B.Width(), "B has to be a square matrix");
4175 n = A.Width();
4176 MFEM_VERIFY(B.Height() == n, "A and B dimension mismatch");
4177
4178 jobvl = 'N';
4179 jobvr = 'N';
4180 A_copy.SetSize(n);
4181 B_copy.SetSize(n);
4182 if (left_eigen_vectors)
4183 {
4184 jobvl = 'V';
4185 Vl.SetSize(n);
4186 }
4187 if (right_eigen_vectors)
4188 {
4189 jobvr = 'V';
4190 Vr.SetSize(n);
4191 }
4192
4193 lwork = -1;
4194 real_t qwork;
4195
4196 alphar = new real_t[n];
4197 alphai = new real_t[n];
4198 beta = new real_t[n];
4199
4200 int nl = max(1,Vl.Height());
4201 int nr = max(1,Vr.Height());
4202
4203 MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
4204 alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
4205 &nr, &qwork, &lwork, &info);
4206
4207 lwork = (int) qwork;
4208 work = new real_t[lwork];
4209}
4210
4212{
4213 int nl = max(1,Vl.Height());
4214 int nr = max(1,Vr.Height());
4215
4216 A_copy = A;
4217 B_copy = B;
4218 MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
4219 alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
4220 &nr, work, &lwork, &info);
4221 if (info != 0)
4222 {
4223 mfem::err << "DenseMatrixGeneralizedEigensystem::Eval(): DGGEV error code: "
4224 << info << endl;
4225 mfem_error();
4226 }
4227 evalues_r.SetSize(n);
4228 evalues_i.SetSize(n);
4229 for (int i = 0; i<n; i++)
4230 {
4231 if (beta[i] != 0.)
4232 {
4233 evalues_r(i) = alphar[i]/beta[i];
4234 evalues_i(i) = alphai[i]/beta[i];
4235 }
4236 else
4237 {
4238 evalues_r(i) = infinity();
4239 evalues_i(i) = infinity();
4240 }
4241 }
4242}
4243
4245{
4246 delete [] alphar;
4247 delete [] alphai;
4248 delete [] beta;
4249 delete [] work;
4250}
4251
4253 bool left_singular_vectors,
4254 bool right_singular_vectors)
4255{
4256 m = M.Height();
4257 n = M.Width();
4258 jobu = (left_singular_vectors)? 'S' : 'N';
4259 jobvt = (right_singular_vectors)? 'S' : 'N';
4260 Init();
4261}
4262
4264 bool left_singular_vectors,
4265 bool right_singular_vectors)
4266{
4267 m = h;
4268 n = w;
4269 jobu = (left_singular_vectors)? 'S' : 'N';
4270 jobvt = (right_singular_vectors)? 'S' : 'N';
4271 Init();
4272}
4273
4275 char left_singular_vectors,
4276 char right_singular_vectors)
4277{
4278 m = M.Height();
4279 n = M.Width();
4280 jobu = left_singular_vectors;
4281 jobvt = right_singular_vectors;
4282 Init();
4283}
4284
4286 char left_singular_vectors,
4287 char right_singular_vectors)
4288{
4289 m = h;
4290 n = w;
4291 jobu = left_singular_vectors;
4292 jobvt = right_singular_vectors;
4293 Init();
4294}
4295
4296void DenseMatrixSVD::Init()
4297{
4298 sv.SetSize(min(m, n));
4299 real_t qwork;
4300 lwork = -1;
4301 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(),
4302 NULL, &m, NULL, &n, &qwork, &lwork, &info);
4303 lwork = (int) qwork;
4304 work = new real_t[lwork];
4305}
4306
4308{
4309#ifdef MFEM_DEBUG
4310 if (M.Height() != m || M.Width() != n)
4311 {
4312 mfem_error("DenseMatrixSVD::Eval()");
4313 }
4314#endif
4315 real_t * datau = nullptr;
4316 real_t * datavt = nullptr;
4317 if (jobu == 'A')
4318 {
4319 U.SetSize(m,m);
4320 datau = U.Data();
4321 }
4322 else if (jobu == 'S')
4323 {
4324 U.SetSize(m,min(m,n));
4325 datau = U.Data();
4326 }
4327 if (jobvt == 'A')
4328 {
4329 Vt.SetSize(n,n);
4330 datavt = Vt.Data();
4331 }
4332 else if (jobvt == 'S')
4333 {
4334 Vt.SetSize(min(m,n),n);
4335 datavt = Vt.Data();
4336 }
4337 Mc = M;
4338 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(),
4339 datau, &m, datavt, &n, work, &lwork, &info);
4340
4341 if (info)
4342 {
4343 mfem::err << "DenseMatrixSVD::Eval() : info = " << info << endl;
4344 mfem_error();
4345 }
4346}
4347
4349{
4350 delete [] work;
4351}
4352
4353#endif // if MFEM_USE_LAPACK
4354
4355
4356void DenseTensor::AddMult(const Table &elem_dof, const Vector &x, Vector &y)
4357const
4358{
4359 int n = SizeI(), ne = SizeK();
4360 const int *I = elem_dof.GetI(), *J = elem_dof.GetJ(), *dofs;
4361 const real_t *d_col = tdata.HostRead();
4362 real_t *yp = y.HostReadWrite();
4363 real_t x_col;
4364 const real_t *xp = x.HostRead();
4365 // the '4' here can be tuned for given platform and compiler
4366 if (n <= 4)
4367 {
4368 for (int i = 0; i < ne; i++)
4369 {
4370 dofs = J + I[i];
4371 for (int col = 0; col < n; col++)
4372 {
4373 x_col = xp[dofs[col]];
4374 for (int row = 0; row < n; row++)
4375 {
4376 yp[dofs[row]] += x_col*d_col[row];
4377 }
4378 d_col += n;
4379 }
4380 }
4381 }
4382 else
4383 {
4384 Vector ye(n);
4385 for (int i = 0; i < ne; i++)
4386 {
4387 dofs = J + I[i];
4388 x_col = xp[dofs[0]];
4389 for (int row = 0; row < n; row++)
4390 {
4391 ye(row) = x_col*d_col[row];
4392 }
4393 d_col += n;
4394 for (int col = 1; col < n; col++)
4395 {
4396 x_col = xp[dofs[col]];
4397 for (int row = 0; row < n; row++)
4398 {
4399 ye(row) += x_col*d_col[row];
4400 }
4401 d_col += n;
4402 }
4403 for (int row = 0; row < n; row++)
4404 {
4405 yp[dofs[row]] += ye(row);
4406 }
4407 }
4408 }
4409}
4410
4412{
4413 int s = SizeI() * SizeJ() * SizeK();
4414 for (int i=0; i<s; i++)
4415 {
4416 tdata[i] = c;
4417 }
4418 return *this;
4419}
4420
4422{
4424}
4425
4426void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X)
4427{
4428 BatchedLinAlg::LUSolve(Mlu, P, X);
4429}
4430
4431#ifdef MFEM_USE_LAPACK
4432void BandedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B,
4433 Array<int> &ipiv)
4434{
4435 int LDAB = (2*KL) + KU + 1;
4436 int N = AB.NumCols();
4437 int NRHS = B.NumCols();
4438 int info;
4439 ipiv.SetSize(N);
4440 MFEM_LAPACK_PREFIX(gbsv_)(&N, &KL, &KU, &NRHS, AB.GetData(), &LDAB,
4441 ipiv.GetData(), B.GetData(), &N, &info);
4442 MFEM_ASSERT(info == 0, "BandedSolve failed in LAPACK");
4443}
4444
4445void BandedFactorizedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B,
4446 bool transpose, Array<int> &ipiv)
4447{
4448 int LDAB = (2*KL) + KU + 1;
4449 int N = AB.NumCols();
4450 int NRHS = B.NumCols();
4451 char trans = transpose ? 'T' : 'N';
4452 int info;
4453 MFEM_LAPACK_PREFIX(gbtrs_)(&trans, &N, &KL, &KU, &NRHS, AB.GetData(), &LDAB,
4454 ipiv.GetData(), B.GetData(), &N, &info);
4455 MFEM_ASSERT(info == 0, "BandedFactorizedSolve failed in LAPACK");
4456}
4457#endif
4458
4459} // namespace mfem
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:414
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:86
int Size() const
Return the logical size of the array.
Definition array.hpp:192
T * GetData()
Returns the data.
Definition array.hpp:159
static void LUFactor(DenseTensor &A, Array< int > &P)
Replaces the block diagonal matrix with its LU factors. The pivots are stored in P.
Definition batched.cpp:77
static void LUSolve(const DenseTensor &A, const Array< int > &P, Vector &x)
Replaces with , given the LU factors A and pivots P of the block-diagonal matrix .
Definition batched.cpp:82
void UMult(int m, int n, real_t *X) const
void Solve(int m, int n, real_t *X) const override
void RightSolve(int m, int n, real_t *X) const
void USolve(int m, int n, real_t *X) const
void LSolve(int m, int n, real_t *X) 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) const override
Assuming L.L^t = A factored data of size (m x m), compute X <- A^{-1}.
void LMult(int m, int n, real_t *X) const
real_t Det(int m) const override
DenseMatrixEigensystem(DenseMatrix &m)
DenseMatrixGeneralizedEigensystem(DenseMatrix &a, DenseMatrix &b, bool left_eigen_vectors=false, bool right_eigen_vectors=false)
void TestInversion()
Print the numerical conditioning of the inversion: ||A^{-1} A - I||.
DenseMatrixInverse(bool spd_=false)
Default constructor.
Definition densemat.hpp:867
virtual ~DenseMatrixInverse()
Destroys dense inverse matrix.
void Factor()
Factor the current DenseMatrix, *a.
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication with the inverse of dense matrix.
real_t Det() const
Compute the determinant of the original DenseMatrix using the LU factors.
Definition densemat.hpp:905
void GetInverseMatrix(DenseMatrix &Ainv) const
Compute and return the inverse matrix in Ainv.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
MFEM_DEPRECATED DenseMatrixSVD(DenseMatrix &M, bool left_singular_vectors=false, bool right_singular_vectors=false)
Constructor for the DenseMatrixSVD.
void Eval(DenseMatrix &M)
Evaluate the SVD.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void GetDiag(Vector &d) const
Returns the diagonal of the matrix.
void CopyMNDiag(real_t c, int n, int row_offset, int col_offset)
Copy c on the diagonal of size n to *this at row_offset, col_offset.
void AddMult_a(real_t a, const Vector &x, Vector &y) const
y += a * A.x
Definition densemat.cpp:241
void GetRowl1(Vector &l) const
Returns the l1 norm of the rows of the matrix v_i = sum_j |a_ij|.
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
Definition densemat.cpp:108
void AddMultTranspose_a(real_t a, const Vector &x, Vector &y) const
y += a * A^t x
Definition densemat.cpp:262
void Set(real_t alpha, const real_t *A)
Set the matrix to alpha * A, assuming that A has the same dimensions as the matrix and uses column-ma...
Definition densemat.cpp:580
void TestInversion()
Invert and print the numerical conditioning of the inversion.
void CopyExceptMN(const DenseMatrix &A, int m, int n)
Copy All rows and columns except m and n from A.
void CopyCols(const DenseMatrix &A, int col1, int col2)
Copy columns col1 through col2 from A to *this.
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:158
void Transpose()
(*this) = (*this)^t
void AddToVector(int offset, Vector &v) const
Add the matrix 'data' to the Vector 'v' at the given 'offset'.
void Threshold(real_t eps)
Replace small entries, abs(a_ij) <= eps, with zero.
const real_t * HostRead() const
Shortcut for mfem::Read(GetMemory(), TotalSize(), false).
Definition densemat.hpp:509
void CalcEigenvalues(real_t *lambda, real_t *vec) const
void RightScaling(const Vector &s)
RightScaling: this = this * diag(s);.
Definition densemat.cpp:325
void SetRow(int r, const real_t *row)
void SymmetricScaling(const Vector &s)
SymmetricScaling this = diag(sqrt(s)) * this * diag(sqrt(s))
Definition densemat.cpp:354
MFEM_DEPRECATED void Getl1Diag(Vector &l) const
real_t & operator()(int i, int j)
Returns reference to a_{ij}.
real_t InnerProduct(const real_t *x, const real_t *y) const
Compute y^t A x.
Definition densemat.cpp:281
real_t * Data() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:131
void GetSubMatrix(const Array< int > &idx, DenseMatrix &A) const
real_t * GetData() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:135
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
y += a * A.x
Definition densemat.cpp:194
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:125
friend class DenseMatrixInverse
Definition densemat.hpp:26
void AdjustDofDirection(const Array< int > &dofs)
void SetCol(int c, const real_t *col)
void Symmetrize()
(*this) = 1/2 ((*this) + (*this)^t)
void Invert()
Replaces the current matrix with its inverse.
Definition densemat.cpp:674
void AbsMult(const Vector &x, Vector &y) const override
Absolute-value matrix vector multiplication.
Definition densemat.cpp:135
real_t Weight() const
Definition densemat.cpp:553
void GetRowl2(Vector &l) const
Returns the l2norm of the rows of the DenseMatrix.
DenseMatrix & operator+=(const real_t *m)
Definition densemat.cpp:629
void Neg()
(*this) = -(*this)
Definition densemat.cpp:665
real_t operator*(const DenseMatrix &m) const
Matrix inner product: tr(A^t B)
Definition densemat.cpp:143
void CopyMNt(const DenseMatrix &A, int row_offset, int col_offset)
Copy matrix A^t to the location in *this at row_offset, col_offset.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
y += a * A^t x
Definition densemat.cpp:217
void AbsMultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the absolute-value transpose matrix.
Definition densemat.cpp:185
void InvRightScaling(const Vector &s)
InvRightScaling: this = this * diag(1./s);.
Definition densemat.cpp:340
void SingularValues(Vector &sv) const
real_t FNorm() const
Compute the Frobenius norm of the matrix.
Definition densemat.hpp:294
void InvLeftScaling(const Vector &s)
InvLeftScaling this = diag(1./s) * this.
Definition densemat.cpp:312
void SetSubMatrix(const Array< int > &idx, const DenseMatrix &A)
Set (*this)(idx[i],idx[j]) = A(i,j)
virtual void PrintT(std::ostream &out=mfem::out, int width_=4) const
Prints the transpose matrix to stream out.
void AddSubMatrix(const Array< int > &idx, const DenseMatrix &A)
(*this)(idx[i],idx[j]) += A(i,j)
real_t Trace() const
Trace of a square matrix.
Definition densemat.cpp:409
void Diag(real_t c, int n)
Creates n x n diagonal matrix with diagonal elements c.
void SquareRootInverse()
Replaces the current matrix with its square root inverse.
Definition densemat.cpp:784
virtual void PrintMathematica(std::ostream &out=mfem::out) const
DenseMatrix & operator*=(real_t c)
Definition densemat.cpp:655
void Swap(DenseMatrix &other)
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0<=i.
void GetRowSums(Vector &l) const
Returns the row sums of the DenseMatrix.
real_t & Elem(int i, int j) override
Returns reference to a_{ij}.
Definition densemat.cpp:98
void CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this.
void InvSymmetricScaling(const Vector &s)
InvSymmetricScaling this = diag(sqrt(1./s)) * this * diag(sqrt(1./s))
Definition densemat.cpp:382
int Rank(real_t tol) const
void Add(const real_t c, const DenseMatrix &A)
Adds the matrix A multiplied by the number c to the matrix.
Definition densemat.cpp:589
void PrintMatlab(std::ostream &out=mfem::out) const override
Prints operator in Matlab format.
void LeftScaling(const Vector &s)
LeftScaling this = diag(s) * this.
Definition densemat.cpp:299
DenseMatrix & operator-=(const DenseMatrix &m)
Definition densemat.cpp:642
real_t CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
void GradToCurl(DenseMatrix &curl)
DenseMatrix & operator=(const DenseMatrix &)=default
Copy assignment (deep copy).
void Print(std::ostream &out=mfem::out, int width_=4) const override
Prints matrix to stream out.
void GetColumn(int c, Vector &col) const
void GradToVectorCurl2D(DenseMatrix &curl)
MatrixInverse * Inverse() const override
Returns a pointer to the inverse matrix.
Definition densemat.cpp:428
real_t MaxMaxNorm() const
Compute the norm ||A|| = max_{ij} |A_{ij}|.
Definition densemat.cpp:842
void Norm2(real_t *v) const
Take the 2-norm of the columns of A and store in v.
Definition densemat.cpp:829
void GetFromVector(int offset, const Vector &v)
Get the matrix 'data' from the Vector 'v' at the given 'offset'.
void GetRow(int r, Vector &row) const
void CopyRows(const DenseMatrix &A, int row1, int row2)
Copy rows row1 through row2 from A to *this.
real_t Det() const
Definition densemat.cpp:496
void GradToDiv(Vector &div)
Rank 3 tensor (array of matrices)
DenseTensor & operator=(const DenseTensor &other)
int SizeJ() const
void AddMult(const Table &elem_dof, const Vector &x, Vector &y) const
int SizeI() const
int SizeK() const
virtual void GetInverseMatrix(int m, real_t *X) const
Definition densemat.hpp:683
virtual void Solve(int m, int n, real_t *X) const
Definition densemat.hpp:678
real_t * data
Definition densemat.hpp:660
virtual bool Factor(int m, real_t TOL=0.0)
Definition densemat.hpp:666
A class to initialize the size of a Tensor.
Definition dtensor.hpp:57
void LSolve(int m, int n, real_t *X) const
static void SubMult(int m, int n, int r, const real_t *A21, const real_t *X1, real_t *X2)
bool Factor(int m, real_t TOL=0.0) override
Compute the LU factorization of the current matrix.
void Mult(int m, int n, real_t *X) const
void USolve(int m, int n, real_t *X) const
void BlockFactor(int m, int n, real_t *A12, real_t *A21, real_t *A22) const
real_t Det(int m) const override
void BlockForwSolve(int m, int n, int r, const real_t *L21, real_t *B1, real_t *B2) const
void Solve(int m, int n, real_t *X) const override
void RightSolve(int m, int n, real_t *X) const
void BlockBackSolve(int m, int n, int r, const real_t *U12, const real_t *X2, real_t *Y1) const
void GetInverseMatrix(int m, real_t *X) const override
Assuming L.U = P.A factored data of size (m x m), compute X <- A^{-1}.
static constexpr int ipiv_base
Definition densemat.hpp:698
Abstract data type for matrix inverse.
Definition matrix.hpp:63
Abstract data type matrix.
Definition matrix.hpp:28
bool IsSquare() const
Returns whether the matrix is a square matrix.
Definition matrix.hpp:39
Abstract operator.
Definition operator.hpp:27
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:30
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition operator.hpp:77
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
Definition table.hpp:43
int * GetJ()
Definition table.hpp:128
int * GetI()
Definition table.hpp:127
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
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
mfem::real_t real_t
MFEM_HOST_DEVICE void CalcInverse(const T *data, T *inv_data)
Return the inverse of a matrix with given size and data into the matrix with data inv_data.
Definition kernels.hpp:306
MFEM_HOST_DEVICE real_t CalcSingularvalue< 2 >(const real_t *data, const int i)
Return the i'th singular value of the matrix of size 2 with given data.
Definition kernels.hpp:1472
MFEM_HOST_DEVICE void CalcEigenvalues< 2 >(const real_t *data, real_t *lambda, real_t *vec)
Definition kernels.hpp:1239
MFEM_HOST_DEVICE void Add(const int height, const int width, const TALPHA alpha, const TA *Adata, const TB *Bdata, TC *Cdata)
Compute C = A + alpha*B, where the matrices A, B and C are of size height x width with data Adata,...
Definition kernels.hpp:326
MFEM_HOST_DEVICE void AbsMult(const int height, const int width, const TA *data, const TX *x, TY *y)
Absolute-value matrix vector multiplication: y = |A| x, where the matrix A is of size height x width ...
Definition kernels.hpp:193
MFEM_HOST_DEVICE void Mult(const int height, const int width, const TA *data, const TX *x, TY *y)
Matrix vector multiplication: y = A x, where the matrix A is of size height x width with given data,...
Definition kernels.hpp:160
MFEM_HOST_DEVICE void CalcLeftInverse< 2, 1 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1200
MFEM_HOST_DEVICE void LSolve(const real_t *data, const int m, const int *ipiv, real_t *x)
Assuming L.U = P.A factored matrix of size (m x m), compute X <- L^{-1} P X, for a vector X of length...
Definition kernels.hpp:1760
MFEM_HOST_DEVICE void MultABt(const int Aheight, const int Awidth, const int Bheight, const TA *Adata, const TB *Bdata, TC *ABtdata)
Multiply a matrix of size Aheight x Awidth and data Adata with the transpose of a matrix of size Bhei...
Definition kernels.hpp:443
MFEM_HOST_DEVICE void MultTranspose(const int height, const int width, const TA *data, const TX *x, TY *y)
Matrix transpose vector multiplication: y = At x, where the matrix A is of size height x width with g...
Definition kernels.hpp:227
MFEM_HOST_DEVICE void USolve(const real_t *data, const int m, real_t *x)
Assuming L.U = P.A factored matrix of size (m x m), compute X <- U^{-1} X, for a vector X of length m...
Definition kernels.hpp:1785
MFEM_HOST_DEVICE void AbsMultTranspose(const int height, const int width, const TA *data, const TX *x, TY *y)
Absolute-value matrix transpose vector multiplication: y = |At| x, where the matrix A is of size heig...
Definition kernels.hpp:256
MFEM_HOST_DEVICE void Symmetrize(const int size, T *data)
Symmetrize a square matrix with given size and data: A -> (A+A^T)/2.
Definition kernels.hpp:283
MFEM_HOST_DEVICE void CalcLeftInverse< 3, 2 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1217
MFEM_HOST_DEVICE void BlockFactor(const real_t *data, int m, const int *ipiv, int n, real_t *A12, real_t *A21, real_t *A22)
Definition kernels.hpp:1843
MFEM_HOST_DEVICE void CalcLeftInverse< 3, 1 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1208
MFEM_HOST_DEVICE real_t CalcSingularvalue< 3 >(const real_t *data, const int i)
Return the i'th singular value of the matrix of size 3 with given data.
Definition kernels.hpp:1520
MFEM_HOST_DEVICE void CalcEigenvalues< 3 >(const real_t *data, real_t *lambda, real_t *vec)
Definition kernels.hpp:1270
MFEM_HOST_DEVICE void SubMult(const int m, const int n, const int r, const real_t *A21, const real_t *X1, real_t *X2)
Given an (n x m) matrix A21, compute X2 <- X2 - A21 X1, for matrices X1, and X2 of size (m x r) and (...
Definition kernels.hpp:1815
void CalcOrtho(const DenseMatrix &J, Vector &n)
void AddMult_a_ABt(real_t a, const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
ABt += a * A * B^t.
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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:505
void BatchLUSolve(const DenseTensor &Mlu, const Array< int > &P, Vector &X)
Solve batch linear systems. Calls BatchedLinAlg::LUSolve.
void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += alpha * B * C.
void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat)
Calculate the transposed adjugate of a matrix (for NxN matrices, N=1,2,3)
void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
void MultADBt(const DenseMatrix &A, const Vector &D, const DenseMatrix &B, DenseMatrix &ADBt)
ADBt = A D B^t, where D is diagonal.
void AddMultVVt(const Vector &v, DenseMatrix &VVt)
VVt += v v^t.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void dsygv_Eigensystem(DenseMatrix &a, DenseMatrix &b, Vector &ev, DenseMatrix *evect)
void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
Definition densemat.cpp:891
void MultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
ADAt = A D A^t, where D is diagonal.
void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
Multiply a matrix A with the transpose of a matrix B: A*Bt.
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
void AddMult_a_VWt(const real_t a, const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += a * v w^t.
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
void AddMult_a_VVt(const real_t a, const Vector &v, DenseMatrix &VVt)
VVt += a * v v^t.
void BatchLUFactor(DenseTensor &Mlu, Array< int > &P, const real_t TOL)
Compute the LU factorization of a batch of matrices. Calls BatchedLinAlg::LUFactor.
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
Definition array.hpp:767
void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += v w^t.
int CheckFinite(const real_t *v, const int n)
Definition vector.hpp:613
void AddMult_a_AtB(real_t a, const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
AtB += a * A^t * B.
void dsyev_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
void MultVVt(const Vector &v, DenseMatrix &vvt)
Make a matrix from a vector V.Vt.
bool LinearSolve(DenseMatrix &A, real_t *X, real_t TOL)
Solves the dense linear system, A * X = B for X
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition globals.hpp:71
void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
ABt += A * B^t.
void AddMult_a_AAt(real_t a, const DenseMatrix &A, DenseMatrix &AAt)
AAt += a * A * A^t.
void MultAAt(const DenseMatrix &a, DenseMatrix &aat)
Calculate the matrix A.At.
void CalcInverseTranspose(const DenseMatrix &a, DenseMatrix &inva)
Calculate the inverse transpose of a matrix (for NxN matrices, N=1,2,3)
void AddMultADBt(const DenseMatrix &A, const Vector &D, const DenseMatrix &B, DenseMatrix &ADBt)
ADBt = A D B^t, where D is diagonal.
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:46
void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += B * C.
void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
AtB += A^t * B.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void BandedFactorizedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B, bool transpose, Array< int > &ipiv)
void Mult_a_AAt(real_t a, const DenseMatrix &A, DenseMatrix &AAt)
AAt = a * A * A^t.
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
void AddMultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
ADAt += A D A^t, where D is diagonal.
void BandedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B, Array< int > &ipiv)
STL namespace.
real_t p(const Vector &x, real_t t)
MFEM_HOST_DEVICE real_t norm(const Complex &z)
MFEM_HOST_DEVICE real_t abs(const Complex &z)