Skip to content
Snippets Groups Projects
Test-Matrix.C 29 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
        \\  /    A nd           | www.openfoam.com
    
         \\/     M anipulation  |
    
    -------------------------------------------------------------------------------
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
        Copyright (C) 2011-2016 OpenFOAM Foundation
        Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
    
    
    \*---------------------------------------------------------------------------*/
    
    
    #include "MatrixTools.H"
    
    #include "Random.H"
    #include "SortList.H"
    
    #include "Switch.H"
    
    #include <algorithm>
    
    
    using namespace Foam;
    
    using namespace Foam::MatrixTools;
    
    
    #define RUNALL true
    
    #define isEqual MatrixTools::equal
    
    void horizontalLine()
    {
        Info<< "+---------+---------+---------+---------+---------+" << nl;
    }
    
    
    // Copy values into matrix
    template<class Form, class Type>
    void assignMatrix
    (
        Matrix<Form, Type>& mat,
        std::initializer_list<typename Matrix<Form, Type>::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<class MatrixType>
    
    MatrixType makeRandomMatrix
    
    (
        const labelPair& dims,
    
    )
    {
        MatrixType mat(dims);
    
    
        std::generate
        (
            mat.begin(),
            mat.end(),
            [&]{return rndGen.GaussNormal<typename MatrixType::cmptType>();}
        );
    
    template<class MatrixType>
    Ostream& operator<<(Ostream& os, const ConstMatrixBlock<MatrixType>& mat)
    
        return MatrixTools::printMatrix(os, mat);
    }
    
    template<class MatrixType>
    Ostream& operator<<(Ostream& os, const MatrixBlock<MatrixType>& mat)
    {
        return MatrixTools::printMatrix(os, mat);
    
    // * * * * * * * * * * * * * * * Main Program  * * * * * * * * * * * * * * * //
    
    
    int main(int argc, char *argv[])
    {
    
        typedef SquareMatrix<scalar> SMatrix;
        typedef SquareMatrix<complex> SCMatrix;
        typedef RectangularMatrix<scalar> RMatrix;
        typedef RectangularMatrix<complex> RCMatrix;
    
        Random rndGen(1234);
    
    
        #if (0 | RUNALL)
    
        {
            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 (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<scalar> 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
    
        #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<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 (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<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);
    
                    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<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);
            }
    
            Info<< "# Diagonal sort of Matrix:" << nl;
    
                    makeRandomMatrix<SMatrix>
    
                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 (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<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
    
        #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<scalar> S1 = " << S1 << nl;
                Info<< "SquareMatrix<scalar> S2 = " << S2 << nl;
                Info<< "SquareMatrix<scalar> 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<scalar> 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<scalar>:" << 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<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}
                );
    
                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);
    
                    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();
    
        #if (0 | RUNALL)
    
            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<complex> S1 = " << S1 << nl;
                Info<< "SquareMatrix<complex> S2 = " << S2 << nl;
                Info<< "SquareMatrix<complex> 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<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)
    
                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;
    
            #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();
    
        #if (0 | RUNALL)
        {
            horizontalLine();
    
            Info<< "## Query to determine if a square matrix is symmetric:" << nl;
    
            {
                const label mRows = 100;
                SMatrix A(makeRandomMatrix<SMatrix>({mRows, mRows}, rndGen));
    
                Info<< "# SquareMatrix<scalar>.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<scalar>.symmetric():" << nl
                    << A.symmetric() << nl;
            }
    
            {
                const label mRows = 100;
    
                SCMatrix A(mRows);
    
                for (auto& val : A)
                {
                    val.Re() = rndGen.GaussNormal<scalar>();
                    val.Im() = rndGen.GaussNormal<scalar>();
                }
    
                Info<< "# SquareMatrix<complex>.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<complex>.symmetric():" << nl
                    << A.symmetric() << nl;
            }
    
            horizontalLine();
        }
        #endif
    
    
        #if (0 | RUNALL)
    
            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;
    
        #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));