MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
densemat.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12
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 for (int i = 0; i < height; i++)
1377 {
1378 real_t d = 0.0;
1379 for (int j = 0; j < width; j++)
1380 {
1381 d += operator()(i, j);
1382 }
1383 l(i) = d;
1384 }
1385}
1386
1388{
1389 SetSize(n);
1390
1391 const int N = n*n;
1392 for (int i = 0; i < N; i++)
1393 {
1394 data[i] = 0.0;
1395 }
1396 for (int i = 0; i < n; i++)
1397 {
1398 data[i*(n+1)] = c;
1399 }
1400}
1401
1402void DenseMatrix::Diag(real_t *diag, int n)
1403{
1404 SetSize(n);
1405
1406 int i, N = n*n;
1407 for (i = 0; i < N; i++)
1408 {
1409 data[i] = 0.0;
1410 }
1411 for (i = 0; i < n; i++)
1412 {
1413 data[i*(n+1)] = diag[i];
1414 }
1415}
1416
1418{
1419 int i, j;
1420 real_t t;
1421
1422 if (Width() == Height())
1423 {
1424 for (i = 0; i < Height(); i++)
1425 for (j = i+1; j < Width(); j++)
1426 {
1427 t = (*this)(i,j);
1428 (*this)(i,j) = (*this)(j,i);
1429 (*this)(j,i) = t;
1430 }
1431 }
1432 else
1433 {
1434 DenseMatrix T(*this,'t');
1435 (*this) = T;
1436 }
1437}
1438
1440{
1441 SetSize(A.Width(),A.Height());
1442
1443 for (int i = 0; i < Height(); i++)
1444 for (int j = 0; j < Width(); j++)
1445 {
1446 (*this)(i,j) = A(j,i);
1447 }
1448}
1449
1451{
1452#ifdef MFEM_DEBUG
1453 if (Width() != Height())
1454 {
1455 mfem_error("DenseMatrix::Symmetrize() : not a square matrix!");
1456 }
1457#endif
1459}
1460
1462{
1463 for (int i = 0; i < Height(); i++)
1464 {
1465 real_t L = 0.0;
1466 for (int j = 0; j < Width(); j++)
1467 {
1468 L += (*this)(i, j);
1469 (*this)(i, j) = 0.0;
1470 }
1471 (*this)(i, i) = L;
1472 }
1473}
1474
1476{
1477 int n = Height();
1478
1479#ifdef MFEM_DEBUG
1480 if ((Width() != 2 || curl.Width() != 1 || 2*n != curl.Height()) &&
1481 (Width() != 3 || curl.Width() != 3 || 3*n != curl.Height()))
1482 {
1483 mfem_error("DenseMatrix::GradToCurl(...): dimension mismatch");
1484 }
1485#endif
1486
1487 if (Width() == 2)
1488 {
1489 for (int i = 0; i < n; i++)
1490 {
1491 // (x,y) is grad of Ui
1492 real_t x = (*this)(i,0);
1493 real_t y = (*this)(i,1);
1494
1495 int j = i+n;
1496
1497 // curl of (Ui,0)
1498 curl(i,0) = -y;
1499
1500 // curl of (0,Ui)
1501 curl(j,0) = x;
1502 }
1503 }
1504 else
1505 {
1506 for (int i = 0; i < n; i++)
1507 {
1508 // (x,y,z) is grad of Ui
1509 real_t x = (*this)(i,0);
1510 real_t y = (*this)(i,1);
1511 real_t z = (*this)(i,2);
1512
1513 int j = i+n;
1514 int k = j+n;
1515
1516 // curl of (Ui,0,0)
1517 curl(i,0) = 0.;
1518 curl(i,1) = z;
1519 curl(i,2) = -y;
1520
1521 // curl of (0,Ui,0)
1522 curl(j,0) = -z;
1523 curl(j,1) = 0.;
1524 curl(j,2) = x;
1525
1526 // curl of (0,0,Ui)
1527 curl(k,0) = y;
1528 curl(k,1) = -x;
1529 curl(k,2) = 0.;
1530 }
1531 }
1532}
1533
1535{
1536 MFEM_VERIFY(Width() == 2,
1537 "DenseMatrix::GradToVectorCurl2D(...): dimension must be 2")
1538
1539 int n = Height();
1540 // rotate gradient
1541 for (int i = 0; i < n; i++)
1542 {
1543 curl(i,0) = (*this)(i,1);
1544 curl(i,1) = -(*this)(i,0);
1545 }
1546}
1547
1549{
1550 MFEM_ASSERT(Width()*Height() == div.Size(), "incompatible Vector 'div'!");
1551
1552 // div(dof*j+i) <-- (*this)(i,j)
1553
1554 const int n = height * width;
1555 real_t *ddata = div.GetData();
1556
1557 for (int i = 0; i < n; i++)
1558 {
1559 ddata[i] = data[i];
1560 }
1561}
1562
1563void DenseMatrix::CopyRows(const DenseMatrix &A, int row1, int row2)
1564{
1565 SetSize(row2 - row1 + 1, A.Width());
1566
1567 for (int j = 0; j < Width(); j++)
1568 {
1569 for (int i = row1; i <= row2; i++)
1570 {
1571 (*this)(i-row1,j) = A(i,j);
1572 }
1573 }
1574}
1575
1576void DenseMatrix::CopyCols(const DenseMatrix &A, int col1, int col2)
1577{
1578 SetSize(A.Height(), col2 - col1 + 1);
1579
1580 for (int j = col1; j <= col2; j++)
1581 {
1582 for (int i = 0; i < Height(); i++)
1583 {
1584 (*this)(i,j-col1) = A(i,j);
1585 }
1586 }
1587}
1588
1589void DenseMatrix::CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
1590{
1591 SetSize(m,n);
1592
1593 for (int j = 0; j < n; j++)
1594 {
1595 for (int i = 0; i < m; i++)
1596 {
1597 (*this)(i,j) = A(Aro+i,Aco+j);
1598 }
1599 }
1600}
1601
1602void DenseMatrix::CopyMN(const DenseMatrix &A, int row_offset, int col_offset)
1603{
1604 real_t *v = A.Data();
1605
1606 for (int j = 0; j < A.Width(); j++)
1607 {
1608 for (int i = 0; i < A.Height(); i++)
1609 {
1610 (*this)(row_offset+i,col_offset+j) = *(v++);
1611 }
1612 }
1613}
1614
1615void DenseMatrix::CopyMNt(const DenseMatrix &A, int row_offset, int col_offset)
1616{
1617 real_t *v = A.Data();
1618
1619 for (int i = 0; i < A.Width(); i++)
1620 {
1621 for (int j = 0; j < A.Height(); j++)
1622 {
1623 (*this)(row_offset+i,col_offset+j) = *(v++);
1624 }
1625 }
1626}
1627
1628void DenseMatrix::CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco,
1629 int row_offset, int col_offset)
1630{
1631 MFEM_VERIFY(row_offset+m <= this->Height() && col_offset+n <= this->Width(),
1632 "this DenseMatrix is too small to accommodate the submatrix. "
1633 << "row_offset = " << row_offset
1634 << ", m = " << m
1635 << ", this->Height() = " << this->Height()
1636 << ", col_offset = " << col_offset
1637 << ", n = " << n
1638 << ", this->Width() = " << this->Width()
1639 );
1640 MFEM_VERIFY(Aro+m <= A.Height() && Aco+n <= A.Width(),
1641 "The A DenseMatrix is too small to accommodate the submatrix. "
1642 << "Aro = " << Aro
1643 << ", m = " << m
1644 << ", A.Height() = " << A.Height()
1645 << ", Aco = " << Aco
1646 << ", n = " << n
1647 << ", A.Width() = " << A.Width()
1648 );
1649
1650 for (int j = 0; j < n; j++)
1651 {
1652 for (int i = 0; i < m; i++)
1653 {
1654 (*this)(row_offset+i,col_offset+j) = A(Aro+i,Aco+j);
1655 }
1656 }
1657}
1658
1659void DenseMatrix::CopyMNDiag(real_t c, int n, int row_offset, int col_offset)
1660{
1661 for (int i = 0; i < n; i++)
1662 {
1663 for (int j = i+1; j < n; j++)
1664 {
1665 (*this)(row_offset+i,col_offset+j) =
1666 (*this)(row_offset+j,col_offset+i) = 0.0;
1667 }
1668 }
1669
1670 for (int i = 0; i < n; i++)
1671 {
1672 (*this)(row_offset+i,col_offset+i) = c;
1673 }
1674}
1675
1676void DenseMatrix::CopyMNDiag(real_t *diag, int n, int row_offset,
1677 int col_offset)
1678{
1679 for (int i = 0; i < n; i++)
1680 {
1681 for (int j = i+1; j < n; j++)
1682 {
1683 (*this)(row_offset+i,col_offset+j) =
1684 (*this)(row_offset+j,col_offset+i) = 0.0;
1685 }
1686 }
1687
1688 for (int i = 0; i < n; i++)
1689 {
1690 (*this)(row_offset+i,col_offset+i) = diag[i];
1691 }
1692}
1693
1694void DenseMatrix::CopyExceptMN(const DenseMatrix &A, int m, int n)
1695{
1696 SetSize(A.Width()-1,A.Height()-1);
1697
1698 int i, j, i_off = 0, j_off = 0;
1699
1700 for (j = 0; j < A.Width(); j++)
1701 {
1702 if ( j == n )
1703 {
1704 j_off = 1;
1705 continue;
1706 }
1707 for (i = 0; i < A.Height(); i++)
1708 {
1709 if ( i == m )
1710 {
1711 i_off = 1;
1712 continue;
1713 }
1714 (*this)(i-i_off,j-j_off) = A(i,j);
1715 }
1716 i_off = 0;
1717 }
1718}
1719
1720void DenseMatrix::AddMatrix(DenseMatrix &A, int ro, int co)
1721{
1722 int h, ah, aw;
1723 real_t *p, *ap;
1724
1725 h = Height();
1726 ah = A.Height();
1727 aw = A.Width();
1728
1729#ifdef MFEM_DEBUG
1730 if (co+aw > Width() || ro+ah > h)
1731 {
1732 mfem_error("DenseMatrix::AddMatrix(...) 1 : dimension mismatch");
1733 }
1734#endif
1735
1736 p = data + ro + co * h;
1737 ap = A.data;
1738
1739 for (int c = 0; c < aw; c++)
1740 {
1741 for (int r = 0; r < ah; r++)
1742 {
1743 p[r] += ap[r];
1744 }
1745 p += h;
1746 ap += ah;
1747 }
1748}
1749
1750void DenseMatrix::AddMatrix(real_t a, const DenseMatrix &A, int ro, int co)
1751{
1752 int h, ah, aw;
1753 real_t *p, *ap;
1754
1755 h = Height();
1756 ah = A.Height();
1757 aw = A.Width();
1758
1759#ifdef MFEM_DEBUG
1760 if (co+aw > Width() || ro+ah > h)
1761 {
1762 mfem_error("DenseMatrix::AddMatrix(...) 2 : dimension mismatch");
1763 }
1764#endif
1765
1766 p = data + ro + co * h;
1767 ap = A.Data();
1768
1769 for (int c = 0; c < aw; c++)
1770 {
1771 for (int r = 0; r < ah; r++)
1772 {
1773 p[r] += a * ap[r];
1774 }
1775 p += h;
1776 ap += ah;
1777 }
1778}
1779
1781{
1782 int k = idx.Size();
1783 int idx_max = idx.Max();
1784 MFEM_VERIFY(idx.Min() >=0 && idx_max < this->height && idx_max < this->width,
1785 "DenseMatrix::GetSubMatrix: Index out of bounds");
1786 A.SetSize(k);
1787 real_t * adata = A.Data();
1788
1789 int ii, jj;
1790 for (int i = 0; i<k; i++)
1791 {
1792 ii = idx[i];
1793 for (int j = 0; j<k; j++)
1794 {
1795 jj = idx[j];
1796 adata[i+j*k] = this->data[ii+jj*height];
1797 }
1798 }
1799}
1800
1802 const Array<int> & idx_j, DenseMatrix & A) const
1803{
1804 int k = idx_i.Size();
1805 int l = idx_j.Size();
1806
1807 MFEM_VERIFY(idx_i.Min() >=0 && idx_i.Max() < this->height,
1808 "DenseMatrix::GetSubMatrix: Row index out of bounds");
1809 MFEM_VERIFY(idx_j.Min() >=0 && idx_j.Max() < this->width,
1810 "DenseMatrix::GetSubMatrix: Col index out of bounds");
1811
1812 A.SetSize(k,l);
1813 real_t * adata = A.Data();
1814
1815 int ii, jj;
1816 for (int i = 0; i<k; i++)
1817 {
1818 ii = idx_i[i];
1819 for (int j = 0; j<l; j++)
1820 {
1821 jj = idx_j[j];
1822 adata[i+j*k] = this->data[ii+jj*height];
1823 }
1824 }
1825}
1826
1827void DenseMatrix::GetSubMatrix(int ibeg, int iend, DenseMatrix & A)
1828{
1829 MFEM_VERIFY(iend >= ibeg, "DenseMatrix::GetSubMatrix: Inconsistent range");
1830 MFEM_VERIFY(ibeg >=0,
1831 "DenseMatrix::GetSubMatrix: Negative index");
1832 MFEM_VERIFY(iend <= this->height && iend <= this->width,
1833 "DenseMatrix::GetSubMatrix: Index bigger than upper bound");
1834
1835 int k = iend - ibeg;
1836 A.SetSize(k);
1837 real_t * adata = A.Data();
1838
1839 int ii, jj;
1840 for (int i = 0; i<k; i++)
1841 {
1842 ii = ibeg + i;
1843 for (int j = 0; j<k; j++)
1844 {
1845 jj = ibeg + j;
1846 adata[i+j*k] = this->data[ii+jj*height];
1847 }
1848 }
1849}
1850
1851void DenseMatrix::GetSubMatrix(int ibeg, int iend, int jbeg, int jend,
1852 DenseMatrix & A)
1853{
1854 MFEM_VERIFY(iend >= ibeg,
1855 "DenseMatrix::GetSubMatrix: Inconsistent row range");
1856 MFEM_VERIFY(jend >= jbeg,
1857 "DenseMatrix::GetSubMatrix: Inconsistent col range");
1858 MFEM_VERIFY(ibeg >=0,
1859 "DenseMatrix::GetSubMatrix: Negative row index");
1860 MFEM_VERIFY(jbeg >=0,
1861 "DenseMatrix::GetSubMatrix: Negative row index");
1862 MFEM_VERIFY(iend <= this->height,
1863 "DenseMatrix::GetSubMatrix: Index bigger than row upper bound");
1864 MFEM_VERIFY(jend <= this->width,
1865 "DenseMatrix::GetSubMatrix: Index bigger than col upper bound");
1866
1867 int k = iend - ibeg;
1868 int l = jend - jbeg;
1869 A.SetSize(k,l);
1870 real_t * adata = A.Data();
1871
1872 int ii, jj;
1873 for (int i = 0; i<k; i++)
1874 {
1875 ii = ibeg + i;
1876 for (int j = 0; j<l; j++)
1877 {
1878 jj = jbeg + j;
1879 adata[i+j*k] = this->data[ii+jj*height];
1880 }
1881 }
1882}
1883
1885{
1886 int k = idx.Size();
1887 MFEM_VERIFY(A.Height() == k && A.Width() == k,
1888 "DenseMatrix::SetSubMatrix:Inconsistent matrix dimensions");
1889
1890 int idx_max = idx.Max();
1891
1892 MFEM_VERIFY(idx.Min() >=0,
1893 "DenseMatrix::SetSubMatrix: Negative index");
1894 MFEM_VERIFY(idx_max < this->height,
1895 "DenseMatrix::SetSubMatrix: Index bigger than row upper bound");
1896 MFEM_VERIFY(idx_max < this->width,
1897 "DenseMatrix::SetSubMatrix: Index bigger than col upper bound");
1898
1899 real_t * adata = A.Data();
1900
1901 int ii, jj;
1902 for (int i = 0; i<k; i++)
1903 {
1904 ii = idx[i];
1905 for (int j = 0; j<k; j++)
1906 {
1907 jj = idx[j];
1908 this->data[ii+jj*height] = adata[i+j*k];
1909 }
1910 }
1911}
1912
1914 const Array<int> & idx_j, const DenseMatrix & A)
1915{
1916 int k = idx_i.Size();
1917 int l = idx_j.Size();
1918 MFEM_VERIFY(k == A.Height() && l == A.Width(),
1919 "DenseMatrix::SetSubMatrix:Inconsistent matrix dimensions");
1920 MFEM_VERIFY(idx_i.Min() >=0,
1921 "DenseMatrix::SetSubMatrix: Negative row index");
1922 MFEM_VERIFY(idx_j.Min() >=0,
1923 "DenseMatrix::SetSubMatrix: Negative col index");
1924 MFEM_VERIFY(idx_i.Max() < this->height,
1925 "DenseMatrix::SetSubMatrix: Index bigger than row upper bound");
1926 MFEM_VERIFY(idx_j.Max() < this->width,
1927 "DenseMatrix::SetSubMatrix: Index bigger than col upper bound");
1928
1929 real_t * adata = A.Data();
1930
1931 int ii, jj;
1932 for (int i = 0; i<k; i++)
1933 {
1934 ii = idx_i[i];
1935 for (int j = 0; j<l; j++)
1936 {
1937 jj = idx_j[j];
1938 this->data[ii+jj*height] = adata[i+j*k];
1939 }
1940 }
1941}
1942
1944{
1945 int k = A.Height();
1946
1947 MFEM_VERIFY(A.Width() == k, "DenseMatrix::SetSubmatrix: A is not square");
1948 MFEM_VERIFY(ibeg >=0,
1949 "DenseMatrix::SetSubmatrix: Negative index");
1950 MFEM_VERIFY(ibeg + k <= this->height,
1951 "DenseMatrix::SetSubmatrix: index bigger than row upper bound");
1952 MFEM_VERIFY(ibeg + k <= this->width,
1953 "DenseMatrix::SetSubmatrix: index bigger than col upper bound");
1954
1955 real_t * adata = A.Data();
1956
1957 int ii, jj;
1958 for (int i = 0; i<k; i++)
1959 {
1960 ii = ibeg + i;
1961 for (int j = 0; j<k; j++)
1962 {
1963 jj = ibeg + j;
1964 this->data[ii+jj*height] = adata[i+j*k];
1965 }
1966 }
1967}
1968
1969void DenseMatrix::SetSubMatrix(int ibeg, int jbeg, const DenseMatrix & A)
1970{
1971 int k = A.Height();
1972 int l = A.Width();
1973
1974 MFEM_VERIFY(ibeg>=0,
1975 "DenseMatrix::SetSubmatrix: Negative row index");
1976 MFEM_VERIFY(jbeg>=0,
1977 "DenseMatrix::SetSubmatrix: Negative col index");
1978 MFEM_VERIFY(ibeg + k <= this->height,
1979 "DenseMatrix::SetSubmatrix: Index bigger than row upper bound");
1980 MFEM_VERIFY(jbeg + l <= this->width,
1981 "DenseMatrix::SetSubmatrix: Index bigger than col upper bound");
1982
1983 real_t * adata = A.Data();
1984
1985 int ii, jj;
1986 for (int i = 0; i<k; i++)
1987 {
1988 ii = ibeg + i;
1989 for (int j = 0; j<l; j++)
1990 {
1991 jj = jbeg + j;
1992 this->data[ii+jj*height] = adata[i+j*k];
1993 }
1994 }
1995}
1996
1998{
1999 int k = idx.Size();
2000 MFEM_VERIFY(A.Height() == k && A.Width() == k,
2001 "DenseMatrix::AddSubMatrix:Inconsistent matrix dimensions");
2002
2003 int idx_max = idx.Max();
2004
2005 MFEM_VERIFY(idx.Min() >=0, "DenseMatrix::AddSubMatrix: Negative index");
2006 MFEM_VERIFY(idx_max < this->height,
2007 "DenseMatrix::AddSubMatrix: Index bigger than row upper bound");
2008 MFEM_VERIFY(idx_max < this->width,
2009 "DenseMatrix::AddSubMatrix: Index bigger than col upper bound");
2010
2011 real_t * adata = A.Data();
2012
2013 int ii, jj;
2014 for (int i = 0; i<k; i++)
2015 {
2016 ii = idx[i];
2017 for (int j = 0; j<k; j++)
2018 {
2019 jj = idx[j];
2020 this->data[ii+jj*height] += adata[i+j*k];
2021 }
2022 }
2023}
2024
2026 const Array<int> & idx_j, const DenseMatrix & A)
2027{
2028 int k = idx_i.Size();
2029 int l = idx_j.Size();
2030 MFEM_VERIFY(k == A.Height() && l == A.Width(),
2031 "DenseMatrix::AddSubMatrix:Inconsistent matrix dimensions");
2032
2033 MFEM_VERIFY(idx_i.Min() >=0,
2034 "DenseMatrix::AddSubMatrix: Negative row index");
2035 MFEM_VERIFY(idx_j.Min() >=0,
2036 "DenseMatrix::AddSubMatrix: Negative col index");
2037 MFEM_VERIFY(idx_i.Max() < this->height,
2038 "DenseMatrix::AddSubMatrix: Index bigger than row upper bound");
2039 MFEM_VERIFY(idx_j.Max() < this->width,
2040 "DenseMatrix::AddSubMatrix: Index bigger than col upper bound");
2041
2042 real_t * adata = A.Data();
2043
2044 int ii, jj;
2045 for (int i = 0; i<k; i++)
2046 {
2047 ii = idx_i[i];
2048 for (int j = 0; j<l; j++)
2049 {
2050 jj = idx_j[j];
2051 this->data[ii+jj*height] += adata[i+j*k];
2052 }
2053 }
2054}
2055
2057{
2058 int k = A.Height();
2059 MFEM_VERIFY(A.Width() == k, "DenseMatrix::AddSubmatrix: A is not square");
2060
2061 MFEM_VERIFY(ibeg>=0,
2062 "DenseMatrix::AddSubmatrix: Negative index");
2063 MFEM_VERIFY(ibeg + k <= this->Height(),
2064 "DenseMatrix::AddSubmatrix: Index bigger than row upper bound");
2065 MFEM_VERIFY(ibeg + k <= this->Width(),
2066 "DenseMatrix::AddSubmatrix: Index bigger than col upper bound");
2067
2068 real_t * adata = A.Data();
2069
2070 int ii, jj;
2071 for (int i = 0; i<k; i++)
2072 {
2073 ii = ibeg + i;
2074 for (int j = 0; j<k; j++)
2075 {
2076 jj = ibeg + j;
2077 this->data[ii+jj*height] += adata[i+j*k];
2078 }
2079 }
2080}
2081
2082void DenseMatrix::AddSubMatrix(int ibeg, int jbeg, const DenseMatrix & A)
2083{
2084 int k = A.Height();
2085 int l = A.Width();
2086
2087 MFEM_VERIFY(ibeg>=0,
2088 "DenseMatrix::AddSubmatrix: Negative row index");
2089 MFEM_VERIFY(jbeg>=0,
2090 "DenseMatrix::AddSubmatrix: Negative col index");
2091 MFEM_VERIFY(ibeg + k <= this->height,
2092 "DenseMatrix::AddSubmatrix: Index bigger than row upper bound");
2093 MFEM_VERIFY(jbeg + l <= this->width,
2094 "DenseMatrix::AddSubmatrix: Index bigger than col upper bound");
2095
2096 real_t * adata = A.Data();
2097
2098 int ii, jj;
2099 for (int i = 0; i<k; i++)
2100 {
2101 ii = ibeg + i;
2102 for (int j = 0; j<l; j++)
2103 {
2104 jj = jbeg + j;
2105 this->data[ii+jj*height] += adata[i+j*k];
2106 }
2107 }
2108}
2109
2110void DenseMatrix::AddToVector(int offset, Vector &v) const
2111{
2112 const int n = height * width;
2113 real_t *vdata = v.GetData() + offset;
2114
2115 for (int i = 0; i < n; i++)
2116 {
2117 vdata[i] += data[i];
2118 }
2119}
2120
2121void DenseMatrix::GetFromVector(int offset, const Vector &v)
2122{
2123 const int n = height * width;
2124 const real_t *vdata = v.GetData() + offset;
2125
2126 for (int i = 0; i < n; i++)
2127 {
2128 data[i] = vdata[i];
2129 }
2130}
2131
2133{
2134 const int n = Height();
2135
2136#ifdef MFEM_DEBUG
2137 if (dofs.Size() != n || Width() != n)
2138 {
2139 mfem_error("DenseMatrix::AdjustDofDirection(...): dimension mismatch");
2140 }
2141#endif
2142
2143 int *dof = dofs;
2144 for (int i = 0; i < n-1; i++)
2145 {
2146 const int s = (dof[i] < 0) ? (-1) : (1);
2147 for (int j = i+1; j < n; j++)
2148 {
2149 const int t = (dof[j] < 0) ? (-s) : (s);
2150 if (t < 0)
2151 {
2152 (*this)(i,j) = -(*this)(i,j);
2153 (*this)(j,i) = -(*this)(j,i);
2154 }
2155 }
2156 }
2157}
2158
2159void DenseMatrix::SetRow(int row, real_t value)
2160{
2161 for (int j = 0; j < Width(); j++)
2162 {
2163 (*this)(row, j) = value;
2164 }
2165}
2166
2167void DenseMatrix::SetCol(int col, real_t value)
2168{
2169 for (int i = 0; i < Height(); i++)
2170 {
2171 (*this)(i, col) = value;
2172 }
2173}
2174
2175void DenseMatrix::SetRow(int r, const real_t* row)
2176{
2177 MFEM_ASSERT(row != nullptr, "supplied row pointer is null");
2178 for (int j = 0; j < Width(); j++)
2179 {
2180 (*this)(r, j) = row[j];
2181 }
2182}
2183
2184void DenseMatrix::SetRow(int r, const Vector &row)
2185{
2186 MFEM_ASSERT(Width() == row.Size(), "");
2187 SetRow(r, row.GetData());
2188}
2189
2190void DenseMatrix::SetCol(int c, const real_t* col)
2191{
2192 MFEM_ASSERT(col != nullptr, "supplied column pointer is null");
2193 for (int i = 0; i < Height(); i++)
2194 {
2195 (*this)(i, c) = col[i];
2196 }
2197}
2198
2199void DenseMatrix::SetCol(int c, const Vector &col)
2200{
2201 MFEM_ASSERT(Height() == col.Size(), "");
2202 SetCol(c, col.GetData());
2203}
2204
2206{
2207 for (int col = 0; col < Width(); col++)
2208 {
2209 for (int row = 0; row < Height(); row++)
2210 {
2211 if (std::abs(operator()(row,col)) <= eps)
2212 {
2213 operator()(row,col) = 0.0;
2214 }
2215 }
2216 }
2217}
2218
2219void DenseMatrix::Print(std::ostream &os, int width_) const
2220{
2221 // save current output flags
2222 ios::fmtflags old_flags = os.flags();
2223 // output flags = scientific + show sign
2224 os << setiosflags(ios::scientific | ios::showpos);
2225 for (int i = 0; i < height; i++)
2226 {
2227 os << "[row " << i << "]\n";
2228 for (int j = 0; j < width; j++)
2229 {
2230 os << (*this)(i,j);
2231 if (j+1 == width || (j+1) % width_ == 0)
2232 {
2233 os << '\n';
2234 }
2235 else
2236 {
2237 os << ' ';
2238 }
2239 }
2240 }
2241 // reset output flags to original values
2242 os.flags(old_flags);
2243}
2244
2245void DenseMatrix::PrintMatlab(std::ostream &os) const
2246{
2247 // save current output flags
2248 ios::fmtflags old_flags = os.flags();
2249 // output flags = scientific + show sign
2250 os << setiosflags(ios::scientific | ios::showpos);
2251 for (int i = 0; i < height; i++)
2252 {
2253 for (int j = 0; j < width; j++)
2254 {
2255 os << (*this)(i,j);
2256 os << ' ';
2257 }
2258 os << "\n";
2259 }
2260 // reset output flags to original values
2261 os.flags(old_flags);
2262}
2263
2264void DenseMatrix::PrintMathematica(std::ostream &os) const
2265{
2266 ios::fmtflags old_fmt = os.flags();
2267 os.setf(ios::scientific);
2268 std::streamsize old_prec = os.precision(14);
2269
2270 os << "(* Read file into Mathematica using: "
2271 << "myMat = Get[\"this_file_name\"] *)\n";
2272 os << "{\n";
2273
2274 for (int i = 0; i < height; i++)
2275 {
2276 os << "{\n";
2277 for (int j = 0; j < width; j++)
2278 {
2279 os << "Internal`StringToMReal[\"" << (*this)(i,j) << "\"]";
2280 if (j < width - 1) { os << ','; }
2281 os << '\n';
2282 }
2283 os << '}';
2284 if (i < height - 1) { os << ','; }
2285 os << '\n';
2286 }
2287 os << "}\n";
2288
2289 os.precision(old_prec);
2290 os.flags(old_fmt);
2291}
2292
2293void DenseMatrix::PrintT(std::ostream &os, int width_) const
2294{
2295 // save current output flags
2296 ios::fmtflags old_flags = os.flags();
2297 // output flags = scientific + show sign
2298 os << setiosflags(ios::scientific | ios::showpos);
2299 for (int j = 0; j < width; j++)
2300 {
2301 os << "[col " << j << "]\n";
2302 for (int i = 0; i < height; i++)
2303 {
2304 os << (*this)(i,j);
2305 if (i+1 == height || (i+1) % width_ == 0)
2306 {
2307 os << '\n';
2308 }
2309 else
2310 {
2311 os << ' ';
2312 }
2313 }
2314 }
2315 // reset output flags to original values
2316 os.flags(old_flags);
2317}
2318
2320{
2321 DenseMatrix copy(*this), C(width);
2322 Invert();
2323 mfem::Mult(*this, copy, C);
2324
2325 for (int i = 0; i < width; i++)
2326 {
2327 C(i,i) -= 1.0;
2328 }
2329 mfem::out << "size = " << width << ", i_max = " << C.MaxMaxNorm()
2330 << ", cond_F = " << FNorm()*copy.FNorm() << endl;
2331}
2332
2334{
2335 mfem::Swap(*this, other);
2336}
2337
2338
2339void Add(const DenseMatrix &A, const DenseMatrix &B,
2341{
2342 kernels::Add(C.Height(), C.Width(), alpha, A.Data(), B.Data(), C.Data());
2343}
2344
2345void Add(real_t alpha, const real_t *A,
2346 real_t beta, const real_t *B, DenseMatrix &C)
2347{
2348 kernels::Add(C.Height(), C.Width(), alpha, A, beta, B, C.Data());
2349}
2350
2352 real_t beta, const DenseMatrix &B, DenseMatrix &C)
2353{
2354 MFEM_ASSERT(A.Height() == C.Height(), "");
2355 MFEM_ASSERT(B.Height() == C.Height(), "");
2356 MFEM_ASSERT(A.Width() == C.Width(), "");
2357 MFEM_ASSERT(B.Width() == C.Width(), "");
2358 Add(alpha, A.GetData(), beta, B.GetData(), C);
2359}
2360
2362{
2363 MFEM_VERIFY(A.IsSquare(), "A must be a square matrix!");
2364 MFEM_ASSERT(A.NumCols() > 0, "supplied matrix, A, is empty!");
2365 MFEM_ASSERT(X != nullptr, "supplied vector, X, is null!");
2366
2367 int N = A.NumCols();
2368
2369 switch (N)
2370 {
2371 case 1:
2372 {
2373 real_t det = A(0,0);
2374 if (std::abs(det) <= TOL) { return false; } // singular
2375
2376 X[0] /= det;
2377 break;
2378 }
2379 case 2:
2380 {
2381 real_t det = A.Det();
2382 if (std::abs(det) <= TOL) { return false; } // singular
2383
2384 real_t invdet = 1. / det;
2385
2386 real_t b0 = X[0];
2387 real_t b1 = X[1];
2388
2389 X[0] = ( A(1,1)*b0 - A(0,1)*b1) * invdet;
2390 X[1] = (-A(1,0)*b0 + A(0,0)*b1) * invdet;
2391 break;
2392 }
2393 default:
2394 {
2395 // default to LU factorization for the general case
2396 Array<int> ipiv(N);
2397 LUFactors lu(A.Data(), ipiv);
2398
2399 if (!lu.Factor(N,TOL)) { return false; } // singular
2400
2401 lu.Solve(N, 1, X);
2402 }
2403
2404 } // END switch
2405
2406 return true;
2407}
2408
2409void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
2410{
2411 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2412 b.Width() == c.Height(), "incompatible dimensions");
2413
2414#ifdef MFEM_USE_LAPACK
2415 static char transa = 'N', transb = 'N';
2416 static real_t alpha = 1.0, beta = 0.0;
2417 int m = b.Height(), n = c.Width(), k = b.Width();
2418
2419 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2420 c.Data(), &k, &beta, a.Data(), &m);
2421#else
2422 const int ah = a.Height();
2423 const int aw = a.Width();
2424 const int bw = b.Width();
2425 real_t *ad = a.Data();
2426 const real_t *bd = b.Data();
2427 const real_t *cd = c.Data();
2428 kernels::Mult(ah,aw,bw,bd,cd,ad);
2429#endif
2430}
2431
2433 DenseMatrix &a)
2434{
2435 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2436 b.Width() == c.Height(), "incompatible dimensions");
2437
2438#ifdef MFEM_USE_LAPACK
2439 static char transa = 'N', transb = 'N';
2440 static real_t beta = 1.0;
2441 int m = b.Height(), n = c.Width(), k = b.Width();
2442
2443 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2444 c.Data(), &k, &beta, a.Data(), &m);
2445#else
2446 const int ah = a.Height();
2447 const int aw = a.Width();
2448 const int bw = b.Width();
2449 real_t *ad = a.Data();
2450 const real_t *bd = b.Data();
2451 const real_t *cd = c.Data();
2452 for (int j = 0; j < aw; j++)
2453 {
2454 for (int k = 0; k < bw; k++)
2455 {
2456 for (int i = 0; i < ah; i++)
2457 {
2458 ad[i+j*ah] += alpha * bd[i+k*ah] * cd[k+j*bw];
2459 }
2460 }
2461 }
2462#endif
2463}
2464
2466{
2467 MFEM_ASSERT(a.Height() == b.Height() && a.Width() == c.Width() &&
2468 b.Width() == c.Height(), "incompatible dimensions");
2469
2470#ifdef MFEM_USE_LAPACK
2471 static char transa = 'N', transb = 'N';
2472 static real_t alpha = 1.0, beta = 1.0;
2473 int m = b.Height(), n = c.Width(), k = b.Width();
2474
2475 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
2476 c.Data(), &k, &beta, a.Data(), &m);
2477#else
2478 const int ah = a.Height();
2479 const int aw = a.Width();
2480 const int bw = b.Width();
2481 real_t *ad = a.Data();
2482 const real_t *bd = b.Data();
2483 const real_t *cd = c.Data();
2484 for (int j = 0; j < aw; j++)
2485 {
2486 for (int k = 0; k < bw; k++)
2487 {
2488 for (int i = 0; i < ah; i++)
2489 {
2490 ad[i+j*ah] += bd[i+k*ah] * cd[k+j*bw];
2491 }
2492 }
2493 }
2494#endif
2495}
2496
2498{
2499#ifdef MFEM_DEBUG
2500 if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 3)
2501 {
2502 mfem_error("CalcAdjugate(...): unsupported dimensions");
2503 }
2504 if (a.Width() != adja.Height() || a.Height() != adja.Width())
2505 {
2506 mfem_error("CalcAdjugate(...): dimension mismatch");
2507 }
2508#endif
2509
2510 if (a.Width() < a.Height())
2511 {
2512 const real_t *d = a.Data();
2513 real_t *ad = adja.Data();
2514 if (a.Width() == 1)
2515 {
2516 // N x 1, N = 2,3
2517 ad[0] = d[0];
2518 ad[1] = d[1];
2519 if (a.Height() == 3)
2520 {
2521 ad[2] = d[2];
2522 }
2523 }
2524 else
2525 {
2526 // 3 x 2
2527 real_t e, g, f;
2528 e = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
2529 g = d[3]*d[3] + d[4]*d[4] + d[5]*d[5];
2530 f = d[0]*d[3] + d[1]*d[4] + d[2]*d[5];
2531
2532 ad[0] = d[0]*g - d[3]*f;
2533 ad[1] = d[3]*e - d[0]*f;
2534 ad[2] = d[1]*g - d[4]*f;
2535 ad[3] = d[4]*e - d[1]*f;
2536 ad[4] = d[2]*g - d[5]*f;
2537 ad[5] = d[5]*e - d[2]*f;
2538 }
2539 return;
2540 }
2541
2542 if (a.Width() == 1)
2543 {
2544 adja(0,0) = 1.0;
2545 }
2546 else if (a.Width() == 2)
2547 {
2548 adja(0,0) = a(1,1);
2549 adja(0,1) = -a(0,1);
2550 adja(1,0) = -a(1,0);
2551 adja(1,1) = a(0,0);
2552 }
2553 else
2554 {
2555 adja(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
2556 adja(0,1) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
2557 adja(0,2) = a(0,1)*a(1,2)-a(0,2)*a(1,1);
2558
2559 adja(1,0) = a(1,2)*a(2,0)-a(1,0)*a(2,2);
2560 adja(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0);
2561 adja(1,2) = a(0,2)*a(1,0)-a(0,0)*a(1,2);
2562
2563 adja(2,0) = a(1,0)*a(2,1)-a(1,1)*a(2,0);
2564 adja(2,1) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
2565 adja(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
2566 }
2567}
2568
2570{
2571#ifdef MFEM_DEBUG
2572 if (a.Height() != a.Width() || adjat.Height() != adjat.Width() ||
2573 a.Width() != adjat.Width() || a.Width() < 1 || a.Width() > 3)
2574 {
2575 mfem_error("CalcAdjugateTranspose(...): dimension mismatch");
2576 }
2577#endif
2578 if (a.Width() == 1)
2579 {
2580 adjat(0,0) = 1.0;
2581 }
2582 else if (a.Width() == 2)
2583 {
2584 adjat(0,0) = a(1,1);
2585 adjat(1,0) = -a(0,1);
2586 adjat(0,1) = -a(1,0);
2587 adjat(1,1) = a(0,0);
2588 }
2589 else
2590 {
2591 adjat(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
2592 adjat(1,0) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
2593 adjat(2,0) = a(0,1)*a(1,2)-a(0,2)*a(1,1);
2594
2595 adjat(0,1) = a(1,2)*a(2,0)-a(1,0)*a(2,2);
2596 adjat(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0);
2597 adjat(2,1) = a(0,2)*a(1,0)-a(0,0)*a(1,2);
2598
2599 adjat(0,2) = a(1,0)*a(2,1)-a(1,1)*a(2,0);
2600 adjat(1,2) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
2601 adjat(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
2602 }
2603}
2604
2606{
2607 MFEM_ASSERT(a.Width() <= a.Height() && a.Width() >= 1 && a.Height() <= 3, "");
2608 MFEM_ASSERT(inva.Height() == a.Width(), "incorrect dimensions");
2609 MFEM_ASSERT(inva.Width() == a.Height(), "incorrect dimensions");
2610
2611 if (a.Width() < a.Height())
2612 {
2613 const real_t *d = a.Data();
2614 real_t *id = inva.Data();
2615 if (a.Height() == 2)
2616 {
2618 }
2619 else
2620 {
2621 if (a.Width() == 1)
2622 {
2624 }
2625 else
2626 {
2628 }
2629 }
2630 return;
2631 }
2632
2633#ifdef MFEM_DEBUG
2634 const real_t t = a.Det();
2635 MFEM_ASSERT(std::abs(t) > 1.0e-14 * pow(a.FNorm()/a.Width(), a.Width()),
2636 "singular matrix!");
2637#endif
2638
2639 switch (a.Height())
2640 {
2641 case 1:
2642 inva(0,0) = 1.0 / a.Det();
2643 break;
2644 case 2:
2645 kernels::CalcInverse<2>(a.Data(), inva.Data());
2646 break;
2647 case 3:
2648 kernels::CalcInverse<3>(a.Data(), inva.Data());
2649 break;
2650 }
2651}
2652
2654{
2655#ifdef MFEM_DEBUG
2656 if ( (a.Width() != a.Height()) || ( (a.Height()!= 1) && (a.Height()!= 2)
2657 && (a.Height()!= 3) ) )
2658 {
2659 mfem_error("CalcInverseTranspose(...): dimension mismatch");
2660 }
2661#endif
2662
2663 real_t t = 1. / a.Det() ;
2664
2665 switch (a.Height())
2666 {
2667 case 1:
2668 inva(0,0) = 1.0 / a(0,0);
2669 break;
2670 case 2:
2671 inva(0,0) = a(1,1) * t ;
2672 inva(1,0) = -a(0,1) * t ;
2673 inva(0,1) = -a(1,0) * t ;
2674 inva(1,1) = a(0,0) * t ;
2675 break;
2676 case 3:
2677 inva(0,0) = (a(1,1)*a(2,2)-a(1,2)*a(2,1))*t;
2678 inva(1,0) = (a(0,2)*a(2,1)-a(0,1)*a(2,2))*t;
2679 inva(2,0) = (a(0,1)*a(1,2)-a(0,2)*a(1,1))*t;
2680
2681 inva(0,1) = (a(1,2)*a(2,0)-a(1,0)*a(2,2))*t;
2682 inva(1,1) = (a(0,0)*a(2,2)-a(0,2)*a(2,0))*t;
2683 inva(2,1) = (a(0,2)*a(1,0)-a(0,0)*a(1,2))*t;
2684
2685 inva(0,2) = (a(1,0)*a(2,1)-a(1,1)*a(2,0))*t;
2686 inva(1,2) = (a(0,1)*a(2,0)-a(0,0)*a(2,1))*t;
2687 inva(2,2) = (a(0,0)*a(1,1)-a(0,1)*a(1,0))*t;
2688 break;
2689 }
2690}
2691
2692void CalcOrtho(const DenseMatrix &J, Vector &n)
2693{
2694 MFEM_ASSERT( ((J.Height() == 2 && J.Width() == 1)
2695 || (J.Height() == 3 && J.Width() == 2))
2696 && (J.Height() == n.Size()),
2697 "Matrix must be 3x2 or 2x1, "
2698 << "and the Vector must be sized with the rows. "
2699 << " J.Height() = " << J.Height()
2700 << ", J.Width() = " << J.Width()
2701 << ", n.Size() = " << n.Size()
2702 );
2703
2704 const real_t *d = J.Data();
2705 if (J.Height() == 2)
2706 {
2707 n(0) = d[1];
2708 n(1) = -d[0];
2709 }
2710 else
2711 {
2712 n(0) = d[1]*d[5] - d[2]*d[4];
2713 n(1) = d[2]*d[3] - d[0]*d[5];
2714 n(2) = d[0]*d[4] - d[1]*d[3];
2715 }
2716}
2717
2719{
2720 const int height = a.Height();
2721 const int width = a.Width();
2722 for (int i = 0; i < height; i++)
2723 {
2724 for (int j = 0; j <= i; j++)
2725 {
2726 real_t temp = 0.;
2727 for (int k = 0; k < width; k++)
2728 {
2729 temp += a(i,k) * a(j,k);
2730 }
2731 aat(j,i) = aat(i,j) = temp;
2732 }
2733 }
2734}
2735
2736void AddMultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
2737{
2738 for (int i = 0; i < A.Height(); i++)
2739 {
2740 for (int j = 0; j < i; j++)
2741 {
2742 real_t t = 0.;
2743 for (int k = 0; k < A.Width(); k++)
2744 {
2745 t += D(k) * A(i, k) * A(j, k);
2746 }
2747 ADAt(i, j) += t;
2748 ADAt(j, i) += t;
2749 }
2750 }
2751
2752 // process diagonal
2753 for (int i = 0; i < A.Height(); i++)
2754 {
2755 real_t t = 0.;
2756 for (int k = 0; k < A.Width(); k++)
2757 {
2758 t += D(k) * A(i, k) * A(i, k);
2759 }
2760 ADAt(i, i) += t;
2761 }
2762}
2763
2764void MultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
2765{
2766 for (int i = 0; i < A.Height(); i++)
2767 {
2768 for (int j = 0; j <= i; j++)
2769 {
2770 real_t t = 0.;
2771 for (int k = 0; k < A.Width(); k++)
2772 {
2773 t += D(k) * A(i, k) * A(j, k);
2774 }
2775 ADAt(j, i) = ADAt(i, j) = t;
2776 }
2777 }
2778}
2779
2780void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
2781{
2782#ifdef MFEM_DEBUG
2783 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
2784 A.Width() != B.Width())
2785 {
2786 mfem_error("MultABt(...): dimension mismatch");
2787 }
2788#endif
2789
2790#ifdef MFEM_USE_LAPACK
2791 static char transa = 'N', transb = 'T';
2792 static real_t alpha = 1.0, beta = 0.0;
2793 int m = A.Height(), n = B.Height(), k = A.Width();
2794
2795 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
2796 B.Data(), &n, &beta, ABt.Data(), &m);
2797#elif 1
2798 const int ah = A.Height();
2799 const int bh = B.Height();
2800 const int aw = A.Width();
2801 const real_t *ad = A.Data();
2802 const real_t *bd = B.Data();
2803 real_t *cd = ABt.Data();
2804
2805 kernels::MultABt(ah, aw, bh, ad, bd, cd);
2806#elif 1
2807 const int ah = A.Height();
2808 const int bh = B.Height();
2809 const int aw = A.Width();
2810 const real_t *ad = A.Data();
2811 const real_t *bd = B.Data();
2812 real_t *cd = ABt.Data();
2813
2814 for (int j = 0; j < bh; j++)
2815 for (int i = 0; i < ah; i++)
2816 {
2817 real_t d = 0.0;
2818 const real_t *ap = ad + i;
2819 const real_t *bp = bd + j;
2820 for (int k = 0; k < aw; k++)
2821 {
2822 d += (*ap) * (*bp);
2823 ap += ah;
2824 bp += bh;
2825 }
2826 *(cd++) = d;
2827 }
2828#else
2829 int i, j, k;
2830 real_t d;
2831
2832 for (i = 0; i < A.Height(); i++)
2833 for (j = 0; j < B.Height(); j++)
2834 {
2835 d = 0.0;
2836 for (k = 0; k < A.Width(); k++)
2837 {
2838 d += A(i, k) * B(j, k);
2839 }
2840 ABt(i, j) = d;
2841 }
2842#endif
2843}
2844
2845void MultADBt(const DenseMatrix &A, const Vector &D,
2846 const DenseMatrix &B, DenseMatrix &ADBt)
2847{
2848#ifdef MFEM_DEBUG
2849 if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
2850 A.Width() != B.Width() || A.Width() != D.Size())
2851 {
2852 mfem_error("MultADBt(...): dimension mismatch");
2853 }
2854#endif
2855
2856 const int ah = A.Height();
2857 const int bh = B.Height();
2858 const int aw = A.Width();
2859 const real_t *ad = A.Data();
2860 const real_t *bd = B.Data();
2861 const real_t *dd = D.GetData();
2862 real_t *cd = ADBt.Data();
2863
2864 for (int i = 0, s = ah*bh; i < s; i++)
2865 {
2866 cd[i] = 0.0;
2867 }
2868 for (int k = 0; k < aw; k++)
2869 {
2870 real_t *cp = cd;
2871 for (int j = 0; j < bh; j++)
2872 {
2873 const real_t dk_bjk = dd[k] * bd[j];
2874 for (int i = 0; i < ah; i++)
2875 {
2876 cp[i] += ad[i] * dk_bjk;
2877 }
2878 cp += ah;
2879 }
2880 ad += ah;
2881 bd += bh;
2882 }
2883}
2884
2885void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
2886{
2887#ifdef MFEM_DEBUG
2888 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
2889 A.Width() != B.Width())
2890 {
2891 mfem_error("AddMultABt(...): dimension mismatch");
2892 }
2893#endif
2894
2895#ifdef MFEM_USE_LAPACK
2896 static char transa = 'N', transb = 'T';
2897 static real_t alpha = 1.0, beta = 1.0;
2898 int m = A.Height(), n = B.Height(), k = A.Width();
2899
2900 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
2901 B.Data(), &n, &beta, ABt.Data(), &m);
2902#elif 1
2903 const int ah = A.Height();
2904 const int bh = B.Height();
2905 const int aw = A.Width();
2906 const real_t *ad = A.Data();
2907 const real_t *bd = B.Data();
2908 real_t *cd = ABt.Data();
2909
2910 for (int k = 0; k < aw; k++)
2911 {
2912 real_t *cp = cd;
2913 for (int j = 0; j < bh; j++)
2914 {
2915 const real_t bjk = bd[j];
2916 for (int i = 0; i < ah; i++)
2917 {
2918 cp[i] += ad[i] * bjk;
2919 }
2920 cp += ah;
2921 }
2922 ad += ah;
2923 bd += bh;
2924 }
2925#else
2926 int i, j, k;
2927 real_t d;
2928
2929 for (i = 0; i < A.Height(); i++)
2930 for (j = 0; j < B.Height(); j++)
2931 {
2932 d = 0.0;
2933 for (k = 0; k < A.Width(); k++)
2934 {
2935 d += A(i, k) * B(j, k);
2936 }
2937 ABt(i, j) += d;
2938 }
2939#endif
2940}
2941
2942void AddMultADBt(const DenseMatrix &A, const Vector &D,
2943 const DenseMatrix &B, DenseMatrix &ADBt)
2944{
2945#ifdef MFEM_DEBUG
2946 if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
2947 A.Width() != B.Width() || A.Width() != D.Size())
2948 {
2949 mfem_error("AddMultADBt(...): dimension mismatch");
2950 }
2951#endif
2952
2953 const int ah = A.Height();
2954 const int bh = B.Height();
2955 const int aw = A.Width();
2956 const real_t *ad = A.Data();
2957 const real_t *bd = B.Data();
2958 const real_t *dd = D.GetData();
2959 real_t *cd = ADBt.Data();
2960
2961 for (int k = 0; k < aw; k++)
2962 {
2963 real_t *cp = cd;
2964 for (int j = 0; j < bh; j++)
2965 {
2966 const real_t dk_bjk = dd[k] * bd[j];
2967 for (int i = 0; i < ah; i++)
2968 {
2969 cp[i] += ad[i] * dk_bjk;
2970 }
2971 cp += ah;
2972 }
2973 ad += ah;
2974 bd += bh;
2975 }
2976}
2977
2979 DenseMatrix &ABt)
2980{
2981#ifdef MFEM_DEBUG
2982 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
2983 A.Width() != B.Width())
2984 {
2985 mfem_error("AddMult_a_ABt(...): dimension mismatch");
2986 }
2987#endif
2988
2989#ifdef MFEM_USE_LAPACK
2990 static char transa = 'N', transb = 'T';
2991 real_t alpha = a;
2992 static real_t beta = 1.0;
2993 int m = A.Height(), n = B.Height(), k = A.Width();
2994
2995 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
2996 B.Data(), &n, &beta, ABt.Data(), &m);
2997#elif 1
2998 const int ah = A.Height();
2999 const int bh = B.Height();
3000 const int aw = A.Width();
3001 const real_t *ad = A.Data();
3002 const real_t *bd = B.Data();
3003 real_t *cd = ABt.Data();
3004
3005 for (int k = 0; k < aw; k++)
3006 {
3007 real_t *cp = cd;
3008 for (int j = 0; j < bh; j++)
3009 {
3010 const real_t bjk = a * bd[j];
3011 for (int i = 0; i < ah; i++)
3012 {
3013 cp[i] += ad[i] * bjk;
3014 }
3015 cp += ah;
3016 }
3017 ad += ah;
3018 bd += bh;
3019 }
3020#else
3021 int i, j, k;
3022 real_t d;
3023
3024 for (i = 0; i < A.Height(); i++)
3025 for (j = 0; j < B.Height(); j++)
3026 {
3027 d = 0.0;
3028 for (k = 0; k < A.Width(); k++)
3029 {
3030 d += A(i, k) * B(j, k);
3031 }
3032 ABt(i, j) += a * d;
3033 }
3034#endif
3035}
3036
3037void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
3038{
3039#ifdef MFEM_DEBUG
3040 if (A.Width() != AtB.Height() || B.Width() != AtB.Width() ||
3041 A.Height() != B.Height())
3042 {
3043 mfem_error("MultAtB(...): dimension mismatch");
3044 }
3045#endif
3046
3047#ifdef MFEM_USE_LAPACK
3048 static char transa = 'T', transb = 'N';
3049 static real_t alpha = 1.0, beta = 0.0;
3050 int m = A.Width(), n = B.Width(), k = A.Height();
3051
3052 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3053 B.Data(), &k, &beta, AtB.Data(), &m);
3054#elif 1
3055 const int ah = A.Height();
3056 const int aw = A.Width();
3057 const int bw = B.Width();
3058 const real_t *ad = A.Data();
3059 const real_t *bd = B.Data();
3060 real_t *cd = AtB.Data();
3061
3062 for (int j = 0; j < bw; j++)
3063 {
3064 const real_t *ap = ad;
3065 for (int i = 0; i < aw; i++)
3066 {
3067 real_t d = 0.0;
3068 for (int k = 0; k < ah; k++)
3069 {
3070 d += ap[k] * bd[k];
3071 }
3072 *(cd++) = d;
3073 ap += ah;
3074 }
3075 bd += ah;
3076 }
3077#else
3078 int i, j, k;
3079 real_t d;
3080
3081 for (i = 0; i < A.Width(); i++)
3082 for (j = 0; j < B.Width(); j++)
3083 {
3084 d = 0.0;
3085 for (k = 0; k < A.Height(); k++)
3086 {
3087 d += A(k, i) * B(k, j);
3088 }
3089 AtB(i, j) = d;
3090 }
3091#endif
3092}
3093
3094void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B,
3095 DenseMatrix &AtB)
3096{
3097 MFEM_ASSERT(AtB.Height() == A.Width() && AtB.Width() == B.Width() &&
3098 A.Height() == B.Height(), "incompatible dimensions");
3099
3100#ifdef MFEM_USE_LAPACK
3101 static char transa = 'T', transb = 'N';
3102 static real_t alpha = 1.0, beta = 1.0;
3103 int m = A.Width(), n = B.Width(), k = A.Height();
3104
3105 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3106 B.Data(), &k, &beta, AtB.Data(), &m);
3107#else
3108 const int ah = A.Height();
3109 const int aw = A.Width();
3110 const int bw = B.Width();
3111 const real_t *ad = A.Data();
3112 const real_t *bd = B.Data();
3113 real_t *cd = AtB.Data();
3114
3115 for (int j = 0; j < bw; j++)
3116 {
3117 const real_t *ap = ad;
3118 for (int i = 0; i < aw; i++)
3119 {
3120 real_t d = 0.0;
3121 for (int k = 0; k < ah; k++)
3122 {
3123 d += ap[k] * bd[k];
3124 }
3125 *(cd++) += d;
3126 ap += ah;
3127 }
3128 bd += ah;
3129 }
3130#endif
3131}
3132
3134 DenseMatrix &AtB)
3135{
3136 MFEM_ASSERT(AtB.Height() == A.Width() && AtB.Width() == B.Width() &&
3137 A.Height() == B.Height(), "incompatible dimensions");
3138
3139#ifdef MFEM_USE_LAPACK
3140 static char transa = 'T', transb = 'N';
3141 real_t alpha = a;
3142 static real_t beta = 1.0;
3143 int m = A.Width(), n = B.Width(), k = A.Height();
3144
3145 MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
3146 B.Data(), &k, &beta, AtB.Data(), &m);
3147#else
3148 const int ah = A.Height();
3149 const int aw = A.Width();
3150 const int bw = B.Width();
3151 const real_t *ad = A.Data();
3152 const real_t *bd = B.Data();
3153 real_t *cd = AtB.Data();
3154
3155 for (int j = 0; j < bw; j++)
3156 {
3157 const real_t *ap = ad;
3158 for (int i = 0; i < aw; i++)
3159 {
3160 real_t d = 0.0;
3161 for (int k = 0; k < ah; k++)
3162 {
3163 d += ap[k] * bd[k];
3164 }
3165 *(cd++) += a * d;
3166 ap += ah;
3167 }
3168 bd += ah;
3169 }
3170#endif
3171}
3172
3174{
3175 real_t d;
3176
3177 for (int i = 0; i < A.Height(); i++)
3178 {
3179 for (int j = 0; j < i; j++)
3180 {
3181 d = 0.;
3182 for (int k = 0; k < A.Width(); k++)
3183 {
3184 d += A(i,k) * A(j,k);
3185 }
3186 AAt(i, j) += (d *= a);
3187 AAt(j, i) += d;
3188 }
3189 d = 0.;
3190 for (int k = 0; k < A.Width(); k++)
3191 {
3192 d += A(i,k) * A(i,k);
3193 }
3194 AAt(i, i) += a * d;
3195 }
3196}
3197
3199{
3200 for (int i = 0; i < A.Height(); i++)
3201 {
3202 for (int j = 0; j <= i; j++)
3203 {
3204 real_t d = 0.;
3205 for (int k = 0; k < A.Width(); k++)
3206 {
3207 d += A(i,k) * A(j,k);
3208 }
3209 AAt(i, j) = AAt(j, i) = a * d;
3210 }
3211 }
3212}
3213
3214void MultVVt(const Vector &v, DenseMatrix &vvt)
3215{
3216 for (int i = 0; i < v.Size(); i++)
3217 {
3218 for (int j = 0; j <= i; j++)
3219 {
3220 vvt(i,j) = vvt(j,i) = v(i) * v(j);
3221 }
3222 }
3223}
3224
3225void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
3226{
3227#ifdef MFEM_DEBUG
3228 if (v.Size() != VWt.Height() || w.Size() != VWt.Width())
3229 {
3230 mfem_error("MultVWt(...): dimension mismatch");
3231 }
3232#endif
3233
3234 for (int i = 0; i < v.Size(); i++)
3235 {
3236 const real_t vi = v(i);
3237 for (int j = 0; j < w.Size(); j++)
3238 {
3239 VWt(i, j) = vi * w(j);
3240 }
3241 }
3242}
3243
3244void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
3245{
3246 const int m = v.Size(), n = w.Size();
3247
3248#ifdef MFEM_DEBUG
3249 if (VWt.Height() != m || VWt.Width() != n)
3250 {
3251 mfem_error("AddMultVWt(...): dimension mismatch");
3252 }
3253#endif
3254
3255 for (int i = 0; i < m; i++)
3256 {
3257 const real_t vi = v(i);
3258 for (int j = 0; j < n; j++)
3259 {
3260 VWt(i, j) += vi * w(j);
3261 }
3262 }
3263}
3264
3265void AddMultVVt(const Vector &v, DenseMatrix &VVt)
3266{
3267 const int n = v.Size();
3268
3269#ifdef MFEM_DEBUG
3270 if (VVt.Height() != n || VVt.Width() != n)
3271 {
3272 mfem_error("AddMultVVt(...): dimension mismatch");
3273 }
3274#endif
3275
3276 for (int i = 0; i < n; i++)
3277 {
3278 const real_t vi = v(i);
3279 for (int j = 0; j < i; j++)
3280 {
3281 const real_t vivj = vi * v(j);
3282 VVt(i, j) += vivj;
3283 VVt(j, i) += vivj;
3284 }
3285 VVt(i, i) += vi * vi;
3286 }
3287}
3288
3289void AddMult_a_VWt(const real_t a, const Vector &v, const Vector &w,
3290 DenseMatrix &VWt)
3291{
3292 const int m = v.Size(), n = w.Size();
3293
3294#ifdef MFEM_DEBUG
3295 if (VWt.Height() != m || VWt.Width() != n)
3296 {
3297 mfem_error("AddMult_a_VWt(...): dimension mismatch");
3298 }
3299#endif
3300
3301 for (int j = 0; j < n; j++)
3302 {
3303 const real_t awj = a * w(j);
3304 for (int i = 0; i < m; i++)
3305 {
3306 VWt(i, j) += v(i) * awj;
3307 }
3308 }
3309}
3310
3311void AddMult_a_VVt(const real_t a, const Vector &v, DenseMatrix &VVt)
3312{
3313 MFEM_ASSERT(VVt.Height() == v.Size() && VVt.Width() == v.Size(),
3314 "incompatible dimensions!");
3315
3316 const int n = v.Size();
3317 for (int i = 0; i < n; i++)
3318 {
3319 real_t avi = a * v(i);
3320 for (int j = 0; j < i; j++)
3321 {
3322 const real_t avivj = avi * v(j);
3323 VVt(i, j) += avivj;
3324 VVt(j, i) += avivj;
3325 }
3326 VVt(i, i) += avi * v(i);
3327 }
3328}
3329
3330void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix & RAP)
3331{
3332 DenseMatrix RA(P.Width(),A.Width());
3333 MultAtB(P,A,RA);
3334 RAP.SetSize(RA.Height(), P.Width());
3335 Mult(RA,P, RAP);
3336}
3337
3338void RAP(const DenseMatrix &Rt, const DenseMatrix &A,
3339 const DenseMatrix &P, DenseMatrix & RAP)
3340{
3341 DenseMatrix RA(Rt.Width(),A.Width());
3342 MultAtB(Rt,A,RA);
3343 RAP.SetSize(RA.Height(), P.Width());
3344 Mult(RA,P, RAP);
3345}
3346
3348{
3349#ifdef MFEM_USE_LAPACK
3350 int info = 0;
3351 if (m) { MFEM_LAPACK_PREFIX(getrf_)(&m, &m, data, &m, ipiv, &info); }
3352 return info == 0;
3353#else
3354 // compiling without LAPACK
3355 real_t *data_ptr = this->data;
3356 for (int i = 0; i < m; i++)
3357 {
3358 // pivoting
3359 {
3360 int piv = i;
3361 real_t a = std::abs(data_ptr[piv+i*m]);
3362 for (int j = i+1; j < m; j++)
3363 {
3364 const real_t b = std::abs(data_ptr[j+i*m]);
3365 if (b > a)
3366 {
3367 a = b;
3368 piv = j;
3369 }
3370 }
3371 ipiv[i] = piv + 1;
3372 if (piv != i)
3373 {
3374 // swap rows i and piv in both L and U parts
3375 for (int j = 0; j < m; j++)
3376 {
3377 mfem::Swap<real_t>(data_ptr[i+j*m], data_ptr[piv+j*m]);
3378 }
3379 }
3380 }
3381
3382 if (abs(data_ptr[i + i*m]) <= TOL)
3383 {
3384 return false; // failed
3385 }
3386
3387 const real_t a_ii_inv = 1.0 / data_ptr[i+i*m];
3388 for (int j = i+1; j < m; j++)
3389 {
3390 data_ptr[j+i*m] *= a_ii_inv;
3391 }
3392 for (int k = i+1; k < m; k++)
3393 {
3394 const real_t a_ik = data_ptr[i+k*m];
3395 for (int j = i+1; j < m; j++)
3396 {
3397 data_ptr[j+k*m] -= a_ik * data_ptr[j+i*m];
3398 }
3399 }
3400 }
3401#endif
3402
3403 return true; // success
3404}
3405
3407{
3408 real_t det = 1.0;
3409 for (int i=0; i<m; i++)
3410 {
3411 if (ipiv[i] != i - ipiv_base)
3412 {
3413 det *= -data[m * i + i];
3414 }
3415 else
3416 {
3417 det *= data[m * i + i];
3418 }
3419 }
3420 return det;
3421}
3422
3423void LUFactors::Mult(int m, int n, real_t *X) const
3424{
3425 real_t *x = X;
3426 for (int k = 0; k < n; k++)
3427 {
3428 // X <- U X
3429 for (int i = 0; i < m; i++)
3430 {
3431 real_t x_i = x[i] * data[i+i*m];
3432 for (int j = i+1; j < m; j++)
3433 {
3434 x_i += x[j] * data[i+j*m];
3435 }
3436 x[i] = x_i;
3437 }
3438 // X <- L X
3439 for (int i = m-1; i >= 0; i--)
3440 {
3441 real_t x_i = x[i];
3442 for (int j = 0; j < i; j++)
3443 {
3444 x_i += x[j] * data[i+j*m];
3445 }
3446 x[i] = x_i;
3447 }
3448 // X <- P^{-1} X
3449 for (int i = m-1; i >= 0; i--)
3450 {
3451 mfem::Swap<real_t>(x[i], x[ipiv[i]-ipiv_base]);
3452 }
3453 x += m;
3454 }
3455}
3456
3457void LUFactors::LSolve(int m, int n, real_t *X) const
3458{
3459 real_t *x = X;
3460 for (int k = 0; k < n; k++)
3461 {
3462 kernels::LSolve(data, m, ipiv, x);
3463 x += m;
3464 }
3465}
3466
3467void LUFactors::USolve(int m, int n, real_t *X) const
3468{
3469 real_t *x = X;
3470 for (int k = 0; k < n; k++)
3471 {
3472 kernels::USolve(data, m, x);
3473 x += m;
3474 }
3475}
3476
3477void LUFactors::Solve(int m, int n, real_t *X) const
3478{
3479#ifdef MFEM_USE_LAPACK
3480 char trans = 'N';
3481 int info = 0;
3482 if (m > 0 && n > 0)
3483 {
3484 MFEM_LAPACK_PREFIX(getrs_)(&trans, &m, &n, data, &m, ipiv, X, &m, &info);
3485 }
3486 MFEM_VERIFY(!info, "LAPACK: error in DGETRS");
3487#else
3488 // compiling without LAPACK
3489 LSolve(m, n, X);
3490 USolve(m, n, X);
3491#endif
3492}
3493
3494void LUFactors::RightSolve(int m, int n, real_t *X) const
3495{
3496 real_t *x;
3497#ifdef MFEM_USE_LAPACK
3498 char n_ch = 'N', side = 'R', u_ch = 'U', l_ch = 'L';
3499 real_t alpha = 1.0;
3500 if (m > 0 && n > 0)
3501 {
3502 MFEM_LAPACK_PREFIX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
3503 MFEM_LAPACK_PREFIX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
3504 }
3505#else
3506 // compiling without LAPACK
3507 // X <- X U^{-1}
3508 x = X;
3509 for (int k = 0; k < n; k++)
3510 {
3511 for (int j = 0; j < m; j++)
3512 {
3513 const real_t x_j = ( x[j*n] /= data[j+j*m]);
3514 for (int i = j+1; i < m; i++)
3515 {
3516 x[i*n] -= data[j + i*m] * x_j;
3517 }
3518 }
3519 ++x;
3520 }
3521
3522 // X <- X L^{-1}
3523 x = X;
3524 for (int k = 0; k < n; k++)
3525 {
3526 for (int j = m-1; j >= 0; j--)
3527 {
3528 const real_t x_j = x[j*n];
3529 for (int i = 0; i < j; i++)
3530 {
3531 x[i*n] -= data[j + i*m] * x_j;
3532 }
3533 }
3534 ++x;
3535 }
3536#endif
3537 // X <- X P
3538 x = X;
3539 for (int k = 0; k < n; k++)
3540 {
3541 for (int i = m-1; i >= 0; --i)
3542 {
3543 mfem::Swap<real_t>(x[i*n], x[(ipiv[i]-ipiv_base)*n]);
3544 }
3545 ++x;
3546 }
3547}
3548
3550{
3551 // A^{-1} = U^{-1} L^{-1} P
3552 // X <- U^{-1} (set only the upper triangular part of X)
3553 real_t *x = X;
3554 for (int k = 0; k < m; k++)
3555 {
3556 const real_t minus_x_k = -( x[k] = 1.0/data[k+k*m] );
3557 for (int i = 0; i < k; i++)
3558 {
3559 x[i] = data[i+k*m] * minus_x_k;
3560 }
3561 for (int j = k-1; j >= 0; j--)
3562 {
3563 const real_t x_j = ( x[j] /= data[j+j*m] );
3564 for (int i = 0; i < j; i++)
3565 {
3566 x[i] -= data[i+j*m] * x_j;
3567 }
3568 }
3569 x += m;
3570 }
3571 // X <- X L^{-1} (use input only from the upper triangular part of X)
3572 {
3573 int k = m-1;
3574 for (int j = 0; j < k; j++)
3575 {
3576 const real_t minus_L_kj = -data[k+j*m];
3577 for (int i = 0; i <= j; i++)
3578 {
3579 X[i+j*m] += X[i+k*m] * minus_L_kj;
3580 }
3581 for (int i = j+1; i < m; i++)
3582 {
3583 X[i+j*m] = X[i+k*m] * minus_L_kj;
3584 }
3585 }
3586 }
3587 for (int k = m-2; k >= 0; k--)
3588 {
3589 for (int j = 0; j < k; j++)
3590 {
3591 const real_t L_kj = data[k+j*m];
3592 for (int i = 0; i < m; i++)
3593 {
3594 X[i+j*m] -= X[i+k*m] * L_kj;
3595 }
3596 }
3597 }
3598 // X <- X P
3599 for (int k = m-1; k >= 0; k--)
3600 {
3601 const int piv_k = ipiv[k]-ipiv_base;
3602 if (k != piv_k)
3603 {
3604 for (int i = 0; i < m; i++)
3605 {
3606 Swap<real_t>(X[i+k*m], X[i+piv_k*m]);
3607 }
3608 }
3609 }
3610}
3611
3612void LUFactors::SubMult(int m, int n, int r, const real_t *A21,
3613 const real_t *X1, real_t *X2)
3614{
3615 kernels::SubMult(m, n, r, A21, X1, X2);
3616}
3617
3619 int m, int n, real_t *A12, real_t *A21, real_t *A22) const
3620{
3621 kernels::BlockFactor(data, m, ipiv, n, A12, A21, A22);
3622}
3623
3624void LUFactors::BlockForwSolve(int m, int n, int r, const real_t *L21,
3625 real_t *B1, real_t *B2) const
3626{
3627 // B1 <- L^{-1} P B1
3628 LSolve(m, r, B1);
3629 // B2 <- B2 - L21 B1
3630 SubMult(m, n, r, L21, B1, B2);
3631}
3632
3633void LUFactors::BlockBackSolve(int m, int n, int r, const real_t *U12,
3634 const real_t *X2, real_t *Y1) const
3635{
3636 // Y1 <- Y1 - U12 X2
3637 SubMult(n, m, r, U12, X2, Y1);
3638 // Y1 <- U^{-1} Y1
3639 USolve(m, r, Y1);
3640}
3641
3642
3644{
3645#ifdef MFEM_USE_LAPACK
3646 int info = 0;
3647 char uplo = 'L';
3648 MFEM_VERIFY(data, "Matrix data not set");
3649 if (m) { MFEM_LAPACK_PREFIX(potrf_)(&uplo, &m, data, &m, &info); }
3650 return info == 0;
3651#else
3652 // Cholesky–Crout algorithm
3653 for (int j = 0; j<m; j++)
3654 {
3655 real_t a = 0.;
3656 for (int k = 0; k<j; k++)
3657 {
3658 a+=data[j+k*m]*data[j+k*m];
3659 }
3660
3661 MFEM_VERIFY(data[j+j*m] - a > 0.,
3662 "CholeskyFactors::Factor: The matrix is not SPD");
3663
3664 data[j+j*m] = std::sqrt(data[j+j*m] - a);
3665
3666 if (data[j + j*m] <= TOL)
3667 {
3668 return false; // failed
3669 }
3670
3671 for (int i = j+1; i<m; i++)
3672 {
3673 a = 0.;
3674 for (int k = 0; k<j; k++)
3675 {
3676 a+= data[i+k*m]*data[j+k*m];
3677 }
3678 data[i+j*m] = 1./data[j+m*j]*(data[i+j*m] - a);
3679 }
3680 }
3681 return true; // success
3682#endif
3683}
3684
3686{
3687 real_t det = 1.0;
3688 for (int i=0; i<m; i++)
3689 {
3690 det *= data[i + i*m];
3691 }
3692 return det;
3693}
3694
3695void CholeskyFactors::LMult(int m, int n, real_t * X) const
3696{
3697 // X <- L X
3698 real_t *x = X;
3699 for (int k = 0; k < n; k++)
3700 {
3701 for (int j = m-1; j >= 0; j--)
3702 {
3703 real_t x_j = x[j] * data[j+j*m];
3704 for (int i = 0; i < j; i++)
3705 {
3706 x_j += x[i] * data[j+i*m];
3707 }
3708 x[j] = x_j;
3709 }
3710 x += m;
3711 }
3712}
3713
3714void CholeskyFactors::UMult(int m, int n, real_t * X) const
3715{
3716 real_t *x = X;
3717 for (int k = 0; k < n; k++)
3718 {
3719 for (int i = 0; i < m; i++)
3720 {
3721 real_t x_i = x[i] * data[i+i*m];
3722 for (int j = i+1; j < m; j++)
3723 {
3724 x_i += x[j] * data[j+i*m];
3725 }
3726 x[i] = x_i;
3727 }
3728 x += m;
3729 }
3730}
3731
3732void CholeskyFactors::LSolve(int m, int n, real_t * X) const
3733{
3734
3735#ifdef MFEM_USE_LAPACK
3736 char uplo = 'L';
3737 char trans = 'N';
3738 char diag = 'N';
3739 int info = 0;
3740
3741 MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
3742 &info);
3743 MFEM_VERIFY(!info, "CholeskyFactors:LSolve:: info");
3744
3745#else
3746 real_t *x = X;
3747 for (int k = 0; k < n; k++)
3748 {
3749 // X <- L^{-1} X
3750 for (int j = 0; j < m; j++)
3751 {
3752 const real_t x_j = (x[j] /= data[j+j*m]);
3753 for (int i = j+1; i < m; i++)
3754 {
3755 x[i] -= data[i+j*m] * x_j;
3756 }
3757 }
3758 x += m;
3759 }
3760#endif
3761}
3762
3763void CholeskyFactors::USolve(int m, int n, real_t * X) const
3764{
3765#ifdef MFEM_USE_LAPACK
3766
3767 char uplo = 'L';
3768 char trans = 'T';
3769 char diag = 'N';
3770 int info = 0;
3771
3772 MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
3773 &info);
3774 MFEM_VERIFY(!info, "CholeskyFactors:USolve:: info");
3775
3776#else
3777 // X <- L^{-t} X
3778 real_t *x = X;
3779 for (int k = 0; k < n; k++)
3780 {
3781 for (int j = m-1; j >= 0; j--)
3782 {
3783 const real_t x_j = ( x[j] /= data[j+j*m] );
3784 for (int i = 0; i < j; i++)
3785 {
3786 x[i] -= data[j+i*m] * x_j;
3787 }
3788 }
3789 x += m;
3790 }
3791#endif
3792}
3793
3794void CholeskyFactors::Solve(int m, int n, real_t * X) const
3795{
3796#ifdef MFEM_USE_LAPACK
3797 char uplo = 'L';
3798 int info = 0;
3799 MFEM_LAPACK_PREFIX(potrs_)(&uplo, &m, &n, data, &m, X, &m, &info);
3800 MFEM_VERIFY(!info, "CholeskyFactors:Solve:: info");
3801
3802#else
3803 LSolve(m, n, X);
3804 USolve(m, n, X);
3805#endif
3806}
3807
3808void CholeskyFactors::RightSolve(int m, int n, real_t * X) const
3809{
3810#ifdef MFEM_USE_LAPACK
3811 char side = 'R';
3812 char uplo = 'L';
3813 char transt = 'T';
3814 char trans = 'N';
3815 char diag = 'N';
3816
3817 real_t alpha = 1.0;
3818 if (m > 0 && n > 0)
3819 {
3820 MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
3821 MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
3822 }
3823#else
3824 // X <- X L^{-t}
3825 real_t *x = X;
3826 for (int k = 0; k < n; k++)
3827 {
3828 for (int j = 0; j < m; j++)
3829 {
3830 const real_t x_j = ( x[j*n] /= data[j+j*m]);
3831 for (int i = j+1; i < m; i++)
3832 {
3833 x[i*n] -= data[i + j*m] * x_j;
3834 }
3835 }
3836 ++x;
3837 }
3838 // X <- X L^{-1}
3839 x = X;
3840 for (int k = 0; k < n; k++)
3841 {
3842 for (int j = m-1; j >= 0; j--)
3843 {
3844 const real_t x_j = (x[j*n] /= data[j+j*m]);
3845 for (int i = 0; i < j; i++)
3846 {
3847 x[i*n] -= data[j + i*m] * x_j;
3848 }
3849 }
3850 ++x;
3851 }
3852#endif
3853}
3854
3856{
3857 // A^{-1} = L^{-t} L^{-1}
3858#ifdef MFEM_USE_LAPACK
3859 // copy the lower triangular part of L to X
3860 for (int i = 0; i<m; i++)
3861 {
3862 for (int j = i; j<m; j++)
3863 {
3864 X[j+i*m] = data[j+i*m];
3865 }
3866 }
3867 char uplo = 'L';
3868 int info = 0;
3869 MFEM_LAPACK_PREFIX(potri_)(&uplo, &m, X, &m, &info);
3870 MFEM_VERIFY(!info, "CholeskyFactors:GetInverseMatrix:: info");
3871 // fill in the upper triangular part
3872 for (int i = 0; i<m; i++)
3873 {
3874 for (int j = i+1; j<m; j++)
3875 {
3876 X[i+j*m] = X[j+i*m];
3877 }
3878 }
3879#else
3880 // L^-t * L^-1 (in place)
3881 for (int k = 0; k<m; k++)
3882 {
3883 X[k+k*m] = 1./data[k+k*m];
3884 for (int i = k+1; i < m; i++)
3885 {
3886 real_t s=0.;
3887 for (int j=k; j<i; j++)
3888 {
3889 s -= data[i+j*m] * X[j+k*m]/data[i+i*m];
3890 }
3891 X[i+k*m] = s;
3892 }
3893 }
3894 for (int i = 0; i < m; i++)
3895 {
3896 for (int j = i; j < m; j++)
3897 {
3898 real_t s = 0.;
3899 for (int k=j; k<m; k++)
3900 {
3901 s += X[k+i*m] * X[k+j*m];
3902 }
3903 X[i+j*m] = X[j+i*m] = s;
3904 }
3905 }
3906#endif
3907}
3908
3909
3910void DenseMatrixInverse::Init(int m)
3911{
3912 if (spd)
3913 {
3914 factors = new CholeskyFactors();
3915 }
3916 else
3917 {
3918 factors = new LUFactors();
3919 }
3920 if (m>0)
3921 {
3922 factors->data = new real_t[m*m];
3923 if (!spd)
3924 {
3925 dynamic_cast<LUFactors *>(factors)->ipiv = new int[m];
3926 }
3927 own_data = true;
3928 }
3929}
3930
3932 : MatrixInverse(mat), spd(spd_)
3933{
3934 MFEM_ASSERT(height == width, "not a square matrix");
3935 a = &mat;
3936 Init(width);
3937 Factor();
3938}
3939
3941 : MatrixInverse(*mat), spd(spd_)
3942{
3943 MFEM_ASSERT(height == width, "not a square matrix");
3944 a = mat;
3945 Init(width);
3946}
3947
3949{
3950 MFEM_ASSERT(a, "DenseMatrix is not given");
3951 const real_t *adata = a->data;
3952 const int s = width*width;
3953 for (int i = 0; i < s; i++)
3954 {
3955 factors->data[i] = adata[i];
3956 }
3957 factors->Factor(width);
3958}
3959
3961{
3962 Ainv.SetSize(width);
3963 factors->GetInverseMatrix(width,Ainv.Data());
3964}
3965
3967{
3968 MFEM_VERIFY(mat.height == mat.width, "DenseMatrix is not square!");
3969 if (width != mat.width)
3970 {
3971 height = width = mat.width;
3972 if (own_data) { delete [] factors->data; }
3973 factors->data = new real_t[width*width];
3974
3975 if (!spd)
3976 {
3977 LUFactors * lu = dynamic_cast<LUFactors *>(factors);
3978 if (own_data) { delete [] lu->ipiv; }
3979 lu->ipiv = new int[width];
3980 }
3981 own_data = true;
3982 }
3983 a = &mat;
3984 Factor();
3985}
3986
3988{
3989 const DenseMatrix *p = dynamic_cast<const DenseMatrix*>(&op);
3990 MFEM_VERIFY(p != NULL, "Operator is not a DenseMatrix!");
3991 Factor(*p);
3992}
3993
3995{
3996 for (int row = 0; row < height; row++)
3997 {
3998 y[row] = x[row];
3999 }
4000 factors->Solve(width, 1, y);
4001}
4002
4004{
4005 y = x;
4006 factors->Solve(width, 1, y.GetData());
4007}
4008
4010{
4011 X = B;
4012 factors->Solve(width, X.Width(), X.Data());
4013}
4014
4016{
4017 DenseMatrix C(width);
4018 Mult(*a, C);
4019 for (int i = 0; i < width; i++)
4020 {
4021 C(i,i) -= 1.0;
4022 }
4023 mfem::out << "size = " << width << ", i_max = " << C.MaxMaxNorm() << endl;
4024}
4025
4027{
4028 if (own_data)
4029 {
4030 delete [] factors->data;
4031 if (!spd)
4032 {
4033 delete [] dynamic_cast<LUFactors *>(factors)->ipiv;
4034 }
4035 }
4036 delete factors;
4037}
4038
4039#ifdef MFEM_USE_LAPACK
4040
4042 : mat(m)
4043{
4044 n = mat.Width();
4045 EVal.SetSize(n);
4046 EVect.SetSize(n);
4047 ev.SetDataAndSize(NULL, n);
4048
4049 jobz = 'V';
4050 uplo = 'U';
4051 lwork = -1;
4052 real_t qwork;
4053 MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
4054 &qwork, &lwork, &info);
4055
4056 lwork = (int) qwork;
4057 work = new real_t[lwork];
4058}
4059
4061 const DenseMatrixEigensystem &other)
4062 : mat(other.mat), EVal(other.EVal), EVect(other.EVect), ev(NULL, other.n),
4063 n(other.n)
4064{
4065 jobz = other.jobz;
4066 uplo = other.uplo;
4067 lwork = other.lwork;
4068
4069 work = new real_t[lwork];
4070}
4071
4073{
4074#ifdef MFEM_DEBUG
4075 if (mat.Width() != n)
4076 {
4077 mfem_error("DenseMatrixEigensystem::Eval(): dimension mismatch");
4078 }
4079#endif
4080
4081 EVect = mat;
4082 MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
4083 work, &lwork, &info);
4084
4085 if (info != 0)
4086 {
4087 mfem::err << "DenseMatrixEigensystem::Eval(): DSYEV error code: "
4088 << info << endl;
4089 mfem_error();
4090 }
4091}
4092
4094{
4095 delete [] work;
4096}
4097
4098
4101 bool left_eigen_vectors,
4102 bool right_eigen_vectors)
4103 : A(a), B(b)
4104{
4105 MFEM_VERIFY(A.Height() == A.Width(), "A has to be a square matrix");
4106 MFEM_VERIFY(B.Height() == B.Width(), "B has to be a square matrix");
4107 n = A.Width();
4108 MFEM_VERIFY(B.Height() == n, "A and B dimension mismatch");
4109
4110 jobvl = 'N';
4111 jobvr = 'N';
4112 A_copy.SetSize(n);
4113 B_copy.SetSize(n);
4114 if (left_eigen_vectors)
4115 {
4116 jobvl = 'V';
4117 Vl.SetSize(n);
4118 }
4119 if (right_eigen_vectors)
4120 {
4121 jobvr = 'V';
4122 Vr.SetSize(n);
4123 }
4124
4125 lwork = -1;
4126 real_t qwork;
4127
4128 alphar = new real_t[n];
4129 alphai = new real_t[n];
4130 beta = new real_t[n];
4131
4132 int nl = max(1,Vl.Height());
4133 int nr = max(1,Vr.Height());
4134
4135 MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
4136 alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
4137 &nr, &qwork, &lwork, &info);
4138
4139 lwork = (int) qwork;
4140 work = new real_t[lwork];
4141}
4142
4144{
4145 int nl = max(1,Vl.Height());
4146 int nr = max(1,Vr.Height());
4147
4148 A_copy = A;
4149 B_copy = B;
4150 MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
4151 alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
4152 &nr, work, &lwork, &info);
4153 if (info != 0)
4154 {
4155 mfem::err << "DenseMatrixGeneralizedEigensystem::Eval(): DGGEV error code: "
4156 << info << endl;
4157 mfem_error();
4158 }
4159 evalues_r.SetSize(n);
4160 evalues_i.SetSize(n);
4161 for (int i = 0; i<n; i++)
4162 {
4163 if (beta[i] != 0.)
4164 {
4165 evalues_r(i) = alphar[i]/beta[i];
4166 evalues_i(i) = alphai[i]/beta[i];
4167 }
4168 else
4169 {
4170 evalues_r(i) = infinity();
4171 evalues_i(i) = infinity();
4172 }
4173 }
4174}
4175
4177{
4178 delete [] alphar;
4179 delete [] alphai;
4180 delete [] beta;
4181 delete [] work;
4182}
4183
4185 bool left_singular_vectors,
4186 bool right_singular_vectors)
4187{
4188 m = M.Height();
4189 n = M.Width();
4190 jobu = (left_singular_vectors)? 'S' : 'N';
4191 jobvt = (right_singular_vectors)? 'S' : 'N';
4192 Init();
4193}
4194
4196 bool left_singular_vectors,
4197 bool right_singular_vectors)
4198{
4199 m = h;
4200 n = w;
4201 jobu = (left_singular_vectors)? 'S' : 'N';
4202 jobvt = (right_singular_vectors)? 'S' : 'N';
4203 Init();
4204}
4205
4207 char left_singular_vectors,
4208 char right_singular_vectors)
4209{
4210 m = M.Height();
4211 n = M.Width();
4212 jobu = left_singular_vectors;
4213 jobvt = right_singular_vectors;
4214 Init();
4215}
4216
4218 char left_singular_vectors,
4219 char right_singular_vectors)
4220{
4221 m = h;
4222 n = w;
4223 jobu = left_singular_vectors;
4224 jobvt = right_singular_vectors;
4225 Init();
4226}
4227
4228void DenseMatrixSVD::Init()
4229{
4230 sv.SetSize(min(m, n));
4231 real_t qwork;
4232 lwork = -1;
4233 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(),
4234 NULL, &m, NULL, &n, &qwork, &lwork, &info);
4235 lwork = (int) qwork;
4236 work = new real_t[lwork];
4237}
4238
4240{
4241#ifdef MFEM_DEBUG
4242 if (M.Height() != m || M.Width() != n)
4243 {
4244 mfem_error("DenseMatrixSVD::Eval()");
4245 }
4246#endif
4247 real_t * datau = nullptr;
4248 real_t * datavt = nullptr;
4249 if (jobu == 'A')
4250 {
4251 U.SetSize(m,m);
4252 datau = U.Data();
4253 }
4254 else if (jobu == 'S')
4255 {
4256 U.SetSize(m,min(m,n));
4257 datau = U.Data();
4258 }
4259 if (jobvt == 'A')
4260 {
4261 Vt.SetSize(n,n);
4262 datavt = Vt.Data();
4263 }
4264 else if (jobvt == 'S')
4265 {
4266 Vt.SetSize(min(m,n),n);
4267 datavt = Vt.Data();
4268 }
4269 Mc = M;
4270 MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(),
4271 datau, &m, datavt, &n, work, &lwork, &info);
4272
4273 if (info)
4274 {
4275 mfem::err << "DenseMatrixSVD::Eval() : info = " << info << endl;
4276 mfem_error();
4277 }
4278}
4279
4281{
4282 delete [] work;
4283}
4284
4285#endif // if MFEM_USE_LAPACK
4286
4287
4288void DenseTensor::AddMult(const Table &elem_dof, const Vector &x, Vector &y)
4289const
4290{
4291 int n = SizeI(), ne = SizeK();
4292 const int *I = elem_dof.GetI(), *J = elem_dof.GetJ(), *dofs;
4293 const real_t *d_col = tdata.HostRead();
4294 real_t *yp = y.HostReadWrite();
4295 real_t x_col;
4296 const real_t *xp = x.HostRead();
4297 // the '4' here can be tuned for given platform and compiler
4298 if (n <= 4)
4299 {
4300 for (int i = 0; i < ne; i++)
4301 {
4302 dofs = J + I[i];
4303 for (int col = 0; col < n; col++)
4304 {
4305 x_col = xp[dofs[col]];
4306 for (int row = 0; row < n; row++)
4307 {
4308 yp[dofs[row]] += x_col*d_col[row];
4309 }
4310 d_col += n;
4311 }
4312 }
4313 }
4314 else
4315 {
4316 Vector ye(n);
4317 for (int i = 0; i < ne; i++)
4318 {
4319 dofs = J + I[i];
4320 x_col = xp[dofs[0]];
4321 for (int row = 0; row < n; row++)
4322 {
4323 ye(row) = x_col*d_col[row];
4324 }
4325 d_col += n;
4326 for (int col = 1; col < n; col++)
4327 {
4328 x_col = xp[dofs[col]];
4329 for (int row = 0; row < n; row++)
4330 {
4331 ye(row) += x_col*d_col[row];
4332 }
4333 d_col += n;
4334 }
4335 for (int row = 0; row < n; row++)
4336 {
4337 yp[dofs[row]] += ye(row);
4338 }
4339 }
4340 }
4341}
4342
4344{
4345 int s = SizeI() * SizeJ() * SizeK();
4346 for (int i=0; i<s; i++)
4347 {
4348 tdata[i] = c;
4349 }
4350 return *this;
4351}
4352
4354{
4356}
4357
4358void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X)
4359{
4360 BatchedLinAlg::LUSolve(Mlu, P, X);
4361}
4362
4363#ifdef MFEM_USE_LAPACK
4364void BandedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B,
4365 Array<int> &ipiv)
4366{
4367 int LDAB = (2*KL) + KU + 1;
4368 int N = AB.NumCols();
4369 int NRHS = B.NumCols();
4370 int info;
4371 ipiv.SetSize(N);
4372 MFEM_LAPACK_PREFIX(gbsv_)(&N, &KL, &KU, &NRHS, AB.GetData(), &LDAB,
4373 ipiv.GetData(), B.GetData(), &N, &info);
4374 MFEM_ASSERT(info == 0, "BandedSolve failed in LAPACK");
4375}
4376
4377void BandedFactorizedSolve(int KL, int KU, DenseMatrix &AB, DenseMatrix &B,
4378 bool transpose, Array<int> &ipiv)
4379{
4380 int LDAB = (2*KL) + KU + 1;
4381 int N = AB.NumCols();
4382 int NRHS = B.NumCols();
4383 char trans = transpose ? 'T' : 'N';
4384 int info;
4385 MFEM_LAPACK_PREFIX(gbtrs_)(&trans, &N, &KL, &KU, &NRHS, AB.GetData(), &LDAB,
4386 ipiv.GetData(), B.GetData(), &N, &info);
4387 MFEM_ASSERT(info == 0, "BandedFactorizedSolve failed in LAPACK");
4388}
4389#endif
4390
4391} // 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:385
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
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:166
T * GetData()
Returns the data.
Definition array.hpp:140
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:76
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:81
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:847
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:885
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 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:489
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
void Getl1Diag(Vector &l) const
Returns the l1 norm of the rows of the matrix v_i = sum_j |a_ij|.
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:122
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:126
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:116
friend class DenseMatrixInverse
Definition densemat.hpp:26
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
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 AdjustDofDirection(Array< int > &dofs)
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:285
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
Compute 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)
int SizeJ() const
void AddMult(const Table &elem_dof, const Vector &x, Vector &y) const
int SizeI() const
DenseTensor & operator=(real_t c)
Sets the tensor elements equal to constant c.
int SizeK() const
virtual void GetInverseMatrix(int m, real_t *X) const
Definition densemat.hpp:663
virtual void Solve(int m, int n, real_t *X) const
Definition densemat.hpp:658
real_t * data
Definition densemat.hpp:640
virtual bool Factor(int m, real_t TOL=0.0)
Definition densemat.hpp:646
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:678
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:25
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition operator.hpp:75
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
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:584
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)
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
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:738
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:564
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.
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)
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)