/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "MatrixTools.H" #include "LUscalarMatrix.H" #include "LLTMatrix.H" #include "Random.H" #include "SortList.H" #include "Switch.H" using namespace Foam; using namespace Foam::MatrixTools; #define RUNALL true #define isEqual MatrixTools::equal void horizontalLine() { Info<< "+---------+---------+---------+---------+---------+" << nl; } // Copy values into matrix template void assignMatrix ( Matrix& mat, std::initializer_list::cmptType> list ) { const label nargs = list.size(); if (nargs != mat.size()) { FatalErrorInFunction << "Mismatch in matrix dimension (" << mat.m() << ", " << mat.n() << ") and number of args (" << nargs << ')' << nl << exit(FatalError); } std::copy(list.begin(), list.end(), mat.begin()); } template MatrixType makeRandomMatrix ( const labelPair& dims, Random& rndGen ) { MatrixType mat(dims); std::generate ( mat.begin(), mat.end(), [&]{return rndGen.GaussNormal();} ); return mat; } template Ostream& operator<<(Ostream& os, const ConstMatrixBlock& mat) { return MatrixTools::printMatrix(os, mat); } template Ostream& operator<<(Ostream& os, const MatrixBlock& mat) { return MatrixTools::printMatrix(os, mat); } // * * * * * * * * * * * * * * * Main Program * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { typedef SquareMatrix SMatrix; typedef SquareMatrix SCMatrix; typedef RectangularMatrix RMatrix; typedef RectangularMatrix RCMatrix; Random rndGen(1234); #if (0 | RUNALL) { horizontalLine(); Info<< "## Matrix Constructors & Assignments:" << nl << nl; Info<< "# SquareMatrix examples:" << nl; { const label mRows = 2; const label nCols = 2; Matrix MS0(mRows, nCols); Matrix MS1(mRows, nCols, Zero); Matrix MS2(mRows, nCols, 17.44); Matrix MS3(MS2); SMatrix S0(mRows); SMatrix S1(mRows, Zero); SMatrix S2(mRows, I); SMatrix S3(mRows, 17.44); SMatrix S4(2, Zero); SMatrix S5(labelPair{mRows, nCols}); SMatrix S6(mRows, nCols, Zero); SMatrix S7({mRows, nCols}, Zero); SMatrix S8({mRows, nCols}, 17.44); assignMatrix ( S8, { 1, 2, // 0th row 3, 4 // 1st row and so on } ); S1 = Zero; S2 = 13.13; S3 = I; } Info<< "# RectangularMatrix examples:" << nl; { const label mRows = 2; const label nCols = 3; Matrix MR0(mRows, nCols); Matrix MR1(mRows, nCols, Zero); Matrix MR2(mRows, nCols, 17.44); RMatrix R0(mRows, nCols); RMatrix R1(labelPair{mRows, nCols}); RMatrix R2(mRows, nCols, Zero); RMatrix R3({mRows, nCols}, Zero); RMatrix R4(mRows, nCols, -17.44); RMatrix R5({mRows, nCols}, -17.44); RMatrix R6(3, 4, Zero); RMatrix R7({3, 4}, Zero); assignMatrix ( R7, { 1, 2, 3, 4, 5, 6, 7, 8.8, 9, 10, 11, 12 } ); R0 = Zero; R2 = -13.13; } Info<< "# SquareMatrix examples:" << nl; { const label mRows = 2; const label nCols = 2; Matrix MS0(mRows, nCols); Matrix MS1(mRows, nCols, Zero); Matrix MS2(mRows, nCols, complex(17.44, 44.17)); Matrix MS3(MS2); SCMatrix S0(mRows); SCMatrix S1(mRows, Zero); SCMatrix S2(mRows, I); SCMatrix S3(mRows, complex(17.44,0)); SCMatrix S4(2, Zero); SCMatrix S5(labelPair{mRows, nCols}); SCMatrix S6(mRows, nCols, Zero); SCMatrix S7({mRows, nCols}, Zero); SCMatrix S8({mRows, nCols}, complex(17.44,0)); assignMatrix ( S8, { complex(1,0), complex(2,2), complex(4,2), complex(5,0) } ); S1 = Zero; S2 = complex(13.13,0); S3 = I; } Info<< nl; horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Access Functions:" << nl; SMatrix S(3, Zero); assignMatrix ( S, { -3, 11, -4, 2, 3, 10, 2, 6, 1 } ); S(0,1) = 10; Info<< "# SquareMatrix example:" << nl; printMatrix(Info, S) << nl; Info << "Number of rows =" << tab << S.m() << nl << "Number of columns = " << tab << S.n() << nl << "Number of elements = " << tab << S.size() << nl << "Number of rows/columns = " << tab << S.sizes() << nl << "Matrix is empty = " << tab << Switch(S.empty()) << nl << "Constant pointer = " << tab << name(S.cdata()) << nl << "Pointer = " << tab << name(S.data()) << nl << nl; horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Block Access Functions:" << nl; RMatrix R(4, 3, Zero); assignMatrix ( R, { -3, 11, -4, 2, 3, 10, 2, 6, 1, 1, 2, 3 } ); Info<< "# RectangularMatrix example:" << nl; printMatrix(Info, R) << nl; // Indices begin at 0 const label columnI = 1; const label rowI = 2; const label colStartI = 1; const label rowStartI = 1; const label szRows = 2; const label szCols = 2; Info << "column: " << R.subColumn(columnI) << nl << "sub-column: " << R.subColumn(columnI, rowStartI) << nl << "sub-sub-column: " << R.subColumn(columnI, rowStartI, szRows) << nl << "row: " << R.subRow(rowI) << nl << "sub-row: " << R.subRow(rowI, colStartI) << nl << "sub-sub-row: " << R.subRow(rowI, colStartI, szCols) << nl << "sub-block: " << R.subMatrix(rowStartI, colStartI) << nl << "sub-block with row size: " << R.subMatrix(rowStartI, colStartI, szRows) << nl << "sub-block with row|col size: " << R.subMatrix(rowStartI, colStartI, szRows, szCols) << nl; horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Edit Functions:" << nl; RMatrix R(2, 2, Zero); assignMatrix ( R, { 1, 2, 3, 4 } ); Info<< "# Before Matrix.clear():" << nl << R << nl; R.clear(); Info<< "# After Matrix.clear():" << nl << R << nl; Info<< "# Before Matrix.resize(m, n):" << nl << R; R.resize(3, 2); Info<< "# After Matrix.resize(m, n):" << nl << R << nl << nl; // Steal matrix contents Info<< "# Before Matrix.release():" << nl << R << nl; List newOwner(R.release()); Info<< "# After Matrix.release():" << nl << R << "& corresponding List content:" << nl << newOwner << nl << nl; R.resize(3, 2); assignMatrix ( R, { 1, 2, 5, 6, 9e-19, 1e-17 } ); Info<< "# Before Matrix.round():" << nl << R << nl; R.round(); Info<< "# After Matrix.round():" << nl << R << nl << nl; Info<< "# Before Matrix.T() (Transpose):" << nl << R << nl; RMatrix RT = R.T(); Info<< "# After Matrix.T():" << nl << RT << nl << nl; RCMatrix RC(3, 2, Zero); assignMatrix ( RC, { complex(1, 0), complex(2,5), complex(4, 3), complex(1,-1), complex(1, 2), complex(2,9) } ); Info<< "# Before Matrix.T() (Hermitian transpose):" << nl << RC << nl; RCMatrix RCH = RC.T(); Info<< "# After Matrix.T():" << nl << RCH << nl << nl; Info<< "# Diagonal and trace:" << nl; RMatrix R1(5, 7, 3.4); { List diagR = R1.diag(); scalar traceR = R1.trace(); Info<< "RectangularMatrix:" << nl << R1 << nl << "Major diagonal of RectangularMatrix:" << nl << diagR << nl << "Trace of RectangularMatrix:" << nl << traceR << nl << nl; } Info<< "# List assignment to the main diagonal of Matrix:" << nl; { SMatrix S1(5, I); Info<< "Before List assignment:" << nl; printMatrix(Info, S1); List lst(5, 2.0); S1.diag(lst); Info<< "After List assignment:" << nl; printMatrix(Info, S1); } Info<< "# Diagonal sort of Matrix:" << nl; { auto S1 ( makeRandomMatrix ( {3, 3}, rndGen ) ); List diag = S1.diag(); SortList incrDiag(diag); incrDiag.sort(); Info<< "Diagonal list:" << diag << nl << "Ascending diagonal list: " << incrDiag << nl << nl; } horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Transpose Verifications:" << nl; const label numberOfTests = 10; for (label i = 0; i < numberOfTests; ++i) { const label mRows = rndGen.position(1,10); const label nCols = rndGen.position(1,10); Info << "# SquareMatrix example:" << nl; { Info<< "A(mxm) where m = " << mRows << nl; auto A(makeRandomMatrix({mRows, mRows}, rndGen)); auto B(makeRandomMatrix({mRows, mRows}, rndGen)); Info<< nl << "# (A.T()).T() = A:" << nl; isEqual((A.T()).T(), A, true); Info<< nl << "# (A + B).T() = A.T() + B.T():" << nl; isEqual((A + B).T(), A.T() + B.T(), true); Info<< nl << "# (A*B).T() = B.T()*A.T():" << nl; isEqual((A*B).T(), B.T()*A.T(), true); Info<< nl << nl; } Info << "# RectangularMatrix example:" << nl; { Info<< "A(mxn) where" << " m = " << mRows << "," << " n = " << nCols << nl; auto A(makeRandomMatrix({mRows, nCols}, rndGen)); auto B(makeRandomMatrix({mRows, nCols}, rndGen)); auto C(makeRandomMatrix({nCols, mRows}, rndGen)); Info<< nl << "# (A.T()).T() = A:" << nl; isEqual((A.T()).T(), A, true); Info<< nl << "# (A + B).T() = A.T() + B.T():" << nl; isEqual((A + B).T(), A.T() + B.T(), true); Info<< nl << "# (A*C).T() = C.T()*C.T():" << nl; isEqual((A*C).T(), C.T()*A.T(), true); Info<< nl << nl; } Info << "# SquareMatrix example:" << nl; { Info<< "A(mxm) where m = " << mRows << nl; SCMatrix A(mRows); SCMatrix B(mRows); for (auto& val : A) { val.real(rndGen.GaussNormal()); val.imag(rndGen.GaussNormal()); } for (auto& val : B) { val.real(rndGen.GaussNormal()); val.imag(rndGen.GaussNormal()); } Info<< nl << "# (A.T()).T() = A:" << nl; isEqual((A.T()).T(), A, true); Info<< nl << "# (A + B).T() = A.T() + B.T():" << nl; isEqual((A + B).T(), A.T() + B.T(), true); Info<< nl << "# (A*B).T() = B.T()*A.T():" << nl; isEqual((A*B).T(), B.T()*A.T(), true); Info<< nl << nl; } } horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Scalar Arithmetic Operations:" << nl; if (true) { SMatrix S1(3, Zero); assignMatrix ( S1, { 4.1, 12.5, -16.3, -192.3, -9.1, -3.0, 1.0, 5.02, -4.4 } ); SMatrix S2 = S1; SMatrix S3(3, Zero); Info<< "SquareMatrix S1 = " << S1 << nl; Info<< "SquareMatrix S2 = " << S2 << nl; Info<< "SquareMatrix S3 = " << S3 << nl; S3 = S1*S2; Info<< "S1*S2 = " << S3 << nl; S3 = S1 - S2; Info<< "S1 - S2 = " << S3 << nl; S3 = S1 + S2; Info<< "S1 + S2 = " << S3 << nl; // S3 *= S1; // Not Implemented S3 -= S1; Info<< "S3 -= S1; S3 = " << S3 << nl; S3 += S1; Info<< "S3 += S1; S3 = " << S3 << nl; Info<< nl << "# Scalar broadcasting:" << nl; S3 *= 5.0; Info<< "S3 *= 5.0; S3 = " << S3 << nl; S3 /= 5.0; Info<< "S3 /= 5.0; S3 = " << S3 << nl; S3 -= 1.0; Info<< "S3 -= 1.0; S3 = " << S3 << nl; S3 += 1.0; Info<< "S3 += 1.0; S3 = " << S3 << nl; Info<< nl << "# Operations between different matrix types:" << nl; RMatrix R1 = S1; Info<< "RectangularMatrix R1 = " << R1 << nl; // RectangularMatrix*SquareMatrix returns RectangularMatrix // S3 = S3*R1; // Not implemented R1 = S3*R1; Info<< "R1 = S3*R1; R1 = " << R1 << nl; S3 = S3 - R1; Info<< "S3 = S3 - R1; S3 = " << S3 << nl; S3 = S3 + R1; Info<< "S3 = S3 + R1; S3 = " << S3 << nl; R1 = S3 + R1; Info<< "R1 = S3 + R1; R1 = " << R1 << nl; Info<< nl << "# Extrema operations:" << nl; Info<< "min(S3) = " << min(S3) << nl << "max(S3) = " << max(S3) << nl << "minMax(S3) = " << minMax(S3) << nl; } if (true) { Info<< nl << "# Operations with ListTypes:" << nl; SMatrix A(3, Zero); assignMatrix ( A, { 4.1, 12.5, -16.3, -192.3, -9.1, -3.0, 1.0, 5.02, -4.4 } ); const List lst({1, 2, 3}); RMatrix colVector(3, 1, Zero); assignMatrix ( colVector, {1, 2, 3} ); RMatrix rowVector(1, 3, Zero); assignMatrix ( rowVector, {1, 2, 3} ); Info<< "A = " << A << nl; Info<< "colVector = " << colVector << nl; Info<< "rowVector = " << rowVector << nl; const Field field1(A.Amul(lst)); const Field field2(A*lst); const Field field3(A.Tmul(lst)); const Field field4(lst*A); Info << "Field1 = A*lst = A.Amul(lst):" << nl << field1 << nl << "Field2 = A*lst:" << nl << field2 << nl << "A*colVector:" << nl << A*colVector << nl << "Field3 = lst*A = A.Tmul(lst):" << nl << field3 << nl << "Field4 = lst*A:" << nl << field4 << nl << "rowVector*A:" << nl << rowVector*A << nl << nl; } if (true) { Info<< nl << "# Implicit inner/outer products:" << nl; const scalar r = 2.0; RMatrix A(3, 2, Zero); assignMatrix ( A, { 1, 2, 3, 4, 5, 6 } ); const RMatrix B(A); const RMatrix C(B); Info<< nl << "# Inner product:" << nl; { Info<< "- Explicit vs Implicit => A.T()*B == A&B:" << nl; isEqual(A.T()*B, A&B, true); Info<< "- Commutative => A&B == B&A:" << nl; isEqual(A&B, B&A, true); Info<< "- Distributive => A&(B+C) == A&B + A&C:" << nl; isEqual(A&(B + C), (A&B) + (A&C), true); Info<< "- Bilinear => A&(rB+C) == r(A&B) + (A&C):" << nl; isEqual(A&(r*B + C), r*(A&B) + (A&C), true); Info<< "- Scalar multiplication => (rA)&(rB) == rr(A&B):" << nl; isEqual((r*A)&(r*B), r*r*(A&B), true); } Info<< nl << "# Outer product:" << nl; { Info<< "- Explicit vs Implicit => A*B.T() == A^B:" << nl; isEqual(A*B.T(), A^B, true); Info<< "- Commutative => A^B == B^A:" << nl; isEqual(A^B, B^A, true); Info<< "- Distributive => A^(B+C) == A^B + A^C:" << nl; isEqual(A^(B + C), (A^B) + (A^C), true); Info<< "- Scalar multiplication => r*(A^B) == (r*A)^B:" << nl; isEqual(r*(A^B), (r*A)^B, true); } } Info<< nl; horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Complex Arithmetic Operations:" << nl; if (true) { SCMatrix S1(3, Zero); assignMatrix ( S1, { complex(4.1, 1.0), complex(12.5, -1), complex(-16.3,-3), complex(-192.3, 5), complex(-9.1, 3), complex(-3.0, 1), complex(1.0, 3), complex(5.02, 0.3), complex(-4.4, 1) } ); SCMatrix S2 = S1; SCMatrix S3(3, Zero); Info<< "SquareMatrix S1 = " << S1 << nl; Info<< "SquareMatrix S2 = " << S2 << nl; Info<< "SquareMatrix S3 = " << S3 << nl; S3 = S1*S2; Info<< "S1*S2 = " << S3 << nl; S3 = S1 - S2; Info<< "S1 - S2 = " << S3 << nl; S3 = S1 + S2; Info<< "S1 + S2 = " << S3 << nl; // S3 *= S1; // Not Implemented S3 -= S1; Info<< "S3 -= S1; S3 = " << S3 << nl; S3 += S1; Info<< "S3 += S1; S3 = " << S3 << nl; Info<< nl << "# Complex broadcasting:" << nl; S3 *= complex(5, 0); Info<< "S3 *= complex(5, 0); S3 = " << S3 << nl; S3 /= complex(5, 0); Info<< "S3 /= complex(5, 0); S3 = " << S3 << nl; S3 -= complex(1, 0); Info<< "S3 -= complex(1, 0); S3 = " << S3 << nl; S3 += complex(1, 0); Info<< "S3 += complex(1, 0); S3 = " << S3 << nl; Info<< nl << "# Operations between different matrix types:" << nl; RCMatrix R1 = S1; Info<< "RectangularMatrix R1 = " << R1 << nl; R1 = S3*R1; Info<< "R1 = S3*R1; R1 = " << R1 << nl; S3 = S3 - R1; Info<< "S3 = S3 - R1; S3 = " << S3 << nl; S3 = S3 + R1; Info<< "S3 = S3 + R1:" << S3 << nl; // Extrama operations // Not Implemented } if (true) { Info<< nl << "# Operations with ListTypes:" << nl; SCMatrix A(3, Zero); assignMatrix ( A, { complex(4.1, 1.0), complex(12.5, -1), complex(-16.3,-3), complex(-192.3, 5), complex(-9.1, 3), complex(-3.0, 1), complex(1.0, 3), complex(5.02, 0.3), complex(-4.4, 1) } ); const List lst({complex(1,1), complex(2,2), complex(3,3)}); RCMatrix colVector(3, 1, Zero); assignMatrix ( colVector, {complex(1,1), complex(2,2), complex(3,3)} ); RCMatrix rowVector(1, 3, Zero); assignMatrix ( rowVector, {complex(1,1), complex(2,2), complex(3,3)} ); Info<< "A = " << A << nl; Info<< "colVector = " << colVector << nl; Info<< "rowVector = " << rowVector << nl; const Field field1(A.Amul(lst)); const Field field2(A*lst); const Field field3(A.Tmul(lst)); const Field field4(lst*A); Info << "Field1 = A*lst = A.Amul(lst):" << nl << field1 << nl << "Field2 = A*lst:" << nl << field2 << nl << "A*colVector:" << nl << A*colVector << nl << "Field3 = lst*A = A.Tmul(lst):" << nl << field3 << nl << "Field4 = lst*A:" << nl << field4 << nl << "rowVector*A:" << nl << rowVector*A << nl << nl; } #if (0 | RUNALL) { Info<< nl << "# Implicit inner/outer products:" << nl; const complex r(2.0,1.0); RCMatrix A(3, 2, Zero); assignMatrix ( A, { complex(1,0), complex(2,1), complex(3,-0.3), complex(4,-1), complex(0.5,-0.1), complex(6,0.4) } ); const RCMatrix B(A); const RCMatrix C(B); Info<< nl << "# Inner product:" << nl; { Info<< "- Explicit vs Implicit => A.T()*B == A&B:" << nl; isEqual(A.T()*B, A&B, true); Info<< "- Commutative => A&B == B&A:" << nl; isEqual(A&B, B&A, true); Info<< "- Distributive => A&(B+C) == A&B + A&C:" << nl; isEqual(A&(B + C), (A&B) + (A&C), true); Info<< "- Bilinear => A&(rB+C) == r(A&B) + (A&C):" << nl; isEqual(A&(r*B + C), r*(A&B) + (A&C), true); } Info<< nl << "# Outer product:" << nl; { Info<< "- Explicit vs Implicit => A*B.T() == A^B:" << nl; isEqual(A*B.T(), A^B, true); Info<< "- Commutative => A^B == B^A:" << nl; isEqual(A^B, B^A, true); Info<< "- Distributive => A^(B+C) == A^B + A^C:" << nl; isEqual(A^(B + C), (A^B) + (A^C), true); Info<< "- Scalar multiplication => r*(A^B) == (r*A)^B:" << nl; isEqual(r*(A^B), (r*A)^B, true); } } #endif Info<< nl; horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## Query to determine if a square matrix is symmetric:" << nl; { const label mRows = 100; SMatrix A(makeRandomMatrix({mRows, mRows}, rndGen)); Info<< "# SquareMatrix.symmetric():" << nl << A.symmetric() << nl; // Symmetrise for (label n = 0; n < A.n() - 1; ++n) { for (label m = A.m() - 1; n < m; --m) { A(n, m) = A(m, n); } } Info<< "# SquareMatrix.symmetric():" << nl << A.symmetric() << nl; } { const label mRows = 100; SCMatrix A(mRows); for (auto& val : A) { val.real(rndGen.GaussNormal()); val.imag(rndGen.GaussNormal()); } Info<< "# SquareMatrix.symmetric():" << nl << A.symmetric() << nl; // Symmetrise for (label n = 0; n < A.n() - 1; ++n) { for (label m = A.m() - 1; n < m; --m) { A(n, m) = A(m, n); } } Info<< "# SquareMatrix.symmetric():" << nl << A.symmetric() << nl; } horizontalLine(); } #endif #if (0 | RUNALL) { horizontalLine(); Info<< "## SymmetricSquareMatrix algorithms:" << nl; scalarSymmetricSquareMatrix symm(3, Zero); symm(0, 0) = 4; symm(1, 0) = 12; symm(1, 1) = 37; symm(2, 0) = -16; symm(2, 1) = -43; symm(2, 2) = 98; Info<< "SymmetricSquareMatrix = " << nl << symm << nl << "Inverse = " << nl << inv(symm) << nl << "Determinant = " << det(symm) << nl; scalarSymmetricSquareMatrix symm2(symm); LUDecompose(symm2); Info<< "LU decomposition:" << nl << "Inverse = " << nl << invDecomposed(symm2) << nl << "Determinant = " << detDecomposed(symm2) << nl; scalarDiagonalMatrix rhs(3, 0); rhs[0] = 1; rhs[1] = 2; rhs[2] = 3; LUsolve(symm, rhs); Info<< "Solving linear system through LU decomposition:" << nl << "Decomposition = " << nl << symm << nl << "Solution = " << rhs << nl; } #endif #if (0 | RUNALL) { scalarSquareMatrix squareMatrix(3, Zero); scalarSquareMatrix S(3, Zero); assignMatrix ( S, { 4, 12, -16, 12, 37, -43, -16, -43, 98 } ); const scalarField source(3, 1); Info<< nl << "Square Matrix = " << S << endl; if (true) { { scalarSquareMatrix S2(S); Info<< "Determinant = " << det(S2) << nl; } scalarSquareMatrix S2(S); labelList rhs(3, 0); label sign; LUDecompose(S2, rhs, sign); Info<< "LU decomposition = " << S2 << nl << "Pivots = " << rhs << nl << "Sign = " << sign << nl << "Determinant = " << detDecomposed(S2, sign) << nl; } if (true) { LUscalarMatrix LU(S); scalarField x(LU.solve(source)); scalarSquareMatrix inv(3); LU.inv(inv); Info<< "LU.solve(source) residual: " << (S*x - source) << nl << "LU inv " << inv << nl << "LU inv*S " << (inv*S) << nl; } if (true) { LLTMatrix LLT(S); scalarField x(LLT.solve(source)); Info<< "LLT solve residual " << (S*x - source) << nl; } horizontalLine(); } #endif Info<< nl << "End" << nl; return 0; } // ************************************************************************* //