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