-
Notifications
You must be signed in to change notification settings - Fork 13
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
Intersection speedup and refactor #344
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## devel #344 +/- ##
==========================================
- Coverage 72.94% 71.64% -1.31%
==========================================
Files 33 30 -3
Lines 4144 3636 -508
Branches 955 846 -109
==========================================
- Hits 3023 2605 -418
+ Misses 740 736 -4
+ Partials 381 295 -86
☔ View full report in Codecov by Sentry. |
src/nfa/intersection.cc
Outdated
std::vector<State> min_lhs; | ||
std::vector<State> max_lhs; | ||
|
||
auto update_ranges = [&min_rhs,&max_rhs,&min_lhs,&max_lhs](State lhs_state, State rhs_state) |
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.
This series of lambda functions is quite ugly. I would consider some better code structure or something.
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 was going to say that I agree, but as a method with all this stuff as parameters it is even uglier.
In fact I am thinking that this way of doing it is quite succinct and easy to read, even thogh it is not exactly standard.
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.
It might be a bit slower than functions, but I agree that in this case, unless you want to create a class for intersection, the lambdas here simplify the structure and passing parameters around.
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.
david said just write [&], looks nicer now
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 think that the problem in this conversion is about having 6 or so lambda one after another, often without any documentation comment explaining what they are for.
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.
now there is much less lamdas and they are simple
src/nfa/intersection.cc
Outdated
const StatePost& lhs_state_post{lhs.delta[lhs_source] }; | ||
|
||
//TODO: handling of epsilons might not be ideal, don't know, it would need some brain cycles to improve. | ||
// (handling of normal symbols is more important and it is ok) |
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.
Well I guess this is not true. In noodler
we use heavily this epsilon product.
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.
Is there a benchmark with it at tacas?
Anyway, I currently don't know how to do it better.
Lets think about it if we find it slow on some benchmark.
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.
Well, depends on which tacas paper do you mean. For mata
we don't use it.
src/nfa/intersection.cc
Outdated
// And every containment test first asks whether lhs and rhs are in each others ranges. | ||
// This is several times faster compared to pure product_vec_map, which is turn is notably faster that one unordered map from pairs to states. | ||
// (but Juraj says that rewriting hash function may help unordered map significantly, so maybe that would be enough ... ?) | ||
// TODO: where to put this magical constant? It should not be here. |
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.
Alternative to that is a vector of sets. First state in a pair serves as an index to the vector, the second state is found in the set using binary search.
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, replacing unordered_map with map makes it 40% slower.
StackOverflow people say that this is because memory locality is by far the most important thing when the collections are not too large, and set has pointers everywhere.
Besides, when trying this, I also tried disable the optimization with ranges, and the fucker got faster.
So maybe we can simplify this and remove all that, just keep the switching between matrix and vector of unordered maps. But I will try to see what happened first.
optimizing the number of searches in the lhs/rhs to product maps
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 have few minor suggestions for small speed ups. Other than that, it is quite a beast. It would be good to go through it again after deadlines and try to make it little bit more readable, as it is sometimes heavy.
Also, I'm wondering if we should keep the old version and maybe have some portfolio intersection method deciding wrt e.g. the size of the input automata, since I have a feeling this will work for big automata, but might be worse for smaller ones (since there are lot of vectors, vector of vectors etc.). Experiments will tell.
namespace mata::nfa { | ||
|
||
Nfa intersection(const Nfa& lhs, const Nfa& rhs, const Symbol first_epsilon, ProductMap *prod_map) { | ||
|
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.
Btw. one small suggestion for potential speedup: test the following:
if lhs.empty:
return lhs
elif rhs.empty:
return rhs
Might show some speed up, if in the product you do some initialization steps.
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.
Might make sense, but I am not sure whether emptiness is really for free, we are changing it now, lets see the performance first.
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.
As I said at meeting, I don't suggest testing language emptiness, but maybe delta emptiness? Or final state emptiness could be applied? Basically anything cheap, that can be used to avoid costly initializations.
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.
aha, ok
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.
fine, I added test for final initial state emptiness
tests-integration/src/utils/utils.cc
Outdated
@@ -62,7 +62,7 @@ int load_automata( | |||
std::vector<mata::IntermediateAut> mintermized = mintermization.mintermize(inter_auts); | |||
TIME_END(mintermization); | |||
for (mata::IntermediateAut& inter_aut : mintermized) { | |||
assert(inter_aut.alphabet_type == mata::IntermediateAut::AlphabetType::BITVECTOR); | |||
//assert(inter_aut.alphabet_type == mata::IntermediateAut::AlphabetType::BITVECTOR); |
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.
Probably don't commit this at all and keep your repo dirty.
Co-authored-by: Tomas Fiedor <[email protected]>
Co-authored-by: Tomas Fiedor <[email protected]>
Co-authored-by: Tomas Fiedor <[email protected]>
Ok lets see, but I actually don't believe that it can be slower, the vectors should be all much cheaper to allocate then the deltas of the input automata, so it should cost relatively nothing. |
I uncommenting that assert in uitils.cc in integration-tests but Mmaybe it should no bet failing. |
Co-authored-by: David Chocholatý <[email protected]>
…inates after finding first final state).
Co-authored-by: David Chocholatý <[email protected]>
Lets merge this, no? |
You are done? |
Now yes, 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.
I reviewed the changes again, resolved some unresolved discussions from this PR, and will integrate the changes in another PR.
@kilohsakul Can the branch be removed? We are trying to keep the number of branches to a minimum in order to keep the repository clean and uncluttered. |
Mainly better sotrage for map of pairs to states,
and a number of other things.