MatrixFunctions.h

Go to the documentation of this file.
00001 /*
00002  * The information in this file is
00003  * Copyright(c) 2007 Ball Aerospace & Technologies Corporation
00004  * and is subject to the terms and conditions of the
00005  * GNU Lesser General Public License Version 2.1
00006  * The license text is available from   
00007  * http://www.gnu.org/licenses/lgpl.html
00008  */
00009 
00010 #ifndef MATRIXFUNCTIONS_H
00011 #define MATRIXFUNCTIONS_H
00012 
00013 #include "Resource.h"
00014 
00015 #include <exception>
00016 #include <math.h>
00017 #include <memory>
00018 #include <string.h>
00019 
00020 class RasterElement;
00021 
00022 /**
00023  * A collection of matrix functions.
00024  */
00025 namespace MatrixFunctions
00026 {
00027    //forward declarations only, see below for actual function definition
00028    template<typename T> T** createMatrix(const int& numRows, const int& numCols, const T* pInitialData = NULL);
00029    template<typename T> bool deleteMatrix(T**& pMatrix);
00030 
00031    /**
00032     * The %MatrixObject is a trait object for use with the %Resource template. 
00033     *
00034     * The %MatrixObject is a trait object for use with the %Resource template.
00035     * It provides capability for creating and destroying two-dimensional matrices.
00036     * 
00037     * @see MatrixResource
00038     */
00039    template<typename T>
00040    class MatrixObject
00041    {
00042    public:
00043       /**
00044       * This is an implementation detail of the %MatrixObject class. 
00045       *
00046       * This is an implementation detail of the MatrixObject class. It is used 
00047       * for passing the parameters required by createMatrix.
00048       */
00049       class Args
00050       {
00051       public:
00052          const int mNumRows;
00053          const int mNumCols;
00054          const T* const mpInitialData;
00055          Args(const int& numRows, const int& numCols, const T* pInitialData) :
00056             mNumRows(numRows), mNumCols(numCols), mpInitialData(pInitialData) {}
00057       private:
00058          Args& operator=(const Args& rhs);
00059       };
00060 
00061       /**
00062        * Obtains an matrix using the createMatrix function.
00063        *
00064        * @param  args
00065        *         The arguments for obtaining the resource. Should be of type MatrixObject::Args.
00066        * @return Returns a pointer to the created Matrix.
00067        */
00068       T* obtainResource(const Args& args) const 
00069       {
00070          return reinterpret_cast<T*>(createMatrix<T>(args.mNumRows, args.mNumCols, args.mpInitialData));
00071       }
00072 
00073       /**
00074        * Releases a matrix using the deleteMatrix function.
00075        *
00076        * @param  args
00077        *         The arguments for releasing the resource. Should be of type MatrixObject::Args.
00078        * @param  pMatrix
00079        *         A pointer to the matrix to be freed.
00080        */
00081       void releaseResource(const Args& args, T* pMatrix) const
00082       {
00083          deleteMatrix<T>(reinterpret_cast<T**&>(pMatrix));
00084       }
00085    };
00086 
00087    /**
00088     *  This is a %Resource class that creates and destroys two-dimensional matrices.
00089     *
00090     *  This is a %Resource class that creates and destroys two-dimensional matrices. It has a conversion
00091     *  operator to allow a %MatrixResource object to be used whereever a double** would normally be used.
00092    */
00093    template<typename T>
00094    class MatrixResource : public Resource<T, MatrixObject<T> >
00095    {
00096    public:
00097       /**
00098        *  Constructs a Resource object that wraps a double**.
00099        *
00100        *  Constructs a Resource object that wraps a double**.
00101        *  Creates a matrix of the specified size with (optional) initial data.
00102        *
00103        *  @param   numRows
00104        *           The number of rows to allocate.
00105        *           This parameter cannot be less than or equal to 0.
00106        *
00107        *  @param   numCols
00108        *           The number of columns to allocate.
00109        *           This parameter cannot be less than or equal to 0.
00110        *
00111        *  @param   pInitialData
00112        *           The initial values to copy into the matrix.
00113        *           There should be \c numRows \c * \c numCols elements available in this buffer.
00114        *           If this parameter is \b NULL, the returned matrix will be set to 0 before returning.
00115        */
00116       MatrixResource(const int& numRows, const int& numCols, const T* pInitialData = NULL) :
00117          Resource<T, MatrixObject<T> >(typename MatrixObject<T>::Args(numRows, numCols, pInitialData)) {}
00118 
00119       /**
00120        *  Returns a pointer to the underlying T**.
00121        *
00122        *  Returns a pointer to the underlying T**. This operator
00123        *  allows the %MatrixResource object to be used whereever
00124        *  a T** would normally be used.
00125        *
00126        *  @return   A pointer to the underlying T**.
00127        */
00128       operator T**()
00129       {
00130          return reinterpret_cast<T**>(Resource<T,MatrixObject<T> >::get());
00131       }
00132 
00133       /**
00134        *  Returns a const pointer to the underlying T**.
00135        *
00136        *  Returns a const pointer to the underlying T**. This operator
00137        *  allows the %MatrixResource object to be used whereever
00138        *  a const T** would normally be used.
00139        *
00140        *  @return   A const pointer to the underlying T**.
00141        */
00142       operator const T**() const
00143       {
00144          return reinterpret_cast<const T**>(const_cast<T*>(Resource<T,MatrixObject<T> >::get()));
00145       }
00146 
00147       /**
00148        *  Returns a pointer to a row.
00149        *
00150        *  @param index
00151        *           The zero-based row to obtain.
00152        *
00153        *  @warning This overload is only valid for \c int variables.
00154        *
00155        *  @return   A pointer to the requested row.
00156        */
00157        T*& operator[] (const int& index)
00158       {
00159          T** pMatrix = reinterpret_cast<T**>(Resource<T,MatrixObject<T> >::get());
00160          return pMatrix[index];
00161       }
00162 
00163       /**
00164        *  Returns a const pointer to a row.
00165        *
00166        *  @param index
00167        *           The zero-based row to obtain.
00168        *
00169        *  @warning This overload is only valid for \c int variables.
00170        *
00171        *  @return   A const pointer to the requested row.
00172        */
00173       const T*& operator[] (const int& index) const
00174       {
00175          T** pMatrix = reinterpret_cast<T**>(Resource<T,MatrixObject<T> >::get());
00176          return pMatrix[index];
00177       }
00178    };
00179 
00180    /**
00181     *  Allocate memory for a two-dimensional matrix.
00182     *
00183     *  @param   numRows
00184     *           The number of rows to allocate.
00185     *           This parameter cannot be less than or equal to 0.
00186     *
00187     *  @param   numCols
00188     *           The number of columns to allocate.
00189     *           This parameter cannot be less than or equal to 0.
00190     *
00191     *  @param   pInitialData
00192     *           The initial values to copy into the matrix.
00193     *           There should be \c numRows \c * \c numCols elements available in this buffer.
00194     *           If this parameter is \b NULL, the returned matrix will be set to 0 before returning.
00195     *
00196     *  @return A pointer to the matrix if the operation succeeded, NULL otherwise.
00197     *
00198     *  @see deleteMatrix()
00199     */
00200    template<typename T>
00201    T** createMatrix(const int& numRows, const int& numCols, const T* pInitialData)
00202    {
00203       if (numRows <= 0 || numCols <= 0)
00204       {
00205          return NULL;
00206       }
00207 
00208       T** pMatrix = NULL;
00209       try
00210       {
00211          pMatrix = new T*[numRows];
00212          pMatrix[0] = new T[numRows * numCols];
00213       }
00214       catch (const std::bad_alloc&)
00215       {
00216          delete [] pMatrix[0];
00217          delete [] pMatrix;
00218          return NULL;
00219       }
00220 
00221       if (pInitialData == NULL)
00222       {
00223          memset(pMatrix[0], 0, numRows * numCols * sizeof(T));
00224       }
00225       else
00226       {
00227          memcpy(pMatrix[0], pInitialData, numRows * numCols * sizeof(T));
00228       }
00229 
00230       for (int row = 1; row < numRows; ++row)
00231       {
00232          pMatrix[row] = pMatrix[row - 1] + numCols;
00233       }
00234 
00235       return pMatrix;
00236    }
00237 
00238    /**
00239     *  Free memory for a two-dimensional matrix.
00240     *
00241     *  @param   pMatrix
00242     *           The value returned by createMatrix().
00243     *           On successful return, this will be set to \b NULL.
00244     *
00245     *  @return True if the operation succeeded, false otherwise.
00246     *
00247     *  @see createMatrix()
00248     */
00249    template<typename T>
00250    bool deleteMatrix(T**& pMatrix)
00251    {
00252       if (pMatrix == NULL)
00253       {
00254          return false;
00255       }
00256 
00257       delete [] pMatrix[0];
00258       delete [] pMatrix;
00259       pMatrix = NULL;
00260       return true;
00261    }
00262 
00263    /**
00264     *  Calculates the singular value decomposition (SVD) for the given matrix.
00265     *
00266     *  @param   pMatrix
00267     *           A pointer to the location of the matrix to use for computation.
00268     *           This location must be allocated and freed by the caller of this function.
00269     *           This parameter cannot be \b NULL.
00270     *
00271     *  @param   pSingularValues
00272     *           A pointer to the location to store the singular values.
00273     *           This location must be allocated and freed by the caller of this function.
00274     *           If this parameter is \b NULL, singular values will not be returned.
00275     *
00276     *  @param   pColumnMatrix
00277     *           A pointer to the location to store the numRows x numCols column matrix of the decomposition.
00278     *           This location must be allocated and freed by the caller of this function.
00279     *           If this parameter is \b NULL, the column matrix will not be returned.
00280     *
00281     *  @param   pOrthogonalMatrix
00282     *           A pointer to the location to store the numCols x numCols orthogonal matrix of the decomposition.
00283     *           This location must be allocated and freed by the caller of this function.
00284     *           If this parameter is \b NULL, the orthogonal matrix will not be returned.
00285     *
00286     *  @param   numRows
00287     *           The number of rows in \c pMatrix.
00288     *           This parameter cannot be less than \c numCols.
00289     *
00290     *  @param   numCols
00291     *           The number of columns in \c pMatrix.
00292     *           This parameter cannot be less than or equal to 0.
00293     *
00294     *  @return True if the operation succeeded, false otherwise.
00295     *
00296     *  @see isMatrixSymmetric()
00297     */
00298    bool computeSingularValueDecomposition(const double** pMatrix, double* pSingularValues,
00299       double** pColumnMatrix, double** pOrthogonalMatrix, const int& numRows, const int& numCols);
00300 
00301    /**
00302     *  Solves a linear equation of the form Ax = b, where A is represented by \c pLhs,
00303     *  b is represented by \c pRhs, and x is represented by \c pResult.
00304     *
00305     *  @param   pResult
00306     *           A pointer to the location of the vector to use for results.
00307     *           This vector is assumed to be 1 column wide and contain \c numRows entries.
00308     *           This location must be allocated and freed by the caller of this function.
00309     *           This parameter cannot be \b NULL.
00310     *
00311     *  @param   pLhs
00312     *           A pointer to the location of the matrix to use for solving the equation.
00313     *           This location must be allocated and freed by the caller of this function.
00314     *           This parameter cannot be \b NULL.
00315     *
00316     *  @param   pRhs
00317     *           A pointer to the location of the vector to use for solving the equation.
00318     *           This vector is assumed to be 1 column wide and contain \c numRows entries.
00319     *           This location must be allocated and freed by the caller of this function.
00320     *           This parameter cannot be \b NULL.
00321     *
00322     *  @param   numRows
00323     *           The number of rows in \c pLhs, \c pRhs and \c pResult.
00324     *           This parameter cannot be less than \c numColsLhs.
00325     *
00326     *  @param   numColsLhs
00327     *           The number of columns in \c pLhs.
00328     *           This parameter cannot be less than or equal to 0.
00329     *
00330     *  @return True if the operation succeeded, false otherwise.
00331     */
00332    bool solveLinearEquation(double* pResult, const double** pLhs, const double* pRhs,
00333       const int& numRows, const int& numColsLhs);
00334 
00335    /**
00336     *  Calculates eigenvalues and eigenvectors for the given symmetric matrix.
00337     *
00338     *  @param   pSymmetricMatrix
00339     *           A pointer to the location of the symmetric matrix to use for computation.
00340     *           This location must be allocated and freed by the caller of this function.
00341     *           This parameter cannot be \b NULL.
00342     *
00343     *  @param   pEigenvalues
00344     *           A pointer to the location to store the sorted eigenvalues.
00345     *           This location must be allocated and freed by the caller of this function.
00346     *           If this parameter is \b NULL, eigenvalues will not be returned.
00347     *
00348     *  @param   pEigenvectors
00349     *           A pointer to the location to store the sorted eigenvectors.
00350     *           This location must be allocated and freed by the caller of this function.
00351     *           If this parameter is \b NULL, eigenvectors will not be returned.
00352     *
00353     *  @param   numRows
00354     *           The number of rows in \c pSymmetricMatrix.
00355     *           Since only square matrices have eigenvalues, this value also represents the number of columns.
00356     *           This parameter cannot be less than or equal to 0.
00357     *
00358     *  @return True if the operation succeeded, false otherwise.
00359     *
00360     *  @see isMatrixSymmetric()
00361     */
00362    bool getEigenvalues(const double** pSymmetricMatrix, double* pEigenvalues, double** pEigenvectors,
00363       const int& numRows);
00364 
00365    /**
00366     *  Inverts a square matrix.
00367     *
00368     *  @param   pDestination
00369     *           A pointer to the location to store the inverted matrix.
00370     *           This location must be allocated and freed by the caller of this function.
00371     *           This parameter can be the same as \c pSource.
00372     *           This parameter cannot be \b NULL.
00373     *
00374     *  @param   pSource
00375     *           A pointer to the location of the matrix to be inverted.
00376     *           This location must be allocated and freed by the caller of this function.
00377     *           This parameter can be the same as \c pDestination.
00378     *           This parameter cannot be \b NULL.
00379     *
00380     *  @param   numRows
00381     *           The number of rows in \c pDestination and \c pSource.
00382     *           Since only square matrices are invertible, this value also represents the number of columns.
00383     *           This parameter cannot be less than or equal to 0.
00384     *
00385     *  @return True if the operation succeeded, false otherwise.
00386     */
00387    bool invertSquareMatrix1D(double* pDestination, const double* pSource, const int& numRows);
00388 
00389    /**
00390     *  This method is similar to invertSquareMatrix1D, except \c pSource and \c pDestination refer
00391     *  to two-dimensional pointers, such as those returned by createMatrix().
00392     *
00393     *  @copydoc invertSquareMatrix1D()
00394     *
00395     *  @see createMatrix()
00396     */
00397    bool invertSquareMatrix2D(double** pDestination, const double** pSource, const int& numRows);
00398 
00399    /**
00400     *  Inverts a RasterElement representing a square matrix.
00401     *
00402     *  @param   pDestination
00403     *           A pointer to the RasterElement to store the inverted matrix.
00404     *           This parameter must be the same size (rows, columns, and bands) and EncodingType as \c pSource.
00405     *           This parameter can be the same as \c pSource.
00406     *           This parameter cannot be \b NULL.
00407     *
00408     *  @param   pSource
00409     *           A pointer to the RasterElement containing the data to be inverted.
00410     *           The number of rows must not be greater than \c numeric_limits<int>::max().
00411     *           This parameter must contain the same number of rows and columns.
00412     *           This parameter must contain single band data.
00413     *           This parameter must have an EncodingType of FLT8BYTES.
00414     *           This parameter can be the same as \c pDestination.
00415     *           This parameter cannot be \b NULL.
00416     *
00417     *  @return True if the operation succeeded, false otherwise.
00418     */
00419    bool invertRasterElement(RasterElement* pDestination, const RasterElement* pSource);
00420 
00421    /**
00422     *  Compares two matrices for equality.
00423     *
00424     *  @param   pLhsMatrix
00425     *           A pointer to the location of the left-hand side matrix to be compared.
00426     *           This location must be allocated and freed by the caller of this function.
00427     *           This parameter cannot be \b NULL.
00428     *
00429     *  @param   pRhsMatrix
00430     *           A pointer to the location of the right-hand side matrix to be compared.
00431     *           This location must be allocated and freed by the caller of this function.
00432     *           This parameter cannot be \b NULL.
00433     *
00434     *  @param   numRows
00435     *           The number of rows in \c pLhsMatrix and \c pRhsMatrix.
00436     *           This parameter cannot be less than or equal to 0.
00437     *
00438     *  @param   numCols
00439     *           The number of columns in \c pLhsMatrix and \c pRhsMatrix.
00440     *           This parameter cannot be less than or equal to 0.
00441     *
00442     *  @param   tolerance
00443     *           The maximum allowable difference between any single element of pLhsMatrix and pRhsMatrix.
00444     *           This parameter cannot be less than 0.
00445     *
00446     *  @return True if the operation succeeded, false otherwise.
00447     */
00448    template<typename T>
00449    bool areMatricesEqual(const T** pLhsMatrix, const T** pRhsMatrix,
00450       const int& numRows, const int& numCols, const double& tolerance = 1e-6)
00451    {
00452       if (pLhsMatrix == NULL || pRhsMatrix == NULL || numRows <= 0 || numCols <= 0 || tolerance < 0.0)
00453       {
00454          return false;
00455       }
00456 
00457       if (pLhsMatrix == pRhsMatrix)
00458       {
00459          return true;
00460       }
00461 
00462       if (tolerance == 0.0)
00463       {
00464          if (memcmp(pLhsMatrix, pRhsMatrix, numRows * numCols * sizeof(T)) != 0)
00465          {
00466             return false;
00467          }
00468       }
00469       else
00470       {
00471          for (int row = 0; row < numRows; ++row)
00472          {
00473             for (int col = 0; col < numCols; ++col)
00474             {
00475                if (fabs(static_cast<double>(pLhsMatrix[row][col] - pRhsMatrix[row][col])) > tolerance)
00476                {
00477                   return false;
00478                }
00479             }
00480          }
00481       }
00482 
00483       return true;
00484    }
00485 
00486    /**
00487     *  Determines whether a given matrix is symmetric.
00488     *
00489     *  @param   pMatrix
00490     *           A pointer to the location of the matrix to be checked.
00491     *           This location must be allocated and freed by the caller of this function.
00492     *           This parameter cannot be \b NULL.
00493     *
00494     *  @param   numRows
00495     *           The number of rows in \c pMatrix.
00496     *           Since only square matrices can be symmetric, this value also represents the number of columns.
00497     *           This parameter cannot be less than or equal to 0.
00498     *
00499     *  @param   tolerance
00500     *           The maximum allowable difference between pMatrix[row][col] and pMatrix[col][row].
00501     *           This parameter cannot be less than 0.
00502     *
00503     *  @return True if the operation succeeded, false otherwise.
00504     */
00505    template<typename T>
00506    bool isMatrixSymmetric(const T** pMatrix, const int& numRows, const double& tolerance = 1e-3)
00507    {
00508       if (pMatrix == NULL || numRows <=0 || tolerance < 0.0)
00509       {
00510          return false;
00511       }
00512 
00513       const int numCols = numRows;
00514       for (int row = 0; row < numRows; ++row)
00515       {
00516          for (int col = row + 1; col < numCols; ++col)
00517          {
00518             if (fabs(static_cast<double>(pMatrix[row][col] - pMatrix[col][row])) > tolerance)
00519             {
00520                return false;
00521             }
00522          }
00523       }
00524 
00525       return true;
00526    }
00527 }
00528 
00529 #endif

Software Development Kit - Opticks 4.9.0 Build 16218