Orbiter 2022
Combinatorial Objects
mckay.cpp
Go to the documentation of this file.
1// mckay.cpp
2//
3// solver due to Brendan McKay
4// Commented by Alfred Wassermann
5// C++ translation by Volker Widor 2003
6// adapted by Anton Betten
7// 1/16/2009
8
9#include "foundations.h"
10
11using namespace std;
12
13namespace orbiter {
14namespace layer1_foundations {
15namespace solvers {
16
17
18
21 first_moved = 0;
22 second_moved = 0;
23 problem_label = NULL;
24
25 _eqnanz = 0;
26 _varanz = 0;
27 //vector<bool> unitcoeffs;
28 //vector<bool> active;
29 rekurs = 0;
30 _break = false;
31
32 D = NULL;
33 //tLGS *_lgs;
34
35#ifdef MCKAY_DEBUG
36 //vector<int> range, split, branch;
37 ticks0 = 0;
38#endif
39};
40
42 const char *label, int aEqnAnz, int aVarAnz)
43{
45
46 _varanz=aVarAnz;
47 _eqnanz=aEqnAnz;
48 nb_calls_to_solve = 0;
49 D = lgs;
50 //_lgs = aLgs;
51 rekurs=0;
52 unitcoeffs.resize(_eqnanz);
53 active.resize(_eqnanz);
54 problem_label = label;
55#ifdef MCKAY_DEBUG
56 int m;
57
58 m = MAXIMUM(_eqnanz, _varanz) + 1;
59 range.resize(m);
60 split.resize(m);
61 branch.resize(m);
62 ticks0 = Os.os_ticks();
63#endif
64}
65
66void mckay::tMCKAY::possolve(vector<int> &lo, vector<int> &hi,
67 vector<equation> &eqn, vector<int> &lorhs, vector<int> &hirhs,
68 vector<int> &neqn, int numeqn, int numvar, int verbose_level)
69{
70 int f_v = (verbose_level >= 1);
71 int f_v4 = (verbose_level >= 4);
72 int i,j;
73 bool hopeless;
74
75 if (f_v) {
76 cout << "possolve" << endl;
77 }
78 nb_calls_to_solve = 0;
79 first_moved = INT_MAX;
80 second_moved = INT_MAX;
81
82
83 if (numeqn > _eqnanz || numvar > _varanz) {
84 cerr<<"*** >E intsolve: limits exceeded\n";
85 throw this;
86 }
87/* First step:
88 If for one equation there is no coefficient different from
89 zero, this equation is \"not" active.
90 Further mark in \|unitcoeffs| the equations with coefficients
91 solely $\in\{0,1\}$.
92*/
93 hopeless = false;
94 for (i = 0; i < numeqn; ++i) {
95 if (neqn[i] == 0) {
96 active[i] = false;
97 if (lorhs[i] > 0 || hirhs[i] < 0) hopeless = true;
98 }
99 else {
100 active[i] = true;
101 }
102 for (j = neqn[i]; --j >= 0;) if (eqn[i][j].coeff != 1) break;
103 unitcoeffs[i] = (j < 0);
104 }
105
106/* More output. */
107 if (f_v4) {
108 puteqns(lo,hi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
109 }
110
111/* Finally the recursion starts. */
112 if (!hopeless)
113 _break = false;
114
115 if (f_v) {
116 cout << "mckay::tMCKAY::possolve: calling solve" << endl;
117 }
118 solve(0,lo,hi,active,numvar,lorhs,hirhs,eqn,neqn,numeqn, verbose_level);
119 if (f_v) {
120 cout << "mckay::tMCKAY::possolve done" << endl;
121 }
122
123 return;
124}
125
126/* \subsection{subtract}
127 subtract equation e1 from e2 if possible ---
128 return success.
129 It is used in function \|pruneqn|.
130*/
132 int eqn1, equation &e1, int l1, int lors1, int hirs1,
133 int eqn2, equation &e2, int *pl2, int *plors2, int *phirs2,
134 int verbose_level)
135{
136 int f_v = (verbose_level >= 1);
137 int i,j,k;
138 term e1i;
139 int l2,factor,minfactor;
140
141 /* First test if subtraction is possible. */
142 minfactor = 999999;
143 l2 = *pl2;
144 if (l1 > l2 || hirs1 > lors1) return false;
145
146 /* Second test if subtraction is possible. */
147 j = 0;
148 for (i = 0; i < l1; ++i) {
149 e1i = e1[i];
150 for (; j < l2 && e2[j].var != e1i.var; ++j) {}
151 if (j == l2 || e2[j].coeff < e1i.coeff) return false;
152 factor = e2[j].coeff / e1i.coeff;
153 if (factor < minfactor) minfactor = factor;
154 }
155
156 /* Do subtraction */
157 k = 0;
158 for (i = j = 0; i < l1; ++i, ++j)
159 {
160 e1i = e1[i];
161 for (; j < l2 && e2[j].var != e1i.var; ++j) e2[k++] = e2[j];
162 if (j < l2 && e2[j].coeff > minfactor*e1i.coeff) {
163 e2[k].var = e2[j].var;
164 e2[k].coeff = e2[j].coeff - minfactor*e1i.coeff;
165 ++k;
166 }
167 }
168 for (; j < l2; ++j) e2[k++] = e2[j];
169
170 *pl2 = k;
171 *plors2 -= minfactor*lors1;
172 *phirs2 -= minfactor*hirs1;
173
174 /* end of subtraction. */
175 if (f_v) {
176 cout << "subtract: subtracted equation " << eqn1
177 << " from equation " << eqn2 << endl;
178 }
179 return true;
180}
181
182/* \subsection{pruneqn --- remove equations}
183 prune equations by subtraction.
184*/
185void mckay::tMCKAY::pruneqn(vector<int> &lo, vector<int> &hi,
186 int numvar,
187 vector<int> &lorhs, vector<int> &hirhs,
188 vector<equation> &eqn, vector<int> &neqn,
189 int numeqn, int verbose_level)
190{
191 int f_v = (verbose_level >= 1);
192 bool ok;
193 vector<bool> done;
194 done.resize(_eqnanz);
195 int i,j;
196
197/* \|done| is always \|false|. Why? */
198
199 for (i = 0; i < numeqn; ++i) {
200 done[i] = false;
201 }
202
203 do {
204 ok = true;
205 for (i = 0; i < numeqn; ++i) {
206 if (!done[i] && neqn[i] > 0) {
207 for (j = 0; j < numeqn; ++j) {
208 if (i != j &&
209 subtract(i, eqn[i],neqn[i],
210 lorhs[i],hirhs[i],j, eqn[j],
211 &neqn[j],&lorhs[j],&hirhs[j],
212 verbose_level)) {
213 if (f_v) {
214 cout << "mckay::tMCKAY::pruneqn after subtract:" << endl;
215 puteqns(lo, hi,
216 numvar, lorhs, hirhs, eqn, neqn, numeqn);
217 }
218 ok = false;
219 done[j] = false;
220 } // if
221 } // for
222 } // if
223 } // for
224 } while (!ok);
225 return;
226}
227
228/*
229 \subsection{varprune --- remove variables}
230 Try to remove free variables by testing if variables are already
231 fixed. This is the case if the lower bound on a variable is equal to its
232 upper bound.
233*/
234
235void mckay::tMCKAY::varprune(vector<int> &lo, vector<int> &hi,
236 vector<int> &lorhs, vector<int> &hirhs,
237 vector<equation> &eqn, vector<int> &neqn,
238 int numeqn, int verbose_level)
239{
240 int f_v = (verbose_level >= 1);
241 int i,j,sum,len;
242
243 for (j = 0; j < numeqn; ++j) {
244 len = neqn[j];
245 sum = 0;
246 // simple test whether the lower bound
247 // of a variable meets its upper bound:
248 for (i = 0; i < len;) {
249 if (lo[eqn[j][i].var] == hi[eqn[j][i].var]) {
250 sum += eqn[j][i].coeff*lo[eqn[j][i].var];
251 if (f_v && sum) {
252 cout << "varprune: equation " << j << " variable "
253 << eqn[j][i].var << " is not free any more, "
254 "sum += " << eqn[j][i].coeff * lo[eqn[j][i].var]
255 << endl;
256 }
257 eqn[j][i] = eqn[j][--len];
258 }
259 else {
260 ++i;
261 }
262 }
263 lorhs[j] -= sum;
264 hirhs[j] -= sum;
265 if (f_v && sum) {
266 cout << "varprune: equation " << j << " reducing RHS by "
267 << sum << " to lorhs[j]=" << lorhs[j] << " hirhs[j]="
268 << hirhs[j] << endl;
269 }
270 neqn[j] = len;
271 }
272}
273
274
275void mckay::tMCKAY::puteqns(vector<int> &lo, vector<int> &hi,
276 int numvar, vector<int> &lorhs, vector<int> &hirhs,
277 vector<equation> &eqn, vector<int> &neqn, int numeqn)
278{
279 int i,j;
280
281 // First the lower and upper bounds on the variable are written:
282 cout << "CON" << endl;
283 for (i = 0; i < numvar; ++i) {
284 if (i > 0) cout << "," << endl;
285 if (lo[i] > 0) cout << "x" << i << " >= " << lo[i] << ", ";
286 cout << "x" << i << " <= " << hi[i];
287 }
288
289 // print the equations:
290 for (i = 0; i < numeqn; ++i) {
291 cout << "," << endl;
292 cout << "Equation " << i << " : ";
293 for (j = 0; j < neqn[i]; ++j) {
294 if (j % 16 == 15) cout << endl << " ";
295 cout << (j == 0 ? "" : "+") << eqn[i][j].coeff
296 << "*x" << eqn[i][j].var;
297 }
298 cout << (lorhs[i] < hirhs[i] ? " >= " : " = ") << lorhs[i];
299
300 if (lorhs[i] == hirhs[i]) continue;
301
302 // inequalities:
303 cout << "," << endl;
304 for (j = 0; j < neqn[i]; ++j) {
305 if (j % 16 == 15) cout << endl << " ";
306 cout << (j == 0 ? "" : "+") << eqn[i][j].coeff
307 << "*x" << eqn[i][j].var;
308 }
309 cout << " <= " << hirhs[i];
310 }
311 cout << ";" << endl;
312}
313
314/*
315 \subsection{divideeqns}
316 take out common factors, return bad eqn number.
317 It is only used in the main program.
318*/
319int mckay::tMCKAY::divideeqns(vector<int> &lorhs,
320 vector<int> &hirhs, vector<equation> &eqn,
321 vector<int> &neqn, int numeqn)
322{
323 int i,j,g,len;
324
325 for (j = 0; j < numeqn; ++j)
326 {
327 len = neqn[j];
328 if (len == 0) continue;
329
330 g = eqn[j][0].coeff;
331 i = 1;
332 for (i = 1; i < len && g > 1; ++i) g = gcd(g,eqn[j][i].coeff);
333/* $g = \gcd$ of all coefficients of the left hand side of equation $i$.
334 If $g=1$ step to the next equation.
335*/
336 if (g == 1) continue;
337 for (i = 0; i < len; ++i) eqn[j][i].coeff /= g;
338
339 lorhs[j] = lorhs[j] < 0 ? 0 : (lorhs[j] + g - 1) / g;
340 hirhs[j] = hirhs[j] < 0 ? -1 : hirhs[j] / g;
341
342/* Write some information.*/
343 cerr<<"eqn "<<j<<": g="<<g<<" lorhs="<<lorhs[j]
344 <<" hirhs="<<hirhs[j]<<"\n";
345
346 if (lorhs[j] > hirhs[j]) return j;
347 }
348
349 return -1;
350}
351
352/*
353\subsection{gcd}
354used in \|divideeqns|.
355*/
356int mckay::tMCKAY::gcd(int n1,int n2)
357{
358 int a,b,c;
359
360 if (n1 > n2) {
361 a = n1; b = n2;
362 }
363 else {
364 a = n2; b = n1;
365 }
366
367 while ((c = a % b) > 0) {
368 a = b; b = c;
369 }
370
371 return(b);
372}
373
374/*
375\section{solve --- brute force recursion}
376This procedure is called recursively.
377*/
378void mckay::tMCKAY::solve(int level,
379 vector<int> &alo, vector<int> &ahi,
380 vector<bool> &aactive, int numvar,
381 vector<int> &lorhs, vector<int> &hirhs,
382 vector<equation> &eqn, vector<int> &neqn,
383 int numeqn, int verbose_level)
384{
385 int f_v = (verbose_level >= 1);
386 //int f_vv = (verbose_level >= 2);
387 int f_vvv = (verbose_level >= 3);
388 int i,j;
389 vector<int> lo, hi;
390 lo.resize(_varanz);
391 hi.resize(_varanz);
392 int isplit, mindiff;
393 vector<bool> active;
394 active.resize(_eqnanz);
395 //int current_node;
396 int f_restriction_made;
397
398 //current_node = nb_calls_to_solve;
399 nb_calls_to_solve++;
400#if 0
401 if (f_vv) {
402 log_12l(nb_calls_to_solve, level);
403 //log_12l(current_node, level);
404 cout << "mckay::tMCKAY::solve " << problem_label
405 //<< " node " << current_node
406 << " first_moved " << first_moved
407 << " second_moved " << second_moved
408 << " level " << level << endl;
409 }
410#ifdef MCKAY_DEBUG
411 if (f_vvv) {
412 cout << " : ";
413 for (i = 0; i < level; ++i) {
414 cout << "x_" << split[i] << "=" << branch[i];
415 if (i < level - 1) {
416 cout << ", ";
417 }
418 }
419 }
420#endif
421 if (f_vv) {
422 cout << endl;
423 }
424#endif
425#ifdef MCKAY_DEBUG
426 if (f_vvv) {
427 cout << "level=" << level << endl;
428 cout << "i : split[i] : range[i] : branch[i]" << endl;
429 for (i = 0; i < level; ++i) {
430 cout << i << " : " << split[i] << " : " << range[i]
431 << " : " << branch[i] << " : " << endl;
432 }
433 cout << "low and high:" << endl;
434 for (j = 0; j < numvar; j++) {
435 cout << j << " : " << alo[j] << " : " << ahi[j] << endl;
436 }
437 }
438#endif
439
440#if 0
441 if (f_vvv) {
442 log_12l(current_node, level);
443 cout << " current system:" << endl;
444 puteqns(alo,ahi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
445 }
446#endif
447 //f_debug = FALSE;
448
449 //f_debug = (verbose_level >= 10);
450
451 if (_break) {
452 return;
453 }
454
455
456 if (FALSE) {
457 int nacc = 0;
458 cout << " SOLVE level "<<level<< endl;
459 cout<<"Number of active equations: ";
460 for (i = numeqn; --i >= 0;) if (aactive[i]) ++nacc;
461 cout<<":"<<nacc<<endl;
462 for (i = 0; i < numeqn; i++) {
463 if (aactive[i])
464 cout << i << " ";
465 }
466 cout << endl;
467 cout << "low and high:" << endl;
468 for (j = 0; j < numvar; j++) {
469 cout << j << " : " << alo[j] << " : " << ahi[j] << endl;
470 }
471#ifdef MCKAY_DEBUG
473 if (((Os.os_ticks() - ticks0) / Os.os_ticks_per_second())
475 ticks0 = Os.os_ticks();
476 //f_debug = TRUE;
477 puteqns(alo,ahi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
478 cout << "level=" << level << endl;
479 cout << "range[] : branch[] :" << endl;
480 for (i = 0; i < level; ++i)
481 cout << range[i] << " : " << branch[i] << " : " << endl;
482 }
483#endif
484 }
485
486
487
488
489/* \|lo|, \|hi| and \|active| are local arrays. */
490
491 for (i = 0; i < numvar; ++i) {
492 lo[i] = alo[i];
493 hi[i] = ahi[i];
494 }
495 for (i = 0; i < numeqn; ++i) {
496 active[i] = aactive[i];
497 }
498
499
500 if (!restrict_variables(level, lo, hi, active, numvar,
501 lorhs, hirhs,
502 eqn, neqn,
503 numeqn, f_restriction_made, verbose_level - 1)) {
504
505#if 0
506 if (f_vv) {
507 log_12l(nb_calls_to_solve, level);
508 //log_12l(current_node, level);
509 cout << "solve restrict_variables returns FALSE, "
510 "backtracking" << endl;
511 }
512#endif
513 return;
514 }
515
516
517
518#if 0
519 if (f_vvv && f_restriction_made) {
520 log_12l(nb_calls_to_solve, level);
521 //log_12l(current_node, level);
522 cout << " after restriction: low and high:" << endl;
523 for (i = 0; i < numvar; i++) {
524 cout << i << " : " << lo[i] << " : " << hi[i] << endl;
525 }
526 }
527#endif
528
529 // Here comes the searching part.
530 // \|mindiff| gives the smallest
531 // difference between lower and upper bound of a variable.
532 // \|isplit|
533 // is the corresponding variable number.
534
535#if 0
536 if (f_vv) {
537 log_12l(nb_calls_to_solve, level);
538 //log_12l(current_node, level);
539 cout << "searching part" << endl;
540 }
541#endif
542
543 mindiff = INT_MAX;
544 isplit = -1;
545 for (i = 0; i < numvar; ++i) {
546 if (hi[i] != lo[i] && hi[i] - lo[i] < mindiff) {
547 isplit = i;
548 mindiff = hi[i] - lo[i];
549 }
550 }
551
552 // If \|isplit| $< 0$ we have found a solution.
553 // Otherwise we try to delete variables by
554 // \|varprune| and we try to delete equations
555 // by \|pruneqn|.
556
557 if (isplit < 0) {
558 if (f_v) {
559 log_12l(nb_calls_to_solve, level);
560 cout << " solution " << D->_resultanz << endl;
561 }
562 D->_results.push_back(lo);
563 D->_resultanz++;
564 if (D->_resultanz < D->_maxresults) {
565 _break = false;
566 }
567 else {
568 _break = true;
569 }
570 }
571 else {
572 if (level == 0) {
573 varprune(lo,hi,lorhs,hirhs,eqn,neqn,numeqn, verbose_level);
574
575//#if VERBOSE > 2
576 //puteqns(lo,hi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
577//#endif
578
579
580 pruneqn(lo,hi,numvar,lorhs,hirhs,eqn,neqn,numeqn, verbose_level);
581
582//#if VERBOSE > 2
583
584#if 0
585 if (f_vvv) {
586 log_12l(nb_calls_to_solve, level);
587 //log_12l(current_node, level);
588 cout << " after varprune and pruneqn:" << endl;
589 puteqns(lo,hi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
590 }
591#endif
592//#endif
593 }
594
595/*
596 Finally we start the recursion.
597 the variable with the number \|isplit| runs from
598 \|lo[isplit]| to \|hi[isplit]| and for each step we call \|solve|
599 with this fixed value.
600
601 \|branch|, \|split| and \|range| are collected for debugging purposes.
602*/
603
604
605#if 0
606 if (TRUE /*(f_v && (current_node % 10000) == 0) || f_vv*/) {
607 //log_12l(current_node, level);
608 log_12l(nb_calls_to_solve, level);
609 cout << "solve choosing variable " << isplit
610 << " lo=" << lo[isplit] << " hi=" << hi[isplit] << endl;
611 }
612#endif
613 for (i = 0; i <= mindiff; ++i) {
614 int first_moved_orig = first_moved;
615 int second_moved_orig = second_moved;
616 int f_first_moved_has_changed = FALSE;
617 int f_second_moved_has_changed = FALSE;
618
619
620 if (i) {
621
622 if (level < first_moved) {
623 first_moved = level;
624 second_moved = INT_MAX;
625 }
626 else if (level < second_moved) {
627 second_moved = level;
628 }
629 if (first_moved != first_moved_orig) {
630 f_first_moved_has_changed = TRUE;
631 }
632 if (second_moved != second_moved_orig) {
633 f_second_moved_has_changed = TRUE;
634 }
635 }
636 if (f_first_moved_has_changed || f_second_moved_has_changed ||
637 (nb_calls_to_solve % 10000000) == 0) {
638 log_12l(nb_calls_to_solve, level);
639 cout << " x_" << isplit << " = " << lo[isplit] << endl;
640 }
641 hi[isplit] = lo[isplit];
642#ifdef MCKAY_DEBUG
643 split[level] = isplit;
644 branch[level] = lo[isplit];
645 range[level] = mindiff+1;
646#endif
647
648 // here comes the recursion:
649
650 if (f_v) {
651 cout << "solve level " << level << " isplit=" << isplit << " before solve i=" << i << " / " << mindiff << endl;
652 for (j = 0; j < numeqn; j++) {
653 if (aactive[i])
654 cout << j << " ";
655 }
656 cout << endl;
657 cout << "low and high:" << endl;
658 for (j = 0; j <= level; j++) {
659 cout << j << " : " << alo[j] << " : " << ahi[j] << endl;
660 }
661#if 0
662#ifdef MCKAY_DEBUG
663 if (TRUE/*((os_ticks() - ticks0) / os_ticks_per_second())
664 > INTERVAL_IN_SECONDS*/) {
665 ticks0 = os_ticks();
666 //f_debug = TRUE;
667 puteqns(alo,ahi,numvar,lorhs,hirhs,eqn,neqn,numeqn);
668 cout << "level=" << level << endl;
669 cout << "range[] : branch[] :" << endl;
670 for (j = 0; j <= level; j++) {
671 cout << range[j] << " : " << branch[j] << " : " << endl;
672 }
673 }
674#else
675 // cout << "MCKAY_DEBUG is FALSE" << endl;
676#endif
677#endif
678 }
679 solve(level + 1, lo, hi, active, numvar,
680 lorhs, hirhs, eqn, neqn, numeqn,
681 verbose_level);
682
683 if (f_v) {
684 cout << "solve level " << level << " isplit=" << isplit << " after solve" << endl;
685 }
686 ++lo[isplit];
687 } // next i
688 } // else
689
690#if 0
691 if (f_vv) {
692 log_12l(nb_calls_to_solve, level);
693 //log_12l(current_node, level);
694 cout << " done" << endl;
695 }
696#endif
697}
698
700 vector<int> &lo, vector<int> &hi,
701 vector<bool> &active, int numvar,
702 vector<int> &lorhs, vector<int> &hirhs,
703 vector<equation> &eqn, vector<int> &neqn,
704 int numeqn, int &f_restriction_made, int verbose_level)
705{
706 int f_v = (verbose_level >= 1);
707 int f_vv = (verbose_level >= 2);
708 //int f_vvv = (verbose_level >= 3);
709 //int f_debug;
710 int i, j;
711 long int current_node;
712 int losum,hisum,eic,eiv,lx,hx;
713 int nfree,ok, xlo,xhi;
714 int save;
715 int f_restriction_made_in_this_eqn;
716
717 if (f_v) {
718 cout << "mckay::tMCKAY::restrict_variables" << endl;
719 }
720 if (f_vv) {
721 cout << "low and high:" << endl;
722 for (j = 0; j <= level; j++) {
723 cout << j << " : " << lo[j] << " : " << hi[j] << endl;
724 }
725 puteqns(lo, hi, numvar, lorhs, hirhs, eqn, neqn, numeqn);
726 cout << "level=" << level << endl;
727 cout << "range[] : branch[] :" << endl;
728 for (j = 0; j <= level; j++) {
729 cout << range[j] << " : " << branch[j] << " : " << endl;
730 }
731 }
732 current_node = nb_calls_to_solve;
733/* The following line seems to be a relict from another problem. */
734/* *< if (level == 8 && lo[22] == 1 && lo[19] == 1) nul(); >* */
735
736/* The following loop through the equations tries to restrict the lower
737 and upper bounds on the variables.
738 We only have to handle active equations.
739*/
740 ok = 0;
741 /* ok = number of equations that have been
742 * checked since the last change of any
743 * lo[] or hi[] was made.
744 * the aim is to check all equations once
745 * without reducing hi[] - lo[];
746 * so that we have reached stability */
747
748 f_restriction_made = FALSE;
749 for (j = 0; ok < numeqn; j = (j == numeqn-1 ? 0 : j+1)) {
750 // j is the next equation to check;
751 // j wraps around all equation indices
752 if (f_vv /*f_debug*/) {
753 cout << "mckay::tMCKAY::restrict_variables checking equation " << j << endl;
754 }
755 ++ok;
756 if (active[j]) {
757
758 f_restriction_made_in_this_eqn = FALSE;
759 // we check equation j:
760
761 // We distinguish two cases:
762 // First, if there are only $\{0,1\}$-coefficients.
763
764
765 if (FALSE /*unitcoeffs[j]*/) {
766 // The lower and upper bounds on the variables
767 // (belonging to nonzero coefficients) are summed up
768 // in \|losum| and \|hisum|.
769
770 if (f_vv /*f_debug*/) {
771 cout << "checking equation " << j
772 << " with unitcoeffs" << endl;
773 }
774 losum = 0;
775 hisum = 0;
776 for (i = neqn[j]; --i >= 0;) {
777 losum += lo[eqn[j][i].var];
778 // lowest possible lhs
779 hisum += hi[eqn[j][i].var];
780 // highest possible lhs
781 }
782 if (losum > hirhs[j]) {
783 if (f_v) {
784 cout << "solve " << problem_label << " node "
785 << current_node << " level " << level
786 << "return b/c for equation " << j
787 << " with unitcoeffs "
788 "we have losum = " << losum << " > "
789 << hirhs[j] << " = hirhs[j]" << endl;
790 }
791 return FALSE;
792 }
793 if (hisum < lorhs[j]) {
794 if (f_v) {
795 cout << "solve " << problem_label << " node "
796 << current_node << " level " << level
797 << "return b/c for equation " << j
798 << " with unitcoeffs "
799 " we have hisum = " << hisum << " < "
800 << lorhs[j] << " = lorhs[j]" << endl;
801 }
802 return FALSE;
803 }
804
805 // If possible the lower or upper bounds on the
806 // variables are restricted further.
807 // count the number of remaining free
808 // variables in nfree.
809
810 nfree = 0;
811 for (i = neqn[j]; --i >= 0;) {
812 eiv = eqn[j][i].var;
813 hx = hi[eiv];
814 lx = lo[eiv];
815 if (hx != lx) {
816
817 xlo = lorhs[j] + hx - hisum;
818 // = lorhs[j] - (hisum - hx), i.e.,
819 // lorhs[j] minus hisum of all the
820 // other variables.
821 // This is a lower bound on the amount
822 // that the current variable contributes.
823
824 xhi = hirhs[j] + lx - losum;
825 // = hirhs[j] - (losum - lx), i.e.
826 // hirhs[j] minus losum of all the
827 // other variables.
828 // This is an upper bound on the amount
829 // that the current variable contributes.
830
831 if (xlo > lx) {
832 save = lo[eiv];
833 lo[eiv] = xlo;
834 if (lo[eiv] != save) {
835 f_restriction_made = TRUE;
836 f_restriction_made_in_this_eqn = TRUE;
837 if (f_v) {
838 cout << "increasing lo[" << eiv
839 << "] from " << save << " to "
840 << lo[eiv] << endl;
841 }
842 }
843 ok = 0;
844 // a change was made;
845 // loop through all
846 // equations again.
847 }
848 if (xhi < hx) {
849 save = hi[eiv];
850 hi[eiv] = xhi;
851 if (lo[eiv] != save) {
852 f_restriction_made = TRUE;
853 f_restriction_made_in_this_eqn = TRUE;
854 if (f_v) {
855 cout << "reducing hi[" << eiv
856 << "] from " << save << " to "
857 << hi[eiv] << endl;
858 }
859 }
860 ok = 0;
861 }
862 if (lo[eiv] != hi[eiv]) {
863 ++nfree;
864 }
865 } // if (hx != lx)
866 } // next i
867 } // if (unitcoeffs[j])
868
869 // Now the slightly more complicated case
870 // if there are coefficents greater than $1$.
871 // If the lower bound of a variable becomes greater
872 // than its upper bound, the procedure is stopped at once.
873 else {
874 // Again the lower and upper bounds on the variables
875 // (belonging to nonzero coefficients) are summed
876 // up in \|losum| and \|hisum|.
877 if (f_v /*f_debug*/) {
878 cout << "mckay::tMCKAY::restrict_variables checking equation " << j
879 << " without unitcoeffs" << endl;
880 }
881 losum = 0;
882 hisum = 0;
883 for (i = neqn[j]; --i >= 0;) {
884 losum += eqn[j][i].coeff * lo[eqn[j][i].var];
885 hisum += eqn[j][i].coeff * hi[eqn[j][i].var];
886 }
887 if (losum > hirhs[j]) {
888 if (f_v) {
889 cout << "mckay::tMCKAY::restrict_variables "
890 << problem_label << " node "
891 << current_node << " level " << level
892 << "return b/c for equation " << j
893 << " without unitcoeffs "
894 "we have losum = " << losum << " > "
895 << hirhs[j] << " = hirhs[j]" << endl;
896 }
897 return FALSE;
898 }
899 if (hisum < lorhs[j]) {
900 if (f_v) {
901 cout << "mckay::tMCKAY::restrict_variables "
902 << problem_label << " node "
903 << current_node << " level " << level
904 << "return b/c for equation " << j
905 << " without unitcoeffs "
906 "we have hisum = " << hisum << " < "
907 << lorhs[j] << " = lorhs[j]" << endl;
908 }
909 return FALSE;
910 }
911
912 if (f_vv && f_restriction_made_in_this_eqn) {
913 cout << "mckay::tMCKAY::restrict_variables "
914 "equation " << j << ", after restriction: "
915 "low and high:" << endl;
916 for (i = 0; i < numvar; i++) {
917 cout << i << " : " << lo[i] << " : "
918 << hi[i] << endl;
919 }
920 cout << "hisum=" << hisum << endl;
921 cout << "losum=" << losum << endl;
922 }
923 // And if possible the lower or upper bounds
924 // on the variables
925 // are restricted further.
926
927 f_restriction_made_in_this_eqn = FALSE;
928
929 nfree = 0;
930 for (i = neqn[j]; --i >= 0;) {
931 if (FALSE /*f_debug*/) {
932 cout << "restricting lower and upper "
933 "bounds equation " << j << endl;
934 }
935 if (hi[eqn[j][i].var] != lo[eqn[j][i].var]) {
936 eic = eqn[j][i].coeff;
937 eiv = eqn[j][i].var;
938 hx = eic * hi[eiv];
939 lx = eic * lo[eiv];
940 xlo = lorhs[j] + hx - hisum;
941 // = lorhs[j] - (hisum - hx), i.e.,
942 // lorhs[j] minus hisum of all the other variables.
943 // This is a lower bound on the amount
944 // that the current variable contributes.
945
946 xhi = hirhs[j] + lx - losum;
947 // = hirhs[j] - (losum - lx), i.e.
948 // hirhs[j] minus losum of all the other variables.
949 // This is an upper bound on the amount
950 // that the current variable contributes.
951
952 if (xlo > lx) {
953 save = lo[eiv];
954 lo[eiv] = (xlo + eic - 1) / eic;
955 if (lo[eiv] != save) {
956 f_restriction_made = TRUE;
957 f_restriction_made_in_this_eqn = TRUE;
958 if (f_v) {
959 cout << "increasing lo[" << eiv
960 << "] from "
961 << save << " to " << lo[eiv] << " : "
962 << "eqn j=" << j << " variable "
963 << eiv << " coeff=" << eic
964 << " lorhs[j]=" << lorhs[j]
965 << " hisum=" << hisum
966 << " hx=" << hx
967 << " hisum - hx=" << hisum - hx
968 << endl;
969 }
970 }
971 if (lo[eiv] > hi[eiv]) {
972 if (f_v) {
973 cout << "return bc for eqn " << j
974 << " term " << i << " xlo > lx "
975 "and lo[eiv] > hi[eiv]" << endl;
976 }
977 return FALSE;
978 }
979 ok = 0;
980 }
981 if (xhi < hx) {
982 save = hi[eiv];
983 hi[eiv] = xhi / eic;
984 if (hi[eiv] < save) {
985 f_restriction_made = TRUE;
986 f_restriction_made_in_this_eqn = TRUE;
987 if (f_v) {
988 cout << "reducing hi[" << eiv << "] from "
989 << save << " to " << hi[eiv] << " : "
990 << "eqn j=" << j << " variable "
991 << eiv << " coeff=" << eic
992 << " hirhs[j]=" << hirhs[j]
993 << " losum=" << losum
994 << " lx=" << lx
995 << " losum - lx=" << losum - lx
996 << endl;
997 }
998 }
999 if (lo[eiv] > hi[eiv]) {
1000 if (f_v) {
1001 cout << "return bc for eqn " << j
1002 << " term " << i << " xhi < hx "
1003 "and lo[eiv] > hi[eiv]" << endl;
1004 cout << "xlo=" << xlo << endl;
1005 cout << "xhi=" << xhi << endl;
1006 cout << "lx=" << lx << endl;
1007 cout << "hx=" << hx << endl;
1008 cout << "eic=" << eic << endl;
1009 cout << "eiv=" << eiv << endl;
1010 cout << "lo[eiv]=" << lo[eiv] << endl;
1011 cout << "hi[eiv]=" << hi[eiv] << endl;
1012 }
1013 return FALSE;
1014 }
1015 ok = 0;
1016 }
1017 if (lo[eiv] != hi[eiv]) {
1018 ++nfree;
1019 }
1020 } // if hi[eqn[j][i]
1021 } // next i
1022
1023 if (f_vv && f_restriction_made_in_this_eqn) {
1024 cout << "mckay::tMCKAY::restrict_variables "
1025 "equation " << j << ", after restriction: "
1026 "low and high:" << endl;
1027 for (i = 0; i < numvar; i++) {
1028 cout << i << " : " << lo[i] << " : "
1029 << hi[i] << endl;
1030 }
1031 cout << "hisum=" << hisum << endl;
1032 cout << "losum=" << losum << endl;
1033 }
1034
1035
1036 } // else
1037
1038
1039 // Now hopefully the variables are in each
1040 // case further restricted.
1041 // The equation becomes inactive if
1042 // \item{(1)} there are no free variables in
1043 // this equation \"and
1044 // \item{(2)} if it was not possible to further
1045 // restrict the variables in the last try.
1046
1047 if (ok > 0 && nfree == 0) {
1048 active[j] = false;
1049 }
1050 } // if (active[j])
1051 } // next j
1052
1053 return TRUE;
1054}
1055
1056void mckay::tMCKAY::log_12l(long int current_node, int level)
1057{
1058 cout << "solve " << problem_label
1059 << " node " << current_node
1060 << " first_moved ";
1061
1062 if (first_moved < INT_MAX) {
1063 cout << first_moved;
1064 }
1065 else {
1066 cout << "infinity";
1067 }
1068
1069 cout << " second_moved ";
1070 if (second_moved < INT_MAX) {
1071 cout << second_moved;
1072 }
1073 else {
1074 cout << "infinity";
1075 }
1076
1077 cout << " level " << level;
1078 cout << " nb_sol=" << D->_resultanz;
1079}
1080
1081
1082}}}
1083
diophantine systems of equations (i.e., linear systems over the integers)
Definition: solvers.h:209
void possolve(std::vector< int > &lo, std::vector< int > &hi, std::vector< equation > &eqn, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< int > &neqn, int numeqn, int numvar, int verbose_level)
Definition: mckay.cpp:66
void Init(diophant *lgs, const char *label, int aEqnAnz, int aVarAnz)
Definition: mckay.cpp:41
void varprune(std::vector< int > &lo, std::vector< int > &hi, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn, int verbose_level)
Definition: mckay.cpp:235
void pruneqn(std::vector< int > &lo, std::vector< int > &hi, int numvar, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn, int verbose_level)
Definition: mckay.cpp:185
void puteqns(std::vector< int > &lo, std::vector< int > &hi, int numvar, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn)
Definition: mckay.cpp:275
int restrict_variables(int level, std::vector< int > &lo, std::vector< int > &hi, std::vector< bool > &active, int numvar, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn, int &f_restriction_made, int verbose_level)
Definition: mckay.cpp:699
int divideeqns(std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn)
Definition: mckay.cpp:319
bool subtract(int eqn1, equation &e1, int l1, int lors1, int hirs1, int eqn2, equation &e2, int *pl2, int *plors2, int *phirs2, int verbose_level)
Definition: mckay.cpp:131
void log_12l(long int current_node, int level)
Definition: mckay.cpp:1056
void solve(int level, std::vector< int > &alo, std::vector< int > &ahi, std::vector< bool > &aactive, int numvar, std::vector< int > &lorhs, std::vector< int > &hirhs, std::vector< equation > &eqn, std::vector< int > &neqn, int numeqn, int verbose_level)
Definition: mckay.cpp:378
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define MAXIMUM(x, y)
Definition: foundations.h:217
the orbiter library for the classification of combinatorial objects
#define INTERVAL_IN_SECONDS
Definition: solvers.h:607
a term in a diophantine system of type tMCKAY
Definition: solvers.h:611