Search code examples
c++algorithmmatrixsumcomponents

sum up vectors in a matrix, element by element in c++


Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:

sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]

I find out that exists this method for two vectors, I would like to extend it to many vectors, in particular to the std::vector<type>rows componing the matrix std::vector<vector<type> > M, not knowing a-priori the dimomension of M.


Solution

  • Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:

    sum[0]=M[0][0]+M[1][0]+M[2][0]
    sum[1]=M[0][1]+M[1][1]+M[2][1]
    sum[2]=M[0][2]+M[1][2]+M[2][2]
    

    Unfortunately, there is no simple method in the C++ standard library for adding a container's elements column-wise.

    There is std::accumulate(), but naturally, it would add up the row elements together, not the column elements, but we can fix that by iterating through each column index inside the matrix and adding up the elements one by one:

    #include <iostream>
    #include <numeric>
    #include <cstddef>
    #include <vector>
    
    // The below function assumes that all columns of your matrix have the same length
    template <typename T>
    std::vector<T> m_col_add(std::vector<std::vector<T>> const& mat) {
        std::vector<T> res;
        const auto column_size = mat[0].size();
        for (size_t x = 0; x < column_size; ++x)
            res.push_back(std::accumulate(mat.begin(), mat.end(), T{}, [x](T const& a, std::vector<T> const& row) {
                return a + row[x];
            }));
        return res;
    }
    
    int main() {
        std::vector<std::vector<int>> mat {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        };
        auto res = m_col_add(mat);
        for (auto const& elem : res)
            std::cout << elem << " ";
    }
    

    Output:

    15 18 21 24 
    

    Alternatively, if you already know the sizes of the rows and columns during compile-time and are using C++17 or above, you can use fold expressions and std::index_sequence<> to add up the elements faster by compile-time expansion:

    #include <iostream>
    #include <utility>
    #include <cstddef>
    #include <array>
    
    template <size_t Column, typename T, size_t Rows, size_t Columns, size_t ...Sizes>
    T m_col_add_impl2(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
        return (mat[Sizes][Column] + ...);
    }
    
    template <typename T, size_t Rows, size_t Columns, size_t ...Sizes>
    std::array<T, Columns> m_col_add_impl1(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
        std::array<T, Columns> sum;
        ((sum[Sizes] = m_col_add_impl2<Sizes>(std::make_index_sequence<Rows>(), mat)), ...);
        return sum;
    }
    
    template <typename T, size_t Rows, size_t Columns>
    std::array<T, Columns> m_col_add(std::array<std::array<T, Columns>, Rows> const& mat) {
        return m_col_add_impl1(std::make_index_sequence<Columns>(), mat);
    }
    
    int main() {
        std::array mat {
            std::array {1, 2, 3, 4},
            std::array {5, 6, 7, 8},
            std::array {9, 10, 11, 12}
        };
        auto res = m_col_add(mat);
        for (auto const& elem : res)
        std::cout << elem << " ";
    }
    

    Output:

    15 18 21 24