//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1997 // // File: vrmatrx.h // //-------------------------------------------------------------------------- #ifndef _MATRIX_H_ #define _MATRIX_H_ #include #include "basics.h" #include "mdvect.h" // // VRMATRIXSQ.H: Matrix handling // template void fastMemMove(const T * ptfrom, T * ptto, int ct) { ::memmove( (void*) ptto, (void*) ptfrom, ct * sizeof(T) ); } class VRMATRIX : public TMDVDENSE { public: VRMATRIX ( int cRow, int cCol = 0 ) { Init( cRow, cCol ); } VRMATRIX () {} void Init ( int cRow, int cCol = 0 ) { second.Init( 2, cRow, cCol != 0 ? cCol : cRow ); first.resize( second._Totlen() ); } void Init ( const VRMATRIX & vrmat ) { Init( vrmat.CRow(), vrmat.CCol() ); } bool BCanMultiply( const VRMATRIX & mat ) const { return CCol() == mat.CRow(); } bool BSameDimension( const VRMATRIX & mat ) const { return CRow() == mat.CRow() && CCol() == mat.CCol() ; } int CDim ( int iDim ) const { return second.size().size() > iDim ? second.size()[iDim] : 0 ; } int CRow () const { return CDim(0); } int CCol () const { return CDim(1); } bool BSquare() const { return CRow() == CCol() ; } int IOffset ( int irow, int icol ) const { int cRow = CRow(); int cCol = CCol(); if ( irow >= CRow() || icol >= CCol() ) throw GMException(EC_MDVECT_MISUSE,"subscript error on matrix"); return second.stride()[0] * irow + second.stride()[1] * icol; } REAL & operator () ( int irow, int icol ) { return first[ IOffset(irow,icol) ]; } const REAL & operator () ( int irow, int icol ) const { VRMATRIX & vrmx = const_cast(self); return vrmx.first[ IOffset(irow,icol) ]; } void InterchangeRows ( int irow1, int irow2 ) { if ( irow1 >= CRow() && irow2 >= CRow() ) throw GMException(EC_MDVECT_MISUSE,"subscript error on matrix"); if ( irow1 == irow2 ) return; REAL * pr1 = & self(irow1,0); REAL * pr2 = & self(irow2,0); assert( & self(irow1,1) - pr1 == 1 ); for ( int icol = 0; icol < CCol(); icol++ ) { REAL r = *pr1; *pr1++ = *pr2; *pr2++ = r; } } void InterchangeCols ( int icol1, int icol2 ) { if ( icol1 >= CCol() && icol2 >= CCol() ) throw GMException(EC_MDVECT_MISUSE,"subscript error on matrix"); if ( icol1 == icol2 ) return; REAL * pr1 = & self(0,icol1); REAL * pr2 = & self(0,icol2); int icolInc = CCol(); for ( int irow = 0; irow < CRow(); irow++ ) { REAL r = *pr1; *pr1 = *pr2; *pr2 = r; pr1 += icolInc; pr2 += icolInc; } } // Return the transpose of the matrix VRMATRIX VrmatrixTranspose () const; // Return a row vector VLREAL VectorRow ( int irow ) const; // Return a column vector VLREAL VectorColumn ( int icol ) const; // Project a view of the matrix (see documentation below). VRMATRIX VrmatrixProject ( const VIMD & vimdRowColumnRetain ) const; VRMATRIX operator * ( const VRMATRIX & matrix ) const; VRMATRIX operator * ( const VLREAL & vreal ) const; VRMATRIX & operator += ( const VRMATRIX & matrix ); VRMATRIX & operator -= ( const VRMATRIX & matrix ); VRMATRIX & operator *= ( REAL rScalar ); VRMATRIX & operator += ( REAL rScalar ); VRMATRIX & operator -= ( REAL rScalar ); VRMATRIX & operator /= ( REAL rScalar ); }; class VRMATRIXSQ : public VRMATRIX { public: VRMATRIXSQ(int cdim) : VRMATRIX(cdim,cdim), _iSign(1) {} VRMATRIXSQ () {} // Construct a square matrix as the product of a column // and a row vector. VRMATRIXSQ ( const VLREAL & vrColumn, const VLREAL & vrRow ); ~ VRMATRIXSQ() {} // Return true if matrix is in L-U decomposition form bool BIsLUDecomposed () const { return _vimdRow.size() > 0 ; } // Destructive computation routines VRMATRIXSQ & operator *= ( REAL rScalar ) { VRMATRIX::operator*=(rScalar); return self; } VRMATRIXSQ & operator /= ( REAL rScalar ) { VRMATRIX::operator/=(rScalar); return self; } VRMATRIXSQ & operator += ( REAL rScalar ) { VRMATRIX::operator+=(rScalar); return self; } VRMATRIXSQ & operator -= ( REAL rScalar ) { VRMATRIX::operator-=(rScalar); return self; } VRMATRIXSQ & operator += ( const VRMATRIXSQ & matrix ) { VRMATRIX::operator+=(matrix); return self; } VRMATRIXSQ & operator -= ( const VRMATRIXSQ & matrix ) { VRMATRIX::operator-=(matrix); return self; } VRMATRIXSQ & operator *= ( const VRMATRIXSQ & matrix ); // Perform L-U decomposition; throw exception if singular // If "use tiny" is set, pivots at zero are replaced with // RTINY value (1.0e-20) void LUDecompose( bool bUseTinyIfSingular = false ); // Invert; throw exception singular. If not in L-U form, // L-U Decomp is called. void Invert( bool bUseTinyIfSingular = false ); // Return the determinant. If not in L-U form, // L-U Decomp is called. DBL DblDeterminant(); // Return the log of the determinant. If not in L-U form, // L-U Decomp is called. Throws exception if negative. DBL DblLogDeterminant(); // ------------------------------------ // Non-destructive computation routines // ------------------------------------ // Adds the log of each element in the diagonal and returns the sum. DBL DblAddLogDiagonal() const; // Set vrmatResult to be the result of performing an L-U // decomposition on the matrix. Will throw exception if // the matrix is singular // If "use tiny" is set, pivots at zero are replaced with // RTINY value (1.0e-20) void GetLUDecompose( VRMATRIXSQ & vrmatResult, bool bUseTinyIfSingular = false ) const; // Set vrmatResult to the inverse of the matrix. // Will throw an exception if the matrix is singular. void GetInverse( VRMATRIXSQ & vrmatResult, bool bUseTinyIfSingular = false ) const; // Get the determinant without modifying (LU decomposing) the matrix. // vrmatResult will contain the LU decomposed version of the matrix. void GetDblDeterminant( DBL& dblDeterm, VRMATRIXSQ & vrmatResult ) const; // Get the log of determinant without modifying (LU decomposing) the matrix. // vrmatResult will contain the LU decomposed version of the matrix. void GetDblLogDeterminant( DBL& dblLogDeterm, VRMATRIXSQ & vrmatResult) const; // Project a view of the matrix (see documentation below). VRMATRIXSQ VrmatrixProject ( const VIMD & vimdRowColumnRetain ) const; protected: int _iSign; VIMD _vimdRow; void LUDBackSub(const VRMATRIXSQ & matrix); }; /* How to use the VRMATRIX::Project() function. Original matrix: 1 2 3 4 5 6 7 8 9 The (0,2) projection is obtained by deleting the 2nd row and 2nd column: 1 3 7 9 The (0,1) projection is obtained by deleting the 3rd row (and third column): 1 2 4 5 The (1,2) projeciton is obtained by deleting the 1st row and 1st column: 5 6 8 9 The (0) projection is obtained by deleting the 2nd and 3rd rows and columns: 1 */ #endif