2
Copyright (C) 2003-2006 Tommi Junttila
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License version 2
6
as published by the Free Software Foundation.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18
/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
26
#include "bliss_defs.hh"
27
#include "bliss_timer.hh"
28
#include "bliss_graph.hh"
29
#include "bliss_partition.hh"
30
#include <limits.h> // INT_MAX, etc
32
extern bool bliss_verbose;
33
extern FILE *bliss_verbstr;
37
static const bool should_not_happen = false;
39
/*-------------------------------------------------------------------------
41
* Constructor and destructor routines for the abstract graph class
43
*-------------------------------------------------------------------------*/
46
AbstractGraph::AbstractGraph()
48
/* Initialize stuff */
49
first_path_labeling = 0;
50
first_path_labeling_inv = 0;
51
best_path_labeling = 0;
52
best_path_labeling_inv = 0;
53
first_path_automorphism = 0;
54
best_path_automorphism = 0;
60
AbstractGraph::~AbstractGraph()
62
if(first_path_labeling) {
63
free(first_path_labeling); first_path_labeling = 0; }
64
if(first_path_labeling_inv) {
65
free(first_path_labeling_inv); first_path_labeling_inv = 0; }
66
if(best_path_labeling) {
67
free(best_path_labeling); best_path_labeling = 0; }
68
if(best_path_labeling_inv) {
69
free(best_path_labeling_inv); best_path_labeling_inv = 0; }
70
if(first_path_automorphism) {
71
free(first_path_automorphism); first_path_automorphism = 0; }
72
if(best_path_automorphism) {
73
free(best_path_automorphism); best_path_automorphism = 0; }
75
// free(certificate); certificate = 0; }
76
while(!long_prune_fixed.empty())
78
delete long_prune_fixed.back();
79
long_prune_fixed.pop_back();
81
while(!long_prune_mcrs.empty())
83
delete long_prune_mcrs.back();
84
long_prune_mcrs.pop_back();
92
/*-------------------------------------------------------------------------
94
* Routines for refinement to equitable partition
96
*-------------------------------------------------------------------------*/
99
void AbstractGraph::refine_to_equitable()
101
assert(p.splitting_queue.is_empty());
103
for(Cell *cell = p.first_cell; cell; cell = cell->next)
105
p.add_in_splitting_queue(cell);
108
return do_refine_to_equitable();
112
void AbstractGraph::refine_to_equitable(Cell *cell1)
114
DEBUG_ASSERT(cell1->length == 1);
116
#ifdef EXPENSIVE_CONSISTENCY_CHECKS
117
for(Cell *cell = p.first_cell; cell; cell = cell->next) {
118
assert(cell->in_splitting_queue == false);
119
assert(cell->in_neighbour_heap == false);
123
assert(p.splitting_queue.is_empty());
125
p.add_in_splitting_queue(cell1);
127
return do_refine_to_equitable();
131
void AbstractGraph::refine_to_equitable(Cell *cell1, Cell *cell2)
133
DEBUG_ASSERT(cell1->length == 1);
134
DEBUG_ASSERT(cell2->length == 1);
136
#ifdef EXPENSIVE_CONSISTENCY_CHECKS
137
for(Cell *cell = p.first_cell; cell; cell = cell->next) {
138
assert(cell->in_splitting_queue == false);
139
assert(cell->in_neighbour_heap == false);
143
assert(p.splitting_queue.is_empty());
145
p.add_in_splitting_queue(cell1);
146
p.add_in_splitting_queue(cell2);
148
return do_refine_to_equitable();
152
void AbstractGraph::do_refine_to_equitable()
154
assert(!p.splitting_queue.is_empty());
155
assert(neighbour_heap.is_empty());
159
while(!p.splitting_queue.is_empty())
161
Cell *cell = p.splitting_queue.pop_front();
162
DEBUG_ASSERT(cell->in_splitting_queue);
163
cell->in_splitting_queue = false;
165
if(cell->length == 1)
168
if(first_path_automorphism) {
169
/* Build the (potential) automorphism on-the-fly */
170
assert(first_path_labeling_inv);
171
first_path_automorphism[first_path_labeling_inv[cell->first]] =
172
p.elements[cell->first];
174
if(best_path_automorphism)
176
/* Build the (potential) automorphism on-the-fly */
177
assert(best_path_labeling_inv);
178
best_path_automorphism[best_path_labeling_inv[cell->first]] =
179
p.elements[cell->first];
183
bool worse = split_neighbourhood_of_unit_cell(cell);
184
if(in_search && worse)
189
split_neighbourhood_of_cell(cell);
193
eqref_worse_than_certificate = false;
197
/* Clear splitting_queue */
198
p.clear_splitting_queue();
199
eqref_worse_than_certificate = true;
207
/*-------------------------------------------------------------------------
209
* Routines for handling the canonical labeling
211
*-------------------------------------------------------------------------*/
214
void AbstractGraph::update_labeling(unsigned int * const labeling)
216
const unsigned int N = get_nof_vertices();
217
unsigned int *ep = p.elements;
218
for(unsigned int i = 0; i < N; i++, ep++)
223
void AbstractGraph::update_labeling_and_its_inverse(unsigned int * const labeling,
224
unsigned int * const labeling_inv)
226
const unsigned int N = get_nof_vertices();
227
unsigned int *ep = p.elements;
228
unsigned int *clip = labeling_inv;
230
for(unsigned int i = 0; i < N; ) {
241
/*-------------------------------------------------------------------------
243
* Routines for handling automorphisms
245
*-------------------------------------------------------------------------*/
248
void AbstractGraph::reset_permutation(unsigned int *perm)
250
const unsigned int N = get_nof_vertices();
251
for(unsigned int i = 0; i < N; i++, perm++)
256
bool AbstractGraph::is_automorphism(unsigned int * const perm)
258
assert(should_not_happen);
266
/*-------------------------------------------------------------------------
270
*-------------------------------------------------------------------------*/
272
void AbstractGraph::long_prune_init()
274
const unsigned int N = get_nof_vertices();
275
long_prune_temp.clear();
276
long_prune_temp.resize(N);
278
for(unsigned int i = 0; i < N; i++)
279
assert(long_prune_temp[i] == false);
281
const unsigned int nof_fitting_in_max_mem =
282
(long_prune_options_max_mem * 1024 * 1024) / (((N * 2) / 8)+1);
283
long_prune_max_stored_autss = long_prune_options_max_stored_auts;
284
/* Had some problems with g++ in using (a<b)?a:b when constants involved,
285
so had to make this in a stupid way...*/
286
if(nof_fitting_in_max_mem < long_prune_options_max_stored_auts)
287
long_prune_max_stored_autss = nof_fitting_in_max_mem;
289
while(!long_prune_fixed.empty())
291
delete long_prune_fixed.back();
292
long_prune_fixed.pop_back();
294
while(!long_prune_mcrs.empty())
296
delete long_prune_mcrs.back();
297
long_prune_mcrs.pop_back();
299
for(unsigned int i = 0; i < long_prune_max_stored_autss; i++)
301
long_prune_fixed.push_back(new std::vector<bool>(N));
302
long_prune_mcrs.push_back(new std::vector<bool>(N));
304
long_prune_begin = 0;
308
void AbstractGraph::long_prune_swap(const unsigned int i, const unsigned int j)
310
assert(long_prune_begin <= long_prune_end);
311
assert(long_prune_end - long_prune_end <= long_prune_max_stored_autss);
312
assert(i >= long_prune_begin);
313
assert(i < long_prune_end);
314
assert(j >= long_prune_begin);
315
assert(j < long_prune_end);
316
const unsigned int real_i = i % long_prune_max_stored_autss;
317
const unsigned int real_j = j % long_prune_max_stored_autss;
318
std::vector<bool> * tmp = long_prune_fixed[real_i];
319
long_prune_fixed[real_i] = long_prune_fixed[real_j];
320
long_prune_fixed[real_j] = tmp;
321
tmp = long_prune_mcrs[real_i];
322
long_prune_mcrs[real_i] = long_prune_mcrs[real_j];
323
long_prune_mcrs[real_j] = tmp;
326
std::vector<bool> &AbstractGraph::long_prune_get_fixed(const unsigned int index)
328
assert(long_prune_begin <= long_prune_end);
329
assert(long_prune_end - long_prune_end <= long_prune_max_stored_autss);
330
assert(index >= long_prune_begin);
331
assert(index < long_prune_end);
332
return *long_prune_fixed[index % long_prune_max_stored_autss];
335
std::vector<bool> &AbstractGraph::long_prune_get_mcrs(const unsigned int index)
337
assert(long_prune_begin <= long_prune_end);
338
assert(long_prune_end - long_prune_end <= long_prune_max_stored_autss);
339
assert(index >= long_prune_begin);
340
assert(index < long_prune_end);
341
return *long_prune_mcrs[index % long_prune_max_stored_autss];
345
void AbstractGraph::long_prune_add_automorphism(const unsigned int *aut)
347
if(long_prune_max_stored_autss == 0)
350
const unsigned int N = get_nof_vertices();
353
assert(long_prune_temp.size() == N);
354
for(unsigned int i = 0; i < N; i++)
355
assert(long_prune_temp[i] == false);
358
DEBUG_ASSERT(long_prune_fixed.size() == long_prune_mcrs.size());
359
assert(long_prune_begin <= long_prune_end);
360
assert(long_prune_end - long_prune_end <= long_prune_max_stored_autss);
361
if(long_prune_end - long_prune_begin == long_prune_max_stored_autss)
366
std::vector<bool> &fixed = long_prune_get_fixed(long_prune_end-1);
367
std::vector<bool> &mcrs = long_prune_get_mcrs(long_prune_end-1);
369
for(unsigned int i = 0; i < N; i++)
371
fixed[i] = (aut[i] == i);
372
if(!long_prune_temp[i])
375
unsigned int j = aut[i];
379
long_prune_temp[j] = true;
387
long_prune_temp[i] = false;
392
for(unsigned int i = 0; i < N; i++)
393
assert(long_prune_temp[i] == false);
398
/*-------------------------------------------------------------------------
400
* Routines for handling orbit information
402
*-------------------------------------------------------------------------*/
405
void AbstractGraph::update_orbit_information(Orbit &o, const unsigned int *p)
407
const unsigned int N = get_nof_vertices();
408
for(unsigned int i = 0; i < N; i++)
410
o.merge_orbits(i, p[i]);
417
/*-------------------------------------------------------------------------
419
* Print a permutation in cycle notation
421
*-------------------------------------------------------------------------*/
424
void AbstractGraph::print_permutation(FILE *fp, const unsigned int *perm)
426
const unsigned int N = get_nof_vertices();
427
for(unsigned int i = 0; i < N; i++) {
428
unsigned int j = perm[i];
431
bool is_first = true;
441
fprintf(fp, "(%u,", i);
444
fprintf(fp, "%u", j);
457
/*-------------------------------------------------------------------------
459
* The actual backtracking search
461
*-------------------------------------------------------------------------*/
466
unsigned int split_cell_first;
467
unsigned int refinement_stack_size;
468
unsigned int certificate_index;
472
bool equal_to_first_path;
473
int cmp_to_best_path;
475
bool needs_long_prune;
476
unsigned int long_prune_begin;
477
std::set<unsigned int, std::less<unsigned int> > long_prune_redundant;
479
EqrefHash eqref_hash;
480
unsigned int subcertificate_length;
485
typedef struct t_path_info {
486
unsigned int splitting_element;
487
unsigned int certificate_index;
488
unsigned int subcertificate_length;
489
EqrefHash eqref_hash;
493
void AbstractGraph::search(const bool canonical, Stats &stats)
495
const unsigned int N = get_nof_vertices();
497
const bool write_automorphisms = 0;
499
unsigned int all_same_level = UINT_MAX;
506
remove_duplicate_edges();
509
* Reset search statistics
511
stats.group_size.assign(1);
513
stats.nof_leaf_nodes = 1;
514
stats.nof_bad_nodes = 0;
515
stats.nof_canupdates = 0;
516
stats.nof_generators = 0;
519
if(first_path_labeling)
521
free(first_path_labeling);
522
first_path_labeling = 0;
524
if(first_path_labeling_inv)
526
free(first_path_labeling_inv);
527
first_path_labeling_inv = 0;
529
if(first_path_automorphism)
531
free(first_path_automorphism);
532
first_path_automorphism = 0;
535
if(best_path_labeling)
537
free(best_path_labeling);
538
best_path_labeling = 0;
540
if(best_path_labeling_inv)
542
free(best_path_labeling_inv);
543
best_path_labeling_inv = 0;
545
if(best_path_automorphism)
547
free(best_path_automorphism);
548
best_path_automorphism = 0;
555
neighbour_heap.init(N);
564
make_initial_equitable_partition();
566
#if defined(VERIFY_EQUITABLEDNESS)
567
assert(is_equitable());
572
fprintf(bliss_verbstr, "Initial partition computed in %.2fs\n",
574
fflush(bliss_verbstr);
578
* Allocate space for the labelings
580
if(first_path_labeling)
581
free(first_path_labeling);
582
first_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));
583
if(best_path_labeling)
584
free(best_path_labeling);
585
best_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));
588
* Are there any non-singleton cells?
592
update_labeling(best_path_labeling);
596
//p.print_signature(stderr); fprintf(stderr, "\n");
599
* Allocate space for the inverses of the labelings
601
if(first_path_labeling_inv)
602
free(first_path_labeling_inv);
603
first_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));
604
if(best_path_labeling_inv)
605
free(best_path_labeling_inv);
606
best_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));
610
* Allocate space for the automorphisms
612
if(first_path_automorphism) free(first_path_automorphism);
613
first_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));
614
if(best_path_automorphism) free(best_path_automorphism);
615
best_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));
619
* Initialize orbit information
621
first_path_orbits.init(N);
622
best_path_orbits.init(N);
625
* Initialize certificate memory
627
initialize_certificate();
628
//assert(certificate);
629
assert(certificate_index == 0);
632
std::vector<LevelInfo> search_stack;
633
std::vector<PathInfo> first_path_info;
634
std::vector<PathInfo> best_path_info;
636
search_stack.clear();
637
p.refinement_stack.clean();
638
assert(neighbour_heap.is_empty());
641
* Initialize long prune
646
* Build the first level info
648
info.split_cell_first = find_next_cell_to_be_splitted(p.first_cell)->first;
649
info.split_element = -1;
650
info.refinement_stack_size = p.refinement_stack.size();
651
info.certificate_index = 0;
652
info.in_first_path = false;
653
info.in_best_path = false;
654
info.long_prune_begin = 0;
655
search_stack.push_back(info);
658
* Set status and global flags for search related procedures
661
refine_compare_certificate = false;
662
stats.nof_leaf_nodes = 0;
665
#ifdef PRINT_SEARCH_TREE_DOT
666
dotty_output = fopen("debug_stree.dot", "w");
667
fprintf(dotty_output, "digraph stree {\n");
668
fprintf(dotty_output, "\"n\" [label=\"");
669
fprintf(dotty_output, "M"); //p.print(dotty_output);
670
fprintf(dotty_output, "\"];\n");
673
p.consistency_check();
676
* The actual backtracking search
678
while(!search_stack.empty())
680
info = search_stack.back();
681
search_stack.pop_back();
683
p.consistency_check();
686
* Restore partition, certificate index, and split cell
688
p.unrefine(p.level, info.refinement_stack_size);
689
assert(info.certificate_index <= certificate_size);
690
certificate_index = info.certificate_index;
691
certificate_current_path.resize(certificate_index);
692
Cell * const cell = p.element_to_cell_map[p.elements[info.split_cell_first]];
693
assert(cell->length > 1);
695
p.consistency_check();
697
if(p.level > 0 && !info.in_first_path)
699
if(info.split_element == -1)
701
info.needs_long_prune = true;
703
else if(info.needs_long_prune)
705
info.needs_long_prune = false;
706
/* THIS IS A QUITE HORRIBLE HACK! */
707
unsigned int begin = (info.long_prune_begin>long_prune_begin)?info.long_prune_begin:long_prune_begin;
708
for(unsigned int i = begin; i < long_prune_end; i++)
710
const std::vector<bool> &fixed = long_prune_get_fixed(i);
711
bool fixes_all = true;
712
for(unsigned int l = 0; l < p.level; l++)
714
if(fixed[search_stack[l].split_element] == false)
722
long_prune_swap(begin, i);
724
info.long_prune_begin = begin;
727
const std::vector<bool> &mcrs = long_prune_get_mcrs(i);
728
unsigned int *ep = p.elements + cell->first;
729
for(unsigned int j = cell->length; j > 0; j--, ep++) {
730
if(mcrs[*ep] == false)
732
info.long_prune_redundant.insert(*ep);
740
* Find the next smallest element in cell
742
unsigned int next_split_element = UINT_MAX;
743
unsigned int *next_split_element_pos = 0;
744
unsigned int *ep = p.elements + cell->first;
745
if(info.in_first_path)
747
/* Find the next larger splitting element that is a mor */
748
for(unsigned int i = cell->length; i > 0; i--, ep++) {
749
if((int)(*ep) > info.split_element &&
750
*ep < next_split_element &&
751
first_path_orbits.is_minimal_representative(*ep)) {
752
next_split_element = *ep;
753
next_split_element_pos = ep;
757
else if(info.in_best_path)
759
/* Find the next larger splitting element that is a mor */
760
for(unsigned int i = cell->length; i > 0; i--, ep++) {
761
if((int)(*ep) > info.split_element &&
762
*ep < next_split_element &&
763
best_path_orbits.is_minimal_representative(*ep) &&
764
(info.long_prune_redundant.find(*ep) ==
765
info.long_prune_redundant.end())) {
766
next_split_element = *ep;
767
next_split_element_pos = ep;
773
/* Find the next larger splitting element */
774
for(unsigned int i = cell->length; i > 0; i--, ep++) {
775
if((int)(*ep) > info.split_element &&
776
*ep < next_split_element &&
777
(info.long_prune_redundant.find(*ep) ==
778
info.long_prune_redundant.end())) {
779
next_split_element = *ep;
780
next_split_element_pos = ep;
784
if(next_split_element == UINT_MAX)
787
* No more splitting elements (unexplored children) in the cell
789
/* Update group size if required */
790
if(info.in_first_path == true) {
791
const unsigned int index =
792
first_path_orbits.orbit_size(first_path_info[p.level].splitting_element);
793
stats.group_size.multiply(index);
795
* Update all_same_level
797
if(index == cell->length && all_same_level == p.level+1)
798
all_same_level = p.level;
801
"Level %u: orbits=%u, index=%u/%u, all_same_level=%u\n",
803
first_path_orbits.nof_orbits(),
809
/* Backtrack to the previous level */
814
/* Split on smallest */
815
info.split_element = next_split_element;
818
* Save the current search situation
820
search_stack.push_back(info);
823
* No more in the first path
825
info.in_first_path = false;
827
* No more in the best path
829
info.in_best_path = false;
833
if(p.level > stats.max_level)
834
stats.max_level = p.level;
836
p.consistency_check();
839
* Move the split element to be the last in the cell
841
*next_split_element_pos = p.elements[cell->first + cell->length - 1];
842
p.in_pos[*next_split_element_pos] = next_split_element_pos;
843
p.elements[cell->first + cell->length - 1] = next_split_element;
844
p.in_pos[next_split_element] = p.elements+ cell->first + cell->length -1;
846
* Split the cell in two:
847
* the last element in the cell (split element) forms a singleton cell
849
Cell * const new_cell = p.aux_split_in_two(cell, cell->length - 1);
850
p.element_to_cell_map[p.elements[new_cell->first]] = new_cell;
851
p.consistency_check();
854
const bool prev_equal_to_first_path = info.equal_to_first_path;
855
const int prev_cmp_to_best_path = info.cmp_to_best_path;
857
//assert(!(!info.equal_to_first_path && info.cmp_to_best_path < 0));
859
if(!first_path_info.empty())
861
refine_equal_to_first = info.equal_to_first_path;
862
if(refine_equal_to_first)
863
refine_first_path_subcertificate_end =
864
first_path_info[p.level-1].certificate_index +
865
first_path_info[p.level-1].subcertificate_length;
868
refine_cmp_to_best = info.cmp_to_best_path;
869
if(refine_cmp_to_best == 0)
870
refine_best_path_subcertificate_end =
871
best_path_info[p.level-1].certificate_index +
872
best_path_info[p.level-1].subcertificate_length;
875
refine_cmp_to_best = -1;
878
* Refine the new partition to equitable
880
if(cell->length == 1)
881
refine_to_equitable(cell, new_cell);
883
refine_to_equitable(new_cell);
885
p.consistency_check();
888
#ifdef PRINT_SEARCH_TREE_DOT
889
fprintf(dotty_output, "\"n");
890
for(unsigned int i = 0; i < search_stack.size(); i++) {
891
fprintf(dotty_output, "%u", search_stack[i].split_element);
892
if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
894
fprintf(dotty_output, "\"");
895
fprintf(dotty_output, " [label=\"");
896
fprintf(dotty_output, "%u",cell->first); /*p.print(dotty_output);*/
897
fprintf(dotty_output, "\"]");
898
if(!first_path_info.empty() && canonical && refine_cmp_to_best > 0) {
899
fprintf(dotty_output, "[color=green]");
901
fprintf(dotty_output, ";\n");
903
fprintf(dotty_output, "\"n");
904
for(unsigned int i = 0; i < search_stack.size() - 1; i++) {
905
fprintf(dotty_output, "%u", search_stack[i].split_element);
906
if(i < search_stack.size() - 2) fprintf(dotty_output, ".");
908
fprintf(dotty_output, "\" -> \"n");
909
for(unsigned int i = 0; i < search_stack.size(); i++) {
910
fprintf(dotty_output, "%u", search_stack[i].split_element);
911
if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
913
fprintf(dotty_output, "\" [label=\"%d\"];\n", next_split_element);
917
if(prev_cmp_to_best_path == 0 && refine_cmp_to_best < 0)
918
fprintf(stderr, "BP- ");
919
if(prev_cmp_to_best_path == 0 && refine_cmp_to_best > 0)
920
fprintf(stderr, "BP+ ");
925
/* Update statistics */
926
stats.nof_leaf_nodes++;
928
if(stats.nof_leaf_nodes % 100 == 0) {
929
fprintf(stdout, "Nodes: %lu, Leafs: %lu, Bad: %lu\n",
930
stats.nof_nodes, stats.nof_leaf_nodes,
931
stats.nof_bad_nodes);
937
if(!first_path_info.empty())
939
/* We are no longer on the first path */
940
assert(best_path_info.size() > 0);
941
assert(certificate_current_path.size() >= certificate_index);
942
const unsigned int subcertificate_length =
943
certificate_current_path.size() - certificate_index;
944
if(refine_equal_to_first)
946
/* Was equal to the first path so far */
947
assert(first_path_info.size() >= p.level);
948
PathInfo &first_pinfo = first_path_info[p.level-1];
949
assert(first_pinfo.certificate_index == certificate_index);
950
if(subcertificate_length != first_pinfo.subcertificate_length)
952
refine_equal_to_first = false;
954
else if(first_pinfo.eqref_hash.cmp(eqref_hash) != 0)
956
refine_equal_to_first = false;
959
if(canonical && (refine_cmp_to_best == 0))
961
/* Was equal to the best path so far */
962
assert(best_path_info.size() >= p.level);
963
PathInfo &best_pinfo = best_path_info[p.level-1];
964
assert(best_pinfo.certificate_index == certificate_index);
965
if(subcertificate_length < best_pinfo.subcertificate_length)
967
refine_cmp_to_best = -1;
968
//fprintf(stderr, "BSCL- ");
970
else if(subcertificate_length > best_pinfo.subcertificate_length)
972
refine_cmp_to_best = 1;
973
//fprintf(stderr, "BSCL+ ");
975
else if(best_pinfo.eqref_hash.cmp(eqref_hash) > 0)
977
refine_cmp_to_best = -1;
978
//fprintf(stderr, "BHL- ");
980
else if(best_pinfo.eqref_hash.cmp(eqref_hash) < 0)
982
refine_cmp_to_best = 1;
983
//fprintf(stderr, "BHL+ ");
986
if(refine_equal_to_first == false &&
987
(!canonical || (refine_cmp_to_best < 0)))
990
#ifdef PRINT_SEARCH_TREE_DOT
991
fprintf(dotty_output, "\"n");
992
for(unsigned int i = 0; i < search_stack.size(); i++) {
993
fprintf(dotty_output, "%u", search_stack[i].split_element);
994
if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
996
fprintf(dotty_output, "\" [color=red];\n");
998
stats.nof_bad_nodes++;
999
if(search_stack.back().equal_to_first_path == true &&
1000
p.level > all_same_level)
1002
assert(all_same_level >= 1);
1003
for(unsigned int i = all_same_level;
1004
i < search_stack.size();
1007
search_stack[i].equal_to_first_path = false;
1010
while(!search_stack.empty())
1013
LevelInfo &info2 = search_stack.back();
1014
if(!(info2.equal_to_first_path == false &&
1015
(!canonical || (info2.cmp_to_best_path < 0))))
1017
search_stack.pop_back();
1023
#if defined(VERIFY_EQUITABLEDNESS)
1024
/* The new partition should be equitable */
1025
assert(is_equitable());
1028
info.equal_to_first_path = refine_equal_to_first;
1029
info.cmp_to_best_path = refine_cmp_to_best;
1031
certificate_index = certificate_current_path.size();
1033
search_stack.back().eqref_hash = eqref_hash;
1034
search_stack.back().subcertificate_length =
1035
certificate_index - info.certificate_index;
1038
if(!p.is_discrete())
1041
* An internal, non-leaf node
1043
/* Build the next node info */
1044
/* Find the next cell to be splitted */
1045
assert(cell == p.element_to_cell_map[p.elements[info.split_cell_first]]);
1046
Cell * const next_split_cell = find_next_cell_to_be_splitted(cell);
1047
assert(next_split_cell);
1048
/* Copy current info to the search stack */
1049
search_stack.push_back(info);
1050
LevelInfo &new_info = search_stack.back();
1051
new_info.split_cell_first = next_split_cell->first;
1052
new_info.split_element = -1;
1053
new_info.certificate_index = certificate_index;
1054
new_info.refinement_stack_size = p.refinement_stack.size();
1055
new_info.long_prune_redundant.clear();
1056
new_info.long_prune_begin = info.long_prune_begin;
1063
assert(certificate_index == certificate_size);
1065
if(first_path_info.empty())
1067
/* The first path, update first_path and best_path */
1068
//fprintf(stdout, "Level %u: FIRST\n", p.level); fflush(stdout);
1069
stats.nof_canupdates++;
1071
* Update labelings and their inverses
1073
update_labeling_and_its_inverse(first_path_labeling,
1074
first_path_labeling_inv);
1075
update_labeling_and_its_inverse(best_path_labeling,
1076
best_path_labeling_inv);
1078
* Reset automorphism array
1080
reset_permutation(first_path_automorphism);
1081
reset_permutation(best_path_automorphism);
1083
* Reset orbit information
1085
first_path_orbits.reset();
1086
best_path_orbits.reset();
1090
stats.group_size.assign(1);
1092
* Reset all_same_level
1094
all_same_level = p.level;
1096
* Mark the current path to be the first and best one and save it
1098
const unsigned int base_size = search_stack.size();
1099
assert(p.level == base_size);
1100
best_path_info.clear();
1101
//fprintf(stdout, " New base is: ");
1102
for(unsigned int i = 0; i < base_size; i++) {
1103
search_stack[i].in_first_path = true;
1104
search_stack[i].in_best_path = true;
1105
search_stack[i].equal_to_first_path = true;
1106
search_stack[i].cmp_to_best_path = 0;
1108
path_info.splitting_element = search_stack[i].split_element;
1109
path_info.certificate_index = search_stack[i].certificate_index;
1110
path_info.eqref_hash = search_stack[i].eqref_hash;
1111
path_info.subcertificate_length = search_stack[i].subcertificate_length;
1112
first_path_info.push_back(path_info);
1113
best_path_info.push_back(path_info);
1114
//fprintf(stdout, "%u ", search_stack[i].split_element);
1116
//fprintf(stdout, "\n"); fflush(stdout);
1117
certificate_first_path = certificate_current_path;
1118
certificate_best_path = certificate_current_path;
1120
refine_compare_certificate = true;
1122
* Backtrack to the previous level
1128
DEBUG_ASSERT(first_path_info.size() > 0);
1130
//fprintf(stdout, "Level %u: LEAF %d %d\n", p.level, info.equal_to_first_path, info.cmp_to_best_path); fflush(stdout);
1132
if(info.equal_to_first_path)
1135
* An automorphism found: aut[i] = elements[first_path_labeling[i]]
1137
assert(!info.in_first_path);
1138
//fprintf(stdout, "A"); fflush(stdout);
1140
#ifdef PRINT_SEARCH_TREE_DOT
1141
fprintf(dotty_output, "\"n");
1142
for(unsigned int i = 0; i < search_stack.size(); i++) {
1143
fprintf(dotty_output, "%u", search_stack[i].split_element);
1144
if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
1146
fprintf(dotty_output, "\" [color=blue];\n");
1150
/* Verify that the automorphism is correctly built */
1151
for(unsigned int i = 0; i < N; i++)
1152
assert(first_path_automorphism[i] ==
1153
p.elements[first_path_labeling[i]]);
1156
#if defined(VERIFY_AUTOMORPHISMS)
1157
/* Verify that it really is an automorphism */
1158
assert(is_automorphism(first_path_automorphism));
1161
long_prune_add_automorphism(first_path_automorphism);
1164
* Update orbit information
1166
update_orbit_information(first_path_orbits, first_path_automorphism);
1169
* Compute backjumping level
1171
unsigned int backjumping_level = 0;
1172
for(unsigned int i = search_stack.size(); i > 0; i--) {
1173
const unsigned int split_element =
1174
search_stack[backjumping_level].split_element;
1175
if(first_path_automorphism[split_element] != split_element)
1177
backjumping_level++;
1179
assert(backjumping_level < p.level);
1181
* Go back to backjumping_level
1183
p.level = backjumping_level;
1184
search_stack.resize(p.level + 1);
1186
if(write_automorphisms)
1188
print_permutation(stdout, first_path_automorphism);
1189
fprintf(stdout, "\n");
1191
stats.nof_generators++;
1196
assert(info.cmp_to_best_path >= 0);
1197
if(info.cmp_to_best_path > 0)
1200
* A new, better representative found
1202
//fprintf(stdout, "Level %u: NEW BEST\n", p.level); fflush(stdout);
1203
stats.nof_canupdates++;
1205
* Update canonical labeling and its inverse
1207
update_labeling_and_its_inverse(best_path_labeling,
1208
best_path_labeling_inv);
1209
/* Reset best path automorphism */
1210
reset_permutation(best_path_automorphism);
1211
/* Reset best path orbit structure */
1212
best_path_orbits.reset();
1214
* Mark the current path to be the best one and save it
1216
const unsigned int base_size = search_stack.size();
1217
assert(p.level == base_size);
1218
best_path_info.clear();
1219
//fprintf(stdout, " New base is: ");
1220
for(unsigned int i = 0; i < base_size; i++) {
1221
search_stack[i].cmp_to_best_path = 0;
1222
search_stack[i].in_best_path = true;
1224
path_info.splitting_element = search_stack[i].split_element;
1225
path_info.certificate_index = search_stack[i].certificate_index;
1226
path_info.eqref_hash = search_stack[i].eqref_hash;
1227
path_info.subcertificate_length = search_stack[i].subcertificate_length;
1228
best_path_info.push_back(path_info);
1229
//fprintf(stdout, "%u ", search_stack[i].split_element);
1231
certificate_best_path = certificate_current_path;
1232
//fprintf(stdout, "\n"); fflush(stdout);
1234
* Backtrack to the previous level
1241
//fprintf(stderr, "BAUT ");
1243
* Equal to the previous best path
1246
/* Verify that the automorphism is correctly built */
1247
for(unsigned int i = 0; i < N; i++)
1248
assert(best_path_automorphism[i] ==
1249
p.elements[best_path_labeling[i]]);
1252
#if defined(VERIFY_AUTOMORPHISMS)
1253
/* Verify that it really is an automorphism */
1254
assert(is_automorphism(best_path_automorphism));
1257
unsigned int gca_level_with_first = 0;
1258
for(unsigned int i = search_stack.size(); i > 0; i--) {
1259
if((int)first_path_info[gca_level_with_first].splitting_element !=
1260
search_stack[gca_level_with_first].split_element)
1262
gca_level_with_first++;
1264
assert(gca_level_with_first < p.level);
1266
unsigned int gca_level_with_best = 0;
1267
for(unsigned int i = search_stack.size(); i > 0; i--) {
1268
if((int)best_path_info[gca_level_with_best].splitting_element !=
1269
search_stack[gca_level_with_best].split_element)
1271
gca_level_with_best++;
1273
assert(gca_level_with_best < p.level);
1275
long_prune_add_automorphism(best_path_automorphism);
1278
* Update orbit information
1280
update_orbit_information(best_path_orbits, best_path_automorphism);
1283
* Update orbit information
1285
const unsigned int nof_old_orbits = first_path_orbits.nof_orbits();
1286
update_orbit_information(first_path_orbits, best_path_automorphism);
1287
if(nof_old_orbits != first_path_orbits.nof_orbits())
1289
if(write_automorphisms)
1291
print_permutation(stdout, best_path_automorphism);
1292
fprintf(stdout, "\n");
1294
stats.nof_generators++;
1298
* Compute backjumping level
1300
unsigned int backjumping_level = p.level - 1;
1301
if(!first_path_orbits.is_minimal_representative(search_stack[gca_level_with_first].split_element))
1303
backjumping_level = gca_level_with_first;
1304
/*fprintf(stderr, "bj1: %u %u\n", p.level, backjumping_level);*/
1308
assert(!best_path_orbits.is_minimal_representative(search_stack[gca_level_with_best].split_element));
1309
backjumping_level = gca_level_with_best;
1310
/*fprintf(stderr, "bj2: %u %u\n", p.level, backjumping_level);*/
1313
search_stack.resize(backjumping_level + 1);
1314
p.level = backjumping_level;
1319
#ifdef PRINT_SEARCH_TREE_DOT
1320
fprintf(dotty_output, "}\n");
1321
fclose(dotty_output);
1328
void AbstractGraph::find_automorphisms(Stats &stats)
1330
search(false, stats);
1332
if(first_path_labeling)
1334
free(first_path_labeling);
1335
first_path_labeling = 0;
1337
if(best_path_labeling)
1339
free(best_path_labeling);
1340
best_path_labeling = 0;
1345
const unsigned int *AbstractGraph::canonical_form(Stats &stats)
1347
search(true, stats);
1349
return best_path_labeling;
1355
/*-------------------------------------------------------------------------
1357
* Routines for undirected graphs
1359
*-------------------------------------------------------------------------*/
1361
Graph::Vertex::Vertex()
1368
Graph::Vertex::~Vertex()
1374
void Graph::Vertex::add_edge(const unsigned int other_vertex)
1376
edges.push_back(other_vertex);
1378
DEBUG_ASSERT(nof_edges == edges.size());
1382
void Graph::Vertex::remove_duplicate_edges(bool * const duplicate_array)
1384
for(std::vector<unsigned int>::iterator iter = edges.begin();
1385
iter != edges.end(); )
1387
const unsigned int dest_vertex = *iter;
1388
if(duplicate_array[dest_vertex] == true)
1390
/* A duplicate edge found! */
1391
iter = edges.erase(iter);
1393
DEBUG_ASSERT(nof_edges == edges.size());
1397
/* Not seen earlier, mark as seen */
1398
duplicate_array[dest_vertex] = true;
1403
/* Clear duplicate_array */
1404
for(std::vector<unsigned int>::iterator iter = edges.begin();
1405
iter != edges.end();
1408
duplicate_array[*iter] = false;
1416
/*-------------------------------------------------------------------------
1418
* Constructor and destructor for undirected graphs
1420
*-------------------------------------------------------------------------*/
1423
Graph::Graph(const unsigned int nof_vertices)
1425
vertices.resize(nof_vertices);
1436
unsigned int Graph::add_vertex(const unsigned int new_label)
1438
const unsigned int new_vertex_num = vertices.size();
1439
vertices.resize(new_vertex_num + 1);
1440
vertices.back().label = new_label;
1441
return new_vertex_num;
1445
void Graph::add_edge(const unsigned int vertex1, const unsigned int vertex2)
1447
//fprintf(stderr, "(%u,%u) ", vertex1, vertex2);
1448
assert(vertex1 < vertices.size());
1449
assert(vertex2 < vertices.size());
1450
vertices[vertex1].add_edge(vertex2);
1451
vertices[vertex2].add_edge(vertex1);
1455
void Graph::change_label(const unsigned int vertex,
1456
const unsigned int new_label)
1458
assert(vertex < vertices.size());
1459
vertices[vertex].label = new_label;
1466
/*-------------------------------------------------------------------------
1468
* Read graph in the DIMACS format
1470
*-------------------------------------------------------------------------*/
1472
Graph *Graph::read_dimacs(FILE *fp)
1475
unsigned int nof_vertices, nof_edges;
1476
unsigned int line_num = 1;
1479
/* read comments and problem line*/
1483
while((c = getc(fp)) != '\n') {
1485
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1494
if(fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2) {
1495
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1501
fprintf(stderr, "error in line %u: not in DIMACS format\n", line_num);
1505
if(nof_vertices <= 0) {
1506
fprintf(stderr, "error: no vertices\n");
1510
if(nof_edges <= 0) {
1511
fprintf(stderr, "error: no edges\n");
1516
fprintf(bliss_verbstr, "Instance has %d vertices and %d edges\n",
1517
nof_vertices, nof_edges);
1518
fflush(bliss_verbstr);
1521
g = new Graph(nof_vertices);
1524
// Read vertex labels
1527
fprintf(bliss_verbstr, "Reading vertex labels...\n");
1528
fflush(bliss_verbstr); }
1536
unsigned int vertex, label;
1537
if(fscanf(fp, "n %u %u\n", &vertex, &label) != 2) {
1538
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1542
if(vertex > nof_vertices) {
1543
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1548
g->change_label(vertex - 1, label);
1551
fprintf(bliss_verbstr, "Done\n");
1552
fflush(bliss_verbstr); }
1558
fprintf(bliss_verbstr, "Reading edges...\n");
1559
fflush(bliss_verbstr); }
1560
for(unsigned i = 0; i < nof_edges; i++) {
1561
unsigned int from, to;
1562
if(fscanf(fp, "e %u %u\n", &from, &to) != 2) {
1563
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1567
if(from > nof_vertices || to > nof_vertices) {
1568
fprintf(stderr, "error in line %u: not in DIMACS format\n",
1573
g->add_edge(from - 1, to - 1);
1576
fprintf(bliss_verbstr, "Done\n");
1577
fflush(bliss_verbstr);
1589
Graph *Graph::from_igraph(const igraph_t *graph) {
1591
unsigned int nof_vertices= (unsigned int)igraph_vcount(graph);
1592
unsigned int nof_edges= (unsigned int)igraph_ecount(graph);
1593
Graph *g=new Graph(nof_vertices);
1594
// for (unsigned int i=0; i<nof_vertices; i++) {
1595
// g->change_label(i, i);
1597
for (unsigned int i=0; i<nof_edges; i++) {
1598
g->add_edge((unsigned int)IGRAPH_FROM(graph, i),
1599
(unsigned int)IGRAPH_TO(graph, i));
1604
void Graph::print_dimacs(FILE *fp)
1606
unsigned int nof_edges = 0;
1607
for(unsigned int i = 0; i < get_nof_vertices(); i++)
1609
Vertex &v = vertices[i];
1610
for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1611
ei != v.edges.end();
1614
const unsigned int dest_i = *ei;
1621
fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);
1622
for(unsigned int i = 0; i < get_nof_vertices(); i++)
1624
Vertex &v = vertices[i];
1627
fprintf(fp, "n %u %u\n", i+1, v.label);
1630
for(unsigned int i = 0; i < get_nof_vertices(); i++)
1632
Vertex &v = vertices[i];
1633
for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1634
ei != v.edges.end();
1637
const unsigned int dest_i = *ei;
1640
fprintf(fp, "e %u %u\n", i+1, dest_i+1);
1648
Graph *Graph::permute(const unsigned int *perm)
1650
Graph *g = new Graph(get_nof_vertices());
1651
for(unsigned int i = 0; i < get_nof_vertices(); i++)
1653
Vertex &v = vertices[i];
1654
Vertex &permuted_v = g->vertices[perm[i]];
1655
permuted_v.label = v.label;
1656
for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1657
ei != v.edges.end();
1660
const unsigned int dest_v = *ei;
1661
permuted_v.add_edge(perm[dest_v]);
1663
std::sort(permuted_v.edges.begin(), permuted_v.edges.end());
1672
/*-------------------------------------------------------------------------
1674
* Print graph in graphviz format
1676
*-------------------------------------------------------------------------*/
1679
void Graph::to_dot(const char *file_name)
1681
FILE *fp = fopen(file_name, "w");
1688
void Graph::to_dot(FILE *fp)
1690
remove_duplicate_edges();
1692
fprintf(fp, "graph g {\n");
1694
unsigned int vnum = 0;
1695
for(std::vector<Vertex>::iterator vi = vertices.begin();
1696
vi != vertices.end();
1700
fprintf(fp, "v%u [label=\"%u:%u\"];\n", vnum, vnum, v.label);
1701
for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1702
ei != v.edges.end();
1705
const unsigned int vnum2 = *ei;
1707
fprintf(fp, "v%u -- v%u\n", vnum, vnum2);
1718
void Graph::remove_duplicate_edges()
1720
bool *duplicate_array = (bool*)calloc(vertices.size(), sizeof(bool));
1722
for(std::vector<Vertex>::iterator vi = vertices.begin();
1723
vi != vertices.end();
1726
#ifdef EXPENSIVE_CONSISTENCY_CHECKS
1727
for(unsigned int i = 0; i < vertices.size(); i++)
1728
assert(duplicate_array[i] == false);
1731
v.remove_duplicate_edges(duplicate_array);
1734
free(duplicate_array);
1741
/*-------------------------------------------------------------------------
1743
* Partition independent invariants
1745
*-------------------------------------------------------------------------*/
1748
unsigned int Graph::label_invariant(Graph *g, unsigned int v)
1750
DEBUG_ASSERT(v < g->vertices.size());
1751
return g->vertices[v].label;
1755
unsigned int Graph::degree_invariant(Graph *g, unsigned int v)
1757
DEBUG_ASSERT(v < g->vertices.size());
1758
DEBUG_ASSERT(g->vertices[v].edges.size() ==
1759
g->vertices[v].nof_edges);
1760
return g->vertices[v].nof_edges;
1769
/*-------------------------------------------------------------------------
1771
* Refine the partition p according to a partition independent invariant
1773
*-------------------------------------------------------------------------*/
1775
bool Graph::refine_according_to_invariant(unsigned int (*inv)(Graph * const g, unsigned int v))
1777
bool refined = false;
1779
for(Cell *cell = p.first_cell; cell; )
1781
assert(cell->max_ival == 0);
1782
assert(cell->max_ival_count == 0);
1784
Cell * const next_cell = cell->next;
1786
if(cell->length == 1)
1792
const unsigned int *ep = p.elements + cell->first;
1793
for(unsigned int i = cell->length; i > 0; i--, ep++)
1795
unsigned int ival = inv(this, *ep);
1796
p.invariant_values[*ep] = ival;
1797
if(ival > cell->max_ival) {
1798
cell->max_ival = ival;
1799
cell->max_ival_count = 1;
1801
else if(ival == cell->max_ival) {
1802
cell->max_ival_count++;
1805
Cell * const last_new_cell = p.zplit_cell(cell, true);
1806
refined = (last_new_cell != cell);
1817
/*-------------------------------------------------------------------------
1819
* Split the neighbourhood of a cell according to the equitable invariant
1821
*-------------------------------------------------------------------------*/
1824
void Graph::split_neighbourhood_of_cell(Cell * const cell)
1826
DEBUG_ASSERT(neighbour_heap.is_empty());
1827
DEBUG_ASSERT(cell->length > 1);
1829
eqref_hash.update(cell->first);
1830
eqref_hash.update(cell->length);
1832
unsigned int *ep = p.elements + cell->first;
1833
for(unsigned int i = cell->length; i > 0; i--)
1835
const Vertex &v = vertices[*ep];
1838
std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1839
for(unsigned int j = v.nof_edges; j > 0; j--)
1841
const unsigned int dest_vertex = *ei++;
1842
Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
1843
if(neighbour_cell->length == 1)
1845
const unsigned int ival = p.invariant_values[dest_vertex] + 1;
1846
p.invariant_values[dest_vertex] = ival;
1847
if(ival > neighbour_cell->max_ival) {
1848
neighbour_cell->max_ival = ival;
1849
neighbour_cell->max_ival_count = 1;
1851
else if(ival == neighbour_cell->max_ival) {
1852
neighbour_cell->max_ival_count++;
1854
if(!neighbour_cell->in_neighbour_heap) {
1855
neighbour_cell->in_neighbour_heap = true;
1856
neighbour_heap.insert(neighbour_cell->first);
1861
while(!neighbour_heap.is_empty())
1863
const unsigned int start = neighbour_heap.remove();
1864
Cell * const neighbour_cell = p.element_to_cell_map[p.elements[start]];
1865
DEBUG_ASSERT(neighbour_cell->first == start);
1866
DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
1867
neighbour_cell->in_neighbour_heap = false;
1869
DEBUG_ASSERT(neighbour_cell->length > 1);
1870
DEBUG_ASSERT(neighbour_cell->max_ival >= 1);
1871
DEBUG_ASSERT(neighbour_cell->max_ival_count >= 1);
1873
eqref_hash.update(neighbour_cell->first);
1874
eqref_hash.update(neighbour_cell->length);
1875
eqref_hash.update(neighbour_cell->max_ival);
1876
eqref_hash.update(neighbour_cell->max_ival_count);
1878
Cell * const last_new_cell = p.zplit_cell(neighbour_cell, true);
1880
const Cell *c = neighbour_cell;
1883
eqref_hash.update(c->first);
1884
eqref_hash.update(c->length);
1885
if(c == last_new_cell)
1893
bool Graph::split_neighbourhood_of_unit_cell(Cell * const unit_cell)
1895
DEBUG_ASSERT(neighbour_heap.is_empty());
1897
DEBUG_ASSERT(unit_cell->length == 1);
1898
DEBUG_ASSERT(p.element_to_cell_map[p.elements[unit_cell->first]] == unit_cell);
1899
DEBUG_ASSERT(p.in_pos[p.elements[unit_cell->first]] ==
1900
p.elements + unit_cell->first);
1902
eqref_hash.update(0x87654321);
1903
eqref_hash.update(unit_cell->first);
1904
eqref_hash.update(1);
1906
const Vertex &v = vertices[p.elements[unit_cell->first]];
1908
std::vector<unsigned int>::const_iterator ei = v.edges.begin();
1909
for(unsigned int j = v.nof_edges; j > 0; j--)
1911
const unsigned int dest_vertex = *ei++;
1912
Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
1913
DEBUG_ASSERT(*p.in_pos[dest_vertex] == dest_vertex);
1915
if(neighbour_cell->length == 1) {
1916
DEBUG_ASSERT(!neighbour_cell->in_neighbour_heap);
1918
neighbour_cell->in_neighbour_heap = true;
1919
neighbour_heap.insert(neighbour_cell->first);
1923
if(!neighbour_cell->in_neighbour_heap) {
1924
neighbour_cell->in_neighbour_heap = true;
1925
neighbour_heap.insert(neighbour_cell->first);
1927
neighbour_cell->max_ival_count++;
1928
DEBUG_ASSERT(neighbour_cell->max_ival_count <= neighbour_cell->length);
1930
unsigned int * const swap_position =
1931
p.elements + neighbour_cell->first + neighbour_cell->length -
1932
neighbour_cell->max_ival_count;
1933
DEBUG_ASSERT(p.in_pos[dest_vertex] <= swap_position);
1934
*p.in_pos[dest_vertex] = *swap_position;
1935
p.in_pos[*swap_position] = p.in_pos[dest_vertex];
1936
*swap_position = dest_vertex;
1937
p.in_pos[dest_vertex] = swap_position;
1940
while(!neighbour_heap.is_empty())
1942
const unsigned int start = neighbour_heap.remove();
1943
Cell *neighbour_cell = p.element_to_cell_map[p.elements[start]];
1944
DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
1945
neighbour_cell->in_neighbour_heap = false;
1948
assert(neighbour_cell->first == start);
1949
if(neighbour_cell->length == 1) {
1950
assert(neighbour_cell->max_ival_count == 0);
1952
assert(neighbour_cell->max_ival_count > 0);
1953
assert(neighbour_cell->max_ival_count <= neighbour_cell->length);
1957
eqref_hash.update(neighbour_cell->first);
1958
eqref_hash.update(neighbour_cell->length);
1959
eqref_hash.update(neighbour_cell->max_ival_count);
1961
if(neighbour_cell->length > 1 &&
1962
neighbour_cell->max_ival_count != neighbour_cell->length) {
1964
p.consistency_check();
1966
Cell * const new_cell = p.aux_split_in_two(neighbour_cell, neighbour_cell->length - neighbour_cell->max_ival_count);
1967
unsigned int *ep = p.elements + new_cell->first;
1968
unsigned int * const lp = p.elements+new_cell->first+new_cell->length;
1970
DEBUG_ASSERT(p.in_pos[*ep] == ep);
1971
p.element_to_cell_map[*ep] = new_cell;
1974
neighbour_cell->max_ival_count = 0;
1976
p.consistency_check();
1979
eqref_hash.update(neighbour_cell->first);
1980
eqref_hash.update(neighbour_cell->length);
1981
eqref_hash.update(0);
1982
eqref_hash.update(new_cell->first);
1983
eqref_hash.update(new_cell->length);
1984
eqref_hash.update(1);
1986
/* Add cells in splitting_queue */
1987
DEBUG_ASSERT(!new_cell->in_splitting_queue);
1988
if(neighbour_cell->in_splitting_queue) {
1989
/* Both cells must be included in splitting_queue in order
1990
to have refinement to equitable partition */
1991
p.add_in_splitting_queue(new_cell);
1993
Cell *min_cell, *max_cell;
1994
if(neighbour_cell->length <= new_cell->length) {
1995
min_cell = neighbour_cell;
1996
max_cell = new_cell;
1998
min_cell = new_cell;
1999
max_cell = neighbour_cell;
2001
/* Put the smaller cell in splitting_queue */
2002
p.add_in_splitting_queue(min_cell);
2003
if(max_cell->length == 1) {
2004
/* Put the "larger" cell also in splitting_queue */
2005
p.add_in_splitting_queue(max_cell);
2008
/* Update pointer for certificate generation */
2009
neighbour_cell = new_cell;
2012
neighbour_cell->max_ival_count = 0;
2015
* Build certificate if required
2019
for(unsigned int i = neighbour_cell->first,
2020
j = neighbour_cell->length,
2021
c_index = certificate_current_path.size();
2023
j--, i++, c_index += 2)
2025
if(refine_compare_certificate)
2027
if(refine_equal_to_first)
2029
if(c_index >= refine_first_path_subcertificate_end)
2030
refine_equal_to_first = false;
2031
else if(certificate_first_path[c_index] !=
2033
refine_equal_to_first = false;
2034
else if(certificate_first_path[c_index+1] != i)
2035
refine_equal_to_first = false;
2037
if(refine_cmp_to_best == 0)
2039
if(c_index >= refine_best_path_subcertificate_end)
2041
refine_cmp_to_best = 1;
2043
else if(unit_cell->first>certificate_best_path[c_index])
2045
refine_cmp_to_best = 1;
2047
else if(unit_cell->first<certificate_best_path[c_index])
2049
refine_cmp_to_best = -1;
2051
else if(i > certificate_best_path[c_index+1])
2053
refine_cmp_to_best = 1;
2055
else if(i < certificate_best_path[c_index+1])
2057
refine_cmp_to_best = -1;
2060
if((refine_equal_to_first == false) &&
2061
(refine_cmp_to_best < 0))
2064
certificate_current_path.push_back(unit_cell->first);
2065
certificate_current_path.push_back(i);
2067
} /* if(in_search) */
2068
} /* while(!neighbour_heap.is_empty()) */
2073
while(!neighbour_heap.is_empty())
2075
const unsigned int start = neighbour_heap.remove();
2076
Cell * const neighbour_cell = p.element_to_cell_map[p.elements[start]];
2077
DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
2078
neighbour_cell->in_neighbour_heap = false;
2079
neighbour_cell->max_ival_count = 0;
2088
/*-------------------------------------------------------------------------
2090
* Check whether the current partition p is equitable
2091
* Slow: use only for debugging purposes
2092
* Side effect: resets max_ival and max_ival_count fields in cells
2094
*-------------------------------------------------------------------------*/
2096
bool Graph::is_equitable()
2101
* Max ival and max_ival_count are used for counting purposes,
2102
* they should be reset...
2104
for(Cell *cell = p.first_cell; cell; cell = cell->next)
2106
assert(cell->prev_next_ptr && *(cell->prev_next_ptr) == cell);
2107
assert(cell->max_ival == 0);
2108
assert(cell->max_ival_count == 0);
2112
for(Cell *cell = p.first_cell; cell; cell = cell->next)
2114
if(cell->length == 1)
2117
unsigned int *ep = p.elements + cell->first;
2118
Vertex &first_vertex = vertices[*ep++];
2120
/* Count edges of the first vertex for cells in max_ival */
2121
std::vector<unsigned int>::const_iterator ei = first_vertex.edges.begin();
2122
for(unsigned int j = first_vertex.nof_edges; j > 0; j--)
2124
p.element_to_cell_map[*ei++]->max_ival++;
2127
/* Count and compare edges of the other vertices */
2128
for(unsigned int i = cell->length; i > 1; i--)
2130
Vertex &vertex = vertices[*ep++];
2131
std::vector<unsigned int>::const_iterator ei = vertex.edges.begin();
2132
for(unsigned int j = vertex.nof_edges; j > 0; j--)
2134
p.element_to_cell_map[*ei++]->max_ival_count++;
2136
for(Cell *cell2 = p.first_cell; cell2; cell2 = cell2->next)
2138
if(cell2->max_ival != cell2->max_ival_count)
2143
cell2->max_ival_count = 0;
2146
/* Reset max_ival */
2147
for(Cell *cell2 = p.first_cell; cell2; cell2 = cell2->next)
2149
cell2->max_ival = 0;
2150
assert(cell2->max_ival_count == 0);
2156
for(Cell *cell = p.first_cell; cell; cell = cell->next)
2159
cell->max_ival_count = 0;
2169
/*-------------------------------------------------------------------------
2171
* Build the initial equitable partition
2173
*-------------------------------------------------------------------------*/
2175
void Graph::make_initial_equitable_partition()
2177
refine_according_to_invariant(&label_invariant);
2178
p.clear_splitting_queue();
2179
//p.print_signature(stderr); fprintf(stderr, "\n");
2181
refine_according_to_invariant(°ree_invariant);
2182
p.clear_splitting_queue();
2183
//p.print_signature(stderr); fprintf(stderr, "\n");
2185
/* To do: add loop invariant */
2187
refine_to_equitable();
2188
p.refinement_stack.clean();
2189
//p.print_signature(stderr); fprintf(stderr, "\n");
2196
/*-------------------------------------------------------------------------
2198
* Find the next cell to be splitted
2200
*-------------------------------------------------------------------------*/
2202
Cell *Graph::find_next_cell_to_be_splitted(Cell *cell)
2204
assert(!p.is_discrete());
2207
return sh_first(cell);
2209
return sh_first_smallest(cell);
2211
return sh_first_largest(cell);
2213
return sh_first_max_neighbours(cell);
2215
return sh_first_smallest_max_neighbours(cell);
2217
return sh_first_largest_max_neighbours(cell);
2219
assert(false && "Unknown splitting heuristics");
2223
/* First nonsingleton cell */
2224
Cell *Graph::sh_first(Cell *cell)
2226
return p.first_nonsingleton_cell;
2229
/* First smallest nonsingleton cell. */
2230
Cell *Graph::sh_first_smallest(Cell *cell)
2232
Cell *best_cell = 0;
2233
unsigned int best_size = UINT_MAX;
2234
for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
2236
assert(cell->length > 1);
2237
if(cell->length < best_size)
2239
best_size = cell->length;
2247
/* First largest nonsingleton cell. */
2248
Cell *Graph::sh_first_largest(Cell *cell)
2250
Cell *best_cell = 0;
2251
unsigned int best_size = 0;
2252
for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
2254
assert(cell->length > 1);
2255
if(cell->length > best_size)
2257
best_size = cell->length;
2265
/* First nonsingleton cell with max number of neighbouring
2266
* nonsingleton cells.
2267
* Assumes that the partition p is equitable.
2268
* Messes up in_neighbour_heap and max_ival fields of cells
2269
* (assumes they are false/0).
2271
Cell *Graph::sh_first_max_neighbours(Cell *cell)
2273
Cell *best_cell = 0;
2274
int best_value = -1;
2275
for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
2277
assert(cell->length > 1);
2279
const Vertex &v = vertices[p.elements[cell->first]];
2280
std::vector<unsigned int>::const_iterator ei = v.edges.begin();
2281
std::list<Cell*> neighbour_cells_visited;
2282
for(unsigned int j = v.nof_edges; j > 0; j--)
2284
const unsigned int dest_vertex = *ei++;
2285
Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
2286
if(neighbour_cell->length == 1)
2288
neighbour_cell->max_ival++;
2289
if(neighbour_cell->in_neighbour_heap)
2291
neighbour_cell->in_neighbour_heap = true;
2292
neighbour_cells_visited.push_back(neighbour_cell);
2295
while(!neighbour_cells_visited.empty())
2297
Cell * const neighbour_cell = neighbour_cells_visited.front();
2298
neighbour_cells_visited.pop_front();
2299
assert(neighbour_cell->in_neighbour_heap);
2300
neighbour_cell->in_neighbour_heap = false;
2301
if(neighbour_cell->max_ival != neighbour_cell->length)
2303
neighbour_cell->max_ival = 0;
2305
if(value > best_value)
2314
/* First smallest nonsingleton cell with max number of neighbouring
2315
* nonsingleton cells.
2316
* Assumes that the partition p is equitable.
2317
* Messes up in_neighbour_heap and max_ival fields of cells
2318
* (assumes they are false).
2320
Cell *Graph::sh_first_smallest_max_neighbours(Cell *cell)
2322
Cell *best_cell = 0;
2323
int best_value = -1;
2324
int best_size = INT_MAX;
2325
for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
2327
assert(cell->length > 1);
2329
const Vertex &v = vertices[p.elements[cell->first]];
2330
std::vector<unsigned int>::const_iterator ei = v.edges.begin();
2331
std::list<Cell*> neighbour_cells_visited;
2332
for(unsigned int j = v.nof_edges; j > 0; j--)
2334
const unsigned int dest_vertex = *ei++;
2335
Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
2336
if(neighbour_cell->length == 1)
2338
neighbour_cell->max_ival++;
2339
if(neighbour_cell->in_neighbour_heap)
2341
neighbour_cell->in_neighbour_heap = true;
2342
neighbour_cells_visited.push_back(neighbour_cell);
2345
while(!neighbour_cells_visited.empty())
2347
Cell * const neighbour_cell = neighbour_cells_visited.front();
2348
neighbour_cells_visited.pop_front();
2349
assert(neighbour_cell->in_neighbour_heap);
2350
neighbour_cell->in_neighbour_heap = false;
2351
if(neighbour_cell->max_ival != neighbour_cell->length)
2353
neighbour_cell->max_ival = 0;
2355
if((value > best_value) ||
2356
(value == best_value && (int)cell->length < best_size))
2359
best_size = cell->length;
2366
/* First largest nonsingleton cell with max number of neighbouring
2367
* nonsingleton cells.
2368
* Assumes that the partition p is equitable.
2369
* Messes up in_neighbour_heap and max_ival fields of cells
2370
* (assumes they are false/0).
2372
Cell *Graph::sh_first_largest_max_neighbours(Cell *cell)
2374
Cell *best_cell = 0;
2375
int best_value = -1;
2377
for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
2379
assert(cell->length > 1);
2381
const Vertex &v = vertices[p.elements[cell->first]];
2382
std::vector<unsigned int>::const_iterator ei = v.edges.begin();
2383
std::list<Cell*> neighbour_cells_visited;
2384
for(unsigned int j = v.nof_edges; j > 0; j--)
2386
const unsigned int dest_vertex = *ei++;
2387
Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
2388
if(neighbour_cell->length == 1)
2390
neighbour_cell->max_ival++;
2391
if(neighbour_cell->in_neighbour_heap)
2393
neighbour_cell->in_neighbour_heap = true;
2394
neighbour_cells_visited.push_back(neighbour_cell);
2397
while(!neighbour_cells_visited.empty())
2399
Cell * const neighbour_cell = neighbour_cells_visited.front();
2400
neighbour_cells_visited.pop_front();
2401
assert(neighbour_cell->in_neighbour_heap);
2402
neighbour_cell->in_neighbour_heap = false;
2403
if(neighbour_cell->max_ival != neighbour_cell->length)
2405
neighbour_cell->max_ival = 0;
2407
if((value > best_value) ||
2408
(value == best_value && (int)cell->length > best_size))
2411
best_size = cell->length;
2423
/*-------------------------------------------------------------------------
2425
* Initialize the certificate size and memory
2427
*-------------------------------------------------------------------------*/
2429
void Graph::initialize_certificate()
2431
certificate_size = 0;
2432
for(Cell *cell = p.first_cell; cell; cell = cell->next)
2434
if(cell->length > 1) {
2436
vertices[p.elements[cell->first]].nof_edges * 2 * cell->length;
2440
// free(certificate);
2441
//certificate = (unsigned int*)malloc(certificate_size * sizeof(unsigned int));
2442
certificate_index = 0;
2444
certificate_current_path.clear();
2445
certificate_first_path.clear();
2446
certificate_best_path.clear();
2453
/*-------------------------------------------------------------------------
2455
* Check whether perm is an automorphism
2457
*-------------------------------------------------------------------------*/
2459
bool Graph::is_automorphism(unsigned int * const perm)
2461
std::set<unsigned int, std::less<unsigned int> > edges1;
2462
std::set<unsigned int, std::less<unsigned int> > edges2;
2466
for(unsigned int i = 0; i < vertices.size(); i++)
2468
Vertex &v1 = vertices[i];
2470
for(std::vector<unsigned int>::iterator ei = v1.edges.begin();
2471
ei != v1.edges.end();
2473
edges1.insert(perm[*ei]);
2475
Vertex &v2 = vertices[perm[i]];
2477
for(std::vector<unsigned int>::iterator ei = v2.edges.begin();
2478
ei != v2.edges.end();
2482
if(!(edges1 == edges2))