template DenseMatrix::DenseMatrix() { _RowCount = 0; _ColCount = 0; _Data = NULL; } template DenseMatrix::DenseMatrix(UINT Size) { _RowCount = 0; _ColCount = 0; _Data = NULL; Allocate(Size, Size); } template DenseMatrix::DenseMatrix(UINT RowCount, UINT ColCount) { _RowCount = 0; _ColCount = 0; _Data = NULL; Allocate(RowCount, ColCount); } template DenseMatrix::DenseMatrix(const DenseMatrix&M) { _RowCount = 0; _ColCount = 0; _Data = NULL; Allocate(M.RowCount(), M.ColCount()); memcpy(_Data, M._Data, sizeof(T) * M.RowCount() * M.ColCount()); } template DenseMatrix::DenseMatrix(const SparseMatrix &M) { _RowCount = 0; _ColCount = 0; _Data = NULL; Allocate(M.RowCount(), M.ColCount()); for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { Cell(Row, Col) = M.GetElement(Row, Col); } } } template DenseMatrix::~DenseMatrix() { FreeMemory(); } template void DenseMatrix::FreeMemory() { //_Data.FreeMemory(); if(_Data != NULL) { delete[] _Data; _Data = NULL; } _RowCount = 0; _ColCount = 0; } template void DenseMatrix::Allocate(UINT RowCount, UINT ColCount) { if(_RowCount != RowCount || _ColCount != ColCount) { _RowCount = RowCount; _ColCount = ColCount; _Data = new T[_RowCount * _ColCount]; //_Data.Allocate(_RowCount * _ColCount); } } template void DenseMatrix::WriteToStream(ostream &os, char Delimeter) const { for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { os << Cell(Row, Col); if(Col != _ColCount - 1) { os << Delimeter; } } os << endl; } } template void DenseMatrix::WriteMathematicaToStream(ostream &os, const String &MatrixName) const { os << setprecision(16) << setiosflags(ios::right | ios::fixed); os << MatrixName << "={" << endl; for(UINT Row = 0; Row < _RowCount; Row++) { os << " {"; for(UINT Col = 0; Col < _ColCount; Col++) { os << Cell(Row, Col); if(Col != _ColCount - 1) { os << ","; } } if(Row == _RowCount - 1) { os << "}};" << endl; } else { os << "}," << endl; } } } template void DenseMatrix::SaveToMATLAB(const String &Filename) const { ofstream File(Filename.CString()); for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { File << Cell(Row, Col); if(Col != _ColCount - 1) { File << '\t'; } } File << endl; } } template void DenseMatrix::LoadFromFile(const String &Filename) { Vector Lines, Words; Utility::GetFileLines(Filename, Lines); UINT TargetColCount = 0; Vector AllData; for(UINT LineIndex = 0; LineIndex < Lines.Length(); LineIndex++) //for(UINT LineIndex = 0; LineIndex < 1000; LineIndex++) { const String &CurLine = Lines[LineIndex]; if(CurLine.Length() > 2) { CurLine.Partition(' ', Words); if(TargetColCount == 0) { TargetColCount = Words.Length(); } else { Assert(TargetColCount == Words.Length(), "Invalid file in DenseMatrix::LoadFromFile"); } for(UINT WordIndex = 0; WordIndex < TargetColCount; WordIndex++) { AllData.PushEnd(T(Words[WordIndex].ConvertToDouble())); } } } PersistentAssert(TargetColCount != 0 && AllData.Length() > 0, "Invalid file in DenseMatrix::LoadFromFile"); Allocate(AllData.Length() / TargetColCount, TargetColCount); memcpy(_Data, AllData.CArray(), sizeof(T) * AllData.Length()); /*for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { } }*/ } template void DenseMatrix::ExtractRow(UINT Row, Vector &Result) { Result.Allocate(_ColCount); for(UINT Col = 0; Col < _ColCount; Col++) { Result[Col] = _Data[Row * _ColCount + Col]; } } template void DenseMatrix::ExtractCol(UINT Col, Vector &Result) { Result.Allocate(_RowCount); for(UINT Row = 0; Row < _RowCount; Row++) { Result[Row] = _Data[Row * _ColCount + Col]; } } template Vector DenseMatrix::ExtractRow(UINT Row) { Vector Result(_ColCount); for(UINT Col = 0; Col < _ColCount; Col++) { Result[Col] = _Data[Row * _ColCount + Col]; } return Result; } template Vector DenseMatrix::ExtractCol(UINT Col) { Vector Result(_RowCount); for(UINT Row = 0; Row < _RowCount; Row++) { Result[Row] = _Data[Row * _ColCount + Col]; } return Result; } template void DenseMatrix::Clear(T Value) { for(UINT Index = 0; Index < _RowCount * _ColCount; Index++) { _Data[Index] = Value; } } template DenseMatrix& DenseMatrix::operator = (const DenseMatrix&M) { Allocate(M.RowCount(), M.ColCount()); memcpy(_Data, M._Data, sizeof(T) * M.RowCount() * M.ColCount()); return (*this); } template DenseMatrix DenseMatrix::OuterProduct(const Vector &A, const Vector &B) { Assert(A.Length() == B.Length() && A.Length() != 0, "Invalid vector dimensions in DenseMatrix::OuterProduct"); const UINT Size = A.Length(); DenseMatrix Result, AMat(Size, 1), BMat(1, Size); for(UINT Index = 0; Index < Size; Index++) { AMat[Index][0] = A[Index]; BMat[0][Index] = B[Index]; } DenseMatrix::Multiply(Result, AMat, BMat); return Result; } template T DenseMatrix::CompareMatrices(const DenseMatrix &Left, const DenseMatrix &Right) { T Result = T(0.0); UINT RowCount = Left.RowCount(); UINT ColCount = Left.ColCount(); for(UINT Row = 0; Row < RowCount; Row++) { for(UINT Col = 0; Col < ColCount; Col++) { Result += Math::Abs(Left[Row][Col] - Right[Row][Col]); } } return Result; } template void DenseMatrix::LUSolve(Vector &x, const Vector &b) { Assert(Square() && b.Length() == _RowCount, "Invalid paramater DenseMatrix::LUSolve"); Vector y; x.Allocate(b.Length()); y.Allocate(b.Length()); DenseMatrix L, U, Copy; Copy = *this; Copy.LUDecomposition(L, U); for(UINT i = 0; i < _RowCount; i++) { T Sum = 0.0f; for(UINT j = 0; j < i; j++) { Sum += L[i][j] * y[j]; } y[i] = b[i] - Sum; } for(int i = _RowCount - 1; i >= 0; i--) { T Sum = 0.0; for(int j = i + 1; j < int(_RowCount); j++) { Sum += U[i][j] * x[j]; } x[i] = (y[i] - Sum) / U[i][i]; } } template void DenseMatrix::operator += (const DenseMatrix &M) { Assert(M._RowCount == _RowCount && M._ColCount == _ColCount, "Invalid matrix dimensions"); for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { (*this)[Row][Col] += M[Row][Col]; } } } template void DenseMatrix::LUDecomposition(DenseMatrix &L, DenseMatrix &U) { Assert(Square(), "DenseMatrix::LUDecomposition called on non-square matrix"); L.Identity(_RowCount); U.Identity(_RowCount); for(UINT k = 0; k < _RowCount; k++) { U[k][k] = Cell(k, k); for(UINT i = k; i < _RowCount; i++) { L[i][k] = Cell(i, k) / U[k][k]; U[k][i] = Cell(k, i); } for(UINT i = k; i < _RowCount; i++) { for(UINT j = k; j < _RowCount; j++) { Cell(i, j) -= L[i][k] * U[k][j]; } } } } template bool DenseMatrix::VictorEigenSystem(Vector &Eigenvalues, DenseMatrix &Eigenvectors) const { PersistentAssert(Square(), "Eigensystem requires a square matrix"); const UINT N = _RowCount; std::complex *A = new std::complex[N * N]; for(UINT Col = 0; Col < N; Col++) { for(UINT Row = 0; Row < N; Row++) { A[Col * N + Row] = std::complex(Cell(Row, Col), 0.0); } } std::complex *evals = new std::complex[N]; std::complex *evecs = new std::complex[N * N]; size_t nrot; size_t MaxIterations = (int)(2 + 2.8 * log((double)N) / log(2.0)); if(MaxIterations < 8) { MaxIterations = 8; } Console::WriteLine(String("Eigensystem solve, sweeps: ") + String(MaxIterations)); RNP::Eigensystem(N, A, N, evals, evecs, N, MaxIterations, &nrot); Eigenvalues.Allocate(N); Eigenvectors.Allocate(N, N); for(UINT Col = 0; Col < N; Col++) { Eigenvalues[Col] = evals[Col].real(); for(UINT Row = 0; Row < N; Row++) { Eigenvectors.Cell(Row, Col) = evecs[Col * N + Row].real(); } } delete [] A; delete [] evecs; delete [] evals; return true; } #define VTK_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\ a[k][l]=h+s*(g-h*tau) #define VTK_MAX_ROTATIONS 20 template bool DenseMatrix::EigenSystem(Vector &Eigenvalues, DenseMatrix &Eigenvectors) const { const UINT Dimension = _RowCount; Eigenvalues.Allocate(Dimension); Eigenvectors.Allocate(Dimension, Dimension); Vector EigenvectorList(Dimension); for(UINT DimensionIndex = 0; DimensionIndex < Dimension; DimensionIndex++) { EigenvectorList[DimensionIndex] = Eigenvectors[DimensionIndex]; } return EigenSystem(Eigenvalues.CArray(), EigenvectorList.CArray()); } template String DenseMatrix::EigenTest(const Vector &Eigenvalues, const DenseMatrix &Eigenvectors) const { const UINT Dimension = _RowCount; Vector EigenvectorList(Dimension); for(UINT DimensionIndex = 0; DimensionIndex < Dimension; DimensionIndex++) { EigenvectorList[DimensionIndex] = Eigenvectors[DimensionIndex]; } return EigenTest(Eigenvalues.CArray(), EigenvectorList.CArray()); } // // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn // real symmetric matrix. Square nxn matrix a; size of matrix in n; // output eigenvalues in w; and output eigenvectors in Eigenvectors. Resulting // eigenvalues/vectors are sorted in decreasing order; eigenvectors are // normalized. // // Code modified from VTK vtkJacobiN function // template bool DenseMatrix::EigenSystem(T *Eigenvalues, T **Eigenvectors) const { PersistentAssert(Square() && _RowCount >= 2, "Invalid matrix dimensions"); int i, j, k, iq, ip, numPos, n = int(_RowCount); double tresh, theta, tau, t, sm, s, h, g, c, tmp; double bspace[4], zspace[4]; double *b = bspace; double *z = zspace; // // Jacobi iteration destroys the matrix so create a temporary copy // DenseMatrix a(_RowCount); for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { a.Cell(Row, Col) = Cell(Row, Col); } } // // only allocate memory if the matrix is large // if (n > 4) { b = new double[n]; z = new double[n]; } // // initialize // for (ip=0; ip 3 && (fabs(Eigenvalues[ip])+g) == fabs(Eigenvalues[ip]) && (fabs(Eigenvalues[iq])+g) == fabs(Eigenvalues[iq])) { a[ip][iq] = 0.0; } else if (fabs(a[ip][iq]) > tresh) { h = Eigenvalues[iq] - Eigenvalues[ip]; if ( (fabs(h)+g) == fabs(h)) { t = (a[ip][iq]) / h; } else { theta = 0.5*h / (a[ip][iq]); t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta)); if (theta < 0.0) { t = -t; } } c = 1.0 / sqrt(1+t*t); s = t*c; tau = s/(1.0+c); h = t*a[ip][iq]; z[ip] -= h; z[iq] += h; Eigenvalues[ip] -= T(h); Eigenvalues[iq] += T(h); a[ip][iq] = 0.0; // ip already shifted left by 1 unit for (j = 0;j <= ip-1;j++) { VTK_ROTATE(a,j,ip,j,iq); } // ip and iq already shifted left by 1 unit for (j = ip+1;j <= iq-1;j++) { VTK_ROTATE(a,ip,j,j,iq); } // iq already shifted left by 1 unit for (j=iq+1; j= VTK_MAX_ROTATIONS ) { SignalError("VTK_MAX_ROTATIONS exceeded"); return false; } // sort eigenfunctions these changes do not affect accuracy for (j=0; j= tmp) // why exchage if same? { k = i; tmp = Eigenvalues[k]; } } if (k != j) { Eigenvalues[k] = Eigenvalues[j]; Eigenvalues[j] = T(tmp); for (i=0; i> 1) + (n & 1); for (j=0; j= 0.0 ) { numPos++; } } // if ( numPos < ceil(double(n)/double(2.0)) ) if ( numPos < ceil_half_n) { for(i=0; i 4) { delete [] b; delete [] z; } return true; } template String DenseMatrix::EigenTest(const T *Eigenvalues, const T **Eigenvectors) const { const bool Verbose = false; String Description; PersistentAssert(Square() && _RowCount >= 2, "Invalid matrix dimensions"); Vector Eigenvector(_RowCount), Result; double MaxError = 0.0; for(UINT EigenIndex = 0; EigenIndex < _RowCount; EigenIndex++) { for(UINT ElementIndex = 0; ElementIndex < _RowCount; ElementIndex++) { Eigenvector[ElementIndex] = Eigenvectors[ElementIndex][EigenIndex]; } DenseMatrix::Multiply(Result, *this, Eigenvector); double Error = 0.0; T CurEigenvalue = Eigenvalues[EigenIndex]; for(UINT ElementIndex = 0; ElementIndex < _RowCount; ElementIndex++) { Error += Math::Abs(Eigenvector[ElementIndex] * CurEigenvalue - Result[ElementIndex]); } if(Verbose) { Description += String("Eigenvector ") + String(EigenIndex) + String(" absolute error: ") + String(Error) + String("\n"); } MaxError = Math::Max(Error, MaxError); } Description += String("Max eigenvector error: ") + String(MaxError) + String("\n"); return Description; } template T DenseMatrix::Determinant() { Assert(Square(), "Determinant called on non-square matrix"); if(_RowCount == 2) { return Cell(0, 0) * Cell(1, 1) - Cell(1, 0) * Cell(0, 1); } else if(_RowCount == 3) { return (Cell(0, 0) * Cell(1, 1) * Cell(2, 2) + Cell(0, 1) * Cell(1, 2) * Cell(2, 0) + Cell(0, 2) * Cell(1, 0) * Cell(2, 1)) - (Cell(2, 0) * Cell(1, 1) * Cell(0, 2) + Cell(2, 1) * Cell(1, 2) * Cell(0, 0) + Cell(2, 2) * Cell(1, 0) * Cell(0, 1)); } else { SignalError("Not implemented"); return 0.0f; } } template DenseMatrixDenseMatrix::Inverse() { DenseMatrixResult = *this; Result.InvertInPlace(); return Result; } template void DenseMatrix::InvertInPlace() { Assert(Square(), "DenseMatrix::Invert called on non-square matrix"); for (UINT i = 1; i < _RowCount; i++) { Cell(0, i) /= Cell(0, 0); } for (UINT i = 1; i < _RowCount; i++) { // // do a column of L // for (UINT j = i; j < _RowCount; j++) { T Sum = 0.0f; for (UINT k = 0; k < i; k++) { Sum += Cell(j, k) * Cell(k, i); } Cell(j, i) -= Sum; } if (i == _RowCount - 1) { continue; } // // do a row of U // for (UINT j = i + 1; j < _RowCount; j++) { T Sum = 0.0f; for (UINT k = 0; k < i; k++) Sum += Cell(i, k) * Cell(k, j); Cell(i, j) = (Cell(i, j) - Sum) / Cell(i, i); } } // // invert L // for (UINT i = 0; i < _RowCount; i++) for (UINT j = i; j < _RowCount; j++) { T Sum = 1.0f; if ( i != j ) { Sum = 0.0f; for (UINT k = i; k < j; k++ ) { Sum -= Cell(j, k) * Cell(k, i); } } Cell(j, i) = Sum / Cell(j, j); } // // invert U // for (UINT i = 0; i < _RowCount; i++) for (UINT j = i; j < _RowCount; j++) { if ( i == j ) { continue; } T Sum = 0.0f; for (UINT k = i; k < j; k++) { T Val = 1.0f; if(i != k) { Val = Cell(i, k); } Sum += Cell(k, j) * Val; } Cell(i, j) = -Sum; } // // final inversion // for (UINT i = 0; i < _RowCount; i++) { for (UINT j = 0; j < _RowCount; j++) { T Sum = 0.0f; UINT Larger = j; if(i > j) { Larger = i; } for (UINT k = Larger; k < _RowCount; k++) { T Val = 1.0f; if(j != k) { Val = Cell(j, k); } Sum += Val * Cell(k, i); } Cell(j, i) = Sum; } } //Assert(ElementsValid(), "Degenerate Matrix inversion."); } template void DenseMatrix::Identity() { Assert(Square(), "DenseMatrix::Identity called on non-square Matrix4."); for(UINT i = 0; i < _RowCount; i++) { for(UINT i2 = 0; i2 < _RowCount; i2++) { if(i == i2) { Cell(i, i2) = 1.0f; } else { Cell(i, i2) = 0.0f; } } } } template void DenseMatrix::Identity(UINT Size) { Allocate(Size, Size); Identity(); } template bool DenseMatrix::Square() const { return (_RowCount == _ColCount); } template bool DenseMatrix::ElementsValid() { for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { if(Cell(Row, Col) != Cell(Row, Col)) { return false; } } } return true; } template DenseMatrix DenseMatrix::Transpose() { DenseMatrix Result; Result.Allocate(_ColCount, _RowCount); for(UINT i = 0; i < _RowCount; i++) { for(UINT i2 = 0; i2 < _ColCount; i2++) { Result.Cell(i2, i) = Cell(i, i2); } } return Result; } /*ostream& operator << (ostream &os, const DenseMatrix&m) { UINT n = m.RowCount(); //os << setprecision(8) << setiosflags(ios::right | ios::showpoint); os << "{"; for(UINT i=0;i ostream& operator << (ostream &os, const DenseMatrix&m) { Assert(m.Square(), "Output not correct for non-square matrices."); UINT n = m.RowCount(); os << setprecision(8) << setiosflags(ios::right | ios::showpoint); for(UINT i = 0; i < n; i++) { for(UINT i2 = 0; i2 < n; i2++) { os << setw(12) << m[i][i2]; } os << endl; } return os; } template void DenseMatrix::Multiply(Vector &Result, const DenseMatrix&Left, const Vector &Right) { Assert(Left.ColCount() == Right.Length(), "Invalid dimensions in DenseMatrix::Multiply"); Result.Allocate(Left.RowCount()); for(UINT Row = 0; Row < Result.Length(); Row++) { T Total = 0.0; for(UINT Index = 0; Index < Left.ColCount(); Index++) { Total += Left.Cell(Row, Index) * Right[Index]; } Result[Row] = Total; } } template void DenseMatrix::Multiply(DenseMatrix&Result, const DenseMatrix&Left, const DenseMatrix&Right) { Assert(Left.ColCount() == Right.RowCount(), "Invalid matrix dimensions on SetProduct"); const UINT RowCount = Left.RowCount(); const UINT ColCount = Right.ColCount(); Result.Allocate(RowCount, ColCount); for(UINT RowIndex = 0; RowIndex < RowCount; RowIndex++) { for(UINT ColIndex = 0; ColIndex < ColCount; ColIndex++) { T Total = 0.0; for(UINT InnerIndex = 0; InnerIndex < Left.ColCount(); InnerIndex++) { Total += Left.Cell(RowIndex, InnerIndex) * Right.Cell(InnerIndex, ColIndex); } Result[RowIndex][ColIndex] = Total; } } } /*void SparseMatrix::Multiply(SparseMatrix &A, const SparseMatrix &B, const SparseMatrix &C) { Assert(B.ColCount() == C.RowCount(), "Invalid matrix multiply dimensions."); A.Allocate(B.RowCount(), C.ColCount()); for(UINT BRow = 0; BRow < B.RowCount(); BRow++) { UINT BRowLength = B.Rows()[BRow].Data.Length(); for(UINT BColIndex = 0; BColIndex < BRowLength; BColIndex++) { const SparseElement *BElement = &B.Rows()[BRow].Data[BColIndex]; UINT j = BElement->Col; T BEntry = BElement->Entry; UINT CRowLength = C.Rows()[j].Data.Length(); for(UINT CRowIndex = 0; CRowIndex < CRowLength; CRowIndex++) { const SparseElement *CElement = &C.Rows()[j].Data[CRowIndex]; UINT k = CElement->Col; T CEntry = CElement->Entry; A.PushElement(BRow, k, BEntry * CEntry); } } } }*/ template void DenseMatrix::Multiply(DenseMatrix&Result, const SparseMatrix &Left, const DenseMatrix &Right) { Assert(Left.ColCount() == Right.RowCount(), "Invalid matrix dimensions"); const UINT RowCount = Left.RowCount(); const UINT ColCount = Right.ColCount(); const UINT InnerCount = Left.ColCount(); Result.Allocate(RowCount, ColCount); Result.Clear(0.0); for(UINT RowIndex = 0; RowIndex < RowCount; RowIndex++) { const Vector< SparseElement > &LeftRowEntries = Left.Rows()[RowIndex].Data; const UINT LeftRowEntryCount = LeftRowEntries.Length(); for(UINT LeftColIndex = 0; LeftColIndex < LeftRowEntryCount; LeftColIndex++) { const SparseElement &CurLeftEntry = LeftRowEntries[LeftColIndex]; for(UINT RightColIndex = 0; RightColIndex < ColCount; RightColIndex++) { Result.Cell(RowIndex, ColCount) += CurLeftEntry.Entry * Right.Cell(CurLeftEntry.Col, RightColIndex); } } } } template void DenseMatrix::Multiply(DenseMatrix&Result, const DenseMatrix&Left, const SparseMatrix &Right) { Assert(Left.ColCount() == Right.RowCount(), "Invalid matrix dimensions"); const UINT RowCount = Left.RowCount(); const UINT ColCount = Right.ColCount(); const UINT InnerCount = Left.ColCount(); Result.Allocate(RowCount, ColCount); Result.Clear(0.0); for(UINT RowIndex = 0; RowIndex < RowCount; RowIndex++) { for(UINT LeftColIndex = 0; LeftColIndex < InnerCount; LeftColIndex++) { T LeftEntry = Left.Cell(RowIndex, LeftColIndex); const Vector &RightRowEntries = Right.Rows()[LeftColIndex].Data; const UINT RightRowEntryCount = RightRowEntries.Length(); for(UINT RightRowIndex = 0; RightRowIndex < RightRowEntryCount; RightRowIndex++) { const SparseElement &CurRightEntry = RightRowEntries[RightRowIndex]; Result.Cell(RowIndex, CurRightEntry.Col) += LeftEntry * CurRightEntry.Entry; } } } } template void DenseMatrix::MultiplyMMTranspose(DenseMatrix&Result, const DenseMatrix&M) { const UINT RowCount = M.RowCount(); const UINT ColCount = M.ColCount(); Result.Allocate(RowCount, RowCount); for(UINT i = 0; i < RowCount; i++) { for(UINT i2 = 0; i2 < RowCount; i2++) { T Total = 0.0; for(UINT i3 = 0; i3 < ColCount; i3++) { Total += M.Cell(i, i3) * M.Cell(i2, i3); } Result.Cell(i, i2) = Total; } } } template void DenseMatrix::MultiplyMMTranspose(DenseMatrix &Result, const SparseMatrix &M) { const UINT RowCount = M.RowCount(); const UINT ColCount = M.ColCount(); Result.Allocate(RowCount, RowCount); for(UINT i = 0; i < RowCount; i++) { for(UINT i2 = 0; i2 < RowCount; i2++) { T Total = 0.0; for(UINT i3 = 0; i3 < ColCount; i3++) { Total += M.GetElement(i, i3) * M.GetElement(i2, i3); } Result.Cell(i, i2) = Total; } } } template void DenseMatrix::MultiplyInPlace(DenseMatrix&Result, T Right) { for(UINT Row = 0; Row < Result.RowCount(); Row++) { for(UINT Col = 0; Col < Result.ColCount(); Col++) { Result[Row][Col] *= Right; } } } template DenseMatrixoperator * (const DenseMatrix&Left, const DenseMatrix&Right) { DenseMatrixResult; DenseMatrix::Multiply(Result, Left, Right); return Result; } template DenseMatrixoperator * (const SparseMatrix &Left, const DenseMatrix&Right) { DenseMatrixResult; DenseMatrix::Multiply(Result, Left, Right); return Result; } template DenseMatrixoperator * (const DenseMatrix&Left, const SparseMatrix &Right) { DenseMatrixResult; DenseMatrix::Multiply(Result, Left, Right); return Result; } template DenseMatrixoperator * (const DenseMatrix&Left, T Right) { DenseMatrixReturn(Left.RowCount(), Left.ColCount()); for(UINT Row = 0; Row < Left.RowCount(); Row++) { for(UINT Col = 0; Col < Left.ColCount(); Col++) { Return[Row][Col] = Left[Row][Col] * Right; } } return Return; } template DenseMatrixoperator * (T Right, const DenseMatrix&Left) { DenseMatrixReturn(Left.RowCount(), Left.ColCount()); for(UINT Row = 0; Row < Left.RowCount(); Row++) { for(UINT Col = 0; Col < Left.ColCount(); Col++) { Return[Row][Col] = Left[Row][Col] * Right; } } return Return; } template DenseMatrixoperator + (const DenseMatrix&Left, const DenseMatrix&Right) { Assert(Left.RowCount() == Right.RowCount() && Left.ColCount() == Right.ColCount(), "Invalid dimensions on Matrix4 addition."); DenseMatrixReturn(Left.RowCount(), Left.ColCount()); for(UINT Row = 0; Row < Left.RowCount(); Row++) { for(UINT Col = 0; Col < Left.ColCount(); Col++) { Return[Row][Col] = Left[Row][Col] + Right[Row][Col]; } } return Return; } template DenseMatrixoperator - (const DenseMatrix&Left, const DenseMatrix&Right) { Assert(Left.RowCount() == Right.RowCount() && Left.ColCount() == Right.ColCount(), "Invalid dimensions on Matrix4 addition."); DenseMatrixReturn(Left.RowCount(), Left.ColCount()); for(UINT Row = 0; Row < Left.RowCount(); Row++) { for(UINT Col = 0; Col < Left.ColCount(); Col++) { Return[Row][Col] = Left[Row][Col] - Right[Row][Col]; } } return Return; } namespace Math { __forceinline void ReorientBasis(Vec3f &_V1, const Vec3f &_V2, const Vec3f &_V3) { Vec3f V1 = Vec3f::Normalize(_V1); Vec3f V2 = Vec3f::Normalize(_V2); Vec3f V3 = Vec3f::Normalize(_V3); DenseMatrixM(3); M[0][0] = V1.x; M[1][0] = V1.y; M[2][0] = V1.z; M[0][1] = V2.x; M[1][1] = V2.y; M[2][1] = V2.z; M[0][2] = V3.x; M[1][2] = V3.y; M[2][2] = V3.z; if(M.Determinant() < 0.0f) { _V1 = -V1; } } }