'Range-v3 operator overloading to write shorter code

For my matrix class I want to do some sort of operator overloading (probably using expression templates) on range-v3 views for + - / * % . For example if I want to get a view of the sum of two columns, I want to write

col_1 + col_2

instead of

rv::zip_with([](auto c1, auto c2) {return c1 + c2;}, col_1, col_2);

Probably some ideas from this paper can be used to avoid constructing too many temporaries. Here is the code that I want to write:

//simple example
//what I want to write
auto rangeview =    col_1 + col_2;
//what I can write
auto rangeview =    rv::zip_with([](auto c1, auto c2) {
                        return c1 + c2;
                    }, col_1, col_2);


//itermediate
//what I want to write
auto rangeview =    col_1 + col_2 + col_3;
//what I can write
auto rangeview =    rv::zip_with([](auto c1, auto c2, auto c3) {
                        return c1 + c2 + c3;
                    }, col_1, col_2, col_3);


//advanced
//what I want to write
auto rangeview =    10*col_1 + 20*col_2 - 30*col_3;
//what I can write
auto rangeview =    rv::zip_with([](auto c1, auto c2, auto c3) {
                        return 10.0*c1 + 20.0*c2 - 30.0*c3;
                    }, col_1, col_2, col_3);


//more advanced with elementwise multiplication
//what I want to write
auto rangeview =    10*col_1 + 20*col_2 - col_2 % col_3;
//what I can write
auto rangeview =    rv::zip_with([](auto c1, auto c2, auto c3) {
                        return 10.0*c1 + 20.0*c2 - c2*c3;
                    }, col_1, col_2, col_3);


Solution 1:[1]

Range views are supposedly lazy; Is it not why they are called views in the first place? So why not to return the resulting view in a user defined operand of your own? They'll ideally get evaluated, once the final range is iterated in a for loop or an algorithm.

IMHO not everything can be provided by the std or any other general purpose library. Some little tweaks are necessary using any tool:

decltype(auto) operator+(column const& col_1, column const& col_2){
    return rv::zip_transform( [] (auto c1, auto c2)
                                 {return c1 + c2;},
                             rv::all(col_1),
                             rv::all(col_2) );
};

A scalar * vector multiplication operator can be separately defined in a similar manor too. Then the linear combination of columns is written just as it is mathematically written. The actual calculations will wait till a for loop or an algorithm like std::fold or std::foreach traverses the range.


Lazy scalar * vector product becomes:

decltype(auto) operator*(range_value_t<column> const coef, column& col) {
    return rv::transform(rv::all(col),[=,coef](auto x){return coef*x});
};

Solution 2:[2]

You main concern seem to be with (possible huge) temporaries that could be created. This can be solved with a concept called expression templates, but there is not really a one size fits all solution here. Best bet is probably switch to a matrix library that supports that. Unless you are developing a library or want to invest in this you probably want to steer away from writing your own expression templates. An easier method for getting closer, but without a lot of operator overloading/expression templates could be using range based for loop with custom iteration type (not as syntactically sugery as expression templates but much easier to implement):

Pseudocode:

*resultype* result;//perhaps alloc on this line or make zip handle it..
for (auto z : zip(result, col_1, col_2, col_3)) {
  z[0] = 10.0*z[1] + 20.0*z[2] - 30.0*z[3];
}

This is on the idea stage, but will be a bit shorter (and imho a bit more pleasing to read) than the lambda style. How to implement the zip class I leave out of this answer.

Solution 3:[3]

I agree with @darune, unless you have a strong need, you should use a library, and in particular Eigen. Most of the operations you want to support are illustrated on This link.

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
Solution 2 darune
Solution 3 Dilan