New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement move semantics for Add and Mul #192
Conversation
We have to cast away const'ness in order to move the internal dictionary, but since the expression that contains it is destroyed in the same function, it must work.
(Travis tests are passing: https://travis-ci.org/certik/csympy/builds/27439688.) |
For comparison, on the same machine. Ginac:
Sage:
|
I went through the Thomas Becker`s article couple of times, I don't think I understood it completely. But, to my knowledge, this PR is +1 to merge. |
I don't understand it completely either. But the relatively simple changes Sent from my mobile phone.
|
// 'p->first' will be destroyed when 'd' is at the end of this | ||
// function, so we "steal" its dict_ to avoid an unnecessary | ||
// copy. | ||
map_basic_basic &d3 = const_cast<map_basic_basic &>(d2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to benchmark expand2
without using the temporaries d2
and d3
here and in pow.cpp
. I got better results once or twice but most of the times the timings were not that different. Removing d2
and d3
results in quite unreadable code anyway, so I don't think it matters a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to always do lots of runs and take the fastest time. The numbers always oscillate a bit. The temporaries d2
and d3
should be optimized out by the compiler. It's just a reference anyway (no copying being done).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I didn't do a lot of test runs on this. Compiler should optimize them so I guess there is not going to be a huge difference.
Yes, I agree. |
I just read about |
Ok, there seem to be no objections, tests pass, so I am merging this. |
Implement move semantics for Add and Mul
This PR implements move semantics in Add's and Mul's constructors, so the dictionary (
std::map
forMul
orstd::unordered_map
forAdd
) is not copied when the class is constructed, but rather it is moved using the C++11 move semantics using rvalue references.Just google "rvalue references", e.g. here is some introduction: http://thbecker.net/articles/rvalue_references/section_01.html. It is confusing at first, but the actual practice, as seen from this PR, is pretty simple. One just has to be careful to make sure the object really gets moved, instead of copied by proper using of
std::move
everywhere, as well as proper declarations.This significantly speeds up some of our benchmarks (i.e. 12% speedup):
Before:
After:
@hazelnusse, let me know what you think. Do you have more ideas along these lines how to speedup CSymPy?
@thilinarmtb, @sushant-hiray if you could review this PR as well, that would be awesome.