00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "cxutils/math/matrix.h"
00042 #include "cxutils/math/cxmath.h"
00043 #include <assert.h>
00044 #include <iostream>
00045 #include <iomanip>
00046 #include <string.h>
00047
00048 using namespace std;
00049 using namespace CxUtils;
00050
00056 Matrix::Matrix()
00057 {
00058 mpMatrix = NULL;
00059 mRows = mCols = mSize = 0;
00060 }
00061
00062
00068 Matrix::Matrix(const Matrix& m)
00069 {
00070 mRows = m.mRows;
00071 mCols = m.mCols;
00072 mSize = m.mSize;
00073
00074 if(mSize != 0)
00075 {
00076 mpMatrix = new double[mSize];
00077 assert(mpMatrix);
00078 memcpy(mpMatrix, m.mpMatrix, sizeof(double)*mSize);
00079 }
00080 else
00081 {
00082 mpMatrix = NULL;
00083 }
00084 }
00085
00086
00097 Matrix::Matrix(const unsigned int rows, const unsigned int cols)
00098 {
00099 mpMatrix = NULL;
00100 mRows = mCols = mSize = 0;
00101 Create(rows, cols);
00102 }
00103
00104
00114 Matrix::Matrix(const unsigned int rows, const unsigned int cols, const double v)
00115 {
00116 mpMatrix = NULL;
00117 mRows = mCols = mSize = 0;
00118 Create(rows, cols, v);
00119 }
00120
00121
00127 Matrix::~Matrix()
00128 {
00129 Destroy();
00130 }
00131
00132
00143 int Matrix::Create(const unsigned int rows, const unsigned int cols)
00144 {
00145 if(rows == mRows && cols == mCols)
00146 {
00147 if(mSize > 0)
00148 {
00149 memset(mpMatrix, 0, sizeof(double)*mSize);
00150 }
00151 return 1;
00152 }
00153 Destroy();
00154 if(rows == 0 || cols == 0)
00155 {
00156 return 0;
00157 }
00158
00159 mSize = rows*cols;
00160 mRows = rows;
00161 mCols = cols;
00162
00163 mpMatrix = new double[mSize];
00164 memset(mpMatrix, 0, sizeof(double)*mSize);
00165 return 1;
00166 }
00167
00168
00180 int Matrix::Create(const unsigned int rows, const unsigned int cols, const double v)
00181 {
00182 if(rows == mRows && cols == mCols)
00183 {
00184 double *ptr = mpMatrix;
00185 for(unsigned int i = 0; i < mSize; i++)
00186 *(ptr++) = v;
00187
00188 return 1;
00189 }
00190
00191 Destroy();
00192 if(rows == 0 || cols == 0)
00193 {
00194 return 0;
00195 }
00196
00197 mSize = rows*cols;
00198 mRows = rows;
00199 mCols = cols;
00200
00201 mpMatrix = new double[mSize];
00202 assert(mpMatrix);
00203 double *ptr = mpMatrix;
00204 for(unsigned int i = 0; i < mSize; i++)
00205 *(ptr++) = v;
00206 return 1;
00207 }
00208
00209
00221 int Matrix::GetDeterminant(double& d) const
00222 {
00223 if(mRows == mCols && mSize > 0)
00224 {
00225 if(mRows == 1)
00226 {
00227 d = *mpMatrix;
00228 }
00229 else if(mRows == 2)
00230 {
00231 d = mpMatrix[0]*mpMatrix[3] - mpMatrix[1]*mpMatrix[2];
00232 }
00233 else if(mRows == 3)
00234 {
00235 d = mpMatrix[0]*
00236 ( mpMatrix[4]*mpMatrix[8] -
00237 mpMatrix[7]*mpMatrix[5]) -
00238 mpMatrix[1]*
00239 ( mpMatrix[3]*mpMatrix[8] -
00240 mpMatrix[6]*mpMatrix[5]) +
00241 mpMatrix[0*mCols + 1]*
00242 ( mpMatrix[3]*mpMatrix[7] -
00243 mpMatrix[6]*mpMatrix[4]);
00244 }
00245 else
00246 {
00247 d = 0;
00248 Matrix minor;
00249 double sign = -1.0;
00250 for(unsigned int i = 0; i < mRows; i++)
00251 {
00252 double det = 0;
00253 sign = pow(-1.0f, (float)i);
00254 GetMinor(0, i, minor);
00255 minor.GetDeterminant(det);
00256 d += sign*det*mpMatrix[i];
00257 }
00258 }
00259 return 1;
00260 }
00261 return 0;
00262 }
00263
00264
00280 int Matrix::GetMinor(const unsigned int row, const unsigned int col, Matrix& m) const
00281 {
00282 assert(mRows == mCols && "Matrix::Error - Dimensions must be equal to get a minor.");
00283
00284 if(row >= mRows || col >= mCols)
00285 return 0;
00286
00287 if(m.mRows != mRows - 1 || m.mCols != mCols - 1)
00288 m.Create(mRows - 1, mCols - 1);
00289
00290 double *ptr = m.mpMatrix;
00291 double *mat = mpMatrix;
00292 for(unsigned int r = 0; r < mRows; r++)
00293 {
00294 if(r != row)
00295 {
00296 mat = mpMatrix + r*mCols;
00297 for(unsigned int c = 0; c < mCols; c++, mat++)
00298 {
00299 if(c != col)
00300 {
00301 *ptr++ = *mat;
00302 }
00303 }
00304 }
00305 }
00306
00307 return 1;
00308 }
00309
00310
00320 int Matrix::GetInverse(Matrix& i) const
00321 {
00322 if(mRows != mCols || mRows == 0)
00323 {
00324 std::cout << "Matrix::Error Cannot Invert, (mRows != mCols || mRows == 0)\n";
00325 return 0;
00326 }
00327
00328 Matrix identity(mRows, mCols);
00329 for(unsigned int k = 0; k < mRows; k++)
00330 identity.mpMatrix[k*mRows + k] = 1.0;
00331 return GaussJordan(*this, identity, i);
00332 }
00333
00334
00353 int Matrix::GaussJordan(Matrix& a, Matrix& b)
00354 {
00355 unsigned int iRow, iCol;
00356 unsigned int n = 0, m = 0;
00357 unsigned int *cIndex, *rIndex, *iPivots;
00358 double max, pInv = 0.0;
00359
00360
00361 if(a.mCols != a.mRows)
00362 {
00363 return 0;
00364 }
00365
00366
00367
00368 if(a.mRows != b.mRows)
00369 {
00370 return 0;
00371 }
00372
00373 n = a.mRows;
00374 m = b.mCols;
00375
00376 cIndex = new unsigned int[n];
00377 rIndex = new unsigned int[n];
00378 iPivots = new unsigned int[n];
00379 assert(cIndex && rIndex && iPivots);
00380
00381 memset(cIndex, 0, sizeof(unsigned int)*n);
00382 memset(rIndex, 0, sizeof(unsigned int)*n);
00383 memset(iPivots, 0, sizeof(unsigned int)*n);
00384 iRow = iCol = 0;
00385
00386 for(unsigned int i = 0; i < n; i++)
00387 {
00388 max = 0.0;
00389 for(unsigned int j = 0; j < n; j++)
00390 {
00391 if(iPivots[j] != 1)
00392 {
00393 for(unsigned int k = 0; k < n; k++)
00394 {
00395 if(iPivots[k] == 0)
00396 {
00397 double val = fabs(a.mpMatrix[j*a.mCols + k]);
00398 if(val >= max)
00399 {
00400 max = val;
00401 iRow = j;
00402 iCol = k;
00403 }
00404 }
00405 }
00406 }
00407 }
00408 ++(iPivots[iCol]);
00409 if(iRow != iCol)
00410 {
00411 for(unsigned int l = 0; l < n || l < m; l++)
00412 {
00413 double t;
00414 double *p1, *p2;
00415 if(l < n)
00416 {
00417 p1 = &(a.mpMatrix[iRow*a.mCols + l]);
00418 p2 = &(a.mpMatrix[iCol*a.mCols + l]);
00419 t = *p1;
00420 *p1 = *p2;
00421 *p2 = t;
00422 }
00423 if(l < m)
00424 {
00425 p1 = &(b.mpMatrix[iRow*b.mCols + l]);
00426 p2 = &(b.mpMatrix[iCol*b.mCols + l]);
00427 t = *p1;
00428 *p1 = *p2;
00429 *p2 = t;
00430 }
00431 }
00432 }
00433
00434 rIndex[i] = iRow;
00435 cIndex[i] = iCol;
00436 unsigned int pos = iCol*a.mCols + iCol;
00437 double t = a.mpMatrix[pos];
00438 if( fabs(t) < CX_EPSILON )
00439 {
00440
00441 if(cIndex)
00442 delete[] cIndex;
00443 if(rIndex)
00444 delete[] rIndex;
00445 if(iPivots)
00446 delete[] iPivots;
00447 return 0;
00448 }
00449 pInv = 1.0/t;
00450 a.mpMatrix[pos] = 1.0;
00451
00452 for(unsigned int l = 0; l < n || l < m; l++)
00453 {
00454 if(l < n)
00455 a.mpMatrix[iCol*a.mCols + l] *= pInv;
00456 if(l < m)
00457 b.mpMatrix[iCol*b.mCols + l] *= pInv;
00458 }
00459
00460 for(unsigned int l = 0; l < n; l++)
00461 {
00462 if(l != iCol)
00463 {
00464 t = a.mpMatrix[l*a.mCols + iCol];
00465 a.mpMatrix[l*a.mCols + iCol] = 0.0;
00466 for(unsigned int k = 0; k < n || k < m; k++)
00467 {
00468 if(k < n)
00469 {
00470 a.mpMatrix[l*a.mCols + k] -= a.mpMatrix[iCol*a.mCols + k]*t;
00471 }
00472 if(k < m)
00473 {
00474 b.mpMatrix[l*b.mCols + k] -= b.mpMatrix[iCol*b.mCols + k]*t;
00475 }
00476 }
00477 }
00478 }
00479
00480 for(int l = (int)(n - 1); l >= 0; l--)
00481 {
00482 if(rIndex[l] != cIndex[l])
00483 {
00484 double *p1, *p2;
00485 for(unsigned int k = 0; k < n; k++)
00486 {
00487 p1 = &(a.mpMatrix[k*a.mCols + rIndex[l]]);
00488 p2 = &(a.mpMatrix[k*a.mCols + cIndex[l]]);
00489 t = *p1;
00490 *p1 = *p2;
00491 *p2 = t;
00492 }
00493 }
00494 }
00495 }
00496
00497 if(cIndex)
00498 delete[] cIndex;
00499 if(rIndex)
00500 delete[] rIndex;
00501 if(iPivots)
00502 delete[] iPivots;
00503
00504 return 1;
00505 }
00506
00507
00526 int Matrix::GaussJordan(const Matrix& a, const Matrix& b, Matrix& x)
00527 {
00528 x = b;
00529 Matrix aCopy = a;
00530 if(GaussJordan(aCopy, x))
00531 {
00532 return 1;
00533 }
00534 return 0;
00535 }
00536
00537
00543 void Matrix::Clear()
00544 {
00545 if(mpMatrix)
00546 {
00547 memset(mpMatrix, 0, sizeof(double)*mSize);
00548 }
00549 }
00550
00551
00557 void Matrix::Destroy()
00558 {
00559 if(mpMatrix)
00560 {
00561 delete[] mpMatrix;
00562 mpMatrix = NULL;
00563 }
00564 mRows = mCols = mSize = 0;
00565 }
00566
00567
00573 void Matrix::Print() const
00574 {
00575 double *ptr = mpMatrix;
00576 cout << "\n";
00577 if(ptr == NULL)
00578 {
00579 cout << "[ ]\n";
00580 return;
00581 }
00582
00583 for(unsigned int i = 0; i < mRows; i++)
00584 {
00585 cout << "| ";
00586 for(unsigned int j = 0; j < mCols; j++)
00587 {
00588 if(fabs(*ptr) < .000000000001)
00589 {
00590 cout << setw(10) << 0 << " ";
00591 ptr++;
00592 }
00593 else
00594 cout << setw(10) << *ptr++ << " ";
00595 }
00596 cout << setw(10) << " |\n";
00597 }
00598 cout << "\n";
00599 }
00600
00601
00608 void Matrix::Transpose(const Matrix& original, Matrix& transpose)
00609 {
00610 transpose.Create(original.mCols, original.mRows);
00611 for(unsigned int i = 0; i < original.mCols; i++)
00612 {
00613 for(unsigned int j = 0; j < original.mRows; j++)
00614 {
00615 unsigned int posA = j*original.mCols + i;
00616 unsigned int posB = i*original.mRows + j;
00617 transpose.mpMatrix[posB] = original.mpMatrix[posA];
00618 }
00619 }
00620 }
00621
00622
00630 Matrix Matrix::Inverse() const
00631 {
00632 Matrix inverse(mRows, mCols);
00633 int result = GetInverse(inverse);
00634 assert(result && "Matrix: Can only invert square matrix.");
00635 return inverse;
00636 }
00637
00638
00644 Matrix Matrix::Transpose() const
00645 {
00646 Matrix t(mCols, mRows);
00647 for(unsigned int i = 0; i < mCols; i++)
00648 {
00649 for(unsigned int j = 0; j < mRows; j++)
00650 {
00651 unsigned int posA = j*mCols + i;
00652 unsigned int posB = i*mRows + j;
00653 t.mpMatrix[posB] = mpMatrix[posA];
00654 }
00655 }
00656 return t;
00657 }
00658
00659
00670 Matrix Matrix::CreateRotationX(const double val,
00671 const bool degrees)
00672 {
00673 Matrix m(4,4);
00674 m.mpMatrix[0] = 1.0;
00675 m.mpMatrix[5] = degrees ? cos(CX_DEG2RAD(val)) : cos(val);
00676 m.mpMatrix[6] = degrees ? -sin(CX_DEG2RAD(val)) : -sin(val);
00677 m.mpMatrix[9] = -m.mpMatrix[6];
00678 m.mpMatrix[10] = m.mpMatrix[5];
00679 m.mpMatrix[15] = 1.0;
00680 return m;
00681 }
00682
00693 Matrix Matrix::CreateRotationY(const double val,
00694 const bool degrees)
00695 {
00696 Matrix m(4,4);
00697 m.mpMatrix[0] = degrees ? cos(CX_DEG2RAD(val)) : cos(val);
00698 m.mpMatrix[2] = degrees ? sin(CX_DEG2RAD(val)) : sin(val);
00699 m.mpMatrix[5] = 1.0;
00700 m.mpMatrix[8] = -m.mpMatrix[2];
00701 m.mpMatrix[10] = m.mpMatrix[0];
00702 m.mpMatrix[15] = 1.0;
00703 return m;
00704 }
00705
00716 Matrix Matrix::CreateRotationZ(const double val,
00717 const bool degrees)
00718 {
00719 Matrix m(4,4);
00720 m.mpMatrix[0] = degrees ? cos(CX_DEG2RAD(val)) : cos(val);
00721 m.mpMatrix[1] = degrees ? -sin(CX_DEG2RAD(val)) : -sin(val);
00722 m.mpMatrix[4] = -m.mpMatrix[1];
00723 m.mpMatrix[5] = m.mpMatrix[0];
00724 m.mpMatrix[10] = 1.0;
00725 m.mpMatrix[15] = 1.0;
00726 return m;
00727 }
00728
00742 Matrix Matrix::CreateScalingMatrix(const double x,
00743 const double y,
00744 const double z)
00745 {
00746 Matrix m(4,4);
00747 m.mpMatrix[0] = x;
00748 m.mpMatrix[5] = y;
00749 m.mpMatrix[10] = z;
00750 m.mpMatrix[15] = 1.0;
00751 return m;
00752 }
00753
00765 Matrix Matrix::CreateTranslationMatrix(const double x,
00766 const double y,
00767 const double z)
00768 {
00769 Matrix m(4,4);
00770 m.mpMatrix[0] = 1.0;
00771 m.mpMatrix[3] = x;
00772 m.mpMatrix[5] = 1.0;
00773 m.mpMatrix[7] = y;
00774 m.mpMatrix[10] = 1.0;
00775 m.mpMatrix[11] = z;
00776 m.mpMatrix[15] = 1.0;
00777 return m;
00778 }
00779
00785 Matrix& Matrix::operator=(const Matrix& m)
00786 {
00787 if(this != &m)
00788 {
00789 if(mSize != m.mSize)
00790 {
00791 if(mpMatrix)
00792 {
00793 delete[] mpMatrix;
00794 mpMatrix = NULL;
00795 }
00796 }
00797
00798 mRows = m.mRows;
00799 mCols = m.mCols;
00800 mSize = m.mSize;
00801
00802 if(mSize != 0)
00803 {
00804 if(!mpMatrix)
00805 {
00806 mpMatrix = new double[mSize];
00807 assert(mpMatrix);
00808 }
00809 memcpy(mpMatrix, m.mpMatrix, sizeof(double)*mSize);
00810 }
00811 else
00812 {
00813 mpMatrix = NULL;
00814 }
00815 }
00816
00817 return *this;
00818 }
00819
00820
00828 Matrix& Matrix::operator=(const double v)
00829 {
00830 if(mpMatrix)
00831 {
00832 double *p = mpMatrix;
00833 for(unsigned int i = 0; i < mSize; i++, p++)
00834 *p = v;
00835 }
00836
00837 return *this;
00838 }
00839
00840
00851 Matrix Matrix::operator+(const Matrix& m) const
00852 {
00853 assert(mRows == m.mRows && mCols == m.mCols && "Matrix::Error - Dimensions are not equal.");
00854 Matrix result(mRows, mCols);
00855 if(mSize > 0)
00856 {
00857 double* m1;
00858 double* m2;
00859 double *m3;
00860 m1 = mpMatrix;
00861 m2 = m.mpMatrix;
00862 m3 = result.mpMatrix;
00863 for(unsigned int i = 0; i < mSize; i++, m1++, m2++, m3++)
00864 *m3 = *m1 + *m2;
00865 }
00866
00867 return result;
00868 }
00869
00870
00881 Matrix& Matrix::operator+=(const Matrix& m)
00882 {
00883 assert(mRows == m.mRows && mCols == m.mCols && "Matrix::Error - Dimensions are not equal.");
00884 if(mSize > 0)
00885 {
00886 double* m1;
00887 double* m2;
00888 m1 = mpMatrix;
00889 m2 = m.mpMatrix;
00890 for(unsigned int i = 0; i < mSize; i++, m1++, m2++)
00891 *m1 += *m2;
00892 }
00893
00894 return *this;
00895 }
00896
00897
00908 Matrix Matrix::operator-(const Matrix& m) const
00909 {
00910 assert(mRows == m.mRows && mCols == m.mCols && "Matrix::Error - Dimensions are not equal.");
00911 Matrix result(mRows, mCols);
00912 if(mSize > 0)
00913 {
00914 double* m1;
00915 double* m2;
00916 double *m3;
00917 m1 = mpMatrix;
00918 m2 = m.mpMatrix;
00919 m3 = result.mpMatrix;
00920 for(unsigned int i = 0; i < mSize; i++, m1++, m2++, m3++)
00921 *m3 = *m1 - *m2;
00922 }
00923
00924 return result;
00925 }
00926
00927
00938 Matrix& Matrix::operator-=(const Matrix& m)
00939 {
00940 assert(mRows == m.mRows && mCols == m.mCols && "Matrix::Error - Dimensions are not equal.");
00941 if(mSize > 0)
00942 {
00943 double* m1;
00944 double* m2;
00945 m1 = mpMatrix;
00946 m2 = m.mpMatrix;
00947 for(unsigned int i = 0; i < mSize; i++, m1++, m2++)
00948 *m1 -= *m2;
00949 }
00950
00951 return *this;
00952 }
00953
00954
00965 Matrix Matrix::operator*(const Matrix& m) const
00966 {
00967 assert(mpMatrix && m.mpMatrix && mCols == m.mRows && "Matrix::Error - M1 columns must equal M2 rows for multiplication.");
00968 double* m1;
00969 double* m2;
00970 double* m3;
00971 Matrix result(mRows, m.mCols);
00972 m1 = mpMatrix;
00973 m2 = m.mpMatrix;
00974 m3 = result.mpMatrix;
00975 for(unsigned int r = 0; r < result.mRows; r++)
00976 {
00977 for(unsigned int c = 0; c < result.mCols; c++)
00978 {
00979 *m3 = 0;
00980 for(unsigned int i = 0; i < mCols; i++)
00981 {
00982 *m3 += m1[r*mCols + i]*m2[i*m.mCols + c];
00983 }
00984 m3++;
00985 }
00986 }
00987
00988 return result;
00989 }
00990
01001 Matrix Matrix::operator/(const Matrix& m) const
01002 {
01003 return *this * m.Inverse();
01004 }
01005
01006
01017 Matrix& Matrix::operator*=(const Matrix& m)
01018 {
01019 assert(mpMatrix && m.mpMatrix && mCols == m.mRows && "Matrix::Error - M1 columns must equal M2 rows for multiplication.");
01020 double* m1;
01021 double* m2;
01022 double* m3;
01023 Matrix result(mRows, m.mCols);
01024 m1 = mpMatrix;
01025 m2 = m.mpMatrix;
01026 m3 = result.mpMatrix;
01027 for(unsigned int r = 0; r < result.mRows; r++)
01028 {
01029 for(unsigned int c = 0; c < result.mCols; c++)
01030 {
01031 *m3 = 0;
01032 for(unsigned int i = 0; i < mCols; i++)
01033 {
01034 *m3 += m1[r*mCols + i]*m2[i*m.mCols + c];
01035 }
01036 m3++;
01037 }
01038 }
01039
01040 *this = result;
01041
01042 return *this;
01043 }
01044
01045
01056 Matrix& Matrix::operator/=(const Matrix& m)
01057 {
01058 *this *= m.Inverse();
01059
01060 return *this;
01061 }
01062
01063
01079 double* Matrix::operator[](const unsigned int i)
01080 {
01081 assert(mpMatrix && i < mRows && "Matrix::Error - Invalid row/col.");
01082 return &(mpMatrix[i*mCols]);
01083 }
01084
01100 double* Matrix::operator[](const unsigned int i) const
01101 {
01102 assert(mpMatrix && i < mRows && "Matrix::Error - Invalid row/col.");
01103 return (double *)&(mpMatrix[i*mCols]);
01104 }
01105
01106
01117 double& Matrix::operator()(const unsigned int row, const unsigned int col)
01118 {
01119 assert(mpMatrix && row < mRows && col < mCols && "Matrix::Error - Invalid row/col.");
01120 return mpMatrix[row*mCols + col];
01121 }
01122
01123
01134 double Matrix::operator()(const unsigned int row, const unsigned int col) const
01135 {
01136 assert(mpMatrix && row < mRows && col < mCols && "Matrix::Error - Invalid row/col.");
01137 return mpMatrix[row*mCols + col];
01138 }
01139
01140
01141