Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,52 +63,58 @@ class IsomorphicSubgraphScheduler {
static constexpr bool verbose = false;
const HashComputer<vertex_idx_t<Graph_t>>* hash_computer_;
size_t symmetry_ = 4;
size_t min_symmetry_ = 2;
Scheduler<Constr_Graph_t> * bsp_scheduler_;
bool use_max_group_size_ = false;
unsigned max_group_size_ = 0;
bool plot_dot_graphs_ = false;
v_workw_t<Constr_Graph_t> work_threshold_ = 10;
v_workw_t<Constr_Graph_t> critical_path_threshold_ = 10;
double orbit_lock_ratio_ = 0.2;
double orbit_lock_ratio_ = 0.4;
double natural_breaks_count_percentage_ = 0.1;
bool merge_different_node_types = true;
bool allow_use_trimmed_scheduler = true;
bool use_max_bsp = false;
bool use_adaptive_symmetry_threshold = true;

public:

explicit IsomorphicSubgraphScheduler(Scheduler<Constr_Graph_t> & bsp_scheduler)
: hash_computer_(nullptr), symmetry_(4), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}
: hash_computer_(nullptr), bsp_scheduler_(&bsp_scheduler), plot_dot_graphs_(false) {}

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

virtual ~IsomorphicSubgraphScheduler() {}

void setMergeDifferentTypes(bool flag) {merge_different_node_types = flag;}
void setWorkThreshold(v_workw_t<Constr_Graph_t> work_threshold) {work_threshold_ = work_threshold;}
void setCriticalPathThreshold(v_workw_t<Constr_Graph_t> critical_path_threshold) {critical_path_threshold_ = critical_path_threshold;}
void setOrbitLockRatio(double orbit_lock_ratio) {orbit_lock_ratio_ = orbit_lock_ratio;}
void setNaturalBreaksCountPercentage(double natural_breaks_count_percentage) {natural_breaks_count_percentage_ = natural_breaks_count_percentage;}
void setAllowTrimmedScheduler(bool flag) {allow_use_trimmed_scheduler = flag;}
void set_symmetry(size_t symmetry) { symmetry_ = symmetry; }
void setMinSymmetry(size_t min_symmetry) { min_symmetry_ = min_symmetry; }
void set_plot_dot_graphs(bool plot) { plot_dot_graphs_ = plot; }
void disable_use_max_group_size() { use_max_group_size_ = false; }
void setUseMaxBsp(bool flag) { use_max_bsp = flag; }
void enable_use_max_group_size(const unsigned max_group_size) {
use_max_group_size_ = true;
max_group_size_ = max_group_size;
}

void setEnableAdaptiveSymmetryThreshold() { use_adaptive_symmetry_threshold = true; }
void setUseStaticSymmetryLevel(size_t static_symmetry_level) {
use_adaptive_symmetry_threshold = false;
symmetry_ = static_symmetry_level;
}

std::vector<vertex_idx_t<Graph_t>> compute_partition(const BspInstance<Graph_t>& instance) {
OrbitGraphProcessor<Graph_t, Constr_Graph_t> orbit_processor(symmetry_);
OrbitGraphProcessor<Graph_t, Constr_Graph_t> orbit_processor;
orbit_processor.set_work_threshold(work_threshold_);
orbit_processor.setMergeDifferentNodeTypes(merge_different_node_types);
orbit_processor.setCriticalPathThreshold(critical_path_threshold_);
orbit_processor.setLockRatio(orbit_lock_ratio_);
orbit_processor.setMinSymmetry(min_symmetry_);

orbit_processor.setNaturalBreaksCountPercentage(natural_breaks_count_percentage_);
if (not use_adaptive_symmetry_threshold) {
orbit_processor.setUseStaticSymmetryLevel(symmetry_);
}

std::unique_ptr<HashComputer<vertex_idx_t<Graph_t>>> local_hasher;
if (!hash_computer_) {
Expand Down
48 changes: 38 additions & 10 deletions include/osp/dag_divider/isomorphism_divider/OrbitGraphProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ class OrbitGraphProcessor {
std::vector<Group> final_groups_;
size_t current_symmetry;

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

bool use_adaptive_symmetry_threshold_ = true;

struct PairHasher {
template<class T1, class T2>
std::size_t operator()(const std::pair<T1, T2> &p) const {
Expand Down Expand Up @@ -514,20 +515,25 @@ class OrbitGraphProcessor {

public:

explicit OrbitGraphProcessor(size_t symmetry_threshold = 2) : symmetry_threshold_(symmetry_threshold) {}
explicit OrbitGraphProcessor() {}

void set_symmetry_threshold(size_t threshold) { symmetry_threshold_ = threshold; }
void setMergeDifferentNodeTypes(bool flag) { merge_different_node_types_ = flag; }
void set_work_threshold(v_workw_t<Constr_Graph_t> work_threshold) { work_threshold_ = work_threshold; }
void setCriticalPathThreshold(v_workw_t<Constr_Graph_t> critical_path_threshold) { critical_path_threshold_ = critical_path_threshold; }
void setLockRatio(double lock_ratio) { lock_orbit_ratio = lock_ratio; }
void setMinSymmetry(size_t min_symmetry) { min_symmetry_ = min_symmetry; }

void setSymmetryLevelHeuristic(SymmetryLevelHeuristic heuristic) { symmetry_level_heuristic_ = heuristic; }
void setWorkPercentiles(const std::vector<double>& percentiles) {
work_percentiles_ = percentiles;
std::sort(work_percentiles_.begin(), work_percentiles_.end());
}

void setUseStaticSymmetryLevel(size_t static_symmetry_level) {
symmetry_level_heuristic_ = SymmetryLevelHeuristic::NATURAL_BREAKS;
use_adaptive_symmetry_threshold_ = false;
current_symmetry = static_symmetry_level;
}

void setNaturalBreaksCountPercentage(double percentage) { natural_breaks_count_percentage_ = percentage; }


Expand Down Expand Up @@ -568,21 +574,24 @@ class OrbitGraphProcessor {
v_workw_t<Graph_t> total_work = 0;
for (const auto &[hash, vertices] : orbits) {
const size_t orbit_size = vertices.size();

if (orbit_size == 1U) continue; // exclude single node orbits from total work

orbit_size_counts[orbit_size]++;

v_workw_t<Graph_t> orbit_work = 0;
for (const auto v : vertices) {
orbit_work += dag.vertex_work_weight(v);
}

if (not merge_different_node_types_ && has_typed_vertices_v<Graph_t>) {
work_per_vertex_type[dag.vertex_type(vertices[0])] += orbit_work;
} else {
work_per_vertex_type[0] += orbit_work;
}

work_per_orbit_size[orbit_size] += orbit_work;
total_work += orbit_work;
total_work += orbit_work;
}

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

coarser_util::construct_coarse_dag(dag, coarse_graph_, contraction_map_);
perform_coarsening_adaptive_symmetry(dag, coarse_graph_, lock_threshold_per_type, symmetry_levels_to_test);

if (use_adaptive_symmetry_threshold_) {
perform_coarsening_adaptive_symmetry(dag, coarse_graph_, lock_threshold_per_type, symmetry_levels_to_test);
} else {
size_t total_size_count = 0U;
for (const auto& [size, count] : orbit_size_counts) {
total_size_count += count;
}

for (const auto& [size, count] : orbit_size_counts) {
if (size == 1U || size > current_symmetry) continue;

if (count > total_size_count / 2) {
if constexpr (verbose) {
std::cout << "Setting current_symmetry to " << size << " because " << count << " orbits of size " << size << " are more than half of the total number of orbits.\n";
}
current_symmetry = size;
}
}

perform_coarsening(dag, coarse_graph_);
}
}

private:
Expand All @@ -640,9 +670,7 @@ class OrbitGraphProcessor {
if constexpr (verbose) { std::cout << "Using PERCENTILE_BASED heuristic for symmetry levels.\n"; }
size_t percentile_idx = 0;
v_workw_t<Graph_t> cumulative_work = 0;
for (auto it = work_per_orbit_size.rbegin();
it != work_per_orbit_size.rend();
++it)
for (auto it = work_per_orbit_size.rbegin(); it != work_per_orbit_size.rend(); ++it)
{
cumulative_work += it->second;
if (total_work == 0) continue; // Avoid division by zero
Expand Down
3 changes: 1 addition & 2 deletions tests/isomorphic_subgraph_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ BOOST_AUTO_TEST_CASE(TrimSubgraphGroupsTest_WithTrim) {
GreedyBspScheduler<constr_graph_t> greedy_scheduler;
IsomorphicSubgraphSchedulerTester<graph_t, constr_graph_t> tester(greedy_scheduler);
tester.setAllowTrimmedScheduler(false);
tester.set_symmetry(4);
tester.setMinSymmetry(4);


BspInstance<graph_t> instance;
auto& dag = instance.getComputationalDag();
Expand Down
17 changes: 8 additions & 9 deletions tests/orbit_graph_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_SimpleMerge) {

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

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

Expand Down Expand Up @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(OrbitGraphProcessor_PartitionCheck_MediumGraph) {
BOOST_REQUIRE_GT(dag.num_vertices(), 0);

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

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

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

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

OrbitGraphProcessor<graph_t, graph_t> processor(2);
OrbitGraphProcessor<graph_t, graph_t> processor;
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
processor.discover_isomorphic_groups(dag, hasher);

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

OrbitGraphProcessor<graph_t, graph_t> processor(2);
OrbitGraphProcessor<graph_t, graph_t> processor;
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
processor.discover_isomorphic_groups(dag, hasher);

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

OrbitGraphProcessor<graph_t, graph_t> processor(2);
OrbitGraphProcessor<graph_t, graph_t> processor;
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
processor.discover_isomorphic_groups(dag, hasher);

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

OrbitGraphProcessor<graph_t, graph_t> processor(16);
processor.setMinSymmetry(16);
OrbitGraphProcessor<graph_t, graph_t> processor;
MerkleHashComputer<graph_t, bwd_merkle_node_hash_func<graph_t>, true> hasher(dag, dag);
processor.discover_isomorphic_groups(dag, hasher);

Expand Down