MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 00013 // Implementation of data types dense matrix, inverse dense matrix 00014 00015 00016 #include <iostream> 00017 #include <iomanip> 00018 #include <math.h> 00019 #include <stdlib.h> 00020 00021 #include "vector.hpp" 00022 #include "matrix.hpp" 00023 #include "densemat.hpp" 00024 00025 00026 DenseMatrix::DenseMatrix() : Matrix(0) 00027 { 00028 height = 0; 00029 data = NULL; 00030 } 00031 00032 DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.size) 00033 { 00034 height = m.height; 00035 int hw = size * height; 00036 data = new double[hw]; 00037 for (int i = 0; i < hw; i++) 00038 data[i] = m.data[i]; 00039 } 00040 00041 DenseMatrix::DenseMatrix(int s) : Matrix(s) 00042 { 00043 height = s; 00044 00045 data = new double[s*s]; 00046 00047 for (int i = 0; i < s; i++) 00048 for (int j = 0; j < s; j++) 00049 (*this)(i,j) = 0; 00050 } 00051 00052 DenseMatrix::DenseMatrix(int m, int n) : Matrix(n) 00053 { 00054 height = m; 00055 00056 data = new double[m*n]; 00057 00058 for (int i = 0; i < m; i++) 00059 for (int j = 0; j < n; j++) 00060 (*this)(i,j) = 0; 00061 } 00062 00063 DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch) : Matrix(mat.height) 00064 { 00065 if (ch == 't') 00066 { 00067 height = mat.size; 00068 00069 data = new double[size*height]; 00070 00071 for (int i = 0; i < height; i++) 00072 for (int j = 0; j < size; j++) 00073 (*this)(i,j) = mat(j,i); 00074 } 00075 } 00076 00077 void DenseMatrix::SetSize(int s) 00078 { 00079 if (Size() == s && Height() == s) 00080 return; 00081 if (data != NULL) 00082 delete [] data; 00083 size = height = s; 00084 if (s > 0) 00085 { 00086 int ss = s*s; 00087 data = new double[ss]; 00088 for (int i = 0; i < ss; i++) 00089 data[i] = 0.0; 00090 } 00091 else 00092 data = 0; 00093 } 00094 00095 void DenseMatrix::SetSize(int h, int w) 00096 { 00097 if (Size() == w && Height() == h) 00098 return; 00099 if (data != NULL) 00100 delete [] data; 00101 size = w; 00102 height = h; 00103 if (h > 0 && w > 0) 00104 { 00105 int hw = h*w; 00106 data = new double[hw]; 00107 for (int i = 0; i < hw; i++) 00108 data[i] = 0.0; 00109 } 00110 else 00111 data = 0; 00112 } 00113 00114 double &DenseMatrix::Elem(int i, int j) 00115 { 00116 return (*this)(i,j); 00117 } 00118 00119 const double &DenseMatrix::Elem(int i, int j) const 00120 { 00121 return (*this)(i,j); 00122 } 00123 00124 void DenseMatrix::Mult(const double *x, double *y) const 00125 { 00126 for (int i = 0; i < height; i++) 00127 { 00128 double a = 0.; 00129 for (int j = 0; j < size; j++) 00130 a += (*this)(i,j) * x[j]; 00131 y[i] = a; 00132 } 00133 } 00134 00135 void DenseMatrix::Mult(const Vector &x, Vector &y) const 00136 { 00137 #ifdef MFEM_DEBUG 00138 if ( size != x.Size() || height != y.Size() ) 00139 mfem_error("DenseMatrix::Mult"); 00140 #endif 00141 00142 Mult((const double *)x, (double *)y); 00143 } 00144 00145 double DenseMatrix::operator *(const DenseMatrix &m) const 00146 { 00147 #ifdef MFEM_DEBUG 00148 if (Height() != m.Height() || Width() != m.Width()) 00149 mfem_error("DenseMatrix::operator *(...)"); 00150 #endif 00151 00152 int hw = size * height; 00153 double a = 0.0; 00154 for (int i = 0; i < hw; i++) 00155 a += data[i] * m.data[i]; 00156 00157 return a; 00158 } 00159 00160 void DenseMatrix::MultTranspose(const Vector &x, Vector &y) const 00161 { 00162 #ifdef MFEM_DEBUG 00163 if ( height != x.Size() || size != y.Size() ) 00164 mfem_error("DenseMatrix::MultTranspose"); 00165 #endif 00166 00167 for (int i = 0; i < size; i++) 00168 { 00169 double d = 0.0; 00170 for (int j = 0; j < height; j++) 00171 d += (*this)(j,i) * x(j); 00172 y(i) = d; 00173 } 00174 } 00175 00176 void DenseMatrix::AddMult(const Vector &x, Vector &y) const 00177 { 00178 #ifdef MFEM_DEBUG 00179 if ( size != x.Size() || height != y.Size() ) 00180 mfem_error("DenseMatrix::AddMult"); 00181 #endif 00182 00183 for (int i = 0; i < height; i++) 00184 for (int j = 0; j < size; j++) 00185 y(i) += (*this)(i,j) * x(j); 00186 } 00187 00188 double DenseMatrix::InnerProduct(const double *x, const double *y) const 00189 { 00190 double prod = 0.0; 00191 00192 for (int i = 0; i < height; i++) 00193 { 00194 double Axi = 0.0; 00195 for (int j = 0; j < size; j++) 00196 Axi += (*this)(i,j) * x[j]; 00197 prod += y[i] * Axi; 00198 } 00199 00200 return prod; 00201 } 00202 00203 double DenseMatrix::Trace() const 00204 { 00205 #ifdef MFEM_DEBUG 00206 if (Width() != Height()) 00207 mfem_error("DenseMatrix::Trace() : not a square matrix!"); 00208 #endif 00209 00210 double t = 0.0; 00211 00212 for (int i = 0; i < size; i++) 00213 t += (*this)(i, i); 00214 00215 return t; 00216 } 00217 00218 MatrixInverse *DenseMatrix::Inverse() const 00219 { 00220 return new DenseMatrixInverse(*this); 00221 } 00222 00223 double DenseMatrix::Det() const 00224 { 00225 #ifdef MFEM_DEBUG 00226 if (Height() != Width() || Height() < 1 || Height() > 3) 00227 mfem_error("DenseMatrix::Det"); 00228 #endif 00229 00230 switch (Height()) 00231 { 00232 case 1: 00233 return data[0]; 00234 00235 case 2: 00236 return data[0] * data[3] - data[1] * data[2]; 00237 00238 case 3: 00239 { 00240 const double *d = data; 00241 return 00242 d[0] * (d[4] * d[8] - d[5] * d[7]) + 00243 d[3] * (d[2] * d[7] - d[1] * d[8]) + 00244 d[6] * (d[1] * d[5] - d[2] * d[4]); 00245 } 00246 } 00247 return 0.0; 00248 } 00249 00250 double DenseMatrix::Weight() const 00251 { 00252 if (Height() == Width()) 00253 { 00254 // return fabs(Det()); 00255 return Det(); 00256 } 00257 else if ((Height() == 2) && (Width() == 1)) 00258 { 00259 return sqrt(data[0] * data[0] + data[1] * data[1]); 00260 } 00261 else if ((Height() == 3) && (Width() == 2)) 00262 { 00263 const double *d = data; 00264 double E = d[0] * d[0] + d[1] * d[1] + d[2] * d[2]; 00265 double G = d[3] * d[3] + d[4] * d[4] + d[5] * d[5]; 00266 double F = d[0] * d[3] + d[1] * d[4] + d[2] * d[5]; 00267 return sqrt(E * G - F * F); 00268 } 00269 mfem_error("DenseMatrix::Weight()"); 00270 return 0.0; 00271 } 00272 00273 void DenseMatrix::Add(const double c, DenseMatrix &A) 00274 { 00275 for (int i = 0; i < Height(); i++) 00276 for (int j = 0; j < Size(); j++) 00277 (*this)(i,j) += c * A(i,j); 00278 } 00279 00280 DenseMatrix &DenseMatrix::operator=(double c) 00281 { 00282 int s = Size()*Height(); 00283 if (data != NULL) 00284 for (int i = 0; i < s; i++) 00285 data[i] = c; 00286 return *this; 00287 } 00288 00289 DenseMatrix &DenseMatrix::operator=(const DenseMatrix &m) 00290 { 00291 int i, hw; 00292 00293 SetSize(m.height, m.size); 00294 00295 hw = size * height; 00296 for (i = 0; i < hw; i++) 00297 data[i] = m.data[i]; 00298 00299 return *this; 00300 } 00301 00302 DenseMatrix &DenseMatrix::operator+=(DenseMatrix &m) 00303 { 00304 int i, j; 00305 00306 for (i = 0; i < height; i++) 00307 for (j = 0; j < size; j++) 00308 (*this)(i, j) += m(i, j); 00309 00310 return *this; 00311 } 00312 00313 DenseMatrix &DenseMatrix::operator-=(DenseMatrix &m) 00314 { 00315 int i, j; 00316 00317 for (i = 0; i < height; i++) 00318 for (j = 0; j < size; j++) 00319 (*this)(i, j) -= m(i, j); 00320 00321 return *this; 00322 } 00323 00324 DenseMatrix &DenseMatrix::operator*=(double c) 00325 { 00326 int s = Size()*Height(); 00327 if (data != NULL) 00328 for (int i = 0; i < s; i++) 00329 data[i] *= c; 00330 return *this; 00331 } 00332 00333 void DenseMatrix::Neg() 00334 { 00335 int i, hw = Height() * Size(); 00336 00337 for (i = 0; i < hw; i++) 00338 data[i] = -data[i]; 00339 } 00340 00341 #ifdef MFEM_USE_LAPACK 00342 extern "C" void 00343 dgetrf_(int *, int *, double *, int *, int *, int *); 00344 extern "C" void 00345 dgetrs_(char *, int *, int *, double *, int *, int *, double *, int *, int *); 00346 extern "C" void 00347 dgetri_(int *N, double *A, int *LDA, int *IPIV, double *WORK, 00348 int *LWORK, int *INFO); 00349 #endif 00350 00351 void DenseMatrix::Invert() 00352 { 00353 #ifdef MFEM_DEBUG 00354 if (Size() <= 0 || Size() != Height()) 00355 mfem_error("DenseMatrix::Invert()"); 00356 #endif 00357 00358 #ifdef MFEM_USE_LAPACK 00359 int *ipiv = new int[size]; 00360 int lwork = -1; 00361 double qwork, *work; 00362 int info; 00363 00364 dgetrf_(&size, &size, data, &size, ipiv, &info); 00365 00366 if (info) 00367 mfem_error("DenseMatrix::Invert() : Error in DGETRF"); 00368 00369 dgetri_(&size, data, &size, ipiv, &qwork, &lwork, &info); 00370 00371 lwork = (int) qwork; 00372 work = new double[lwork]; 00373 00374 dgetri_(&size, data, &size, ipiv, work, &lwork, &info); 00375 00376 if (info) 00377 mfem_error("DenseMatrix::Invert() : Error in DGETRI"); 00378 00379 delete [] work; 00380 delete [] ipiv; 00381 #else 00382 int c, i, j, n = Size(); 00383 double a, b; 00384 Array<int> piv(n); 00385 00386 for (c = 0; c < n; c++) 00387 { 00388 a = fabs((*this)(c, c)); 00389 i = c; 00390 for (j = c + 1; j < n; j++) 00391 { 00392 b = fabs((*this)(j, c)); 00393 if (a < b) 00394 { 00395 a = b; 00396 i = j; 00397 } 00398 } 00399 if (a == 0.0) 00400 mfem_error("DenseMatrix::Invert() : singular matrix"); 00401 piv[c] = i; 00402 for (j = 0; j < n; j++) 00403 Swap<double>((*this)(c, j), (*this)(i, j)); 00404 00405 a = (*this)(c, c) = 1.0 / (*this)(c, c); 00406 for (j = 0; j < c; j++) 00407 (*this)(c, j) *= a; 00408 for (j++; j < n; j++) 00409 (*this)(c, j) *= a; 00410 for (i = 0; i < c; i++) 00411 { 00412 (*this)(i, c) = a * (b = -(*this)(i, c)); 00413 for (j = 0; j < c; j++) 00414 (*this)(i, j) += b * (*this)(c, j); 00415 for (j++; j < n; j++) 00416 (*this)(i, j) += b * (*this)(c, j); 00417 } 00418 for (i++; i < n; i++) 00419 { 00420 (*this)(i, c) = a * (b = -(*this)(i, c)); 00421 for (j = 0; j < c; j++) 00422 (*this)(i, j) += b * (*this)(c, j); 00423 for (j++; j < n; j++) 00424 (*this)(i, j) += b * (*this)(c, j); 00425 } 00426 } 00427 00428 for (c = n - 1; c >= 0; c--) 00429 { 00430 j = piv[c]; 00431 for (i = 0; i < n; i++) 00432 Swap<double>((*this)(i, c), (*this)(i, j)); 00433 } 00434 #endif 00435 } 00436 00437 void DenseMatrix::Norm2(double *v) const 00438 { 00439 for (int j = 0; j < Size(); j++) 00440 { 00441 v[j] = 0.0; 00442 for (int i = 0; i < Height(); i++) 00443 v[j] += (*this)(i,j)*(*this)(i,j); 00444 v[j] = sqrt(v[j]); 00445 } 00446 } 00447 00448 double DenseMatrix::FNorm() const 00449 { 00450 int i, hw = Height() * Size(); 00451 double max_norm = 0.0, entry, fnorm2; 00452 00453 for (i = 0; i < hw; i++) 00454 { 00455 entry = fabs(data[i]); 00456 if (entry > max_norm) 00457 max_norm = entry; 00458 } 00459 00460 if (max_norm == 0.0) 00461 return 0.0; 00462 00463 fnorm2 = 0.0; 00464 for (i = 0; i < hw; i++) 00465 { 00466 entry = data[i] / max_norm; 00467 fnorm2 += entry * entry; 00468 } 00469 00470 return max_norm * sqrt(fnorm2); 00471 } 00472 00473 #ifdef MFEM_USE_LAPACK 00474 extern "C" void 00475 dsyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, double *A, int *LDA, 00476 double *VL, double *VU, int *IL, int *IU, double *ABSTOL, int *M, 00477 double *W, double *Z, int *LDZ, int *ISUPPZ, double *WORK, int *LWORK, 00478 int *IWORK, int *LIWORK, int *INFO); 00479 extern "C" void 00480 dsyev_(char *JOBZ, char *UPLO, int *N, double *A, int *LDA, double *W, 00481 double *WORK, int *LWORK, int *INFO); 00482 extern "C" void 00483 dgesvd_(char *JOBU, char *JOBVT, int *M, int *N, double *A, int *LDA, 00484 double *S, double *U, int *LDU, double *VT, int *LDVT, double *WORK, 00485 int *LWORK, int *INFO); 00486 #endif 00487 00488 void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect) 00489 { 00490 00491 #ifdef MFEM_USE_LAPACK 00492 00493 ev.SetSize(a.Size()); 00494 00495 char JOBZ = 'N'; 00496 char RANGE = 'A'; 00497 char UPLO = 'U'; 00498 int N = a.Size(); 00499 double *A = new double[N*N]; 00500 int LDA = N; 00501 double VL = 0.0; 00502 double VU = 1.0; 00503 int IL = 0; 00504 int IU = 1; 00505 double ABSTOL = 0.0; 00506 int M; 00507 double *W = ev.GetData(); 00508 double *Z = NULL; 00509 int LDZ = 1; 00510 int *ISUPPZ = new int[2*N]; 00511 int LWORK = -1; // query optimal (double) workspace size 00512 double QWORK; 00513 double *WORK = NULL; 00514 int LIWORK = -1; // query optimal (int) workspace size 00515 int QIWORK; 00516 int *IWORK = NULL; 00517 int INFO; 00518 00519 if (evect) // Compute eigenvectors too 00520 { 00521 evect->SetSize(N); 00522 00523 JOBZ = 'V'; 00524 Z = evect->Data(); 00525 LDZ = N; 00526 } 00527 00528 int hw = a.Height() * a.Width(); 00529 double *data = a.Data(); 00530 00531 for (int i = 0; i < hw; i++) 00532 A[i] = data[i]; 00533 00534 dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU, 00535 &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK, &LWORK, 00536 &QIWORK, &LIWORK, &INFO ); 00537 00538 LWORK = (int) QWORK; 00539 LIWORK = QIWORK; 00540 00541 WORK = new double[LWORK]; 00542 IWORK = new int[LIWORK]; 00543 00544 dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU, 00545 &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK, &LWORK, 00546 IWORK, &LIWORK, &INFO ); 00547 00548 if (INFO != 0) 00549 { 00550 cerr << "dsyevr_Eigensystem(...): DSYEVR error code: " 00551 << INFO << endl; 00552 mfem_error(); 00553 } 00554 00555 #ifdef MFEM_DEBUG 00556 if (M < N) 00557 { 00558 cerr << "dsyevr_Eigensystem(...):\n" 00559 << " DSYEVR did not find all eigenvalues " 00560 << M << "/" << N << endl; 00561 mfem_error(); 00562 } 00563 for (IL = 0; IL < N; IL++) 00564 if (!finite(W[IL])) 00565 mfem_error("dsyevr_Eigensystem(...): !finite value in W"); 00566 for (IL = 0; IL < N*N; IL++) 00567 if (!finite(Z[IL])) 00568 mfem_error("dsyevr_Eigensystem(...): !finite value in Z"); 00569 VU = 0.0; 00570 for (IL = 0; IL < N; IL++) 00571 for (IU = 0; IU <= IL; IU++) 00572 { 00573 VL = 0.0; 00574 for (M = 0; M < N; M++) 00575 VL += Z[M+IL*N] * Z[M+IU*N]; 00576 if (IU < IL) 00577 VL = fabs(VL); 00578 else 00579 VL = fabs(VL-1.0); 00580 if (VL > VU) 00581 VU = VL; 00582 if (VU > 0.5) 00583 { 00584 cerr << "dsyevr_Eigensystem(...):" 00585 << " Z^t Z - I deviation = " << VU 00586 << "\n W[max] = " << W[N-1] << ", W[min] = " 00587 << W[0] << ", N = " << N << endl; 00588 mfem_error(); 00589 } 00590 } 00591 if (VU > 1e-9) 00592 { 00593 cerr << "dsyevr_Eigensystem(...):" 00594 << " Z^t Z - I deviation = " << VU 00595 << "\n W[max] = " << W[N-1] << ", W[min] = " 00596 << W[0] << ", N = " << N << endl; 00597 } 00598 if (VU > 1e-5) 00599 mfem_error("dsyevr_Eigensystem(...): ERROR: ..."); 00600 VU = 0.0; 00601 for (IL = 0; IL < N; IL++) 00602 for (IU = 0; IU < N; IU++) 00603 { 00604 VL = 0.0; 00605 for (M = 0; M < N; M++) 00606 VL += Z[IL+M*N] * W[M] * Z[IU+M*N]; 00607 VL = fabs(VL-data[IL+N*IU]); 00608 if (VL > VU) 00609 VU = VL; 00610 } 00611 if (VU > 1e-9) 00612 { 00613 cerr << "dsyevr_Eigensystem(...):" 00614 << " max matrix deviation = " << VU 00615 << "\n W[max] = " << W[N-1] << ", W[min] = " 00616 << W[0] << ", N = " << N << endl; 00617 } 00618 if (VU > 1e-5) 00619 mfem_error("dsyevr_Eigensystem(...): ERROR: ..."); 00620 #endif 00621 00622 delete [] IWORK; 00623 delete [] WORK; 00624 delete [] ISUPPZ; 00625 delete [] A; 00626 00627 #endif 00628 } 00629 00630 void dsyev_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect) 00631 { 00632 00633 #ifdef MFEM_USE_LAPACK 00634 00635 int N = a.Size(); 00636 char JOBZ = 'N'; 00637 char UPLO = 'U'; 00638 int LDA = N; 00639 int LWORK = -1; /* query optimal workspace size */ 00640 int INFO; 00641 00642 ev.SetSize(N); 00643 00644 double *A = NULL; 00645 double *W = ev.GetData(); 00646 double *WORK = NULL; 00647 double QWORK; 00648 00649 if (evect) 00650 { 00651 JOBZ = 'V'; 00652 evect->SetSize(N); 00653 A = evect->Data(); 00654 } 00655 else 00656 { 00657 A = new double[N*N]; 00658 } 00659 00660 int hw = a.Height() * a.Width(); 00661 double *data = a.Data(); 00662 for (int i = 0; i < hw; i++) 00663 A[i] = data[i]; 00664 00665 dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO); 00666 00667 LWORK = (int) QWORK; 00668 WORK = new double[LWORK]; 00669 00670 dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); 00671 00672 if (INFO != 0) 00673 { 00674 cerr << "dsyev_Eigensystem: DSYEV error code: " << INFO << endl; 00675 mfem_error(); 00676 } 00677 00678 delete [] WORK; 00679 if (evect == NULL) delete [] A; 00680 00681 #endif 00682 } 00683 00684 void DenseMatrix::Eigensystem(Vector &ev, DenseMatrix *evect) 00685 { 00686 #ifdef MFEM_USE_LAPACK 00687 00688 // dsyevr_Eigensystem(*this, ev, evect); 00689 00690 dsyev_Eigensystem(*this, ev, evect); 00691 00692 #else 00693 00694 mfem_error("DenseMatrix::Eigensystem"); 00695 00696 #endif 00697 } 00698 00699 void DenseMatrix::SingularValues(Vector &sv) const 00700 { 00701 #ifdef MFEM_USE_LAPACK 00702 DenseMatrix copy_of_this = *this; 00703 char jobu = 'N'; 00704 char jobvt = 'N'; 00705 int m = Height(); 00706 int n = Width(); 00707 double *a = copy_of_this.data; 00708 sv.SetSize(min(m, n)); 00709 double *s = sv; 00710 double *u = NULL; 00711 double *vt = NULL; 00712 double *work = NULL; 00713 int lwork = -1; 00714 int info; 00715 double qwork; 00716 00717 dgesvd_(&jobu, &jobvt, &m, &n, a, &m, 00718 s, u, &m, vt, &n, &qwork, &lwork, &info); 00719 00720 lwork = (int) qwork; 00721 work = new double[lwork]; 00722 00723 dgesvd_(&jobu, &jobvt, &m, &n, a, &m, 00724 s, u, &m, vt, &n, work, &lwork, &info); 00725 00726 delete [] work; 00727 if (info) 00728 { 00729 cerr << "DenseMatrix::SingularValues : info = " << info << endl; 00730 mfem_error(); 00731 } 00732 #else 00733 // compiling without lapack 00734 mfem_error("DenseMatrix::SingularValues"); 00735 #endif 00736 } 00737 00738 double DenseMatrix::CalcSingularvalue(const int i) const 00739 { 00740 #ifdef MFEM_DEBUG 00741 if (Height() != Width() || Height() < 2 || Height() > 3) 00742 mfem_error("DenseMatrix::CalcSingularvalue"); 00743 #endif 00744 00745 const int n = Height(); 00746 const double *d = data; 00747 00748 if (n == 2) 00749 { 00750 #if 0 00751 double b11 = d[0]*d[0] + d[1]*d[1]; 00752 double b12 = d[0]*d[2] + d[1]*d[3]; 00753 double b22 = d[2]*d[2] + d[3]*d[3]; 00754 00755 double tmp = 0.5*(b11 - b22); 00756 double sqrtD_2 = sqrt(tmp*tmp + b12*b12); 00757 double mid = 0.5*(b11 + b22); 00758 if (i == 0) 00759 return sqrt(mid + sqrtD_2); 00760 if ((mid -= sqrtD_2) <= 0.0) 00761 return 0.0; 00762 return sqrt(mid); 00763 #else 00764 register double d0, d1, d2, d3; 00765 d0 = d[0]; 00766 d1 = d[1]; 00767 d2 = d[2]; 00768 d3 = d[3]; 00769 // double b11 = d[0]*d[0] + d[1]*d[1]; 00770 // double b12 = d[0]*d[2] + d[1]*d[3]; 00771 // double b22 = d[2]*d[2] + d[3]*d[3]; 00772 // t = 0.5*(a+b).(a-b) = 0.5*(|a|^2-|b|^2) 00773 // with a,b - the columns of (*this) 00774 // double t = 0.5*(b11 - b22); 00775 double t = 0.5*((d0+d2)*(d0-d2)+(d1-d3)*(d1+d3)); 00776 // double s = sqrt(0.5*(b11 + b22) + sqrt(t*t + b12*b12)); 00777 double s = d0*d2 + d1*d3; 00778 s = sqrt(0.5*(d0*d0 + d1*d1 + d2*d2 + d3*d3) + sqrt(t*t + s*s)); 00779 if (s == 0.0) 00780 return 0.0; 00781 t = fabs(d0*d3 - d1*d2) / s; 00782 // #ifdef MFEM_DEBUG 00783 if (t > s) 00784 { 00785 if (i == 0) 00786 return t; 00787 return s; 00788 // mfem_error("DenseMatrix::CalcSingularvalue : 2x2"); 00789 } 00790 // #endif 00791 if (i == 0) 00792 return s; 00793 return t; 00794 #endif 00795 } 00796 else 00797 { 00798 double b11 = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; 00799 double b12 = d[0]*d[3] + d[1]*d[4] + d[2]*d[5]; 00800 double b13 = d[0]*d[6] + d[1]*d[7] + d[2]*d[8]; 00801 double b22 = d[3]*d[3] + d[4]*d[4] + d[5]*d[5]; 00802 double b23 = d[3]*d[6] + d[4]*d[7] + d[5]*d[8]; 00803 double b33 = d[6]*d[6] + d[7]*d[7] + d[8]*d[8]; 00804 00805 // double a, b, c; 00806 // a = -(b11 + b22 + b33); 00807 // b = b11*(b22 + b33) + b22*b33 - b12*b12 - b13*b13 - b23*b23; 00808 // c = b11*(b23*b23 - b22*b33) + b12*(b12*b33 - 2*b13*b23) + b13*b13*b22; 00809 00810 // double Q = (a * a - 3 * b) / 9; 00811 // double Q = (b12*b12 + b13*b13 + b23*b23 + 00812 // ((b11 - b22)*(b11 - b22) + 00813 // (b11 - b33)*(b11 - b33) + 00814 // (b22 - b33)*(b22 - b33))/6)/3; 00815 // Q = (3*(b12^2 + b13^2 + b23^2) + 00816 // ((b11 - b22)^2 + (b11 - b33)^2 + (b22 - b33)^2)/2)/9 00817 // or 00818 // Q = (1/6)*|B-tr(B)/3|_F^2 00819 // Q >= 0 and 00820 // Q = 0 <==> B = scalar * I 00821 // double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54; 00822 double aa = (b11 + b22 + b33)/3; // aa = tr(B)/3 00823 double c1, c2, c3; 00824 // c1 = b11 - aa; // ((b11 - b22) + (b11 - b33))/3 00825 // c2 = b22 - aa; // ((b22 - b11) + (b22 - b33))/3 00826 // c3 = b33 - aa; // ((b33 - b11) + (b33 - b22))/3 00827 { 00828 double b11_b22 = ((d[0]-d[3])*(d[0]+d[3])+ 00829 (d[1]-d[4])*(d[1]+d[4])+ 00830 (d[2]-d[5])*(d[2]+d[5])); 00831 double b22_b33 = ((d[3]-d[6])*(d[3]+d[6])+ 00832 (d[4]-d[7])*(d[4]+d[7])+ 00833 (d[5]-d[8])*(d[5]+d[8])); 00834 double b33_b11 = ((d[6]-d[0])*(d[6]+d[0])+ 00835 (d[7]-d[1])*(d[7]+d[1])+ 00836 (d[8]-d[2])*(d[8]+d[2])); 00837 c1 = (b11_b22 - b33_b11)/3; 00838 c2 = (b22_b33 - b11_b22)/3; 00839 c3 = (b33_b11 - b22_b33)/3; 00840 } 00841 double Q = (2*(b12*b12 + b13*b13 + b23*b23) + 00842 c1*c1 + c2*c2 + c3*c3)/6; 00843 double R = (c1*(b23*b23 - c2*c3)+ b12*(b12*c3 - 2*b13*b23) + 00844 b13*b13*c2)/2; 00845 // R = (-1/2)*det(B-(tr(B)/3)*I) 00846 // Note: 54*(det(S))^2 <= |S|_F^6, when S^t=S and tr(S)=0, S is 3x3 00847 // Therefore: R^2 <= Q^3 00848 00849 if (Q <= 0.) 00850 { 00851 ; 00852 } 00853 00854 // else if (fabs(R) >= sqrtQ3) 00855 // { 00856 // double det = (d[0] * (d[4] * d[8] - d[5] * d[7]) + 00857 // d[3] * (d[2] * d[7] - d[1] * d[8]) + 00858 // d[6] * (d[1] * d[5] - d[2] * d[4])); 00859 // 00860 // if (R > 0.) 00861 // { 00862 // if (i == 2) 00863 // // aa -= 2*sqrtQ; 00864 // return fabs(det)/(aa + sqrtQ); 00865 // else 00866 // aa += sqrtQ; 00867 // } 00868 // else 00869 // { 00870 // if (i != 0) 00871 // aa -= sqrtQ; 00872 // // aa = fabs(det)/sqrt(aa + 2*sqrtQ); 00873 // else 00874 // aa += 2*sqrtQ; 00875 // } 00876 // } 00877 00878 else 00879 { 00880 double sqrtQ = sqrt(Q); 00881 double sqrtQ3 = Q*sqrtQ; 00882 // double sqrtQ3 = sqrtQ*sqrtQ*sqrtQ; 00883 // double sqrtQ3 = pow(Q, 1.5); 00884 double r; 00885 00886 if (fabs(R) >= sqrtQ3) 00887 { 00888 if (R < 0.) 00889 { 00890 R = -1.; 00891 r = 2*sqrtQ; 00892 } 00893 else 00894 { 00895 R = 1.; 00896 r = -2*sqrtQ; 00897 } 00898 } 00899 else 00900 { 00901 R = R/sqrtQ3; 00902 00903 // if (fabs(R) <= 0.95) 00904 if (fabs(R) <= 0.9) 00905 { 00906 if (i == 2) 00907 aa -= 2*sqrtQ*cos(acos(R)/3); // min 00908 else if (i == 0) 00909 aa -= 2*sqrtQ*cos((acos(R) + 2.0*M_PI)/3); // max 00910 else 00911 aa -= 2*sqrtQ*cos((acos(R) - 2.0*M_PI)/3); // mid 00912 goto have_aa; 00913 } 00914 00915 if (R < 0.) 00916 { 00917 r = -2*sqrtQ*cos((acos(R) + 2.0*M_PI)/3); // max 00918 if (i == 0) 00919 { 00920 aa += r; 00921 goto have_aa; 00922 } 00923 } 00924 else 00925 { 00926 r = -2*sqrtQ*cos(acos(R)/3); // min 00927 if (i == 2) 00928 { 00929 aa += r; 00930 goto have_aa; 00931 } 00932 } 00933 } 00934 00935 // (tr(B)/3 + r) is the root which is separated from the other 00936 // two roots which are close to each other when |R| is close to 1 00937 00938 c1 -= r; 00939 c2 -= r; 00940 c3 -= r; 00941 00942 // QR factorization of 00943 // c1 b12 b13 00944 // b12 c2 b23 00945 // b13 b23 c3 00946 // to find an eigenvector (z1,z2,z3) for [tr(B)/3 + r] 00947 double z1, z2, z3; 00948 double sigma = b12*b12 + b13*b13; 00949 double mu, gamma, u1; 00950 double c12, c13, c23, c32, w1, w2, w3; 00951 if (sigma == 0.) 00952 { 00953 z1 = 1.; 00954 z2 = z3 = 0.; 00955 } 00956 else 00957 { 00958 mu = copysign(sqrt(c1*c1 + sigma), c1); 00959 u1 = -sigma/(c1 + mu); // = c1 - mu 00960 gamma = 2./(sigma + u1*u1); 00961 // u = (u1, b12, b13), gamma = 2/(u^t u) 00962 // Q = I - 2/(u^t u) u u^t, Q (c1, b12, b13) = mu e_1 00963 c1 = mu; 00964 w2 = gamma*(b12*(u1 + c2) + b23*b13); 00965 w3 = gamma*(b13*(u1 + c3) + b23*b12); 00966 c12 = b12 - u1 *w2; 00967 c2 = c2 - b12*w2; 00968 c32 = b23 - b13*w2; 00969 c13 = b13 - u1 *w3; 00970 c23 = b23 - b12*w3; 00971 c3 = c3 - b13*w3; 00972 00973 sigma = c32*c32; 00974 if (sigma == 0.) 00975 { 00976 ; 00977 } 00978 else 00979 { 00980 mu = copysign(sqrt(c2*c2 + sigma), c2); 00981 u1 = -sigma/(c2 + mu); // = c2 - mu 00982 gamma = 2./(sigma + u1*u1); 00983 // u = (0, u1, c32), gamma = 2/(u^t u) 00984 // Q = I - 2/(u^t u) u u^t, Q (c12, c2, c32) = (c12, mu, 0) 00985 c2 = mu; 00986 w3 = gamma*(u1*c23 + c32*c3); 00987 c23 = c23 - u1 *w3; 00988 c3 = c3 - c32*w3; 00989 } 00990 // solve: 00991 // | c1 c12 c13 | | z1 | | 0 | 00992 // | 0 c2 c23 | | z2 | = | 0 | 00993 // | 0 0 c3 | | z3 | | 0 | 00994 // either c2 or c3 must be 0 00995 if (fabs(c3) < fabs(c2)) 00996 { 00997 // c3 ~ 0? --> set z3 = 1 00998 // c2*z2 + c23 = 0 ==> z2 = -c23/c2 00999 // c1*z1 + c12*z2 + c13 = 0 ==> z1 = (-c13 - c12*z2)/c1 01000 z3 = 1.; 01001 z2 = -c23/c2; 01002 z1 = -(c13 + c12*z2)/c1; 01003 } 01004 else 01005 { 01006 // c2 ~ 0? 01007 z3 = 0.; 01008 z2 = 1.; 01009 z1 = -c12/c1; 01010 } 01011 } 01012 01013 // using the eigenvector z=(z1,z2,z3) transform B into 01014 // | * 0 0 | 01015 // Q B Q = | 0 c2 c23 | 01016 // | 0 c23 c3 | 01017 sigma = z2*z2 + z3*z3; 01018 if (sigma == 0.) 01019 { 01020 c2 = b22; 01021 c23 = b23; 01022 c3 = b33; 01023 } 01024 else 01025 { 01026 mu = copysign(sqrt(z1*z1 + sigma), z1); 01027 u1 = -sigma/(z1 + mu); // = z1 - mu 01028 gamma = 2./(sigma + u1*u1); 01029 // u = (u1, z2, z3), gamma = 2/(u^t u) 01030 // Q = I - 2/(u^t u) u u^t, Q (z1, z2, z3) = mu e_1 01031 // Compute Q B Q 01032 // w = gamma*B u 01033 w1 = gamma*(b11*u1 + b12*z2 + b13*z3); 01034 w2 = gamma*(b12*u1 + b22*z2 + b23*z3); 01035 w3 = gamma*(b13*u1 + b23*z2 + b33*z3); 01036 // w <- w - (gamma*(u^t w)/2) u 01037 double gutw2 = gamma*(u1*w1 + z2*w2 + z3*w3)/2; 01038 w2 -= gutw2*z2; 01039 w3 -= gutw2*z3; 01040 c2 = b22 - 2*z2*w2; 01041 c23 = b23 - z2*w3 - z3*w2; 01042 c3 = b33 - 2*z3*w3; 01043 01044 #ifdef MFEM_DEBUG 01045 // for debugger testing 01046 // is z close to an eigenvector? 01047 w1 -= gutw2*u1; 01048 c1 = b11 - 2*u1*w1; // is c1 more accurate than (aa + r)? 01049 c12 = b12 - u1*w2 - z2*w1; 01050 c13 = b13 - u1*w3 - z3*w1; 01051 #endif 01052 } 01053 01054 // find the eigenvalues of 01055 // | c2 c23 | 01056 // | c23 c3 | 01057 w1 = 0.5*(c3 - c2); 01058 w2 = 0.5*(c2 + c3) + sqrt(w1*w1 + c23*c23); 01059 if (w2 == 0.0) 01060 { 01061 w1 = 0.0; 01062 } 01063 else 01064 { 01065 w1 = (c2*c3 - c23*c23)/w2; 01066 } 01067 01068 if (R < 0.) 01069 { 01070 // order is w1 <= w2 <= aa + r 01071 if (i == 2) 01072 aa = w1; 01073 else if (i == 0) 01074 aa += r; 01075 else 01076 aa = w2; 01077 } 01078 else 01079 { 01080 // order is aa + r <= w1 <= w2 01081 if (i == 2) 01082 aa += r; 01083 else if (i == 0) 01084 aa = w2; 01085 else 01086 aa = w1; 01087 } 01088 01089 // double theta = acos(R / sqrtQ3); 01090 // double A = -2 * sqrt(Q); 01091 // 01092 // if (i == 2) 01093 // { 01094 // aa += A * cos(theta / 3); // min 01095 // } 01096 // else if (i == 0) 01097 // { 01098 // aa += A * cos((theta + 2.0 * M_PI) / 3); // max 01099 // } 01100 // else 01101 // { 01102 // aa += A * cos((theta - 2.0 * M_PI) / 3); // mid 01103 // } 01104 } 01105 01106 have_aa: 01107 if (aa < 0.0) 01108 { 01109 cerr << "DenseMatrix::CalcSingularvalue (3x3) : aa = " << aa << endl; 01110 mfem_error(); 01111 return 0.0; 01112 } 01113 01114 return sqrt(aa); 01115 } 01116 01117 // return 0.0; 01118 } 01119 01120 void DenseMatrix::CalcEigenvalues(double *lambda, double *vec) const 01121 { 01122 #ifdef MFEM_DEBUG 01123 if (Height() != Width() || Height() < 2 || Height() > 3) 01124 mfem_error("DenseMatrix::CalcEigenvalues"); 01125 #endif 01126 01127 const int n = Height(); 01128 const double *d = data; 01129 01130 if (n == 2) 01131 { 01132 const double d0 = d[0]; 01133 const double d2 = d[2]; // use the upper triangular entry 01134 const double d3 = d[3]; 01135 01136 double c, s, l0, l1; 01137 if (d2 == 0.) 01138 { 01139 c = 1.; 01140 s = 0.; 01141 l0 = d0; 01142 l1 = d3; 01143 } 01144 else 01145 { 01146 // "The Symmetric Eigenvalue Problem", B. N. Parlett, pp.189-190 01147 double zeta = (d3 - d0)/(2*d2); 01148 double t = copysign(1./(fabs(zeta) + sqrt(1. + zeta*zeta)), zeta); 01149 c = 1./sqrt(1. + t*t); 01150 s = c*t; 01151 l0 = d0 - d2*t; 01152 l1 = d3 + d2*t; 01153 } 01154 if (l0 <= l1) 01155 { 01156 lambda[0] = l0; 01157 lambda[1] = l1; 01158 vec[0] = c; 01159 vec[1] = -s; 01160 vec[2] = s; 01161 vec[3] = c; 01162 } 01163 else 01164 { 01165 lambda[0] = l1; 01166 lambda[1] = l0; 01167 vec[0] = s; 01168 vec[1] = c; 01169 vec[2] = c; 01170 vec[3] = -s; 01171 } 01172 } 01173 else 01174 { 01175 const double d11 = d[0]; 01176 const double d22 = d[4]; 01177 const double d33 = d[8]; 01178 const double d12 = d[3]; // use the upper triangular entries 01179 const double d13 = d[6]; 01180 const double d23 = d[7]; 01181 01182 double aa = (d11 + d22 + d33)/3; // aa = tr(A)/3 01183 double c1 = d11 - aa; 01184 double c2 = d22 - aa; 01185 double c3 = d33 - aa; 01186 01187 double Q = (2*(d12*d12 + d13*d13 + d23*d23) + 01188 c1*c1 + c2*c2 + c3*c3)/6; 01189 double R = (c1*(d23*d23 - c2*c3)+ d12*(d12*c3 - 2*d13*d23) + 01190 d13*d13*c2)/2; 01191 01192 if (Q <= 0.) 01193 { 01194 lambda[0] = lambda[1] = lambda[2] = aa; 01195 vec[0] = 1.; vec[3] = 0.; vec[6] = 0.; 01196 vec[1] = 0.; vec[4] = 1.; vec[7] = 0.; 01197 vec[2] = 0.; vec[5] = 0.; vec[8] = 1.; 01198 } 01199 else 01200 { 01201 double sqrtQ = sqrt(Q); 01202 double sqrtQ3 = Q*sqrtQ; 01203 // double sqrtQ3 = sqrtQ*sqrtQ*sqrtQ; 01204 // double sqrtQ3 = pow(Q, 1.5); 01205 double r; 01206 if (fabs(R) >= sqrtQ3) 01207 { 01208 if (R < 0.) 01209 { 01210 R = -1.; 01211 r = 2*sqrtQ; 01212 } 01213 else 01214 { 01215 R = 1.; 01216 r = -2*sqrtQ; 01217 } 01218 } 01219 else 01220 { 01221 R = R/sqrtQ3; 01222 01223 if (R < 0.) 01224 { 01225 r = -2*sqrtQ*cos((acos(R) + 2.0*M_PI)/3); // max 01226 } 01227 else 01228 { 01229 r = -2*sqrtQ*cos(acos(R)/3); // min 01230 } 01231 } 01232 01233 c1 -= r; 01234 c2 -= r; 01235 c3 -= r; 01236 01237 // QR factorization of 01238 // c1 d12 d13 01239 // d12 c2 d23 01240 // d13 d23 c3 01241 // to find an eigenvector (z1,z2,z3) for [tr(A)/3 + r] 01242 double z1, z2, z3; 01243 double sigma = d12*d12 + d13*d13; 01244 double mu, gamma, u1; 01245 double c12, c13, c23, c32, w1, w2, w3; 01246 if (sigma == 0.) 01247 { 01248 z1 = 1.; 01249 z2 = z3 = 0.; 01250 } 01251 else 01252 { 01253 mu = copysign(sqrt(c1*c1 + sigma), c1); 01254 u1 = -sigma/(c1 + mu); 01255 gamma = 2./(sigma + u1*u1); 01256 c1 = mu; 01257 w2 = gamma*(d12*(u1 + c2) + d23*d13); 01258 w3 = gamma*(d13*(u1 + c3) + d23*d12); 01259 c12 = d12 - u1 *w2; 01260 c2 = c2 - d12*w2; 01261 c32 = d23 - d13*w2; 01262 c13 = d13 - u1 *w3; 01263 c23 = d23 - d12*w3; 01264 c3 = c3 - d13*w3; 01265 01266 sigma = c32*c32; 01267 if (sigma == 0.) 01268 { 01269 ; 01270 } 01271 else 01272 { 01273 mu = copysign(sqrt(c2*c2 + sigma), c2); 01274 u1 = -sigma/(c2 + mu); 01275 gamma = 2./(sigma + u1*u1); 01276 c2 = mu; 01277 w3 = gamma*(u1*c23 + c32*c3); 01278 c23 = c23 - u1 *w3; 01279 c3 = c3 - c32*w3; 01280 } 01281 if (fabs(c3) < fabs(c2)) 01282 { 01283 z3 = 1.; 01284 z2 = -c23/c2; 01285 z1 = -(c13 + c12*z2)/c1; 01286 } 01287 else 01288 { 01289 z3 = 0.; 01290 z2 = 1.; 01291 z1 = -c12/c1; 01292 } 01293 } 01294 01295 // using the eigenvector z=(z1,z2,z3) transform A into 01296 // | * 0 0 | 01297 // Q A Q = | 0 c2 c23 | 01298 // | 0 c23 c3 | 01299 sigma = z2*z2 + z3*z3; 01300 if (sigma == 0.) 01301 { 01302 c2 = d22; 01303 c23 = d23; 01304 c3 = d33; 01305 } 01306 else 01307 { 01308 mu = copysign(sqrt(z1*z1 + sigma), z1); 01309 u1 = -sigma/(z1 + mu); 01310 gamma = 2./(sigma + u1*u1); 01311 w1 = gamma*(d11*u1 + d12*z2 + d13*z3); 01312 w2 = gamma*(d12*u1 + d22*z2 + d23*z3); 01313 w3 = gamma*(d13*u1 + d23*z2 + d33*z3); 01314 double gutw2 = gamma*(u1*w1 + z2*w2 + z3*w3)/2; 01315 w2 -= gutw2*z2; 01316 w3 -= gutw2*z3; 01317 c2 = d22 - 2*z2*w2; 01318 c23 = d23 - z2*w3 - z3*w2; 01319 c3 = d33 - 2*z3*w3; 01320 01321 #ifdef MFEM_DEBUG 01322 // for debugger testing 01323 // is z close to an eigenvector? 01324 w1 -= gutw2*u1; 01325 c1 = d11 - 2*u1*w1; // is c1 more accurate than (aa + r)? 01326 c12 = d12 - u1*w2 - z2*w1; 01327 c13 = d13 - u1*w3 - z3*w1; 01328 #endif 01329 } 01330 01331 // find the eigenvalues and eigenvectors for 01332 // | c2 c23 | 01333 // | c23 c3 | 01334 double c, s; 01335 if (c23 == 0.) 01336 { 01337 c = 1.; 01338 s = 0.; 01339 w1 = c2; 01340 w2 = c3; 01341 } 01342 else 01343 { 01344 double zeta = (c3 - c2)/(2*c23); 01345 double t = copysign(1./(fabs(zeta) + sqrt(1. + zeta*zeta)), zeta); 01346 c = 1./sqrt(1. + t*t); 01347 s = c*t; 01348 w1 = c2 - c23*t; 01349 w2 = c3 + c23*t; 01350 } 01351 // w1 <-> Q (0, c, -s), w2 <-> Q (0, s, c) 01352 // Q = I, when sigma = 0 01353 // Q = I - gamma* u u^t, u = (u1, z2, z3) 01354 01355 double *vec_ar, *vec_w1, *vec_w2; 01356 if (R < 0.) 01357 { 01358 // (aa + r) is max 01359 lambda[2] = aa + r; 01360 vec_ar = vec + 6; 01361 if (w1 <= w2) 01362 { 01363 lambda[0] = w1; vec_w1 = vec; 01364 lambda[1] = w2; vec_w2 = vec + 3; 01365 } 01366 else 01367 { 01368 lambda[0] = w2; vec_w2 = vec; 01369 lambda[1] = w1; vec_w1 = vec + 3; 01370 } 01371 } 01372 else 01373 { 01374 // (aa + r) is min 01375 lambda[0] = aa + r; 01376 vec_ar = vec; 01377 if (w1 <= w2) 01378 { 01379 lambda[1] = w1; vec_w1 = vec + 3; 01380 lambda[2] = w2; vec_w2 = vec + 6; 01381 } 01382 else 01383 { 01384 lambda[1] = w2; vec_w2 = vec + 3; 01385 lambda[2] = w1; vec_w1 = vec + 6; 01386 } 01387 } 01388 01389 if (sigma == 0.) 01390 { 01391 mu = fabs(z1); 01392 vec_w1[0] = 0.; vec_w2[0] = 0.; 01393 vec_w1[1] = c; vec_w2[1] = s; 01394 vec_w1[2] = -s; vec_w2[2] = c; 01395 } 01396 else 01397 { 01398 mu = fabs(mu); 01399 w1 = gamma*(z2*c - z3*s); 01400 w2 = gamma*(z2*s + z3*c); 01401 vec_w1[0] = - u1*w1; vec_w2[0] = - u1*w2; 01402 vec_w1[1] = c - z2*w1; vec_w2[1] = s - z2*w2; 01403 vec_w1[2] = -s - z3*w1; vec_w2[2] = c - z3*w2; 01404 } 01405 vec_ar[0] = z1/mu; 01406 vec_ar[1] = z2/mu; 01407 vec_ar[2] = z3/mu; 01408 } 01409 } 01410 } 01411 01412 void DenseMatrix::GetColumn(int c, Vector &col) 01413 { 01414 int n; 01415 double *cp, *vp; 01416 01417 n = Height(); 01418 col.SetSize(n); 01419 cp = data + c * n; 01420 vp = col.GetData(); 01421 01422 for (int i = 0; i < n; i++) 01423 vp[i] = cp[i]; 01424 } 01425 01426 void DenseMatrix::Diag(double c, int n) 01427 { 01428 SetSize(n); 01429 01430 int i, N = n*n; 01431 for (i = 0; i < N; i++) 01432 data[i] = 0.0; 01433 for (i = 0; i < n; i++) 01434 data[i*(n+1)] = c; 01435 } 01436 01437 void DenseMatrix::Diag(double *diag, int n) 01438 { 01439 SetSize(n); 01440 01441 int i, N = n*n; 01442 for (i = 0; i < N; i++) 01443 data[i] = 0.0; 01444 for (i = 0; i < n; i++) 01445 data[i*(n+1)] = diag[i]; 01446 } 01447 01448 void DenseMatrix::Transpose() 01449 { 01450 int i, j; 01451 double t; 01452 01453 if (Size() == Height()) 01454 { 01455 for (i = 0; i < Height(); i++) 01456 for (j = i+1; j < Size(); j++) 01457 { 01458 t = (*this)(i,j); 01459 (*this)(i,j) = (*this)(j,i); 01460 (*this)(j,i) = t; 01461 } 01462 } 01463 else 01464 { 01465 DenseMatrix T(*this,'t'); 01466 (*this) = T; 01467 } 01468 } 01469 01470 void DenseMatrix::Transpose(DenseMatrix &A) 01471 { 01472 SetSize(A.Size(),A.Height()); 01473 01474 for (int i = 0; i < Height(); i++) 01475 for (int j = 0; j < Size(); j++) 01476 (*this)(i,j) = A(j,i); 01477 } 01478 01479 void DenseMatrix::Symmetrize() 01480 { 01481 #ifdef MFEM_DEBUG 01482 if (Width() != Height()) 01483 mfem_error("DenseMatrix::Symmetrize() : not a square matrix!"); 01484 #endif 01485 01486 for (int i = 0; i < Height(); i++) 01487 for (int j = 0; j < i; j++) 01488 { 01489 double a = 0.5 * ((*this)(i,j) + (*this)(j,i)); 01490 (*this)(j,i) = (*this)(i,j) = a; 01491 } 01492 } 01493 01494 void DenseMatrix::Lump() 01495 { 01496 for (int i = 0; i < Height(); i++) 01497 { 01498 double L = 0.0; 01499 for (int j = 0; j < Width(); j++) 01500 { 01501 L += (*this)(i, j); 01502 (*this)(i, j) = 0.0; 01503 } 01504 (*this)(i, i) = L; 01505 } 01506 } 01507 01508 void DenseMatrix::GradToCurl(DenseMatrix &curl) 01509 { 01510 int n = Height(); 01511 01512 #ifdef MFEM_DEBUG 01513 if (Width() != 3 || curl.Width() != 3 || 3*n != curl.Height()) 01514 mfem_error("DenseMatrix::GradToCurl(...)"); 01515 #endif 01516 01517 for (int i = 0; i < n; i++) 01518 { 01519 // (x,y,z) is grad of Ui 01520 double x = (*this)(i,0); 01521 double y = (*this)(i,1); 01522 double z = (*this)(i,2); 01523 01524 int j = i+n; 01525 int k = j+n; 01526 01527 // curl of (Ui,0,0) 01528 curl(i,0) = 0.; 01529 curl(i,1) = z; 01530 curl(i,2) = -y; 01531 01532 // curl of (0,Ui,0) 01533 curl(j,0) = -z; 01534 curl(j,1) = 0.; 01535 curl(j,2) = x; 01536 01537 // curl of (0,0,Ui) 01538 curl(k,0) = y; 01539 curl(k,1) = -x; 01540 curl(k,2) = 0.; 01541 } 01542 } 01543 01544 void DenseMatrix::GradToDiv(Vector &div) 01545 { 01546 01547 #ifdef MFEM_DEBUG 01548 if (Width()*Height() != div.Size()) 01549 mfem_error("DenseMatrix::GradToDiv(...)"); 01550 #endif 01551 01552 // div(dof*j+i) <-- (*this)(i,j) 01553 01554 int n = size * height; 01555 double *ddata = div.GetData(); 01556 01557 for (int i = 0; i < n; i++) 01558 ddata[i] = data[i]; 01559 } 01560 01561 void DenseMatrix::CopyRows(DenseMatrix &A, int row1, int row2) 01562 { 01563 SetSize(row2 - row1 + 1, A.Size()); 01564 01565 for (int i = row1; i <= row2; i++) 01566 for (int j = 0; j < Size(); j++) 01567 (*this)(i-row1,j) = A(i,j); 01568 } 01569 01570 void DenseMatrix::CopyCols(DenseMatrix &A, int col1, int col2) 01571 { 01572 SetSize(A.Height(), col2 - col1 + 1); 01573 01574 for (int i = 0; i < Height(); i++) 01575 for (int j = col1; j <= col2; j++) 01576 (*this)(i,j-col1) = A(i,j); 01577 } 01578 01579 void DenseMatrix::CopyMN(DenseMatrix &A, int m, int n, int Aro, int Aco) 01580 { 01581 int i, j; 01582 01583 SetSize(m,n); 01584 01585 for (j = 0; j < n; j++) 01586 for (i = 0; i < m; i++) 01587 (*this)(i,j) = A(Aro+i,Aco+j); 01588 } 01589 01590 void DenseMatrix::CopyMN(DenseMatrix &A, int row_offset, int col_offset) 01591 { 01592 int i, j; 01593 double *v = A.data; 01594 01595 for (j = 0; j < A.Size(); j++) 01596 for (i = 0; i < A.Height(); i++) 01597 (*this)(row_offset+i,col_offset+j) = *(v++); 01598 } 01599 01600 void DenseMatrix::CopyMNt(DenseMatrix &A, int row_offset, int col_offset) 01601 { 01602 int i, j; 01603 double *v = A.data; 01604 01605 for (i = 0; i < A.Size(); i++) 01606 for (j = 0; j < A.Height(); j++) 01607 (*this)(row_offset+i,col_offset+j) = *(v++); 01608 } 01609 01610 void DenseMatrix::CopyMNDiag(double c, int n, int row_offset, int col_offset) 01611 { 01612 int i, j; 01613 01614 for (i = 0; i < n; i++) 01615 for (j = i+1; j < n; j++) 01616 (*this)(row_offset+i,col_offset+j) = 01617 (*this)(row_offset+j,col_offset+i) = 0.0; 01618 01619 for (i = 0; i < n; i++) 01620 (*this)(row_offset+i,col_offset+i) = c; 01621 } 01622 01623 void DenseMatrix::CopyMNDiag(double *diag, int n, int row_offset, 01624 int col_offset) 01625 { 01626 int i, j; 01627 01628 for (i = 0; i < n; i++) 01629 for (j = i+1; j < n; j++) 01630 (*this)(row_offset+i,col_offset+j) = 01631 (*this)(row_offset+j,col_offset+i) = 0.0; 01632 01633 for (i = 0; i < n; i++) 01634 (*this)(row_offset+i,col_offset+i) = diag[i]; 01635 } 01636 01637 void DenseMatrix::AddMatrix(DenseMatrix &A, int ro, int co) 01638 { 01639 int h, ah, aw; 01640 double *p, *ap; 01641 01642 h = Height(); 01643 ah = A.Height(); 01644 aw = A.Width(); 01645 01646 #ifdef MFEM_DEBUG 01647 if (co+aw > Width() || ro+ah > h) 01648 mfem_error("DenseMatrix::AddMatrix(...) 1"); 01649 #endif 01650 01651 p = data + ro + co * h; 01652 ap = A.data; 01653 01654 for (int c = 0; c < aw; c++) 01655 { 01656 for (int r = 0; r < ah; r++) 01657 p[r] += ap[r]; 01658 p += h; 01659 ap += ah; 01660 } 01661 } 01662 01663 void DenseMatrix::AddMatrix(double a, DenseMatrix &A, int ro, int co) 01664 { 01665 int h, ah, aw; 01666 double *p, *ap; 01667 01668 h = Height(); 01669 ah = A.Height(); 01670 aw = A.Width(); 01671 01672 #ifdef MFEM_DEBUG 01673 if (co+aw > Width() || ro+ah > h) 01674 mfem_error("DenseMatrix::AddMatrix(...) 2"); 01675 #endif 01676 01677 p = data + ro + co * h; 01678 ap = A.data; 01679 01680 for (int c = 0; c < aw; c++) 01681 { 01682 for (int r = 0; r < ah; r++) 01683 p[r] += a * ap[r]; 01684 p += h; 01685 ap += ah; 01686 } 01687 } 01688 01689 void DenseMatrix::AddToVector(int offset, Vector &v) const 01690 { 01691 int i, n = size * height; 01692 double *vdata = v.GetData() + offset; 01693 01694 for (i = 0; i < n; i++) 01695 vdata[i] += data[i]; 01696 } 01697 01698 void DenseMatrix::GetFromVector(int offset, const Vector &v) 01699 { 01700 int i, n = size * height; 01701 const double *vdata = v.GetData() + offset; 01702 01703 for (i = 0; i < n; i++) 01704 data[i] = vdata[i]; 01705 } 01706 01707 void DenseMatrix::AdjustDofDirection(Array<int> &dofs) 01708 { 01709 int n = Height(); 01710 01711 #ifdef MFEM_DEBUG 01712 if (dofs.Size() != n || Width() != n) 01713 mfem_error("DenseMatrix::AdjustDofDirection(...)"); 01714 #endif 01715 01716 int *dof = dofs; 01717 for (int i = 0; i < n-1; i++) 01718 { 01719 int s = (dof[i] < 0) ? (-1) : (1); 01720 for (int j = i+1; j < n; j++) 01721 { 01722 int t = (dof[j] < 0) ? (-s) : (s); 01723 if (t < 0) 01724 { 01725 (*this)(i,j) = -(*this)(i,j); 01726 (*this)(j,i) = -(*this)(j,i); 01727 } 01728 } 01729 } 01730 } 01731 01732 01733 void DenseMatrix::Print(ostream &out, int width) const 01734 { 01735 // output flags = scientific + show sign 01736 out << setiosflags(ios::scientific | ios::showpos); 01737 for (int i = 0; i < height; i++) 01738 { 01739 out << "[row " << i << "]\n"; 01740 for (int j = 0; j < size; j++) 01741 { 01742 out << (*this)(i,j); 01743 if (j+1 == size || (j+1) % width == 0) 01744 out << '\n'; 01745 else 01746 out << ' '; 01747 } 01748 } 01749 } 01750 01751 void DenseMatrix::PrintT(ostream &out, int width) const 01752 { 01753 // output flags = scientific + show sign 01754 out << setiosflags(ios::scientific | ios::showpos); 01755 for (int j = 0; j < size; j++) 01756 { 01757 out << "[col " << j << "]\n"; 01758 for (int i = 0; i < height; i++) 01759 { 01760 out << (*this)(i,j); 01761 if (i+1 == height || (i+1) % width == 0) 01762 out << '\n'; 01763 else 01764 out << ' '; 01765 } 01766 } 01767 } 01768 01769 void DenseMatrix::TestInversion() 01770 { 01771 DenseMatrix copy(*this), C(size); 01772 Invert(); 01773 ::Mult(*this, copy, C); 01774 01775 double i_max = 0.; 01776 for (int j = 0; j < size; j++) 01777 for (int i = 0; i < size; i++) 01778 { 01779 if (i == j) 01780 C(i,j) -= 1.; 01781 i_max = fmax(i_max, fabs(C(i, j))); 01782 } 01783 cout << "size = " << size << ", i_max = " << i_max 01784 << ", cond_F = " << FNorm()*copy.FNorm() << endl; 01785 } 01786 01787 DenseMatrix::~DenseMatrix() 01788 { 01789 if (data != NULL) 01790 delete [] data; 01791 } 01792 01793 01794 01795 void Add(const DenseMatrix &A, const DenseMatrix &B, 01796 double alpha, DenseMatrix &C) 01797 { 01798 for (int i = 0; i < C.Height(); i++) 01799 for (int j = 0; j < C.Size(); j++) 01800 C(i,j) = A(i,j) + alpha * B(i,j); 01801 } 01802 01803 01804 void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a) 01805 { 01806 #ifdef MFEM_DEBUG 01807 if (a.height != b.height || a.size != c.size || b.size != c.height) 01808 mfem_error("Mult (product of DenseMatrices)"); 01809 #endif 01810 01811 register int ah = a.height; 01812 register int as = a.size; 01813 register int bs = b.size; 01814 register double *ad = a.data; 01815 register double *bd = b.data; 01816 register double *cd = c.data; 01817 register int i, j, k; 01818 register double d, *bdd, *cdd; 01819 01820 for (j = 0; j < as; j++, cd += bs) 01821 { 01822 for (i = 0; i < ah; i++, ad++) 01823 { 01824 d = 0.0; 01825 bdd = bd+i; 01826 cdd = cd; 01827 for (k = 0 ; k < bs; k++) 01828 { 01829 d += (*bdd) * (*cdd); 01830 cdd++; 01831 bdd += ah; 01832 } 01833 *ad = d; 01834 } 01835 } 01836 } 01837 01838 void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja) 01839 { 01840 #ifdef MFEM_DEBUG 01841 if (a.Height() != a.Size() || adja.Height() != adja.Size() || 01842 a.Size() != adja.Size() || a.Size() < 2 || a.Size() > 3) 01843 mfem_error("DenseMatrix::CalcAdjugate(...)"); 01844 #endif 01845 if (a.Size() == 2) 01846 { 01847 adja(0,0) = a(1,1); 01848 adja(0,1) = -a(0,1); 01849 adja(1,0) = -a(1,0); 01850 adja(1,1) = a(0,0); 01851 } 01852 else 01853 { 01854 adja(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1); 01855 adja(0,1) = a(0,2)*a(2,1)-a(0,1)*a(2,2); 01856 adja(0,2) = a(0,1)*a(1,2)-a(0,2)*a(1,1); 01857 01858 adja(1,0) = a(1,2)*a(2,0)-a(1,0)*a(2,2); 01859 adja(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0); 01860 adja(1,2) = a(0,2)*a(1,0)-a(0,0)*a(1,2); 01861 01862 adja(2,0) = a(1,0)*a(2,1)-a(1,1)*a(2,0); 01863 adja(2,1) = a(0,1)*a(2,0)-a(0,0)*a(2,1); 01864 adja(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0); 01865 } 01866 } 01867 01868 void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat) 01869 { 01870 #ifdef MFEM_DEBUG 01871 if (a.Height() != a.Size() || adjat.Height() != adjat.Size() || 01872 a.Size() != adjat.Size() || a.Size() < 2 || a.Size() > 3) 01873 mfem_error("DenseMatrix::CalcAdjugateTranspose(...)"); 01874 #endif 01875 if (a.Size() == 2) 01876 { 01877 adjat(0,0) = a(1,1); 01878 adjat(1,0) = -a(0,1); 01879 adjat(0,1) = -a(1,0); 01880 adjat(1,1) = a(0,0); 01881 } 01882 else 01883 { 01884 adjat(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1); 01885 adjat(1,0) = a(0,2)*a(2,1)-a(0,1)*a(2,2); 01886 adjat(2,0) = a(0,1)*a(1,2)-a(0,2)*a(1,1); 01887 01888 adjat(0,1) = a(1,2)*a(2,0)-a(1,0)*a(2,2); 01889 adjat(1,1) = a(0,0)*a(2,2)-a(0,2)*a(2,0); 01890 adjat(2,1) = a(0,2)*a(1,0)-a(0,0)*a(1,2); 01891 01892 adjat(0,2) = a(1,0)*a(2,1)-a(1,1)*a(2,0); 01893 adjat(1,2) = a(0,1)*a(2,0)-a(0,0)*a(2,1); 01894 adjat(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0); 01895 } 01896 } 01897 01898 void CalcInverse(const DenseMatrix &a, DenseMatrix &inva) 01899 { 01900 #ifdef MFEM_DEBUG 01901 if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 3) 01902 mfem_error("DenseMatrix::CalcInverse(...)"); 01903 #endif 01904 01905 double t; 01906 01907 if (a.Width() < a.Height()) 01908 { 01909 const double *d = a.Data(); 01910 double *id = inva.Data(); 01911 if (a.Height() == 2) 01912 { 01913 t = 1.0 / (d[0]*d[0] + d[1]*d[1]); 01914 id[0] = d[0] * t; 01915 id[1] = d[1] * t; 01916 } 01917 else 01918 { 01919 if (a.Width() == 1) 01920 { 01921 t = 1.0 / (d[0]*d[0] + d[1]*d[1] + d[2]*d[2]); 01922 id[0] = d[0] * t; 01923 id[1] = d[1] * t; 01924 id[2] = d[2] * t; 01925 } 01926 else 01927 { 01928 double e, g, f; 01929 e = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; 01930 g = d[3]*d[3] + d[4]*d[4] + d[5]*d[5]; 01931 f = d[0]*d[3] + d[1]*d[4] + d[2]*d[5]; 01932 t = 1.0 / (e*g - f*f); 01933 e *= t; g *= t; f *= t; 01934 01935 id[0] = d[0]*g - d[3]*f; 01936 id[1] = d[3]*e - d[0]*f; 01937 id[2] = d[1]*g - d[4]*f; 01938 id[3] = d[4]*e - d[1]*f; 01939 id[4] = d[2]*g - d[5]*f; 01940 id[5] = d[5]*e - d[2]*f; 01941 } 01942 } 01943 return; 01944 } 01945 01946 #ifdef MFEM_DEBUG 01947 t = a.Det(); 01948 if (fabs(t) < 1.0e-12 * a.FNorm()) 01949 cerr << "DenseMatrix::CalcInverse(...) : singular matrix!" 01950 << endl; 01951 t = 1. / t; 01952 #else 01953 t = 1.0 / a.Det(); 01954 #endif 01955 01956 switch (a.Height()) 01957 { 01958 case 1: 01959 inva(0,0) = t; 01960 break; 01961 case 2: 01962 inva(0,0) = a(1,1) * t ; 01963 inva(0,1) = -a(0,1) * t ; 01964 inva(1,0) = -a(1,0) * t ; 01965 inva(1,1) = a(0,0) * t ; 01966 break; 01967 case 3: 01968 inva(0,0) = (a(1,1)*a(2,2)-a(1,2)*a(2,1))*t; 01969 inva(0,1) = (a(0,2)*a(2,1)-a(0,1)*a(2,2))*t; 01970 inva(0,2) = (a(0,1)*a(1,2)-a(0,2)*a(1,1))*t; 01971 01972 inva(1,0) = (a(1,2)*a(2,0)-a(1,0)*a(2,2))*t; 01973 inva(1,1) = (a(0,0)*a(2,2)-a(0,2)*a(2,0))*t; 01974 inva(1,2) = (a(0,2)*a(1,0)-a(0,0)*a(1,2))*t; 01975 01976 inva(2,0) = (a(1,0)*a(2,1)-a(1,1)*a(2,0))*t; 01977 inva(2,1) = (a(0,1)*a(2,0)-a(0,0)*a(2,1))*t; 01978 inva(2,2) = (a(0,0)*a(1,1)-a(0,1)*a(1,0))*t; 01979 break; 01980 } 01981 } 01982 01983 void CalcInverseTranspose(const DenseMatrix &a, DenseMatrix &inva) 01984 { 01985 #ifdef MFEM_DEBUG 01986 if ( (a.Size() != a.Height()) || ( (a.Height()!= 1) && (a.Height()!= 2) 01987 && (a.Height()!= 3) ) ) 01988 mfem_error("DenseMatrix::CalcInverse(...)"); 01989 #endif 01990 01991 double t = 1. / a.Det() ; 01992 01993 switch (a.Height()) 01994 { 01995 case 1: 01996 inva(0,0) = 1.0 / a(0,0); 01997 break; 01998 case 2: 01999 inva(0,0) = a(1,1) * t ; 02000 inva(1,0) = -a(0,1) * t ; 02001 inva(0,1) = -a(1,0) * t ; 02002 inva(1,1) = a(0,0) * t ; 02003 break; 02004 case 3: 02005 inva(0,0) = (a(1,1)*a(2,2)-a(1,2)*a(2,1))*t; 02006 inva(1,0) = (a(0,2)*a(2,1)-a(0,1)*a(2,2))*t; 02007 inva(2,0) = (a(0,1)*a(1,2)-a(0,2)*a(1,1))*t; 02008 02009 inva(0,1) = (a(1,2)*a(2,0)-a(1,0)*a(2,2))*t; 02010 inva(1,1) = (a(0,0)*a(2,2)-a(0,2)*a(2,0))*t; 02011 inva(2,1) = (a(0,2)*a(1,0)-a(0,0)*a(1,2))*t; 02012 02013 inva(0,2) = (a(1,0)*a(2,1)-a(1,1)*a(2,0))*t; 02014 inva(1,2) = (a(0,1)*a(2,0)-a(0,0)*a(2,1))*t; 02015 inva(2,2) = (a(0,0)*a(1,1)-a(0,1)*a(1,0))*t; 02016 break; 02017 } 02018 } 02019 02020 void MultAAt(const DenseMatrix &a, DenseMatrix &aat) 02021 { 02022 for (int i = 0; i < a.Height(); i++) 02023 for (int j = 0; j <= i; j++) 02024 { 02025 double temp = 0.; 02026 for (int k = 0; k < a.Size(); k++) 02027 temp += a(i,k) * a(j,k); 02028 aat(j,i) = aat(i,j) = temp; 02029 } 02030 } 02031 02032 void AddMultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt) 02033 { 02034 for (int i = 0; i < A.Height(); i++) 02035 { 02036 for (int j = 0; j < i; j++) 02037 { 02038 double t = 0.; 02039 for (int k = 0; k < A.Width(); k++) 02040 t += D(k) * A(i, k) * A(j, k); 02041 ADAt(i, j) += t; 02042 ADAt(j, i) += t; 02043 } 02044 } 02045 02046 // process diagonal 02047 for (int i = 0; i < A.Height(); i++) 02048 { 02049 double t = 0.; 02050 for (int k = 0; k < A.Width(); k++) 02051 t += D(k) * A(i, k) * A(i, k); 02052 ADAt(i, i) += t; 02053 } 02054 } 02055 02056 void MultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt) 02057 { 02058 for (int i = 0; i < A.Height(); i++) 02059 { 02060 for (int j = 0; j <= i; j++) 02061 { 02062 double t = 0.; 02063 for (int k = 0; k < A.Width(); k++) 02064 t += D(k) * A(i, k) * A(j, k); 02065 ADAt(j, i) = ADAt(i, j) = t; 02066 } 02067 } 02068 } 02069 02070 #ifdef MFEM_USE_LAPACK 02071 extern "C" void 02072 dgemm_(char *, char *, int *, int *, int *, double *, double *, 02073 int *, double *, int *, double *, double *, int *); 02074 #endif 02075 02076 void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt) 02077 { 02078 #ifdef MFEM_DEBUG 02079 if (A.Height() != ABt.Height() || B.Height() != ABt.Width() || 02080 A.Width() != B.Width()) 02081 mfem_error("MultABt(...)"); 02082 #endif 02083 02084 #ifdef MFEM_USE_LAPACK 02085 static char transa = 'N', transb = 'T'; 02086 static double alpha = 1.0, beta = 0.0; 02087 int m = A.Height(), n = B.Height(), k = A.Width(); 02088 02089 dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m, 02090 B.Data(), &n, &beta, ABt.Data(), &m); 02091 #elif 1 02092 register const int ah = A.Height(); 02093 register const int bh = B.Height(); 02094 register const int aw = A.Width(); 02095 register const double *ad = A.Data(); 02096 register const double *bd = B.Data(); 02097 register double *cd = ABt.Data(); 02098 register double *cp; 02099 02100 cp = cd; 02101 for (register int i = 0, s = ah*bh; i < s; i++) 02102 *(cp++) = 0.0; 02103 for (register int k = 0; k < aw; k++) 02104 { 02105 cp = cd; 02106 for (register int j = 0; j < bh; j++) 02107 { 02108 register const double bjk = bd[j]; 02109 for (register int i = 0; i < ah; i++) 02110 { 02111 *(cp++) += ad[i] * bjk; 02112 } 02113 } 02114 ad += ah; 02115 bd += bh; 02116 } 02117 #elif 1 02118 register const int ah = A.Height(); 02119 register const int bh = B.Height(); 02120 register const int aw = A.Width(); 02121 register const double *ad = A.Data(); 02122 register const double *bd = B.Data(); 02123 register double *cd = ABt.Data(); 02124 02125 for (register int j = 0; j < bh; j++) 02126 for (register int i = 0; i < ah; i++) 02127 { 02128 register double d = 0.0; 02129 register const double *ap = ad + i; 02130 register const double *bp = bd + j; 02131 for (register int k = 0; k < aw; k++) 02132 { 02133 d += (*ap) * (*bp); 02134 ap += ah; 02135 bp += bh; 02136 } 02137 *(cd++) = d; 02138 } 02139 #else 02140 int i, j, k; 02141 double d; 02142 02143 for (i = 0; i < A.Height(); i++) 02144 for (j = 0; j < B.Height(); j++) 02145 { 02146 d = 0.0; 02147 for (k = 0; k < A.Width(); k++) 02148 d += A(i, k) * B(j, k); 02149 ABt(i, j) = d; 02150 } 02151 #endif 02152 } 02153 02154 void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt) 02155 { 02156 int i, j, k; 02157 double d; 02158 02159 #ifdef MFEM_DEBUG 02160 if (A.Height() != ABt.Height() || B.Height() != ABt.Width()) 02161 mfem_error("AddMultABt(...)"); 02162 #endif 02163 02164 for (i = 0; i < A.Height(); i++) 02165 for (j = 0; j < B.Height(); j++) 02166 { 02167 d = 0.0; 02168 for (k = 0; k < A.Width(); k++) 02169 d += A(i, k) * B(j, k); 02170 ABt(i, j) += d; 02171 } 02172 } 02173 02174 void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB) 02175 { 02176 #ifdef MFEM_DEBUG 02177 if (A.Width() != AtB.Height() || B.Width() != AtB.Width() || 02178 A.Height() != B.Height()) 02179 mfem_error("MultAtB(...)"); 02180 #endif 02181 02182 #ifdef MFEM_USE_LAPACK 02183 static char transa = 'T', transb = 'N'; 02184 static double alpha = 1.0, beta = 0.0; 02185 int m = A.Width(), n = B.Width(), k = A.Height(); 02186 02187 dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k, 02188 B.Data(), &k, &beta, AtB.Data(), &m); 02189 #elif 1 02190 register const int ah = A.Height(); 02191 register const int aw = A.Width(); 02192 register const int bw = B.Width(); 02193 register const double *ad = A.Data(); 02194 register const double *bd = B.Data(); 02195 register double *cd = AtB.Data(); 02196 02197 for (register int j = 0; j < bw; j++) 02198 { 02199 register const double *ap = ad; 02200 for (register int i = 0; i < aw; i++) 02201 { 02202 register double d = 0.0; 02203 for (register int k = 0; k < ah; k++) 02204 { 02205 d += *(ap++) * bd[k]; 02206 } 02207 *(cd++) = d; 02208 } 02209 bd += ah; 02210 } 02211 #else 02212 int i, j, k; 02213 double d; 02214 02215 for (i = 0; i < A.Size(); i++) 02216 for (j = 0; j < B.Size(); j++) 02217 { 02218 d = 0.0; 02219 for (k = 0; k < A.Height(); k++) 02220 d += A(k, i) * B(k, j); 02221 AtB(i, j) = d; 02222 } 02223 #endif 02224 } 02225 02226 void AddMult_a_AAt(double a, const DenseMatrix &A, DenseMatrix &AAt) 02227 { 02228 double d; 02229 02230 for (int i = 0; i < A.Height(); i++) 02231 { 02232 for (int j = 0; j < i; j++) 02233 { 02234 d = 0.; 02235 for (int k = 0; k < A.Width(); k++) 02236 d += A(i,k) * A(j,k); 02237 AAt(i, j) += (d *= a); 02238 AAt(j, i) += d; 02239 } 02240 d = 0.; 02241 for (int k = 0; k < A.Width(); k++) 02242 d += A(i,k) * A(i,k); 02243 AAt(i, i) += a * d; 02244 } 02245 } 02246 02247 void Mult_a_AAt(double a, const DenseMatrix &A, DenseMatrix &AAt) 02248 { 02249 for (int i = 0; i < A.Height(); i++) 02250 for (int j = 0; j <= i; j++) 02251 { 02252 double d = 0.; 02253 for (int k = 0; k < A.Width(); k++) 02254 d += A(i,k) * A(j,k); 02255 AAt(i, j) = AAt(j, i) = a * d; 02256 } 02257 } 02258 02259 void MultVVt(const Vector &v, DenseMatrix &vvt) 02260 { 02261 for (int i = 0; i < v.Size(); i++) 02262 for (int j = 0; j <= i; j++) 02263 { 02264 vvt(i,j) = vvt(j,i) = v(i) * v(j); 02265 } 02266 } 02267 02268 void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt) 02269 { 02270 int i, j; 02271 double vi; 02272 02273 #ifdef MFEM_DEBUG 02274 if (v.Size() != VWt.Height() || w.Size() != VWt.Size()) 02275 mfem_error("MultVWt(...)"); 02276 #endif 02277 02278 for (i = 0; i < v.Size(); i++) 02279 { 02280 vi = v(i); 02281 for (j = 0; j < w.Size(); j++) 02282 VWt(i, j) = vi * w(j); 02283 } 02284 } 02285 02286 void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt) 02287 { 02288 int m = v.Size(), n = w.Size(); 02289 02290 #ifdef MFEM_DEBUG 02291 if (VWt.Height() != m || VWt.Width() != n) 02292 mfem_error("AddMultVWt(...)"); 02293 #endif 02294 02295 for (int i = 0; i < m; i++) 02296 { 02297 double vi = v(i); 02298 for (int j = 0; j < n; j++) 02299 VWt(i, j) += vi * w(j); 02300 } 02301 } 02302 02303 void AddMult_a_VVt(const double a, const Vector &v, DenseMatrix &VVt) 02304 { 02305 int n = v.Size(); 02306 02307 #ifdef MFEM_DEBUG 02308 if (VVt.Height() != n || VVt.Width() != n) 02309 mfem_error("AddMult_a_VVt(...)"); 02310 #endif 02311 02312 for (int i = 0; i < n; i++) 02313 { 02314 double avi = a * v(i); 02315 for (int j = 0; j < i; j++) 02316 { 02317 double avivj = avi * v(j); 02318 VVt(i, j) += avivj; 02319 VVt(j, i) += avivj; 02320 } 02321 VVt(i, i) += avi * v(i); 02322 } 02323 } 02324 02325 02326 DenseMatrixInverse::DenseMatrixInverse(const DenseMatrix &mat) 02327 : MatrixInverse(mat) 02328 { 02329 data = new double[size*size]; 02330 #ifdef MFEM_USE_LAPACK 02331 ipiv = new int[size]; 02332 #endif 02333 Factor(); 02334 } 02335 02336 DenseMatrixInverse::DenseMatrixInverse(const DenseMatrix *mat) 02337 : MatrixInverse(*mat) 02338 { 02339 data = new double[size*size]; 02340 #ifdef MFEM_USE_LAPACK 02341 ipiv = new int[size]; 02342 #endif 02343 } 02344 02345 void DenseMatrixInverse::Factor() 02346 { 02347 const double *adata = ((const DenseMatrix *)a)->data; 02348 02349 #ifdef MFEM_USE_LAPACK 02350 for (int i = 0; i < size*size; i++) 02351 data[i] = adata[i]; 02352 02353 int info; 02354 dgetrf_(&size, &size, data, &size, ipiv, &info); 02355 02356 if (info) 02357 mfem_error("DenseMatrixInverse::Factor : Error in DGETRF"); 02358 #else 02359 // compiling without LAPACK 02360 int i, j, k; 02361 02362 // perform LU factorization. 02363 for (i = 0; i < size; i++) 02364 { 02365 #ifdef MFEM_DEBUG 02366 if (i > 0 && data[i-1+size*(i-1)] == 0.0) 02367 mfem_error("DenseMatrixInverse::Factor()"); 02368 #endif 02369 for (j = 0; j < i; j++) 02370 { 02371 data[i+size*j] = adata[i+size*j]; 02372 for (k = 0; k < j; k++) 02373 data[i+size*j] -= data[i+size*k] * data[k+size*j]; 02374 data[i+size*j] /= data[j+size*j]; 02375 } 02376 02377 for (j = i; j < size; j++) 02378 { 02379 data[i+size*j] = adata[i+size*j]; 02380 for (k = 0; k < i; k++) 02381 data[i+size*j] -= data[i+size*k] * data[k+size*j]; 02382 } 02383 } 02384 #endif 02385 } 02386 02387 void DenseMatrixInverse::Factor(const DenseMatrix &mat) 02388 { 02389 #ifdef MFEM_DEBUG 02390 if (mat.height != mat.size) 02391 mfem_error("DenseMatrixInverse::Factor #1"); 02392 if (size != mat.size) 02393 mfem_error("DenseMatrixInverse::Factor #2"); 02394 #endif 02395 a = &mat; 02396 02397 Factor(); 02398 } 02399 02400 void DenseMatrixInverse::Mult(const Vector &x, Vector &y) const 02401 { 02402 #ifdef MFEM_USE_LAPACK 02403 char trans = 'N'; 02404 int n = size; 02405 int nrhs = 1; 02406 int info; 02407 y = x; 02408 dgetrs_(&trans, &n, &nrhs, data, &n, ipiv, y.GetData(), &n, &info); 02409 02410 if (info) 02411 mfem_error("DenseMatrixInverse::Mult #1"); 02412 #else 02413 // compiling without LAPACK 02414 int i, j; 02415 02416 // y <- L^{-1} x 02417 for (i = 0; i < size; i++) 02418 { 02419 y(i) = x(i); 02420 for (j = 0; j < i; j++) 02421 y(i) -= data[i+size*j] * y(j); 02422 } 02423 02424 // y <- U^{-1} y 02425 for (i = size-1; i >= 0; i--) 02426 { 02427 for (j = i+1; j < size; j++) 02428 y(i) -= data[i+size*j] * y(j); 02429 #ifdef MFEM_DEBUG 02430 if ((data[i+size*i]) == 0.0) 02431 mfem_error("DenseMatrixInverse::Mult #2"); 02432 #endif 02433 y(i) /= data[i+size*i]; 02434 } 02435 #endif 02436 } 02437 02438 DenseMatrixInverse::~DenseMatrixInverse() 02439 { 02440 delete [] data; 02441 #ifdef MFEM_USE_LAPACK 02442 delete [] ipiv; 02443 #endif 02444 } 02445 02446 02447 DenseMatrixEigensystem::DenseMatrixEigensystem(DenseMatrix &m) 02448 : mat(m) 02449 { 02450 n = m.Size(); 02451 EVal.SetSize(n); 02452 EVect.SetSize(n); 02453 ev.SetDataAndSize(NULL, n); 02454 jobz = 'V'; 02455 uplo = 'U'; 02456 02457 #ifdef MFEM_USE_LAPACK 02458 lwork = -1; 02459 double qwork; 02460 dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(), 02461 &qwork, &lwork, &info); 02462 02463 lwork = (int) qwork; 02464 work = new double[lwork]; 02465 #endif 02466 } 02467 02468 void DenseMatrixEigensystem::Eval() 02469 { 02470 #ifdef MFEM_DEBUG 02471 if (mat.Size() != n) 02472 mfem_error("DenseMatrixEigensystem::Eval()"); 02473 #endif 02474 02475 #ifdef MFEM_USE_LAPACK 02476 EVect = mat; 02477 dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(), 02478 work, &lwork, &info); 02479 02480 if (info != 0) 02481 { 02482 cerr << "DenseMatrixEigensystem::Eval(): DSYEV error code: " 02483 << info << endl; 02484 mfem_error(); 02485 } 02486 #else 02487 mfem_error("DenseMatrixEigensystem::Eval(): Compiled without LAPACK"); 02488 #endif 02489 } 02490 02491 DenseMatrixEigensystem::~DenseMatrixEigensystem() 02492 { 02493 delete [] work; 02494 } 02495 02496 02497 DenseMatrixSVD::DenseMatrixSVD(DenseMatrix &M) 02498 { 02499 m = M.Height(); 02500 n = M.Width(); 02501 Init(); 02502 } 02503 02504 DenseMatrixSVD::DenseMatrixSVD(int h, int w) 02505 { 02506 m = h; 02507 n = w; 02508 Init(); 02509 } 02510 02511 void DenseMatrixSVD::Init() 02512 { 02513 #ifdef MFEM_USE_LAPACK 02514 sv.SetSize(min(m, n)); 02515 02516 jobu = 'N'; 02517 jobvt = 'N'; 02518 02519 double qwork; 02520 lwork = -1; 02521 dgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m, 02522 NULL, &n, &qwork, &lwork, &info); 02523 02524 lwork = (int) qwork; 02525 work = new double[lwork]; 02526 #else 02527 work = NULL; 02528 mfem_error("DenseMatrixSVD::Init(): Compiled without LAPACK"); 02529 #endif 02530 } 02531 02532 void DenseMatrixSVD::Eval(DenseMatrix &M) 02533 { 02534 #ifdef MFEM_DEBUG 02535 if (M.Height() != m || M.Width() != n) 02536 mfem_error("DenseMatrixSVD::Eval()"); 02537 #endif 02538 02539 #ifdef MFEM_USE_LAPACK 02540 dgesvd_(&jobu, &jobvt, &m, &n, M.Data(), &m, sv.GetData(), NULL, &m, 02541 NULL, &n, work, &lwork, &info); 02542 02543 if (info) 02544 { 02545 cerr << "DenseMatrixSVD::Eval() : info = " << info << endl; 02546 mfem_error(); 02547 } 02548 #else 02549 mfem_error("DenseMatrixSVD::Eval(): Compiled without LAPACK"); 02550 #endif 02551 } 02552 02553 DenseMatrixSVD::~DenseMatrixSVD() 02554 { 02555 delete [] work; 02556 }