8#define SASSY_VERSION_MAJOR 2
9#define SASSY_VERSION_MINOR 0
23 static preprocessor* save_preprocessor;
37 enum preop { deg01, deg2ue, deg2ma, qcedgeflip, densify2, twins };
51 bool layers_melded =
false;
53 bool skipped_preprocessing =
false;
58 std::vector<std::vector<int>> translation_layers;
59 std::vector<std::vector<int>> backward_translation_layers;
61 std::vector<int> backward_translation;
62 std::vector<std::vector<int>> recovery_strings;
64 std::vector<std::pair<int, int>> baked_recovery_string_pt;
65 std::vector<int> baked_recovery_string;
67 std::vector<std::vector<int>> add_edge_buff;
75 std::vector<int> g_old_v;
76 std::vector<int> g_old_e;
79 std::vector<int> translate_layer_fwd;
80 std::vector<int> translate_layer_bwd;
82 int edge_attached_information = 0;
83 std::vector<int> recovery_edge_attached;
84 std::vector<std::vector<std::tuple<int,int,int>>> recovery_edge_adjacent;
88 std::vector<int> save_colmap;
93 int current_component = 0;
95 bool ir_quotient_component_init =
false;
113 const int layers =
static_cast<int>(translation_layers.size());
114 for (
int l = layers - 1; l >= 0; --l) {
115 v = backward_translation_layers[l][v];
126 decomposer = new_decomposer;
127 current_component = component;
132 void meld_translation_layers() {
135 const int layers =
static_cast<int>(translation_layers.size());
137 backward_translation_layers.emplace_back();
138 backward_translation_layers[0].reserve(
domain_size);
140 backward_translation_layers[0].push_back(i);
142 layers_melded =
true;
147 const int reduced_size =
static_cast<int>(backward_translation_layers[layers - 1].size());
148 backward_translation.reserve(reduced_size);
149 for (
int i = 0; i < reduced_size; ++i) backward_translation.push_back(i);
150 for (
int i = 0; i < reduced_size; ++i) {
152 for (
int l = layers - 1; l >= 0; --l) {
153 next_v = backward_translation_layers[l][next_v];
155 backward_translation[i] = next_v;
157 layers_melded =
true;
162 for (
int i = 0; i < reduced_size; ++i) {
163 const int orig_i = backward_translation[i];
164 const int pt_start =
static_cast<int>(baked_recovery_string.size());
165 for(
auto v : recovery_strings[orig_i]) baked_recovery_string.push_back(v);
166 const int pt_end =
static_cast<int>(baked_recovery_string.size());
167 baked_recovery_string_pt.emplace_back(pt_start, pt_end);
169 recovery_strings.clear();
174 copy_coloring_to_colmap(&c, colmap);
179 workset_t<int> neighbours(g->
v_size);
180 workspace scratch(2*g->
v_size);
182 int removed_twins = 0;
184 for(
int refine_with_v = 0; refine_with_v < g->
v_size; ++refine_with_v) {
185 const int start_pt = g->
v[refine_with_v];
186 const int end_pt = start_pt + g->
d[refine_with_v];
188 neighbour_colors.reset();
191 for(
int j = start_pt; j < end_pt; ++j) {
192 const int neighbour = g->
e[j];
196 if (c.
ptn[neighbour_col] == 0)
continue;
198 if(neighbours.get(neighbour_col) == -1) {
199 neighbour_colors.push_back(neighbour_col);
201 neighbours.set(neighbour_col, 0);
206 scratch[2*neighbour_col + neighbours.get(neighbour_col)] = neighbour;
207 neighbours.inc_nr(neighbour_col);
212 const int neighbour = refine_with_v;
216 if (c.
ptn[neighbour_col] > 0) {
217 if (neighbours.get(neighbour_col) == -1) {
218 neighbour_colors.push_back(neighbour_col);
220 neighbours.set(neighbour_col, 0);
223 dej_assert(2 * neighbour_col + neighbours.get(neighbour_col) < 2 * g->
v_size);
224 scratch[2 * neighbour_col + neighbours.get(neighbour_col)] = neighbour;
225 neighbours.inc_nr(neighbour_col);
229 for(
int j = 0; j < neighbour_colors.cur_pos; ++j) {
230 const int deg0_col = neighbour_colors[j];
231 const int deg1_col_sz = neighbours.get(deg0_col);
232 const int deg0_col_sz = (c.
ptn[deg0_col] + 1) - deg1_col_sz;
233 const int deg1_col = deg0_col + deg0_col_sz;
239 if (deg0_col == deg1_col) {
240 neighbours.set(deg0_col, -1);
249 c.
ptn[deg0_col] = deg0_col_sz - 1;
250 c.
ptn[deg1_col] = deg1_col_sz - 1;
251 c.
ptn[deg1_col - 1] = 0;
253 int deg1_write_pos = deg1_col;
254 int deg1_read_pos = 2*deg0_col + neighbours.get(deg0_col) - 1;
259 while (deg1_read_pos >= 2*deg0_col) {
261 const int v = scratch[deg1_read_pos];
262 const int vertex_at_pos = c.
lab[deg1_write_pos];
265 c.
lab[deg1_write_pos] = v;
269 c.
lab[lab_pos] = vertex_at_pos;
276 dej_assert(deg1_write_pos == deg1_col + deg1_col_sz);
281 neighbours.set(deg0_col, -1);
287 for(
int i = 0; i < g->
v_size;) {
288 const int twin_class = i;
289 const int twin_class_sz = c.
ptn[twin_class] + 1;
292 if(twin_class_sz > 1) {
293 const int remaining_vertex = c.
lab[twin_class];
294 const int orig_remaining_vertex =
translate_back(remaining_vertex);
295 int group_size_calculation = 2;
298 for (
int j = twin_class + 1; j < twin_class + twin_class_sz; ++j) {
299 const int vertex = c.
lab[j];
303 ++group_size_calculation;
306 _automorphism[vertex] = remaining_vertex;
307 _automorphism[remaining_vertex] = vertex;
309 dej_assert(colmap[vertex] == colmap[remaining_vertex]);
312 _automorphism_supp.
push_back(remaining_vertex);
319 _automorphism_supp.
reset();
322 for (
int j = twin_class + 1; j < twin_class + twin_class_sz; ++j) {
323 const int vertex = c.
lab[j];
327 recovery_strings[orig_remaining_vertex].push_back(orig_other);
328 for (
int k = 0; k < static_cast<int>(recovery_strings[orig_other].size()); ++k) {
329 recovery_strings[orig_remaining_vertex].push_back(recovery_strings[orig_other][k]);
338 colmap[remaining_vertex] = colmap[remaining_vertex] + (twin_class_sz-1);
342 return removed_twins;
350 std::vector<int> add_to_string;
358 std::vector<int> potential_twin_list;
362 int d_limit = std::max(
static_cast<int>(sqrt(sqrt(g->
v_size))), 8);
365 for(
int i = 0; i < g->
v_size; ++i) twin_counter[i] = 0;
367 for(
int i = 0; i < g->
v_size;) {
369 const int color_size = c.
ptn[color] + 1;
372 for(
int j = 0; j < color_size; ++j) {
373 if(j == 2 && s_twins == 0)
break;
374 const int vertex = c.
lab[color + j];
375 if(g->
d[vertex] > d_limit)
break;
378 int twin_class_sz = 1;
380 bool limit_breached =
false;
382 add_to_string.clear();
383 if(del.
get(vertex))
continue;
385 potential_twin.reset();
386 potential_twin_list.clear();
387 for(
int k = 0; k < g->
d[vertex]; ++k) {
388 const int neighbour = g->
e[g->
v[vertex] + k];
389 test_twin.set(neighbour);
390 if(g->
d[neighbour] > d_limit) {
391 limit_breached =
true;
394 for(
int l = 0; l < g->
d[neighbour]; ++l) {
395 const int neighbour_neighbour = g->
e[g->
v[neighbour] + l];
396 if(touched.get(neighbour_neighbour))
continue;
397 if(potential_twin.get(neighbour_neighbour)) {
398 potential_twin_counter[neighbour_neighbour] += 1;
400 potential_twin.set(neighbour_neighbour);
401 potential_twin_counter[neighbour_neighbour] = 1;
402 potential_twin_list.push_back(neighbour_neighbour);
406 if(limit_breached)
break;
409 for(
int other_vertex : potential_twin_list) {
412 if(potential_twin_counter[other_vertex] < g->
d[vertex] - 1)
continue;
413 if(vertex == other_vertex || del.
get(other_vertex) ||
416 for(
int k = 0; k < g->
d[other_vertex]; ++k) {
417 const int neighbour = g->
e[g->
v[other_vertex] + k];
418 if(neighbour == vertex)
continue;
419 if(!test_twin.get(neighbour)) {
427 ++twin_counter[vertex];
431 del.
set(other_vertex);
432 add_to_string.push_back(other_vertex);
434 _automorphism[vertex] = other_vertex;
435 _automorphism[other_vertex] = vertex;
437 _automorphism_supp.
push_back(other_vertex);
444 _automorphism_supp.
reset();
449 dej_assert(twin_class_sz -1 ==
static_cast<int>(add_to_string.size()));
450 dej_assert(twin_counter[vertex] ==
static_cast<int>(add_to_string.size()));
452 for(
auto& other_vertex : add_to_string) {
455 dej_assert(
static_cast<int>(recovery_strings[orig_vertex].size()) ==
456 static_cast<int>(recovery_strings[orig_other].size()));
457 recovery_strings[orig_vertex].push_back(orig_other);
458 for(
int k = 0; k < static_cast<int>(recovery_strings[orig_other].size()); ++k) {
459 recovery_strings[orig_vertex].push_back(recovery_strings[orig_other][k]);
464 add_to_string.clear();
465 for(
int j = 0; j < color_size; ++j) {
466 const int vertex = c.
lab[color + j];
467 if(!del.
get(vertex)) {
468 dej_assert(colmap[vertex] + twin_counter[vertex] < color + color_size);
469 colmap[vertex] = color + twin_counter[vertex];
470 add_to_string.push_back(vertex);
479 static void reset_automorphism(
int *rautomorphism,
int nsupp,
const int *supp) {
480 for (
int i = 0; i < nsupp; ++i) {
481 rautomorphism[supp[i]] = supp[i];
487 if(g->
d[vert1] < g->
d[vert2]) {
488 for(
int i = 0; i < g->
d[vert1]; ++i) {
489 if(g->
e[g->
v[vert1] + i] == vert2)
494 for(
int i = 0; i < g->
d[vert2]; ++i) {
495 if(g->
e[g->
v[vert2] + i] == vert1)
512 assure_ir_quotient_init(g);
514 touched_color_cache.
reset();
516 worklist_deg0.
reset();
517 worklist_deg1.
reset();
519 for (
int i = 0; i < g->
v_size; ++i) {
524 add_edge_buff_act.
reset();
529 for (
int i = 0; i < g->
v_size;) {
530 const int test_v = c.
lab[i];
531 const int path_col_sz = c.
ptn[i];
532 if (g->
d[test_v] == 2) {
533 const int n1 = g->
e[g->
v[test_v] + 0];
534 const int n2 = g->
e[g->
v[test_v] + 1];
535 if (g->
d[n1] != 2 && g->
d[n2] != 2) {
543 if (col_sz_n1 != col_sz_n2 || col_sz_n1 != path_col_sz || col_n1 == col_n2) {
548 bool already_matched_n1_n2 =
false;
550 const int already_match_pt1 = g->
v[c.
lab[col_n1]];
551 const int already_match_pt2 = g->
v[c.
lab[col_n2]];
553 if (touched_color_cache.
get(col_n1) && touched_color_cache.
get(col_n2)) {
554 for (
int j = 0; j < worklist_deg0[col_n1]; ++j) {
555 if (edge_scratch[already_match_pt1 + j] == col_n2)
556 already_matched_n1_n2 =
true;
560 if (touched_color_cache.
get(col_n1) && touched_color_cache.
get(col_n2) &&
561 already_matched_n1_n2 && worklist_deg0[col_n1] == 1 && worklist_deg0[col_n2] == 1) {
568 bool check_if_match =
true;
569 for (
int f = 0; f < c.
ptn[i] + 1; ++f) {
570 const int _test_v = c.
lab[i + f];
571 const int _n1 = g->
e[g->
v[_test_v] + 0];
572 const int _n2 = g->
e[g->
v[_test_v] + 1];
573 check_if_match = check_if_match && (worklist_deg1[_n1] == _n2);
578 if (check_if_match) {
579 for (
int f = 0; f < c.
ptn[i] + 1; ++f) {
580 const int _test_v = c.
lab[i + f];
583 for (
int f = 0; f < c.
ptn[i] + 1; ++f) {
584 const int _test_v = c.
lab[i + f];
585 const int _n1 = g->
e[g->
v[_test_v] + 0];
586 const int _n2 = g->
e[g->
v[_test_v] + 1];
594 recovery_strings[orig_n1].push_back(orig_test_v);
595 for (
size_t s = 0; s < recovery_strings[orig_test_v].size(); ++s)
596 recovery_strings[orig_n1].push_back(
597 recovery_strings[orig_test_v][s]);
606 if (touched_color_cache.
get(col_n1) && touched_color_cache.
get(col_n2) &&
607 already_matched_n1_n2) {
612 const int col_endpoint2 = colmap[n2];
613 bool col_cycle =
false;
614 for (
int f = 0; f < g->
d[n1]; ++f) {
615 const int col_other = colmap[g->
e[g->
v[n1] + f]];
616 if (col_other == col_endpoint2) {
627 edge_scratch[already_match_pt1 + worklist_deg0[col_n1]] = col_n2;
629 edge_scratch[already_match_pt2 + worklist_deg0[col_n2]] = col_n1;
630 ++worklist_deg0[col_n1];
631 ++worklist_deg0[col_n2];
633 touched_color_cache.
set(col_n1);
634 touched_color_cache.
set(col_n2);
638 for (
int f = 0; f < c.
ptn[i] + 1; ++f) {
639 const int _test_v = c.
lab[i + f];
641 const int _n1 = g->
e[g->
v[_test_v] + 0];
642 const int _n2 = g->
e[g->
v[_test_v] + 1];
643 worklist_deg1[_n1] = _n2;
644 worklist_deg1[_n2] = _n1;
645 for (
size_t t = 0; t < add_edge_buff[_n2].size(); ++t)
647 add_edge_buff[_n2].push_back(_n1);
648 add_edge_buff_act.
set(_n2);
649 add_edge_buff[_n1].push_back(_n2);
650 add_edge_buff_act.
set(_n1);
661 recovery_strings[orig_n1].push_back(orig_test_v);
662 for (
size_t s = 0; s < recovery_strings[orig_test_v].size(); ++s) {
663 recovery_strings[orig_n1].push_back(recovery_strings[orig_test_v][s]);
671 worklist_deg0.reset();
672 worklist_deg1.reset();
673 touched_color_cache.
reset();
681 int current_vertex = start;
682 int last_vertex = block;
687 if(path_done) path_done->
set(block);
690 if (g->
d[current_vertex] != 2) {
696 if(path) path->
push_back(current_vertex);
697 if(path_done) path_done->
set(current_vertex);
699 const int next_vertex1 = g->
e[g->
v[current_vertex] + 0];
700 const int next_vertex2 = g->
e[g->
v[current_vertex] + 1];
701 int next_vertex = next_vertex1;
702 if(next_vertex1 == last_vertex) next_vertex = next_vertex2;
703 if(next_vertex == block)
break;
705 last_vertex = current_vertex;
706 current_vertex = next_vertex;
715 static std::pair<int, int> walk_to_endpoint(
dejavu::sgraph *g,
const int start,
const int block,
717 int current_vertex = start;
718 int last_vertex = block;
720 while(g->
d[current_vertex] == 2) {
722 path_done->
set(current_vertex);
724 const int next_vertex1 = g->
e[g->
v[current_vertex] + 0];
725 const int next_vertex2 = g->
e[g->
v[current_vertex] + 1];
726 int next_vertex = next_vertex1;
727 if(next_vertex1 == last_vertex)
728 next_vertex = next_vertex2;
730 last_vertex = current_vertex;
731 current_vertex = next_vertex;
734 return {current_vertex, last_vertex};
739 for(k = 1; k < g->
v_size && g->
v[k-1] <= g->
v[k]; ++k);
740 if(k == g->
v_size)
return;
744 for(
int i = 0; i < g->
v_size; ++i) {
745 const int eptr = g->
v[i];
746 const int deg = g->
d[i];
748 for(
int j = eptr; j < eptr + deg; ++j) {
749 g->
e[epos] = edge_scratch[j];
758 static int walk_to_endpoint_collect_path(
dejavu::sgraph *g,
const int start,
const int block,
760 int current_vertex = start;
761 int last_vertex = block;
763 while(g->
d[current_vertex] == 2) {
767 const int next_vertex1 = g->
e[g->
v[current_vertex] + 0];
768 const int next_vertex2 = g->
e[g->
v[current_vertex] + 1];
769 int next_vertex = next_vertex1;
770 if(next_vertex1 == last_vertex)
771 next_vertex = next_vertex2;
773 last_vertex = current_vertex;
774 current_vertex = next_vertex;
778 return current_vertex;
792 add_edge_buff_act.
reset();
793 for (
int i = 0; i < g->
v_size; ++i) {
794 add_edge_buff[i].clear();
799 worklist_deg1.reset();
802 for (
int i = 0; i < g->
v_size; ++i) {
803 endpoint_cnt.push_back(0);
814 for (
int i = 0; i < g->
v_size; ++i) {
818 const int n1 = g->
e[g->
v[i] + 0];
819 const int n2 = g->
e[g->
v[i] + 1];
822 const auto other_endpoint = walk_to_endpoint(g, i, n1, &path_done);
823 if(other_endpoint.first == n1)
825 connected_paths[g->
v[n1] + endpoint_cnt[n1]] = i;
826 connected_endpoints[g->
v[n1] + endpoint_cnt[n1]] = other_endpoint.first;
828 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
829 other_endpoint.second;
830 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n1;
831 ++endpoint_cnt[other_endpoint.first];
835 }
else if(g->
d[n2] != 2) {
836 const auto other_endpoint = walk_to_endpoint(g, i, n2, &path_done);
837 if(other_endpoint.first == n2)
839 connected_paths[g->
v[n2] + endpoint_cnt[n2]] = i;
840 connected_endpoints[g->
v[n2] + endpoint_cnt[n2]] = other_endpoint.first;
842 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
843 other_endpoint.second;
844 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n2;
845 ++endpoint_cnt[other_endpoint.first];
856 for(
int i = 0; i < g->
v_size;) {
858 const int color_size = c.
ptn[color] + 1;
860 const int test_vertex = c.
lab[color];
861 const int endpoints = endpoint_cnt[test_vertex];
863 for(
int j = 0; j < color_size; ++j) {
867 if(endpoints == 0)
continue;
871 color_unique.reset();
874 for(
int j = 0; j < endpoints; ++j) {
875 const int neighbour = connected_paths[g->
v[test_vertex] + j];
877 if(color_test.get(neighbour_col)) {
878 color_unique.set(neighbour_col);
880 color_test.set(neighbour_col);
885 for(
int j = 0; j < endpoints; ++j) {
886 const int neighbour = connected_paths[g->
v[test_vertex] + j];
888 if(!color_unique.get(neighbour_col)) {
895 color_unique.reset();
898 for(
int j = 0; j < g->
d[test_vertex]; ++j) {
899 const int neighbour = g->
e[g->
v[test_vertex] + j];
901 color_test.set(neighbour_col);
905 color_test.set(color);
907 for(
int k = 0; k < filter.cur_pos; ++k) {
908 const int j = filter[k];
909 const int neighbour_endpoint = connected_endpoints[g->
v[test_vertex] + j];
910 const int neighbour_col = c.
vertex_to_col[neighbour_endpoint];
911 if(color_test.get(neighbour_col)) {
912 color_unique.set(neighbour_col);
914 color_test.set(neighbour_col);
919 for(
int k = 0; k < filter.cur_pos; ++k) {
920 const int j = filter[k];
921 const int neighbour = connected_endpoints[g->
v[test_vertex] + j];
923 if(!color_unique.get(neighbour_col)) {
924 filter[write_pos] = j;
928 filter.cur_pos = write_pos;
933 color_unique.reset();
934 for(
int k = 0; k < filter.cur_pos; ++k) {
935 const int j = filter[k];
936 const int filter_to_col = c.
vertex_to_col[connected_paths[g->
v[test_vertex] + j]];
937 color_unique.set(filter_to_col);
938 filter[k] = filter_to_col;
944 for(
int k = 0; k < filter.cur_pos; ++k) {
945 color_pos[filter[k]] = k;
948 const int num_paths = filter.cur_pos;
950 #if defined(DEJDEBUG) && !defined(NDEBUG)
951 int reduced_verts = 0;
952 int reduced_verts_last = 0;
956 for(
int j = 0; j < color_size; ++j) {
957 const int vertex = c.
lab[color + j];
959 int sanity_check = 0;
962 for(
int k = 0; k < g->
d[vertex]; ++k) {
963 const int neighbour = g->
e[g->
v[vertex] + k];
965 if(color_unique.get(neighbour_col)) {
966 const int pos = color_pos[neighbour_col];
967 path_list[pos] = neighbour;
970 color_test.set(neighbour_col);
976 for(
int k = 0; k < num_paths; ++k) {
977 const int path_start_vertex = path_list[k];
979 if(path_done.
get(path_start_vertex)) {
985 const int other_endpoint =
986 walk_to_endpoint_collect_path(g, path_start_vertex, vertex, &path);
989 dej_assert(other_endpoint != path_start_vertex);
992 for(
int l = 0; l < path.
cur_pos; ++l) {
993 const int del_v = path[l];
998 path_done.
set(del_v);
1002 dej_assert(!is_adjacent(g, vertex, other_endpoint));
1003 add_edge_buff[other_endpoint].push_back(vertex);
1004 add_edge_buff_act.
set(other_endpoint);
1005 add_edge_buff[vertex].push_back(other_endpoint);
1006 add_edge_buff_act.
set(vertex);
1012 recovery_strings[unique_endpoint_orig].reserve(
1013 2*(recovery_strings[unique_endpoint_orig].size() + path.
cur_pos));
1014 for (
int l = 0; l < path.
cur_pos; ++l) {
1020 recovery_strings[unique_endpoint_orig].push_back(path_v_orig);
1021 recovery_strings[unique_endpoint_orig].insert(
1022 recovery_strings[unique_endpoint_orig].end(),
1023 recovery_strings[path_v_orig].begin(),
1024 recovery_strings[path_v_orig].end());
1028 #if defined(DEJDEBUG) && !defined(NDEBUG)
1029 reduced_verts =
static_cast<int>(recovery_strings[
translate_back(vertex)].size());
1031 dej_assert(reduced_verts == reduced_verts_last);
1033 reduced_verts_last = reduced_verts;
1048 void recovery_attach_to_edge(
int v1,
int v2, std::vector<int>& recovery) {
1049 const int pos =
static_cast<int>(recovery_edge_attached.size());
1051 const int len =
static_cast<int>(recovery.size());
1052 ++edge_attached_information;
1055 recovery_edge_adjacent[v1].emplace_back(v2, recovery[0], len);
1056 recovery_edge_adjacent[v2].emplace_back(v1, recovery[0], len);
1059 for (
int i = 0; i < len; ++i) { recovery_edge_attached.push_back(recovery[i]); }
1060 recovery_edge_adjacent[v1].emplace_back(v2, pos, len);
1061 recovery_edge_adjacent[v2].emplace_back(v1, pos, len);
1077 if(recovery_edge_adjacent[v].empty())
return;
1078 const int v_map = aut[v];
1080 for(
auto & j : recovery_edge_adjacent[v]) {
1081 const int other = std::get<0>(j);
1082 const int id = std::get<1>(j);
1085 const int other_map = aut[other];
1087 (*help_array2)[other_map] = id;
1090 dej_assert(recovery_edge_adjacent[v].size() == recovery_edge_adjacent[v_map].size());
1092 for(
auto & j : recovery_edge_adjacent[v_map]) {
1093 const int other_map = std::get<0>(j);
1094 const int id = std::get<1>(j);
1095 const int len = std::get<2>(j);
1098 const int orig_id = (*help_array2)[other_map];
1099 if(
id == orig_id)
continue;
1108 const int v_from = orig_id;
1109 const int v_to = id;
1110 if (v_from != v_to && aut[v_from] == v_from) {
1116 for (
int k = 0; k < len; ++k) {
1117 const int v_from = recovery_edge_attached[orig_id + k];
1118 const int v_to = recovery_edge_attached[
id + k];
1119 if (v_from != v_to && aut[v_from] == v_from) {
1142 add_edge_buff_act.
reset();
1143 for (
int i = 0; i < g->
v_size; ++i) {
1144 add_edge_buff[i].clear();
1148 worklist_deg1.reset();
1151 for (
int i = 0; i < g->
v_size; ++i) endpoint_cnt.push_back(0);
1166 int total_paths = 0;
1168 for (
int i = 0; i < g->
v_size; ++i) {
1170 hub_vertex_position[i] = -1;
1174 if(path_done.
get(i))
1176 const int n1 = g->
e[g->
v[i] + 0];
1177 const int n2 = g->
e[g->
v[i] + 1];
1180 const auto other_endpoint = walk_to_endpoint(g, i, n1, &path_done);
1181 if(other_endpoint.first == n1)
1183 connected_paths[g->
v[n1] + endpoint_cnt[n1]] = i;
1184 connected_endpoints[g->
v[n1] + endpoint_cnt[n1]] = other_endpoint.first;
1186 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
1187 other_endpoint.second;
1188 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n1;
1189 ++endpoint_cnt[other_endpoint.first];
1194 }
else if(g->
d[n2] != 2) {
1195 const auto other_endpoint = walk_to_endpoint(g, i, n2, &path_done);
1196 if(other_endpoint.first == n2)
1198 connected_paths[g->
v[n2] + endpoint_cnt[n2]] = i;
1199 connected_endpoints[g->
v[n2] + endpoint_cnt[n2]] = other_endpoint.first;
1201 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
1202 other_endpoint.second;
1203 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n2;
1204 ++endpoint_cnt[other_endpoint.first];
1215 if(total_paths < g->v_size/10)
return;
1221 for(
int i = 0; i < g->
v_size;) {
1222 const int color = i;
1223 const int color_size = c.
ptn[color] + 1;
1225 const int test_vertex = c.
lab[color];
1226 const int endpoints = endpoint_cnt[test_vertex];
1228 for(
int j = 0; j < color_size; ++j) {
1233 if(endpoints == 0)
continue;
1236 color_unique.reset();
1240 for(
int j = 0; j < endpoints; ++j) {
1241 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1245 if(color_test.get(neighbour_col) && !path_done.
get(neighbour)) {
1246 ++color_deg[neighbour_col];
1247 color_unique.set(neighbour_col);
1249 color_deg[neighbour_col] = 1;
1251 color_test.set(neighbour_col);
1256 bool duplicate_endpoint_flag =
false;
1257 for(
int j = 0; j < color_size; ++j) {
1258 const int endpt_test_vertex = c.
lab[color + j];
1259 duplicate_endpoints.reset();
1260 duplicate_endpoints.set(endpt_test_vertex);
1261 dej_assert(endpoint_cnt[endpt_test_vertex] == endpoints);
1262 for (
int k = 0; k < endpoints; ++k) {
1263 const int endpoint = connected_endpoints[g->
v[endpt_test_vertex] + k];
1264 if(duplicate_endpoints.get(endpoint)) {
1265 duplicate_endpoint_flag =
true;
1268 duplicate_endpoints.set(endpoint);
1270 if(duplicate_endpoint_flag)
break;
1274 if(duplicate_endpoint_flag)
continue;
1278 for(
int j = 0; j < endpoints; ++j) {
1279 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1282 const int endpoint = connected_endpoints[g->
v[test_vertex] + j];
1285 const int endpoint_col_sz = c.
ptn[endpoint_col] + 1;
1286 if(color_unique.get(neighbour_col) && color != endpoint_col &&
1287 endpoint_col_sz >= color_size) {
1288 filter.push_back(j);
1295 color_unique.reset();
1298 for(
int k = 0; k < filter.cur_pos; ++k) {
1299 const int filter_col = c.
vertex_to_col[connected_paths[g->
v[test_vertex] + filter[k]]];
1300 if(!color_unique.get(filter_col)) {
1301 color_pos[filter_col] = use_pos;
1302 color_unique.set(filter_col);
1303 use_pos += color_deg[filter_col];
1307 const int num_paths = filter.cur_pos;
1310 for(
int j = 0; j < color_size; ++j) {
1311 const int vertex = c.
lab[color + j];
1314 for(
int k = 0; k < filter.cur_pos; ++k) {
1315 const int filter_col = c.
vertex_to_col[connected_paths[g->
v[test_vertex] + filter[k]]];
1316 color_deg[filter_col] = 0;
1319 int sanity_check_num_paths = 0;
1321 for(
int k = 0; k < g->
d[vertex]; ++k) {
1322 const int neighbour = g->
e[g->
v[vertex] + k];
1324 if(color_unique.get(neighbour_col)) {
1325 const int pos = color_pos[neighbour_col] + color_deg[neighbour_col];
1326 path_list[pos] = neighbour;
1328 color_canonical_v[neighbour_col] = neighbour;
1329 ++color_deg[neighbour_col];
1330 ++sanity_check_num_paths;
1334 dej_assert(num_paths == sanity_check_num_paths);
1336 for(
int k = 0; k < num_paths; ++k) {
1337 const int path_start_vertex = path_list[k];
1339 if(path_done.
get(path_start_vertex)) {
1345 const int other_endpoint = walk_to_endpoint_collect_path(g, path_start_vertex, vertex, &path);
1348 dej_assert(other_endpoint != path_start_vertex);
1351 const int hub_vertex = color_canonical_v[c.
vertex_to_col[path_start_vertex]];
1355 dej_assert(is_adjacent(g, hub_vertex, vertex));
1358 for(
int l = 0; l < path.
cur_pos; ++l) {
1359 const int del_v = path[l];
1364 path_done.
set(del_v);
1366 del.
unset(hub_vertex);
1371 if(!is_adjacent(g, hub_vertex, other_endpoint)) {
1372 add_edge_buff[other_endpoint].push_back(hub_vertex);
1373 add_edge_buff_act.
set(other_endpoint);
1374 add_edge_buff[hub_vertex].push_back(other_endpoint);
1375 add_edge_buff_act.
set(hub_vertex);
1384 if(recovery_strings[hub_vertex_orig].empty())
1385 recovery_strings[hub_vertex_orig].push_back(INT32_MAX);
1387 std::vector<int> recovery;
1388 for (
int l = 0; l < path.
cur_pos; ++l) {
1395 recovery.push_back(path_v_orig);
1396 dej_assert(path_v_orig != hub_vertex_orig? recovery_strings[path_v_orig].size() == 0: true);
1410 add_edge_buff_act.
reset();
1411 for (
int i = 0; i < g->
v_size; ++i) add_edge_buff[i].clear();
1414 worklist_deg1.reset();
1417 for (
int i = 0; i < g->
v_size; ++i) endpoint_cnt.push_back(0);
1428 int total_paths = 0;
1430 for (
int i = 0; i < g->
v_size; ++i) {
1432 if(path_done.
get(i))
1434 const int n1 = g->
e[g->
v[i] + 0];
1435 const int n2 = g->
e[g->
v[i] + 1];
1437 if(g->
d[n1] != 2 && g->
d[n2] != 2) {
1438 const auto other_endpoint = walk_to_endpoint(g, i, n1, &path_done);
1439 if(other_endpoint.first == n1)
1441 connected_paths[g->
v[n1] + endpoint_cnt[n1]] = i;
1442 connected_endpoints[g->
v[n1] + endpoint_cnt[n1]] = other_endpoint.first;
1444 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
1445 other_endpoint.second;
1446 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n1;
1447 ++endpoint_cnt[other_endpoint.first];
1458 if(total_paths < g->v_size/10)
return;
1464 for(
int i = 0; i < g->
v_size;) {
1465 const int color = i;
1466 const int color_size = c.
ptn[color] + 1;
1468 const int test_vertex = c.
lab[color];
1469 const int endpoints = endpoint_cnt[test_vertex];
1471 for(
int j = 0; j < color_size; ++j) {
1476 if(endpoints == 0)
continue;
1480 int color_deg_single = 0;
1481 bool only_one =
true;
1482 int relevant_neighbour_color = -1;
1483 for(
int j = 0; j < endpoints; ++j) {
1484 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1485 const int endpoint = connected_endpoints[g->
v[test_vertex] + j];
1490 if(!path_done.
get(neighbour) && endpoint_col == color) {
1491 if(relevant_neighbour_color == -1) {
1492 relevant_neighbour_color = neighbour_col;
1494 only_one = only_one && (relevant_neighbour_color == neighbour_col);
1495 color_deg_single += 1;
1499 if(!only_one || color_deg_single == 0)
continue;
1501 bool duplicate_endpoint_flag =
false;
1503 for(
int j = g->
v[test_vertex]; j < g->
v[test_vertex] + g->
d[test_vertex]; ++j) {
1504 const int neighbour = g->
e[j];
1506 duplicate_endpoint_flag =
true;
1513 for(
int j = 0; j < color_size; ++j) {
1514 const int endpt_test_vertex = c.
lab[color + j];
1515 duplicate_endpoints.reset();
1516 duplicate_endpoints.set(endpt_test_vertex);
1517 dej_assert(endpoint_cnt[endpt_test_vertex] == endpoints);
1518 for (
int k = 0; k < endpoints; ++k) {
1519 const int neighbour = connected_paths[g->
v[endpt_test_vertex] + k];
1521 if(neighbour_col != relevant_neighbour_color)
continue;
1523 const int endpoint = connected_endpoints[g->
v[endpt_test_vertex] + k];
1525 if(duplicate_endpoints.get(endpoint)) {
1526 duplicate_endpoint_flag =
true;
1529 duplicate_endpoints.set(endpoint);
1531 if(duplicate_endpoint_flag)
break;
1535 if(duplicate_endpoint_flag)
continue;
1539 for(
int j = 0; j < endpoints; ++j) {
1540 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1543 if(neighbour_col == relevant_neighbour_color) {
1544 dej_assert(neighbour_col == relevant_neighbour_color);
1545 filter.push_back(j);
1550 const int num_paths = filter.cur_pos;
1553 for(
int j = 0; j < color_size; ++j) {
1554 const int vertex = c.
lab[color + j];
1558 int sanity_check_num_paths = 0;
1560 for(
int k = 0; k < g->
d[vertex]; ++k) {
1561 const int neighbour = g->
e[g->
v[vertex] + k];
1563 if(neighbour_col == relevant_neighbour_color) {
1564 const int pos = next_pos;
1565 path_list[pos] = neighbour;
1568 ++sanity_check_num_paths;
1572 dej_assert(num_paths == sanity_check_num_paths);
1574 for(
int k = 0; k < num_paths; ++k) {
1575 const int path_start_vertex = path_list[k];
1577 if(path_done.
get(path_start_vertex)) {
1583 const int other_endpoint = walk_to_endpoint_collect_path(g, path_start_vertex, vertex, &path);
1586 dej_assert(other_endpoint != path_start_vertex);
1589 for(
int l = 0; l < path.
cur_pos; ++l) {
1590 const int del_v = path[l];
1595 path_done.
set(del_v);
1600 if(!is_adjacent(g, vertex, other_endpoint)) {
1601 add_edge_buff[other_endpoint].push_back(vertex);
1602 add_edge_buff_act.
set(other_endpoint);
1603 add_edge_buff[vertex].push_back(other_endpoint);
1604 add_edge_buff_act.
set(vertex);
1608 std::vector<int> recovery;
1609 for (
int l = 0; l < path.
cur_pos; ++l) {
1615 recovery.push_back(path_v_orig);
1616 for(
int f = 0; f < static_cast<int>(recovery_strings[path_v_orig].size()); ++f) {
1617 recovery.push_back(recovery_strings[path_v_orig][f]);
1632 for(
int i = 0; i < g->
v_size; ++i) {
1636 int cycles_recolored = 0;
1641 for (
int i = 0; i < g->
v_size; ++i) {
1643 if(path_done.
get(i))
1645 const int n1 = g->
e[g->
v[i] + 0];
1646 const int n2 = g->
e[g->
v[i] + 1];
1648 if(g->
d[n1] != 2 || g->
d[n2] != 2)
1652 const int cycle_length = walk_cycle(g, i, n1, &path_done, &path);
1653 if(cycle_length == -1) {
1656 cycles_recolored += 1;
1657 for(
int j = 0; j < path.
cur_pos; ++j) {
1658 colmap[path[j]] = colmap[path[j]] + g->
v_size * cycle_length;
1664 if(cycles_recolored > 0) {
1666 bool has_discrete =
false;
1667 for(
int i = 0; i < g->
v_size && !has_discrete; ) {
1668 const int col_sz = c.
ptn[i] + 1;
1669 has_discrete = has_discrete || (col_sz == 1);
1672 for(
int i = 0; i < g->
v_size; ++i) {
1675 return has_discrete;
1691 add_edge_buff_act.
reset();
1692 for (
int i = 0; i < g->
v_size; ++i) add_edge_buff[i].clear();
1696 worklist_deg1.reset();
1699 for (
int i = 0; i < g->
v_size; ++i) endpoint_cnt.push_back(0);
1712 for (
int i = 0; i < g->
v_size; ++i) {
1714 if(path_done.
get(i))
1716 const int n1 = g->
e[g->
v[i] + 0];
1717 const int n2 = g->
e[g->
v[i] + 1];
1720 const auto other_endpoint = walk_to_endpoint(g, i, n1, &path_done);
1721 if(other_endpoint.first == n1)
1723 connected_paths[g->
v[n1] + endpoint_cnt[n1]] = i;
1724 connected_endpoints[g->
v[n1] + endpoint_cnt[n1]] = other_endpoint.first;
1726 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
1727 other_endpoint.second;
1728 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n1;
1729 ++endpoint_cnt[other_endpoint.first];
1733 }
else if(g->
d[n2] != 2) {
1734 const auto other_endpoint = walk_to_endpoint(g, i, n2, &path_done);
1735 if(other_endpoint.first == n2)
1737 connected_paths[g->
v[n2] + endpoint_cnt[n2]] = i;
1738 connected_endpoints[g->
v[n2] + endpoint_cnt[n2]] = other_endpoint.first;
1740 connected_paths[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] =
1741 other_endpoint.second;
1742 connected_endpoints[g->
v[other_endpoint.first] + endpoint_cnt[other_endpoint.first]] = n2;
1743 ++endpoint_cnt[other_endpoint.first];
1754 for(
int i = 0; i < g->
v_size;) {
1755 const int color = i;
1756 const int color_size = c.
ptn[color] + 1;
1758 const int test_vertex = c.
lab[color];
1759 const int endpoints = endpoint_cnt[test_vertex];
1761 if (endpoints == 0) {
1766 color_unique.reset();
1769 for (
int j = 0; j < endpoints; ++j) {
1770 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1772 if (color_test.get(neighbour_col)) {
1773 color_unique.set(neighbour_col);
1775 color_test.set(neighbour_col);
1780 for (
int j = 0; j < endpoints; ++j) {
1781 const int neighbour = connected_paths[g->
v[test_vertex] + j];
1783 if (color_unique.get(neighbour_col)) {
1784 not_unique.push_back(neighbour);
1785 dej_assert(connected_endpoints[g->
v[test_vertex] + j] >= 0);
1787 not_unique.push_back(connected_endpoints[g->
v[test_vertex] + j]);
1792 color_unique.reset();
1795 for (
int kk = 0; kk < not_unique.cur_pos; kk += 2) {
1796 const int endpoint = not_unique[kk + 1];
1798 const int neighbour = not_unique[kk];
1800 not_unique_analysis[endpoint_col] = 0;
1801 not_unique_analysis[neighbour_col] = 0;
1803 for (
int kk = 0; kk < not_unique.cur_pos; kk += 2) {
1804 const int endpoint = not_unique[kk + 1];
1806 const int neighbour = not_unique[kk];
1808 ++not_unique_analysis[endpoint_col];
1809 ++not_unique_analysis[neighbour_col];
1811 for (
int kk = 0; kk < not_unique.cur_pos; kk += 2) {
1812 const int neighbour = not_unique[kk];
1814 const int endpoint = not_unique[kk + 1];
1817 if (!color_test.get(endpoint_col)) {
1818 color_test.set(endpoint_col);
1819 if (not_unique_analysis[endpoint_col] == not_unique_analysis[neighbour_col] &&
1820 not_unique_analysis[endpoint_col] == c.
ptn[endpoint_col] + 1) {
1822 bool all_unique =
true;
1823 color_unique.reset();
1824 for (
int jj = 1; jj < not_unique.cur_pos; jj += 2) {
1825 const int _endpoint = not_unique[jj];
1827 if (_endpoint_col == endpoint_col) {
1828 if (color_unique.get(_endpoint)) {
1832 color_unique.set(_endpoint);
1837 if (all_unique && color < endpoint_col) {
1839 dej_assert(c.
ptn[path_col] + 1 == (not_unique_analysis[endpoint_col] * color_size));
1840 dej_assert(c.
ptn[endpoint_col] + 1 == not_unique_analysis[endpoint_col]);
1843 int endpoint_neighbour_col = -1;
1845 for(
int jjj = 0; jjj < color_size; ++jjj ) {
1846 const int col1_vertj = c.
lab[color + jjj];
1849 neighbour_list.reset();
1850 for (
int jj = 0; jj < g->
d[col1_vertj]; ++jj) {
1851 const int _neighbour = g->
e[g->
v[col1_vertj] + jj];
1855 if (_neighbour_col == path_col) {
1856 neighbour_list.push_back(_neighbour);
1857 const auto other_endpoint =
1858 walk_to_endpoint(g, _neighbour, col1_vertj,
nullptr);
1859 neighbour_to_endpoint[_neighbour] = other_endpoint.first;
1860 if(endpoint_neighbour_col == -1) {
1861 endpoint_neighbour_col = c.
vertex_to_col[other_endpoint.second];
1866 neighbour_list.sort_after_map(neighbour_to_endpoint.get_array());
1869 for (
int jj = 0; jj < neighbour_list.cur_pos; ++jj) {
1870 const int _neighbour = neighbour_list[jj];
1873 int _endpoint = walk_to_endpoint_collect_path(g, _neighbour,
1878 for (
int l = 0; l < path.
cur_pos; ++l) {
1879 const int del_v = path[l];
1884 path_done.
set(del_v);
1891 recovery_strings[vert_orig].reserve(
1892 recovery_strings[vert_orig].size() +
1894 for (
int l = 0; l < path.
cur_pos; ++l) {
1900 recovery_strings[vert_orig].push_back(path_v_orig);
1901 for(
size_t rsi = 0; rsi < recovery_strings[path_v_orig].size(); ++rsi) {
1902 recovery_strings[vert_orig].push_back(
1903 recovery_strings[path_v_orig][rsi]);
1910 recovery_strings[endpoint_orig].reserve(
1911 recovery_strings[endpoint_orig].size() +
1913 for (
int l = 0; l < path.
cur_pos; ++l) {
1919 recovery_strings[endpoint_orig].push_back(-path_v_orig);
1920 for(
size_t rsi = 0; rsi < recovery_strings[path_v_orig].size(); ++rsi) {
1921 recovery_strings[endpoint_orig].push_back(
1922 -abs(recovery_strings[path_v_orig][rsi]));
1941 g_old_v.reserve(g->
v_size);
1942 bool has_01 =
false;
1943 for (
int i = 0; i < g->
v_size; ++i) {
1944 const int d = g->
d[i];
1945 has_01 = has_01 || (d == 0) || (d == 1);
1946 g_old_v.push_back(d);
1950 worklist_deg0.reset();
1951 worklist_deg1.reset();
1957 for (
int i = 0; i < g->
v_size; ++i)
1958 childcount.push_back(0);
1961 for (
int i = 0; i < g->
v_size; ++i)
1962 childcount_prev.push_back(0);
1971 const int v = c.
lab[i];
1972 switch (g_old_v[v]) {
1974 worklist_deg0.push_back(v);
1978 worklist_deg1.push_back(v);
1986 while (!worklist_deg1.empty()) {
1987 const int v_child = worklist_deg1.pop_back();
1988 if (del.
get(v_child))
1990 if (g_old_v[v_child] != 1)
1994 const int child_col_sz = c.
ptn[v_child_col] + 1;
1995 bool is_pairs =
false;
1996 bool permute_parents_instead =
false;
1997 if (child_col_sz == 1) {
2004 for (
int i = v_child_col; i < v_child_col + child_col_sz; ++i) {
2005 int child = c.
lab[i];
2008 const int e_pos_child = g->
v[child];
2009 int parent = g->
e[e_pos_child];
2011 if (is_pairs && del.
get(child))
2014 int search_parent = 0;
2015 while (del.
get(parent)) {
2017 parent = g->
e[e_pos_child + search_parent];
2025 pair_match[child] = parent;
2026 pair_match[parent] = child;
2027 if (parent < child) {
2028 parentlist.push_back(parent);
2030 parentlist.push_back(child);
2038 edge_scratch[g->
v[parent] + childcount[parent]] = child;
2040 ++childcount[parent];
2042 if (!is_parent.get(parent)) {
2043 is_parent.set(parent);
2044 childcount_prev[parent] = childcount[parent] - 1;
2049 g_old_v[parent] -= 1;
2050 if (g_old_v[parent] == 1 && i == v_child_col) {
2051 worklist_deg1.push_back(parent);
2052 }
else if (g_old_v[parent] == 0 && i == v_child_col) {
2053 worklist_deg0.push_back(parent);
2061 for (
int j = 0; j < parentlist.cur_pos; ++j) {
2062 const int first_pair_parent = parentlist[j];
2063 const int pair_from = first_pair_parent;
2064 const int pair_to = pair_match[pair_from];
2068 map.push_back(pair_from);
2069 stack1.push_back(std::pair<int, int>(g->
v[pair_from], g->
v[pair_from] + childcount[pair_from]));
2070 while (!stack1.empty()) {
2071 std::pair<int, int> from_to = stack1.pop_back();
2072 int from = from_to.first;
2073 const int to = from_to.second;
2074 for (
int f = from; f < to; ++f) {
2075 const int next = edge_scratch[f];
2077 const int from_next = g->
v[next];
2078 const int to_next = g->
v[next] + childcount[next];
2079 map.push_back(next);
2081 if (from_next != to_next)
2082 stack1.push_back(std::pair<int, int>(from_next, to_next));
2096 const int v_to_1 = pair_to;
2097 const int v_from_1 = map[pos];
2099 dej_assert(automorphism[v_from_1] == v_from_1);
2101 _automorphism[v_from_1] = v_to_1;
2102 _automorphism[v_to_1] = v_from_1;
2108 dej_assert(childcount[pair_to] == childcount[pair_from]);
2109 stack1.push_back(std::pair<int, int>(g->
v[pair_to], g->
v[pair_to] + childcount[pair_to]));
2110 while (!stack1.empty()) {
2111 std::pair<int, int> from_to = stack1.pop_back();
2112 int from = from_to.first;
2113 const int to = from_to.second;
2114 for (
int f = from; f < to; ++f) {
2115 const int next = edge_scratch[f];
2117 const int from_next = g->
v[next];
2118 const int to_next = g->
v[next] + childcount[next];
2124 const int v_to_2 = next;
2125 const int v_from_2 = map[pos];
2128 dej_assert(_automorphism[v_from_2] == v_from_2);
2129 _automorphism[v_from_2] = v_to_2;
2130 _automorphism[v_to_2] = v_from_2;
2135 if (from_next != to_next)
2136 stack1.push_back(std::pair<int, int>(from_next, to_next));
2152 _automorphism_supp.
reset();
2155 for (
int j = 0; j < parentlist.cur_pos; ++j) {
2156 const int first_pair_parent = parentlist[j];
2157 const int pair_from = first_pair_parent;
2158 const int pair_to = pair_match[pair_from];
2162 recovery_strings[original_parent].push_back(original_pair_to);
2163 for (
size_t s = 0; s < recovery_strings[original_pair_to].size(); ++s)
2164 recovery_strings[original_parent].push_back(
2165 recovery_strings[original_pair_to][s]);
2170 stack1.push_back(std::pair<int, int>(g->
v[pair_to], g->
v[pair_to] + childcount[pair_to]));
2171 while (!stack1.empty()) {
2172 std::pair<int, int> from_to = stack1.pop_back();
2173 int from = from_to.first;
2174 const int to = from_to.second;
2175 for (
int f = from; f < to; ++f) {
2176 const int next = edge_scratch[f];
2178 const int from_next = g->
v[next];
2179 const int to_next = g->
v[next] + childcount[next];
2181 recovery_strings[original_parent].push_back(orig_next);
2182 for (
size_t s = 0; s < recovery_strings[orig_next].size(); ++s)
2183 recovery_strings[original_parent].push_back(
2184 recovery_strings[orig_next][s]);
2185 if (from_next != to_next)
2186 stack1.push_back(std::pair<int, int>(from_next, to_next));
2191 permute_parents_instead =
true;
2194 while (!parentlist.empty()) {
2195 int parent, childcount_from, childcount_to, child_from;
2196 if (!permute_parents_instead) {
2197 parent = parentlist.pop_back();
2198 childcount_from = childcount_prev[parent];
2199 childcount_to = childcount[parent];
2202 childcount_from = 0;
2203 childcount_to = parentlist.cur_pos;
2206 dej_assert(childcount_to - childcount_from > 0);
2207 if (childcount_to - childcount_from == 1) {
2208 if (permute_parents_instead)
2212 if (!permute_parents_instead) {
2213 child_from = edge_scratch[g->
v[parent] + childcount_from];
2216 child_from = parentlist[0];
2222 map.push_back(child_from);
2223 stack1.push_back(std::pair<int, int>(g->
v[child_from], g->
v[child_from] + childcount[child_from]));
2224 while (!stack1.empty()) {
2225 std::pair<int, int> from_to = stack1.pop_back();
2226 int from = from_to.first;
2227 const int to = from_to.second;
2228 for (
int f = from; f < to; ++f) {
2229 const int next = edge_scratch[f];
2231 const int from_next = g->
v[next];
2232 const int to_next = g->
v[next] + childcount[next];
2233 map.push_back(next);
2235 if (from_next != to_next)
2236 stack1.push_back(std::pair<int, int>(from_next, to_next));
2240 for (
int i = childcount_from + 1; i < childcount_to; ++i) {
2244 if (!permute_parents_instead) {
2245 child_to = edge_scratch[g->
v[parent] + i];
2248 child_to = parentlist[i];
2254 _automorphism_supp.
reset();
2260 const int v_to_1 = child_to;
2261 const int v_from_1 = map[pos];
2263 dej_assert(_automorphism[v_from_1] == v_from_1);
2264 _automorphism[v_from_1] = v_to_1;
2265 _automorphism[v_to_1] = v_from_1;
2271 dej_assert(childcount[child_to] == childcount[child_from]);
2272 stack1.push_back(std::pair<int, int>(g->
v[child_to], g->
v[child_to] + childcount[child_to]));
2273 while (!stack1.empty()) {
2274 std::pair<int, int> from_to = stack1.pop_back();
2275 int from = from_to.first;
2276 const int to = from_to.second;
2277 for (
int f = from; f < to; ++f) {
2278 const int next = edge_scratch[f];
2280 const int from_next = g->
v[next];
2281 const int to_next = g->
v[next] + childcount[next];
2287 const int v_to_2 = next;
2288 const int v_from_2 = map[pos];
2290 dej_assert(_automorphism[v_from_2] == v_from_2);
2291 _automorphism[v_from_2] = v_to_2;
2292 _automorphism[v_to_2] = v_from_2;
2297 if (from_next != to_next)
2298 stack1.push_back(std::pair<int, int>(from_next, to_next));
2313 _automorphism_supp.
reset();
2315 if (permute_parents_instead) {
2324 for (
int _i = 0; _i < g->
v_size; ++_i) {
2328 stack1.push_back(std::pair<int, int>(g->
v[_i], g->
v[_i] + childcount[_i]));
2330 recovery_strings[orig_i].reserve(
2331 recovery_strings[orig_i].size() + childcount[_i]);
2332 while (!stack1.empty()) {
2333 std::pair<int, int> from_to = stack1.pop_back();
2334 int from = from_to.first;
2335 const int to = from_to.second;
2339 const int next = edge_scratch[from];
2341 const int from_next = g->
v[next];
2342 const int to_next = g->
v[next] + childcount[next];
2345 recovery_strings[orig_i].push_back(orig_next);
2350 for (
size_t j = 0; j < recovery_strings[orig_next].size(); ++j)
2351 recovery_strings[orig_i].push_back(
2352 recovery_strings[orig_next][j]);
2353 stack1.push_back(std::pair<int, int>(from, to));
2354 stack1.push_back(std::pair<int, int>(from_next, to_next));
2362 while (!worklist_deg0.empty()) {
2363 const int v_child = worklist_deg0.pop_back();
2364 if (del.
get(v_child))
2370 const int child_col_sz = c.
ptn[v_child_col] + 1;
2371 const int parent_from = c.
lab[v_child_col];
2372 del.
set(parent_from);
2374 if (child_col_sz == 1)
2377 for (
int i = v_child_col + 1; i < v_child_col + child_col_sz; ++i) {
2380 const int parent_to = c.
lab[i];
2388 _automorphism[parent_to] = parent_from;
2389 _automorphism[parent_from] = parent_to;
2390 _automorphism_supp.
push_back(parent_from);
2391 _automorphism_supp.
push_back(parent_to);
2398 _automorphism_supp.
reset();
2405 if (g->
v_size <= 1)
return;
2408 worklist_deg0.reset();
2413 for (
int y = 0; y < g->
v_size; ++y) worklist_deg0[y] = 0;
2415 for (
int i = 0; i < g->
v_size;) {
2417 for (
int f = g->
v[v]; f < g->
v[v] + g->
d[v]; ++f) {
2418 const int v_neigh = g->
e[f];
2422 for (
int ii = 0; ii < c.
ptn[i] + 1; ++ii) {
2423 const int vx = c.
lab[i + ii];
2424 bool skipped_none =
true;
2425 for (
int f = g->
v[vx]; f < g->
v[vx] + g->
d[vx]; ++f) {
2426 const int v_neigh = g->
e[f];
2430 skipped_none =
false;
2433 if(skipped_none)
break;
2436 for (
int f = g->
v[v]; f < g->
v[v] + g->
d[v]; ++f) {
2437 const int v_neigh = g->
e[f];
2445 static void copy_coloring_to_colmap(
const coloring *c,
int *colmap) {
2446 for (
int i = 0; i < c->domain_size; ++i) {
2447 colmap[i] = c->vertex_to_col[i];
2456 translate_layer_fwd.clear();
2457 translate_layer_bwd.clear();
2459 translate_layer_bwd.reserve(backward_translation_layers[backward_translation_layers.size() - 1].size());
2460 translate_layer_fwd.reserve(g->
v_size);
2461 for (
size_t i = 0; i < backward_translation_layers[backward_translation_layers.size() - 1].size(); ++i)
2462 translate_layer_bwd.push_back(
2463 backward_translation_layers[backward_translation_layers.size() - 1][i]);
2469 for (
int i = 0; i < g->
v_size; ++i) {
2471 translate_layer_fwd.push_back(cnt);
2472 const int translate_back = translate_layer_bwd[translate_layer_fwd.size() - 1];
2473 backward_translation_layers[backward_translation_layers.size() - 1][cnt] =
translate_back;
2477 translate_layer_fwd.push_back(-1);
2481 if (new_vsize == 0 || new_vsize == 1) {
2487 backward_translation_layers[backward_translation_layers.size() - 1].resize(cnt);
2489 g_old_v.reserve(g->
v_size);
2490 for (
int i = 0; i < g->
v_size; ++i) {
2491 g_old_v.push_back(g->
v[i]);
2496 for (
int i = 0; i < g->
v_size; ++i) {
2497 const int old_v = i;
2498 const int new_v = translate_layer_fwd[i];
2504 for (
int j = g_old_v[old_v]; j < g_old_v[old_v] + g->
d[old_v]; ++j) {
2505 const int ve = g->
e[j];
2506 const int new_ve = translate_layer_fwd[ve];
2512 g->
e[epos] = new_ve;
2517 g_old_v[old_v] = new_d;
2521 for (
int i = 0; i < g->
v_size; ++i) {
2522 const int old_v = i;
2523 const int new_v = translate_layer_fwd[i];
2530 colmap[new_v] = colmap[old_v];
2534 for (
int i = 0; i < g->
v_size; ++i) {
2535 const int old_v = i;
2536 const int new_v = translate_layer_fwd[i];
2538 g->
d[new_v] = g_old_v[old_v];
2559 g_old_v.reserve(g->
v_size);
2561 for (
int i = 0; i < g->
v_size; ++i) {
2562 g_old_v.push_back(g->
v[i]);
2567 int new_vsize = g->
v_size;
2571 for (
int i = 0; i < g->
v_size; ++i) {
2572 const int old_v = i;
2573 const int new_v = old_v;
2578 for (
int j = g_old_v[old_v]; j < g_old_v[old_v] + g->
d[old_v]; ++j) {
2579 const int ve = g->
e[j];
2580 const int new_ve = ve;
2581 if (!del_e.
get(j)) {
2585 g->
e[epos] = new_ve;
2590 g->
d[new_v] = new_d;
2608 translate_layer_fwd.clear();
2609 translate_layer_bwd.clear();
2611 for (
size_t i = 0; i < backward_translation_layers[backward_translation_layers.size() - 1].size(); ++i)
2612 translate_layer_bwd.push_back(backward_translation_layers[backward_translation_layers.size() - 1][i]);
2617 for (
int i = 0; i < g->
v_size; ++i) {
2618 worklist_deg0[i] = colmap[i];
2620 translate_layer_fwd.push_back(cnt);
2621 const int translate_back = translate_layer_bwd[translate_layer_fwd.size() - 1];
2622 backward_translation_layers[backward_translation_layers.size() - 1][cnt] =
translate_back;
2627 translate_layer_fwd.push_back(-1);
2631 if (new_vsize == g->
v_size)
2634 if (new_vsize == 0 || new_vsize == 1) {
2640 g_old_v.reserve(g->
v_size);
2642 for (
int i = 0; i < g->
v_size; ++i) {
2643 g_old_v.push_back(g->
v[i]);
2646 backward_translation_layers[backward_translation_layers.size() - 1].resize(cnt);
2650 for (
int i = 0; i < g->
v_size; ++i) {
2651 const int old_v = i;
2652 const int new_v = translate_layer_fwd[old_v];
2657 for (
int j = g_old_v[old_v]; j < g_old_v[old_v] + g->
d[old_v]; ++j) {
2658 const int ve = g->
e[j];
2659 const int new_ve = translate_layer_fwd[ve];
2664 g->
e[epos] = new_ve;
2668 if (add_edge_buff_act.
get(old_v)) {
2669 while (!add_edge_buff[old_v].empty()) {
2670 const int edge_to_old = add_edge_buff[old_v].back();
2671 add_edge_buff[old_v].pop_back();
2675 const int edge_to_new = translate_layer_fwd[edge_to_old];
2681 g->
e[epos] = edge_to_new;
2685 g_old_v[old_v] = new_d;
2689 for (
int i = 0; i < g->
v_size; ++i) {
2690 const int old_v = i;
2691 const int new_v = translate_layer_fwd[i];
2693 g->
d[new_v] = g_old_v[old_v];
2700 for (
int i = 0; i < g->
v_size; ++i) {
2701 const int old_v = i;
2703 const int new_v = translate_layer_fwd[i];
2709 colmap[new_v] = worklist_deg0[old_v];
2715 for (
int i = 0; i < g->
v_size; ++i) {
2721 for (
int i = 0; i < g->
e_size; ++i) {
2726 add_edge_buff_act.
reset();
2734 void perform_del_add_edge_general(
dejavu::sgraph *g,
int *colmap) {
2741 translate_layer_fwd.clear();
2742 translate_layer_bwd.clear();
2744 for (
size_t i = 0; i < backward_translation_layers[backward_translation_layers.size() - 1].size(); ++i)
2745 translate_layer_bwd.push_back(backward_translation_layers[backward_translation_layers.size() - 1][i]);
2750 for (
int i = 0; i < g->
v_size; ++i) {
2751 worklist_deg0[i] = colmap[i];
2753 translate_layer_fwd.push_back(cnt);
2754 const int translate_back = translate_layer_bwd[translate_layer_fwd.size() - 1];
2755 backward_translation_layers[backward_translation_layers.size() - 1][cnt] =
translate_back;
2760 translate_layer_fwd.push_back(-1);
2764 if (new_vsize == g->
v_size)
2767 if (new_vsize == 0 || new_vsize == 1) {
2773 g_old_v.reserve(g->
v_size);
2775 for (
int i = 0; i < g->
v_size; ++i) {
2776 g_old_v.push_back(g->
v[i]);
2778 for (
int i = 0; i < g->
e_size; ++i) {
2779 g_old_e.push_back(g->
e[i]);
2782 backward_translation_layers[backward_translation_layers.size() - 1].resize(cnt);
2786 for (
int i = 0; i < g->
v_size; ++i) {
2787 const int old_v = i;
2788 const int new_v = translate_layer_fwd[old_v];
2793 for (
int j = g_old_v[old_v]; j < g_old_v[old_v] + g->
d[old_v]; ++j) {
2794 const int ve = g_old_e[j];
2795 const int new_ve = translate_layer_fwd[ve];
2800 g->
e[epos] = new_ve;
2804 if (add_edge_buff_act.
get(old_v)) {
2805 while (!add_edge_buff[old_v].empty()) {
2806 const int edge_to_old = add_edge_buff[old_v].back();
2807 add_edge_buff[old_v].pop_back();
2811 const int edge_to_new = translate_layer_fwd[edge_to_old];
2817 g->
e[epos] = edge_to_new;
2821 g_old_v[old_v] = new_d;
2825 for (
int i = 0; i < g->
v_size; ++i) {
2826 const int old_v = i;
2827 const int new_v = translate_layer_fwd[i];
2829 g->
d[new_v] = g_old_v[old_v];
2836 for (
int i = 0; i < g->
v_size; ++i) {
2837 const int old_v = i;
2839 const int new_v = translate_layer_fwd[i];
2845 colmap[new_v] = worklist_deg0[old_v];
2851 for (
int i = 0; i < g->
v_size; ++i) {
2857 for (
int i = 0; i < g->
e_size; ++i) {
2862 add_edge_buff_act.
reset();
2867 void mark_discrete_for_deletion(
dejavu::sgraph *g,
int *colmap) {
2869 worklist_deg0.reset();
2871 worklist_deg0.push_back(0);
2873 for (
int i = 0; i < g->
v_size; ++i) {
2875 worklist_deg0[colmap[i]]++;
2877 for (
int i = 0; i < g->
v_size; ++i) {
2878 if (worklist_deg0[colmap[i]] == 1)
2881 worklist_deg0.reset();
2889 int discrete_cnt = 0;
2890 worklist_deg0.reset();
2892 worklist_deg0.push_back(0);
2894 for (
int i = 0; i < g->
v_size; ++i) {
2896 worklist_deg0[colmap[i]]++;
2898 for (
int i = 0; i < g->
v_size; ++i) {
2899 discrete_cnt += (worklist_deg0[colmap[i]] == 1);
2901 if (discrete_cnt == g->
v_size) {
2906 if (discrete_cnt == 0) {
2912 translate_layer_fwd.clear();
2913 translate_layer_bwd.clear();
2915 for (
size_t i = 0; i < backward_translation_layers[backward_translation_layers.size() - 1].size(); ++i)
2916 translate_layer_bwd.push_back(backward_translation_layers[backward_translation_layers.size() - 1][i]);
2918 g_old_v.reserve(g->
v_size);
2920 for (
int i = 0; i < g->
v_size; ++i) {
2921 g_old_v.push_back(g->
v[i]);
2927 for (
int i = 0; i < g->
v_size; ++i) {
2928 if (worklist_deg0[colmap[i]] != 1) {
2929 translate_layer_fwd.push_back(cnt);
2930 const int translate_back = translate_layer_bwd[translate_layer_fwd.size() - 1];
2931 backward_translation_layers[backward_translation_layers.size() - 1][cnt] =
translate_back;
2935 translate_layer_fwd.push_back(-1);
2939 backward_translation_layers[backward_translation_layers.size() - 1].resize(cnt);
2943 for (
int i = 0; i < g->
v_size; ++i) {
2944 const int old_v = i;
2945 const int new_v = translate_layer_fwd[i];
2951 for (
int j = g_old_v[old_v]; j < g_old_v[old_v] + g->
d[old_v]; ++j) {
2952 const int ve = g->
e[j];
2953 const int new_ve = ve>=0?translate_layer_fwd[ve]:-1;
2959 g->
e[epos] = new_ve;
2964 g_old_v[old_v] = new_d;
2968 for (
int i = 0; i < g->
v_size; ++i) {
2969 const int old_v = i;
2970 const int new_v = translate_layer_fwd[i];
2977 colmap[new_v] = colmap[old_v];
2981 for (
int i = 0; i < g->
v_size; ++i) {
2982 const int old_v = i;
2983 const int new_v = translate_layer_fwd[i];
2985 g->
d[new_v] = g_old_v[old_v];
2999 void pre_hook(
int,
const int *_aut,
int _supp,
const int *_aut_supp,
dejavu_hook* hook) {
3003 automorphism_supp.
reset();
3005 bool use_aux_auto =
false;
3007 for (
int i = 0; i < _supp; ++i) {
3008 const int v_from = _aut_supp[i];
3010 const int v_to = _aut[v_from];
3020 const bool added_vertex = !recovery_strings[orig_v_from].empty() &&
3021 recovery_strings[orig_v_from][0] == INT32_MAX;
3023 dej_assert(automorphism[orig_v_from] == orig_v_from || added_vertex);
3026 automorphism[orig_v_from] = orig_v_to;
3027 automorphism_supp.
push_back(orig_v_from);
3029 dej_assert(recovery_strings[orig_v_to].size() == 1);
3032 dej_assert(recovery_strings[orig_v_to].size() == recovery_strings[orig_v_from].size());
3034 for (
size_t j = 0; j < recovery_strings[orig_v_to].size(); ++j) {
3035 const int v_from_t = recovery_strings[orig_v_from][j];
3036 const int v_to_t = recovery_strings[orig_v_to][j];
3037 dej_assert((v_from_t == INT32_MAX) == (v_to_t == INT32_MAX));
3038 if(v_from_t == INT32_MAX)
continue;
3044 if(v_from_t >= 0 && v_to_t >= 0) {
3045 dej_assert(automorphism[v_from_t] == v_from_t);
3046 automorphism[v_from_t] = v_to_t;
3049 const int abs_v_from_t = abs(v_from_t);
3050 const int abs_v_to_t = abs(v_to_t);
3052 dej_assert(aux_automorphism[abs_v_from_t] == abs_v_from_t);
3053 aux_automorphism[abs_v_from_t] = abs_v_to_t;
3054 aux_automorphism_supp.
push_back(abs_v_from_t);
3056 use_aux_auto =
true;
3062 for(
int i = 0; i < aux_automorphism_supp.
cur_pos; ++i) {
3063 const int v_from = aux_automorphism_supp[i];
3064 before_move[v_from] = automorphism[aux_automorphism[v_from]];
3066 for(
int i = 0; i < aux_automorphism_supp.
cur_pos; ++i) {
3067 const int v_from = aux_automorphism_supp[i];
3068 if(automorphism[v_from] == v_from) {
3071 dej_assert(automorphism[v_from] != before_move[v_from]);
3072 automorphism[v_from] = before_move[v_from];
3074 reset_automorphism(aux_automorphism.
get_array(), aux_automorphism_supp.
cur_pos,
3076 aux_automorphism_supp.
reset();
3079 const int end_pos = automorphism_supp.
cur_pos;
3081 if(!recovery_edge_attached.empty()) {
3082 for (
int i = 0; i < end_pos; ++i) {
3083 recovery_attached_edges_to_automorphism(automorphism_supp[i], automorphism.
get_array(),
3084 &automorphism_supp, &aux_automorphism, &before_move);
3091 automorphism_supp.
reset();
3098 if(hook ==
nullptr) {
3102 meld_translation_layers();
3106 automorphism_supp.
reset();
3107 bool use_aux_auto =
false;
3110 for (
int i = 0; i < _supp; ++i) {
3111 const int _v_from = _aut_supp[i];
3112 const int v_from = decomposer==
nullptr?_v_from:decomposer->
map_back(current_component, _v_from);
3114 const int orig_v_from = backward_translation[v_from];
3115 const int _v_to = _aut[_v_from];
3116 const int v_to = decomposer==
nullptr?_v_to:decomposer->
map_back(current_component, _v_to);
3118 const int orig_v_to = backward_translation[v_to];
3119 dej_assert((
unsigned int)v_from < backward_translation.size());
3121 dej_assert((
unsigned int)v_to < backward_translation.size());
3127 dej_assert(automorphism[orig_v_from] == orig_v_from);
3128 const int to_recovery_string_start_pt = baked_recovery_string_pt[v_to].first;
3129 const int to_recovery_string_end_pt = baked_recovery_string_pt[v_to].second;
3130 const int to_recovery_string_size = to_recovery_string_end_pt - to_recovery_string_start_pt;
3131 const int from_recovery_string_start_pt = baked_recovery_string_pt[v_from].first;
3132 if(to_recovery_string_size == 0 || baked_recovery_string[to_recovery_string_start_pt] != INT32_MAX) {
3133 automorphism[orig_v_from] = orig_v_to;
3134 automorphism_supp.
push_back(orig_v_from);
3137 dej_assert((baked_recovery_string_pt[v_from].second - from_recovery_string_start_pt) ==
3138 to_recovery_string_size);
3140 for (
int j = 0; j < to_recovery_string_size; ++j) {
3141 const int v_from_t = baked_recovery_string[from_recovery_string_start_pt + j];
3142 const int v_to_t = baked_recovery_string[to_recovery_string_start_pt + j];
3144 if(v_from_t == INT32_MAX)
continue;
3155 if(v_from_t >= 0 && v_to_t >= 0) {
3156 dej_assert(automorphism[v_from_t] == v_from_t);
3157 automorphism[v_from_t] = v_to_t;
3160 const int abs_v_from_t = abs(v_from_t);
3161 const int abs_v_to_t = abs(v_to_t);
3163 aux_automorphism[abs_v_from_t] = abs_v_to_t;
3164 aux_automorphism_supp.
push_back(abs_v_from_t);
3166 use_aux_auto =
true;
3171 for (
int i = 0; i < _n; ++i) {
3172 const int _v_from = i;
3173 const int v_from = decomposer==
nullptr?_v_from:decomposer->
map_back(current_component, _v_from);
3174 const int orig_v_from = backward_translation[v_from];
3175 const int _v_to = _aut[_v_from];
3176 const int v_to = decomposer==
nullptr?_v_to:decomposer->
map_back(current_component, _v_to);
3179 const int orig_v_to = backward_translation[v_to];
3180 dej_assert((
unsigned int)v_from < backward_translation.size());
3182 dej_assert((
unsigned int)v_to < backward_translation.size());
3188 dej_assert(automorphism[orig_v_from] == orig_v_from);
3190 const int to_recovery_string_start_pt = baked_recovery_string_pt[v_to].first;
3191 const int to_recovery_string_end_pt = baked_recovery_string_pt[v_to].second;
3192 const int to_recovery_string_size = to_recovery_string_end_pt - to_recovery_string_start_pt;
3193 const int from_recovery_string_start_pt = baked_recovery_string_pt[v_from].first;
3195 if(to_recovery_string_size == 0 || baked_recovery_string[to_recovery_string_start_pt] != INT32_MAX) {
3196 automorphism[orig_v_from] = orig_v_to;
3197 automorphism_supp.
push_back(orig_v_from);
3200 dej_assert((baked_recovery_string_pt[v_from].second - from_recovery_string_start_pt) ==
3201 to_recovery_string_size);
3203 for (
int j = 0; j < to_recovery_string_size; ++j) {
3204 const int v_from_t = baked_recovery_string[from_recovery_string_start_pt + j];
3205 const int v_to_t = baked_recovery_string[to_recovery_string_start_pt + j];
3207 if(v_from_t == INT32_MAX)
continue;
3213 if(v_from_t >= 0 && v_to_t >= 0) {
3214 dej_assert(automorphism[v_from_t] == v_from_t);
3215 automorphism[v_from_t] = v_to_t;
3218 const int abs_v_from_t = abs(v_from_t);
3219 const int abs_v_to_t = abs(v_to_t);
3221 aux_automorphism[abs_v_from_t] = abs_v_to_t;
3222 aux_automorphism_supp.
push_back(abs_v_from_t);
3224 use_aux_auto =
true;
3231 for(
int i = 0; i < aux_automorphism_supp.
cur_pos; ++i) {
3232 const int v_from = aux_automorphism_supp[i];
3233 before_move[v_from] = automorphism[aux_automorphism[v_from]];
3235 for(
int i = 0; i < aux_automorphism_supp.
cur_pos; ++i) {
3236 const int v_from = aux_automorphism_supp[i];
3237 if(automorphism[v_from] == v_from)
3239 automorphism[v_from] = before_move[v_from];
3241 reset_automorphism(aux_automorphism.
get_array(), aux_automorphism_supp.
cur_pos,
3243 aux_automorphism_supp.
reset();
3246 const int end_pos = automorphism_supp.
cur_pos;
3248 if(edge_attached_information > 0) {
3249 for (
int i = 0; i < end_pos; ++i) {
3250 recovery_attached_edges_to_automorphism(automorphism_supp[i], automorphism.
get_array(),
3251 &automorphism_supp, &aux_automorphism, &before_move);
3255 if(hook !=
nullptr) {
3259 automorphism_supp.
reset();
3266 if (!ir_quotient_component_init) {
3268 ir_quotient_component_init =
true;
3273 void del_discrete_edges_inplace(
dejavu::sgraph *g, coloring *col) {
3275 int discrete_vert = 0;
3277 for (
int i = 0; i < col->domain_size;) {
3278 const int col_sz = col->ptn[i];
3281 del.
set(col->lab[i]);
3286 for (
int v = 0; v < g->
v_size; ++v) {
3288 dej_assert(col->ptn[col->vertex_to_col[v]] == 0);
3289 rem_edges += g->
d[v];
3294 for (
int n = g->
v[v]; n < g->
v[v] + g->
d[v];) {
3295 const int neigh = g->
e[n];
3297 if (del.
get(neigh)) {
3298 const int swap_neigh = g->
e[g->
v[v] + g->
d[v] - 1];
3300 g->
e[n] = swap_neigh;
3312 bool in_order =
true;
3313 for(
int i = 0; i < g->
v_size-1 && in_order; ++i) in_order = in_order && (colmap[i] <= colmap[i+1]);
3322 std::memcpy(old_arr.get_array(), g->
v, g->
v_size*
sizeof(
int));
3323 for(
int j = 0; j < g->
v_size; ++j) {
3324 g->
v[j] = old_arr[c.lab[j]];
3327 std::memcpy(old_arr.get_array(), g->
d, g->
v_size*
sizeof(
int));
3328 for(
int j = 0; j < g->
v_size; ++j) {
3329 old_arr[j] = g->
d[j];
3331 for(
int j = 0; j < g->
v_size; ++j) {
3332 g->
d[j] = old_arr[c.lab[j]];
3336 for(
int i = 0; i < g->
v_size; ++i) {
3337 colmap[i] = c.vertex_to_col[c.lab[i]];
3340 for(
int i = 0; i < g->
v_size; ++i) {
3341 const int map_to = c.lab[i];
3342 old_arr[map_to] = i;
3345 for(
int j = 0; j < g->
e_size; ++j) {
3346 g->
e[j] = old_arr[g->
e[j]];
3349 dej_assert((
int)backward_translation_layers[backward_translation_layers.size() - 1].size() == g->
v_size);
3350 for(
int i = 0; i < g->
v_size; ++i) {
3351 old_arr[i] = backward_translation_layers[backward_translation_layers.size() - 1][i];
3354 for(
int i = 0; i < g->
v_size; ++i) {
3355 backward_translation_layers[backward_translation_layers.size() - 1][i] = old_arr[c.lab[i]];
3383 const std::vector<preop> default_schedule =
3384 {deg01, qcedgeflip, deg01, twins, deg2ma, deg2ue, densify2};
3388 if(schedule ==
nullptr) schedule = &default_schedule;
3393 save_preprocessor =
this;
3398 const int test_d = g->
d[0];
3400 for (k = 0; k < (g->
v_size) && (g->
d[k] == test_d); ++k);
3402 int test_col = colmap[0];
3404 for (l = 1; l < (g->
v_size) && (colmap[l] == test_col); ++l);
3408 skipped_preprocessing =
true;
3413 backward_translation_layers.emplace_back();
3414 const size_t back_ind = backward_translation_layers.size() - 1;
3415 translation_layers.emplace_back();
3416 backward_translation_layers[back_ind].reserve(g->
v_size);
3417 for (
int i = 0; i < g->
v_size; ++i) backward_translation_layers[back_ind].push_back(i);
3420 if(g->
v_size > 64) order_according_to_color(g, colmap);
3421 else order_edgelist(g);
3425 const int pre_v_size = g->
v_size;
3426 const int pre_e_size = g->
e_size;
3427 const int pre_cells = c.cells;
3430 if(R1 ==
nullptr) R1 = &R_stack;
3433 const bool color_refinement_effective = pre_cells != c.cells;
3435 if (c.cells == g->
v_size) {
3443 add_edge_buff.clear();
3446 add_edge_buff.emplace_back();
3449 translate_layer_fwd.reserve(g->
v_size);
3452 for (
int i = 0; i < g->
v_size; ++i) {
3457 for (
int i = 0; i < g->
v_size; ++i) {
3463 for (
int i = 0; i < g->
v_size; ++i)
3464 _automorphism[i] = i;
3468 worklist_deg0.allocate(g->
v_size);
3469 worklist_deg1.allocate(g->
v_size);
3477 recovery_strings.reserve(g->
v_size);
3478 for (
int j = 0; j <
domain_size; ++j) recovery_strings.emplace_back();
3481 del_discrete_edges_inplace(g, &c);
3483 bool has_deg_0 =
false;
3484 bool has_deg_1 =
false;
3485 bool has_deg_2 =
false;
3486 bool has_discrete =
false;
3487 bool graph_changed =
false;
3491 int count_discrete = 0;
3493 for (
int i = 0; i < c.domain_size;) {
3494 const int v = c.lab[i];
3495 const int col_sz = c.ptn[i] + 1;
3498 count_deg0 += col_sz;
3501 count_deg1 += col_sz;
3504 count_deg2 += col_sz;
3509 count_discrete += (col_sz == 1);
3512 copy_coloring_to_colmap(&c, colmap);
3516 has_deg_0 = (count_deg0 > 4);
3517 has_deg_1 = (count_deg1 > 8);
3518 has_deg_2 = (count_deg2 > 128);
3519 has_discrete = (count_discrete > 4);
3521 if(!has_deg_0 && !has_deg_1 && !has_deg_2 && !has_discrete)
return;
3523 if (schedule !=
nullptr) {
3527 for (
size_t pc = 0; pc < schedule->size(); ++pc) {
3531 preop next_op = (*schedule)[pc];
3532 const int pre_v = g->
v_size;
3533 const int pre_e = g->
e_size;
3535 case preop::deg01: {
3536 if(!has_deg_0 && !has_deg_1 && !has_discrete && !graph_changed)
break;
3537 red_deg10_assume_cref(g, colmap, hook);
3538 perform_del(g, colmap);
3541 if(!(g->
v_size == pre_v_size && g->
e_size == pre_e_size && !color_refinement_effective)) {
3542 order_according_to_color(g, colmap);
3548 case preop::deg2ma: {
3549 if(!has_deg_2 && !graph_changed)
break;
3550 red_deg2_path_size_1(g, colmap);
3551 perform_del_add_edge(g, colmap);
3558 case preop::twins: {
3561 const int s_twins_true = twins_partition_refinement(g, colmap, hook,
false);
3562 if(s_twins_true > 0) perform_del(g, colmap);
3563 const int s_twins_false = twins_partition_refinement(g, colmap, hook,
true);
3564 if(s_twins_false > 0) perform_del(g, colmap);
3565 const int s_twins = s_twins_true + s_twins_false;
3571 copy_coloring_to_colmap(&c, colmap);
3576 if(s_twins >= 16) pc = 0;
3582 case preop::deg2ue: {
3583 if(!has_deg_2 && !graph_changed)
break;
3585 has_discrete = red_deg2_color_cycles(g, colmap);
3587 red_deg2_unique_endpoint(g, colmap);
3588 perform_del_add_edge(g, colmap);
3590 red_deg2_trivial_connect(g, colmap);
3591 perform_del_add_edge(g, colmap);
3593 perform_del_discrete(g, colmap);
3600 case preop::densify2: {
3601 if(!has_deg_2 && !graph_changed)
break;
3602 red_deg2_densify(g, colmap);
3603 perform_del_add_edge_general(g, colmap);
3605 red_deg2_densifysc1(g, colmap);
3606 perform_del_add_edge_general(g, colmap);
3612 case preop::qcedgeflip: {
3613 red_quotient_edge_flip(g, colmap);
3614 perform_del_edge(g);
3620 graph_changed = graph_changed || pre_v != g->
v_size || pre_e != g->
e_size;
3632#if defined(BLISS_VERSION_MAJOR) && defined(BLISS_VERSION_MINOR)
3633#if ( BLISS_VERSION_MAJOR >= 1 || BLISS_VERSION_MINOR >= 76 )
3634 void bliss_hook(
unsigned int n,
const unsigned int *aut) {
3635 auto p = save_preprocessor;
3639 static inline void bliss_hook(
void *user_param,
unsigned int n,
const unsigned int *aut) {
3641 p->pre_hook_buffered(n, (
const int *) aut, -1,
nullptr, p->saved_hook);
3645 static inline void bliss_hook(
void *user_param,
unsigned int n,
const unsigned int *aut) {
3647 p->pre_hook_buffered(n, (
const int *) aut, -1,
nullptr, p->saved_hook);
3652 auto p = save_preprocessor;
3657 save_preprocessor =
this;
3661 static inline void nauty_hook(
int,
int* aut,
int*,
int,
int,
int n) {
3662 auto p = save_preprocessor;
3667 save_preprocessor =
this;
3671 static inline int saucy_hook(
int n,
const int* aut,
int nsupp,
int* supp,
void* user_param) {
3673 p->pre_hook_buffered(n, (
const int *) aut, nsupp, supp, p->saved_hook);
3678 static inline void _dejavu_hook(
int n,
const int* aut,
int nsupp,
const int* supp) {
3679 auto p = save_preprocessor;
3680 if(p->skipped_preprocessing && !p->decomposer) {
3681 if(p->saved_hook !=
nullptr) {
3682 (*p->saved_hook)(n, aut, nsupp, supp);
void multiply(int number)
Vertex coloring for a graph.
Set specialized for quick resets.
void initialize(int size)
Decomposes graphs and manages decomposition information.
int map_back(int component, int vertex)
Color refinement and related algorithms.
void refine_coloring_first(sgraph *g, coloring *c, int init_color_class=-1)
preprocessor for symmetry detection
static void nauty_hook(int, int *aut, int *, int, int, int n)
static void traces_hook(int, int *aut, int n)
preprocessor(dejavu::ir::refinement *R)
void multiply_to_group_size(int n)
int translate_back(int v)
void inject_decomposer(dejavu::ir::graph_decomposer *new_decomposer, int component)
static int saucy_hook(int n, const int *aut, int nsupp, int *supp, void *user_param)
static void bliss_hook(void *user_param, unsigned int n, const unsigned int *aut)
void traces_save_my_preprocessor()
preprocessor(dejavu::timed_print *printer)
void reduce(dejavu::static_graph *g, dejavu_hook *hook, std::vector< preop > *schedule=nullptr)
dejavu::big_number grp_sz
static void _dejavu_hook(int n, const int *aut, int nsupp, const int *supp)
void nauty_save_my_preprocessor()
void reduce(dejavu::sgraph *g, int *colmap, dejavu_hook *hook, const std::vector< preop > *schedule=nullptr)
void save_my_hook(dejavu_hook *hook)
void pre_hook_buffered(int _n, const int *_aut, int _supp, const int *_aut_supp, dejavu_hook *hook)
Internal graph data structure.
void initialize_coloring(ds::coloring *c, int *vertex_to_col)
Graph with static number of vertices and edges.
dejavu::sgraph * get_sgraph()
Prints information to the console.
void timer_print(const std::string &proc, const std::string &p1, const std::string &p2)
void print_header() const
std::function< void(int, const int *, int, const int *)> dejavu_hook