Orbiter 2022
Combinatorial Objects
dlx_solver.cpp
Go to the documentation of this file.
1/*
2 * dlx_solver.cpp
3 *
4 * Created on: Jan 12, 2022
5 * Author: betten
6 */
7
8// based on earlier work from before 2013 by:
9// Xi Chen
10// Student, Computer Science and Engineering
11// University of New South Wales
12// Kensington
13// hypernewbie@gmail.com
14// http://cgi.cse.unsw.edu.au/~xche635/dlx_sodoku/
15
16
17
18#include "foundations.h"
19
20
21using namespace std;
22
23namespace orbiter {
24namespace layer1_foundations {
25namespace solvers {
26
27
28
29
30#define DLX_FANCY_LEVEL 30
31
32
33
34
36{
37 Descr = NULL;
38
39 Input_data = NULL;
40 nb_rows = 0;
41 nb_cols = 0;
42
43
44 //std::string solutions_fname;
45 fp_sol = NULL;
46
47 //std::string tree_fname;
49
50 fp_tree = NULL;
51
52
53 nRow = 0;
54 nCol = 0;
55
56 f_has_RHS = FALSE; // [nCol]
57 target_RHS = NULL; // [nCol]
58 current_RHS = NULL; // [nCol]
59 current_row = NULL; // [nCol]
60 current_row_save = NULL; // [sum_rhs]
61
62
63 // we allow three types of conditions:
64 // equations t_EQ
65 // inequalities t_LE
66 // zero or a fixed value t_ZOR
67
68 f_type = FALSE;
69 type = NULL; // [nCol]
70 changed_type_columns = NULL; // [nCol]
71 nb_changed_type_columns = NULL; // [sum_rhs]
73
74 Result = NULL; // [nRow]
75 Nb_choices = NULL; // [nRow]
76 Cur_choice = NULL; // [nRow]
77 Cur_col = NULL; // [nRow]
78 Nb_col_nodes = NULL; // [nCol]
79 nb_sol = 0;
81 Matrix = NULL; // [nRow * nCol]
82 Root = NULL;
86
87}
88
89
91{
92 if (Input_data) {
94 }
95}
96
97
100 int verbose_level)
101{
102 int f_v = (verbose_level >= 1);
103
104 if (f_v) {
105 cout << "dlx_solver::init" << endl;
106 }
107
109
110
111 if (Descr->f_data_label) {
114 }
115 else if (Descr->f_data_matrix) {
120 }
121 else {
122 cout << "dlx_solver::init please use option -data_label or use data_matrix" << endl;
123 exit(1);
124 }
125
126 if (f_v) {
127 cout << "dlx_solver::init done" << endl;
128 }
129}
130
131
132
134{
135 return i - 1 < 0 ? nCol - 1 : i - 1;
136}
137
139{
140 return (i + 1) % nCol;
141}
142
144{
145 return i - 1 < 0 ? nRow - 1 : i - 1;
146}
147
149{
150 return (i + 1) % nRow;
151}
152
153
155 void (*callback_solution_found)(
156 int *solution, int len, int nb_sol, void *data),
157 void *callback_solution_found_data)
158{
164}
165
167{
169}
170
171#if 0
172void dlx_solver::Test()
173{
174 int Data[] = {
175 0, 0, 1, 0, 1, 1, 0,
176 1, 0, 0, 1, 0, 0, 1,
177 0, 1, 1, 0, 0, 1, 0,
178 1, 0, 0, 1, 0, 0, 0,
179 0, 1, 0, 0, 0, 0, 1,
180 0, 0, 0, 1, 1, 0, 1,
181 };
182 // solutions: rows 0, 3, 4 make 1,1,1,1,1,1,1
183
184 int nb_rows = 6;
185 int nb_cols = 7;
186 int nb_sol, nb_backtrack;
187
189}
190
191void dlx_solver::TransposeAppendAndSolve(int *Data, int nb_rows, int nb_cols,
192 int verbose_level)
193{
194 int *Data2;
195 int i, j;
196
197 Data2 = NEW_int(nb_cols * nb_rows);
198 for (i = 0; i < nb_rows; i++) {
199 for (j = 0; j < nb_cols; j++) {
200 Data2[j * nb_rows + i] = Data[i * nb_cols + j];
201 }
202 }
204 verbose_level);
205
206 FREE_int(Data2);
207}
208
209void dlx_solver::TransposeAndSolveRHS(int *Data, int nb_rows, int nb_cols,
210 int *RHS, int f_has_type, diophant_equation_type *type,
211 int verbose_level)
212{
213 int *Data2;
214 int i, j;
215
216 Data2 = NEW_int(nb_cols * nb_rows);
217 for (i = 0; i < nb_rows; i++) {
218 for (j = 0; j < nb_cols; j++) {
219 Data2[j * nb_rows + i] = Data[i * nb_cols + j];
220 }
221 }
223 RHS, f_has_type, type,
224 verbose_level);
225
226 FREE_int(Data2);
227}
228
229void dlx_solver::AppendRowAndSolve(int *Data, int nb_rows, int nb_cols,
230 int verbose_level)
231{
232 int *Data2;
233 int i, j;
234
235 Data2 = NEW_int((nb_rows + 1) * nb_cols);
236 for (i = 0; i < nb_rows; i++) {
237 for (j = 0; j < nb_cols; j++) {
238 Data2[i * nb_cols + j] = Data[i * nb_cols + j];
239 }
240 }
241 i = nb_rows;
242 for (j = 0; j < nb_cols; j++) {
243 Data2[i * nb_cols + j] = 1;
244 }
245 Solve(Data2, nb_rows + 1, nb_cols,
246 verbose_level);
247
248 FREE_int(Data2);
249}
250
251void dlx_solver::AppendRowAndSolveRHS(int *Data, int nb_rows, int nb_cols,
252 int *RHS, int f_has_type, diophant_equation_type *type,
253 int verbose_level)
254{
255 int *Data2;
256 int i, j;
257
258 Data2 = NEW_int((nb_rows + 1) * nb_cols);
259 for (i = 0; i < nb_rows; i++) {
260 for (j = 0; j < nb_cols; j++) {
261 Data2[i * nb_cols + j] = Data[i * nb_cols + j];
262 }
263 }
264
265 // fill in the RHS in the header:
266 i = nb_rows;
267 for (j = 0; j < nb_cols; j++) {
268 Data2[i * nb_cols + j] = RHS[j];
269 }
270
271
272 Solve_with_RHS(Data2, nb_rows + 1, nb_cols,
273 RHS, f_has_type, type,
274 verbose_level);
275
276 FREE_int(Data2);
277}
278#endif
279
280void dlx_solver::Solve(int verbose_level)
281{
282 int f_v = (verbose_level >= 1);
283
284 if (f_v) {
285 cout << "dlx_solver::Solve nb_rows = " << nb_rows << " nb_cols = "
286 << nb_cols << endl;
287 }
288
289 int *Input_data_transposed;
290
291 int nr, nc;
292 int i, j;
293
294 nr = nb_cols;
295 nr++; // add a row of ones
296 nc = nb_rows;
297
298 Input_data_transposed = NEW_int(nr * nc);
299 for (i = 0; i < nb_cols; i++) {
300 for (j = 0; j < nc; j++) {
301 Input_data_transposed[i * nc + j] = Input_data[j * nb_cols + i];
302 }
303 }
304 i = nb_cols;
305 for (j = 0; j < nc; j++) {
306 Input_data_transposed[i * nc + j] = 1;
307 }
308
309
310 if (f_v) {
311 cout << "dlx_solver::Solve before CreateMatrix" << endl;
312 }
313 CreateMatrix(Input_data_transposed, nr, nc, verbose_level - 1);
314 if (f_v) {
315 cout << "dlx_solver::Solve after CreateMatrix" << endl;
316 }
317
318 open_solution_file(verbose_level);
319
320 open_tree_file(verbose_level);
321
323
324
325 Search(0);
326
327
328 if (f_v) {
329 cout << "dlx_solver::Solve finds " << nb_sol << " solutions "
330 "with nb_backtrack_nodes=" << nb_backtrack_nodes << endl;
331 }
332
335
336
337
338
339 DeleteMatrix();
340
341 FREE_int(Input_data_transposed);
342
343 if (f_v) {
344 cout << "dlx_solver::Solve done" << endl;
345 }
346}
347
348void dlx_solver::Solve_with_RHS(int *RHS, int f_has_type,
350 int verbose_level)
351{
352 int f_v = (verbose_level >= 1);
353
354 if (f_v) {
355 cout << "dlx_solver::Solve_with_RHS nb_rows = " << nb_rows
356 << " nb_cols = " << nb_cols << endl;
357 }
358
359
360 CreateMatrix(Input_data, nb_rows, nb_cols, verbose_level - 1);
361 Create_RHS(nb_cols, RHS, f_has_type, type, verbose_level);
362
363 open_solution_file(verbose_level);
364
365 if (Descr->f_write_tree) {
366 open_tree_file(verbose_level);
367 }
368
370
371
372
373 SearchRHS(0, verbose_level);
374
375
376
377
378 if (f_v) {
379 cout << "dlx_solver::Solve_with_RHS finds "
380 << nb_sol << " solutions "
381 "with nb_backtrack_nodes="
382 << nb_backtrack_nodes << endl;
383 }
384
387
388
389
390
391 DeleteMatrix();
392 Delete_RHS();
393
394
395 if (f_v) {
396 cout << "dlx_solver::Solve_with_RHS done" << endl;
397 }
398}
399
400void dlx_solver::open_solution_file(int verbose_level)
401{
403
405 solutions_fname.append("_solutions.txt");
406
407 fp_sol = new ofstream;
408 fp_sol->open(solutions_fname);
409 }
410}
411
413{
415
416
417
418
419 *fp_sol << -1 << " " << nb_sol << " "
420 << nb_backtrack_nodes << endl;
421 fp_sol->close();
422 delete fp_sol;
423 }
424}
425
426void dlx_solver::open_tree_file(int verbose_level)
427{
428 if (Descr->f_write_tree) {
429
430 tree_fname.assign(Descr->label_txt);
431 tree_fname.append("_tree.txt");
432
433
434 write_tree_cnt = 0;
435 fp_tree = new ofstream;
436 fp_tree->open(tree_fname);
437 *fp_tree << "# " << nCol << endl;
438 }
439}
440
442{
443 if (Descr->f_write_tree) {
444 *fp_tree << -1 << " " << write_tree_cnt << endl;
445 delete fp_tree;
446 }
447}
448
449
450void dlx_solver::Create_RHS(int nb_cols, int *RHS, int f_has_type,
451 diophant_equation_type *type, int verbose_level)
452{
453 int f_v = (verbose_level >= 1);
454 int i, sum_rhs;
455
456 if (f_v) {
457 cout << "dlx_solver::Create_RHS" << endl;
458 }
459
460 f_has_RHS = TRUE;
461 if (nb_cols != nCol) {
462 cout << "dlx_solver::Create_RHS nb_cols != nCol" << endl;
463 exit(1);
464 }
465
466
470
471 for (i = 0; i < nCol; i++) {
472 target_RHS[i] = RHS[i];
473 current_RHS[i] = 0;
474 current_row[i] = -1;
475 }
476
477 sum_rhs = 0;
478 for (i = 0; i < nCol; i++) {
479 sum_rhs += target_RHS[i];
480 }
481
482 if (f_v) {
483 cout << "sum_rhs=" << sum_rhs << endl;
484 }
485
486 current_row_save = NEW_int(sum_rhs);
487
489 if (f_has_type) {
490 for (i = 0; i < nCol; i++) {
491 dlx_solver::type[i] = type[i];
492 }
493 }
494 else {
495 for (i = 0; i < nCol; i++) {
497 }
498 }
502
503 if (f_v) {
504 cout << "dlx_solver::Create_RHS done" << endl;
505 }
506}
507
509{
510 if (target_RHS) {
512 target_RHS = NULL;
513 }
514 if (current_RHS) {
516 current_RHS = NULL;
517 }
518 if (current_row) {
520 current_row = NULL;
521 }
522 if (current_row_save) {
524 current_row_save = NULL;
525 }
526 if (f_type) {
528 type = NULL;
529 }
530}
531
533 int nb_rows, int nb_cols, int verbose_level)
534{
535 int f_v = (verbose_level >= 1);
536 int a, b, i, j;
537
538 if (f_v) {
539 cout << "dlx_solver::CreateMatrix" << endl;
540 }
541 nRow = nb_rows;
542 nCol = nb_cols;
543 nb_sol = 0;
544
545 if (f_v) {
546 cout << "dlx_solver::CreateMatrix" << endl;
547 cout << "The " << nb_rows << " x " << nb_cols
548 << " matrix is:" << endl;
549 for (i = 0; i < nb_rows; i++) {
550 for (j = 0; j < nb_cols; j++) {
551 cout << Data[i * nb_cols + j];
552 }
553 cout << endl;
554 }
555 //int_matrix_print(Data, nb_rows, nb_cols);
556 cout << endl;
557 }
558
559 Matrix = new dlx_node[nRow * nCol];
560 Root = new dlx_node;
561 //RowHeader = new pdlx_node[nRow];
562
563
569
570 for (j = 0; j < nCol; j++) {
571 Nb_col_nodes[j] = 0;
572 }
573
574
575 // Build toroidal linked list according to the data matrix:
576 for (a = 0; a < nRow; a++) {
577 for (b = 0; b < nCol; b++) {
578 Matrix[a * nCol + b].row = a;
579 Matrix[a * nCol + b].col = b;
580 }
581 }
582
583 // Connect the coefficients which are nonzero to
584 // their neighbors up and down and left and right:
585
586 if (f_v) {
587 cout << "dlx_solver::CreateMatrix building the toroidal matrix" << endl;
588 }
589 for (a = 0; a < nRow; a++) {
590 for (b = 0; b < nCol; b++) {
591 if (Data[a * nCol + b] != 0) {
592
593 // Left pointer
594 i = a;
595 j = b;
596 do {
597 j = dataLeft(j);
598 } while (Data[i * nCol + j] == 0);
599
600 Matrix[a * nCol + b].Left = &Matrix[i * nCol + j];
601
602 // Right pointer
603 i = a;
604 j = b;
605 do {
606 j = dataRight(j);
607 } while (Data[i * nCol + j] == 0);
608
609 Matrix[a * nCol + b].Right = &Matrix[i * nCol + j];
610
611 // Up pointer
612 i = a;
613 j = b;
614 do {
615 i = dataUp(i);
616 } while (Data[i * nCol + j] == 0);
617
618 Matrix[a * nCol + b].Up = &Matrix[i * nCol + j];
619
620 // Down pointer
621 i = a;
622 j = b;
623 do {
624 i = dataDown(i);
625 } while (Data[i * nCol + j] == 0);
626
627 Matrix[a * nCol + b].Down = &Matrix[i * nCol + j];
628
629#if 0
630 cout << "at " << a << "/" << b << ":";
631 cout << " Left="; print_position(Matrix[a * nCol + b].Left);
632 cout << " Right="; print_position(Matrix[a * nCol + b].Right);
633 cout << " Up="; print_position(Matrix[a * nCol + b].Up);
634 cout << " Down="; print_position(Matrix[a * nCol + b].Down);
635 cout << endl;
636#endif
637 // Header pointer at the very bottom:
638 Matrix[a * nCol + b].Header =
639 &Matrix[(nRow - 1) * nCol + b];
640 //Row Header
641 //RowHeader[a] = &Matrix[a * nCol + b];
642 }
643 }
644 }
645 if (f_v) {
646 cout << "dlx_solver::CreateMatrix building the toroidal matrix finished" << endl;
647 }
648
649 // Count the number of nodes in each column
650 // (i.e. the number of ones in the column of the matrix)
651 for (j = 0; j < nCol; j++) {
652 Nb_col_nodes[j] = 0;
653
654 if (f_v) {
655 cout << "dlx_solver::CreateMatrix counting nodes in column " << j << endl;
656 }
657 dlx_node *ColNode, *RowNode;
658
659 // this is the RHS
660 ColNode = &Matrix[(nRow - 1) * nCol + j];
661
662 for (RowNode = ColNode->Down; RowNode != ColNode; RowNode = RowNode->Down) {
663 Nb_col_nodes[j]++;
664 }
665 }
666
667#if 0
668 for (a = 0; a < nCol; a++) {
669 Matrix[(nRow - 1) * nCol + a].row = nRow - 1;
670 Matrix[(nRow - 1) * nCol + a].col = a;
671 }
672#endif
673 //Insert root at the end of all RHS nodes:
674 Root->Left = &Matrix[(nRow - 1) * nCol + (nCol - 1)];
675 Root->Right = &Matrix[(nRow - 1) * nCol + 0];
676 Matrix[(nRow - 1) * nCol + nCol - 1].Right = Root;
677 Matrix[(nRow - 1) * nCol + 0].Left = Root;
678 Root->row = -1;
679 Root->col = -1;
680 if (f_v) {
681 cout << "dlx_solver::CreateMatrix done" << endl;
682 }
683}
684
686{
687 delete [] Matrix;
688 delete Root;
693}
694
696{
697 dlx_node *Node;
698
699 for (Node = Root->Right; Node != Root; Node = Node->Right) {
700 if (Node->col == c) {
701 return Node;
702 }
703 }
704 cout << "dlx_solver::get_column_header cannot find column " << c << endl;
705 exit(1);
706}
707
709{
710 int j, nb_node, nb_node_min = 0;
711 dlx_node *Node, *Node_min = NULL;
712
713 for (Node = Root->Right; Node != Root; Node = Node->Right) {
714 j = Node->col;
715 nb_node = Nb_col_nodes[j];
716 if (Node_min == NULL) {
717 Node_min = Node;
718 nb_node_min = nb_node;
719 }
720 else {
721 if (nb_node < nb_node_min) {
722 Node_min = Node;
723 nb_node_min = nb_node;
724 }
725 }
726 }
727 return Node_min;
728}
729
731{
732 if (Root->Right == Root) {
733 cout << "dlx_solver::ChooseColumn Root->Right == Root" << endl;
734 exit(1);
735 }
736 return Root->Right;
737}
738
740{
741 int j, nb_node, nb_node_min = 0;
742 dlx_node *Node, *Node_min = NULL;
743
744 for (Node = Root->Right; Node != Root; Node = Node->Right) {
745 j = Node->col;
746 if (type[j] == t_LE || type[j] == t_ZOR) {
747 continue;
748 }
749 nb_node = Nb_col_nodes[j];
750 if (Node_min == NULL) {
751 Node_min = Node;
752 nb_node_min = nb_node;
753 }
754 else {
755 if (nb_node < nb_node_min) {
756 Node_min = Node;
757 nb_node_min = nb_node;
758 }
759 }
760 }
761 return Node_min;
762}
763
765{
766 dlx_node *Node;
767 int j;
768
769 if (Root->Right == Root) {
770 cout << "dlx_solver::ChooseColumn Root->Right == Root" << endl;
771 exit(1);
772 }
773
774 for (Node = Root->Right; Node != Root; Node = Node->Right) {
775 j = Node->col;
776 if (type[j] == t_LE || type[j] == t_ZOR) {
777 continue;
778 }
779 return Node;
780 }
781 cout << "dlx_solver::ChooseColumnRHS could not find a node" << endl;
782 exit(1);
783}
784
786{
787 if (Descr->f_write_tree) {
788 int i;
789 *fp_tree << k;
790 for (i = 0; i < k; i++) {
791 *fp_tree << " " << Result[i];
792 }
793 *fp_tree << endl;
795 }
796}
797
799{
800 if ((nb_backtrack_nodes & ((1 << 20) - 1)) == 0) {
801 int a, d;
802
803 a = nb_backtrack_nodes >> 20;
804 cout << "Search: " << a << " * 2^20 nodes, "
805 << " nb_sol=" << nb_sol << " position ";
806
808
809 for (int i = 0; i < d; i++) {
810 cout << Cur_choice[i] << " / " << Nb_choices[i];
811 if (i < d - 1) {
812 cout << ", ";
813 }
814 }
815 cout << endl;
816 }
817}
818
820{
821#if 0
822 if (f_v) {
823 cout << "solution " << nb_sol << " : ";
824 //PrintSolution();
825 int_vec_print(cout, Result, k);
826 cout << endl;
827 }
828#endif
830 int i;
831 *fp_sol << k;
832 for (i = 0; i < k; i++) {
833 *fp_sol << " " << Result[i];
834 }
835 *fp_sol << endl;
836 }
838 (*callback_solution_found)(Result,
840 }
841 nb_sol++;
842}
843
845{
846 dlx_node *RowNode;
847 int r, d;
848
849 Nb_choices[k] = 0;
850
852
853 if (k < d) {
854 for (RowNode = Column->Down;
855 RowNode != Column;
856 RowNode = RowNode->Down) {
857 Nb_choices[k]++;
858 }
859
860 if (FALSE) {
861 cout << "Choice set: ";
862 for (RowNode = Column->Down;
863 RowNode != Column;
864 RowNode = RowNode->Down) {
865 r = RowNode->row;
866 cout << " " << r;
867 }
868 cout << endl;
869 }
870 }
871}
872
874{
875 dlx_node *N;
876 int c;
877
878#if 0
879 cout << "c : current_RHS[c] : target_RHS[c]" << endl;
880 for (c = 0; c < nCol; c++) {
881 cout << c << " : " << current_RHS[c]
882 << " : " << target_RHS[c] << endl;
883 }
884#endif
885 N = Root->Left;
886 while (TRUE) {
887 if (N == Root) {
888 //cout << "is done" << endl;
889 return TRUE;
890 }
891 c = N->col;
892 if (IsColumnNotDone(c)) {
893 //cout << "is not done because of column " << c << endl;
894 return FALSE;
895 }
896 N = N->Left;
897 }
898}
899
901{
902 if (current_RHS[c] == target_RHS[c]) {
903 return TRUE;
904 }
905 return FALSE;
906}
907
909{
910 if (type[c] == t_EQ && current_RHS[c] < target_RHS[c]) {
911 return TRUE;
912 }
913 return FALSE;
914}
915
917{
918 //cout << "Search k=" << k << endl;
919 //print_root();
920
921 write_tree(k);
922
925
926 if (Root->Left == Root && Root->Right == Root) {
927 // All header columns gone means we have a valid solution!
928
930 return;
931 }
932
933
934 dlx_node *Column;
935
936
937 if (k < DLX_FANCY_LEVEL) {
938 Column = ChooseColumnFancy();
939 }
940 else {
941 Column = ChooseColumn();
942 }
943
944 Cover(Column);
945
946 dlx_node *RowNode;
947 dlx_node *RightNode;
948 dlx_node *LeftNode;
949
950 count_nb_choices(k, Column);
951
952 Cur_choice[k] = 0;
953
954 // we loop over all nodes in that column:
955
956 for (RowNode = Column->Down;
957 RowNode != Column;
958 RowNode = RowNode->Down, Cur_choice[k]++) {
959
960 // Try this row node on!
961 Result[k] = RowNode->row;
962
963 // Since we have made our choice of row, we can now remove the
964 // columns where the chosen row has a one.
965 // These equations are also satisfied now.
966
967 for (RightNode = RowNode->Right;
968 RightNode != RowNode;
969 RightNode = RightNode->Right) {
970 Cover(RightNode->Header);
971 }
972
973 // And we recurse:
974 Search(k + 1);
975
976
977 // corrected an error in the original version:
978 for (LeftNode = RowNode->Left;
979 LeftNode != RowNode;
980 LeftNode = LeftNode->Left) {
981 UnCover(LeftNode->Header);
982 }
983 }
984
985 UnCover(Column);
986}
987
988void dlx_solver::SearchRHS(int k, int verbose_level)
989{
990 int f_v = (verbose_level >= 1);
991
992#if 0
993 if ((nb_backtrack_nodes % 100000) == 0) {
994 verbose_level += 1;
995 }
996#endif
997
998
999 if (f_v) {
1000 int i;
1001
1002 cout << "dlx_solver::SearchRHS k=" << k
1003 << " nb_backtrack_nodes="
1004 << nb_backtrack_nodes << " : ";
1005 for (i = 0; i < k; i++) {
1006 cout << Cur_choice[i] << "/" << Nb_choices[i];
1007 if (i < k - 1) {
1008 cout << ", ";
1009 }
1010 }
1011 cout << endl;
1012 }
1013 //print_root();
1014
1015 write_tree(k);
1016
1019
1020 if (IsDone()) {
1021 // All header columns gone means we have a valid solution!
1022 if (f_v) {
1023 cout << "dlx_solver::SearchRHS k=" << k << " solution ";
1024 Int_vec_print(cout, Result, k);
1025 cout << " found" << endl;
1026 }
1027
1029 return;
1030 }
1031
1032
1033 dlx_node *Column;
1034 int r, c, f_done, c0, c2;
1035
1036
1037 Column = NULL;
1038
1039 // First we check if we the column from
1040 // the previous level is satisfied or not.
1041 // If it is not, we need to work on this column again.
1042 if (k) {
1043 c0 = Cur_col[k - 1];
1044 if (IsColumnNotDone(c0)) {
1045 Column = get_column_header(c0);
1046 }
1047 }
1048
1049 if (Column == NULL) {
1050 if (k < DLX_FANCY_LEVEL) {
1051 Column = ChooseColumnFancyRHS();
1052 }
1053 else {
1054 Column = ChooseColumnRHS();
1055 }
1056 }
1057
1058 c = Column->col;
1059 Cur_col[k] = c;
1060 if (f_v) {
1061 cout << "dlx_solver::SearchRHS k=" << k
1062 << " choosing column " << c << endl;
1063 }
1064
1066 if (current_RHS[c] == 0) {
1067 current_row[c] = -1;
1068 }
1069 current_RHS[c]++;
1070
1071 if (f_v) {
1072 cout << "dlx_solver::SearchRHS k=" << k << " choosing column " << c
1073 << " RHS = " << current_RHS[c] << " / "
1074 << target_RHS[c] << endl;
1075 }
1076
1077 if (current_RHS[c] > target_RHS[c]) {
1078 cout << "dlx_solver::SearchRHS current_RHS[c] > "
1079 "target_RHS[c] error" << endl;
1080 exit(1);
1081 }
1082
1083
1084 f_done = IsColumnDone(c);
1085 // have we reached the RHS in this column?
1086
1087 if (f_done) {
1088 if (f_v) {
1089 cout << "dlx_solver::SearchRHS k=" << k << " column " << c
1090 << " is done, so we cover it" << endl;
1091 }
1092 // we have reached the RHS in this column,
1093 // so we cannot place any more in this column.
1094 // Hence, rows which have a
1095 // nonzero entry in this column can be removed.
1096 Cover(Column);
1097 }
1098
1099 dlx_node *RowNode;
1100 dlx_node *RightNode;
1101 dlx_node *LeftNode;
1102
1103 count_nb_choices(k, Column);
1104
1105 if (f_v) {
1106 cout << "dlx_solver::SearchRHS k=" << k << " column " << c
1107 << " number of choices is " << Nb_choices[k] << endl;
1108 }
1109
1110
1111 Cur_choice[k] = 0;
1112
1113 // we loop over all nodes in that column:
1114
1115
1116 for (RowNode = Column->Down; RowNode != Column;
1117 RowNode = RowNode->Down, Cur_choice[k]++) {
1118
1119 // Try this row node on!
1120 r = RowNode->row;
1121
1123
1124
1125 Result[k] = r;
1126
1127 if (f_v) {
1128 cout << "dlx_solver::SearchRHS k=" << k << " column " << c
1129 << " choice " << Cur_choice[k] << " / "
1130 << Nb_choices[k] << " which is ";
1131 Int_vec_print(cout, Result, k + 1);
1132 cout << endl;
1133 }
1134
1135#if 1
1136
1137 // The next test is needed to prevent
1138 // solutions from being found repeatedly,
1139 // namely once for each rearrangement
1140 // of the rows associated to a fixed column
1141 // This can only happen if the RHS
1142 // in that column is greater than one.
1143
1144
1145 if (r <= current_row[c]) {
1146 // we should not choose this row,
1147 // because we have dealt with this row before.
1148 if (f_v) {
1149 cout << "dlx_solver::SearchRHS skip" << endl;
1150 }
1151 continue;
1152 }
1153#endif
1154
1155
1156 current_row[c] = r;
1157 // store the current row so that
1158 // if we get to choose another node in this column,
1159 // we require that that node is
1160 // in a row higher than the current one.
1161 // In particular, we cannot choose the same node twice.
1162
1163 // Since we have made our choice of row,
1164 // we can now remove the
1165 // columns where the RHS is now satisfied
1166 // because the chosen row has a one in it
1167 // (other than the column c that we are working on).
1168 // For each of these columns we need to call Cover
1169 // to remove further rows which have a one in that column
1170
1171 for (RightNode = RowNode->Right;
1172 RightNode != RowNode;
1173 RightNode = RightNode->Right) {
1174 c2 = RightNode->col;
1175 if (c2 != c) {
1176 current_RHS[c2]++;
1177 if (current_RHS[c2] > target_RHS[c2]) {
1178 cout << "dlx_solver::SearchRHS current_RHS[c2] > "
1179 "target_RHS[c2] error" << endl;
1180 exit(1);
1181 }
1182 if (current_RHS[c2] == target_RHS[c2]) {
1183 Cover(RightNode->Header);
1184 }
1185
1186#if 1
1187 // Here we change the type of a condition:
1188 // ZOR's are changed into EQ's.
1189 // We record which ones we changed
1190 // so we can later change back.
1191
1192 if (current_RHS[c2] == 1 && type[c2] == t_ZOR) {
1193 type[c2] = t_EQ;
1197 cout << "dlx_solver::SearchRHS nb_changed_type_columns_total >= nCol" << endl;
1198 exit(1);
1199 }
1201 }
1202#endif
1203 }
1204 }
1205
1206
1207
1208 if (f_v) {
1209 cout << "dlx_solver::SearchRHS k=" << k << " column " << c
1210 << " choice " << Cur_choice[k] << " / "
1211 << Nb_choices[k] << " which is ";
1212 Int_vec_print(cout, Result, k + 1);
1213 cout << " recursing" << endl;
1214 }
1215
1216
1217 // And we recurse:
1218 SearchRHS(k + 1, verbose_level);
1219
1220 if (f_v) {
1221 cout << "dlx_solver::SearchRHS k=" << k << " column " << c
1222 << " choice " << Cur_choice[k] << " / "
1223 << Nb_choices[k] << " which is ";
1224 Int_vec_print(cout, Result, k + 1);
1225 cout << " after recursion" << endl;
1226 }
1227
1228
1229 // corrected an error in the original version:
1230 for (LeftNode = RowNode->Left;
1231 LeftNode != RowNode;
1232 LeftNode = LeftNode->Left) {
1233 c2 = LeftNode->col;
1234 if (c2 != c) {
1235 if (current_RHS[c2] == target_RHS[c2]) {
1236 UnCover(LeftNode->Header);
1237 }
1238 current_RHS[c2]--;
1239 }
1240 }
1241
1242#if 1
1243 // Here we undo the change of type from above
1244 // EQ's are changed back into ZOR's:
1245
1246 int i;
1247
1248 for (i = 0; i < nb_changed_type_columns[k]; i++) {
1250 if (current_RHS[c2] != 0) {
1251 cout << "dlx_solver::SearchRHS current_RHS[c2] != 0 error, "
1252 "current_RHS[c2]=" << current_RHS[c2]
1253 << " c2=" << c2
1254 << " c=" << c << " k=" << k << endl;
1255 exit(1);
1256 }
1257 type[c2] = t_ZOR;
1258 }
1259#endif
1260 }
1261
1262
1263
1264 if (f_done) {
1265 // undo the Cover operation
1266 UnCover(Column);
1267 }
1268
1270 current_RHS[c]--;
1271
1272}
1273
1275{
1276
1277 //cout << "Cover" << endl;
1278 dlx_node *RowNode, *RightNode;
1279 int j;
1280
1281 // remove the column by crosslisting
1282 // the left and right neighbors.
1283 // recall that this is in the header.
1284
1285 ColNode->Right->Left = ColNode->Left;
1286 ColNode->Left->Right = ColNode->Right;
1287
1288 // remove rows which have a 1 in column ColNode
1289 // updates column counts
1290
1291 // Go down the column,
1292 // visit each row with a 1 in that particular column
1293 // and remove that row by directly connecting
1294 // the up-neighbor to the down-neighbor.
1295 // This is done for each entry 1 in that row
1296 // which is not in the particular column that we started with.
1297
1298 for (RowNode = ColNode->Down;
1299 RowNode != ColNode;
1300 RowNode = RowNode->Down) {
1301 //cout << "RowNode " << RowNode->row
1302 //<< "/" << RowNode->col << endl;
1303
1304 for (RightNode = RowNode->Right;
1305 RightNode != RowNode;
1306 RightNode = RightNode->Right) {
1307 j = RightNode->col;
1308 Nb_col_nodes[j]--;
1309 RightNode->Up->Down = RightNode->Down;
1310 RightNode->Down->Up = RightNode->Up;
1311 }
1312 }
1313
1314
1315 //cout << "Cover done" << endl;
1316}
1317
1319{
1320
1321 //cout << "dlx_solver::UnCover" << endl;
1322 dlx_node *RowNode, *LeftNode;
1323 int j;
1324
1325 // puts rows back in which have previously been removed in Cover:
1326
1327 for (RowNode = ColNode->Up;
1328 RowNode!= ColNode;
1329 RowNode = RowNode->Up) {
1330 for (LeftNode = RowNode->Left;
1331 LeftNode != RowNode;
1332 LeftNode = LeftNode->Left) {
1333 j = LeftNode->col;
1334 Nb_col_nodes[j]++;
1335 LeftNode->Up->Down = LeftNode;
1336 LeftNode->Down->Up = LeftNode;
1337 }
1338 }
1339
1340 // put the column back in:
1341
1342 ColNode->Right->Left = ColNode;
1343 ColNode->Left->Right = ColNode;
1344
1345
1346 //cout << "dlx_solver::UnCover done" << endl;
1347}
1348
1349
1350
1351}}}
1352
1353
void get_matrix_from_label(std::string &label, int *&v, int &m, int &n)
description of a problem instance for dancing links solver
Definition: solvers.h:406
void TransposeAndSolveRHS(int *Data, int nb_rows, int nb_cols, int *RHS, int f_has_type, diophant_equation_type *type, int verbose_level)
void SearchRHS(int k, int verbose_level)
Definition: dlx_solver.cpp:988
void init(dlx_problem_description *Descr, int verbose_level)
Definition: dlx_solver.cpp:98
void TransposeAppendAndSolve(int *Data, int nb_rows, int nb_cols, int verbose_level)
void count_nb_choices(int k, dlx_node *Column)
Definition: dlx_solver.cpp:844
void AppendRowAndSolveRHS(int *Data, int nb_rows, int nb_cols, int *RHS, int f_has_type, diophant_equation_type *type, int verbose_level)
void install_callback_solution_found(void(*callback_solution_found)(int *solution, int len, int nb_sol, void *data), void *callback_solution_found_data)
Definition: dlx_solver.cpp:154
void Create_RHS(int nb_cols, int *RHS, int f_has_type, diophant_equation_type *type, int verbose_level)
Definition: dlx_solver.cpp:450
void AppendRowAndSolve(int *Data, int nb_rows, int nb_cols, int verbose_level)
void Solve_with_RHS(int *RHS, int f_has_type, diophant_equation_type *type, int verbose_level)
Definition: dlx_solver.cpp:348
void(* callback_solution_found)(int *solution, int len, int nb_sol, void *data)
Definition: solvers.h:499
void CreateMatrix(int *Data, int nb_rows, int nb_cols, int verbose_level)
Definition: dlx_solver.cpp:532
#define DLX_FANCY_LEVEL
Definition: dlx_solver.cpp:30
#define FREE_OBJECTS(p)
Definition: foundations.h:652
#define MINIMUM(x, y)
Definition: foundations.h:216
#define FREE_int(p)
Definition: foundations.h:640
#define NEW_int(n)
Definition: foundations.h:625
#define NEW_OBJECTS(type, n)
Definition: foundations.h:639
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define Int_vec_copy(A, B, C)
Definition: foundations.h:693
#define Int_vec_print(A, B, C)
Definition: foundations.h:685
orbiter_kernel_system::orbiter_session * Orbiter
global Orbiter session
the orbiter library for the classification of combinatorial objects
internal class for the dancing links exact cover algorithm
Definition: solvers.h:567