C++ Efficient arithmetic operator overloading for class containing Eigen matrices - c++

I want to construct a class that contains several Eigen Matrices or Vectors. I want the objects to behave as mathematical vectors: therefore I want to overload +, - and *(by a scalar). I want to do very many linear combinations of these objects, so I would like to implement it in a way that it takes full advantage of Eigen and creates as few copies and temporaries as possible.
I usually follow the recommendations in What are the basic rules and idioms for operator overloading? but they require to pass some of the object by value rather than reference. Eigen "dislikes" when matrices are passed by value.
Below is my attempt (I overload only + for shortness) where I avoid passing by value in the overloading of + and instead I use the named return value optimization (NRVO):
template <int N> class myClass {
public:
Eigen::Matrix<double, N, N> mat = Eigen::Matrix<double, N, N>::Zero();
Eigen::Matrix<double, N, 1> vec = Eigen::Matrix<double, N, 1>::Zero();
public:
myClass(){}
myClass(Eigen::Matrix<double, N, N> & t_mat,Eigen::Matrix<double, N, 1> &t_vec) : mat (t_mat), vec(t_vec){ }
myClass(const myClass & other): mat(other.mat), vec(other.vec) {};
myClass& operator+=(const myClass& rhs){
mat += rhs.mat; vec += rhs.vec;
return *this;
}
public:
enum { NeedsToAlign = (sizeof(mat)%16)==0 || (sizeof(vec)%16)==0 };
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
};
template <int N> myClass<N>& operator+( const myClass<N>& lhs, const myClass<N>& rhs )
{
myClass<N> nrv( lhs );
nrv += rhs;
return nrv;
}
Is this the best solution? Fastest?
As a final short question: it would be nice to use Boost/operators (https://www.boost.org/doc/libs/1_54_0/libs/utility/operators.htm) to easily complete the set of operator overloading. Can I use that, or would that cause problems? I guess it will implement binary operations passing the first argument by value.

I tried to solve the problem by myself. I tried several versions and compared them with directly summing Eigen vectors.
The first strategy follows What are the basic rules and idioms for operator overloading?:
using realValueType = double;
const int NDim = 1000000;
using InternalVecType = Eigen::Matrix<realValueType, Eigen::Dynamic, 1>;
class MyVec {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVec(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVec(const InternalVecType& other): vec(other) {};
MyVec(const MyVec& other): vec(other.vec) {}; // Copy constructor
MyVec(MyVec&& other){vec.swap(other.vec);} // Move constructor
// Arithmetic
MyVec& operator=(MyVec other){vec.swap(other.vec);return *this;} // Copy-and-Swap
MyVec& operator+=(const MyVec& other) {vec+=other.vec; return *this;}
friend MyVec operator+(MyVec lhs, const MyVec& rhs) { lhs += rhs; return lhs;}
};
The second version uses NRVO
class MyVecNRVO {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVecNRVO(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVecNRVO(const InternalVecType& other): vec(other) {};
MyVecNRVO(const MyVec& other): vec(other.vec) {}; // Copy constructor
MyVecNRVO(MyVec&& other){vec.swap(other.vec);} // Move constructor
// Arithmetic
MyVecNRVO& operator=(MyVecNRVO other){vec.swap(other.vec);return *this;} // Copy-and-Swap
MyVecNRVO& operator+=(const MyVecNRVO& other) {vec+=other.vec; return *this;}
friend MyVecNRVO operator+(const MyVecNRVO& lhs, const MyVecNRVO& rhs) {
MyVecNRVO nrv(lhs); nrv += rhs; return nrv;}
};
My third version uses (probably clumsily) expression templates
struct Add { static InternalVecType apply(InternalVecType lhs, InternalVecType rhs) {return lhs+rhs;} };
template<class E1, class E2, class Op> struct ComplexExpr {
E1 l_;
E2 r_;
ComplexExpr(E1 l, E2 r) : l_(l), r_(r) {}
InternalVecType getvec(){return Op::apply(l_.getvec(), r_.getvec());}
};
template<class E1, class E2> ComplexExpr<E1, E2, Add> operator+ (E1 e1, E2 e2) {
return ComplexExpr<E1, E2, Add>( e1, e2 );
}
class MyVecT {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVecT(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVecT(const InternalVecType& other): vec(other) {};
// template<> MyVecT(
InternalVecType getvec(){return vec;};
};
To test it I created 15 vectors of types InternalVecType (meaning the Eigen type not wrapped in my class), MyVec, MyVecNRVO, and MyVecT and summed them in a single line.
What I have noticed is that the first version is not only the fastest, but also as fast as directly adding the Eigen vectors in a single line! NRVO is around 5 times slower, while my attempt at expression templates 100 times slower (ouch! but in my defence, it is my very first attempt ever :D).
It seems that the first option is not only the best, but also the optimal. Maybe a better implementation of expression templates could achieve a better speed, but since the first option is as fast as the raw summation, it does not seem worth to go in that direction. Any comment is welcome.

Related

Compile-time expression factoring for user-defined types

For trivial types, compilers can optimize arithmetic expressions into a new expression, with the same result, that requires less instructions in order to compute it. For example, if a, b are int, then the expression int c = a * a + b * a would be computed as (a + b) * a, which saves an instruction.
Is there a way to tell the compiler to perform this optimization for custom types? E.g., if A, B are matrices, then computing A*A + A*B would be factored as A*(A+B) (at compile time), which saves about n2 operations during runtime.
First note, A*A + A*B != (A+B)*A for matrices, not even close. It's A*(A+B) and that's not the same as matrix multiplication is not commutative. That said, what you're asking for, as a conceptual thing, is feasible.
This is not a complete answer, just a heads up. As #JerryJeremiah correctly wrote, you might use expression templates for this. First for your matrix class, instead of operators implementing evaluation of expressions, you return an unevaluated context: (here I show value scemantics, of course, you might implement it using references/pointers)
template<typename LHS, typename RHS, char op>
struct OperatorContext {
static constexpr char operator = op;
const LHS lhs;
const RHS rhs;
};
// inside Matrix {
template<typename LHS, typename RHS, char op>
friend auto operator+(const Matrix& lhs, OperatorContext<LHS, RHS, op>& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
template<typename LHS, typename RHS, char op>
friend auto operator+(OperatorContext<LHS, RHS, op>& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
friend auto operator+(const Matrix& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, Matrix, '+'>{lhs, rhs};
}
// similarly for other operators
// }
// furthermore, you need similar operators for 2 OperatorContext arguments
Then, you can implement assignment operator to Matrix from various OperatorContext<> versions. Here, you might do the optimization, as you have complete type info. Note that this only works until you assign to a variable. E.g.:
// inside Matrix {
Matrix& operator=(OperatorContext<OperatorContext<Matrix, Matrix, '*'>, OperatorContext<Matrix, Matrix, '*', '+'> other) {
if (other.lhs.lhs == other.rhs.lhs) { // preferably compare-by-address
*this = other.lhs.lhs * (other.lhs.rhs + other.rhs.rhs)
} else {
*this = other.lhs.lhs * other.lhs.rhs + other.rhs.lhs * other.rhs.rhs;
}
return *this;
}
// }

Implementing Matrix operations in C++

I am trying to write a simple C++ header-only library that implements some basic numerical algorithms. It's a hobbyist project, that I wish to do in my personal time.
I created a C++ MatrixX class that represents dynamic-size matrices, that is its dimensions can be supplied at run-time. Say, we create a MatrixX object as follows :
MatrixXd m {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}
};
My MatrixX<scalarType> templated class uses std::vector<scalarType> as the container to store data.
Currently, if I write m.row(i), it returns the i'th row vector of the matrix. What I'd also like is, to be able to have m.row(i) on the left-hand side of an assignment statement. Something like:
m.row(i) = {{1, 2, 3}};
m.row(j) = m.row(j) - 2*m.row(i);
Does anyone have any hints/tips on how to go about this task in C++? I am including my source code, unit tests and documentation as links below, and not pasting it inline for the sake of brevity.
Documentation
Source code
Unit Tests
A common approach for this type of situation is to have the row() method return a proxy object that represents the row without being the row itself.
You are then free to implement how this RowProxy behaves by having its operations inspect and maninupulate the matrix it was created from.
Here's a rough starting point:
template<typename T>
class RowProxy {
public:
template<std::size_t N>
RowProxy& operator=(const std::array<T, N>& rhs) {
assert(N == row_index_.columns());
// ...
}
RowProxy& operator=(const RowProxy& rhs) {
assert(matrix_.columns() == rhs.matrix_.columns());
// ...
}
RowProxy& operator=(const Vector<T>& rhs) {
assert(matrix_.columns() == rhs.matrix_.columns());
// ...
}
Vector<T>& operator*(const T& scalar) const {
return ...;
}
// more operators...
private:
MatrixX<T>& matrix_;
std::size_t row_;
template<typename T>
friend class MatrixX;
RowProxy(MatrixX<T>& m, std::size_t r) : matrix_(m), row_(r) {}
};
template<typename T>
struct MatrixX {
public:
// ...
RowProxy<T> row(std::size_t index) {
return RowProxy<T>{*this, index};
}
// ...
};
template<typename T>
Vector<T>& operator*(const T& scalar, const RowProxy* rhs) const {
return rhs * scalar;
}

operator overloading using template

I'm writing a class named Double which extends the built in type 'double' in c++. It has a data member of the type 'double'. For the class Double I need to overload many basic arithmetic operators like "+", "-", "*", "/". For example, the "+" operator is overloaded this way:
Relation<Double>* operator+ (Double &d2)
// Relation is a abstract class template.
{
/*
...code that do something else.
*/
return new Plus<Double>(this, &d2); // Plus is derived from Relation.
}
// Double + Double returns a Relation pointer.
and the "-" operator is overloaded fast the same way:
Relation<Double>* operator- (Double &d2)
{
/*
...code that do something else but the same as above.
*/
return new Minus<Double>(this, &d2);
}
The actual calculation is done by the member function in the Relation class. The only difference of the operators' bodies is the object initialized(Plus vs Minus).
For operator that takes exactly two operands, I should alway do the overloading like this, which is duplicated and not nice.
So template function comes to my mind. But the problem is, I can pass Plus or Minus as template argument, but can not pass the operator. How could I make a template or use other methods to do the overloading of these operators?
Yes, operator overloading may be a pain and source of code duplication, see this suggestion to the standard to ease it.
For now the only I can think about is something like this:
template<typename T>
struct OperatorMinus {
static T doIt(T const& lhs, T const& rhs) { return lhs - rhs; };
}
template<typename T>
struct OperatorPlus {
static T doIt(T const& lhs, T const& rhs) { return lhs + rhs; };
}
template<typename T, typename U>
class Operator: public Relation<T>
public:
Operator(T const& lhs, T const& rhs): _lhs(lhs), _rhs(rhs) {}
T doIt() override {
return U::doIt(_lhs, _rhs);
}
private:
T _lhs;
T _rhs;
};
Relation<Double>* operator+ (Double &d2)
{
return new Operator<Double, OperatorPlus<Double>>(this, &d2);
}

How can I implement "op" in terms of "op=" in a CRTP base class?

Herb Sutter's Guru of the Week #4, "Class Mechanics", teaches that the "a op b" form of an overloaded operator should be implemented in terms of the "a op= b" form (see point #4 in the solutions).
As an example, he shows how do to this for the + operator:
T& T::operator+=( const T& other ) {
//...
return *this;
}
T operator+( T a, const T& b ) {
a += b;
return a;
}
He points out that first parameter in operator+ is intentionally being passed by value, so that it can be moved if the caller passes a temporary.
Notice that this requires that the operator+ be a non-member function.
My question is, how can I apply this technique to an overloaded operator in a CRTP base class?
So say this is my CRTP base class with its operator+=:
template <typename Derived>
struct Base
{
//...
Derived operator+=(const Derived& other)
{
//...
return static_cast<Derived&>(*this);
}
};
I can see how to implement operator+ in terms of operator+= as a member function if I dispense with the "pass the first argument by value" optimization:
template <typename Derived>
struct Base
{
//...
Derived operator+(const Derived& other) const
{
Derived result(static_cast<const Derived&>(*this);
result += other;
return result;
}
};
but is there a way to do this while using that optimization (and therefore making the operator+ a nonmember)?
The normal way to implement Herb's advice is as follows:
struct A {
A& operator+=(cosnt A& rhs)
{
...
return *this;
}
friend A operator+(A lhs, cosnt A& rhs)
{
return lhs += rhs;
}
};
Extending this to CRTP:
template <typename Derived>
struct Base
{
Derived& operator+=(const Derived& other)
{
//....
return *self();
}
friend Derived operator+(Derived left, const Derived& other)
{
return left += other;
}
private:
Derived* self() {return static_cast<Derived*>(this);}
};
If you try to avoid the use of friend here, you realize it's almost this:
template<class T>
T operator+(T left, const T& right)
{return left += right;}
But is only valid for things derived from Base<T>, which is tricky and ugly to do.
template<class T, class valid=typename std::enable_if<std::is_base_of<Base<T>,T>::value,T>::type>
T operator+(T left, const T& right)
{return left+=right;}
Additionally, if it's a friend internal to the class, then it's not technically in the global namespace. So if someone writes an invalid a+b where neither is a Base, then your overload won't contribute to the 1000 line error message. The free type-trait version does.
As for why that signature: Values for mutable, const& for immutable. && is really only for move constructors and a few other special cases.
T operator+(T&&, T) //left side can't bind to lvalues, unnecessary copy of right hand side ALWAYS
T operator+(T&&, T&&) //neither left nor right can bind to lvalues
T operator+(T&&, const T&) //left side can't bind to lvalues
T operator+(const T&, T) //unnecessary copies of left sometimes and right ALWAYS
T operator+(const T&, T&&) //unnecessary copy of left sometimes and right cant bind to rvalues
T operator+(const T&, const T&) //unnecessary copy of left sometimes
T operator+(T, T) //unnecessary copy of right hand side ALWAYS
T operator+(T, T&&) //right side cant bind to lvalues
T operator+(T, const T&) //good
//when implemented as a member, it acts as if the lhs is of type `T`.
If moves are much faster than copies, and you're dealing with a commutative operator, you may be justified in overloading these four. However, it only applies to commutative operators (where A?B==B?A, so + and *, but not -, /, or %). For non-commutative operators, there's no reason to not use the single overload above.
T operator+(T&& lhs , const T& rhs) {return lhs+=rhs;}
T operator+(T&& lhs , T&& rhs) {return lhs+=rhs;} //no purpose except resolving ambiguity
T operator+(const T& lhs , const T& rhs) {return T(lhs)+=rhs;} //no purpose except resolving ambiguity
T operator+(const T& lhs, T&& rhs) {return rhs+=lhs;} //THIS ONE GIVES THE PERFORMANCE BOOST

Multiplying an object with a constant from left side

I have a Matrix class and it has overloaded * operators for scalar and matrix multiplications.
template <class T> class Matrix
{
public:
// ...
Matrix operator*(T scalar) const;
// ...
}
// ...
template <class T>
Matrix<T> Matrix<T>::operator*(T RightScalar) const
{
Matrix<T> ResultMatrix(m_unRowSize, m_unColSize);
for (uint64_t i=0; i<m_unRowSize; i++)
{
for (uint64_t j=0; j<m_unColSize; j++)
{
ResultMatrix(i, j) = TheMatrix[m_unColSize * i + j] * RightScalar;
}
}
return ResultMatrix;
}
// ...
I can multiply a matrix object with a scalar from right side without any problem:
Matrix<double> X(3, 3, /* ... */); // Define a 3x3 matrix and initialize its contents
Matrix<double> Y; // Define an output matrix
Y = X * 10.0; // Do the linear operation
But, how do I multiply it from left side same way?
Matrix<double> X(3, 3, /* ... */);
Matrix<double> Y;
Y = 10.0 * X;
In arithmetic, it is a common notation to write constants on the left side when doing multiplication. I would like to obey this rule to make my code more readable.
Is it possible to implement this in C++?
If it is possible, how do I modify the class method in my code?
Member functions are matched by their left-hand-side argument which is the this-pointer. Since native types can't have member functions, you have to add right-multiplication with user-defined types through non-member functions (and also for other types you don't have write-access to).
template<typename T>
Matrix<T> operator*(T const& scalar, Matrix<T> rhs)
{
// scalar multiplication is commutative: s M = M s
return rhs *= scalar; // calls rhs.operator*=(scalar);
}
NOTE: I wrote the above non-member operator* implemented in terms of a member operator*=. It is recommended to write all multiplications as non-member functions, and use a member operator*= to implement these multiplications with a lhs Matrix element.
This will a) keep the class interface minimal, and b) prevent hidden conversions. E.g. you could have a Matrix class that is implicitly convertible to scalar if the dimensions are 1x1, and these conversions could silently happen if you don't provide a separate overload that is a direct match.
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, T const& scalar)
{
return lhs *= scalar; // calls lhs.operator*=(scalar);
}
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, Matrix<T> const& rhs)
{
return lhs *= rhs; // calls lhs.operator*=(rhs);
}
Notice on how the lhs Matrix is a copy and not a reference. This allows the compiler to make optimizations such as copy elision / move semantics. Also note that the return type of these operators is Matrix<T> and not const Matrix<T> which was recommended in some old C++ books, but which prevents move semantics in C++11.
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(Matrix<T> const& rhs)
{
// your implementation
return *this;
}
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(T const& scalar)
{
// your implementation
return *this;
}
You'll need a non-member function for that:
template <typename T>
Matrix<T> operator*(T scalar, Matrix<T> const & matrix) {
return matrix * scalar;
}
Non-member operator overloads allow you to specify any type on either side, while member overloads always get the object on the left-hand side.