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