matrix_tools.h

Back to Matrix class

pastel/math/matrix/

// Description: Matrix expressions

#ifndef PASTELMATH_MATRIX_TOOLS_H
#define PASTELMATH_MATRIX_TOOLS_H

#include "pastel/math/matrix/matrix.h"

#include "pastel/sys/mytypes.h"
#include "pastel/sys/tuple/tuple_tools.h"

#include <iostream>

namespace Pastel
{

    //! Returns the only element of a 1x1 matrix.
    template <typename Real>
    Real& scalar(Matrix<Real, 1, 1>& matrix)
    {
        return matrix(0, 0);
    }

    //! Returns the only element of a 1x1 matrix.
    template <typename Real>
    const Real& scalar(const Matrix<Real, 1, 1>& matrix)
    {
        return matrix(0, 0);
    }

    // Returns the diagonal of a matrix.
    template <typename T>
    Vector<typename MatrixExpr<T>::Scalar, MatrixExpr<T>::RowsAtCompileTime> diagonal(
        const MatrixExpr<T>& matrix)
    {
        ENSURE_OP(matrix.cols(), ==, matrix.rows());

        integer n = matrix.cols();

        Vector<typename MatrixExpr<T>::Scalar, MatrixExpr<T>::RowsAtCompileTime> result(ofDimension(n));

        for (integer i = 0;i < n;++i)
        {
            result[i] = matrix(i, i);
        }

        return result;
    }

    //! Returns a diagonal matrix with the given value.
    /*!
   Preconditions:
   matrix.rows() == matrix.cols()
   */
    template <typename Real, int M, int N>
    void setDiagonal(
        Matrix<Real, M, N>& matrix,
        const NoDeduction<Real>& value)
    {
        integer width = matrix.cols();
        integer height = matrix.rows();

        ENSURE_OP(width, ==, height);

        matrix.set(0);

        for (integer i = 0;i < width;++i)
        {
            matrix(i, i) = value;
        }
    }

    //! Returns a diagonal matrix with elements from a vector.
    /*!
   Preconditions:
   matrix.cols() == matrix.rows() == values.size()
   */
    template <typename Real, int M, int N, int NV>
    void setDiagonal(
        Matrix<Real, M, N>& matrix,
        const Vector<Real, NV>& values)
    {
        integer size = values.size();

        ENSURE2(matrix.cols() == size, matrix.cols(), size);
        ENSURE2(matrix.rows() == size, matrix.rows(), size);

        matrix.set(0);

        for (integer i = 0;i < size;++i)
        {
            matrix(i, i) = values[i];
        }
    }

    //! Transponates a matrix in-place.
    template <typename Real, int M, int N>
    void transponate(Matrix<Real, M, N>& matrix)
    {
        matrix.transposeInPlace();
    }

    //! Returns a square diagonal matrix.
    template <typename Real, int N>
    Eigen::DiagonalMatrix<Real, N> diagonalMatrix(
        const Vector<Real, N>& diagonal)
    {
        Eigen::DiagonalMatrix<Real, N> m;
        int n = diagonal.size();
        m.resize(n);
        for (int i = 0;i < n; ++i) {
            m.diagonal()[i] = diagonal[i];
        }
        return m;
    }

    template <typename T>
    Vector<typename MatrixExpr<T>::Scalar, MatrixExpr<T>::SizeAtCompileTime> asVector(const MatrixExpr<T>& right) {
        int m = right.size();
        Vector<typename MatrixExpr<T>::Scalar, MatrixExpr<T>::SizeAtCompileTime> v(ofDimension(m));
        for (int i = 0; i < m; ++i) {
            v[i] = right(i);
        }
        return v;
    }

    //! Returns a square diagonal matrix.
    template <typename Real, int N>
    Eigen::DiagonalMatrix<Real, N> diagonalMatrix(
        const ColMatrix<Real, N>& diagonal)
    {
        return Pastel::diagonalMatrix(asVector(diagonal));
    }

    //! Returns a square diagonal matrix.
    template <typename Real, int N>
    Eigen::DiagonalMatrix<Real, N> diagonalMatrix(
        const RowMatrix<Real, N>& diagonal)
    {
        return Pastel::diagonalMatrix(asVector(diagonal));
    }

    //! Returns the identity matrix.
    /*!
   Preconditions:
   m >= 0
   n >= 0
   */
    template <typename Real, int M = Dynamic, int N = Dynamic>
    decltype(auto) identityMatrix(
        integer m, integer n)
    {
        return Matrix<Real, M, N>::Identity(m, n);
    }

    //! Returns a constant matrix.
    /*!
   Preconditions:
   height >= 0
   width >= 0
   */
    template <typename Real, int M = Dynamic, int N = Dynamic>
    decltype(auto) constantMatrix(
        integer m, integer n, NoDeduction<Real> value)
    {
        return Matrix<Real, M, N>::Constant(m, n, value);
    }

    //! Returns the transpose of the given matrix.
    template <typename T>
    decltype(auto) transpose(const MatrixExpr<T>& that)
    {
        return that.transpose();
    }

    template <typename T>
    decltype(auto) sum(const MatrixExpr<T>& that)
    {
        return that.colwise().sum();
    }

    //! Returns the minimum value of each column as a vector.
    template <typename T>
    decltype(auto) min(const MatrixExpr<T>& that)
    {
        return that.colwise().minCoeff();
    }

    //! Returns the maximum value of each column as a vector.
    template <typename T>
    decltype(auto) max(const MatrixExpr<T>& that)
    {
        return that.colwise().maxCoeff();
    }

    //! Returns the absolute value of each element.
    template <typename T>
    decltype(auto) abs(const MatrixExpr<T>& that)
    {
        return that.cwiseAbs();
    }

    //! Repeats a matrix expression to form a bigger matrix expression.
    /*!
   Preconditions:
   xBlocks >= 0
   yBlocks >= 0
   */
    //template <typename Real, typename Expression>
    //MatrixRepeat<Real, Expression> repeat(
    // const MatrixExpression<Real, Expression>& that,
    // integer yBlocks, integer xBlocks)
    //{
    // return MatrixRepeat<Real, Expression>(
    //     (const Expression&)that, yBlocks, xBlocks);
    //}

    template <typename Real, int N>
    decltype(auto) arrayMatrix(
        integer height, integer width,
        Real (&data)[N])
    {
        PENSURE_OP(height, >=, 0);
        PENSURE_OP(width, >=, 0);
        PENSURE_OP(height * width, ==, N);

        return arrayMatrix(height, width, (const Real*)&data[0]);
    }

    template <typename Real, int M = Dynamic, int N = Dynamic>
    decltype(auto) arrayMatrix(
        integer height, integer width,
        const Real* data)
    {
        PENSURE_OP(height, >=, 0);
        PENSURE_OP(width, >=, 0);

        return Eigen::Map<Matrix<Real, M, N>>(data, height, width);
    }

    template <typename Real, int M, int N>
    decltype(auto) arrayMatrix(
        Real (&data)[M][N])
    {
        return Eigen::Map<Matrix<Real, M, N>>(data, M, N);
    }

    template <typename Real>
    Matrix<Real, 1, 1> matrix1x1(NoDeduction<Real> a00)
    {
        Matrix<Real, 1, 1> matrix(1, 1);
        matrix(0, 0) = a00;
        return matrix;
    }

    template <
        typename Real, int N, 
        typename Expression1>
    Matrix<Real, 1, 1> matrix1x1(
        const Vector<Real, N>& firstColumn)
    {
        Matrix<Real, 1, 1> matrix(1, 1);
        matrix.col(0) = asColumnMatrix(firstColumn);
        return matrix;
    }

    template <typename Real>
    Matrix<Real, 2, 2> matrix2x2(
        NoDeduction<Real> a00, NoDeduction<Real> a01,
        NoDeduction<Real> a10, NoDeduction<Real> a11)
    {
        Matrix<Real, 2, 2> matrix(2, 2);
        matrix(0, 0) = a00;
        matrix(0, 1) = a01;
        matrix(1, 0) = a10;
        matrix(1, 1) = a11;
        return matrix;
    }

    template <typename Real, int N>
    Matrix<Real, 2, 2> matrix2x2(
        const Vector<Real, N>& firstColumn,
        const Vector<Real, N>& secondColumn)
    {
        Matrix<Real, 2, 2> matrix(2, 2);
        matrix.col(0) = asColumnMatrix(firstColumn);
        matrix.col(1) = asColumnMatrix(secondColumn);
        return matrix;
    }

    template <typename Real>
    Matrix<Real, 3, 3> matrix3x3(
        NoDeduction<Real> a00, NoDeduction<Real> a01, NoDeduction<Real> a02,
        NoDeduction<Real> a10, NoDeduction<Real> a11, NoDeduction<Real> a12,
        NoDeduction<Real> a20, NoDeduction<Real> a21, NoDeduction<Real> a22)
    {
        Matrix<Real, 3, 3> matrix(3, 3);
        matrix(0, 0) = a00;
        matrix(0, 1) = a01;
        matrix(0, 2) = a02;
        matrix(1, 0) = a10;
        matrix(1, 1) = a11;
        matrix(1, 2) = a12;
        matrix(2, 0) = a20;
        matrix(2, 1) = a21;
        matrix(2, 2) = a22;
        return matrix;
    }

    template <typename Real, int N>
    Matrix<Real, 3, 3> matrix3x3(
        const Vector<Real, N>& firstColumn,
        const Vector<Real, N>& secondColumn,
        const Vector<Real, N>& thirdColumn)
    {
        Matrix<Real, 3, 3> matrix(3, 3);
        matrix.col(0) = asColumnMatrix(firstColumn);
        matrix.col(1) = asColumnMatrix(secondColumn);
        matrix.col(2) = asColumnMatrix(thirdColumn);
        return matrix;
    }

    template <typename Real>
    Matrix<Real, 4, 4> matrix4x4(
        NoDeduction<Real> a00, NoDeduction<Real> a01, NoDeduction<Real> a02, NoDeduction<Real> a03,
        NoDeduction<Real> a10, NoDeduction<Real> a11, NoDeduction<Real> a12, NoDeduction<Real> a13,
        NoDeduction<Real> a20, NoDeduction<Real> a21, NoDeduction<Real> a22, NoDeduction<Real> a23,
        NoDeduction<Real> a30, NoDeduction<Real> a31, NoDeduction<Real> a32, NoDeduction<Real> a33)
    {
        Matrix<Real, 4, 4> matrix(4, 4);
        matrix(0, 0) = a00;
        matrix(0, 1) = a01;
        matrix(0, 2) = a02;
        matrix(0, 3) = a03;
        matrix(1, 0) = a10;
        matrix(1, 1) = a11;
        matrix(1, 2) = a12;
        matrix(1, 3) = a13;
        matrix(2, 0) = a20;
        matrix(2, 1) = a21;
        matrix(2, 2) = a22;
        matrix(2, 3) = a23;
        matrix(3, 0) = a30;
        matrix(3, 1) = a31;
        matrix(3, 2) = a32;
        matrix(3, 3) = a33;
        return matrix;
    }

    template <typename Real, int N>
    Matrix<Real, 4, 4> matrix4x4(
        const Vector<Real, N>& firstColumn,
        const Vector<Real, N>& secondColumn,
        const Vector<Real, N>& thirdColumn,
        const Vector<Real, N>& fourthColumn)
    {
        Matrix<Real, 4, 4> matrix(4, 4);
        matrix.col(0) = asColumnMatrix(firstColumn);
        matrix.col(1) = asColumnMatrix(secondColumn);
        matrix.col(2) = asColumnMatrix(thirdColumn);
        matrix.col(3) = asColumnMatrix(fourthColumn);
        return matrix;
    }

    //! Computes the outer product v w^T.
    /*!
   Here 'left' is v and 'right' is w.
   */
    template <typename Real, int M, int N>
    decltype(auto) outerProduct(
        const Vector<Real, M>& left,
        const Vector<Real, N>& right)
    {
        return asColumnMatrix(left) * asRowMatrix(right);
    }

    //! Computes the outer product v v^T.
    /*!
   This is a convenience function that calls
   outerProduct(that, that). See the documentation
   for that function.
   */
    template <typename Real, int N>
    decltype(auto) outerProduct(const Vector<Real, N>& that)
    {
        return Pastel::outerProduct(that, that);
    }

    template <typename Real, int M, int N>
    void swap(Matrix<Real, M, N>& left, Matrix<Real, M, N>& right)
    {
        left.swap(right);
    }

    template <typename Real, int NV, typename Derived>
    decltype(auto) operator *(
        const Vector<Real, NV>& left,
        const MatrixExpr<Derived>& right)
    {
        return asVector(asRowMatrix(left) * right);
    }

    template <typename Real, int NV, typename Derived>
    decltype(auto) operator *(
        const MatrixExpr<Derived>& left,
        const Vector<Real, NV>& right)
    {
        return asVector(left * asColumnMatrix(right));
    }

    template <typename Real, int M, int N>
    decltype(auto) range(const Matrix<Real, M, N>& that) {
        return Pastel::range(that.data(), that.data() + that.size());
    }

    template <typename T, int MapOptions>
    decltype(auto) range(const Eigen::Map<T, MapOptions>& that) {
        return Pastel::range(that.data(), that.data() + that.size());
    }

}

#include <iostream>

namespace Pastel
{

    template <typename Real, int M, int N>
    std::ostream& operator<<(
        std::ostream& stream,
        const Matrix<Real, M, N>& m)
    {
        integer width = m.cols();
        integer height = m.rows();

        for (integer y = 0;y < height;++y)
        {
            for (integer x = 0;x < width;++x)
            {
                stream << m(y, x) << ", ";
            }
            stream << std::endl;
        }

        return stream;
    }

}

#endif