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