/* SparseMatrix.cpp Written by Matthew Fisher */ #pragma once template void SparseRow::FreeMemory() { Data.FreeMemory(); } template bool SparseRow::FindElement(UINT Col, const SparseElement* &Output) const { for(UINT i = 0; i < Data.Length(); i++) { if(Data[i].Col == Col) { Output = &Data[i]; return true; } } return false; } template bool SparseRow::FindElement(UINT Col, SparseElement* &Output) { for(UINT i = 0; i < Data.Length(); i++) { if(Data[i].Col == Col) { Output = &Data[i]; return true; } } return false; } template void SparseRow::PushElement(UINT Col, T Entry) { if(Entry == 0.0) { return; } SparseElement *Element; if(FindElement(Col, Element)) { Element->Entry += Entry; } else { SparseElement NewElement; NewElement.Col = Col; NewElement.Entry = Entry; Data.PushEnd(NewElement); } } template void SparseMatrix::Allocate(UINT Size) { Allocate(Size, Size); } template void SparseMatrix::Allocate(UINT NRowCount, UINT NColCount) { _RowCount = NRowCount; _ColCount = NColCount; _Rows.Allocate(NRowCount); } template void SparseMatrix::Init(const Vector &DiagonalEntries) { Allocate(DiagonalEntries.Length()); for(UINT i = 0; i < DiagonalEntries.Length(); i++) { PushElement(i, i, DiagonalEntries[i]); } } template UINT SparseMatrix::TotalElements() { UINT Result = 0; for(UINT i = 0; i < _RowCount; i++) { Result += _Rows[i].Data.Length(); } return Result; } template void SparseMatrix::PushElement(UINT Row, UINT Col, T Entry) { Assert(Row < _RowCount && Col < _ColCount, "Invalid element added."); _Rows[Row].PushElement(Col, Entry); } template T SparseMatrix::Compare(const SparseMatrix &In) { Assert(In._RowCount == _RowCount && In._ColCount == _ColCount, "Invalid size."); T Sum = 0.0; for(UINT i = 0; i < _RowCount; i++) { for(UINT i2 = 0; i2 < _Rows[i].Data.Length(); i2++) { SparseElement *CurElement = &_Rows[i].Data[i2]; const SparseElement *Output; bool Success = In._Rows[i].FindElement(CurElement->Col, Output); Assert(Success, "FindElement failed."); Sum += Math::Abs(Output->Entry - CurElement->Entry); } } return Sum; } template SparseMatrix SparseMatrix::DiagonalInverse() const { SparseMatrix Result = *this; Assert(Square(), "DiagonalInverse failure, matrix not square."); for(UINT i = 0; i < _RowCount; i++) { if(Result._Rows[i].Data.Length() > 0) { Assert(Result._Rows[i].Data.Length() == 1 && Result._Rows[i].Data[0].Col == i, "DiagonalInverse failure, matrix not diagonal."); Result._Rows[i].Data[0].Entry = 1.0f / Result._Rows[i].Data[0].Entry; } } return Result; } template SparseMatrix SparseMatrix::Transpose() const { SparseMatrix O; const SparseElement *Element; O.Rows().FreeMemory(); O.Allocate(_ColCount, _RowCount); for(UINT i = 0; i < _RowCount; i++) { for(UINT i2 = 0; i2 < _Rows[i].Data.Length(); i2++) { Element = &_Rows[i].Data[i2]; O.PushElement(Element->Col, i, Element->Entry); } } return O; } template void SparseMatrix::Dump(ostream &os, bool Sparse) { if(Sparse) { for(UINT Row = 0; Row < _RowCount; Row++) { const SparseRow &CurRow = _Rows[Row]; for(UINT ColEntry = 0; ColEntry < CurRow.Data.Length(); ColEntry++) { const SparseElement &CurEntry = CurRow.Data[ColEntry]; os << CurEntry.Entry << '\t'; } os << endl; } } else { for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT Col = 0; Col < _ColCount; Col++) { SparseElement *Element; T Value = 0.0; if(_Rows[Row].FindElement(Col, Element)) { Value = Element->Entry; } os << Value << '\t'; } os << endl; } } } template bool SparseMatrix::Square() const { return (_RowCount == _ColCount); } template bool SparseMatrix::Symmetric() const { PersistentAssert(Square(), "Only square matrices can be symmetric."); for(UINT i = 0; i < _RowCount; i++) { UINT Entries = _Rows[i].Data.Length(); for(UINT i2 = 0; i2 < Entries; i2++) { const SparseElement *Element = &_Rows[i].Data[i2]; const SparseElement *OtherElement = NULL; if(Element->Entry != 0.0) { PersistentAssert(Element->Entry == Element->Entry, "Invalid entry in matrix"); if(!_Rows[Element->Col].FindElement(i, OtherElement)) { Console::WriteLine("SparseMatrix::Symmetric: Other element not found"); return false; } if(fabs(OtherElement->Entry - Element->Entry) > 1e-5) { Console::WriteLine("Other element does not match."); return false; } } } } return true; } template void SparseMatrix::MathematicaDump(ostream &os, bool Sparse) const { os << setiosflags(ios_base::fixed); os << setprecision(10); if(Sparse) { os << "SparseArray[{"; for(UINT Row = 0; Row < _RowCount; Row++) { for(UINT i = 0; i < _Rows[Row].Data.Length(); i++) { const SparseElement *Element = &_Rows[Row].Data[i]; os << "{" << Row + 1 << "," << Element->Col + 1 << "}->" << Element->Entry; if(Row != _RowCount - 1 || i != _Rows[Row].Data.Length() - 1) { os << ","; } } os << endl; } os << "}, {" << _RowCount << ", " << _ColCount << "}]"; } else { os << "{"; for(UINT Row = 0; Row < _RowCount; Row++) { os << "{"; for(UINT Col = 0; Col < _ColCount; Col++) { const SparseElement *Element; T Value = 0.0; if(_Rows[Row].FindElement(Col, Element)) { Value = Element->Entry; } os << Value; if(Col != _ColCount - 1) { os << ", "; } } os << "}"; if(Row != _RowCount - 1) { os << ","; } os << endl; } os << "}"; } } template SparseMatrix::SparseMatrix() { _RowCount = 0; _ColCount = 0; } template SparseMatrix::SparseMatrix(UINT Size) { Allocate(Size, Size); } template SparseMatrix::SparseMatrix(UINT RowCount, UINT ColCount) { Allocate(RowCount, ColCount); } template SparseMatrix::SparseMatrix(const SparseMatrix &M) { Allocate(M._RowCount, M._ColCount); for(UINT i = 0; i < _RowCount; i++) { _Rows[i] = M._Rows[i]; } } template SparseMatrix::~SparseMatrix() { FreeMemory(); } template void SparseMatrix::FreeMemory() { for(UINT i = 0; i < _Rows.Length(); i++) { _Rows[i].FreeMemory(); } _Rows.FreeMemory(); _RowCount = 0; _ColCount = 0; } template SparseMatrix& SparseMatrix::operator = (const SparseMatrix &M) { Allocate(M._RowCount, M._ColCount); for(UINT i = 0; i < _RowCount; i++) { _Rows[i] = M._Rows[i]; } return *this; } template SparseMatrix& SparseMatrix::operator *= (T Scale) { Multiply(*this, Scale); return *this; } template void SparseMatrix::Add(SparseMatrix &A, const SparseMatrix &B, const SparseMatrix &C) { Assert(B.RowCount() == C.RowCount() && B.ColCount() == C.ColCount(), "Invalid matrix addition dimensions."); A.Allocate(B.RowCount(), C.ColCount()); for(UINT i = 0; i < B.RowCount(); i++) { for(UINT i2 = 0; i2 < B.Rows()[i].Data.Length(); i2++) { const SparseElement *Element = &B.Rows()[i].Data[i2]; A.PushElement(i, Element->Col, Element->Entry); } for(UINT i2 = 0; i2 < C.Rows()[i].Data.Length(); i2++) { const SparseElement *Element = &C.Rows()[i].Data[i2]; A.PushElement(i, Element->Col, Element->Entry); } } } template void SparseMatrix::Subtract(SparseMatrix &A, const SparseMatrix &B, const SparseMatrix &C) { Assert(B.RowCount() == C.RowCount() && B.ColCount() == C.ColCount(), "Invalid matrix addition dimensions."); A.Allocate(B.RowCount(), C.ColCount()); for(UINT i = 0; i < B.RowCount(); i++) { for(UINT i2 = 0; i2 < B.Rows()[i].Data.Length(); i2++) { const SparseElement *Element = &B.Rows()[i].Data[i2]; A.PushElement(i, Element->Col, Element->Entry); } for(UINT i2 = 0; i2 < C.Rows()[i].Data.Length(); i2++) { const SparseElement *Element = &C.Rows()[i].Data[i2]; A.PushElement(i, Element->Col, -Element->Entry); } } } template void SparseMatrix::Multiply(SparseMatrix &A, T B) { UINT _RowCount = A.RowCount(); for(UINT i = 0; i < _RowCount; i++) { UINT Entries = A.Rows()[i].Data.Length(); for(UINT i2 = 0; i2 < Entries; i2++) { A.Rows()[i].Data[i2].Entry *= B; } } } template 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 SparseMatrix::MultiplyTranspose(SparseMatrix &Output, const SparseMatrix &A, const SparseMatrix &B) { Assert(Output.RowCount() == A.RowCount() && Output.ColCount() == B.RowCount() && A.ColCount() == B.ColCount(), "Invalid Matrix4 multiply dimensions."); SignalError("Not implemented"); } template void SparseMatrix::Multiply(Vector &Output, const SparseMatrix &M, const Vector &V) { const SparseElement *E; // RxC * Vx1 = Ox1 Assert(Output.Length() == M.RowCount() && V.Length() == M.ColCount(), "Invalid vector multiply dimensions."); for(UINT i = 0; i < M.RowCount(); i++) { T Total = 0.0; for(UINT i2 = 0; i2 < M.Rows()[i].Data.Length(); i2++) { E = &M.Rows()[i].Data[i2]; Total += E->Entry * V[E->Col]; } Output[i] = Total; } } template void RealVector::Multiply(Vector &Output, T Scale, const Vector &V) { for(UINT i = 0; i < V.Length(); i++) { Output[i] = V[i] * Scale; } } template void RealVector::Multiply(Vector &Output, const Vector &V, T Scale) { Multiply(Output, Scale, V); } /*template T RealVector::DotProduct(const SparseRow &L, const Vector &R) { T Result = 0.0; for(UINT Index = 0; Index < L.Data.Length(); Index++) { const SparseElement *E = &L.Data[Index]; Result += E->Entry * R[E->Col]; } return Result; }*/ template T RealVector::DotProduct(const Vector &L, const Vector &R) { T Result = 0.0; for(UINT Index = 0; Index < L.Length(); Index++) { Result += L[Index] * R[Index]; } return Result; } template void RealVector::Add(Vector &Output, const Vector &L, const Vector &R) { for(UINT i = 0; i < L.Length(); i++) { Output[i] = L[i] + R[i]; } } template void RealVector::Subtract(Vector &Output, const Vector &L, const Vector &R) { for(UINT i = 0; i < L.Length(); i++) { Output[i] = L[i] - R[i]; } }