template<class T>
DenseMatrix<T>::DenseMatrix()
{
_RowCount = 0;
_ColCount = 0;
_Data = NULL;
}
template<class T>
DenseMatrix<T>::DenseMatrix(UINT Size)
{
_RowCount = 0;
_ColCount = 0;
_Data = NULL;
Allocate(Size, Size);
}
template<class T>
DenseMatrix<T>::DenseMatrix(UINT RowCount, UINT ColCount)
{
_RowCount = 0;
_ColCount = 0;
_Data = NULL;
Allocate(RowCount, ColCount);
}
template<class T>
DenseMatrix<T>::DenseMatrix(const DenseMatrix<T>&M)
{
_RowCount = 0;
_ColCount = 0;
_Data = NULL;
Allocate(M.RowCount(), M.ColCount());
memcpy(_Data, M._Data, sizeof(T) * M.RowCount() * M.ColCount());
}
template<class T>
DenseMatrix<T>::DenseMatrix(const SparseMatrix<T> &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<class T>
DenseMatrix<T>::~DenseMatrix()
{
FreeMemory();
}
template<class T>
void DenseMatrix<T>::FreeMemory()
{
if(_Data != NULL)
{
delete[] _Data;
_Data = NULL;
}
_RowCount = 0;
_ColCount = 0;
}
template<class T>
void DenseMatrix<T>::Allocate(UINT RowCount, UINT ColCount)
{
if(_RowCount != RowCount || _ColCount != ColCount)
{
_RowCount = RowCount;
_ColCount = ColCount;
_Data = new T[_RowCount * _ColCount];
}
}
template<class T>
void DenseMatrix<T>::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<class T>
void DenseMatrix<T>::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<class T>
void DenseMatrix<T>::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<class T>
void DenseMatrix<T>::LoadFromFile(const String &Filename)
{
Vector<String> Lines, Words;
Utility::GetFileLines(Filename, Lines);
UINT TargetColCount = 0;
Vector<T> AllData;
for(UINT LineIndex = 0; LineIndex < Lines.Length(); 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<T>::LoadFromFile");
}
for(UINT WordIndex = 0; WordIndex < TargetColCount; WordIndex++)
{
AllData.PushEnd(T(Words[WordIndex].ConvertToDouble()));
}
}
}
PersistentAssert(TargetColCount != 0 && AllData.Length() > 0, "Invalid file in DenseMatrix<T>::LoadFromFile");
Allocate(AllData.Length() / TargetColCount, TargetColCount);
memcpy(_Data, AllData.CArray(), sizeof(T) * AllData.Length());
}
template<class T>
void DenseMatrix<T>::ExtractRow(UINT Row, Vector<T> &Result)
{
Result.Allocate(_ColCount);
for(UINT Col = 0; Col < _ColCount; Col++)
{
Result[Col] = _Data[Row * _ColCount + Col];
}
}
template<class T>
void DenseMatrix<T>::ExtractCol(UINT Col, Vector<T> &Result)
{
Result.Allocate(_RowCount);
for(UINT Row = 0; Row < _RowCount; Row++)
{
Result[Row] = _Data[Row * _ColCount + Col];
}
}
template<class T>
Vector<T> DenseMatrix<T>::ExtractRow(UINT Row)
{
Vector<T> Result(_ColCount);
for(UINT Col = 0; Col < _ColCount; Col++)
{
Result[Col] = _Data[Row * _ColCount + Col];
}
return Result;
}
template<class T>
Vector<T> DenseMatrix<T>::ExtractCol(UINT Col)
{
Vector<T> Result(_RowCount);
for(UINT Row = 0; Row < _RowCount; Row++)
{
Result[Row] = _Data[Row * _ColCount + Col];
}
return Result;
}
template<class T>
void DenseMatrix<T>::Clear(T Value)
{
for(UINT Index = 0; Index < _RowCount * _ColCount; Index++)
{
_Data[Index] = Value;
}
}
template<class T>
DenseMatrix<T>& DenseMatrix<T>::operator = (const DenseMatrix<T>&M)
{
Allocate(M.RowCount(), M.ColCount());
memcpy(_Data, M._Data, sizeof(T) * M.RowCount() * M.ColCount());
return (*this);
}
template<class T>
DenseMatrix<T> DenseMatrix<T>::OuterProduct(const Vector<T> &A, const Vector<T> &B)
{
Assert(A.Length() == B.Length() && A.Length() != 0, "Invalid vector dimensions in DenseMatrix<T>::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<class T>
T DenseMatrix<T>::CompareMatrices(const DenseMatrix<T> &Left, const DenseMatrix<T> &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<class T>
void DenseMatrix<T>::LUSolve(Vector<T> &x, const Vector<T> &b)
{
Assert(Square() && b.Length() == _RowCount, "Invalid paramater DenseMatrix<T>::LUSolve");
Vector<T> y;
x.Allocate(b.Length());
y.Allocate(b.Length());
DenseMatrix<T> 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<class T>
void DenseMatrix<T>::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<class T>
void DenseMatrix<T>::LUDecomposition(DenseMatrix<T> &L, DenseMatrix<T> &U)
{
Assert(Square(), "DenseMatrix<T>::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<class T>
bool DenseMatrix<T>::VictorEigenSystem(Vector<T> &Eigenvalues, DenseMatrix<T> &Eigenvectors) const
{
PersistentAssert(Square(), "Eigensystem requires a square matrix");
const UINT N = _RowCount;
std::complex<double> *A = new std::complex<double>[N * N];
for(UINT Col = 0; Col < N; Col++)
{
for(UINT Row = 0; Row < N; Row++)
{
A[Col * N + Row] = std::complex<double>(Cell(Row, Col), 0.0);
}
}
std::complex<double> *evals = new std::complex<double>[N];
std::complex<double> *evecs = new std::complex<double>[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<class T>
bool DenseMatrix<T>::EigenSystem(Vector<T> &Eigenvalues, DenseMatrix<T> &Eigenvectors) const
{
const UINT Dimension = _RowCount;
Eigenvalues.Allocate(Dimension);
Eigenvectors.Allocate(Dimension, Dimension);
Vector<T*> EigenvectorList(Dimension);
for(UINT DimensionIndex = 0; DimensionIndex < Dimension; DimensionIndex++)
{
EigenvectorList[DimensionIndex] = Eigenvectors[DimensionIndex];
}
return EigenSystem(Eigenvalues.CArray(), EigenvectorList.CArray());
}
template<class T>
String DenseMatrix<T>::EigenTest(const Vector<T> &Eigenvalues, const DenseMatrix<T> &Eigenvectors) const
{
const UINT Dimension = _RowCount;
Vector<const T*> EigenvectorList(Dimension);
for(UINT DimensionIndex = 0; DimensionIndex < Dimension; DimensionIndex++)
{
EigenvectorList[DimensionIndex] = Eigenvectors[DimensionIndex];
}
return EigenTest(Eigenvalues.CArray(), EigenvectorList.CArray());
}
template<class T>
bool DenseMatrix<T>::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;
DenseMatrix<double> a(_RowCount);
for(UINT Row = 0; Row < _RowCount; Row++)
{
for(UINT Col = 0; Col < _ColCount; Col++)
{
a.Cell(Row, Col) = Cell(Row, Col);
}
}
if (n > 4)
{
b = new double[n];
z = new double[n];
}
for (ip=0; ip<n; ip++)
{
for (iq=0; iq<n; iq++)
{
Eigenvectors[ip][iq] = 0.0;
}
Eigenvectors[ip][ip] = 1.0;
}
for (ip=0; ip<n; ip++)
{
b[ip] = a[ip][ip];
Eigenvalues[ip] = T(a[ip][ip]);
z[ip] = 0.0;
}
for (i=0; i<VTK_MAX_ROTATIONS; i++)
{
sm = 0.0;
for (ip=0; ip<n-1; ip++)
{
for (iq=ip+1; iq<n; iq++)
{
sm += fabs(a[ip][iq]);
}
}
if (sm == 0.0)
{
break;
}
if (i < 3) {
tresh = 0.2*sm/(n*n);
}
else
{
tresh = 0.0;
}
for (ip=0; ip<n-1; ip++)
{
for (iq=ip+1; iq<n; iq++)
{
g = T(100.0*fabs(a[ip][iq]));
if (i > 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;
for (j = 0;j <= ip-1;j++)
{
VTK_ROTATE(a,j,ip,j,iq);
}
for (j = ip+1;j <= iq-1;j++)
{
VTK_ROTATE(a,ip,j,j,iq);
}
for (j=iq+1; j<n; j++)
{
VTK_ROTATE(a,ip,j,iq,j);
}
for (j=0; j<n; j++)
{
#pragma warning ( disable : 4244 )
VTK_ROTATE(Eigenvectors,j,ip,j,iq);
#pragma warning ( default : 4244 )
}
}
}
}
for (ip=0; ip<n; ip++)
{
b[ip] += z[ip];
Eigenvalues[ip] = T(b[ip]);
z[ip] = 0.0;
}
}
if ( i >= VTK_MAX_ROTATIONS )
{
SignalError("VTK_MAX_ROTATIONS exceeded");
return false;
}
for (j=0; j<n-1; j++) {
k = j;
tmp = Eigenvalues[k];
for (i=j+1; i<n; i++) {
if (Eigenvalues[i] >= tmp) {
k = i;
tmp = Eigenvalues[k];
}
}
if (k != j)
{
Eigenvalues[k] = Eigenvalues[j];
Eigenvalues[j] = T(tmp);
for (i=0; i<n; i++)
{
tmp = Eigenvectors[i][j];
Eigenvectors[i][j] = Eigenvectors[i][k];
Eigenvectors[i][k] = T(tmp);
}
}
}
int ceil_half_n = (n >> 1) + (n & 1);
for (j=0; j<n; j++)
{
for (numPos=0, i=0; i<n; i++)
{
if ( Eigenvectors[i][j] >= 0.0 )
{
numPos++;
}
}
if ( numPos < ceil_half_n)
{
for(i=0; i<n; i++)
{
Eigenvectors[i][j] *= -1.0;
}
}
}
if (n > 4)
{
delete [] b;
delete [] z;
}
return true;
}
template<class T>
String DenseMatrix<T>::EigenTest(const T *Eigenvalues, const T **Eigenvectors) const
{
const bool Verbose = false;
String Description;
PersistentAssert(Square() && _RowCount >= 2, "Invalid matrix dimensions");
Vector<T> 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<T>::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<class T>
T DenseMatrix<T>::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<class T>
DenseMatrix<T>DenseMatrix<T>::Inverse()
{
DenseMatrix<T>Result = *this;
Result.InvertInPlace();
return Result;
}
template<class T>
void DenseMatrix<T>::InvertInPlace()
{
Assert(Square(), "DenseMatrix<T>::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++)
{
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;
}
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);
}
}
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);
}
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;
}
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;
}
}
}
template<class T>
void DenseMatrix<T>::Identity()
{
Assert(Square(), "DenseMatrix<T>::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<class T>
void DenseMatrix<T>::Identity(UINT Size)
{
Allocate(Size, Size);
Identity();
}
template<class T>
bool DenseMatrix<T>::Square() const
{
return (_RowCount == _ColCount);
}
template<class T>
bool DenseMatrix<T>::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<class T>
DenseMatrix<T> DenseMatrix<T>::Transpose()
{
DenseMatrix<T> 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;
}
template<class T>
ostream& operator << (ostream &os, const DenseMatrix<T>&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<class T>
void DenseMatrix<T>::Multiply(Vector<T> &Result, const DenseMatrix<T>&Left, const Vector<T> &Right)
{
Assert(Left.ColCount() == Right.Length(), "Invalid dimensions in DenseMatrix<T>::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<class T>
void DenseMatrix<T>::Multiply(DenseMatrix<T>&Result, const DenseMatrix<T>&Left, const DenseMatrix<T>&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;
}
}
}
template<class T>
void DenseMatrix<T>::Multiply(DenseMatrix<T>&Result, const SparseMatrix<T> &Left, const DenseMatrix<T> &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<T> > &LeftRowEntries = Left.Rows()[RowIndex].Data;
const UINT LeftRowEntryCount = LeftRowEntries.Length();
for(UINT LeftColIndex = 0; LeftColIndex < LeftRowEntryCount; LeftColIndex++)
{
const SparseElement<T> &CurLeftEntry = LeftRowEntries[LeftColIndex];
for(UINT RightColIndex = 0; RightColIndex < ColCount; RightColIndex++)
{
Result.Cell(RowIndex, ColCount) += CurLeftEntry.Entry * Right.Cell(CurLeftEntry.Col, RightColIndex);
}
}
}
}
template<class T>
void DenseMatrix<T>::Multiply(DenseMatrix<T>&Result, const DenseMatrix<T>&Left, const SparseMatrix<T> &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<SparseElement> &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<class T>
void DenseMatrix<T>::MultiplyMMTranspose(DenseMatrix<T>&Result, const DenseMatrix<T>&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<class T>
void DenseMatrix<T>::MultiplyMMTranspose(DenseMatrix<T> &Result, const SparseMatrix<T> &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<class T>
void DenseMatrix<T>::MultiplyInPlace(DenseMatrix<T>&Result, T Right)
{
for(UINT Row = 0; Row < Result.RowCount(); Row++)
{
for(UINT Col = 0; Col < Result.ColCount(); Col++)
{
Result[Row][Col] *= Right;
}
}
}
template<class T>
DenseMatrix<T>operator * (const DenseMatrix<T>&Left, const DenseMatrix<T>&Right)
{
DenseMatrix<T>Result;
DenseMatrix<T>::Multiply(Result, Left, Right);
return Result;
}
template<class T>
DenseMatrix<T>operator * (const SparseMatrix<T> &Left, const DenseMatrix<T>&Right)
{
DenseMatrix<T>Result;
DenseMatrix<T>::Multiply(Result, Left, Right);
return Result;
}
template<class T>
DenseMatrix<T>operator * (const DenseMatrix<T>&Left, const SparseMatrix<T> &Right)
{
DenseMatrix<T>Result;
DenseMatrix<T>::Multiply(Result, Left, Right);
return Result;
}
template<class T>
DenseMatrix<T>operator * (const DenseMatrix<T>&Left, T Right)
{
DenseMatrix<T>Return(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<class T>
DenseMatrix<T>operator * (T Right, const DenseMatrix<T>&Left)
{
DenseMatrix<T>Return(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<class T>
DenseMatrix<T>operator + (const DenseMatrix<T>&Left, const DenseMatrix<T>&Right)
{
Assert(Left.RowCount() == Right.RowCount() && Left.ColCount() == Right.ColCount(), "Invalid dimensions on Matrix4 addition.");
DenseMatrix<T>Return(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<class T>
DenseMatrix<T>operator - (const DenseMatrix<T>&Left, const DenseMatrix<T>&Right)
{
Assert(Left.RowCount() == Right.RowCount() && Left.ColCount() == Right.ColCount(), "Invalid dimensions on Matrix4 addition.");
DenseMatrix<T>Return(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);
DenseMatrix<float>M(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;
}
}
}