library of assembled shared sources

http://lass.cocamware.com

matrix_solve.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_IMPL_MATRIX_SOLVE_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_NUM_IMPL_MATRIX_SOLVE_INL
00047 
00048 #include "../num_common.h"
00049 #include "matrix_solve.h"
00050 
00051 namespace lass
00052 {
00053 namespace num
00054 {
00055 namespace impl
00056 {
00057 
00058 /** Given a complex matrix iA, this routine replaces it by the LU decomposition
00059  *  of a rowwise permutation of itself.
00060  *  @param ioMatrix [in,out]
00061  *      @arg Random iterator to first element of of a @e square matrix in row major order.
00062  *      @arg ioMatrix is replaced by its LU decomposition.
00063  *      @arg [ioMatrix, ioMatrix + iSize * iSize) must be a valid range
00064  *  @param oIndex [out]
00065  *      @arg records the row permutations effected by the partial pivoting.
00066  *      @arg [oIndex, oIndex + iSize) must be a valid range.
00067  *  @param iSize [in]
00068  *      @arg size of matrix
00069  *  @param oD [out]
00070  *      @arg indicates the number of row interchanges was even (+1) or odd (-1).
00071  *  @return - true: LU decomposition completed
00072  *          - false: matrix ioMatrix is singular
00073  *
00074  *  This routine is used in combination with lusolve() to solve linear
00075  *  equations and lumprove() to improve the solution.
00076  *
00077  *  Method: Crout's algorithm with partial pivoting.
00078  */
00079 template 
00080 <
00081     typename T, 
00082     typename RandomIterator1, 
00083     typename RandomIterator2
00084 >
00085 bool ludecomp(RandomIterator1 ioMatrix,
00086               RandomIterator2 oIndex,
00087               size_t iSize,
00088               int& iD)
00089 {
00090     typedef NumTraits<T> TNumTraits;
00091     typedef typename TNumTraits::baseType TBase;
00092     typedef NumTraits<TBase> TBaseTraits;
00093 
00094     const TBase epsilon = static_cast<TBase>(1e-20);
00095 
00096     std::vector<T> vv(iSize);
00097     iD = 1;
00098 
00099     for (size_t i = 0; i < iSize; ++i)
00100     {
00101         RandomIterator1 rowI = ioMatrix + (i * iSize);
00102         TBase normMax = TBaseTraits::zero;
00103         size_t jMax = iSize;
00104         for (size_t j = 0; j < iSize; ++j)
00105         {
00106             const TBase temp = num::norm(rowI[j]);
00107             if (temp > normMax)
00108             {
00109                 normMax = temp;
00110                 jMax = j;
00111             }
00112         }
00113         if (normMax == TBaseTraits::zero)
00114         {
00115             return false; // no decomposition
00116         }
00117         LASS_ASSERT(jMax != iSize);
00118 
00119         vv[i] = num::conj(rowI[jMax]) / normMax;
00120     }
00121 
00122     for (size_t j = 0; j < iSize; ++j)
00123     {
00124         size_t i;
00125         for (i = 0; i < j; ++i)
00126         {
00127             RandomIterator1 rowI = ioMatrix + (i * iSize);
00128             T sum = rowI[j];
00129             for (size_t k = 0; k < i; ++k)
00130             {
00131                 sum -= rowI[k] * ioMatrix[k * iSize + j];
00132             }
00133             rowI[j] = sum;
00134         }
00135 
00136         TBase normMax = TBaseTraits::zero;
00137         size_t iMax = iSize;
00138         for (i = j; i < iSize; ++i)
00139         {
00140             RandomIterator1 rowI = ioMatrix + (i * iSize);
00141             T sum = rowI[j];
00142             for (size_t k = 0; k < j; ++k)
00143             {
00144                 sum -= rowI[k] * ioMatrix[k * iSize + j];
00145             }
00146             rowI[j] = sum;
00147 
00148             const T dum = vv[i] * sum;
00149             const TBase temp = num::norm(dum);
00150             if (temp >= normMax)
00151             {
00152                normMax = temp;
00153                iMax = i;
00154             }
00155         }
00156         LASS_ASSERT(iMax != iSize);
00157 
00158         if (j != iMax)
00159         {
00160            for (size_t k = 0; k < iSize; ++k)
00161            {
00162                std::swap(ioMatrix[iMax * iSize + k], ioMatrix[j * iSize + k]);
00163            }
00164            iD = -iD;
00165            vv[iMax] = vv[j];
00166         }
00167         oIndex[j] = iMax;
00168 
00169         TBase temp = num::norm(ioMatrix[j * iSize + j]);
00170         if (temp == TBaseTraits::zero)
00171         {
00172             ioMatrix[j * iSize + j] = TNumTraits::one;//CT(T(1), T(1));
00173             temp = epsilon;
00174         }
00175 
00176         if (j != iSize - 1)
00177         {
00178             const T dum = num::conj(ioMatrix[j * iSize + j]) / temp;
00179             for (i = j + 1; i < iSize; ++i)
00180             {
00181                 ioMatrix[i * iSize + j] *= dum;
00182             }
00183         }
00184     }
00185 
00186     return true;
00187 }
00188 
00189 
00190 
00191 /** Solves the set of linear eqautions A X = B.
00192  *  @internal
00193  *  @param iMatrix [in] 
00194  *      @arg Random iterator to first element of A in row major order
00195  *      @arg A as LU decomposition.
00196  *      @arg A must be square.
00197  *      @arg [iMatrix, iMatrx + iSize * iSize) must be a valid range
00198  *  @param iIndex [in]  
00199  *      @arg permutation sequence filled by ludecomp().
00200  *      @arg [iIndex, iIndex + iSize) must be a valid range
00201  *  @param ioColumn [in,out]     
00202  *      @arg as input, it is the righthand side vector B.
00203  *      @arg as output it is the solution vector X.
00204  *      @arg must be of same length as iA
00205  *      @arg [ioColumn, ioColumn + iSize) must be a valid range
00206  *  @param iSize [in]
00207  *      @arg size of matrix
00208  *
00209  *  This routine can be used for successive calls with different right-hand
00210  *  sides B.
00211  *
00212  *  Method: backward and forward substitution, taking into account the leading
00213  *          zero's in B.
00214  */
00215 template 
00216 <
00217     typename T, 
00218     typename RandomIterator1, 
00219     typename RandomIterator2,
00220     typename RandomIterator3
00221 >
00222 void lusolve(RandomIterator1 iMatrix,
00223              RandomIterator2 iIndex,
00224              RandomIterator3 ioColumn,
00225              size_t iSize)
00226 {
00227     typedef NumTraits<T> TNumTraits;
00228 
00229     size_t ii = iSize;
00230     for (size_t i = 0; i < iSize; ++i)
00231     {
00232         RandomIterator1 rowI = iMatrix + (i * iSize);
00233         const size_t ip = iIndex[i];
00234         T sum = ioColumn[ip];
00235         ioColumn[ip] = ioColumn[i];
00236 
00237         if (ii != iSize)
00238         {
00239             for (size_t j = ii; j < i; ++j)
00240             {
00241                 sum -= rowI[j] * ioColumn[j];
00242             }
00243         }
00244         else
00245         {
00246             if (!(sum == TNumTraits::zero)) // BUG in STL???
00247             {
00248                 ii = i;
00249             }
00250         }
00251         ioColumn[i] = sum;
00252     }
00253 
00254     for (size_t ic = iSize; ic > 0; --ic)
00255     {
00256         const size_t i = ic - 1;
00257         RandomIterator1 rowI = iMatrix + (i * iSize);
00258         T sum = ioColumn[i];
00259         for (size_t j = ic; j < iSize; ++j)
00260         {
00261             sum -= rowI[j] * ioColumn[j];
00262         }
00263         ioColumn[i] = sum / rowI[i];
00264     }
00265 }
00266 
00267 
00268 
00269 /** Improves a solution vector X of the linear set of equations A X = B.
00270  *  @internal
00271  *  @param iMatrix [in]    
00272  *      @arg Random iterator to first element of matrix in row major order.
00273  *      @arg must be square.
00274  *      @arg [iMatrix, iMatrix + iSize * iSize) must be a valid range
00275  *  @param iMatrixLU [in]    
00276  *      @arg LU decompostion of A
00277  *      @arg must be square.
00278  *      @arg [iMatrixLU, iMatrixLU + iSize * iSize) must be a valid range
00279  *  @param iIndex [in]  
00280  *      @arg [iIndex, iIndex + iSize) must be a valid range
00281  *  @param iColumn [in]  
00282  *      @arg [iColumn, iColumn + iSize) must be a valid range
00283  *  @param ioX [in,out] 
00284  *      @arg [ioX, ioX + iSize) must be a valid range
00285  *  @param iSize [in]
00286  *      @arg size of matrix
00287  */
00288 template
00289 <
00290     typename T,
00291     typename RandomIterator1,
00292     typename RandomIterator2,
00293     typename RandomIterator3,
00294     typename RandomIterator4,
00295     typename RandomIterator5
00296 >
00297 void lumprove(RandomIterator1 iMatrix,
00298               RandomIterator2 iMatrixLU,
00299               RandomIterator3 iIndex,
00300               RandomIterator4 iColumn,
00301               RandomIterator5 ioX,
00302               size_t iSize)
00303 {
00304     typedef NumTraits<T> TNumTraits;
00305 
00306     std::vector<T> r(iSize);
00307     size_t i;
00308     for (i = 0; i < iSize; ++i)
00309     {
00310         RandomIterator1 rowI = iMatrix + (i * iSize);
00311         r[i] = -iColumn[i];
00312         for (size_t j = 0; j < iSize; ++j)
00313         {
00314             r[i] += rowI[j] * ioX[j];
00315         }
00316     }
00317 
00318     lusolve(iMatrixLU, iIndex, r.begin(), iSize);
00319 
00320     for (i = 0; i < iSize; ++i)
00321     {
00322         ioX[i] -= r[i];
00323     }
00324 }
00325 
00326 
00327 
00328 /** Solve A X = B for 2x2 matrices with Cramer's rule.
00329  *  @param iMatrix [in]    
00330  *      @arg Random iterator to first element of matrix A in row major order.
00331  *      @arg A must be of size 2x2.
00332  *      @arg [iMatrix, iMatrix + 4) must be a valid range
00333  *  @param ioColumn [in,out]
00334  *      @arg Random iterator to first element of B as input
00335  *      @arg Random iterator to first element of X as output
00336  *      @arg [iColumn, iColumn + 2) must be a valid range
00337  */
00338 template 
00339 <
00340     typename T,
00341     typename RandomIterator1,
00342     typename RandomIterator2
00343 > 
00344 bool cramer2(RandomIterator1 iMatrixRowMajor, 
00345              RandomIterator2 ioColumnFirst,
00346              RandomIterator2 ioColumnLast)
00347 {
00348     typedef NumTraits<T> TNumTraits;
00349     RandomIterator1 m = iMatrixRowMajor; // shortcut ;)
00350 
00351     const T determinant = m[0] * m[3] - m[1] * m[2];
00352 
00353     if (determinant == TNumTraits::zero)
00354     {
00355         return false;
00356     }
00357 
00358     const T inverseDeterminant = num::inv(determinant);
00359 
00360     for (RandomIterator2 column = ioColumnFirst; column != ioColumnLast; column += 2)
00361     {
00362         LASS_ASSERT(column + 1 != ioColumnLast);
00363         const T x = column[0];
00364         const T y = column[1];      
00365         column[0] = inverseDeterminant * (x * m[3] - y * m[2]);
00366         column[1] = inverseDeterminant * (m[0] * y - m[1] * x);
00367     }
00368     return true;
00369 }
00370 
00371 
00372 
00373 /** Solve A X = B for 3x3 matrices with Cramer's rule.
00374  *  @internal
00375  *  @param iMatrix [in]
00376  *      @arg Random iterator to first element of matrix A in row major order.
00377  *      @arg A must be of size 3x3.
00378  *      @arg [iMatrix, iMatrix + 9) must be a valid range
00379  *  @param ioColumn [in,out]
00380  *      @arg Random iterator to first element of B as input
00381  *      @arg Random iterator to first element of X as output
00382  *      @arg [iColumn, iColumn + 3) must be a valid range
00383  */
00384 template 
00385 <
00386     typename T,
00387     typename RandomIterator1,
00388     typename RandomIterator2
00389 > 
00390 bool cramer3(RandomIterator1 iMatrixRowMajor, 
00391              RandomIterator2 ioColumnFirst,
00392              RandomIterator2 ioColumnLast)
00393 {
00394     typedef NumTraits<T> TNumTraits;
00395     RandomIterator1 m = iMatrixRowMajor; // shortcut ;)
00396 
00397     const T determinant = 
00398         m[0] * (m[4] * m[8] - m[7] * m[5]) +
00399         m[3] * (m[7] * m[2] - m[1] * m[8]) +
00400         m[6] * (m[1] * m[5] - m[4] * m[2]);
00401     
00402     if (determinant == TNumTraits::zero)
00403     {
00404         return false;
00405     }
00406 
00407     const T inverseDeterminant = num::inv(determinant);
00408 
00409     for (RandomIterator2 column = ioColumnFirst; column != ioColumnLast; column += 3)
00410     {
00411         LASS_ASSERT(column + 1 != ioColumnLast && column + 2 != ioColumnLast);
00412         const T x = column[0];
00413         const T y = column[1];
00414         const T z = column[2];
00415         column[0] = inverseDeterminant * (
00416             x * (m[4] * m[8] - m[7] * m[5]) +
00417             y * (m[7] * m[2] - m[1] * m[8]) +
00418             z * (m[1] * m[5] - m[4] * m[2]));
00419         column[1] = inverseDeterminant * (
00420             m[0] * (y * m[8] - z * m[5]) +
00421             m[3] * (z * m[2] - x * m[8]) +
00422             m[6] * (x * m[5] - y * m[2]));
00423         column[2] = inverseDeterminant * (
00424             m[0] * (m[4] * z - m[7] * y) +
00425             m[3] * (m[7] * x - m[1] * z) +
00426             m[6] * (m[1] * y - m[4] * x));
00427     }
00428 
00429     return true;
00430 }
00431 
00432 
00433 
00434 /** Solve system of linear equations with a tridiagonal matrix.
00435  *  @internal
00436  *  @param iA [in]
00437  *      @arg Random iterator to first element of lower diagonal.
00438  *      @arg This is actually the matrix element in the "zeroth" column of the first row.
00439  *          So, iA[0] is being unused since it's not a valid matrix position.  The first
00440  *          valid element is iA[1]
00441  *      @arg [iA, iA + N) must be a valid range
00442  *  @param iB [in]
00443  *      @arg Random iterator to first element of main diagonal.
00444  *      @arg This is actually the matrix element in the first column of the first row.
00445  *      @arg [iB, iB + N) must be a valid range
00446  *  @param iC [in]
00447  *      @arg Random iterator to first element of upper diagonal.
00448  *      @arg This is actually the matrix element in the second column of the first row.
00449  *      @arg [iC, iC + N) must be a valid range
00450  *      @arg The last element iC[N - 1] isn't really a valid element since it's a position
00451  *          outside the matrix.
00452  */
00453 template 
00454 <
00455     typename T, 
00456     typename RandomIterator1, 
00457     typename RandomIterator2,
00458     typename RandomIterator3
00459 >
00460 bool solveTridiagonal(RandomIterator1 iA, RandomIterator1 iB, RandomIterator1 iC,
00461                       RandomIterator2 ioSolution, RandomIterator3 ioTemp,
00462                       std::size_t iSize)
00463 {
00464     typedef NumTraits<T> TNumTraits;
00465 
00466     T beta = iB[0];
00467     if (beta == TNumTraits::zero)
00468     {
00469         return false;
00470     }
00471     ioSolution[0] /= beta;
00472     for (std::size_t i = 1; i <iSize; ++i)
00473     {
00474         ioTemp[i] = iC[i - 1] / beta;
00475         beta = iB[i] - iA[i] * ioTemp[i];
00476         if (beta == TNumTraits::zero)
00477         {
00478             return false;
00479         }
00480         ioSolution[i] = (ioSolution[i] - iA[i] * ioSolution[i - 1]) / beta;
00481     }
00482     for (std::size_t i = iSize - 1; i > 0; --i)
00483     {
00484         ioSolution[i - 1] -= ioTemp[i] * ioSolution[i];
00485     }
00486     return true;
00487 }
00488 
00489 }
00490 
00491 }
00492 
00493 }
00494 
00495 #endif
00496 
00497 // EOF

Generated on Mon Nov 10 14:20:31 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo