Skip to content
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

Merged
merged 26 commits into from
Sep 28, 2023
Merged

Intersection speedup and refactor #344

merged 26 commits into from
Sep 28, 2023

Conversation

kilohsakul
Copy link
Collaborator

Mainly better sotrage for map of pairs to states,
and a number of other things.

@codecov
Copy link

codecov bot commented Sep 25, 2023

Codecov Report

Attention: 24 lines in your changes are missing coverage. Please review.

Comparison is base (3380500) 72.94% compared to head (8614495) 71.64%.
Report is 10 commits behind head on devel.

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     
Files Coverage Δ
include/mata/nfa/delta.hh 90.54% <ø> (ø)
include/mata/nfa/nfa.hh 100.00% <ø> (ø)
include/mata/nfa/plumbing.hh 94.44% <100.00%> (ø)
src/nfa/inclusion.cc 90.09% <100.00%> (ø)
src/nfa/nfa.cc 80.16% <100.00%> (+0.16%) ⬆️
src/nfa/operations.cc 63.90% <100.00%> (+0.29%) ⬆️
src/strings/nfa-noodlification.cc 71.49% <66.66%> (ø)
src/nfa/delta.cc 82.71% <80.00%> (-0.08%) ⬇️
src/nfa/intersection.cc 79.41% <78.35%> (-3.67%) ⬇️

... and 10 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

src/nfa/intersection.cc Outdated Show resolved Hide resolved
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)
Copy link
Collaborator

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.

Copy link
Collaborator Author

@kilohsakul kilohsakul Sep 26, 2023

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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

Copy link
Collaborator

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.

Copy link
Collaborator Author

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 Show resolved Hide resolved
src/nfa/intersection.cc Show resolved Hide resolved
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)
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

// 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.
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

include/mata/nfa/algorithms.hh Outdated Show resolved Hide resolved
include/mata/nfa/delta.hh Outdated Show resolved Hide resolved
include/mata/nfa/nfa.hh Show resolved Hide resolved
include/mata/nfa/algorithms.hh Outdated Show resolved Hide resolved
include/mata/nfa/algorithms.hh Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
Copy link
Member

@tfiedor tfiedor left a 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.

include/mata/nfa/algorithms.hh Outdated Show resolved Hide resolved
namespace mata::nfa {

Nfa intersection(const Nfa& lhs, const Nfa& rhs, const Symbol first_epsilon, ProductMap *prod_map) {

Copy link
Member

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.

Copy link
Collaborator Author

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.

Copy link
Member

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha, ok

Copy link
Collaborator Author

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

src/nfa/intersection.cc Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/intersection.cc Outdated Show resolved Hide resolved
src/nfa/operations.cc Outdated Show resolved Hide resolved
@@ -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);
Copy link
Member

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.

@kilohsakul
Copy link
Collaborator Author

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.

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.
Lets bother with it only if we see something bad in the experiment.

@kilohsakul
Copy link
Collaborator Author

I uncommenting that assert in uitils.cc in integration-tests but Mmaybe it should no bet failing.
Could you look at it, @tfiedor ? I made an issue.

kilohsakul and others added 2 commits September 28, 2023 15:50
Co-authored-by: David Chocholatý <[email protected]>
@kilohsakul
Copy link
Collaborator Author

Lets merge this, no?

@tfiedor
Copy link
Member

tfiedor commented Sep 28, 2023

Lets merge this, no?

You are done?

@kilohsakul
Copy link
Collaborator Author

Now yes, done.

@tfiedor tfiedor merged commit 025f56a into devel Sep 28, 2023
19 of 20 checks passed
@tfiedor tfiedor deleted the intersection_faster branch September 28, 2023 16:19
@kilohsakul kilohsakul restored the intersection_faster branch September 28, 2023 16:24
Copy link
Collaborator

@Adda0 Adda0 left a 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.

@Adda0
Copy link
Collaborator

Adda0 commented Oct 2, 2023

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants