matrix_view.h

Back to Matrix class

pastel/math/matrix/

// Description: SubMatrix class

#ifndef PASTELMATH_MATRIXVIEW_H
#define PASTELMATH_MATRIXVIEW_H

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

#include "pastel/sys/array.h"
#include "pastel/sys/view/arrayview.h"
#include "pastel/sys/iterator/sparse_iterator.h"
#include "pastel/sys/memory_overlaps.h"

namespace Pastel
{

    /*
   template <typename Real>
   class MatrixRange
   {
   public:
       MatrixRange(
           Real* data,
           integer height
           integer width,
           integer dy,
           integer dx)
           : data_(data)
           , height_(height)
           , width_(width)
           , dy_(dy)
           , dx_(dx)
       {
       }

       Real* data() const
       {
           return data_;
       }

       integer width() const
       {
           return width_;
       }

       integer height() const
       {
           return height_;
       }

       integer dx() const
       {
           return dx_;
       }

       integer dy() const
       {
           return dy_;
       }

   private:
       Real* data_;
       integer height_;
       integer width_;
       integer dy_;
       integer dx_;
   };
   */

    template <typename Real>
    class ConstSubMatrix
        : public MatrixExpression<Real, ConstSubMatrix<Real> >
    {
    public:
        using StorageType = const ConstSubMatrix&;

        using ConstRow = ConstArray_VectorExpression<Real, Dynamic>;
        using ConstIterator = typename ConstSubArray<Real>::ConstIterator;
        using ConstRowIterator = typename ConstSubArray<Real>::ConstRowIterator;
        using ConstColumnIterator = typename ConstSubArray<Real>::ConstRowIterator;

        // Using default copy constructor.
        // Using default assignment.
        // Using default destructor.

        ConstSubMatrix()
            : data_()
        {
        }

        ConstSubMatrix(
            const Real* data,
            const Vector2i& stride,
            const Vector2i& extent)
            : data_(data, stride, extent)
        {
        }

        explicit ConstSubMatrix(
            const ConstSubArray<Real>& data)
            : data_(data)
        {
        }

        bool involves(const void* memoryBegin, const void* memoryEnd) const
        {
            return data_.involves(memoryBegin, memoryEnd);
        }

        bool evaluateBeforeAssignment(const void* memoryBegin, const void* memoryEnd) const
        {
            return data_.involves(memoryBegin, memoryEnd);
        }

        const Real& operator()(integer y, integer x) const
        {
            return data_(Vector2(x, y));
        }

        ConstSubMatrix operator()(
            const Vector2i& min,
            const Vector2i& max) const
        {
            ConstSubMatrix result(data_(min, max));
            return result;
        }

        ConstSubMatrix operator()(
            const Vector2i& min,
            const Vector2i& max,
            const Vector2i& delta) const
        {
            ConstSubMatrix result(data_(
                Vector2i(min.y(), min.x()), 
                Vector2i(max.y(), max.x()), 
                Vector2i(delta.y(), delta.x())));
            return result;
        }

        ConstSubMatrix operator[](integer y) const
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            ConstSubMatrix result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        ConstSubMatrix row(integer y) const
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            ConstSubMatrix result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        ConstSubMatrix column(integer x) const
        {

            PENSURE2(x >= 0 && x < width(), x, width());

            ConstSubMatrix result(
                data_(Vector2i(x, 0), Vector2i(x + 1, 0)));
            return result;
        }

        void swap(ConstSubMatrix& that)
        {
            data_.swap(that.data_);
        }

        integer width() const
        {
            return data_.extent()[0];
        }

        integer height() const
        {
            return data_.extent()[1];
        }

        integer size() const
        {
            return data_.size();
        }

        ConstRowIterator rowBegin(integer y) const
        {
            return data_.rowBegin(0, Vector2i(0, y));
        }

        ConstRowIterator rowEnd(integer y) const
        {
            return data_.rowEnd(0, Vector2i(0, y));
        }

        ConstColumnIterator columnBegin(integer x) const
        {
            return data_.columnBegin(1, Vector2i(x, 0));
        }

        ConstColumnIterator columnEnd(integer x) const
        {
            return data_.columnEnd(1, Vector2i(x, 0));
        }

    private:
        ConstSubMatrix& operator=(
            const ConstSubMatrix& that) = delete;

        ConstSubArray<Real> data_;
    };

    template <typename Real>
    class SubMatrix
        : public MatrixExpression<Real, SubMatrix<Real> >
    {
    public:
        using StorageType = const SubMatrix&;

        using Row = Array_VectorExpression<Real, Dynamic>;
        using ConstRow = ConstArray_VectorExpression<Real, Dynamic>;
        using Iterator = typename SubArray<Real>::Iterator;
        using ConstIterator = typename SubArray<Real>::ConstIterator;
        using RowIterator = typename SubArray<Real>::RowIterator;
        using ConstRowIterator = typename SubArray<Real>::ConstRowIterator;
        using ColumnIterator = typename SubArray<Real>::RowIterator;
        using ConstColumnIterator = typename SubArray<Real>::ConstRowIterator;

        // Using default copy constructor.
        // Using default assignment.
        // Using default destructor.

        SubMatrix()
            : data_()
        {
        }

        SubMatrix(
            Real* data,
            const Vector2i& stride,
            const Vector2i& extent)
            : data_(data, stride, extent)
        {
        }

        explicit SubMatrix(
            const SubArray<Real>& data)
            : data_(data)
        {
        }

        SubMatrix& operator=(
            const SubMatrix& that)
        {
            ENSURE_OP(width(), ==, that.width());
            ENSURE_OP(height(), ==, that.height());

            if (that.evaluateBeforeAssignment(data_.dataBegin(), data_.dataEnd()))
            {
                // The right expression contains this matrix
                // as a subexpression. We thus need to evaluate
                // the expression first.

                *this = Matrix<Real>(that);
            }
            else
            {
                integer m = height();
                for (integer y = 0;y < m;++y)
                {
                    std::copy(
                        that.rowBegin(y), that.rowEnd(y),
                        rowBegin(y));
                }
            }

            return *this;
        }

        bool involves(const void* memoryBegin, const void* memoryEnd) const
        {
            return data_.involves(memoryBegin, memoryEnd);
        }

        bool evaluateBeforeAssignment(const void* memoryBegin, const void* memoryEnd) const
        {
            return data_.involves(memoryBegin, memoryEnd);
        }

        Real& operator()(integer y, integer x)
        {
            return data_(Vector2i(x, y));
        }

        const Real& operator()(integer y, integer x) const
        {
            return data_(Vector2(x, y));
        }

        SubMatrix operator()(
            const Vector2i& min,
            const Vector2i& max)
        {
            SubMatrix result(data_(
                Vector2i(min.y(), min.x()), 
                Vector2i(max.y(), max.y())));
            return result;
        }

        ConstSubMatrix<Real> operator()(
            const Vector2i& min,
            const Vector2i& max) const
        {
            ConstSubMatrix<Real> result(data_(
                Vector2i(min.y(), min.x()), 
                Vector2i(max.y(), max.y())));
            return result;
        }

        SubMatrix operator()(
            const Vector2i& min,
            const Vector2i& max,
            const Vector2i& delta)
        {
            SubMatrix result(data_(
                Vector2i(min.y(), min.x()), 
                Vector2i(max.y(), max.x()), 
                Vector2i(delta.y(), delta.x())));
            return result;
        }

        ConstSubMatrix<Real> operator()(
            const Vector2i& min,
            const Vector2i& max,
            const Vector2i& delta) const
        {
            ConstSubMatrix<Real> result(data_(
                Vector2i(min.y(), min.x()), 
                Vector2i(max.y(), max.x()), 
                Vector2i(delta.y(), delta.x())));
            return result;
        }

        SubMatrix operator[](integer y)
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            SubMatrix result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        ConstSubMatrix<Real> operator[](integer y) const
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            ConstSubMatrix<Real> result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        SubMatrix row(integer y)
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            SubMatrix result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        ConstSubMatrix<Real> row(integer y) const
        {

            PENSURE2(y >= 0 && y < height(), y, height());

            ConstSubMatrix<Real> result(
                data_(Vector2i(0, y), Vector2i(0, y + 1)));
            return result;
        }

        SubMatrix column(integer x)
        {

            PENSURE2(x >= 0 && x < width(), x, width());

            SubMatrix result(
                data_(Vector2i(x, 0), Vector2i(x + 1, 0)));
            return result;
        }

        ConstSubMatrix<Real> column(integer x) const
        {

            PENSURE2(x >= 0 && x < width(), x, width());

            ConstSubMatrix<Real> result(
                data_(Vector2i(x, 0), Vector2i(x + 1, 0)));
            return result;
        }

        template <typename RightExpression>

        SubMatrix& operator=(
            const MatrixExpression<Real, RightExpression>& right)
        {
            ENSURE(width() == right.width() &&
                height() == right.height());

            if (right.evaluateBeforeAssignment(data_.dataBegin(), data_.dataEnd()))
            {
                // The right expression contains this matrix
                // as a subexpression. We thus need to evaluate
                // the expression first.

                *this = Matrix<Real>(right);
            }
            else
            {
                integer m = height();
                integer n = width();

                for (integer i = 0;i < m;++i)
                {
                    RowIterator iter = rowBegin(i);
                    for (integer j = 0;j < n;++j)
                    {

                        *iter = right(i, j);
                        ++iter;
                    }
                }
            }

            return *this;
        }

        template <typename RightExpression>
        SubMatrix& operator*=(
            const MatrixExpression<Real, RightExpression>& right)
        {
            PENSURE2(width() == right.height(), width(), right.height());

            *this = *this * right;

            return *this;
        }

        template <typename RightExpression>
        SubMatrix& operator+=(
            const MatrixExpression<Real, RightExpression>& right)
        {
            PENSURE2(width() == right.width(), width(), right.width());
            PENSURE2(height() == right.height(), height(), right.height());

            if (right.evaluateBeforeAssignment(data_.dataBegin(), data_.dataEnd()))
            {
                *this += Matrix<Real>(right);
            }
            else
            {
                integer m = height();
                integer n = width();

                for (integer i = 0;i < m;++i)
                {
                    RowIterator iter = rowBegin(i);
                    for (integer j = 0;j < n;++j)
                    {

                        *iter += right(i, j);
                        ++iter;
                    }
                }
            }

            return *this;
        }

        template <typename RightExpression>
        SubMatrix& operator-=(
            const MatrixExpression<Real, RightExpression>& right)
        {
            PENSURE2(width() == right.width(), width(), right.width());
            PENSURE2(height() == right.height(), height(), right.height());

            if (right.evaluateBeforeAssignment(data_.dataBegin(), data_.dataEnd()))
            {
                *this -= Matrix<Real>(right);
            }
            else
            {
                integer m = height();
                integer n = width();

                for (integer i = 0;i < m;++i)
                {
                    RowIterator iter = rowBegin(i);
                    for (integer j = 0;j < n;++j)
                    {

                        *iter -= right(i, j);
                        ++iter;
                    }
                }
            }

            return *this;
        }

        // Matrices vs scalars

        // SubMatrix += scalar and SubMatrix -= scalar are not
        // supported because of the possibly ambiguity:
        // it is not clear whether it should mean
        // "add / subtract element-wise" or
        // "add / subtract by multiples of identity matrix".
        // For *= and /= these interpretations are equivalent.

        // The parameter is deliberately taken by value because
        // a reference could be from this matrix.
        SubMatrix& operator*=(
            Real right)
        {
            integer m = height();

            for (integer y = 0;y < m;++y)
            {
                RowIterator iter = rowBegin(y);
                RowIterator iterEnd = rowEnd(y);

                while(iter != iterEnd)
                {

                    (*iter) *= right;
                    ++iter;
                }
            }

            return *this;
        }

        // No need to take the parameter by value,
        // because we construct the inverse.
        SubMatrix& operator/=(
            const Real& right)
        {
            return (*this) *= inverse(right);
        }

        void swap(SubMatrix& that)
        {
            data_.swap(that.data_);
        }

        integer width() const
        {
            return data_.extent()[0];
        }

        integer height() const
        {
            return data_.extent()[1];
        }

        integer size() const
        {
            return data_.size();
        }

        RowIterator rowBegin(integer y)
        {
            return data_.rowBegin(0, Vector2i(0, y));
        }

        ConstRowIterator rowBegin(integer y) const
        {
            return data_.rowBegin(0, Vector2i(0, y));
        }

        RowIterator rowEnd(integer y)
        {
            return data_.rowEnd(0, Vector2i(0, y));
        }

        ConstRowIterator rowEnd(integer y) const
        {
            return data_.rowEnd(0, Vector2i(0, y));
        }

        ColumnIterator columnBegin(integer x)
        {
            return data_.columnBegin(1, Vector2i(x, 0));
        }

        ConstColumnIterator columnBegin(integer x) const
        {
            return data_.columnBegin(1, Vector2i(x, 0));
        }

        ColumnIterator columnEnd(integer x)
        {
            return data_.columnEnd(1, Vector2i(x, 0));
        }

        ConstColumnIterator columnEnd(integer x) const
        {
            return data_.columnEnd(1, Vector2i(x, 0));
        }

    private:
        SubArray<Real> data_;
    };

}

#endif