Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

linear_sys.H

Go to the documentation of this file.
00001 #ifndef LINEAR_SYS_H_IS_INCLUDED
00002 #define LINEAR_SYS_H_IS_INCLUDED
00003 
00004 /*!
00005  *  \file linear_sys.H
00006  *  \brief Solution of systems of linear equations and eigenvalue decomposition.
00007  *  Some are patterned after the code in Numerical Recipes, but with a bit of
00008  *  the fancy C++ template thing happening.
00009  *
00010  *  \note This code is taken almost verbatim from the TriMesh2 library written by
00011  *  Szymon Rusinkiewicz of Princeton University
00012  *  (http://www.cs.princeton.edu/gfx/proj/trimesh2/).
00013  *
00014  */
00015 
00016 #include <cmath>
00017 #include <algorithm>
00018 
00019 namespace mlib {
00020 
00021 #ifndef likely
00022 #  if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
00023 #    define likely(x) (x)
00024 #    define unlikely(x) (x)
00025 #  else
00026 #    define likely(x)   (__builtin_expect((x), 1))
00027 #    define unlikely(x) (__builtin_expect((x), 0))
00028 #  endif
00029 #endif
00030 
00031 //! \brief LU decomposition.
00032 template <class T, int N>
00033 inline bool
00034 ludcmp(T a[N][N], int indx[N], T *d = NULL)
00035 {
00036    int i, j, k;
00037    T vv[N];
00038 
00039    if (d)
00040       *d = 1;
00041    for (i = 0; i < N; i++) {
00042       T big = 0.0;
00043       for (j = 0; j < N; j++) {
00044          T tmp = std::fabs(a[i][j]);
00045          if (tmp > big)
00046             big = tmp;
00047       }
00048       if (big == 0.0)
00049          return false;
00050       vv[i] = 1.0 / big;
00051    }
00052    for (j = 0; j < N; j++) {
00053       for (i = 0; i < j; i++) {
00054          T sum = a[i][j];
00055          for (k = 0; k < i; k++)
00056             sum -= a[i][k]*a[k][j];
00057          a[i][j]=sum;
00058       }
00059       T big = 0.0;
00060       int imax = j;
00061       for (i = j; i < N; i++) {
00062          T sum = a[i][j];
00063          for (k = 0; k < j; k++)
00064             sum -= a[i][k]*a[k][j];
00065          a[i][j] = sum;
00066          T tmp = vv[i] * std::fabs(sum);
00067          if (tmp > big) {
00068             big = tmp;
00069             imax = i;
00070          }
00071       }
00072       if (imax != j) {
00073          for (k = 0; k < N; k++)
00074             std::swap(a[imax][k], a[j][k]);
00075          if (d)
00076             *d = -(*d);
00077          vv[imax] = vv[j];
00078       }
00079       indx[j] = imax;
00080       if (a[j][j] == 0.0)
00081          return false;
00082       if (j != N-1) {
00083          T tmp = 1.0/(a[j][j]);
00084          for (i = j+1; i < N; i++)
00085             a[i][j] *= tmp;
00086       }
00087    }
00088    return true;
00089 }
00090 
00091 
00092 //! \brief Backsubstitution after ludcmp().
00093 template <class T, int N>
00094 inline void
00095 lubksb(T a[N][N], int indx[N], T b[N])
00096 {
00097    int ii = -1, i, j;
00098    for (i = 0; i < N; i++) {
00099       int ip = indx[i];
00100       T sum = b[ip];
00101       b[ip] = b[i];
00102       if (ii != -1)
00103          for (j = ii; j < i; j++)
00104             sum -= a[i][j] * b[j];
00105       else if (sum)
00106          ii = i;
00107       b[i] = sum;
00108    }
00109    for (i = N-1; i >= 0; i--) {
00110       T sum = b[i];
00111       for (j = i+1; j < N; j++)
00112          sum -= a[i][j] * b[j];
00113       b[i] = sum / a[i][i];
00114    }
00115 }
00116 
00117 
00118 //! \brief Perform LDL^T decomposition of a symmetric positive definite matrix.
00119 //! 
00120 //! Like Cholesky, but no square roots.  Overwrites lower triangle of matrix.
00121 template <class T, int N>
00122 inline bool
00123 ldltdc(T A[N][N], T rdiag[N])
00124 {
00125    T v[N-1];
00126    for (int i = 0; i < N; i++) {
00127       for (int k = 0; k < i; k++)
00128          v[k] = A[i][k] * rdiag[k];
00129       for (int j = i; j < N; j++) {
00130          T sum = A[i][j];
00131          for (int k = 0; k < i; k++)
00132             sum -= v[k] * A[j][k];
00133          if (i == j) {
00134             if (unlikely(sum <= T(0)))
00135                return false;
00136             rdiag[i] = T(1) / sum;
00137          } else {
00138             A[j][i] = sum;
00139          }
00140       }
00141    }
00142 
00143    return true;
00144 }
00145 
00146 
00147 //! \brief Solve Ax=B after ldltdc().
00148 template <class T, int N>
00149 inline void
00150 ldltsl(T A[N][N], T rdiag[N], T B[N], T x[N])
00151 {
00152    int i;
00153    for (i = 0; i < N; i++) {
00154       T sum = B[i];
00155       for (int k = 0; k < i; k++)
00156          sum -= A[i][k] * x[k];
00157       x[i] = sum * rdiag[i];
00158    }
00159    for (i = N - 1; i >= 0; i--) {
00160       T sum = 0;
00161       for (int k = i + 1; k < N; k++)
00162          sum += A[k][i] * x[k];
00163       x[i] -= sum * rdiag[i];
00164    }
00165 }
00166 
00167 
00168 //! \brief Eigenvector decomposition for real, symmetric matrices,
00169 //! a la Bowdler et al. / EISPACK / JAMA.
00170 //! 
00171 //! Entries of d are eigenvalues, sorted smallest to largest.
00172 //! A changed in-place to have its columns hold the corresponding eigenvectors.
00173 //! \note A must be completely filled in on input.
00174 template <int N, class T>
00175 inline void
00176 eigdc(T A[N][N], T d[N])
00177 {
00178    // Householder
00179    T e[N];
00180    for (int j = 0; j < N; j++) {
00181       d[j] = A[N-1][j];
00182       e[j] = 0.0;
00183    }
00184    for (int i = N-1; i > 0; i--) {
00185       T scale = 0.0;
00186       for (int k = 0; k < i; k++)
00187          scale += std::fabs(d[k]);
00188       if (scale == 0.0) {
00189          e[i] = d[i-1];
00190          for (int j = 0; j < i; j++) {
00191             d[j] = A[i-1][j];
00192             A[i][j] = A[j][i] = 0.0;
00193          }
00194          d[i] = 0.0;
00195       } else {
00196          T h = 0.0;
00197          T invscale = 1.0 / scale;
00198          for (int k = 0; k < i; k++) {
00199             d[k] *= invscale;
00200             h += sqr(d[k]);
00201          }
00202          T f = d[i-1];
00203          T g = (f > 0.0) ? -std::sqrt(h) : std::sqrt(h);
00204          e[i] = scale * g;
00205          h -= f * g;
00206          d[i-1] = f - g;
00207          for (int j = 0; j < i; j++)
00208             e[j] = 0.0;
00209          for (int j = 0; j < i; j++) {
00210             f = d[j];
00211             A[j][i] = f;
00212             g = e[j] + f * A[j][j];
00213             for (int k = j+1; k < i; k++) {
00214                g += A[k][j] * d[k];
00215                e[k] += A[k][j] * f;
00216             }
00217             e[j] = g;
00218          }
00219          f = 0.0;
00220          T invh = 1.0 / h;
00221          for (int j = 0; j < i; j++) {
00222             e[j] *= invh;
00223             f += e[j] * d[j];
00224          }
00225          T hh = f / (h + h);
00226          for (int j = 0; j < i; j++)
00227             e[j] -= hh * d[j];
00228          for (int j = 0; j < i; j++) {
00229             f = d[j];
00230             g = e[j];
00231             for (int k = j; k < i; k++)
00232                A[k][j] -= f * e[k] + g * d[k];
00233             d[j] = A[i-1][j];
00234             A[i][j] = 0.0;
00235          }
00236          d[i] = h;
00237       }
00238    }
00239 
00240    for (int i = 0; i < N-1; i++) {
00241       A[N-1][i] = A[i][i];
00242       A[i][i] = 1.0;
00243       T h = d[i+1];
00244       if (h != 0.0) {
00245          T invh = 1.0 / h;
00246          for (int k = 0; k <= i; k++)
00247             d[k] = A[k][i+1] * invh;
00248          for (int j = 0; j <= i; j++) {
00249             T g = 0.0;
00250             for (int k = 0; k <= i; k++)
00251                g += A[k][i+1] * A[k][j];
00252             for (int k = 0; k <= i; k++)
00253                A[k][j] -= g * d[k];
00254          }
00255       }
00256       for (int k = 0; k <= i; k++)
00257          A[k][i+1] = 0.0;
00258    }
00259    for (int j = 0; j < N; j++) {
00260       d[j] = A[N-1][j];
00261       A[N-1][j] = 0.0;
00262    }
00263    A[N-1][N-1] = 1.0;
00264 
00265    // QL
00266    for (int i = 1; i < N; i++)
00267       e[i-1] = e[i];
00268    e[N-1] = 0.0;
00269    T f = 0.0, tmp = 0.0;
00270    const T eps = pow(2.0, -52.0);
00271    for (int l = 0; l < N; l++) {
00272       tmp = std::max(tmp, std::fabs(d[l]) + std::fabs(e[l]));
00273       int m = l;
00274       while (m < N) {
00275          if (std::fabs(e[m]) <= eps * tmp)
00276             break;
00277          m++;
00278       }
00279       if (m > l) {
00280          do {
00281             T g = d[l];
00282             T p = (d[l+1] - g) / (e[l] + e[l]);
00283             T r = hypot(p, 1.0);
00284             if (p < 0.0)
00285                r = -r;
00286             d[l] = e[l] / (p + r);
00287             d[l+1] = e[l] * (p + r);
00288             T dl1 = d[l+1];
00289             T h = g - d[l];
00290             for (int i = l+2; i < N; i++)
00291                d[i] -= h; 
00292             f += h;
00293             p = d[m];   
00294             T c = 1.0, c2 = 1.0, c3 = 1.0;
00295             T el1 = e[l+1], s = 0.0, s2 = 0.0;
00296             for (int i = m - 1; i >= l; i--) {
00297                c3 = c2;
00298                c2 = c;
00299                s2 = s;
00300                g = c * e[i];
00301                h = c * p;
00302                r = hypot(p, e[i]);
00303                e[i+1] = s * r;
00304                s = e[i] / r;
00305                c = p / r;
00306                p = c * d[i] - s * g;
00307                d[i+1] = h + s * (c * g + s * d[i]);
00308                for (int k = 0; k < N; k++) {
00309                   h = A[k][i+1];
00310                   A[k][i+1] = s * A[k][i] + c * h;
00311                   A[k][i] = c * A[k][i] - s * h;
00312                }
00313             }
00314             p = -s * s2 * c3 * el1 * e[l] / dl1;
00315             e[l] = s * p;
00316             d[l] = c * p;
00317          } while (std::fabs(e[l]) > eps * tmp);
00318       }
00319       d[l] += f;
00320       e[l] = 0.0;
00321    }
00322 
00323    // Sort
00324    for (int i = 0; i < N-1; i++) {
00325       int k = i;
00326       T p = d[i];
00327       for (int j = i+1; j < N; j++) {
00328          if (d[j] < p) {
00329             k = j;
00330             p = d[j];
00331          }
00332       }
00333       if (k == i)
00334          continue;
00335       d[k] = d[i];
00336       d[i] = p;
00337       for (int j = 0; j < N; j++) {
00338          p = A[j][i];
00339          A[j][i] = A[j][k];
00340          A[j][k] = p;
00341       }
00342    }
00343 }
00344 
00345 
00346 //! \brief x <- A * d * A' * b
00347 template <int N, class T>
00348 inline void
00349 eigmult(T A[N][N], T d[N], T b[N], T x[N])
00350 {
00351    T e[N];
00352    for (int i = 0; i < N; i++) {
00353       e[i] = 0.0;
00354       for (int j = 0; j < N; j++)
00355          e[i] += A[j][i] * b[j];
00356       e[i] *= d[i];
00357    }
00358    for (int i = 0; i < N; i++) {
00359       x[i] = 0.0;
00360       for (int j = 0; j < N; j++)
00361          x[i] += A[i][j] * e[j];
00362    }
00363 }
00364 
00365 } // namespace mlib
00366 
00367 #endif // LINEAR_SYS_H_IS_INCLUDED

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4