I used to take the sum of a symmetric (Hermitian) matrix (the matrix is in an std::vector
), which is a huge waste because the imaginary part will always add to zero (I'm talking about huge matrices with side-length of n>1000
, so I think it makes a difference.
So now I only add the upper-triangular part of the matrix. But I want to optimize this further and avoid adding the complex part because I don't need it.
What I currently use is:
std::real(std::accumulate(myMatrix.begin(), myMatrix.end(), std::complex<Real>(0,0)));
This adds all the element of myMatrix
to std::complex<Real>(0,0)
, resulting in the sum I need.
But this will add real and imaginary components of my vector, which is a waste! How can I write the most optimized version of this that adds only the real part of this matrix?
UPDATE:
While I accepted the answer that works, I discovered that it's slower than summing the real and imaginary parts of my matrix. It's slower by 5%-10% for a matrix with side-length of 128. This is surprising. Any other faster suggestions are highly appreciated.
Please ask if you require additional information.
Real real_sum = std::accumulate(
myMatrix.cbegin(), myMatrix.cend(), Real{},
[](Real const acc, std::complex<Real> const& c) { return acc + std::real(c); }
);
std::accumulate
has two overloads, one of which takes an operator:
template< class InputIt, class T, class BinaryOperation >
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
Just provide your own instead of defaulting to +
:
std::accumulate(myMatrix.begin(), myMatrix.end(), Real{0},
[](Real const& sum, std::complex<Real> const& next){
return sum + std::real(next);
});
Alternatively, you could do something fun like use boost::transform_iterator
:
auto make_real = [](std::complex<Real> const& c) {
return std::real(c);
};
std::accumulate(
boost::make_transform_iterator(myMatrix.begin(), make_real),
boost::make_transform_iterator(myMatrix.end(), make_real),
Real{0});
Or with range-v3:
accumulate(myMatrix,
Real{0},
std::plus<>{},
[](std::complex<Real> const& c) { return c.real(); }
);
Both of the above would be much nicer if real
didn't have overloads and you could just provide std::real<Real>
in the boost example and &std::complex<Real>::real
in the second.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With