Skip to content

Commit ec918bf

Browse files
author
Silvan Sievers
committed
[issue1171] M&S SCC merge strategy: new option to allow working on any SCC
Previously, the merge selector used for selecting pairs of M&S factors only considered one SCC partition after the other. With the new option set to true, it considers the pairs of factors from any cluster of factors that has not been fully merged yet.
1 parent a65bc3d commit ec918bf

8 files changed

Lines changed: 120 additions & 80 deletions

src/search/merge_and_shrink/merge_selector.cc

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,22 @@ using namespace std;
1212

1313
namespace merge_and_shrink {
1414
vector<pair<int, int>> MergeSelector::compute_merge_candidates(
15-
const FactoredTransitionSystem &fts,
16-
const vector<int> &indices_subset) const {
15+
const FactoredTransitionSystem &fts) const {
16+
vector<int> indices;
17+
indices.reserve(fts.get_num_active_entries());
18+
for (int index: fts) {
19+
indices.push_back(index);
20+
}
21+
1722
vector<pair<int, int>> merge_candidates;
18-
if (indices_subset.empty()) {
19-
for (int ts_index1 = 0; ts_index1 < fts.get_size(); ++ts_index1) {
20-
if (fts.is_active(ts_index1)) {
21-
for (int ts_index2 = ts_index1 + 1; ts_index2 < fts.get_size();
22-
++ts_index2) {
23-
if (fts.is_active(ts_index2)) {
24-
merge_candidates.emplace_back(ts_index1, ts_index2);
25-
}
26-
}
27-
}
28-
}
29-
} else {
30-
assert(indices_subset.size() > 1);
31-
for (size_t i = 0; i < indices_subset.size(); ++i) {
32-
int ts_index1 = indices_subset[i];
33-
assert(fts.is_active(ts_index1));
34-
for (size_t j = i + 1; j < indices_subset.size(); ++j) {
35-
int ts_index2 = indices_subset[j];
36-
assert(fts.is_active(ts_index2));
37-
merge_candidates.emplace_back(ts_index1, ts_index2);
38-
}
23+
merge_candidates.reserve(indices.size() * (indices.size() - 1) / 2);
24+
for (size_t i = 0; i < indices.size(); ++i) {
25+
int ts_index1 = indices[i];
26+
assert(fts.is_active(ts_index1));
27+
for (size_t j = i + 1; j < indices.size(); ++j) {
28+
int ts_index2 = indices[j];
29+
assert(fts.is_active(ts_index2));
30+
merge_candidates.emplace_back(ts_index1, ts_index2);
3931
}
4032
}
4133
return merge_candidates;

src/search/merge_and_shrink/merge_selector.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@ class MergeSelector {
1717
virtual std::string name() const = 0;
1818
virtual void dump_selector_specific_options(utils::LogProxy &) const {}
1919
std::vector<std::pair<int, int>> compute_merge_candidates(
20-
const FactoredTransitionSystem &fts,
21-
const std::vector<int> &indices_subset) const;
20+
const FactoredTransitionSystem &fts) const;
2221
public:
2322
MergeSelector() = default;
2423
virtual ~MergeSelector() = default;
2524
virtual std::pair<int, int> select_merge(
2625
const FactoredTransitionSystem &fts,
27-
const std::vector<int> &indices_subset = std::vector<int>()) const = 0;
26+
std::vector<std::pair<int, int>> &&merge_candidates = {}) const = 0;
2827
virtual void initialize(const TaskProxy &task_proxy) = 0;
2928
void dump_options(utils::LogProxy &log) const;
3029
virtual bool requires_init_distances() const = 0;

src/search/merge_and_shrink/merge_selector_score_based_filtering.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ static vector<pair<int, int>> get_remaining_candidates(
3737

3838
pair<int, int> MergeSelectorScoreBasedFiltering::select_merge(
3939
const FactoredTransitionSystem &fts,
40-
const vector<int> &indices_subset) const {
41-
vector<pair<int, int>> merge_candidates =
42-
compute_merge_candidates(fts, indices_subset);
43-
40+
vector<pair<int, int>> &&merge_candidates) const {
41+
if (merge_candidates.empty()) {
42+
merge_candidates = compute_merge_candidates(fts);
43+
}
4444
for (const shared_ptr<MergeScoringFunction> &scoring_function :
4545
merge_scoring_functions) {
4646
vector<double> scores = scoring_function->compute_scores(

src/search/merge_and_shrink/merge_selector_score_based_filtering.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class MergeSelectorScoreBasedFiltering : public MergeSelector {
2222
const std::vector<std::shared_ptr<MergeScoringFunction>> &scoring_functions);
2323
virtual std::pair<int, int> select_merge(
2424
const FactoredTransitionSystem &fts,
25-
const std::vector<int> &indices_subset = std::vector<int>()) const override;
25+
std::vector<std::pair<int, int>> &&merge_candidates = {}) const override;
2626
virtual void initialize(const TaskProxy &task_proxy) override;
2727
virtual bool requires_init_distances() const override;
2828
virtual bool requires_goal_distances() const override;

src/search/merge_and_shrink/merge_strategy_factory_sccs.cc

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ static bool compare_sccs_decreasing(const vector<int> &lhs, const vector<int> &r
3232
MergeStrategyFactorySCCs::MergeStrategyFactorySCCs(
3333
const OrderOfSCCs &order_of_sccs,
3434
const shared_ptr<MergeSelector> &merge_selector,
35+
bool allow_working_on_all_clusters,
3536
utils::Verbosity verbosity)
3637
: MergeStrategyFactory(verbosity),
3738
order_of_sccs(order_of_sccs),
38-
merge_selector(merge_selector) {
39+
merge_selector(merge_selector),
40+
allow_working_on_all_clusters(allow_working_on_all_clusters) {
3941
}
4042

4143
unique_ptr<MergeStrategy> MergeStrategyFactorySCCs::compute_merge_strategy(
@@ -98,7 +100,8 @@ unique_ptr<MergeStrategy> MergeStrategyFactorySCCs::compute_merge_strategy(
98100
return utils::make_unique_ptr<MergeStrategySCCs>(
99101
fts,
100102
merge_selector,
101-
move(non_singleton_cg_sccs));
103+
move(non_singleton_cg_sccs),
104+
allow_working_on_all_clusters);
102105
}
103106

104107
bool MergeStrategyFactorySCCs::requires_init_distances() const {
@@ -155,19 +158,34 @@ class MergeStrategyFactorySCCsFeature
155158
"2016") +
156159
"In a nutshell, it computes the maximal SCCs of the causal graph, "
157160
"obtaining a partitioning of the task's variables. Every such "
158-
"partition is then merged individually, using the specified fallback "
159-
"merge strategy, considering the SCCs in a configurable order. "
160-
"Afterwards, all resulting composite abstractions are merged to form "
161-
"the final abstraction, again using the specified fallback merge "
162-
"strategy and the configurable order of the SCCs.");
161+
"partition is then merged individually, using the score-based merge "
162+
"strategy specified via the merge_selector option. If "
163+
"allow_working_on_all_clusters=true, then all pairs of factors in "
164+
"each partition form the set of candidates scored by the score-based "
165+
"merge strategy. Otherwise, SCC partitions are worked on 'one after "
166+
"the other' in the order specified via 'order_of_sccs', and hence "
167+
"only the pairs of factors of the 'current partition' form the set "
168+
"of candidates. In both cases, once all partitions have been merged, "
169+
"the resulting product factors are merged according to the score-"
170+
"based merge strategy.");
171+
document_note(
172+
"Note regarding allow_working_on_all_clusters",
173+
"The option allow_working_on_all_clusters was not introduced in the "
174+
"original paper, hence to obtain exactly the configurations of that paper, "
175+
"set the option to false.");
163176

164177
add_option<OrderOfSCCs>(
165178
"order_of_sccs",
166-
"how the SCCs should be ordered",
179+
"how the SCCs should be ordered (only relevant if allow_working_on_all_clusters=false)",
167180
"topological");
168181
add_option<shared_ptr<MergeSelector>>(
169182
"merge_selector",
170-
"the fallback merge strategy to use");
183+
"the score-based merge strategy used to merge factors within and across SCCs");
184+
add_option<bool>(
185+
"allow_working_on_all_clusters",
186+
"if true, consider as merge candidates the pairs of factors of all SCCs. If "
187+
"false, fully finish dealing with one cluster at a time.",
188+
"true");
171189
add_merge_strategy_options_to_feature(*this);
172190
}
173191

@@ -176,6 +194,7 @@ class MergeStrategyFactorySCCsFeature
176194
return plugins::make_shared_from_arg_tuples<MergeStrategyFactorySCCs>(
177195
opts.get<OrderOfSCCs>("order_of_sccs"),
178196
opts.get<shared_ptr<MergeSelector>> ("merge_selector"),
197+
opts.get<bool>("allow_working_on_all_clusters"),
179198
get_merge_strategy_arguments_from_options(opts)
180199
);
181200
}

src/search/merge_and_shrink/merge_strategy_factory_sccs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ enum class OrderOfSCCs {
1616
class MergeStrategyFactorySCCs : public MergeStrategyFactory {
1717
OrderOfSCCs order_of_sccs;
1818
std::shared_ptr<MergeSelector> merge_selector;
19+
bool allow_working_on_all_clusters;
1920
protected:
2021
virtual std::string name() const override;
2122
virtual void dump_strategy_specific_options() const override;
2223
public:
2324
MergeStrategyFactorySCCs(
2425
const OrderOfSCCs &order_of_sccs,
2526
const std::shared_ptr<MergeSelector> &merge_selector,
27+
bool allow_working_on_all_clusters,
2628
utils::Verbosity verbosity);
2729
virtual std::unique_ptr<MergeStrategy> compute_merge_strategy(
2830
const TaskProxy &task_proxy,

src/search/merge_and_shrink/merge_strategy_sccs.cc

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
#include "factored_transition_system.h"
44
#include "merge_selector.h"
5-
#include "merge_tree.h"
6-
#include "merge_tree_factory.h"
75
#include "transition_system.h"
86

97
#include <algorithm>
@@ -16,55 +14,85 @@ namespace merge_and_shrink {
1614
MergeStrategySCCs::MergeStrategySCCs(
1715
const FactoredTransitionSystem &fts,
1816
const shared_ptr<MergeSelector> &merge_selector,
19-
vector<vector<int>> &&non_singleton_cg_sccs)
17+
vector<vector<int>> &&unfinished_clusters,
18+
bool allow_working_on_all_clusters)
2019
: MergeStrategy(fts),
2120
merge_selector(merge_selector),
22-
non_singleton_cg_sccs(move(non_singleton_cg_sccs)) {
21+
unfinished_clusters(move(unfinished_clusters)),
22+
allow_working_on_all_clusters(allow_working_on_all_clusters) {
2323
}
2424

2525
MergeStrategySCCs::~MergeStrategySCCs() {
2626
}
2727

28+
static void compute_merge_candidates(
29+
const vector<int> &indices,
30+
vector<pair<int, int>> &merge_candidates) {
31+
for (size_t i = 0; i < indices.size(); ++i) {
32+
int ts_index1 = indices[i];
33+
for (size_t j = i + 1; j < indices.size(); ++j) {
34+
int ts_index2 = indices[j];
35+
merge_candidates.emplace_back(ts_index1, ts_index2);
36+
}
37+
}
38+
}
39+
2840
pair<int, int> MergeStrategySCCs::get_next() {
29-
if (current_ts_indices.empty()) {
30-
/*
31-
We are currently not dealing with merging all factors of an SCC, so
32-
we need to either get the next one or allow merging any existing
33-
factors of the FTS if there is no SCC left.
34-
*/
35-
if (non_singleton_cg_sccs.empty()) {
36-
// We are done dealing with all SCCs, allow merging any factors.
37-
current_ts_indices.reserve(fts.get_num_active_entries());
38-
for (int ts_index: fts) {
39-
current_ts_indices.push_back(ts_index);
41+
if (unfinished_clusters.empty()) {
42+
// We merged all clusters.
43+
return merge_selector->select_merge(fts);
44+
} else {
45+
// There are clusters we still have to deal with.
46+
vector<pair<int, int>> merge_candidates;
47+
vector<int> factor_to_cluster;
48+
if (allow_working_on_all_clusters) {
49+
// Compute merge candidate pairs for each cluster.
50+
factor_to_cluster.resize(fts.get_size(), -1);
51+
for (size_t cluster_index = 0; cluster_index < unfinished_clusters.size(); ++cluster_index) {
52+
const vector<int> &cluster = unfinished_clusters[cluster_index];
53+
for (int factor : cluster) {
54+
factor_to_cluster[factor] = cluster_index;
55+
}
56+
compute_merge_candidates(cluster, merge_candidates);
4057
}
4158
} else {
42-
/*
43-
There is another SCC we have to deal with. Store its factors so
44-
that we merge them over the next iterations.
45-
*/
46-
vector<int> &current_scc = non_singleton_cg_sccs.front();
47-
assert(current_scc.size() > 1);
48-
current_ts_indices = move(current_scc);
49-
non_singleton_cg_sccs.erase(non_singleton_cg_sccs.begin());
59+
// Deal with first cluster.
60+
vector<int> &cluster = unfinished_clusters.front();
61+
compute_merge_candidates(cluster, merge_candidates);
5062
}
51-
} else {
52-
// Add the most recent product to the current index set.
53-
current_ts_indices.push_back(fts.get_size() - 1);
54-
}
5563

56-
// Select the next merge for the current set of indices.
57-
pair<int, int > next_pair = merge_selector->select_merge(fts, current_ts_indices);
64+
// Select the next merge from the allowed merge candidates.
65+
pair<int, int > next_pair = merge_selector->select_merge(
66+
fts, move(merge_candidates));
67+
68+
// Get the cluster from which we selected the next merge.
69+
int affected_cluster_index;
70+
if (allow_working_on_all_clusters) {
71+
affected_cluster_index = factor_to_cluster[next_pair.first];
72+
assert(affected_cluster_index == factor_to_cluster[next_pair.second]);
73+
} else {
74+
affected_cluster_index = 0;
75+
}
76+
77+
// Remove the two merged indices from that cluster.
78+
vector<int> &affected_cluster = unfinished_clusters[affected_cluster_index];
79+
for (vector<int>::iterator it = affected_cluster.begin();
80+
it != affected_cluster.end();) {
81+
if (*it == next_pair.first || *it == next_pair.second) {
82+
it = affected_cluster.erase(it);
83+
} else {
84+
++it;
85+
}
86+
}
5887

59-
// Remove the two merged indices from the current index set.
60-
for (vector<int>::iterator it = current_ts_indices.begin();
61-
it != current_ts_indices.end();) {
62-
if (*it == next_pair.first || *it == next_pair.second) {
63-
it = current_ts_indices.erase(it);
88+
if (affected_cluster.empty()) {
89+
// If the cluster got empty, remove it.
90+
unfinished_clusters.erase(unfinished_clusters.begin() + affected_cluster_index);
6491
} else {
65-
++it;
92+
// Otherwise, add the index of the to-be-created product factor.
93+
affected_cluster.push_back(fts.get_size());
6694
}
95+
return next_pair;
6796
}
68-
return next_pair;
6997
}
7098
}

src/search/merge_and_shrink/merge_strategy_sccs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ namespace merge_and_shrink {
1010
class MergeSelector;
1111
class MergeStrategySCCs : public MergeStrategy {
1212
std::shared_ptr<MergeSelector> merge_selector;
13-
std::vector<std::vector<int>> non_singleton_cg_sccs;
14-
15-
std::vector<int> current_ts_indices;
13+
std::vector<std::vector<int>> unfinished_clusters;
14+
bool allow_working_on_all_clusters;
1615
public:
1716
MergeStrategySCCs(
1817
const FactoredTransitionSystem &fts,
1918
const std::shared_ptr<MergeSelector> &merge_selector,
20-
std::vector<std::vector<int>> &&non_singleton_cg_sccs);
19+
std::vector<std::vector<int>> &&unfinished_clusters,
20+
bool allow_working_on_all_clusters);
2121
virtual ~MergeStrategySCCs() override;
2222
virtual std::pair<int, int> get_next() override;
2323
};

0 commit comments

Comments
 (0)