123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Vector.h>
- #include <Mathematics/GaussianElimination.h>
- namespace WwiseGTE
- {
- template <int NumRows, int NumCols, typename Real>
- class Matrix
- {
- public:
- // The table is initialized to zero.
- Matrix()
- {
- MakeZero();
- }
- // The table is fully initialized by the inputs. The 'values' must be
- // specified in row-major order, regardless of the active storage
- // scheme (GTE_USE_ROW_MAJOR or GTE_USE_COL_MAJOR).
- Matrix(std::array<Real, NumRows * NumCols> const& values)
- {
- for (int r = 0, i = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c, ++i)
- {
- mTable(r, c) = values[i];
- }
- }
- }
- // At most NumRows*NumCols are copied from the initializer list,
- // setting any remaining elements to zero. The 'values' must be
- // specified in row-major order, regardless of the active storage
- // scheme (GTE_USE_ROW_MAJOR or GTE_USE_COL_MAJOR). Create the zero
- // matrix using the syntax
- // Matrix<NumRows,NumCols,Real> zero{(Real)0};
- // WARNING: The C++ 11 specification states that
- // Matrix<NumRows,NumCols,Real> zero{};
- // will lead to a call of the default constructor, not the initializer
- // constructor!
- Matrix(std::initializer_list<Real> values)
- {
- int const numValues = static_cast<int>(values.size());
- auto iter = values.begin();
- int r, c, i;
- for (r = 0, i = 0; r < NumRows; ++r)
- {
- for (c = 0; c < NumCols; ++c, ++i)
- {
- if (i < numValues)
- {
- mTable(r, c) = *iter++;
- }
- else
- {
- break;
- }
- }
- if (c < NumCols)
- {
- // Fill in the remaining columns of the current row with zeros.
- for (/**/; c < NumCols; ++c)
- {
- mTable(r, c) = (Real)0;
- }
- ++r;
- break;
- }
- }
- if (r < NumRows)
- {
- // Fill in the remain rows with zeros.
- for (/**/; r < NumRows; ++r)
- {
- for (c = 0; c < NumCols; ++c)
- {
- mTable(r, c) = (Real)0;
- }
- }
- }
- }
- // For 0 <= r < NumRows and 0 <= c < NumCols, element (r,c) is 1 and
- // all others are 0. If either of r or c is invalid, the zero matrix
- // is created. This is a convenience for creating the standard
- // Euclidean basis matrices; see also MakeUnit(int,int) and
- // Unit(int,int).
- Matrix(int r, int c)
- {
- MakeUnit(r, c);
- }
- // The copy constructor, destructor, and assignment operator are
- // generated by the compiler.
- // Member access for which the storage representation is transparent.
- // The matrix entry in row r and column c is A(r,c). The first
- // operator() returns a const reference rather than a Real value.
- // This supports writing via standard file operations that require a
- // const pointer to data.
- inline Real const& operator()(int r, int c) const
- {
- return mTable(r, c);
- }
- inline Real& operator()(int r, int c)
- {
- return mTable(r, c);
- }
- // Member access by rows or by columns.
- void SetRow(int r, Vector<NumCols, Real> const& vec)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- mTable(r, c) = vec[c];
- }
- }
- void SetCol(int c, Vector<NumRows, Real> const& vec)
- {
- for (int r = 0; r < NumRows; ++r)
- {
- mTable(r, c) = vec[r];
- }
- }
- Vector<NumCols, Real> GetRow(int r) const
- {
- Vector<NumCols, Real> vec;
- for (int c = 0; c < NumCols; ++c)
- {
- vec[c] = mTable(r, c);
- }
- return vec;
- }
- Vector<NumRows, Real> GetCol(int c) const
- {
- Vector<NumRows, Real> vec;
- for (int r = 0; r < NumRows; ++r)
- {
- vec[r] = mTable(r, c);
- }
- return vec;
- }
- // Member access by 1-dimensional index. NOTE: These accessors are
- // useful for the manipulation of matrix entries when it does not
- // matter whether storage is row-major or column-major. Do not use
- // constructs such as M[c+NumCols*r] or M[r+NumRows*c] that expose the
- // storage convention.
- inline Real const& operator[](int i) const
- {
- return mTable[i];
- }
- inline Real& operator[](int i)
- {
- return mTable[i];
- }
- // Comparisons for sorted containers and geometric ordering.
- inline bool operator==(Matrix const& mat) const
- {
- return mTable.mStorage == mat.mTable.mStorage;
- }
- inline bool operator!=(Matrix const& mat) const
- {
- return mTable.mStorage != mat.mTable.mStorage;
- }
- inline bool operator< (Matrix const& mat) const
- {
- return mTable.mStorage < mat.mTable.mStorage;
- }
- inline bool operator<=(Matrix const& mat) const
- {
- return mTable.mStorage <= mat.mTable.mStorage;
- }
- inline bool operator> (Matrix const& mat) const
- {
- return mTable.mStorage > mat.mTable.mStorage;
- }
- inline bool operator>=(Matrix const& mat) const
- {
- return mTable.mStorage >= mat.mTable.mStorage;
- }
- // Special matrices.
- // All components are 0.
- void MakeZero()
- {
- Real const zero(0);
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- mTable[i] = zero;
- }
- }
- // Component (r,c) is 1, all others zero.
- void MakeUnit(int r, int c)
- {
- MakeZero();
- if (0 <= r && r < NumRows && 0 <= c && c < NumCols)
- {
- mTable(r, c) = (Real)1;
- }
- }
- // Diagonal entries 1, others 0, even when nonsquare
- void MakeIdentity()
- {
- MakeZero();
- int const numDiagonal = (NumRows <= NumCols ? NumRows : NumCols);
- for (int i = 0; i < numDiagonal; ++i)
- {
- mTable(i, i) = (Real)1;
- }
- }
- static Matrix Zero()
- {
- Matrix M;
- M.MakeZero();
- return M;
- }
- static Matrix Unit(int r, int c)
- {
- Matrix M;
- M.MakeUnit(r, c);
- return M;
- }
- static Matrix Identity()
- {
- Matrix M;
- M.MakeIdentity();
- return M;
- }
- protected:
- class Table
- {
- public:
- // Storage-order-independent element access as 2D array.
- inline Real const& operator()(int r, int c) const
- {
- #if defined(GTE_USE_ROW_MAJOR)
- return mStorage[r][c];
- #else
- return mStorage[c][r];
- #endif
- }
- inline Real& operator()(int r, int c)
- {
- #if defined(GTE_USE_ROW_MAJOR)
- return mStorage[r][c];
- #else
- return mStorage[c][r];
- #endif
- }
- // Element access as 1D array. Use this internally only when
- // the 2D storage order is not relevant.
- inline Real const& operator[](int i) const
- {
- Real const* elements = &mStorage[0][0];
- return elements[i];
- }
- inline Real& operator[](int i)
- {
- Real* elements = &mStorage[0][0];
- return elements[i];
- }
- #if defined(GTE_USE_ROW_MAJOR)
- std::array<std::array<Real, NumCols>, NumRows> mStorage;
- #else
- std::array<std::array<Real, NumRows>, NumCols> mStorage;
- #endif
- };
- Table mTable;
- };
- // Unary operations.
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator+(Matrix<NumRows, NumCols, Real> const& M)
- {
- return M;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator-(Matrix<NumRows, NumCols, Real> const& M)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- result[i] = -M[i];
- }
- return result;
- }
- // Linear-algebraic operations.
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator+(
- Matrix<NumRows, NumCols, Real> const& M0,
- Matrix<NumRows, NumCols, Real> const& M1)
- {
- Matrix<NumRows, NumCols, Real> result = M0;
- return result += M1;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator-(
- Matrix<NumRows, NumCols, Real> const& M0,
- Matrix<NumRows, NumCols, Real> const& M1)
- {
- Matrix<NumRows, NumCols, Real> result = M0;
- return result -= M1;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator*(
- Matrix<NumRows, NumCols, Real> const& M, Real scalar)
- {
- Matrix<NumRows, NumCols, Real> result = M;
- return result *= scalar;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator*(
- Real scalar, Matrix<NumRows, NumCols, Real> const& M)
- {
- Matrix<NumRows, NumCols, Real> result = M;
- return result *= scalar;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> operator/(
- Matrix<NumRows, NumCols, Real> const& M, Real scalar)
- {
- Matrix<NumRows, NumCols, Real> result = M;
- return result /= scalar;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real>& operator+=(
- Matrix<NumRows, NumCols, Real>& M0,
- Matrix<NumRows, NumCols, Real> const& M1)
- {
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- M0[i] += M1[i];
- }
- return M0;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real>& operator-=(
- Matrix<NumRows, NumCols, Real>& M0,
- Matrix<NumRows, NumCols, Real> const& M1)
- {
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- M0[i] -= M1[i];
- }
- return M0;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real>& operator*=(
- Matrix<NumRows, NumCols, Real>& M, Real scalar)
- {
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- M[i] *= scalar;
- }
- return M;
- }
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real>& operator/=(
- Matrix<NumRows, NumCols, Real>& M, Real scalar)
- {
- if (scalar != (Real)0)
- {
- Real invScalar = ((Real)1) / scalar;
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- M[i] *= invScalar;
- }
- }
- else
- {
- for (int i = 0; i < NumRows * NumCols; ++i)
- {
- M[i] = (Real)0;
- }
- }
- return M;
- }
- // Geometric operations.
- template <int NumRows, int NumCols, typename Real>
- Real L1Norm(Matrix<NumRows, NumCols, Real> const& M)
- {
- Real sum = std::fabs(M[0]);
- for (int i = 1; i < NumRows * NumCols; ++i)
- {
- sum += std::fabs(M[i]);
- }
- return sum;
- }
- template <int NumRows, int NumCols, typename Real>
- Real L2Norm(Matrix<NumRows, NumCols, Real> const& M)
- {
- Real sum = M[0] * M[0];
- for (int i = 1; i < NumRows * NumCols; ++i)
- {
- sum += M[i] * M[i];
- }
- return std::sqrt(sum);
- }
- template <int NumRows, int NumCols, typename Real>
- Real LInfinityNorm(Matrix<NumRows, NumCols, Real> const& M)
- {
- Real maxAbsElement = M[0];
- for (int i = 1; i < NumRows * NumCols; ++i)
- {
- Real absElement = std::fabs(M[i]);
- if (absElement > maxAbsElement)
- {
- maxAbsElement = absElement;
- }
- }
- return maxAbsElement;
- }
- template <int N, typename Real>
- Matrix<N, N, Real> Inverse(Matrix<N, N, Real> const& M, bool* reportInvertibility = nullptr)
- {
- Matrix<N, N, Real> invM;
- Real determinant;
- bool invertible = GaussianElimination<Real>()(N, &M[0], &invM[0],
- determinant, nullptr, nullptr, nullptr, 0, nullptr);
- if (reportInvertibility)
- {
- *reportInvertibility = invertible;
- }
- return invM;
- }
- template <int N, typename Real>
- Real Determinant(Matrix<N, N, Real> const& M)
- {
- Real determinant;
- GaussianElimination<Real>()(N, &M[0], nullptr, determinant, nullptr,
- nullptr, nullptr, 0, nullptr);
- return determinant;
- }
- // M^T
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumCols, NumRows, Real> Transpose(Matrix<NumRows, NumCols, Real> const& M)
- {
- Matrix<NumCols, NumRows, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(c, r) = M(r, c);
- }
- }
- return result;
- }
- // M*V
- template <int NumRows, int NumCols, typename Real>
- Vector<NumRows, Real> operator*(Matrix<NumRows, NumCols, Real> const& M,
- Vector<NumCols, Real> const& V)
- {
- Vector<NumRows, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- result[r] = (Real)0;
- for (int c = 0; c < NumCols; ++c)
- {
- result[r] += M(r, c) * V[c];
- }
- }
- return result;
- }
- // V^T*M
- template <int NumRows, int NumCols, typename Real>
- Vector<NumCols, Real> operator*(Vector<NumRows, Real> const& V,
- Matrix<NumRows, NumCols, Real> const& M)
- {
- Vector<NumCols, Real> result;
- for (int c = 0; c < NumCols; ++c)
- {
- result[c] = (Real)0;
- for (int r = 0; r < NumRows; ++r)
- {
- result[c] += V[r] * M(r, c);
- }
- }
- return result;
- }
- // A*B
- template <int NumRows, int NumCols, int NumCommon, typename Real>
- Matrix<NumRows, NumCols, Real> operator*(
- Matrix<NumRows, NumCommon, Real> const& A,
- Matrix<NumCommon, NumCols, Real> const& B)
- {
- return MultiplyAB(A, B);
- }
- template <int NumRows, int NumCols, int NumCommon, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyAB(
- Matrix<NumRows, NumCommon, Real> const& A,
- Matrix<NumCommon, NumCols, Real> const& B)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = (Real)0;
- for (int i = 0; i < NumCommon; ++i)
- {
- result(r, c) += A(r, i) * B(i, c);
- }
- }
- }
- return result;
- }
- // A*B^T
- template <int NumRows, int NumCols, int NumCommon, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyABT(
- Matrix<NumRows, NumCommon, Real> const& A,
- Matrix<NumCols, NumCommon, Real> const& B)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = (Real)0;
- for (int i = 0; i < NumCommon; ++i)
- {
- result(r, c) += A(r, i) * B(c, i);
- }
- }
- }
- return result;
- }
- // A^T*B
- template <int NumRows, int NumCols, int NumCommon, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyATB(
- Matrix<NumCommon, NumRows, Real> const& A,
- Matrix<NumCommon, NumCols, Real> const& B)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = (Real)0;
- for (int i = 0; i < NumCommon; ++i)
- {
- result(r, c) += A(i, r) * B(i, c);
- }
- }
- }
- return result;
- }
- // A^T*B^T
- template <int NumRows, int NumCols, int NumCommon, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyATBT(
- Matrix<NumCommon, NumRows, Real> const& A,
- Matrix<NumCols, NumCommon, Real> const& B)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = (Real)0;
- for (int i = 0; i < NumCommon; ++i)
- {
- result(r, c) += A(i, r) * B(c, i);
- }
- }
- }
- return result;
- }
- // M*D, D is diagonal NumCols-by-NumCols
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyMD(
- Matrix<NumRows, NumCols, Real> const& M,
- Vector<NumCols, Real> const& D)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = M(r, c) * D[c];
- }
- }
- return result;
- }
- // D*M, D is diagonal NumRows-by-NumRows
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> MultiplyDM(
- Vector<NumRows, Real> const& D,
- Matrix<NumRows, NumCols, Real> const& M)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = D[r] * M(r, c);
- }
- }
- return result;
- }
- // U*V^T, U is NumRows-by-1, V is Num-Cols-by-1, result is NumRows-by-NumCols.
- template <int NumRows, int NumCols, typename Real>
- Matrix<NumRows, NumCols, Real> OuterProduct(
- Vector<NumRows, Real> const& U, Vector<NumCols, Real> const& V)
- {
- Matrix<NumRows, NumCols, Real> result;
- for (int r = 0; r < NumRows; ++r)
- {
- for (int c = 0; c < NumCols; ++c)
- {
- result(r, c) = U[r] * V[c];
- }
- }
- return result;
- }
- // Initialization to a diagonal matrix whose diagonal entries are the
- // components of D.
- template <int N, typename Real>
- void MakeDiagonal(Vector<N, Real> const& D, Matrix<N, N, Real>& M)
- {
- for (int i = 0; i < N * N; ++i)
- {
- M[i] = (Real)0;
- }
- for (int i = 0; i < N; ++i)
- {
- M(i, i) = D[i];
- }
- }
- // Create an (N+1)-by-(N+1) matrix H by setting the upper N-by-N block to
- // the input N-by-N matrix and all other entries to 0 except for the last
- // row and last column entry which is set to 1.
- template <int N, typename Real>
- Matrix<N + 1, N + 1, Real> HLift(Matrix<N, N, Real> const& M)
- {
- Matrix<N + 1, N + 1, Real> result;
- result.MakeIdentity();
- for (int r = 0; r < N; ++r)
- {
- for (int c = 0; c < N; ++c)
- {
- result(r, c) = M(r, c);
- }
- }
- return result;
- }
- // Extract the upper (N-1)-by-(N-1) block of the input N-by-N matrix.
- template <int N, typename Real>
- Matrix<N - 1, N - 1, Real> HProject(Matrix<N, N, Real> const& M)
- {
- static_assert(N >= 2, "Invalid matrix dimension.");
- Matrix<N - 1, N - 1, Real> result;
- for (int r = 0; r < N - 1; ++r)
- {
- for (int c = 0; c < N - 1; ++c)
- {
- result(r, c) = M(r, c);
- }
- }
- return result;
- }
- }
|