MFEM v2.0
densemat.cpp
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines