Orbiter 2022
Combinatorial Objects
clique_finder.cpp
Go to the documentation of this file.
1// clique_finder.cpp
2//
3// Anton Betten
4// 11/6/07
5//
6// moved into TOP_LEVEL: Oct 13, 2011
7//
8// This is the clique finder.
9// The main function is clique_finder::backtrack_search()
10//
11// this file was originally developed for the search of BLT-sets
12
13#include "foundations.h"
14
15using namespace std;
16
17
18namespace orbiter {
19namespace layer1_foundations {
20namespace graph_theory {
21
22
23
24#undef SUSPICIOUS
25
26
28{
29 Control = NULL;
30 n = 0;
31
32 //print_interval = 0;
33
35 //f_decision_nodes_only = FALSE;
36 //std::string fname_tree;
37
38 fp_tree = NULL;
39
40 point_labels = NULL;
42
43 verbose_level = 0;
44
46 adj_list_coded = NULL;
48 Bitvec_adjacency = NULL;
49
50
53
54 pt_list = NULL;
55 pt_list_inv = NULL;
56 nb_points = NULL;
57 candidates = NULL;
58 nb_candidates = NULL;
59 current_choice = NULL;
60 level_counter = NULL;
61 f_level_mod = NULL;
62 level_r = NULL;
63 level_m = NULL;
64
65 current_clique = NULL;
66
67 counter = 0;
69
70 //std::deque<std::vector<int> > solutions;
71 nb_sol = 0;
72
79
80#if 0
81 f_has_print_current_choice_function = FALSE;
82 call_back_print_current_choice = NULL;
83 print_current_choice_data = NULL;
84#endif
85
88 //null();
89}
90
91
92
94{
95 free();
96}
97
99{
100
101}
102
104{
105 if (point_labels) {
107 }
110 }
111 if (pt_list) {
113 }
114 if (pt_list_inv) {
116 }
117 if (nb_points) {
119 }
120 if (candidates) {
122 }
123 if (nb_candidates) {
125 }
126 if (current_choice) {
128 }
129 if (level_counter) {
131 }
132 if (f_level_mod) {
134 }
135 if (level_r) {
137 }
138 if (level_m) {
140 }
141 if (current_clique) {
143 }
145 int i;
146 for (i = 0; i < n; i++) {
148 }
150 }
151
152 null();
153}
154
155
156
157
159 std::string &label, int n,
160 int f_has_adj_list, int *adj_list_coded,
161 int f_has_bitvector, data_structures::bitvector *Bitvec_adjacency,
162 int verbose_level)
163{
164 int f_v = (verbose_level >= 1);
165 int i;
166
167 label.assign(label);
168
172
177
180
181 if (f_v) {
182 cout << "clique_finder::init " << label << " n=" << n
183 << " target_size=" << Control->target_size << endl;
184 cout << "f_has_adj_list=" << f_has_adj_list << endl;
185 cout << "f_has_bitvector=" << f_has_bitvector << endl;
186 }
187
188
189 if (f_v) {
190 cout << "clique_finder::init before delinearize_adjacency_list" << endl;
191 }
193 if (f_v) {
194 cout << "clique_finder::init before after delinearize_adjacency_list" << endl;
195 }
196
197 //nb_sol = 0;
198
199 pt_list = NEW_int(n);
200 if (f_v) {
201 cout << "clique_finder::init pt_list allocated" << endl;
202 }
204 if (f_v) {
205 cout << "clique_finder::init pt_list_inv allocated" << endl;
206 }
216
221
222
223 for (i = 0; i < n; i++) {
224 pt_list[i] = i;
225 pt_list_inv[i] = i;
226 }
227 nb_points[0] = n;
228 counter = 0;
230
231
232 if (f_v) {
233 cout << "clique_finder::init finished" << endl;
234 }
235}
236
237void clique_finder::init_restrictions(int *restrictions,
238 int verbose_level)
239{
240 int f_v = (verbose_level >= 1);
241 int h, i, r, m;
242
243 if (f_v) {
244 cout << "clique_finder::init_restrictions" << endl;
245 }
246 for (h = 0; ; h++) {
247 if (restrictions[h * 3] == -1) {
248 break;
249 }
250 i = restrictions[h * 3 + 0];
251 r = restrictions[h * 3 + 1];
252 m = restrictions[h * 3 + 2];
253 if (i >= Control->target_size) {
254 cout << "clique_finder::init_restrictions "
255 "i >= target_size" << endl;
256 exit(1);
257 }
258 f_level_mod[i] = TRUE;
259 level_r[i] = r;
260 level_m[i] = m;
261 cout << "clique_finder::init_restrictions level "
262 << i << " congruent " << r << " mod " << m << endl;
263 }
264 if (f_v) {
265 cout << "clique_finder::init_restrictions done" << endl;
266 }
267}
268
270{
272 Int_vec_copy(pt_labels, point_labels, n);
273}
274
275void clique_finder::init_suspicious_points(int nb, int *point_list)
276{
277 int i, j, idx;
278 int *point_list_ordered;
280
281 point_list_ordered = NEW_int(nb);
282 for (i = 0; i < nb; i++) {
283 point_list_ordered[i] = point_list[i];
284 }
285 Sorting.int_vec_heapsort(point_list_ordered, nb);
287 for (i = 0; i < n; i++) {
289 }
290 for (i = 0; i < n; i++) {
291 if (point_labels) {
292 j = point_labels[i];
293 }
294 else {
295 j = i;
296 }
297 if (Sorting.int_vec_search(point_list_ordered, nb, j, idx)) {
299 }
300 }
301 FREE_int(point_list_ordered);
302}
303
304void clique_finder::backtrack_search(int depth, int verbose_level)
305{
306 int nb_old, i, nb_new;
307 int pt1, pt2, pt, pass, f_go;
308 unsigned long int counter_save;
309 int my_verbose_level;
310
311 counter++;
312 counter_save = counter;
313
314 if (depth && nb_candidates[depth - 1] > 1) {
316 }
317 if ((counter & ((1 << 23) - 1)) == 0) {
318 my_verbose_level = 1;
319 }
320 else {
321 my_verbose_level = verbose_level;
322 }
323 int f_v = (my_verbose_level >= 1);
324 int f_vv = (my_verbose_level >= 2);
325 //int f_vvv = (my_verbose_level >= 3);
326
327 if (f_v) {
328 cout << "clique_finder::backtrack_search : ";
329 log_position(depth, counter_save, counter);
330 cout << " nb_sol=" << solutions.size() << " starting" << endl;
331 }
333
334 if (depth == Control->target_size) {
335
336 // We found a clique:
337
338 if (f_v) {
339 cout << "clique_finder::backtrack_search "
340 "depth == target_depth" << endl;
341 }
343 //cout << "storing solution" << endl;
344 vector<int> sol;
345 int j;
346 sol.resize(depth);
347 for (j = 0; j < depth; j++) {
348 sol[j] = (int) current_clique[j];
349 }
350 solutions.push_back(sol);
351
352 }
353 nb_sol++;
354
355 //cout << "clique_finder::backtrack_search before
356 //call_back_clique_found" << endl;
358 //cout << "calling call_back_clique_found" << endl;
359 (*call_back_clique_found)(this, verbose_level);
360 }
361 //cout << "solution " << nb_sol << ", found a clique
362 //of size target_depth" << endl;
363 //cout << "clique";
364 //int_set_print(cout, current_clique, depth);
365 //cout << " depth = " << depth << endl;
366 //exit(1);
367
368 return;
369 }
370
371
372 if (Control->f_maxdepth && depth == Control->maxdepth) {
373 return;
374 }
375 if (depth == 0) {
376 nb_old = n;
377 }
378 else {
379 nb_old = nb_points[depth - 1];
380 }
381
382#if 0
383 if (f_v || (counter % print_interval) == 0) {
384 log_position(depth, counter_save, counter);
385 cout << endl;
386 }
387
388 if (f_v && depth) {
389 log_position(depth, counter_save, counter);
390 cout << " : # active points from previous level is "
391 << nb_old << endl;
392 //cout << " : previous lvl_pt_list[" << depth - 1
393 //<< "] of size " << nb_old << " : " << endl;
395 //lvl_nb_points[depth - 1]);
396 //print_point_set(depth, counter_save, counter,
397 //nb_old, lvl_pt_list[depth - 1]);
398 //cout << endl;
399 }
400#endif
401
402 // first pass:
403 // if depth > 0 and we are not using call_back_find_candidates,
404 // we apply the lexicographical ordering test.
405 // the points are required to be greater than
406 // the previous point in the clique.
407 // this also eliminates the point
408 // that was added to the clique in the previous step from pt_list.
409
410 if (f_v) {
411 cout << "clique_finder::backtrack_search : ";
412 log_position(depth, counter_save, counter);
413 cout << " first pass" << endl;
414 }
415
416 if (depth && call_back_find_candidates == NULL) {
417 // if we don't have a find_candidates function,
418 // then we use the lexicographical ordering.
419 // The idea is that we may force the clique to be
420 // constructed in increasing order of its points.
421 // Hence, now we can eliminate all points that
422 // are smaller than the most recently added clique point:
423 nb_new = 0;
424 pt1 = current_clique[depth - 1];
425 for (i = 0; i < nb_old; i++) {
426 pt2 = pt_list[i];
427 if (pt2 > pt1) {
428 swap_point(nb_new, i);
429 nb_new++;
430 }
431 }
432 }
433 else {
434 nb_new = nb_old;
435 }
436
437
438 // second pass: find the points that are connected with the
439 // previously chosen clique point:
440
441 nb_old = nb_new;
442 if (depth) {
443 nb_new = 0;
444 pt1 = current_clique[depth - 1];
445 for (i = 0; i < nb_old; i++) {
446 // go over all points in the old list:
447
448 pt2 = pt_list[i];
449 if (is_adjacent(depth, pt1, pt2)) {
450
451 // point is adjacent, so we keep that point
452
453 swap_point(nb_new, i);
454 nb_new++;
455 }
456
457 }
458 }
459 else {
460 nb_new = nb_old;
461 }
462
463
464 pass = 2;
465
466 if (f_vv) {
467 log_position(depth, counter_save, counter);
468 cout << " : pass 2: ";
470 cout << endl;
471 }
472
473
474#if 0
475 // higher passes:
476 // find the points that have sufficiently high degree:
477
478 do {
479 nb_old = nb_new;
480 nb_new = 0;
481 for (i = 0; i < nb_old; i++) {
482 d = degree_of_point(i, nb_old);
483 if (d >= target_depth - depth - 1) {
484 swap_point(nb_new, i);
485 nb_new++;
486 }
487 else {
490 log_position(depth, counter_save, counter);
491 cout << " : pass " << pass
492 << ": suspicious point " << point_label(pt_list[i])
493 << " eliminated, d=" << d
494 << " is less than target_depth - depth - 1 = "
495 << target_depth - depth - 1 << endl;;
496 degree_of_point_verbose(i, nb_old);
497 }
498 }
499 }
500 pass++;
501
502 if (f_vv) {
503 log_position(depth, counter_save, counter);
504 cout << " : pass " << pass << ": ";
506 cout << endl;
507 }
508
509 } while (nb_new < nb_old);
510#endif
511
512 nb_points[depth] = nb_new;
513
514
515
516 if (f_v) {
517 log_position(depth, counter_save, counter);
518 cout << "after " << pass << " passes: nb_points = "
519 << nb_new << endl;
520 }
521
522
524 if (f_v) {
525 log_position(depth, counter_save, counter);
526 cout << " before call_back_after_reduction" << endl;
527 }
528 (*call_back_after_reduction)(this, depth,
529 nb_points[depth], verbose_level);
530 if (f_v) {
531 log_position(depth, counter_save, counter);
532 cout << " after call_back_after_reduction" << endl;
533 }
534 }
535
536
537 {
538
540 int reduced_nb_points;
541
542 if (f_v) {
543 log_position(depth, counter_save, counter);
544 cout << " before call_back_find_candidates" << endl;
545 }
546 nb_candidates[depth] = (*call_back_find_candidates)(this,
547 depth, current_clique,
548 nb_points[depth], reduced_nb_points, pt_list, pt_list_inv,
549 candidates + depth * n,
550 0/*verbose_level*/);
551
552 if (f_v) {
553 log_position(depth, counter_save, counter);
554 cout << " after call_back_find_candidates nb_candidates="
555 << nb_candidates[depth] << endl;
556 }
557 // The set of candidates is stored in
558 // candidates + depth * n.
559 // The number of candidates is in nb_candidates[depth]
560
561
562#ifdef SUSPICIOUS
563 if (f_vv) {
565 cout << "candidate set of size "
566 << nb_candidates[depth] << endl;
568 nb_candidates[depth],
569 candidates + depth * n);
570 cout << endl;
571 }
572 }
573#endif
574 nb_points[depth] = reduced_nb_points;
575 }
576 else {
577 // If we don't have a find_candidates callback,
578 // we take all the points into consideration:
579
580 Int_vec_copy(pt_list, candidates + depth * n, nb_points[depth]);
581 nb_candidates[depth] = nb_points[depth];
582 }
583 }
584
585
586 // added Dec 2014:
590 }
591
592 // Now we are ready to go in the backtrack search.
593 // We'll try each of the points in candidates one by one:
594
595 for (current_choice[depth] = 0;
596 current_choice[depth] < nb_candidates[depth];
597 current_choice[depth]++, level_counter[depth]++) {
598
599
600 if (f_v) {
601 log_position(depth, counter_save, counter);
602 cout << " choice " << current_choice[depth] << " / "
603 << nb_candidates[depth] << endl;
604 }
605
606 f_go = TRUE; // Whether we want to go in the recursion.
607
608 if (f_level_mod[depth]) {
609 if ((level_counter[depth] % level_m[depth]) != level_r[depth]) {
610 f_go = FALSE;
611 }
612 }
613
614
615 pt = candidates[depth * n + current_choice[depth]];
616
617
618 if (f_vv) {
619 log_position_and_choice(depth, counter_save, counter);
620 cout << endl;
621 }
622
623
624
625 // We add a point under consideration:
626
627 current_clique[depth] = pt;
628
630 if (FALSE /*f_v*/) {
631 cout << "before call_back_add_point" << endl;
632 }
633 (*call_back_add_point)(this, depth, current_clique, pt, 0/*verbose_level*/);
634 if (FALSE /*f_v*/) {
635 cout << "after call_back_add_point" << endl;
636 }
637 }
638
640 if (point_is_suspicious[pt]) {
641 log_position(depth, counter_save, counter);
642 cout << " : considering clique ";
643 print_set(depth + 1, current_clique);
644 //int_set_print(cout, current_clique, depth);
645 cout << " depth = " << depth << " nb_old="
646 << nb_old << endl;
647 f_go = TRUE;
648 }
649 else {
650 f_go = FALSE;
651 }
652 }
653
654
655 // and now, let's do the recursion:
656
657 if (f_go) {
659 }
660
661
662
663
664
665 // We delete the point:
666
668 if (FALSE /*f_v*/) {
669 cout << "before call_back_delete_point" << endl;
670 }
671 (*call_back_delete_point)(this, depth,
672 current_clique, pt, 0/*verbose_level*/);
673 if (FALSE /*f_v*/) {
674 cout << "after call_back_delete_point" << endl;
675 }
676 }
677
678 } // for current_choice[depth]
679
680
681
682 if (f_v) {
683 cout << "backtrack_search : ";
684 log_position(depth, counter_save, counter);
685 cout << " nb_sol=" << solutions.size() << " done" << endl;
686 }
687}
688
689int clique_finder::solve_decision_problem(int depth, int verbose_level)
690// returns TRUE if we found a solution
691{
692 int nb_old, i, nb_new;
693 int pt1, pt2, pt, pass, f_go;
694 unsigned long int counter_save;
695 int my_verbose_level;
696
697 counter++;
698 counter_save = counter;
699
700 if (depth && nb_candidates[depth - 1] > 1) {
702 }
703 if ((counter & ((1 << 17) - 1)) == 0) {
704 my_verbose_level = verbose_level + 1;
705 }
706 else {
707 my_verbose_level = verbose_level;
708 }
709 int f_v = (my_verbose_level >= 1);
710 int f_vv = (my_verbose_level >= 2);
711 //int f_vvv = (my_verbose_level >= 3);
712
713 if (f_v) {
714 cout << "solve_decision_problem : ";
715 log_position(depth, counter_save, counter);
716 cout << " nb_sol=" << solutions.size() << " starting" << endl;
717 }
719
720 if (depth == Control->target_size) {
721 //nb_sol++;
722 //cout << "clique_finder::backtrack_search before
723 //call_back_clique_found" << endl;
725 (*call_back_clique_found)(this, verbose_level);
726 }
727 //cout << "solution " << nb_sol << ", found a clique
728 //of size target_depth" << endl;
729 //cout << "clique";
730 //int_set_print(cout, current_clique, depth);
731 //cout << " depth = " << depth << endl;
732 //exit(1);
733
734 return TRUE;
735 }
736
737
738 if (Control->f_maxdepth && depth == Control->maxdepth) {
739 return FALSE;
740 }
741 if (depth == 0) {
742 nb_old = n;
743 }
744 else {
745 nb_old = nb_points[depth - 1];
746 }
747
748#if 0
749 if (f_v || (counter % print_interval) == 0) {
750 log_position(depth, counter_save, counter);
751 cout << endl;
752 }
753
754 if (f_v && depth) {
755 log_position(depth, counter_save, counter);
756 cout << " : # active points from previous level is "
757 << nb_old << endl;
758 //cout << " : previous lvl_pt_list[" << depth - 1
759 //<< "] of size " << nb_old << " : " << endl;
761 // lvl_nb_points[depth - 1]);
762 //print_point_set(depth, counter_save, counter,
763 //nb_old, lvl_pt_list[depth - 1]);
764 //cout << endl;
765 }
766#endif
767
768 // first pass:
769 // if depth > 0 and we are not using call_back_find_candidates,
770 // we apply the lexicographical ordering test.
771 // the points are required to be greater than the
772 // previous point in the clique.
773 // this also eliminates the point
774 // that was added to the clique in the previous step from pt_list.
775
776 if (depth && call_back_find_candidates == NULL) {
777 nb_new = 0;
778 pt1 = current_clique[depth - 1];
779 for (i = 0; i < nb_old; i++) {
780 pt2 = pt_list[i];
781 if (pt2 > pt1) {
782 swap_point(nb_new, i);
783 nb_new++;
784 }
785 }
786 }
787 else {
788 nb_new = nb_old;
789 }
790
791
792 // second pass: find the points that are connected with the
793 // previously chosen clique point:
794
795 nb_old = nb_new;
796 if (depth) {
797 nb_new = 0;
798 pt1 = current_clique[depth - 1];
799 for (i = 0; i < nb_old; i++) {
800 pt2 = pt_list[i];
801 if (is_adjacent(depth, pt1, pt2)) {
802 swap_point(nb_new, i);
803 nb_new++;
804 }
805 }
806 }
807 else {
808 nb_new = nb_old;
809 }
810
811
812 pass = 2;
813
814 if (f_vv) {
815 log_position(depth, counter_save, counter);
816 cout << " : pass 2: ";
818 cout << endl;
819 }
820
821
822#if 0
823 // higher passes:
824 // find the points that have sufficiently high degree:
825
826 do {
827 nb_old = nb_new;
828 nb_new = 0;
829 for (i = 0; i < nb_old; i++) {
830 d = degree_of_point(i, nb_old);
831 if (d >= target_depth - depth - 1) {
832 swap_point(nb_new, i);
833 nb_new++;
834 }
835 else {
838 log_position(depth, counter_save, counter);
839 cout << " : pass " << pass
840 << ": suspicious point "
841 << point_label(pt_list[i])
842 << " eliminated, d=" << d
843 << " is less than target_depth - depth - 1 = "
844 << target_depth - depth - 1 << endl;;
845 degree_of_point_verbose(i, nb_old);
846 }
847 }
848 }
849 pass++;
850
851 if (f_vv) {
852 log_position(depth, counter_save, counter);
853 cout << " : pass " << pass << ": ";
855 cout << endl;
856 }
857
858 } while (nb_new < nb_old);
859#endif
860
861 nb_points[depth] = nb_new;
862
863
864
865 if (f_v) {
866 log_position(depth, counter_save, counter);
867 cout << "after " << pass << " passes: "
868 "nb_points = " << nb_new << endl;
869 }
870
871
873 (*call_back_after_reduction)(this, depth,
874 nb_points[depth], verbose_level);
875 }
876
877
878 {
879 int i; //, nb_old;
880
882 int reduced_nb_points;
883
884 nb_candidates[depth] = (*call_back_find_candidates)(this,
885 depth, current_clique,
886 nb_points[depth], reduced_nb_points,
888 candidates + depth * n,
889 0/*verbose_level*/);
890#ifdef SUSPICIOUS
891 if (f_vv) {
893 cout << "candidate set of size "
894 << nb_candidates[depth] << endl;
896 nb_candidates[depth],
897 candidates + depth * n);
898 cout << endl;
899 }
900 }
901#endif
902 nb_points[depth] = reduced_nb_points;
903 }
904 else {
905 for (i = 0; i < nb_points[depth]; i++) {
906 candidates[depth * n + i] = pt_list[i];
907 }
908 nb_candidates[depth] = nb_points[depth];
909 }
910 }
911
912
913
914
915 for (current_choice[depth] = 0;
916 current_choice[depth] < nb_candidates[depth];
917 current_choice[depth]++, level_counter[depth]++) {
918
919 pt = candidates[depth * n + current_choice[depth]];
920
921 f_go = TRUE;
922
923 if (f_vv) {
924 log_position_and_choice(depth, counter_save, counter);
925 cout << endl;
926 }
927 // add a point
928
929 current_clique[depth] = pt;
930
932 if (FALSE /*f_v*/) {
933 cout << "before call_back_add_point" << endl;
934 }
935 (*call_back_add_point)(this, depth,
936 current_clique, pt, 0/*verbose_level*/);
937 if (FALSE /*f_v*/) {
938 cout << "after call_back_add_point" << endl;
939 }
940 }
941
943 if (point_is_suspicious[pt]) {
944 log_position(depth, counter_save, counter);
945 cout << " : considering clique ";
946 print_set(depth + 1, current_clique);
947 //int_set_print(cout, current_clique, depth);
948 cout << " depth = " << depth << " nb_old="
949 << nb_old << endl;
950 f_go = TRUE;
951 }
952 else {
953 f_go = FALSE;
954 }
955 }
956
957 if (f_go) {
958 if (solve_decision_problem(depth + 1, verbose_level)) {
959 return TRUE;
960 }
961 } // if (f_go)
962
963 // delete a point:
964
966 if (FALSE /*f_v*/) {
967 cout << "before call_back_delete_point" << endl;
968 }
969 (*call_back_delete_point)(this, depth,
970 current_clique, pt, 0/*verbose_level*/);
971 if (FALSE /*f_v*/) {
972 cout << "after call_back_delete_point" << endl;
973 }
974 }
975
976 } // for current_choice[depth]
977
978
979
980 if (f_v) {
981 cout << "solve_decision_problem : ";
982 log_position(depth, counter_save, counter);
983 cout << " nb_sol=" << solutions.size() << " done" << endl;
984 }
985 return FALSE;
986}
987
988#if 0
989 static int *nb_old, *nb_new;
990 static int *pt1, *pt2, *pt, *pass, *f_go;
991 static unsigned long int *counter_save;
992
993void clique_finder::backtrack_search_not_recursive(int verbose_level)
994{
995 int depth;
996 int i;
997 int f_v = (verbose_level >= 1);
998 int f_vv = (verbose_level >= 2);
999
1000 nb_old = NEW_int(Control->target_size);
1001 nb_new = NEW_int(Control->target_size);
1002 pt1 = NEW_int(Control->target_size);
1003 pt2 = NEW_int(Control->target_size);
1005 pass = NEW_int(Control->target_size);
1006 f_go = NEW_int(Control->target_size);
1007 counter_save = (unsigned long int *) NEW_lint(Control->target_size);
1008
1009
1010 depth = 0;
1011
1012entrance_point:
1013
1014
1015 counter++;
1016 counter_save[depth] = counter;
1017
1018
1019 if (f_v) {
1020 cout << "clique_finder::backtrack_search : ";
1021 log_position(depth, counter_save[depth], counter);
1022 cout << " nb_sol=" << solutions.size() << " starting" << endl;
1023 }
1025
1026 if (depth == Control->target_size) {
1027
1028 // We found a clique:
1029
1030 if (f_v) {
1031 cout << "clique_finder::backtrack_search "
1032 "depth == target_depth" << endl;
1033 }
1035 //cout << "storing solution" << endl;
1036 vector<int> sol;
1037 int j;
1038 sol.resize(depth);
1039 for (j = 0; j < depth; j++) {
1040 sol[j] = (int) current_clique[j];
1041 }
1042 solutions.push_back(sol);
1043
1044 }
1045 //nb_sol++;
1046
1047 //cout << "clique_finder::backtrack_search
1048 // before call_back_clique_found" << endl;
1050 //cout << "calling call_back_clique_found" << endl;
1051 (*call_back_clique_found)(this, verbose_level);
1052 }
1053 //cout << "solution " << nb_sol << ", found a clique
1054 // of size target_depth" << endl;
1055 //cout << "clique";
1056 //int_set_print(cout, current_clique, depth);
1057 //cout << " depth = " << depth << endl;
1058 //exit(1);
1059
1060 goto continuation_point;
1061 }
1062
1063
1064 if (Control->f_maxdepth && depth == Control->maxdepth) {
1065 goto continuation_point;
1066 }
1067 if (depth == 0) {
1068 nb_old[depth] = n;
1069 }
1070 else {
1071 nb_old[depth] = nb_points[depth - 1];
1072 }
1073
1074#if 0
1075 if (f_v || (counter % print_interval) == 0) {
1076 log_position(depth, counter_save, counter);
1077 cout << endl;
1078 }
1079
1080 if (f_v && depth) {
1081 log_position(depth, counter_save, counter);
1082 cout << " : # active points from previous level is "
1083 << nb_old << endl;
1084 //cout << " : previous lvl_pt_list[" << depth - 1
1085 // << "] of size " << nb_old << " : " << endl;
1087 // lvl_nb_points[depth - 1]);
1088 //print_point_set(depth, counter_save, counter,
1089 // nb_old, lvl_pt_list[depth - 1]);
1090 //cout << endl;
1091 }
1092#endif
1093
1094 // first pass:
1095 // if depth > 0 and we are not using call_back_find_candidates,
1096 // we apply the lexicographical ordering test.
1097 // the points are required to be greater than the
1098 // previous point in the clique.
1099 // this also eliminates the point
1100 // that was added to the clique in the previous step from pt_list.
1101
1102 if (f_v) {
1103 cout << "clique_finder::backtrack_search : ";
1104 log_position(depth, counter_save[depth], counter);
1105 cout << " first pass" << endl;
1106 }
1107
1108 if (depth && call_back_find_candidates == NULL) {
1109 // if we don't have a find_candidates function,
1110 // then we use the lexicographical ordering.
1111 // The idea is that we may force the clique to be
1112 // constructed in increasing order of its points.
1113 // Hence, now we can eliminate all points that
1114 // are smaller than the most recently added clique point:
1115 nb_new[depth] = 0;
1116 pt1[depth] = current_clique[depth - 1];
1117 for (i = 0; i < nb_old[depth]; i++) {
1118 pt2[depth] = pt_list[i];
1119 if (pt2[depth] > pt1[depth]) {
1120 swap_point(nb_new[depth], i);
1121 nb_new[depth]++;
1122 }
1123 }
1124 }
1125 else {
1126 nb_new[depth] = nb_old[depth];
1127 }
1128
1129
1130 // second pass: find the points that are connected with the
1131 // previously chosen clique point:
1132
1133 nb_old[depth] = nb_new[depth];
1134 if (depth) {
1135 nb_new[depth] = 0;
1136 pt1[depth] = current_clique[depth - 1];
1137 for (i = 0; i < nb_old[depth]; i++) {
1138 // go over all points in the old list:
1139
1140 pt2[depth] = pt_list[i];
1141 if (is_adjacent(depth, pt1[depth], pt2[depth])) {
1142
1143 // point is adjacent, so we keep that point
1144
1145 swap_point(nb_new[depth], i);
1146 nb_new[depth]++;
1147 }
1148
1149 }
1150 }
1151 else {
1152 nb_new[depth] = nb_old[depth];
1153 }
1154
1155
1156 pass[depth] = 2;
1157
1158 if (f_vv) {
1159 log_position(depth, counter_save[depth], counter);
1160 cout << " : pass 2: ";
1161 print_suspicious_point_subset(nb_new[depth], pt_list);
1162 cout << endl;
1163 }
1164
1165
1166#if 0
1167 // higher passes:
1168 // find the points that have sufficiently high degree:
1169
1170 do {
1171 nb_old = nb_new;
1172 nb_new = 0;
1173 for (i = 0; i < nb_old; i++) {
1174 d = degree_of_point(i, nb_old);
1175 if (d >= target_depth - depth - 1) {
1176 swap_point(nb_new, i);
1177 nb_new++;
1178 }
1179 else {
1180 if (point_is_suspicious &&
1182 log_position(depth, counter_save, counter);
1183 cout << " : pass " << pass
1184 << ": suspicious point "
1185 << point_label(pt_list[i])
1186 << " eliminated, d=" << d
1187 << " is less than target_depth - depth - 1 = "
1188 << target_depth - depth - 1 << endl;;
1189 degree_of_point_verbose(i, nb_old);
1190 }
1191 }
1192 }
1193 pass++;
1194
1195 if (f_vv) {
1196 log_position(depth, counter_save, counter);
1197 cout << " : pass " << pass << ": ";
1199 cout << endl;
1200 }
1201
1202 } while (nb_new < nb_old);
1203#endif
1204
1205 nb_points[depth] = nb_new[depth];
1206
1207
1208
1209 if (f_v) {
1210 log_position(depth, counter_save[depth], counter);
1211 cout << "after " << pass[depth] << " passes: "
1212 "nb_points = " << nb_new[depth] << endl;
1213 }
1214
1215
1217 if (f_v) {
1218 log_position(depth, counter_save[depth], counter);
1219 cout << " before call_back_after_reduction" << endl;
1220 }
1221 (*call_back_after_reduction)(this, depth,
1222 nb_points[depth], verbose_level);
1223 if (f_v) {
1224 log_position(depth, counter_save[depth], counter);
1225 cout << " after call_back_after_reduction" << endl;
1226 }
1227 }
1228
1229
1230 {
1231 //int i; //, nb_old;
1232
1234 int reduced_nb_points;
1235
1236 if (f_v) {
1237 log_position(depth, counter_save[depth], counter);
1238 cout << " before call_back_find_candidates" << endl;
1239 }
1240 nb_candidates[depth] = (*call_back_find_candidates)(this,
1241 depth, current_clique,
1242 nb_points[depth], reduced_nb_points, pt_list, pt_list_inv,
1243 candidates + depth * n,
1244 0/*verbose_level*/);
1245
1246 if (f_v) {
1247 log_position(depth, counter_save[depth], counter);
1248 cout << " after call_back_find_candidates "
1249 "nb_candidates=" << nb_candidates[depth] << endl;
1250 }
1251 // The set of candidates is stored in
1252 // candidates + depth * n.
1253 // The number of candidates is in nb_candidates[depth]
1254
1255
1256#ifdef SUSPICIOUS
1257 if (f_vv) {
1258 if (point_is_suspicious) {
1259 cout << "candidate set of size "
1260 << nb_candidates[depth] << endl;
1262 nb_candidates[depth],
1263 candidates + depth * n);
1264 cout << endl;
1265 }
1266 }
1267#endif
1268 nb_points[depth] = reduced_nb_points;
1269 }
1270 else {
1271 // If we don't have a find_candidates callback,
1272 // we take all the points into consideration:
1273
1274 Orbiter->Int_vec.copy(pt_list, candidates + depth * n,
1275 nb_points[depth]);
1276 nb_candidates[depth] = nb_points[depth];
1277 }
1278 }
1279
1280
1281 // added Dec 2014:
1282 if (f_has_print_current_choice_function) {
1283 (*call_back_print_current_choice)(this, depth,
1284 print_current_choice_data, verbose_level);
1285 }
1286
1287 // Now we are ready to go in the backtrack search.
1288 // We'll try each of the points in candidates one by one:
1289
1290 for (current_choice[depth] = 0;
1291 current_choice[depth] < nb_candidates[depth];
1292 current_choice[depth]++, level_counter[depth]++) {
1293
1294
1295 if (f_v) {
1296 log_position(depth, counter_save[depth], counter);
1297 cout << " choice " << current_choice[depth]
1298 << " / " << nb_candidates[depth] << endl;
1299 }
1300
1301 f_go[depth] = TRUE; // Whether we want to go in the recursion.
1302
1303 if (f_level_mod[depth]) {
1304 if ((level_counter[depth] % level_m[depth]) != level_r[depth]) {
1305 f_go[depth] = FALSE;
1306 }
1307 }
1308
1309
1310 pt[depth] = candidates[depth * n + current_choice[depth]];
1311
1312
1313 if (f_vv) {
1314 log_position_and_choice(depth, counter_save[depth], counter);
1315 cout << endl;
1316 }
1317
1318
1319
1320 // We add a point under consideration:
1321
1322 current_clique[depth] = pt[depth];
1323
1324 if (call_back_add_point) {
1325 if (FALSE /*f_v*/) {
1326 cout << "before call_back_add_point" << endl;
1327 }
1328 (*call_back_add_point)(this, depth,
1329 current_clique, pt[depth], 0/*verbose_level*/);
1330 if (FALSE /*f_v*/) {
1331 cout << "after call_back_add_point" << endl;
1332 }
1333 }
1334
1335 if (point_is_suspicious) {
1336 if (point_is_suspicious[pt[depth]]) {
1337 log_position(depth, counter_save[depth], counter);
1338 cout << " : considering clique ";
1339 print_set(depth + 1, current_clique);
1340 //int_set_print(cout, current_clique, depth);
1341 cout << " depth = " << depth << " nb_old=" << nb_old << endl;
1342 f_go[depth] = TRUE;
1343 }
1344 else {
1345 f_go[depth] = FALSE;
1346 }
1347 }
1348
1349
1350 // and now, let's do the recursion:
1351
1352 if (f_go[depth]) {
1353 //backtrack_search(depth + 1, verbose_level);
1354 depth++;
1355 goto entrance_point;
1356
1357
1358continuation_point:
1359 depth--;
1360 } // if (f_go)
1361
1362
1363
1364
1365
1366 // We delete the point:
1367
1369 if (FALSE /*f_v*/) {
1370 cout << "before call_back_delete_point" << endl;
1371 }
1372 (*call_back_delete_point)(this, depth,
1373 current_clique, pt[depth], 0/*verbose_level*/);
1374 if (FALSE /*f_v*/) {
1375 cout << "after call_back_delete_point" << endl;
1376 }
1377 }
1378
1379 } // for current_choice[depth]
1380
1381 if (depth) {
1382 goto continuation_point;
1383 }
1384
1385
1386 FREE_int(nb_old);
1387 FREE_int(nb_new);
1388 FREE_int(pt1);
1389 FREE_int(pt2);
1390 FREE_int(pt);
1391 FREE_int(pass);
1392 FREE_int(f_go);
1393 FREE_lint((long int *) counter_save);
1394
1395 if (f_v) {
1396 cout << "backtrack_search : ";
1397 log_position(depth, counter_save[depth], counter);
1398 cout << " nb_sol=" << solutions.size() << " done" << endl;
1399 }
1400}
1401#endif
1402
1403void clique_finder::open_tree_file(std::string &fname_base)
1404{
1406 fname_tree.assign(fname_base);
1407 fname_tree.append(".tree");
1408 //clique_finder::f_decision_nodes_only = Control->f_decision_nodes_only;
1409 fp_tree = new ofstream;
1410 fp_tree->open(fname_tree);
1411}
1412
1414{
1416
1417 *fp_tree << -1 << endl;
1418 fp_tree->close();
1419 delete fp_tree;
1420 cout << "written file " << fname_tree << " of size "
1421 << Fio.file_size(fname_tree) << endl;
1422}
1423
1424void clique_finder::get_solutions(int *&Sol, long int &nb_solutions, int &clique_sz,
1425 int verbose_level)
1426{
1427 int f_v = (verbose_level >= 1);
1428
1429 if (f_v) {
1430 cout << "clique_finder::get_solutions nb_sol = " << nb_sol << " clique_sz=" << clique_sz << endl;
1431 }
1432 int i, j;
1433
1434 nb_solutions = nb_sol;//solutions.size();
1435 //nb_sol = nb_sol;
1436
1438 cout << "clique_finder::get_solutions we did not store the solutions" << endl;
1439 exit(1);
1440 }
1441
1442 if (nb_sol != solutions.size()) {
1443 cout << "clique_finder::get_solutions nb_sol != solutions.size()" << endl;
1444 exit(1);
1445 }
1446 clique_sz = Control->target_size;
1447 Sol = NEW_int(solutions.size() * Control->target_size);
1448 for (i = 0; i < solutions.size(); i++) {
1449 for (j = 0; j < Control->target_size; j++) {
1450 Sol[i * Control->target_size + j] = solutions[i][j];
1451 }
1452 //solutions.pop_front();
1453 }
1454 if (f_v) {
1455 cout << "clique_finder::get_solutions done" << endl;
1456 }
1457}
1458
1460{
1461 int i, j;
1462
1463 cout << "Suspicious points: ";
1464 for (i = 0; i < n; i++) {
1465 if (point_is_suspicious[i]) {
1466 if (point_labels) {
1467 j = point_labels[i];
1468 }
1469 else {
1470 j = i;
1471 }
1472 cout << j << " ";
1473 }
1474 }
1475 cout << endl;
1476}
1477
1478void clique_finder::print_set(int size, int *set)
1479{
1480 int i, a, b;
1481
1482 cout << "(";
1483 for (i = 0; i < size; i++) {
1484 a = set[i];
1485 b = point_label(a);
1486 cout << b;
1487 if (i < size - 1) {
1488 cout << ", ";
1489 }
1490 }
1491 cout << ")";
1492}
1493
1495{
1496 int i, a, b, cnt = 0;
1497
1498 for (i = 0; i < size; i++) {
1499 a = set[i];
1500 if (!is_suspicious(a)) {
1501 continue;
1502 }
1503 cnt++;
1504 }
1505 cout << cnt << "(";
1506 for (i = 0; i < size; i++) {
1507 a = set[i];
1508 if (!is_suspicious(a)) {
1509 continue;
1510 }
1511 //if (point_is_suspicious && !point_is_suspicious[a])
1512 //continue;
1513 b = point_label(a);
1514 cout << b;
1515 if (i < size - 1) {
1516 cout << ", ";
1517 }
1518 }
1519 cout << ")";
1520}
1521
1523 unsigned long int counter_save, unsigned long int counter)
1524{
1525 cout << "node " << counter << " at depth " << depth << " : ";
1526 log_choice(depth + 1);
1527 cout << " nb_sol=" << solutions.size() << " ";
1528 if (FALSE) {
1529 cout << " clique ";
1531 }
1532}
1533
1535 unsigned long int counter_save, unsigned long int counter)
1536{
1537 cout << "node " << counter << " at depth " << depth << " : ";
1538 log_choice(depth);
1539 if (FALSE) {
1540 cout << " clique ";
1542 }
1543}
1544
1546{
1547 int i;
1548
1549 cout << "choice ";
1550 for (i = 0; i < depth; i++) {
1551 cout << i << ": " << current_choice[i]
1552 << "/" << nb_candidates[i] << "("
1553 << nb_points[i] << ")";
1554 if (i < depth - 1) {
1555 cout << ", ";
1556 }
1557 }
1558 cout << " ";
1559}
1560
1561void clique_finder::swap_point(int idx1, int idx2)
1562{
1564
1565 Sorting.int_vec_swap_points(pt_list, pt_list_inv, idx1, idx2);
1566}
1567
1569 int nb_points, int verbose_level)
1570{
1571 int *D;
1572 int i;
1573
1574 D = NEW_int(nb_points);
1575 for (i = 0; i < nb_points; i++) {
1576 D[i] = degree_of_point(depth, i, nb_points);
1577 }
1579 int f_second = FALSE;
1580
1581 C.init(D, nb_points, f_second, verbose_level);
1582 C.print(FALSE /* f_backwards */);
1583
1584 FREE_int(D);
1585}
1586
1587int clique_finder::degree_of_point(int depth, int i, int nb_points)
1588{
1589 int pti, ptj, j, d;
1590
1591 pti = pt_list[i];
1592 d = 0;
1593 for (j = 0; j < nb_points; j++) {
1594 if (j == i) {
1595 continue;
1596 }
1597 ptj = pt_list[j];
1598 if (is_adjacent(depth, pti, ptj)) {
1599 d++;
1600 }
1601 }
1602 return d;
1603}
1604
1606{
1607 if (point_is_suspicious == NULL) {
1608 return FALSE;
1609 }
1610 return point_is_suspicious[i];
1611}
1612
1614{
1615 if (point_labels) {
1616 return point_labels[i];
1617 }
1618 else {
1619 return i;
1620 }
1621}
1622
1623int clique_finder::is_adjacent(int depth, int i, int j)
1624{
1625 int a;
1626
1627
1628#if 0
1629 if (i == j) {
1630 return 0;
1631 }
1632#endif
1633
1634 //a = adjacency[i * n + j];
1637 }
1638 else {
1639 a = s_ij(i, j);
1640 }
1641
1642
1643#if 0
1644 if (a == -1) {
1645 a = (*call_back_is_adjacent)(this, i, j, 0/* verbose_level */);
1646 adjacency[i * n + j] = a;
1647 adjacency[j * n + i] = a;
1648 }
1649#endif
1650 return a;
1651}
1652
1654 int verbose_level)
1655{
1656 int i;
1657
1658 if (!f_write_tree) {
1659 return;
1660 }
1661
1662#if 0
1663 *fp_tree << "# " << depth << " ";
1664 for (i = 0; i < depth; i++) {
1665 *fp_tree << current_clique[i] << " ";
1666 }
1667 *fp_tree << endl;
1668#endif
1669
1670 if (Control->f_decision_nodes_only && nb_candidates[depth - 1] == 1) {
1671 return;
1672 }
1673 if (Control->f_decision_nodes_only && depth == 0) {
1674 return;
1675 }
1677 int d;
1678
1679 d = 0;
1680 for (i = 0; i < depth; i++) {
1681 if (nb_candidates[i] > 1) {
1682 d++;
1683 }
1684 }
1685 *fp_tree << d << " ";
1686 for (i = 0; i < depth; i++) {
1687 if (nb_candidates[i] > 1) {
1688 *fp_tree << current_clique[i] << " ";
1689 }
1690 }
1691 *fp_tree << endl;
1692 }
1693 else {
1694 *fp_tree << depth << " ";
1695 for (i = 0; i < depth; i++) {
1696 *fp_tree << current_clique[i] << " ";
1697 }
1698 *fp_tree << endl;
1699 }
1700}
1701
1702
1703int clique_finder::s_ij(int i, int j)
1704{
1705 long int k;
1706 int aij;
1708
1709 if (i < 0 || i >= n) {
1710 cout << "clique_finder::s_ij addressing error, i = "
1711 << i << ", n = " << n << endl;
1712 exit(1);
1713 }
1714 if (j < 0 || j >= n) {
1715 cout << "clique_finder::s_ij addressing error, j = "
1716 << j << ", n = " << n << endl;
1717 exit(1);
1718 }
1719 if (i == j) {
1720 return 0;
1721 }
1722
1724 return row_by_row_adjacency_matrix[i][j];
1725 }
1726#if 0
1727 else if (f_has_bitmatrix) {
1728 return bitvector_s_i(bitmatrix_adjacency, i * n + j);
1729 }
1730#endif
1731 else if (f_has_adj_list) {
1732 if (i == j) {
1733 return 0;
1734 }
1735 k = Combi.ij2k_lint(i, j, n);
1736 aij = adj_list_coded[k];
1737 return aij;
1738 }
1739 else if (f_has_bitvector) {
1740 if (i == j) {
1741 return 0;
1742 }
1743 k = Combi.ij2k_lint(i, j, n);
1744 aij = Bitvec_adjacency->s_i(k);
1745 return aij;
1746 }
1747 else {
1748 cout << "clique_finder::s_ij we don't have a matrix" << endl;
1749 exit(1);
1750 }
1751
1752}
1753
1755{
1756 int f_v = (verbose_level >= 1);
1757 long int i, j, k;
1758 int aij;
1759
1760 if (f_v) {
1761 cout << "clique_finder::delinearize_adjacency_list" << endl;
1762 }
1764 for (i = 0; i < n; i++) {
1766 for (j = 0; j < n; j++) {
1768 }
1769 }
1770 k = 0;
1771 for (i = 0; i < n; i++) {
1772 for (j = i + 1; j < n; j++) {
1773 if (f_has_bitvector) {
1774 aij = Bitvec_adjacency->s_i(k);
1775 }
1776 else if (f_has_adj_list) {
1777 aij = adj_list_coded[k];
1778 }
1779 else {
1780 cout << "clique_finder::delinearize_adjacency_list "
1781 "we don't have bitvector or adjacency list" << endl;
1782 exit(1);
1783 }
1784 if (aij) {
1787 }
1788 k++;
1789 }
1790 }
1792 if (f_v) {
1793 cout << "clique_finder::delinearize_adjacency_list done" << endl;
1794 }
1795}
1796
1797
1798
1799
1800
1801}}}
compact storage of 0/1-data as bitvectors
void set_print(std::ostream &ost, int *v, int len)
Definition: int_vec.cpp:1043
void copy(int *from, int *to, long int len)
Definition: int_vec.cpp:167
a collection of functions related to sorted vectors
int int_vec_search(int *v, int len, int a, int &idx)
Definition: sorting.cpp:1094
void int_vec_swap_points(int *list, int *list_inv, int idx1, int idx2)
Definition: sorting.cpp:152
a statistical analysis of data consisting of single integers
void init(int *data, int data_length, int f_second, int verbose_level)
Definition: tally.cpp:72
parameters that control the clique finding process
Definition: graph_theory.h:32
void(* call_back_print_current_choice)(clique_finder *CF, int depth, void *user_data, int verbose_level)
Definition: graph_theory.h:80
int degree_of_point(int depth, int i, int nb_points)
void degree_of_point_statistic(int depth, int nb_points, int verbose_level)
void log_position(int depth, unsigned long int counter_save, unsigned long int counter)
void init(clique_finder_control *Control, std::string &label, int n, int f_has_adj_list, int *adj_list_coded, int f_has_bitvector, data_structures::bitvector *Bitvec_adjacency, int verbose_level)
int(* call_back_is_adjacent)(clique_finder *CF, int pt1, int pt2, int verbose_level)
Definition: graph_theory.h:187
void write_entry_to_tree_file(int depth, int verbose_level)
int(* call_back_find_candidates)(clique_finder *CF, int current_clique_size, int *current_clique, int nb_pts, int &reduced_nb_pts, int *pt_list, int *pt_list_inv, int *candidates, int verbose_level)
Definition: graph_theory.h:180
void get_solutions(int *&Sol, long int &nb_solutions, int &clique_sz, int verbose_level)
void log_position_and_choice(int depth, unsigned long int counter_save, unsigned long int counter)
void(* call_back_delete_point)(clique_finder *CF, int current_clique_size, int *current_clique, int pt, int verbose_level)
Definition: graph_theory.h:177
int solve_decision_problem(int depth, int verbose_level)
void(* call_back_clique_found)(clique_finder *CF, int verbose_level)
Definition: graph_theory.h:171
void init_restrictions(int *restrictions, int verbose_level)
void(* call_back_add_point)(clique_finder *CF, int current_clique_size, int *current_clique, int pt, int verbose_level)
Definition: graph_theory.h:174
void(* call_back_after_reduction)(clique_finder *CF, int depth, int nb_points, int verbose_level)
Definition: graph_theory.h:191
#define NEW_pchar(n)
Definition: foundations.h:635
#define FREE_pchar(p)
Definition: foundations.h:648
#define FREE_int(p)
Definition: foundations.h:640
#define Int_vec_zero(A, B)
Definition: foundations.h:713
#define NEW_char(n)
Definition: foundations.h:632
#define NEW_int(n)
Definition: foundations.h:625
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define Int_vec_copy(A, B, C)
Definition: foundations.h:693
#define FREE_char(p)
Definition: foundations.h:646
#define FREE_lint(p)
Definition: foundations.h:642
#define NEW_lint(n)
Definition: foundations.h:628
orbiter_kernel_system::orbiter_session * Orbiter
global Orbiter session
the orbiter library for the classification of combinatorial objects