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