32constexpr size_t MAX_SIZE = ~0ULL;
 
   37          typename = 
typename std::enable_if<
 
   38              std::is_integral<T>::value || std::is_floating_point<T>::value,
 
   41    std::vector<std::vector<T>> _mat;
 
   50    template <
typename Integer,
 
   51              typename = 
typename std::enable_if<
 
   52                  std::is_integral<Integer>::value, Integer>::type>
 
   54        for (
size_t i = 0; i < 
size; ++i) {
 
   55            _mat.emplace_back(std::vector<T>(
size, 0));
 
 
   66    template <
typename Integer,
 
   67              typename = 
typename std::enable_if<
 
   68                  std::is_integral<Integer>::value, Integer>::type>
 
   69    Matrix(
const Integer rows, 
const Integer cols) {
 
   70        for (
size_t i = 0; i < rows; ++i) {
 
   71            _mat.emplace_back(std::vector<T>(cols, 0));
 
 
   79    inline std::pair<size_t, size_t> 
size()
 const {
 
   80        return {_mat.size(), _mat[0].size()};
 
 
   90    template <
typename Integer,
 
   91              typename = 
typename std::enable_if<
 
   92                  std::is_integral<Integer>::value, Integer>::type>
 
  106    Matrix slice(
const size_t row_start, 
const size_t row_end = MAX_SIZE,
 
  107                 const size_t col_start = MAX_SIZE,
 
  108                 const size_t col_end = MAX_SIZE)
 const {
 
  109        const size_t h_size =
 
  110            (row_end != MAX_SIZE ? row_end : _mat.size()) - row_start;
 
  111        const size_t v_size = (col_end != MAX_SIZE ? col_end : _mat[0].size()) -
 
  112                              (col_start != MAX_SIZE ? col_start : 0);
 
  115        const size_t v_start = (col_start != MAX_SIZE ? col_start : 0);
 
  116        for (
size_t i = 0; i < h_size; ++i) {
 
  117            for (
size_t j = 0; j < v_size; ++j) {
 
  118                result._mat[i][j] = _mat[i + row_start][j + v_start];
 
 
  130    template <
typename Number, 
typename = 
typename std::enable_if<
 
  131                                   std::is_integral<Number>::value ||
 
  132                                       std::is_floating_point<Number>::value,
 
  135        assert(_mat.size() == other._mat.size());
 
  136        for (
size_t i = 0; i < other._mat.size(); ++i) {
 
  137            for (
size_t j = 0; j < other._mat[i].size(); ++j) {
 
  138                _mat[i].push_back(other._mat[i][j]);
 
 
  149    template <
typename Number, 
typename = 
typename std::enable_if<
 
  150                                   std::is_integral<Number>::value ||
 
  151                                       std::is_floating_point<Number>::value,
 
  154        assert(_mat[0].
size() == other._mat[0].size());
 
  155        for (
size_t i = 0; i < other._mat.size(); ++i) {
 
  156            _mat.emplace_back(std::vector<T>(other._mat[i].size()));
 
  157            for (
size_t j = 0; j < other._mat[i].size(); ++j) {
 
  158                _mat.back()[j] = other._mat[i][j];
 
 
  169    template <
typename Number, 
typename = 
typename std::enable_if<
 
  170                                   std::is_integral<Number>::value ||
 
  171                                       std::is_floating_point<Number>::value,
 
  174        assert(this->
size() == other.
size());
 
  176        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  177            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  178                C._mat[i][j] = _mat[i][j] + other._mat[i][j];
 
 
  190    template <
typename Number, 
typename = 
typename std::enable_if<
 
  191                                   std::is_integral<Number>::value ||
 
  192                                       std::is_floating_point<Number>::value,
 
  195        assert(this->
size() == other.
size());
 
  196        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  197            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  198                _mat[i][j] += other._mat[i][j];
 
 
  210    template <
typename Number, 
typename = 
typename std::enable_if<
 
  211                                   std::is_integral<Number>::value ||
 
  212                                       std::is_floating_point<Number>::value,
 
  215        assert(this->
size() == other.
size());
 
  217        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  218            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  219                C._mat[i][j] = _mat[i][j] - other._mat[i][j];
 
 
  231    template <
typename Number, 
typename = 
typename std::enable_if<
 
  232                                   std::is_integral<Number>::value ||
 
  233                                       std::is_floating_point<Number>::value,
 
  236        assert(this->
size() == other.
size());
 
  237        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  238            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  239                _mat[i][j] -= other._mat[i][j];
 
 
  251    template <
typename Number, 
typename = 
typename std::enable_if<
 
  252                                   std::is_integral<Number>::value ||
 
  253                                       std::is_floating_point<Number>::value,
 
  256        assert(_mat[0].
size() == other._mat.size());
 
  258        const size_t row = 
size.first, col = 
size.second;
 
  262        return (row == col && (row & 1) == 0)
 
 
  273    template <
typename Number, 
typename = 
typename std::enable_if<
 
  274                                   std::is_integral<Number>::value ||
 
  275                                       std::is_floating_point<Number>::value,
 
  279        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  280            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  281                C._mat[i][j] = _mat[i][j] * other;
 
 
  293    template <
typename Number, 
typename = 
typename std::enable_if<
 
  294                                   std::is_integral<Number>::value ||
 
  295                                       std::is_floating_point<Number>::value,
 
  298        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  299            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
 
  312    template <
typename Number, 
typename = 
typename std::enable_if<
 
  313                                   std::is_integral<Number>::value ||
 
  314                                       std::is_floating_point<Number>::value,
 
  319        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  320            for (
size_t k = 0; k < _mat[0].size(); ++k) {
 
  321                for (
size_t j = 0; j < other._mat[0].size(); ++j) {
 
  322                    C._mat[i][j] += _mat[i][k] * other._mat[k][j];
 
 
  336    template <
typename Number, 
typename = 
typename std::enable_if<
 
  337                                   std::is_integral<Number>::value ||
 
  338                                       std::is_floating_point<Number>::value,
 
  341        const size_t size = _mat.size();
 
  346        if (
size <= 64ULL || (
size & 1ULL)) {
 
  362            Matrix P4 = D.strassens_multiplication(G - E);
 
  375            Matrix C11 = P5 + P4 - P2 + P6;
 
  378            Matrix C22 = P1 + P5 - P3 - P7;
 
 
  394        if (_mat.size() != other._mat.size() ||
 
  395            _mat[0].size() != other._mat[0].size()) {
 
  398        for (
size_t i = 0; i < _mat.size(); ++i) {
 
  399            for (
size_t j = 0; j < _mat[i].size(); ++j) {
 
  400                if (_mat[i][j] != other._mat[i][j]) {
 
 
  409        for (
auto &row : mat._mat) {
 
  410            for (
auto &elem : row) {
 
 
  428    const size_t s = 512;
 
  432    for (
size_t i = 0; i < s; ++i) {
 
  433        for (
size_t j = 0; j < s; ++j) {
 
  434            matrix_demo[i][j] = i + j;
 
  440    for (
size_t i = 0; i < s; ++i) {
 
  441        for (
size_t j = 0; j < s; ++j) {
 
  442            matrix_demo2[i][j] = 2 + i + j;
 
  446    auto start = std::chrono::system_clock::now();
 
  447    auto Mat3 = matrix_demo2 * matrix_demo;
 
  448    auto end = std::chrono::system_clock::now();
 
  450    std::chrono::duration<double> time = (end - start);
 
  451    std::cout << 
"Strassen time: " << time.count() << 
"s" << std::endl;
 
  453    start = std::chrono::system_clock::now();
 
  454    auto conf = matrix_demo2.naive_multiplication(matrix_demo);
 
  455    end = std::chrono::system_clock::now();
 
  458    std::cout << 
"Normal time: " << time.count() << 
"s" << std::endl;
 
  461    assert(Mat3 == conf);
 
Matrix(const Integer size)
Constructor.
Matrix slice(const size_t row_start, const size_t row_end=MAX_SIZE, const size_t col_start=MAX_SIZE, const size_t col_end=MAX_SIZE) const
Creates a new matrix and returns a part of it.
Matrix & operator-=(const Matrix< Number > &other) const
Subtract another matrices to current matrix.
Matrix(const Integer rows, const Integer cols)
Constructor.
bool operator==(const Matrix< T > &other) const
Compares two matrices if each of them are equal or not.
Matrix naive_multiplication(const Matrix< Number > &other) const
Naive multiplication performed on this.
Matrix operator*(const Matrix< Number > &other) const
Multiply two matrices and returns a new matrix.
Matrix operator-(const Matrix< Number > &other) const
Subtract two matrices and returns a new matrix.
Matrix strassens_multiplication(const Matrix< Number > &other) const
Strassens method of multiplying two matrices References: https://en.wikipedia.org/wiki/Strassen_algor...
void h_stack(const Matrix< Number > &other)
Horizontally stack the matrix (one after the other)
std::vector< T > & operator[](const Integer index)
returns the address of the element at ith place (here ith row of the matrix)
Matrix operator+(const Matrix< Number > &other) const
Add two matrices and returns a new matrix.
Matrix & operator+=(const Matrix< Number > &other) const
Add another matrices to current matrix.
std::pair< size_t, size_t > size() const
Get the matrix shape.
Matrix operator*(const Number other) const
Multiply matrix with a number and returns a new matrix.
Matrix & operator*=(const Number other) const
Multiply a number to current matrix.
void v_stack(const Matrix< Number > &other)
Horizontally stack the matrix (current matrix above the other)
static void test()
Self-test implementations.
static std::ostream & operator<<(std::ostream &out, matrix< T > const &v)
Namespace for performing strassen's multiplication.