diff --git a/applications/test/Matrix/Test-Matrix.C b/applications/test/Matrix/Test-Matrix.C index 4e001d7c6ac60a12901104e63a38f753417cf5e2..dbccf225fabf27df0105deb71fa58e9740d6b051 100644 --- a/applications/test/Matrix/Test-Matrix.C +++ b/applications/test/Matrix/Test-Matrix.C @@ -25,17 +25,23 @@ License \*---------------------------------------------------------------------------*/ -#include "scalarMatrices.H" +#include "MatrixTools.H" #include "LUscalarMatrix.H" #include "LLTMatrix.H" -#include "QRMatrix.H" -#include "vector.H" -#include "tensor.H" -#include "IFstream.H" - +#include "Random.H" +#include "SortList.H" #include <algorithm> using namespace Foam; +using namespace Foam::MatrixTools; + +#define isEqual MatrixTools::equal + +void horizontalLine() +{ + Info<< "+---------+---------+---------+---------+---------+" << nl; +} + // Copy values into matrix template<class Form, class Type> @@ -59,254 +65,906 @@ void assignMatrix std::copy(list.begin(), list.end(), mat.begin()); } -// Create matrix with values + template<class MatrixType> -MatrixType makeMatrix +MatrixType makeRandomMatrix ( const labelPair& dims, - std::initializer_list<typename MatrixType::cmptType> list + Random& rndGen ) { MatrixType mat(dims); - assignMatrix(mat, list); + std::generate + ( + mat.begin(), + mat.end(), + [&]{return rndGen.GaussNormal<typename MatrixType::cmptType>();} + ); return mat; } -// Create matrix with values -template<class MatrixType, Foam::label nRows, Foam::label nCols> -MatrixType makeMatrix -( - std::initializer_list<typename MatrixType::cmptType> list -) +template<class MatrixType> +Ostream& operator<<(Ostream& os, const ConstMatrixBlock<MatrixType>& mat) { - MatrixType mat(labelPair(nRows, nCols)); + return MatrixTools::printMatrix(os, mat); +} - assignMatrix(mat, list); - return mat; +template<class MatrixType> +Ostream& operator<<(Ostream& os, const MatrixBlock<MatrixType>& mat) +{ + return MatrixTools::printMatrix(os, mat); } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Main program: +// * * * * * * * * * * * * * * * Main Program * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { - // SquareMatrix + typedef SquareMatrix<scalar> SMatrix; + typedef SquareMatrix<complex> SCMatrix; + typedef RectangularMatrix<scalar> RMatrix; + typedef RectangularMatrix<complex> RCMatrix; + + Random rndGen(1234); + + #if 1 + { + horizontalLine(); + + Info<< "## Matrix Constructors & Assignments:" << nl << nl; + + Info<< "# SquareMatrix<scalar> examples:" << nl; + { + const label mRows = 2; + const label nCols = 2; + Matrix<SMatrix, scalar> MS0(mRows, nCols); + Matrix<SMatrix, scalar> MS1(mRows, nCols, Zero); + Matrix<SMatrix, scalar> MS2(mRows, nCols, 17.44); + Matrix<SMatrix, scalar> 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<scalar> examples:" << nl; + { + const label mRows = 2; + const label nCols = 3; + Matrix<RMatrix, scalar> MR0(mRows, nCols); + Matrix<RMatrix, scalar> MR1(mRows, nCols, Zero); + Matrix<RMatrix, scalar> 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<complex> examples:" << nl; + { + const label mRows = 2; + const label nCols = 2; + Matrix<SCMatrix, complex> MS0(mRows, nCols); + Matrix<SCMatrix, complex> MS1(mRows, nCols, Zero); + Matrix<SCMatrix, complex> MS2(mRows, nCols, complex(17.44, 44.17)); + Matrix<SCMatrix, complex> 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 1 + { + 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<scalar> example:" << nl; + printMatrix(Info, S) << nl; + + const label mRows = S.m(); + const label nCols = S.n(); + const label size = S.size(); + const labelPair sizes = S.sizes(); + const bool isEmpty = S.empty(); + const long constPointer = long(S.cdata()); + long pointer = long(S.data()); + + Info + << "Number of rows =" << tab << mRows << nl + << "Number of columns = " << tab << nCols << nl + << "Number of elements = " << tab << size << nl + << "Number of rows/columns = " << tab << sizes << nl + << "Matrix is empty = " << tab << isEmpty << nl + << "Constant pointer = " << tab << constPointer << nl + << "Pointer = " << tab << pointer << nl + << nl; + + horizontalLine(); + } + #endif + + + #if 1 + { + 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<scalar> 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 1 { - Info<< nl << "Test SquareMatrix" << nl; + 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; - SquareMatrix<scalar> square1(3); + 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<scalar> 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 ( - square1, + RC, { - -3.0, 10.0, -4.0, - 2.0, 3.0, 10.0, - 2.0, 6.0, 1.0 + complex(1, 0), complex(2,5), + complex(4, 3), complex(1,-1), + complex(1, 2), complex(2,9) } ); - Info<< "matrix: " << square1 - << " begin: " << uintptr_t(square1.cdata()) << nl; + 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<scalar> diagR = R1.diag(); + scalar traceR = R1.trace(); + Info<< "RectangularMatrix<scalar>:" + << 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<scalar> lst(5, 2.0); + S1.diag(lst); + Info<< "After List assignment:" << nl; + printMatrix(Info, S1); + } - // Test makeMatrix + Info<< "# Diagonal sort of Matrix:" << nl; { - auto square1b + auto S1 ( - makeMatrix<scalarSquareMatrix> + makeRandomMatrix<SMatrix> ( - {3, 3}, - { - -3.0, 10.0, -4.0, - 2.0, 3.0, 10.0, - 2.0, 6.0, 1.0 - } + {3, 3}, rndGen ) ); - Info<< "makeMatrix: " << square1b << nl; + List<scalar> diag = S1.diag(); + SortList<scalar> incrDiag(diag); + incrDiag.sort(); + + Info<< "Diagonal list:" << diag << nl + << "Ascending diagonal list: " << incrDiag << nl << nl; + } + + horizontalLine(); + } + #endif + + + #if 1 + { + 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<scalar> example:" << nl; + { + Info<< "A(mxm) where m = " << mRows << nl; + auto A(makeRandomMatrix<SMatrix>({mRows, mRows}, rndGen)); + auto B(makeRandomMatrix<SMatrix>({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<scalar> example:" << nl; + { + Info<< "A(mxn) where" + << " m = " << mRows << "," + << " n = " << nCols << nl; + auto A(makeRandomMatrix<RMatrix>({mRows, nCols}, rndGen)); + auto B(makeRandomMatrix<RMatrix>({mRows, nCols}, rndGen)); + auto C(makeRandomMatrix<RMatrix>({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<complex> example:" << nl; + { + Info<< "A(mxm) where m = " << mRows << nl; + SCMatrix A(mRows); + SCMatrix B(mRows); + + for (auto& val : A) + { + val.Re() = rndGen.GaussNormal<scalar>(); + val.Im() = rndGen.GaussNormal<scalar>(); + } + for (auto& val : B) + { + val.Re() = rndGen.GaussNormal<scalar>(); + val.Im() = rndGen.GaussNormal<scalar>(); + } + + 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 - auto square1c + + #if 1 + { + horizontalLine(); + + Info<< "## Scalar Arithmetic Operations:" << nl; + + if (true) + { + SMatrix S1(3, Zero); + assignMatrix ( - makeMatrix<scalarSquareMatrix, 3, 3> - ({ - -3.0, 10.0, -4.0, - 2.0, 3.0, 10.0, - 2.0, 6.0, 1.0 - }) + 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<< "makeMatrix: " << square1c << nl; - } + Info<< "SquareMatrix<scalar> S1 = " << S1 << nl; + Info<< "SquareMatrix<scalar> S2 = " << S2 << nl; + Info<< "SquareMatrix<scalar> S3 = " << S3 << nl; - //Info<< square1 - 2.0*(-square1) << nl; - Info<< "min:" << min(square1) << " max:" << max(square1) << nl; - Info<< "min/max: " << minMax(square1) << nl; + S3 = S1*S2; + Info<< "S1*S2 = " << S3 << nl; - // Steal matrix contents + S3 = S1 - S2; + Info<< "S1 - S2 = " << S3 << nl; - List<scalar> stole(square1.release()); + S3 = S1 + S2; + Info<< "S1 + S2 = " << S3 << nl; - Info<< "matrix: " << square1 - << " begin: " << uintptr_t(square1.cdata()) << nl; +// S3 *= S1; // Not Implemented - Info<< "List: " << stole << nl; + S3 -= S1; + Info<< "S3 -= S1; S3 = " << S3 << nl; - Info<< "min/max: " << minMax(square1) << nl; + S3 += S1; + Info<< "S3 += S1; S3 = " << S3 << nl; - square1 = 100; - Info<< "matrix: " << square1 - << " begin: " << uintptr_t(square1.cdata()) << nl; + Info<< nl << "# Scalar broadcasting:" << nl; + S3 *= 5.0; + Info<< "S3 *= 5.0; S3 = " << S3 << nl; - SquareMatrix<scalar> square2(3, I); + S3 /= 5.0; + Info<< "S3 /= 5.0; S3 = " << S3 << nl; - square1 = square2; + S3 -= 1.0; + Info<< "S3 -= 1.0; S3 = " << S3 << nl; - Info<< nl << "After copy assign from Identity:" << nl << square1 << nl; + S3 += 1.0; + Info<< "S3 += 1.0; S3 = " << S3 << nl; - square1 += 1.25*square2; - Info<< nl << "After +=" << nl << square1 << nl; + Info<< nl << "# Operations between different matrix types:" << nl; + RMatrix R1 = S1; + Info<< "RectangularMatrix<scalar> R1 = " << R1 << nl; - square1 -= square2.T(); + // RectangularMatrix*SquareMatrix returns RectangularMatrix + // S3 = S3*R1; // Not implemented + R1 = S3*R1; + Info<< "R1 = S3*R1; R1 = " << R1 << nl; - Info<< nl << "After -=" << nl << square1 << nl; + S3 = S3 - R1; + Info<< "S3 = S3 - R1; S3 = " << S3 << nl; - square1 *= 10; + S3 = S3 + R1; + Info<< "S3 = S3 + R1; S3 = " << S3 << nl; - Info<< nl << "After *=" << nl << square1 << nl; + R1 = S3 + R1; + Info<< "R1 = S3 + R1; R1 = " << R1 << nl; - square1 /= 8; - Info<< nl << "After /=" << nl << square1 << nl; + Info<< nl << "# Extrema operations:" << nl; - SquareMatrix<scalar> square4; - square4 = square2; + Info<< "min(S3) = " << min(S3) << nl + << "max(S3) = " << max(S3) << nl + << "minMax(S3) = " << minMax(S3) << nl; + } - Info<< nl << square4 << endl; + if (true) + { + Info<< nl << "# Operations with ListTypes<scalar>:" << nl; - SquareMatrix<scalar> square5; - square4 = square5; - Info<< nl << square5 << endl; - } + 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<scalar> lst({1, 2, 3}); + RMatrix colVector(3, 1, Zero); + assignMatrix + ( + colVector, + {1, 2, 3} + ); + RMatrix rowVector(1, 3, Zero); + assignMatrix + ( + rowVector, + {1, 2, 3} + ); - // RectangularMatrix - { - Info<< nl << "Test RectangularMatrix" << nl; + Info<< "A = " << A << nl; + Info<< "colVector = " << colVector << nl; + Info<< "rowVector = " << rowVector << nl; + + const Field<scalar> field1(A.Amul(lst)); + const Field<scalar> field2(A*lst); + const Field<scalar> field3(A.Tmul(lst)); + const Field<scalar> 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); - RectangularMatrix<scalar> rm1({5, 6}, 3.1); - rm1(0, 1) = 4.5; + 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); - RectangularMatrix<scalar> rm1b(rm1.block(2, 2, 0, 0)); + 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 // << "Full matrix " << rm1 << nl - << "block = " << rm1b << endl; + Info<< nl; + horizontalLine(); } + #endif + + #if 1 { - scalarSymmetricSquareMatrix symmMatrix(3, Zero); + horizontalLine(); - symmMatrix(0, 0) = 4; - symmMatrix(1, 0) = 12; - symmMatrix(1, 1) = 37; - symmMatrix(2, 0) = -16; - symmMatrix(2, 1) = -43; - symmMatrix(2, 2) = 98; + Info<< "## Complex Arithmetic Operations:" << nl; - Info<< "Symmetric Square Matrix = " << symmMatrix << endl; + 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<< "Inverse = " << inv(symmMatrix) << endl; - Info<< "Determinant = " << det(symmMatrix) << endl; + Info<< "SquareMatrix<complex> S1 = " << S1 << nl; + Info<< "SquareMatrix<complex> S2 = " << S2 << nl; + Info<< "SquareMatrix<complex> S3 = " << S3 << nl; - scalarSymmetricSquareMatrix symmMatrix2(symmMatrix); - LUDecompose(symmMatrix2); + S3 = S1*S2; + Info<< "S1*S2 = " << S3 << nl; - Info<< "Inverse = " << invDecomposed(symmMatrix2) << endl; - Info<< "Determinant = " << detDecomposed(symmMatrix2) << endl; + S3 = S1 - S2; + Info<< "S1 - S2 = " << S3 << nl; - scalarDiagonalMatrix rhs(3, Zero); - rhs[0] = 1; - rhs[1] = 2; - rhs[2] = 3; + S3 = S1 + S2; + Info<< "S1 + S2 = " << S3 << nl; - LUsolve(symmMatrix, rhs); +// S3 *= S1; // Not Implemented - Info<< "Decomposition = " << symmMatrix << endl; - Info<< "Solution = " << rhs << endl; - } + S3 -= S1; + Info<< "S3 -= S1; S3 = " << S3 << nl; + S3 += S1; + Info<< "S3 += S1; S3 = " << S3 << nl; - scalarSquareMatrix squareMatrix(3, Zero); - squareMatrix(0, 0) = 4; - squareMatrix(0, 1) = 12; - squareMatrix(0, 2) = -16; - squareMatrix(1, 0) = 12; - squareMatrix(1, 1) = 37; - squareMatrix(1, 2) = -43; - squareMatrix(2, 0) = -16; - squareMatrix(2, 1) = -43; - squareMatrix(2, 2) = 98; + Info<< nl << "# Complex broadcasting:" << nl; - Info<< nl << "Square Matrix = " << squareMatrix << endl; + S3 *= complex(5, 0); + Info<< "S3 *= complex(5, 0); S3 = " << S3 << nl; - const scalarField source(3, 1); + 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<complex> 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) { - scalarSquareMatrix sm(squareMatrix); - Info<< "det = " << det(sm) << endl; + Info<< nl << "# Operations with ListTypes<complex>:" << 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<complex> 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<complex> field1(A.Amul(lst)); + const Field<complex> field2(A*lst); + const Field<complex> field3(A.Tmul(lst)); + const Field<complex> 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; } - scalarSquareMatrix sm(squareMatrix); - labelList rhs(3, 0); - label sign; - LUDecompose(sm, rhs, sign); + #if 1 + { + Info<< nl << "# Implicit inner/outer products:" << nl; - Info<< "Decomposition = " << sm << endl; - Info<< "Pivots = " << rhs << endl; - Info<< "Sign = " << sign << endl; - Info<< "det = " << detDecomposed(sm, sign) << endl; - } + 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); - { - LUscalarMatrix LU(squareMatrix); - scalarField x(LU.solve(source)); - Info<< "LU solve residual " << (squareMatrix*x - source) << endl; - - scalarSquareMatrix inv(3); - LU.inv(inv); - Info<< "LU inv " << inv << endl; - Info<< "LU inv*squareMatrix " << (inv*squareMatrix) << endl; + 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 1 { - LLTMatrix<scalar> LLT(squareMatrix); - scalarField x(LLT.solve(source)); - Info<< "LLT solve residual " << (squareMatrix*x - source) << endl; + horizontalLine(); + + Info<< "## SymmetricSquareMatrix<scalar> 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 1 { - QRMatrix<scalarSquareMatrix> QR(squareMatrix); - scalarField x(QR.solve(source)); + scalarSquareMatrix squareMatrix(3, Zero); - Info<< "QR solve residual " - << (squareMatrix*x - source) << endl; + scalarSquareMatrix S(3, Zero); + assignMatrix + ( + S, + { + 4, 12, -16, + 12, 37, -43, + -16, -43, 98 + } + ); + + const scalarField source(3, 1); - Info<< "QR inverse solve residual " - << (x - QR.inv()*source) << endl; + Info<< nl << "Square Matrix = " << S << endl; - Info<< "QR inv *squareMatrix " << (QR.inv()*squareMatrix) << 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<scalar> LLT(S); + scalarField x(LLT.solve(source)); + Info<< "LLT solve residual " << (S*x - source) << nl; + } + + horizontalLine(); } + #endif + - Info<< "\nEnd\n" << endl; + Info<< nl << "End" << nl; return 0; } diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.C b/src/OpenFOAM/matrices/Matrix/Matrix.C index 1b0908dc3c665d46d3c83b7ecd14343e1271f4fe..072c78ffe7e51fa0e97cf1583c8d7f4978271096 100644 --- a/src/OpenFOAM/matrices/Matrix/Matrix.C +++ b/src/OpenFOAM/matrices/Matrix/Matrix.C @@ -334,16 +334,29 @@ void Foam::Matrix<Form, Type>::resize(const label m, const label n) } +template<class Form, class Type> +void Foam::Matrix<Form, Type>::round(const scalar tol) +{ + for (Type& val : *this) + { + if (mag(val) < tol) + { + val = Zero; + } + } +} + + template<class Form, class Type> Form Foam::Matrix<Form, Type>::T() const { - Form At(n(), m()); + Form At(labelPair{n(), m()}); for (label i = 0; i < m(); ++i) { for (label j = 0; j < n(); ++j) { - At(j, i) = (*this)(i, j); + At(j, i) = Detail::conj((*this)(i, j)); } } @@ -351,6 +364,91 @@ Form Foam::Matrix<Form, Type>::T() const } +template<class Form, class Type> +Foam::List<Type> Foam::Matrix<Form, Type>::diag() const +{ + const label len = Foam::min(mRows_, nCols_); + + List<Type> result(len); + + for (label i=0; i < len; ++i) + { + result[i] = (*this)(i, i); + } + + return result; +} + + +template<class Form, class Type> +void Foam::Matrix<Form, Type>::diag(const UList<Type>& list) +{ + const label len = Foam::min(mRows_, nCols_); + + #ifdef FULLDEBUG + if (list.size() != len) + { + FatalErrorInFunction + << "List size (" << list.size() + << ") incompatible with Matrix diagonal" << abort(FatalError); + } + #endif + + for (label i=0; i < len; ++i) + { + (*this)(i, i) = list[i]; + } +} + + +template<class Form, class Type> +Type Foam::Matrix<Form, Type>::trace() const +{ + const label len = Foam::min(mRows_, nCols_); + + Type val = Zero; + + for (label i=0; i < len; ++i) + { + val += (*this)(i, i); + } + + return val; +} + + +template<class Form, class Type> +Foam::scalar Foam::Matrix<Form, Type>::columnNorm +( + const label colIndex, + const bool noSqrt +) const +{ + scalar result = Zero; + + for (label i=0; i < mRows_; ++i) + { + result += magSqr((*this)(i, colIndex)); + } + + return noSqrt ? result : Foam::sqrt(result); +} + + +template<class Form, class Type> +Foam::scalar Foam::Matrix<Form, Type>::norm(const bool noSqrt) const +{ + scalar result = Zero; + + for (const Type& val : *this) + { + result += magSqr(val); + } + + return noSqrt ? result : Foam::sqrt(result); +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template<class Form, class Type> @@ -416,9 +514,9 @@ void Foam::Matrix<Form, Type>::operator= const MatrixBlock<MatrixType>& Mb ) { - for (label i=0; i < mRows_; ++i) + for (label i = 0; i < mRows_; ++i) { - for (label j=0; j < nCols_; ++j) + for (label j = 0; j < nCols_; ++j) { (*this)(i, j) = Mb(i, j); } @@ -443,6 +541,7 @@ void Foam::Matrix<Form, Type>::operator=(const zero) template<class Form, class Type> void Foam::Matrix<Form, Type>::operator+=(const Matrix<Form, Type>& other) { + #ifdef FULLDEBUG if (this == &other) { FatalErrorInFunction @@ -458,15 +557,13 @@ void Foam::Matrix<Form, Type>::operator+=(const Matrix<Form, Type>& other) << other.m() << ", " << other.n() << ')' << nl << abort(FatalError); } + #endif - Type* out = this->data(); - const Type* in = other.cdata(); - - const label len = this->size(); - - for (label idx = 0; idx < len; ++idx) + auto iter2 = other.cbegin(); + for (Type& val : *this) { - out[idx] += in[idx]; + val += *iter2; + ++iter2; } } @@ -474,6 +571,7 @@ void Foam::Matrix<Form, Type>::operator+=(const Matrix<Form, Type>& other) template<class Form, class Type> void Foam::Matrix<Form, Type>::operator-=(const Matrix<Form, Type>& other) { + #ifdef FULLDEBUG if (this == &other) { FatalErrorInFunction @@ -489,21 +587,39 @@ void Foam::Matrix<Form, Type>::operator-=(const Matrix<Form, Type>& other) << other.m() << ", " << other.n() << ')' << nl << abort(FatalError); } + #endif + + auto iter2 = other.cbegin(); + for (Type& val : *this) + { + val -= *iter2; + ++iter2; + } +} - Type* out = this->data(); - const Type* in = other.cdata(); - const label len = this->size(); +template<class Form, class Type> +void Foam::Matrix<Form, Type>::operator+=(const Type& s) +{ + for (Type& val : *this) + { + val += s; + } +} + - for (label idx=0; idx < len; ++idx) +template<class Form, class Type> +void Foam::Matrix<Form, Type>::operator-=(const Type& s) +{ + for (Type& val : *this) { - out[idx] -= in[idx]; + val -= s; } } template<class Form, class Type> -void Foam::Matrix<Form, Type>::operator*=(const scalar s) +void Foam::Matrix<Form, Type>::operator*=(const Type& s) { for (Type& val : *this) { @@ -513,7 +629,7 @@ void Foam::Matrix<Form, Type>::operator*=(const scalar s) template<class Form, class Type> -void Foam::Matrix<Form, Type>::operator/=(const scalar s) +void Foam::Matrix<Form, Type>::operator/=(const Type& s) { for (Type& val : *this) { @@ -522,7 +638,7 @@ void Foam::Matrix<Form, Type>::operator/=(const scalar s) } -// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * // template<class Form, class Type> const Type& Foam::max(const Matrix<Form, Type>& mat) @@ -569,7 +685,7 @@ Foam::MinMax<Type> Foam::minMax(const Matrix<Form, Type>& mat) template<class Form, class Type> Form Foam::operator-(const Matrix<Form, Type>& mat) { - Form result(mat.m(), mat.n()); + Form result(mat.sizes()); std::transform ( @@ -583,9 +699,14 @@ Form Foam::operator-(const Matrix<Form, Type>& mat) } -template<class Form, class Type> -Form Foam::operator+(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B) +template<class Form1, class Form2, class Type> +Form1 Foam::operator+ +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B +) { + #ifdef FULLDEBUG if (A.m() != B.m() || A.n() != B.n()) { FatalErrorInFunction @@ -594,27 +715,31 @@ Form Foam::operator+(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B) << B.m() << ", " << B.n() << ')' << nl << abort(FatalError); } + #endif - Form AB(A.m(), A.n()); - - Type* ABv = AB.data(); - const Type* Av = A.cdata(); - const Type* Bv = B.cdata(); - - const label len = A.size(); + Form1 result(A.sizes()); - for (label idx = 0; idx < len; ++idx) - { - ABv[idx] = Av[idx] + Bv[idx]; - } + std::transform + ( + A.cbegin(), + A.cend(), + B.cbegin(), + result.begin(), + std::plus<Type>() + ); - return AB; + return result; } -template<class Form, class Type> -Form Foam::operator-(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B) +template<class Form1, class Form2, class Type> +Form1 Foam::operator- +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B +) { + #ifdef FULLDEBUG if (A.m() != B.m() || A.n() != B.n()) { FatalErrorInFunction @@ -623,85 +748,117 @@ Form Foam::operator-(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B) << B.m() << ", " << B.n() << ')' << nl << abort(FatalError); } + #endif - Form AB(A.m(), A.n()); + Form1 result(A.sizes()); - Type* ABv = AB.data(); - const Type* Av = A.cdata(); - const Type* Bv = B.cdata(); + std::transform + ( + A.cbegin(), + A.cend(), + B.cbegin(), + result.begin(), + std::minus<Type>() + ); - const label len = A.size(); + return result; +} - for (label idx=0; idx < len; ++idx) - { - ABv[idx] = Av[idx] - Bv[idx]; - } - return AB; +template<class Form, class Type> +Form Foam::operator*(const Type& s, const Matrix<Form, Type>& mat) +{ + Form result(mat.sizes()); + + std::transform + ( + mat.cbegin(), + mat.cend(), + result.begin(), + [&](const Type& val) { return s * val; } + ); + + return result; } template<class Form, class Type> -Form Foam::operator*(const scalar s, const Matrix<Form, Type>& mat) +Form Foam::operator+(const Type& s, const Matrix<Form, Type>& mat) { - Form result(mat.m(), mat.n()); + Form result(mat.sizes()); + + std::transform + ( + mat.cbegin(), + mat.cend(), + result.begin(), + [&](const Type& val) { return s + val; } + ); - const label len = mat.size(); + return result; +} - if (len) - { - Type* out = result.data(); - const Type* in = mat.cdata(); - for (label idx = 0; idx < len; ++idx) - { - out[idx] = s * in[idx]; - } - } +template<class Form, class Type> +Form Foam::operator-(const Type& s, const Matrix<Form, Type>& mat) +{ + Form result(mat.sizes()); + + std::transform + ( + mat.cbegin(), + mat.end(), + result.begin(), + [&](const Type& val) { return s - val; } + ); return result; } template<class Form, class Type> -Form Foam::operator*(const Matrix<Form, Type>& mat, const scalar s) +Form Foam::operator*(const Matrix<Form, Type>& mat, const Type& s) { - Form result(mat.m(), mat.n()); + return s*mat; +} - const label len = mat.size(); - if (len) - { - Type* out = result.data(); - const Type* in = mat.cdata(); +template<class Form, class Type> +Form Foam::operator+(const Matrix<Form, Type>& mat, const Type& s) +{ + return s + mat; +} - for (label idx=0; idx < len; ++idx) - { - out[idx] = in[idx] * s; - } - } + +template<class Form, class Type> +Form Foam::operator-(const Matrix<Form, Type>& mat, const Type& s) +{ + Form result(mat.sizes()); + + std::transform + ( + mat.cbegin(), + mat.end(), + result.begin(), + [&](const Type& val) { return val - s; } + ); return result; } template<class Form, class Type> -Form Foam::operator/(const Matrix<Form, Type>& mat, const scalar s) +Form Foam::operator/(const Matrix<Form, Type>& mat, const Type& s) { - Form result(mat.m(), mat.n()); - - const label len = mat.size(); - - if (len) - { - Type* out = result.data(); - const Type* in = mat.cdata(); + Form result(mat.sizes()); - for (label idx=0; idx < len; ++idx) - { - out[idx] = in[idx] / s; - } - } + std::transform + ( + mat.cbegin(), + mat.end(), + result.begin(), + [&](const Type& val) { return val / s; } + ); return result; } @@ -715,6 +872,7 @@ Foam::operator* const Matrix<Form2, Type>& B ) { + #ifdef FULLDEBUG if (A.n() != B.m()) { FatalErrorInFunction @@ -724,6 +882,7 @@ Foam::operator* << "The columns of A must equal rows of B" << abort(FatalError); } + #endif typename typeOfInnerProduct<Type, Form1, Form2>::type AB ( @@ -732,13 +891,97 @@ Foam::operator* Zero ); - for (label i=0; i < AB.m(); ++i) + for (label i = 0; i < AB.m(); ++i) + { + for (label k = 0; k < B.m(); ++k) + { + for (label j = 0; j < AB.n(); ++j) + { + AB(i, j) += A(i, k)*B(k, j); + } + } + } + + return AB; +} + + +template<class Form1, class Form2, class Type> +typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type +Foam::operator& +( + const Matrix<Form1, Type>& AT, + const Matrix<Form2, Type>& B +) +{ + #ifdef FULLDEBUG + if (AT.m() != B.m()) + { + FatalErrorInFunction + << "Attempt to multiply incompatible matrices:" << nl + << "Matrix A : (" << AT.m() << ", " << AT.n() << ')' << nl + << "Matrix B : (" << B.m() << ", " << B.n() << ')' << nl + << "The rows of A must equal rows of B" + << abort(FatalError); + } + #endif + + typename typeOfInnerProduct<Type, Form1, Form2>::type AB + ( + AT.n(), + B.n(), + Zero + ); + + for (label i = 0; i < AB.m(); ++i) + { + for (label k = 0; k < B.m(); ++k) + { + for (label j = 0; j < AB.n(); ++j) + { + AB(i, j) += Detail::conj(AT(k, i))*B(k, j); + } + } + } + + return AB; +} + + +template<class Form1, class Form2, class Type> +typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type +Foam::operator^ +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& BT +) +{ + #ifdef FULLDEBUG + if (A.n() != BT.n()) + { + FatalErrorInFunction + << "Attempt to multiply incompatible matrices:" << nl + << "Matrix A : (" << A.m() << ", " << A.n() << ')' << nl + << "Matrix B : (" << BT.m() << ", " << BT.n() << ')' << nl + << "The columns of A must equal columns of B" + << abort(FatalError); + } + #endif + + typename typeOfInnerProduct<Type, Form1, Form2>::type AB + ( + A.m(), + BT.m(), + Zero + ); + + for (label i = 0; i < AB.m(); ++i) { - for (label j=0; j < AB.n(); ++j) + for (label k = 0; k < BT.n(); ++k) { - for (label k=0; k < B.m(); ++k) + for (label j = 0; j < AB.n(); ++j) { - AB(i, j) += A(i, k) * B(k, j); + AB(i, j) += A(i, k)*Detail::conj(BT(j, k)); } } } diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.H b/src/OpenFOAM/matrices/Matrix/Matrix.H index bfe1c4e51fecf2d56cad216f2ae09f79e0ce199d..2aef3908967f739eee8ca85a2a04e9d2e016b3de 100644 --- a/src/OpenFOAM/matrices/Matrix/Matrix.H +++ b/src/OpenFOAM/matrices/Matrix/Matrix.H @@ -53,6 +53,7 @@ SourceFiles #include "Pair.H" #include "Field.H" #include "autoPtr.H" +#include "complex.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -74,7 +75,7 @@ class Matrix { // Private Data - //- Number of rows and columns in Matrix. + //- Number of rows and columns in Matrix label mRows_, nCols_; //- Vector of values of type Type @@ -86,11 +87,11 @@ class Matrix //- Allocate storage for the contents inline void doAlloc(); - //- Multiply matrix with vector (A * x) + //- Right-multiply Matrix by a column vector (A * x) template<class ListType> tmp<Field<Type>> AmulImpl(const ListType& x) const; - //- Multiply matrix transpose with vector (AT * x, or x * A) + //- Left-multiply Matrix by a row vector (x * A) template<class ListType> tmp<Field<Type>> TmulImpl(const ListType& x) const; @@ -138,7 +139,7 @@ public: //- Construct given number of rows/columns inline explicit Matrix(const labelPair& dims); - //- Construct given number of rows/columns. + //- Construct given number of rows/columns //- initializing all elements to zero inline Matrix(const labelPair& dims, const zero); @@ -152,15 +153,15 @@ public: //- Move construct Matrix(Matrix<Form, Type>&& mat); - //- Copy constructor from matrix of a different form + //- Copy constructor from Matrix of a different form template<class Form2> explicit Matrix(const Matrix<Form2, Type>& mat); - //- Construct from a block of another matrix + //- Construct from a block of another Matrix template<class MatrixType> Matrix(const ConstMatrixBlock<MatrixType>& Mb); - //- Construct from a block of another matrix + //- Construct from a block of another Matrix template<class MatrixType> Matrix(const MatrixBlock<MatrixType>& Mb); @@ -179,34 +180,34 @@ public: // Access - //- Return the number of rows. + //- Return the number of rows inline label m() const noexcept; - //- Return the number of columns. + //- Return the number of columns inline label n() const noexcept; - //- Return the number of elements in matrix (m*n) + //- Return the number of elements in Matrix (m*n) inline label size() const; //- Return row/column sizes inline labelPair sizes() const; - //- Return true if the matrix is empty (ie, size() is zero) + //- Return true if Matrix is empty (i.e., size() is zero) inline bool empty() const noexcept; //- Return const pointer to the first data element, which can also - //- be used to address into the matrix contents + //- be used to address into Matrix contents inline const Type* cdata() const noexcept; //- Return pointer to the first data element, which can also - //- be used to address into the matrix contents + //- be used to address into Matrix contents inline Type* data() noexcept; - //- Return const pointer to data in the specified row. + //- Return const pointer to data in the specified row // Subscript checking only with FULLDEBUG inline const Type* rowData(const label irow) const; - //- Return pointer to data in the specified row. + //- Return pointer to data in the specified row // Subscript checking only with FULLDEBUG inline Type* rowData(const label irow); @@ -219,87 +220,108 @@ public: inline Type& at(const label idx); + // Block Access (const) + + //- Return const column or column's subset of Matrix + // Return entire column by its index: M.subColumn(a); + // Return subset of a column starting from rowIndex: M.subColumn(a, b); + // Return subset of a column starting from rowIndex with szRows elems: + // M.subColumn(a, b, c); + inline ConstMatrixBlock<mType> subColumn + ( + const label colIndex, + const label rowIndex = 0, + label len = -1 + ) const; + + //- Return const row or const row's subset of Matrix + // Return entire row by its index: M.subRow(a); + // Return subset of a row starting from columnIndex: M.subRow(a,b); + // Return subset of a row starting from columnIndex with szCols elems: + // M.subRow(a, b, c); + inline ConstMatrixBlock<mType> subRow + ( + const label rowIndex, + const label colIndex = 0, + label len = -1 + ) const; + + //- Return const sub-block of Matrix + // Sub-block starting at columnIndex & rowIndex indices + inline ConstMatrixBlock<mType> subMatrix + ( + const label rowIndex, + const label colIndex, + label szRows = -1, + label szCols = -1 + ) const; + + //- Access Field as a ConstMatrixBlock + template<class VectorSpace> + inline ConstMatrixBlock<mType> block + ( + const label rowIndex, + const label colIndex + ) const; + + + // Block Access (non-const) + + //- Return column or column's subset of Matrix + inline MatrixBlock<mType> subColumn + ( + const label colIndex, + const label rowIndex = 0, + label len = -1 + ); + + //- Return row or row's subset of Matrix + inline MatrixBlock<mType> subRow + ( + const label rowIndex, + const label colIndex = 0, + label len = -1 + ); + + //- Return sub-block of Matrix + inline MatrixBlock<mType> subMatrix + ( + const label rowIndex, + const label colIndex, + label szRows = -1, + label szCols = -1 + ); + + //- Access Field as a MatrixBlock + template<class VectorSpace> + inline MatrixBlock<mType> block + ( + const label rowIndex, + const label colIndex + ); - // Block Access - - inline ConstMatrixBlock<mType> block - ( - const label m, - const label n, - const label mStart, - const label nStart - ) const; - - template<class VectorSpace> - inline ConstMatrixBlock<mType> block - ( - const label mStart, - const label nStart - ) const; - - inline ConstMatrixBlock<mType> col - ( - const label m, - const label rowStart - ) const; - - inline ConstMatrixBlock<mType> col - ( - const label m, - const label mStart, - const label nStart - ) const; - - - inline MatrixBlock<mType> block - ( - const label m, - const label n, - const label mStart, - const label nStart - ); - - template<class VectorSpace> - inline MatrixBlock<mType> block - ( - const label mStart, - const label nStart - ); - - inline MatrixBlock<mType> col - ( - const label m, - const label rowStart - ); - - inline MatrixBlock<mType> col - ( - const label m, - const label mStart, - const label nStart - ); // Check - //- Check index i is within valid range (0 ... m-1). + //- Check index i is within valid range [0, m) inline void checki(const label irow) const; - //- Check index j is within valid range (0 ... n-1). + //- Check index j is within valid range [0, n) inline void checkj(const label jcol) const; //- Check that dimensions are positive, non-zero inline void checkSize() const; - //- True if all entries have identical values, and matrix is non-empty + //- True if all entries have identical values, and Matrix is non-empty inline bool uniform() const; // Edit - //- Clear the Matrix, i.e. set sizes to zero. + //- Clear Matrix, i.e. set sizes to zero void clear(); - //- Release storage management of the Matrix contents by transferring + //- Release storage management of Matrix contents by transferring //- management to a List List<Type> release(); @@ -307,44 +329,65 @@ public: void swap(Matrix<Form, Type>& mat); //- Transfer the contents of the argument Matrix into this Matrix - //- and annul the argument Matrix. + //- and annul the argument Matrix void transfer(Matrix<Form, Type>& mat); - //- Change the matrix dimensions, preserving the elements + //- Change Matrix dimensions, preserving the elements void resize(const label m, const label n); - //- Change the matrix dimensions, preserving the elements + //- Change Matrix dimensions, preserving the elements inline void setSize(const label m, const label n); - //- Resize the matrix without reallocating storage (unsafe) + //- Resize Matrix without reallocating storage (unsafe) inline void shallowResize(const label m, const label n); + //- Round to zero elements with magnitude smaller than tol (SMALL) + void round(const scalar tol = SMALL); + // Operations - //- Return the transpose of the matrix + //- Return (conjugate) transpose of Matrix Form T() const; - //- Multiply matrix with vector (A * x) + //- Right-multiply Matrix by a column vector (A * x) inline tmp<Field<Type>> Amul(const UList<Type>& x) const; - //- Multiply matrix with vector (A * x) + //- Right-multiply Matrix by a column vector (A * x) template<class Addr> inline tmp<Field<Type>> Amul ( const IndirectListBase<Type, Addr>& x ) const; - //- Multiply matrix transpose with vector (AT * x, or x * A) + //- Left-multiply Matrix by a row vector (x * A) inline tmp<Field<Type>> Tmul(const UList<Type>& x) const; - //- Multiply matrix transpose with vector (AT * x, or x * A) + //- Left-multiply Matrix by a row vector (x * A) template<class Addr> inline tmp<Field<Type>> Tmul ( const IndirectListBase<Type, Addr>& x ) const; + //- Extract the diagonal elements. Method may change in the future. + List<Type> diag() const; + + //- Assign diagonal of Matrix + void diag(const UList<Type>& list); + + //- Return the trace + Type trace() const; + + //- Return L2-Norm of chosen column + // Optional without sqrt for parallel usage. + scalar columnNorm(const label colIndex, const bool noSqrt=false) const; + + //- Return Frobenius norm of Matrix + // Optional without sqrt for parallel usage. + // https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm + scalar norm(const bool noSqrt=false) const; + // Member Operators @@ -370,11 +413,11 @@ public: //- Move assignment void operator=(Matrix<Form, Type>&& mat); - //- Assignment to a block of another matrix + //- Assignment to a block of another Matrix template<class MatrixType> void operator=(const ConstMatrixBlock<MatrixType>& Mb); - //- Assignment to a block of another matrix + //- Assignment to a block of another Matrix template<class MatrixType> void operator=(const MatrixBlock<MatrixType>& Mb); @@ -390,14 +433,20 @@ public: //- Matrix subtraction void operator-=(const Matrix<Form, Type>& other); + //- Matrix scalar addition + void operator+=(const Type& s); + + //- Matrix scalar subtraction + void operator-=(const Type& s); + //- Matrix scalar multiplication - void operator*=(const scalar s); + void operator*=(const Type& s); //- Matrix scalar division - void operator/=(const scalar s); + void operator/=(const Type& s); - // Random access iterator (non-const) + // Random Access Iterator (non-const) //- Return an iterator to begin traversing a Matrix inline iterator begin(); @@ -406,7 +455,7 @@ public: inline iterator end(); - // Random access iterator (const) + // Random Access Iterator (const) //- Return const_iterator to begin traversing a constant Matrix inline const_iterator cbegin() const; @@ -447,10 +496,73 @@ public: { return v_; } + + //- Deprecated(2019-04) - use subMatrix() + // \deprecated(2019-04) - use subMatrix() + ConstMatrixBlock<mType> + FOAM_DEPRECATED_FOR(2019-04, "subMatrix() method") block + ( + const label m, + const label n, + const label mStart, + const label nStart + ) const + { + return this->subMatrix(mStart, nStart, m, n); + } + + //- Deprecated(2019-04) - use subMatrix() + // \deprecated(2019-04) - use subMatrix() + MatrixBlock<mType> + FOAM_DEPRECATED_FOR(2019-04, "subMatrix() method") block + ( + const label m, + const label n, + const label mStart, + const label nStart + ) + { + return this->subMatrix(mStart, nStart, m, n); + } + + + //- Deprecated(2019-04) - use subColumn() + // \deprecated(2019-04) - use subColumn() + ConstMatrixBlock<mType> + FOAM_DEPRECATED_FOR(2019-04, "subColumn() method") col + ( + const label m, + const label mStart, + const label nStart + ) const + { + return this->subColumn(nStart, mStart, m); + } + + //- Deprecated(2019-04) - use subColumn() + // \deprecated(2019-04) - use subColumn() + MatrixBlock<mType> + FOAM_DEPRECATED_FOR(2019-04, "subColumn() method") col + ( + const label m, + const label mStart, + const label nStart + ) + { + return this->subColumn(nStart, mStart, m); + } + + //- Deleted(2019-04) - use subColumn() + // \deprecated(2019-04) - use subColumn() + void col(const label m, const label rowStart) const = delete; + + //- Deleted(2019-04) - use subColumn() + // \deprecated(2019-04) - use subColumn() + void col(const label m, const label rowStart) = delete; }; -// IOstream Operators +// * * * * * * * * * * * * * * * IOstream Operator * * * * * * * * * * * * * // //- Read Matrix from Istream, discarding contents of existing Matrix. template<class Form, class Type> @@ -462,70 +574,100 @@ template<class Form, class Type> Ostream& operator<<(Ostream& os, const Matrix<Form, Type>& mat); -// Global Functions, Operators +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * // -//- Find max value in the matrix +//- Find max value in Matrix template<class Form, class Type> const Type& max(const Matrix<Form, Type>& mat); -//- Find min value in the matrix +//- Find min value in Matrix template<class Form, class Type> const Type& min(const Matrix<Form, Type>& mat); -//- Find the min/max values of the matrix +//- Find the min/max values of Matrix template<class Form, class Type> MinMax<Type> minMax(const Matrix<Form, Type>& mat); + +// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * * // + //- Matrix negation template<class Form, class Type> Form operator-(const Matrix<Form, Type>& mat); -//- Matrix addition -template<class Form, class Type> -Form operator+ +//- Matrix addition. Returns Matrix of the same form as the first parameter. +template<class Form1, class Form2, class Type> +Form1 operator+ ( - const Matrix<Form, Type>& A, - const Matrix<Form, Type>& B + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B ); +//- Matrix subtraction. Returns Matrix of the same form as the first parameter. +template<class Form1, class Form2, class Type> +Form1 operator- +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B +); -//- Matrix subtraction +//- Scalar multiplication of Matrix template<class Form, class Type> -Form operator- +Form operator* ( - const Matrix<Form, Type>& A, - const Matrix<Form, Type>& B + const Type& s, + const Matrix<Form, Type>& mat ); - -//- Scalar multiplication of a matrix +//- Scalar addition of Matrix template<class Form, class Type> -Form operator* +Form operator+ ( - const scalar s, + const Type& s, const Matrix<Form, Type>& mat ); +//- Scalar subtraction of Matrix +template<class Form, class Type> +Form operator- +( + const Type& s, + const Matrix<Form, Type>& mat +); -//- Scalar multiplication of a matrix +//- Scalar multiplication of Matrix template<class Form, class Type> Form operator* ( const Matrix<Form, Type>& mat, - const scalar s + const Type& s ); +//- Scalar addition of Matrix +template<class Form, class Type> +Form operator+ +( + const Matrix<Form, Type>& mat, + const Type& s +); -//- Scalar division of a matrix +//- Scalar subtraction of Matrix template<class Form, class Type> -Form operator/ +Form operator- ( const Matrix<Form, Type>& mat, - const scalar s + const Type& s ); +//- Scalar division of Matrix +template<class Form, class Type> +Form operator/ +( + const Matrix<Form, Type>& mat, + const Type& s +); -//- Matrix-matrix multiplication +//- Matrix-Matrix multiplication using ikj-algorithm template<class Form1, class Form2, class Type> typename typeOfInnerProduct<Type, Form1, Form2>::type operator* @@ -534,7 +676,6 @@ operator* const Matrix<Form2, Type>& B ); - //- Matrix-vector multiplication (A * x), where x is a column vector template<class Form, class Type> inline tmp<Field<Type>> operator* @@ -551,8 +692,7 @@ inline tmp<Field<Type>> operator* const IndirectListBase<Type, Addr>& x ); - -//- Vector-matrix multiplication (x * A), where x is a row vector +//- Vector-Matrix multiplication (x * A), where x is a row vector template<class Form, class Type> inline tmp<Field<Type>> operator* ( @@ -560,7 +700,7 @@ inline tmp<Field<Type>> operator* const Matrix<Form, Type>& mat ); -//- Vector-matrix multiplication (x * A), where x is a row vector +//- Vector-Matrix multiplication (x * A), where x is a row vector template<class Form, class Type, class Addr> inline tmp<Field<Type>> operator* ( @@ -568,6 +708,24 @@ inline tmp<Field<Type>> operator* const Matrix<Form, Type>& mat ); +//- Implicit inner product of Matrix-Matrix, equivalent to A.T()*B +template<class Form1, class Form2, class Type> +typename typeOfInnerProduct<Type, Form1, Form2>::type +operator& +( + const Matrix<Form1, Type>& ATranspose, + const Matrix<Form2, Type>& B +); + +//- Implicit outer product of Matrix-Matrix, equivalent to A*B.T() +template<class Form1, class Form2, class Type> +typename typeOfInnerProduct<Type, Form1, Form2>::type +operator^ +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& BTranspose +); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/matrices/Matrix/MatrixI.H b/src/OpenFOAM/matrices/Matrix/MatrixI.H index d6e3d836c674c1f80a0c6c2ec94cf9f382033e32..4c229fbd1879636c12dbf90a3f3238c7f406021e 100644 --- a/src/OpenFOAM/matrices/Matrix/MatrixI.H +++ b/src/OpenFOAM/matrices/Matrix/MatrixI.H @@ -128,40 +128,36 @@ inline bool Foam::Matrix<Form, Type>::empty() const noexcept template<class Form, class Type> inline void Foam::Matrix<Form, Type>::checki(const label i) const { - #ifdef FULLDEBUG if (!mRows_ || !nCols_) { FatalErrorInFunction << "Attempt to access element from empty matrix" << abort(FatalError); } - if (i < 0 || i >= mRows_) + if (i < 0 || mRows_ <= i) { FatalErrorInFunction << "Index " << i << " out of range 0 ... " << mRows_-1 << abort(FatalError); } - #endif } template<class Form, class Type> inline void Foam::Matrix<Form, Type>::checkj(const label j) const { - #ifdef FULLDEBUG if (!mRows_ || !nCols_) { FatalErrorInFunction << "Attempt to access element from empty matrix" << abort(FatalError); } - if (j < 0 || j >= nCols_) + if (j < 0 || nCols_ <= j) { FatalErrorInFunction << "index " << j << " out of range 0 ... " << nCols_-1 << abort(FatalError); } - #endif } @@ -238,7 +234,7 @@ template<class Form, class Type> inline const Type& Foam::Matrix<Form, Type>::at(const label idx) const { #ifdef FULLDEBUG - if (idx < 0 || idx >= this->size()) + if (idx < 0 || this->size() <= idx) { FatalErrorInFunction << "index " << idx << " out of range 0 ... " << this->size() @@ -253,7 +249,7 @@ template<class Form, class Type> inline Type& Foam::Matrix<Form, Type>::at(const label idx) { #ifdef FULLDEBUG - if (idx < 0 || idx >= this->size()) + if (idx < 0 || this->size() <= idx) { FatalErrorInFunction << "index " << idx << " out of range 0 ... " << this->size() @@ -266,152 +262,188 @@ inline Type& Foam::Matrix<Form, Type>::at(const label idx) template<class Form, class Type> inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::block +Foam::Matrix<Form, Type>::subColumn ( - const label m, - const label n, - const label mStart, - const label nStart + const label colIndex, + const label rowIndex, + label len ) const { + if (len < 0) + { + len = mRows_ - rowIndex; + } + return ConstMatrixBlock<mType> ( *this, - m, - n, - mStart, - nStart + len, // rows + 1, + rowIndex, + colIndex ); } template<class Form, class Type> -template<class VectorSpace> inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::block +Foam::Matrix<Form, Type>::subRow ( - const label mStart, - const label nStart + const label rowIndex, + const label colIndex, + label len ) const { + if (len < 0) + { + len = nCols_ - colIndex; + } + return ConstMatrixBlock<mType> ( *this, - VectorSpace::mRows, - VectorSpace::nCols, - mStart, - nStart + 1, + len, // columns + rowIndex, + colIndex ); } template<class Form, class Type> inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::col +Foam::Matrix<Form, Type>::subMatrix ( - const label m, - const label mStart + const label rowIndex, + const label colIndex, + label szRows, + label szCols ) const { + if (szRows < 0) szRows = mRows_ - rowIndex; + if (szCols < 0) szCols = nCols_ - colIndex; + return ConstMatrixBlock<mType> ( *this, - m, - 1, - mStart, - 0 + szRows, + szCols, + rowIndex, + colIndex ); } template<class Form, class Type> +template<class VectorSpace> inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::col +Foam::Matrix<Form, Type>::block ( - const label m, - const label mStart, - const label nStart + const label rowIndex, + const label colIndex ) const { return ConstMatrixBlock<mType> ( *this, - m, - 1, - mStart, - nStart + VectorSpace::mRows, + VectorSpace::nCols, + rowIndex, + colIndex ); } template<class Form, class Type> inline Foam::MatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::block +Foam::Matrix<Form, Type>::subColumn ( - const label m, - const label n, - const label mStart, - const label nStart + const label colIndex, + const label rowIndex, + label len ) { + if (len < 0) + { + len = mRows_ - rowIndex; + } + return MatrixBlock<mType> ( *this, - m, - n, - mStart, - nStart + len, // rows + 1, + rowIndex, + colIndex ); } template<class Form, class Type> -template<class VectorSpace> inline Foam::MatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::block(const label mStart, const label nStart) +Foam::Matrix<Form, Type>::subRow +( + const label rowIndex, + const label colIndex, + label len +) { + if (len < 0) + { + len = nCols_ - colIndex; + } + return MatrixBlock<mType> ( *this, - VectorSpace::mRows, - VectorSpace::nCols, - mStart, - nStart + 1, + len, // columns + rowIndex, + colIndex ); } template<class Form, class Type> inline Foam::MatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::col(const label m, const label mStart) +Foam::Matrix<Form, Type>::subMatrix +( + const label rowIndex, + const label colIndex, + label szRows, + label szCols +) { + if (szRows < 0) szRows = mRows_ - rowIndex; + if (szCols < 0) szCols = nCols_ - colIndex; + return MatrixBlock<mType> ( *this, - m, - 1, - mStart, - 0 + szRows, + szCols, + rowIndex, + colIndex ); } template<class Form, class Type> +template<class VectorSpace> inline Foam::MatrixBlock<Foam::Matrix<Form, Type>> -Foam::Matrix<Form, Type>::col +Foam::Matrix<Form, Type>::block ( - const label m, - const label mStart, - const label nStart + const label rowIndex, + const label colIndex ) { return MatrixBlock<mType> ( *this, - m, - 1, - mStart, - nStart + VectorSpace::mRows, + VectorSpace::nCols, + rowIndex, + colIndex ); } @@ -532,8 +564,10 @@ inline const Type& Foam::Matrix<Form, Type>::operator() const label jcol ) const { + #ifdef FULLDEBUG checki(irow); checkj(jcol); + #endif return v_[irow*nCols_ + jcol]; } @@ -545,8 +579,10 @@ inline Type& Foam::Matrix<Form, Type>::operator() const label jcol ) { + #ifdef FULLDEBUG checki(irow); checkj(jcol); + #endif return v_[irow*nCols_ + jcol]; } @@ -554,7 +590,9 @@ inline Type& Foam::Matrix<Form, Type>::operator() template<class Form, class Type> inline const Type* Foam::Matrix<Form, Type>::operator[](const label irow) const { + #ifdef FULLDEBUG checki(irow); + #endif return v_ + irow*nCols_; } @@ -562,7 +600,9 @@ inline const Type* Foam::Matrix<Form, Type>::operator[](const label irow) const template<class Form, class Type> inline Type* Foam::Matrix<Form, Type>::operator[](const label irow) { + #ifdef FULLDEBUG checki(irow); + #endif return v_ + irow*nCols_; } diff --git a/src/OpenFOAM/matrices/Matrix/MatrixTools.C b/src/OpenFOAM/matrices/Matrix/MatrixTools.C new file mode 100644 index 0000000000000000000000000000000000000000..5ce736cdf3980a003a81c8bf5635474d125953d2 --- /dev/null +++ b/src/OpenFOAM/matrices/Matrix/MatrixTools.C @@ -0,0 +1,136 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "MatrixTools.H" + +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * // + +template<class Form1, class Form2, class Type> +bool Foam::MatrixTools::equal +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B, + const bool verbose, + const scalar relTol, + const scalar absTol +) +{ + const label len = A.size(); + + if (len != B.size()) + { + if (verbose) + { + Info<< "Matrices have different sizes: " + << len << " vs " << B.size() << nl; + } + return false; + } + + auto iter1 = A.cbegin(); + auto iter2 = B.cbegin(); + + for (label i = 0; i < len; ++i) + { + if ((absTol + relTol*mag(*iter2)) < Foam::mag(*iter1 - *iter2)) + { + if (verbose) + { + Info<< "Matrix element " << i + << " differs beyond tolerance: " + << *iter1 << " vs " << *iter2 << nl; + } + return false; + } + + ++iter1; + ++iter2; + } + + if (verbose) + { + Info<< "All elements equal within the tolerances" << nl; + } + + return true; +} + + +template<class Container> +Foam::Ostream& Foam::MatrixTools::printMatrix +( + Ostream& os, + const Container& mat +) +{ + os << mat.m() << ' ' << mat.n(); + + if (mat.m() == 1) + { + // row-vector + os << " ("; + for (label j = 0; j < mat.n(); ++j) + { + if (j) os << ' '; + os << mat(0,j); + } + os << ')' << nl; + } + else if (mat.n() == 1) + { + // col-vector + + os << " ("; + for (label i = 0; i < mat.m(); ++i) + { + if (i) os << ' '; + os << mat(i,0); + } + os << ')' << nl; + } + else + { + // Regular + + os << nl << '(' << nl; + + for (label i = 0; i < mat.m(); ++i) + { + os << '('; + for (label j = 0; j < mat.n(); ++j) + { + if (j) os << ' '; + os << mat(i,j); + } + os << ')' << nl; + } + os << ')' << nl; + } + + return os; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/matrices/Matrix/MatrixTools.H b/src/OpenFOAM/matrices/Matrix/MatrixTools.H new file mode 100644 index 0000000000000000000000000000000000000000..8c63efc0fe0d2ba349caefb4e73d26fb350ac97e --- /dev/null +++ b/src/OpenFOAM/matrices/Matrix/MatrixTools.H @@ -0,0 +1,90 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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 <http://www.gnu.org/licenses/>. + +Namespace + Foam::MatrixTools + +Description + Collection of static functions for matrix-related verifications. + +SourceFiles + MatrixTools.C + +\*---------------------------------------------------------------------------*/ + +#ifndef MatrixTools_H +#define MatrixTools_H + +#include "Matrix.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declarations +class Ostream; + + +/*---------------------------------------------------------------------------*\ + Namespace MatrixTools Declaration +\*---------------------------------------------------------------------------*/ + +namespace MatrixTools +{ + +//- Compare matrix elements for absolute or relative equality +template<class Form1, class Form2, class Type> +bool equal +( + const Matrix<Form1, Type>& A, + const Matrix<Form2, Type>& B, + const bool verbose = false, + const scalar relTol = 1e-5, + const scalar absTol = 1e-8 +); + + +//- Simple ASCII output of Matrix, MatrixBlock +template<class Container> +Ostream& printMatrix(Ostream& os, const Container& mat); + + +} // End namespace MatrixTools + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "MatrixTools.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C index 2784a342a369fec7379c0691da68aa302285eb3c..7ced3ca8de125530acbffb654e374810de26d053 100644 --- a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C +++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | + \\ / A nd | Copyright (C) 2004-2010, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2016 OpenFOAM Foundation @@ -71,6 +71,76 @@ Foam::MatrixBlock<MatrixType>::operator Field<cmptType>() const } +template<class MatrixType> +Foam::label Foam::ConstMatrixBlock<MatrixType>::disallow +( + const char* what +) const +{ + FatalErrorInFunction + << "Block addresses " << what + << " outside matrix or invalid matrix components" + << abort(FatalError); + return 0; +} + + +template<class MatrixType> +Foam::label Foam::MatrixBlock<MatrixType>::disallow +( + const char* what +) const +{ + FatalErrorInFunction + << "Block addresses " << what + << " outside matrix or invalid matrix components" + << abort(FatalError); + return 0; +} + + +template<class MatrixType> void Foam::ConstMatrixBlock<MatrixType>::checkIndex +( + const label i, + const label j +) const +{ + if (i < 0 || i >= mRows_) + { + FatalErrorInFunction + << "Index " << i << " is out of range 0 ... " << mRows_ - 1 + << abort(FatalError); + } + else if (j < 0 || j >= nCols_) + { + FatalErrorInFunction + << "Index " << j << " is out of range 0 ... " << nCols_ - 1 + << abort(FatalError); + } +} + + +template<class MatrixType> void Foam::MatrixBlock<MatrixType>::checkIndex +( + const label i, + const label j +) const +{ + if (i < 0 || i >= mRows_) + { + FatalErrorInFunction + << "Index " << i << " is out of range 0 ... " << mRows_ - 1 + << abort(FatalError); + } + else if (j < 0 || j >= nCols_) + { + FatalErrorInFunction + << "Index " << j << " is out of range 0 ... " << nCols_ - 1 + << abort(FatalError); + } +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template<class MatrixType> diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H index 27e90c7a9f4d77811d82e8fcd720a17201734e86..bb3cf1d95e9194888cbda316528628445c7e7867 100644 --- a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H +++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2004-2010, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2016 OpenFOAM Foundation @@ -65,14 +65,21 @@ class ConstMatrixBlock //- Const reference to the parent matrix const MatrixType& matrix_; - // Block size + //- Block size const label mRows_; const label nCols_; - // Block location in parent matrix + //- Block location in parent matrix const label rowStart_; const label colStart_; + + // Private Member Functions + + //- Error message for failed sanity checks during matrix construction + label disallow(const char *what) const; + + public: typedef typename MatrixType::cmptType cmptType; @@ -110,6 +117,9 @@ public: //- Convert a column of a matrix to a Field operator Field<cmptType>() const; + + //- Check if (i, j) is within range of row-column limits + void checkIndex(const label i, const label j) const; }; @@ -125,14 +135,21 @@ class MatrixBlock //- Reference to the parent matrix MatrixType& matrix_; - // Block size + //- Block size const label mRows_; const label nCols_; - // Block location in parent matrix + //- Block location in parent matrix const label rowStart_; const label colStart_; + + // Private Member Functions + + //- Error message for failed sanity checks during matrix construction + label disallow(const char *what) const; + + public: typedef typename MatrixType::cmptType cmptType; @@ -174,8 +191,11 @@ public: //- Convert a column of a matrix to a Field operator Field<cmptType>() const; + //- Check if (i, j) is within range of row-column limits + void checkIndex(const label i, const label j) const; + - // Member operators + // Member Operators //- Assignment to a compatible matrix template<class Form> diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H index 408f1393a10213472dbbc78186f4e129f6b59829..e6a47e0ba4c63e6c7f363750a7bb1ce689d8b959 100644 --- a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H +++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2004-2010, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2016 OpenFOAM Foundation @@ -38,24 +38,21 @@ Foam::ConstMatrixBlock<MatrixType>::ConstMatrixBlock ) : matrix_(matrix), - mRows_(m), - nCols_(n), - rowStart_(mStart), - colStart_(nStart) -{ - #ifdef FULLDEBUG - if + mRows_(0 < m ? m : disallow("row dim")), + nCols_(0 < n ? n : disallow("col dim")), + rowStart_ + ( + 0 <= mStart + || mStart + mRows_ <= matrix.m() + ? mStart : disallow("row start") + ), + colStart_ ( - rowStart_ + mRows_ > matrix.m() - || colStart_ + nCols_ > matrix.n() + 0 <= nStart + || nStart + nCols_ <= matrix.n() + ? nStart : disallow("col start") ) - { - FatalErrorInFunction - << "Block addresses outside matrix" - << abort(FatalError); - } - #endif -} +{} template<class MatrixType> @@ -69,24 +66,21 @@ Foam::MatrixBlock<MatrixType>::MatrixBlock ) : matrix_(matrix), - mRows_(m), - nCols_(n), - rowStart_(mStart), - colStart_(nStart) -{ - #ifdef FULLDEBUG - if + mRows_(0 < m ? m : disallow("row dim")), + nCols_(0 < n ? n : disallow("col dim")), + rowStart_ + ( + 0 <= mStart + || mStart + mRows_ <= matrix.m() + ? mStart : disallow("row start") + ), + colStart_ ( - rowStart_ + mRows_ > matrix.m() - || colStart_ + nCols_ > matrix.n() + 0 <= nStart + || nStart + nCols_ <= matrix.n() + ? nStart : disallow("col start") ) - { - FatalErrorInFunction - << "Block addresses outside matrix" - << abort(FatalError); - } - #endif -} +{} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -144,18 +138,7 @@ Foam::ConstMatrixBlock<MatrixType>::operator() ) const { #ifdef FULLDEBUG - if (i<0 || i>=mRows_) - { - FatalErrorInFunction - << "Index " << i << " out of range 0 ... " << mRows_-1 - << abort(FatalError); - } - if (j<0 || j>=nCols_) - { - FatalErrorInFunction - << "Index " << j << " out of range 0 ... " << nCols_-1 - << abort(FatalError); - } + checkIndex(i, j); #endif return matrix_(i + rowStart_, j + colStart_); @@ -171,18 +154,7 @@ Foam::MatrixBlock<MatrixType>::operator() ) const { #ifdef FULLDEBUG - if (i<0 || i>=mRows_) - { - FatalErrorInFunction - << "Index " << i << " out of range 0 ... " << mRows_-1 - << abort(FatalError); - } - if (j<0 || j>=nCols_) - { - FatalErrorInFunction - << "Index " << j << " out of range 0 ... " << nCols_-1 - << abort(FatalError); - } + checkIndex(i, j); #endif return matrix_(i + rowStart_, j + colStart_); @@ -198,18 +170,7 @@ Foam::MatrixBlock<MatrixType>::operator() ) { #ifdef FULLDEBUG - if (i<0 || i>=mRows_) - { - FatalErrorInFunction - << "Index " << i << " out of range 0 ... " << mRows_-1 - << abort(FatalError); - } - if (j<0 || j>=nCols_) - { - FatalErrorInFunction - << "Index " << j << " out of range 0 ... " << nCols_-1 - << abort(FatalError); - } + checkIndex(i, j); #endif return matrix_(i + rowStart_, j + colStart_); diff --git a/src/OpenFOAM/matrices/QRMatrix/QRMatrix.C b/src/OpenFOAM/matrices/QRMatrix/QRMatrix.C index ea3c437a860cbedd2f96289777dee65ed188d8e3..624db7b7dcd0dc6e87378bb16c940bee028e8f18 100644 --- a/src/OpenFOAM/matrices/QRMatrix/QRMatrix.C +++ b/src/OpenFOAM/matrices/QRMatrix/QRMatrix.C @@ -282,7 +282,7 @@ Foam::QRMatrix<MatrixType>::inv() const x[j] = Q_(i, j); } solvex(x); - inv.block(m, 1, 0, i) = x; + inv.subColumn(i) = x; } return inv; diff --git a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H index 68ecd56a598cfadac6e473c1fe3fc2949ff033d3..668e0241b013dbd326acb5444144bbbe184b60b1 100644 --- a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H +++ b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H @@ -118,7 +118,7 @@ public: }; -// Global functions and operators +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // template<class Type> class typeOfInnerProduct<Type, RectangularMatrix<Type>, RectangularMatrix<Type>> @@ -128,6 +128,7 @@ public: typedef RectangularMatrix<Type> type; }; + template<class Type> class typeOfInnerProduct<Type, RectangularMatrix<Type>, SquareMatrix<Type>> { @@ -136,6 +137,7 @@ public: typedef RectangularMatrix<Type> type; }; + template<class Type> class typeOfInnerProduct<Type, SquareMatrix<Type>, RectangularMatrix<Type>> { @@ -145,6 +147,8 @@ public: }; +// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // + template<class Type> RectangularMatrix<Type> outer(const Field<Type>& f1, const Field<Type>& f2); diff --git a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H index da3e03b53f3025f61cad5ab1b2313baf84e4c00e..1ff31473717866cc5d894e7a972226fbe59e6751 100644 --- a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H +++ b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H @@ -190,9 +190,9 @@ inline Foam::RectangularMatrix<Type> outer { RectangularMatrix<Type> f1f2T(f1.size(), f2.size()); - for (label i=0; i<f1f2T.m(); i++) + for (label i = 0; i < f1f2T.m(); ++i) { - for (label j=0; j<f1f2T.n(); j++) + for (label j = 0; j < f1f2T.n(); ++j) { f1f2T(i, j) = f1[i]*f2[j]; } diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C index b48d01545c376a421fde9fb38c1d4d9f4afa925f..848b4901b32ad2d6b51b17b56bdfd7abb6755b1b 100644 --- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C +++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | + \\ / A nd | Copyright (C) 2004-2010, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2013-2016 OpenFOAM Foundation @@ -26,6 +26,7 @@ License \*---------------------------------------------------------------------------*/ #include "SquareMatrix.H" +#include "RectangularMatrix.H" #include "labelList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -39,7 +40,7 @@ Foam::scalar Foam::detDecomposed { Type diagProduct = pTraits<Type>::one; - for (label i=0; i<matrix.m(); i++) + for (label i = 0; i < matrix.m(); ++i) { diagProduct *= matrix(i, i); } diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H index dec80275bd28fdb80584b8ccb1e4b66c7d404cb6..1bd82812157b4d15bd8ef9edd38932e1436a9505 100644 --- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H +++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H @@ -149,7 +149,7 @@ public: }; -// Global functions and operators +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // //- Return the LU decomposed SquareMatrix det template<class Type> @@ -171,7 +171,6 @@ public: typedef SquareMatrix<Type> type; }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H index 4e1b3ca483b02b06388b1a4bbbf97cf69db86098..47897b61dc033b4df7751e52797874e06719cb97 100644 --- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H +++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H @@ -251,9 +251,9 @@ inline Foam::SquareMatrix<Type> symmOuter { SquareMatrix<Type> f1f2T(f1.size()); - for (label i=0; i<f1f2T.m(); i++) + for (label i = 0; i < f1f2T.m(); ++i) { - for (label j=0; j<f1f2T.n(); j++) + for (label j = 0; j < f1f2T.n(); ++j) { f1f2T(i, j) = f1[i]*f2[j]; }