-
Notifications
You must be signed in to change notification settings - Fork 189
Issue1171 #244
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
base: main
Are you sure you want to change the base?
Issue1171 #244
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,8 +2,6 @@ | |
|
|
||
| #include "factored_transition_system.h" | ||
| #include "merge_selector.h" | ||
| #include "merge_tree.h" | ||
| #include "merge_tree_factory.h" | ||
| #include "transition_system.h" | ||
|
|
||
| #include <algorithm> | ||
|
|
@@ -16,71 +14,87 @@ namespace merge_and_shrink { | |
| MergeStrategySCCs::MergeStrategySCCs( | ||
| const FactoredTransitionSystem &fts, | ||
| const shared_ptr<MergeSelector> &merge_selector, | ||
| vector<vector<int>> &&non_singleton_cg_sccs) | ||
| vector<vector<int>> &&unfinished_clusters, | ||
| bool allow_working_on_all_clusters) | ||
| : MergeStrategy(fts), | ||
| merge_selector(merge_selector), | ||
| non_singleton_cg_sccs(move(non_singleton_cg_sccs)) { | ||
| unfinished_clusters(move(unfinished_clusters)), | ||
| allow_working_on_all_clusters(allow_working_on_all_clusters) { | ||
| } | ||
|
|
||
| MergeStrategySCCs::~MergeStrategySCCs() { | ||
| } | ||
|
|
||
| static void compute_merge_candidates( | ||
| const vector<int> &indices, vector<pair<int, int>> &merge_candidates) { | ||
| for (size_t i = 0; i < indices.size(); ++i) { | ||
| int ts_index1 = indices[i]; | ||
| for (size_t j = i + 1; j < indices.size(); ++j) { | ||
| int ts_index2 = indices[j]; | ||
| merge_candidates.emplace_back(ts_index1, ts_index2); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pair<int, int> MergeStrategySCCs::get_next() { | ||
| if (current_ts_indices.empty()) { | ||
| /* | ||
| We are currently not dealing with merging all factors of an SCC, so | ||
| we need to either get the next one or allow merging any existing | ||
| factors of the FTS if there is no SCC left. | ||
| */ | ||
| if (non_singleton_cg_sccs.empty()) { | ||
| // We are done dealing with all SCCs, allow merging any factors. | ||
| current_ts_indices.reserve(fts.get_num_active_entries()); | ||
| for (int ts_index : fts) { | ||
| current_ts_indices.push_back(ts_index); | ||
| if (unfinished_clusters.empty()) { | ||
| // We merged all clusters. | ||
| return merge_selector->select_merge(fts); | ||
| } else { | ||
| // There are clusters we still have to deal with. | ||
| vector<pair<int, int>> merge_candidates; | ||
| vector<int> factor_to_cluster; | ||
| if (allow_working_on_all_clusters) { | ||
| // Compute merge candidate pairs for each cluster. | ||
| factor_to_cluster.resize(fts.get_size(), -1); | ||
| for (size_t cluster_index = 0; | ||
| cluster_index < unfinished_clusters.size(); ++cluster_index) { | ||
| const vector<int> &cluster = unfinished_clusters[cluster_index]; | ||
| for (int factor : cluster) { | ||
| factor_to_cluster[factor] = cluster_index; | ||
| } | ||
| compute_merge_candidates(cluster, merge_candidates); | ||
| } | ||
| } else { | ||
| /* | ||
| There is another SCC we have to deal with. Store its factors so | ||
| that we merge them over the next iterations. | ||
| */ | ||
| vector<int> ¤t_scc = non_singleton_cg_sccs.front(); | ||
| assert(current_scc.size() > 1); | ||
| current_ts_indices = move(current_scc); | ||
| non_singleton_cg_sccs.erase(non_singleton_cg_sccs.begin()); | ||
| // Deal with first cluster. | ||
| vector<int> &cluster = unfinished_clusters.front(); | ||
| compute_merge_candidates(cluster, merge_candidates); | ||
| } | ||
| } else { | ||
| // Add the most recent product to the current index set. | ||
| current_ts_indices.push_back(fts.get_size() - 1); | ||
| } | ||
| // Select the next merge from the allowed merge candidates. | ||
| pair<int, int> next_pair = merge_selector->select_merge_from_candidates( | ||
| fts, move(merge_candidates)); | ||
|
|
||
| // Compute all merge candidates for the current set of indices. | ||
| vector<pair<int, int>> merge_candidates; | ||
| merge_candidates.reserve( | ||
| (current_ts_indices.size() * (current_ts_indices.size() - 1)) / 2); | ||
| assert(current_ts_indices.size() > 1); | ||
| for (size_t i = 0; i < current_ts_indices.size(); ++i) { | ||
| int ts_index1 = current_ts_indices[i]; | ||
| assert(fts.is_active(ts_index1)); | ||
| for (size_t j = i + 1; j < current_ts_indices.size(); ++j) { | ||
| int ts_index2 = current_ts_indices[j]; | ||
| assert(fts.is_active(ts_index2)); | ||
| merge_candidates.emplace_back(ts_index1, ts_index2); | ||
| // Get the cluster from which we selected the next merge. | ||
| int affected_cluster_index; | ||
| if (allow_working_on_all_clusters) { | ||
| affected_cluster_index = factor_to_cluster[next_pair.first]; | ||
| assert( | ||
| affected_cluster_index == factor_to_cluster[next_pair.second]); | ||
| } else { | ||
| affected_cluster_index = 0; | ||
| } | ||
| } | ||
|
|
||
| // Select the next merge for the current set of indices. | ||
| pair<int, int> next_pair = merge_selector->select_merge_from_candidates( | ||
| fts, move(merge_candidates)); | ||
| // Remove the two merged indices from that cluster. | ||
| vector<int> &affected_cluster = | ||
| unfinished_clusters[affected_cluster_index]; | ||
| for (vector<int>::iterator it = affected_cluster.begin(); | ||
| it != affected_cluster.end();) { | ||
| if (*it == next_pair.first || *it == next_pair.second) { | ||
| it = affected_cluster.erase(it); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I read https://en.cppreference.com/w/cpp/container/vector/erase correctly, this invalidates the iterator it. I doubt a typical implementation would care, but this is probably still invalid C++. I suggest you access the vector with an index instead, i.e., for (size_t i = 0; i < affected_cluster.size(); ).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What exactly do you think is the problem? The parameter
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, I missed the assignment to Now that we require c++20, there is a nice special version of erase_if that just takes a vector and a predicate as an argument and does all the resizing etc. Something like this could replace the for loop and be more efficient as well: erase_if(affected_cluster, [&](int elem) {
return elem == next_pair.first || elem == next_pair.second; });``` |
||
| } else { | ||
| ++it; | ||
| } | ||
| } | ||
|
|
||
| // Remove the two merged indices from the current index set. | ||
| for (vector<int>::iterator it = current_ts_indices.begin(); | ||
| it != current_ts_indices.end();) { | ||
| if (*it == next_pair.first || *it == next_pair.second) { | ||
| it = current_ts_indices.erase(it); | ||
| if (affected_cluster.empty()) { | ||
| // If the cluster got empty, remove it. | ||
| unfinished_clusters.erase( | ||
| unfinished_clusters.begin() + affected_cluster_index); | ||
| } else { | ||
| ++it; | ||
| // Otherwise, add the index of the to-be-created product factor. | ||
| affected_cluster.push_back(fts.get_size()); | ||
| } | ||
| return next_pair; | ||
| } | ||
| return next_pair; | ||
| } | ||
| } | ||
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.
Perhaps simpler: "If false, deal with one cluster at a time."?