'Mathematical '+' operation on nested vector std::vector<std::vector<double>>

Say I defined second order tensors A and B as nested vectors as:

std::vector<std::vector<double>> A, B;

Now I want to calculate the elementwise addition, meaning:

// Elementwise addition of two tensors
//         |A11+B11  A12+B12  ... |
// A + B = | ...     A22+B22  ... |
//         | ...       ...    ... |

For a std::vector this can be achieved by creating a template for the '+' operator:

#include <cassert>
#include <vector>
#include <algorithm>

template <typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
{
    assert(a.size() == b.size());

    std::vector<T> result;
    result.reserve(a.size());

    std::transform(a.begin(), a.end(), b.begin(), 
                  std::back_inserter(result), std::plus<T>());
    return result;
}

int main(){
    std::vector<double> a {0.0, 1.0, 2.0};
    std::vector<double> b {2.0, 2.0, 2.0};

    std::vector<double> c = a + b  // yields {2.0, 3.0, 4.0}

    return 0;
}

I have tried to solve the problem using the std::for_each function, but I am getting a false result:

#include <vector>
#include <algorithm>

template <typename T>
std::vector<std::vector<T>> operator+=(std::vector<std::vector<T>>& A,
                                      const std::vector<std::vector<T>>& B)
{
    // Ommitt compatibility checks
    std::for_each( A.begin(), A.end(),[&B](std::vector<T>& a){
        std::for_each( B.begin(), B.end(),[&a](const std::vector<T>& b){
            std::transform( a.begin(), a.end(),b.begin(), a.begin(), std::plus<T>());
        });
    });

    return A;
}

template <typename T>
std::vector<std::vector<T>> operator+(std::vector<std::vector<T>> A,
                                     const std::vector<std::vector<T>>& B)
{ 
    return A += B;
}

int main(){
    std::vector<std::vector<double>> A {{0.0,1.0}, {2.0,3.0}};
    std::vector<std::vector<double>> B = {{10.0,100.0}, {1000.0,10000.0}};

    auto C = A + B; 
    // yields C =  {{1010, 10101}, {1012, 10103}
    // should yield C = {{10, 101}, {1002, 10003}}

    return 0;
}

Obviously my code does not yield the correct result. Any recommendations/solution to get a working (efficient) implementation of this?



Solution 1:[1]

For a vector, element lookup is O(1), so a simple counting loop would do. Be careful how you do it. Your current incorrect solution is O(n2) for the two outer loops alone. Do you see what happened?

for   (std::size_t x = 0;  x < A   .size();  x += 1)
  for (std::size_t y = 0;  y < A[0].size();  y += 1)
    A[x][y] += B[x][y];

This is again an O(n) pass over the two matrices.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DĂșthomhas