summaryrefslogblamecommitdiffstats
path: root/matrix.hpp
blob: 1e84db02236578dbf25a04ead6e9352dfb1b6920 (plain) (tree)














































































































































                                                                                   











                                                                   


































                                                         







                                                     












                                                







                                                     










                                                
#ifndef MATRIX_HPP
#define MATRIX_HPP 1

#include <array>
#include <algorithm>
#include <span>
#include <ostream>

template<typename T, std::size_t M, std::size_t N>
    requires(std::is_arithmetic_v<T>)
class matrix
{
protected:
    std::array<T, N * M> v;
public:
    constexpr matrix(const std::array<std::array<T, N>, M> &vs)
    {
        for(std::size_t m = 0; m < M; m++)
        for(std::size_t n = 0; n < N; n++) {
            v[(m * N) + n] = vs[m][n];
        }
    }
    constexpr matrix(const std::array<T, M * N> &vs) :
        v(vs)
    {}

    constexpr matrix(T a) {
        v.fill(a);
    }

    constexpr matrix &operator+=(const matrix &rhs)
    {
        for(std::size_t i = 0; i < M * N; i++)
            v[i] += rhs.v[i];
        return v;
    }

    constexpr friend matrix operator+(
            matrix lhs, 
            const matrix &rhs)
    {
        lhs += rhs;
        return lhs;
    }

    constexpr friend matrix operator-(matrix lhs)
    {
        for(std::size_t i = 0; i < M * N; i++)
            lhs.v[i] = -lhs.v[i];
        return lhs;
    }

    constexpr matrix &operator-=(const matrix &rhs)
    {
        for(std::size_t i = 0; i < M * N; i++)
            v[i] -= rhs.v[i];
        return *this;
    }

    constexpr friend matrix operator-(
            matrix lhs,
            const matrix &rhs)
    {
        lhs -= rhs;
        return lhs;
    }

    template<std::size_t P>
    constexpr friend matrix<T, M, P> operator*(
            const matrix<T, M, N> &rhs,
            const matrix<T, N, P> &lhs)
    {
        matrix<T, M, P> ret(0);
        for(std::size_t p = 0; p < P; p++) {
            for(std::size_t m = 0; m < M; m++) {
                for(std::size_t n = 0; n < N; n++) {
                    ret.at(m, p) += rhs.at(m, n) * lhs.at(n, p);
                }
            }
        }
        return ret;
    }

    constexpr matrix &operator*=(const T &rhs)
    {
        std::ranges::transform(
                v.begin(), 
                v.end(), 
                v.begin(), 
                [rhs](T t) -> T { return t * rhs; }
            );
        return *this;
    }

    constexpr friend matrix operator*(
            matrix lhs,
            const T &rhs)
    {
        lhs *= rhs;
        return lhs;
    }

    constexpr std::array<std::reference_wrapper<T>, N> row(std::size_t m)
    {
        std::array<std::reference_wrapper<T>, N> ret;
        for(std::size_t n = 0; n < N; n++) ret[n] = v[(m * N) + n];
        return ret;
    }

    constexpr std::array<std::reference_wrapper<T>, M> col(std::size_t n)
    {
        std::array<std::reference_wrapper<T>, M> ret;
        for(std::size_t m = 0; m < M; m++) ret[m] = v[(m * M) + n];
        return ret;
    }

    constexpr T &at(std::size_t m, std::size_t n)
    {
        return v.at((m * N) + n);
    }
    constexpr const T &at(std::size_t m, std::size_t n) const
    {
        return v.at((m * N) + n);
    }

    constexpr std::array<T, M * N> &data() noexcept { return v; }
    constexpr std::array<T, M * N> &data() const noexcept { return v; }

    constexpr friend std::ostream &operator<<(std::ostream &lhs, const matrix &rhs)
    {
        for(std::size_t m = 0; m < M; m++) {
            lhs << '\n';
            for(std::size_t n = 0; n < N; n++) {
                lhs << rhs.at(m, n) << ", ";
            }
        }
        return lhs;
    }
};

template<typename T, std::size_t S>
class sqmatrix final : public matrix<T, S, S>
{
public:
    constexpr sqmatrix(const std::array<std::array<T, S>, S> &vs) :
        matrix<T, S, S>(vs)
    {}

    constexpr sqmatrix(const std::array<T, S * S> &vs) :
        matrix<T, S, S>(vs)
    {}

    constexpr sqmatrix(T a) :
        matrix<T, S, S>(a) {}

    static constexpr sqmatrix identity()
    {
        sqmatrix ret(0);
        for(std::size_t i = 0; i < S; i++) {
            ret.at(i, i) = 1;
        }
        return ret;
    }

    constexpr sqmatrix operator*=(const sqmatrix &rhs)
    {
        sqmatrix copy(*this);
        for(std::size_t i = 0; i < S; i++) {
            for(std::size_t j = 0; j < S; j++) {
                T cell = 0;
                for(std::size_t k = 0; k < S; k++)
                    cell += copy.at(k, j) * rhs.at(i, k);
                this->at(i, j) = cell;
            }
        }
        return *this;
    }

    constexpr friend sqmatrix operator*(
            sqmatrix lhs,
            const sqmatrix &rhs)
    {
        lhs *= rhs;
        return lhs;
    }
};

template<typename T, std::size_t L>
class rowmatrix final : public matrix<T, L, 1>
{
public:
    constexpr rowmatrix(const std::array<T, L> &vs) :
        matrix<T, L, 1>(vs)
    {}

    constexpr rowmatrix(T a) :
        matrix<T, L, 1>(a) {}

    constexpr T &operator[](std::size_t i) const
    {
        return this->v[i];
    }
    constexpr T &operator[](std::size_t i)
    {
        return this->v[i];
    }
};

template<typename T, std::size_t L>
class colmatrix final : public matrix<T, 1, L>
{
public:
    constexpr colmatrix(const std::array<T, L> &vs) :
        matrix<T, 1, L>(vs)
    {}

    constexpr colmatrix(T a) :
        matrix<T, 1, L>(a) {}

    constexpr T &operator[](std::size_t i) const
    {
        return this->v[i];
    }
    constexpr T &operator[](std::size_t i)
    {
        return this->v[i];
    }
};

#endif