Skip to content

Commit 22aa075

Browse files
authored
orbit processor symmetry revision (#54)
1 parent 6194d70 commit 22aa075

File tree

4 files changed

+63
-31
lines changed

4 files changed

+63
-31
lines changed

include/osp/dag_divider/isomorphism_divider/IsomorphicSubgraphScheduler.hpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,52 +63,58 @@ class IsomorphicSubgraphScheduler {
6363
static constexpr bool verbose = false;
6464
const HashComputer<vertex_idx_t<Graph_t>>* hash_computer_;
6565
size_t symmetry_ = 4;
66-
size_t min_symmetry_ = 2;
6766
Scheduler<Constr_Graph_t> * bsp_scheduler_;
6867
bool use_max_group_size_ = false;
6968
unsigned max_group_size_ = 0;
7069
bool plot_dot_graphs_ = false;
7170
v_workw_t<Constr_Graph_t> work_threshold_ = 10;
7271
v_workw_t<Constr_Graph_t> critical_path_threshold_ = 10;
73-
double orbit_lock_ratio_ = 0.2;
72+
double orbit_lock_ratio_ = 0.4;
73+
double natural_breaks_count_percentage_ = 0.1;
7474
bool merge_different_node_types = true;
7575
bool allow_use_trimmed_scheduler = true;
7676
bool use_max_bsp = false;
77+
bool use_adaptive_symmetry_threshold = true;
7778

7879
public:
7980

8081
explicit IsomorphicSubgraphScheduler(Scheduler<Constr_Graph_t> & bsp_scheduler)
81-
: hash_computer_(nullptr), symmetry_(4), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}
82+
: hash_computer_(nullptr), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}
8283

8384
IsomorphicSubgraphScheduler(Scheduler<Constr_Graph_t> & bsp_scheduler, const HashComputer<vertex_idx_t<Graph_t>>& hash_computer)
84-
: hash_computer_(&hash_computer), symmetry_(4), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}
85+
: hash_computer_(&hash_computer), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}
8586

8687
virtual ~IsomorphicSubgraphScheduler() {}
8788

8889
void setMergeDifferentTypes(bool flag) {merge_different_node_types = flag;}
8990
void setWorkThreshold(v_workw_t<Constr_Graph_t> work_threshold) {work_threshold_ = work_threshold;}
9091
void setCriticalPathThreshold(v_workw_t<Constr_Graph_t> critical_path_threshold) {critical_path_threshold_ = critical_path_threshold;}
9192
void setOrbitLockRatio(double orbit_lock_ratio) {orbit_lock_ratio_ = orbit_lock_ratio;}
93+
void setNaturalBreaksCountPercentage(double natural_breaks_count_percentage) {natural_breaks_count_percentage_ = natural_breaks_count_percentage;}
9294
void setAllowTrimmedScheduler(bool flag) {allow_use_trimmed_scheduler = flag;}
93-
void set_symmetry(size_t symmetry) { symmetry_ = symmetry; }
94-
void setMinSymmetry(size_t min_symmetry) { min_symmetry_ = min_symmetry; }
9595
void set_plot_dot_graphs(bool plot) { plot_dot_graphs_ = plot; }
9696
void disable_use_max_group_size() { use_max_group_size_ = false; }
9797
void setUseMaxBsp(bool flag) { use_max_bsp = flag; }
9898
void enable_use_max_group_size(const unsigned max_group_size) {
9999
use_max_group_size_ = true;
100100
max_group_size_ = max_group_size;
101101
}
102-
102+
void setEnableAdaptiveSymmetryThreshold() { use_adaptive_symmetry_threshold = true; }
103+
void setUseStaticSymmetryLevel(size_t static_symmetry_level) {
104+
use_adaptive_symmetry_threshold = false;
105+
symmetry_ = static_symmetry_level;
106+
}
103107

104108
std::vector<vertex_idx_t<Graph_t>> compute_partition(const BspInstance<Graph_t>& instance) {
105-
OrbitGraphProcessor<Graph_t, Constr_Graph_t> orbit_processor(symmetry_);
109+
OrbitGraphProcessor<Graph_t, Constr_Graph_t> orbit_processor;
106110
orbit_processor.set_work_threshold(work_threshold_);
107111
orbit_processor.setMergeDifferentNodeTypes(merge_different_node_types);
108112
orbit_processor.setCriticalPathThreshold(critical_path_threshold_);
109113
orbit_processor.setLockRatio(orbit_lock_ratio_);
110-
orbit_processor.setMinSymmetry(min_symmetry_);
111-
114+
orbit_processor.setNaturalBreaksCountPercentage(natural_breaks_count_percentage_);
115+
if (not use_adaptive_symmetry_threshold) {
116+
orbit_processor.setUseStaticSymmetryLevel(symmetry_);
117+
}
112118

113119
std::unique_ptr<HashComputer<vertex_idx_t<Graph_t>>> local_hasher;
114120
if (!hash_computer_) {

include/osp/dag_divider/isomorphism_divider/OrbitGraphProcessor.hpp

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ class OrbitGraphProcessor {
9494
std::vector<Group> final_groups_;
9595
size_t current_symmetry;
9696

97-
size_t symmetry_threshold_ = 8; // max symmetry threshold
9897
size_t min_symmetry_ = 2; // min symmetry threshold
9998
v_workw_t<Constr_Graph_t> work_threshold_ = 0;
10099
v_workw_t<Constr_Graph_t> critical_path_threshold_ = 0;
@@ -105,6 +104,8 @@ class OrbitGraphProcessor {
105104
std::vector<double> work_percentiles_ = {0.50, 0.75};
106105
double natural_breaks_count_percentage_ = 0.2;
107106

107+
bool use_adaptive_symmetry_threshold_ = true;
108+
108109
struct PairHasher {
109110
template<class T1, class T2>
110111
std::size_t operator()(const std::pair<T1, T2> &p) const {
@@ -514,20 +515,25 @@ class OrbitGraphProcessor {
514515

515516
public:
516517

517-
explicit OrbitGraphProcessor(size_t symmetry_threshold = 2) : symmetry_threshold_(symmetry_threshold) {}
518+
explicit OrbitGraphProcessor() {}
518519

519-
void set_symmetry_threshold(size_t threshold) { symmetry_threshold_ = threshold; }
520520
void setMergeDifferentNodeTypes(bool flag) { merge_different_node_types_ = flag; }
521521
void set_work_threshold(v_workw_t<Constr_Graph_t> work_threshold) { work_threshold_ = work_threshold; }
522522
void setCriticalPathThreshold(v_workw_t<Constr_Graph_t> critical_path_threshold) { critical_path_threshold_ = critical_path_threshold; }
523523
void setLockRatio(double lock_ratio) { lock_orbit_ratio = lock_ratio; }
524-
void setMinSymmetry(size_t min_symmetry) { min_symmetry_ = min_symmetry; }
524+
525525
void setSymmetryLevelHeuristic(SymmetryLevelHeuristic heuristic) { symmetry_level_heuristic_ = heuristic; }
526526
void setWorkPercentiles(const std::vector<double>& percentiles) {
527527
work_percentiles_ = percentiles;
528528
std::sort(work_percentiles_.begin(), work_percentiles_.end());
529529
}
530530

531+
void setUseStaticSymmetryLevel(size_t static_symmetry_level) {
532+
symmetry_level_heuristic_ = SymmetryLevelHeuristic::NATURAL_BREAKS;
533+
use_adaptive_symmetry_threshold_ = false;
534+
current_symmetry = static_symmetry_level;
535+
}
536+
531537
void setNaturalBreaksCountPercentage(double percentage) { natural_breaks_count_percentage_ = percentage; }
532538

533539

@@ -568,21 +574,24 @@ class OrbitGraphProcessor {
568574
v_workw_t<Graph_t> total_work = 0;
569575
for (const auto &[hash, vertices] : orbits) {
570576
const size_t orbit_size = vertices.size();
577+
578+
if (orbit_size == 1U) continue; // exclude single node orbits from total work
579+
571580
orbit_size_counts[orbit_size]++;
572581

573582
v_workw_t<Graph_t> orbit_work = 0;
574583
for (const auto v : vertices) {
575584
orbit_work += dag.vertex_work_weight(v);
576585
}
577-
586+
578587
if (not merge_different_node_types_ && has_typed_vertices_v<Graph_t>) {
579588
work_per_vertex_type[dag.vertex_type(vertices[0])] += orbit_work;
580589
} else {
581590
work_per_vertex_type[0] += orbit_work;
582591
}
583592

584593
work_per_orbit_size[orbit_size] += orbit_work;
585-
total_work += orbit_work;
594+
total_work += orbit_work;
586595
}
587596

588597
std::vector<v_workw_t<Graph_t>> lock_threshold_per_type(work_per_vertex_type.size());
@@ -624,7 +633,28 @@ class OrbitGraphProcessor {
624633
}
625634

626635
coarser_util::construct_coarse_dag(dag, coarse_graph_, contraction_map_);
627-
perform_coarsening_adaptive_symmetry(dag, coarse_graph_, lock_threshold_per_type, symmetry_levels_to_test);
636+
637+
if (use_adaptive_symmetry_threshold_) {
638+
perform_coarsening_adaptive_symmetry(dag, coarse_graph_, lock_threshold_per_type, symmetry_levels_to_test);
639+
} else {
640+
size_t total_size_count = 0U;
641+
for (const auto& [size, count] : orbit_size_counts) {
642+
total_size_count += count;
643+
}
644+
645+
for (const auto& [size, count] : orbit_size_counts) {
646+
if (size == 1U || size > current_symmetry) continue;
647+
648+
if (count > total_size_count / 2) {
649+
if constexpr (verbose) {
650+
std::cout << "Setting current_symmetry to " << size << " because " << count << " orbits of size " << size << " are more than half of the total number of orbits.\n";
651+
}
652+
current_symmetry = size;
653+
}
654+
}
655+
656+
perform_coarsening(dag, coarse_graph_);
657+
}
628658
}
629659

630660
private:
@@ -640,9 +670,7 @@ class OrbitGraphProcessor {
640670
if constexpr (verbose) { std::cout << "Using PERCENTILE_BASED heuristic for symmetry levels.\n"; }
641671
size_t percentile_idx = 0;
642672
v_workw_t<Graph_t> cumulative_work = 0;
643-
for (auto it = work_per_orbit_size.rbegin();
644-
it != work_per_orbit_size.rend();
645-
++it)
673+
for (auto it = work_per_orbit_size.rbegin(); it != work_per_orbit_size.rend(); ++it)
646674
{
647675
cumulative_work += it->second;
648676
if (total_work == 0) continue; // Avoid division by zero

tests/isomorphic_subgraph_scheduler.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ BOOST_AUTO_TEST_CASE(TrimSubgraphGroupsTest_WithTrim) {
9898
GreedyBspScheduler<constr_graph_t> greedy_scheduler;
9999
IsomorphicSubgraphSchedulerTester<graph_t, constr_graph_t> tester(greedy_scheduler);
100100
tester.setAllowTrimmedScheduler(false);
101-
tester.set_symmetry(4);
102-
tester.setMinSymmetry(4);
101+
103102

104103
BspInstance<graph_t> instance;
105104
auto& dag = instance.getComputationalDag();

tests/orbit_graph_processor.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_SimpleMerge) {
120120

121121
// Initial orbits: {0, 2} and {1, 3}. Coarse graph: 0 -> 1
122122
// With threshold 2, these should be merged.
123-
OrbitGraphProcessor<graph_t, graph_t> processor(2);
123+
OrbitGraphProcessor<graph_t, graph_t> processor;
124124
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
125125
processor.discover_isomorphic_groups(dag, hasher);
126126

@@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_ForkJoinNoMerge) {
158158
// Initial orbits: {0}, {1,2}, {3}. Coarse graph: 0 -> 1 -> 2
159159
// Merging 0 and 1 would result in a group of size 1 ({0,1,2}), which is not viable (threshold 2).
160160
// Merging 1 and 2 would also result in a group of size 1 ({1,2,3}), not viable.
161-
OrbitGraphProcessor<graph_t, graph_t> processor(2);
161+
OrbitGraphProcessor<graph_t, graph_t> processor;
162162
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
163163
processor.discover_isomorphic_groups(dag, hasher);
164164

@@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_PartitionCheck_MediumGraph) {
193193
BOOST_REQUIRE_GT(dag.num_vertices(), 0);
194194

195195
// Use a higher threshold to encourage more merging on this larger graph
196-
OrbitGraphProcessor<graph_t, graph_t> processor(4);
196+
OrbitGraphProcessor<graph_t, graph_t> processor;
197197
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
198198
processor.discover_isomorphic_groups(dag, hasher);
199199

@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_MultiPipelineMerge) {
208208
const auto dag = construct_multi_pipeline_dag<graph_t>(5, 4);
209209
BOOST_REQUIRE_EQUAL(dag.num_vertices(), 20);
210210

211-
OrbitGraphProcessor<graph_t, graph_t> processor(5); // Set threshold to match pipeline count
211+
OrbitGraphProcessor<graph_t, graph_t> processor; // Set threshold to match pipeline count
212212
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
213213
processor.discover_isomorphic_groups(dag, hasher);
214214

@@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_LadderNoMerge) {
236236
const auto dag = construct_ladder_dag<graph_t>(10);
237237
BOOST_REQUIRE_EQUAL(dag.num_vertices(), 22);
238238

239-
OrbitGraphProcessor<graph_t, graph_t> processor(2);
239+
OrbitGraphProcessor<graph_t, graph_t> processor;
240240
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
241241
processor.discover_isomorphic_groups(dag, hasher);
242242

@@ -256,7 +256,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_AsymmetricNoMerge) {
256256
const auto dag = construct_asymmetric_dag<graph_t>(30);
257257
BOOST_REQUIRE_EQUAL(dag.num_vertices(), 30);
258258

259-
OrbitGraphProcessor<graph_t, graph_t> processor(2);
259+
OrbitGraphProcessor<graph_t, graph_t> processor;
260260
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
261261
processor.discover_isomorphic_groups(dag, hasher);
262262

@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_BinaryTreeNoMerge) {
278278
const auto dag = construct_binary_out_tree<graph_t>(4);
279279
BOOST_REQUIRE_EQUAL(dag.num_vertices(), (1 << 5) - 1);
280280

281-
OrbitGraphProcessor<graph_t, graph_t> processor(2);
281+
OrbitGraphProcessor<graph_t, graph_t> processor;
282282
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
283283
processor.discover_isomorphic_groups(dag, hasher);
284284

@@ -293,8 +293,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_ButterflyMerge) {
293293
const auto dag = construct_butterfly_dag<graph_t>(3);
294294
BOOST_REQUIRE_EQUAL(dag.num_vertices(), (3 + 1) * 8);
295295

296-
OrbitGraphProcessor<graph_t, graph_t> processor(16);
297-
processor.setMinSymmetry(16);
296+
OrbitGraphProcessor<graph_t, graph_t> processor;
298297
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
299298
processor.discover_isomorphic_groups(dag, hasher);
300299

0 commit comments

Comments
 (0)