@@ -22,6 +22,60 @@ struct RootDecision {
2222 int degree;
2323};
2424
25+ int choose_center (const vector<pair<int , double >>& sorted_multi) {
26+ if (sorted_multi.size () < 2 ) {
27+ return 1 ;
28+ }
29+
30+ vector<double > y;
31+ for (const auto & p : sorted_multi) {
32+ y.push_back (p.second );
33+ }
34+
35+ vector<double > delta;
36+ for (size_t i = 1 ; i < y.size (); ++i) {
37+ delta.push_back (fabs (y[i] - y[i-1 ]));
38+ }
39+
40+ if (delta.empty ()) {
41+ return 1 ;
42+ }
43+
44+ vector<double > delta_nozero;
45+ for (double d : delta) {
46+ if (d != 0 ) {
47+ delta_nozero.push_back (d);
48+ }
49+ }
50+
51+ if (delta_nozero.empty ()) {
52+ return 1 ;
53+ }
54+
55+ double mean = 0 ;
56+ for (double d : delta_nozero) {
57+ mean += d;
58+ }
59+ mean /= delta_nozero.size ();
60+
61+ double variance = 0 ;
62+ for (double d : delta_nozero) {
63+ variance += (d - mean) * (d - mean);
64+ }
65+ variance /= delta_nozero.size ();
66+ double std_dev = sqrt (variance);
67+
68+ double threshold = std_dev + mean;
69+
70+ for (size_t i = 0 ; i < delta.size (); ++i) {
71+ if (delta[i] > threshold) {
72+ return i + 1 ;
73+ }
74+ }
75+
76+ return 0 ;
77+ }
78+
2579py::object cpp_localsearch (
2680 py::object G,
2781 py::object center_num,
@@ -40,6 +94,30 @@ py::object cpp_localsearch(
4094 return py::make_tuple (py::none (), py::list (), py::list (), py::dict (), py::dict (), py::none ());
4195 }
4296
97+ bool has_edges = false ;
98+ for (int u = 1 ; u <= n; ++u) {
99+ if (GL .head [u] != -1 ) {
100+ has_edges = true ;
101+ break ;
102+ }
103+ }
104+ if (!has_edges) {
105+ py::dict result_grouped;
106+ py::list result_center_dcd;
107+ py::list result_y_dcd;
108+ py::dict result_y_partition;
109+ for (int u = 1 ; u <= n; ++u) {
110+ py::object node = id_to_node[py::cast (u)];
111+ py::list members;
112+ members.append (node);
113+ result_grouped[node] = members;
114+ result_center_dcd.append (node);
115+ result_y_dcd.append (node);
116+ result_y_partition[node] = node;
117+ }
118+ return py::make_tuple (py::none (), result_center_dcd, result_y_dcd, result_y_partition, result_grouped, py::none ());
119+ }
120+
43121 std::mt19937 rng (42 );
44122 if (!seed.is_none ()) {
45123 try {
@@ -73,6 +151,7 @@ py::object cpp_localsearch(
73151 unordered_map<int , vector<int >> dag_pred;
74152
75153 for (int v = 1 ; v <= n; ++v) {
154+ if (degree[v] == 0 ) continue ;
76155 int kv = degree[v];
77156 vector<pair<int , int >> neighbors;
78157 for (int e = GL .head [v]; e != -1 ; e = GL .edges [e].next ) {
@@ -125,11 +204,43 @@ py::object cpp_localsearch(
125204
126205 vector<int > roots;
127206 for (int u = 1 ; u <= n; ++u) {
128- if (out_degree_dag[u] == 0 ) {
207+ if (out_degree_dag[u] == 0 && degree[u] > 0 ) {
129208 roots.push_back (u);
130209 }
131210 }
132211
212+ if (roots.empty ()) {
213+ for (int u = 1 ; u <= n; ++u) {
214+ if (degree[u] > 0 ) {
215+ roots.push_back (u);
216+ }
217+ }
218+ }
219+
220+ if (roots.size () > 1 ) {
221+ bool all_same_degree = true ;
222+ int first_degree = -1 ;
223+ for (int root : roots) {
224+ if (first_degree == -1 ) {
225+ first_degree = degree[root];
226+ } else if (degree[root] != first_degree) {
227+ all_same_degree = false ;
228+ break ;
229+ }
230+ }
231+
232+ if (all_same_degree) {
233+ int max_root = -1 ;
234+ for (int root : roots) {
235+ if (root > max_root) {
236+ max_root = root;
237+ }
238+ }
239+ roots.clear ();
240+ roots.push_back (max_root);
241+ }
242+ }
243+
133244 unordered_map<int , int > tree_rootnode;
134245 unordered_map<int , int > tree_parentnode;
135246 unordered_map<int , int > tree_distancetoroot;
@@ -200,30 +311,25 @@ py::object cpp_localsearch(
200311 unordered_set<int > root_set (valid_roots.begin (), valid_roots.end ());
201312 unordered_map<int , RootDecision> root_decision;
202313
203- for (int root : valid_roots) {
314+ auto BFS_from_s = [&] (int s) -> pair< int , int > {
204315 queue<int > search_queue;
205316 unordered_map<int , int > path_dict;
206317 unordered_set<int > seen;
207318
208- search_queue.push (root);
209- seen.insert (root);
210- path_dict[root] = 0 ;
211-
212- int superior = root;
213- int shortest_path = -1 ;
319+ search_queue.push (s);
320+ seen.insert (s);
321+ path_dict[s] = 0 ;
214322
215- while (!search_queue.empty () && shortest_path == - 1 ) {
323+ while (!search_queue.empty ()) {
216324 int vertex = search_queue.front ();
217325 search_queue.pop ();
218326 int current_dist = path_dict[vertex];
219327
220328 vector<pair<int , int >> neighbors;
221329 for (int e = GL .head [vertex]; e != -1 ; e = GL .edges [e].next ) {
222330 int nn = GL .edges [e].to ;
223- if (!seen.count (nn)) {
224- int deg_nn = degree[nn];
225- neighbors.push_back ({nn, deg_nn});
226- }
331+ int deg_nn = degree[nn];
332+ neighbors.push_back ({nn, deg_nn});
227333 }
228334
229335 sort (neighbors.begin (), neighbors.end (),
@@ -239,18 +345,20 @@ py::object cpp_localsearch(
239345 search_queue.push (w);
240346 }
241347
242- if (root_set.count (w) && degree[w] > degree[root]) {
243- superior = w;
244- shortest_path = path_dict[w];
245- break ;
348+ if (root_set.count (w) && degree[w] > degree[s]) {
349+ return {w, path_dict[w]};
246350 }
247351 }
248352 }
249-
250- root_decision[root] = {superior, shortest_path, degree[root]};
353+ return {s, -1 };
354+ };
355+
356+ for (int root : valid_roots) {
357+ auto result = BFS_from_s (root);
358+ root_decision[root] = {result.first , result.second , degree[root]};
251359 }
252360
253- int max_path = 0 ;
361+ int max_path = - 1 ;
254362 for (auto & kv : root_decision) {
255363 if (kv.second .path_length > max_path) {
256364 max_path = kv.second .path_length ;
@@ -266,7 +374,7 @@ py::object cpp_localsearch(
266374
267375 unordered_map<int , RootDecision> node_plot = root_decision;
268376 for (int node = 1 ; node <= n; ++node) {
269- if (node_plot.find (node) == node_plot.end ()) {
377+ if (node_plot.find (node) == node_plot.end () && degree[node] > 0 ) {
270378 int parent = tree_parentnode[node];
271379 node_plot[node] = {parent, 1 , degree[node]};
272380 }
@@ -304,6 +412,8 @@ py::object cpp_localsearch(
304412 degree_rank[p.second ] = rank;
305413 rank++;
306414 last_deg = p.first ;
415+ } else {
416+ degree_rank[p.second ] = rank - 1 ;
307417 }
308418 }
309419
@@ -326,8 +436,20 @@ py::object cpp_localsearch(
326436 unordered_map<int , double > multi_dict;
327437 for (size_t i = 0 ; i < node_ids.size (); ++i) {
328438 int node = node_ids[i];
329- double norm_deg = (double )(degree_rank[node] - min_rank) / rank_range;
330- double norm_sq_path = (square_path[i] - min_sq_path) / sq_range;
439+ double norm_deg, norm_sq_path;
440+
441+ if (max_rank == min_rank) {
442+ norm_deg = 1.0 / (double )node_ids.size ();
443+ } else {
444+ norm_deg = (double )(degree_rank[node] - min_rank) / rank_range;
445+ }
446+
447+ if (max_sq_path == min_sq_path) {
448+ norm_sq_path = 1.0 / (double )node_ids.size ();
449+ } else {
450+ norm_sq_path = (square_path[i] - min_sq_path) / sq_range;
451+ }
452+
331453 multi_dict[node] = norm_deg * norm_sq_path;
332454 }
333455
@@ -338,14 +460,28 @@ py::object cpp_localsearch(
338460 sort (sorted_multi.begin (), sorted_multi.end (),
339461 [](const pair<int , double >& a, const pair<int , double >& b) {
340462 if (fabs (a.second - b.second ) > 1e-9 ) return a.second > b.second ;
341- return a.first < b.first ;
463+ return a.first > b.first ;
342464 });
343465
344466 int num_centers = (int )valid_roots.size ();
345- if (!center_num.is_none ()) {
467+
468+ bool auto_choose = auto_choose_centers.cast <bool >();
469+ if (auto_choose && sorted_multi.size () > 0 ) {
470+ int auto_centernum = choose_center (sorted_multi);
471+ if (!center_num.is_none ()) {
472+ int user_center_num = center_num.cast <int >();
473+ num_centers = (auto_centernum < user_center_num) ? auto_centernum : user_center_num;
474+ } else {
475+ num_centers = auto_centernum;
476+ }
477+ } else if (!center_num.is_none ()) {
346478 num_centers = center_num.cast <int >();
347479 }
348480
481+ if (num_centers <= 0 ) {
482+ num_centers = (int )valid_roots.size ();
483+ }
484+
349485 vector<int > center_dcd;
350486 int local_cnt = 0 ;
351487 for (size_t i = 0 ; i < sorted_multi.size () && local_cnt < num_centers; ++i) {
@@ -355,6 +491,27 @@ py::object cpp_localsearch(
355491 }
356492 }
357493
494+ if (center_dcd.empty () && !sorted_multi.empty ()) {
495+ center_dcd.push_back (sorted_multi[0 ].first );
496+ }
497+
498+ bool all_same_degree = true ;
499+ int first_deg = -1 ;
500+ for (int i = 1 ; i <= n && all_same_degree; ++i) {
501+ if (degree[i] > 0 ) {
502+ if (first_deg == -1 ) {
503+ first_deg = degree[i];
504+ } else if (degree[i] != first_deg) {
505+ all_same_degree = false ;
506+ }
507+ }
508+ }
509+
510+ if (all_same_degree && n > 0 ) {
511+ center_dcd.clear ();
512+ center_dcd.push_back (n);
513+ }
514+
358515 unordered_set<int > center_set (center_dcd.begin (), center_dcd.end ());
359516
360517 for (int node : valid_roots) {
@@ -363,35 +520,40 @@ py::object cpp_localsearch(
363520 tree_rootnode[node] = superior;
364521 }
365522
366- for (int node = 1 ; node <= n; ++node) {
367- if (center_set.count (node)) {
523+ for (int node = 0 ; node < n; ++node) {
524+ if (degree[node] > 0 && center_set.count (node)) {
368525 tree_rootnode[node] = node;
369526 }
370527 }
371528
372- for (int node = 1 ; node <= n; ++node) {
373- int current = node ;
529+ for (int node = 0 ; node < n; ++node) {
530+ if (degree[node] == 0 ) continue ;
374531 vector<int > recent;
375- recent.push_back (current );
532+ recent.push_back (node );
376533 bool flag = false ;
377534
378- while (center_set.find (tree_rootnode[current ]) == center_set.end () && !flag) {
379- int next = tree_rootnode[current ];
380- if (next == -1 || find (recent.begin (), recent.end (), next ) != recent.end ()) {
381- tree_rootnode[current ] = -1 ;
535+ while (center_set.find (tree_rootnode[node ]) == center_set.end () && !flag) {
536+ int j = tree_rootnode[node ];
537+ if (j == -1 || find (recent.begin (), recent.end (), j ) != recent.end ()) {
538+ tree_rootnode[node ] = -1 ;
382539 flag = true ;
383540 break ;
384541 }
385- recent.push_back (next);
386- tree_rootnode[current] = tree_rootnode[next];
387- current = next;
542+ recent.push_back (j);
543+ tree_rootnode[node] = tree_rootnode[j];
388544 }
389545 }
390546
391547 unordered_map<int , int > y_partition;
392548 vector<int > y_dcd;
549+
393550 for (int node = 1 ; node <= n; ++node) {
551+ if (degree[node] == 0 ) continue ;
394552 int root = tree_rootnode[node];
553+ if (root == -1 && !center_dcd.empty ()) {
554+ root = center_dcd[0 ];
555+ tree_rootnode[node] = root;
556+ }
395557 y_partition[node] = root;
396558 if (root == -1 ) {
397559 y_dcd.push_back (-1 );
0 commit comments