1717
1818namespace bioimage_cpp ::graph::multicut::detail {
1919
20+ struct DynamicEdge {
21+ double weight = 0.0 ;
22+ std::uint64_t edition = 0 ;
23+ };
24+
2025struct DynamicGraph {
2126 explicit DynamicGraph (const std::size_t size) : adjacency(size), constraints(size), alive(size, true ), alive_count(size) {
2227 }
2328
29+ explicit DynamicGraph (const UndirectedGraph &graph)
30+ : adjacency(static_cast <std::size_t >(graph.number_of_nodes())),
31+ constraints(static_cast <std::size_t >(graph.number_of_nodes())),
32+ alive(static_cast <std::size_t >(graph.number_of_nodes()), true),
33+ alive_count(static_cast <std::size_t >(graph.number_of_nodes())) {
34+ for (std::uint64_t node = 0 ; node < graph.number_of_nodes (); ++node) {
35+ const auto degree = graph.node_adjacency (node).size ();
36+ adjacency[static_cast <std::size_t >(node)].reserve (degree);
37+ }
38+ }
39+
2440 [[nodiscard]] bool edge_exists (const std::size_t u, const std::size_t v) const {
2541 return alive[u] && alive[v] && adjacency[u].find (v) != adjacency[u].end ();
2642 }
2743
44+ [[nodiscard]] const DynamicEdge *edge (const std::size_t u, const std::size_t v) const {
45+ if (!alive[u] || !alive[v]) {
46+ return nullptr ;
47+ }
48+ const auto found = adjacency[u].find (v);
49+ return found == adjacency[u].end () ? nullptr : &found->second ;
50+ }
51+
2852 [[nodiscard]] bool has_constraint (const std::size_t u, const std::size_t v) const {
2953 return constraints[u].find (v) != constraints[u].end ();
3054 }
@@ -34,9 +58,17 @@ struct DynamicGraph {
3458 constraints[v].insert (u);
3559 }
3660
37- void set_edge (const std::size_t u, const std::size_t v, const double weight) {
38- adjacency[u][v] = weight;
39- adjacency[v][u] = weight;
61+ void set_initial_edge (const std::size_t u, const std::size_t v, const double weight) {
62+ adjacency[u][v] = DynamicEdge{weight, 0 };
63+ adjacency[v][u] = DynamicEdge{weight, 0 };
64+ }
65+
66+ std::uint64_t update_edge (const std::size_t u, const std::size_t v, const double weight) {
67+ const auto current = adjacency[u].find (v);
68+ const auto edition = current == adjacency[u].end () ? 0 : current->second .edition + 1 ;
69+ adjacency[u][v] = DynamicEdge{weight, edition};
70+ adjacency[v][u] = DynamicEdge{weight, edition};
71+ return edition;
4072 }
4173
4274 void remove_node (const std::size_t node) {
@@ -50,7 +82,7 @@ struct DynamicGraph {
5082 --alive_count;
5183 }
5284
53- std::vector<std::unordered_map<std::size_t , double >> adjacency;
85+ std::vector<std::unordered_map<std::size_t , DynamicEdge >> adjacency;
5486 std::vector<std::unordered_set<std::size_t >> constraints;
5587 std::vector<bool > alive;
5688 std::size_t alive_count;
@@ -71,7 +103,6 @@ inline void initialize_dynamic_graph(
71103 const UndirectedGraph &graph,
72104 const std::vector<double > &costs,
73105 DynamicGraph &dynamic_graph,
74- std::vector<std::unordered_map<std::size_t , std::uint64_t >> &editions,
75106 std::priority_queue<QueueEdge> &queue,
76107 const bool absolute_priority,
77108 const bool add_noise = false ,
@@ -88,9 +119,7 @@ inline void initialize_dynamic_graph(
88119 if (add_noise) {
89120 weight += noise (generator);
90121 }
91- dynamic_graph.set_edge (u, v, weight);
92- editions[u][v] = 0 ;
93- editions[v][u] = 0 ;
122+ dynamic_graph.set_initial_edge (u, v, weight);
94123 queue.push (QueueEdge{u, v, absolute_priority ? std::abs (weight) : weight, 0 });
95124 }
96125}
@@ -108,7 +137,6 @@ inline std::size_t stop_node_count(const UndirectedGraph &graph, const double no
108137inline std::size_t merge_dynamic_nodes (
109138 DynamicGraph &dynamic_graph,
110139 UnionFind &sets,
111- std::vector<std::unordered_map<std::size_t , std::uint64_t >> &editions,
112140 std::priority_queue<QueueEdge> &queue,
113141 std::size_t u,
114142 std::size_t v,
@@ -119,28 +147,28 @@ inline std::size_t merge_dynamic_nodes(
119147 if (u == v) {
120148 return u;
121149 }
122- sets.merge (u, v);
123- const auto stable = static_cast <std::size_t >(sets.find (u));
124- const auto removed = (stable == u) ? v : u;
125- std::vector<std::pair<std::size_t , double >> neighbors (
150+ auto stable = u;
151+ auto removed = v;
152+ if (dynamic_graph.adjacency [stable].size () < dynamic_graph.adjacency [removed].size ()) {
153+ std::swap (stable, removed);
154+ }
155+ sets.merge_to (stable, removed);
156+ std::vector<std::pair<std::size_t , DynamicEdge>> neighbors (
126157 dynamic_graph.adjacency [removed].begin (),
127158 dynamic_graph.adjacency [removed].end ()
128159 );
129160 dynamic_graph.adjacency [stable].erase (removed);
130161 dynamic_graph.constraints [stable].erase (removed);
131- for (const auto &[neighbor, removed_weight ] : neighbors) {
162+ for (const auto &[neighbor, removed_edge ] : neighbors) {
132163 if (neighbor == stable) {
133164 continue ;
134165 }
135- const auto current = dynamic_graph.edge_exists (stable, neighbor)
136- ? dynamic_graph.adjacency [stable][neighbor]
137- : 0.0 ;
138- const auto merged_weight = current + removed_weight;
166+ const auto current = dynamic_graph.edge (stable, neighbor);
167+ const auto merged_weight = (current == nullptr ? 0.0 : current->weight ) + removed_edge.weight ;
139168 if (dynamic_graph.has_constraint (removed, neighbor)) {
140169 dynamic_graph.add_constraint (stable, neighbor);
141170 }
142- dynamic_graph.set_edge (stable, neighbor, merged_weight);
143- const auto edition = ++editions[std::min (stable, neighbor)][std::max (stable, neighbor)];
171+ const auto edition = dynamic_graph.update_edge (stable, neighbor, merged_weight);
144172 queue.push (QueueEdge{
145173 std::min (stable, neighbor),
146174 std::max (stable, neighbor),
0 commit comments