1 /******************************************
2 Copyright (c) 2012  Cheng-Shen Han
3 Copyright (c) 2012  Jie-Hong Roland Jiang
4 Copyright (c) 2018  Mate Soos
5 
6 For more information, see " When Boolean Satisfiability Meets Gaussian
7 Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang
8 in CAV (Computer Aided Verification), 2012: 410-426
9 
10 
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17 
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 THE SOFTWARE.
28 ***********************************************/
29 
30 #include <algorithm>
31 #include <iomanip>
32 #include <iostream>
33 #include <set>
34 
35 #include "gaussian.h"
36 #include "clause.h"
37 #include "clausecleaner.h"
38 #include "datasync.h"
39 #include "propby.h"
40 #include "solver.h"
41 #include "time_mem.h"
42 #include "varreplacer.h"
43 #include "xorfinder.h"
44 
45 using std::cout;
46 using std::endl;
47 using std::ostream;
48 using std::set;
49 
50 //#define VERBOSE_DEBUG
51 //#define SLOW_DEBUG
52 
53 //don't delete gauss watches, but check when propagating and
54 //lazily delete then
55 //#define LAZY_DELETE_HACK
56 
57 #ifdef VERBOSE_DEBUG
58 #include <iterator>
59 #endif
60 
61 using namespace CMSat;
62 
63 // if variable is not in Gaussian matrix , assiag unknown column
64 static const uint32_t unassigned_col = std::numeric_limits<uint32_t>::max();
65 
EGaussian(Solver * _solver,const uint32_t _matrix_no,const vector<Xor> & _xorclauses)66 EGaussian::EGaussian(
67     Solver* _solver,
68     const uint32_t _matrix_no,
69     const vector<Xor>& _xorclauses) :
70 xorclauses(_xorclauses),
71 solver(_solver),
72 matrix_no(_matrix_no)
73 
74 {
75 }
76 
~EGaussian()77 EGaussian::~EGaussian() {
78     delete_gauss_watch_this_matrix();
79     for(auto& x: tofree) {
80         delete[] x;
81     }
82     tofree.clear();
83 
84     delete cols_unset;
85     delete cols_vals;
86     delete tmp_col;
87     delete tmp_col2;
88 }
89 
90 struct ColSorter {
ColSorterColSorter91     explicit ColSorter(Solver* _solver) :
92         solver(_solver)
93     {
94         for(const auto& ass: solver->assumptions) {
95             Lit p = solver->map_outer_to_inter(ass.lit_outer);
96             if (p.var() < solver->nVars()) {
97                 assert(solver->seen.size() > p.var());
98                 solver->seen[p.var()] = 1;
99             }
100         }
101     }
102 
finishupColSorter103     void finishup()
104     {
105         for(const auto& ass: solver->assumptions) {
106             Lit p = solver->map_outer_to_inter(ass.lit_outer);
107             if (p.var() < solver->nVars()) {
108                 solver->seen[p.var()] = 0;
109             }
110         }
111     }
112 
operator ()ColSorter113     bool operator()(const uint32_t a, const uint32_t b)
114     {
115         assert(solver->seen.size() > a);
116         assert(solver->seen.size() > b);
117         if (solver->seen[b] && !solver->seen[a]) {
118             return true;
119         }
120 
121         if (!solver->seen[b] && solver->seen[a]) {
122             return false;
123         }
124 
125         return false;
126         //return solver->varData[a].level < solver->varData[b].level;
127         //return solver->var_act_vsids[a] > solver->var_act_vsids[b];
128     }
129 
130     Solver* solver;
131 };
132 
select_columnorder()133 uint32_t EGaussian::select_columnorder() {
134     var_to_col.clear();
135     var_to_col.resize(solver->nVars(), unassigned_col);
136     vector<uint32_t> vars_needed;
137     uint32_t largest_used_var = 0;
138 
139     for (const Xor& x : xorclauses) {
140         for (const uint32_t v : x) {
141             assert(solver->value(v) == l_Undef);
142             if (var_to_col[v] == unassigned_col) {
143                 vars_needed.push_back(v);
144                 var_to_col[v] = unassigned_col - 1;
145                 largest_used_var = std::max(largest_used_var, v);
146             }
147         }
148     }
149 
150     if (vars_needed.size() >= std::numeric_limits<uint32_t>::max() / 2 - 1) {
151         if (solver->conf.verbosity) {
152             cout << "c Matrix has too many columns, exiting select_columnorder" << endl;
153         }
154 
155         return 0;
156     }
157     if (xorclauses.size() >= std::numeric_limits<uint32_t>::max() / 2 - 1) {
158         if (solver->conf.verbosity) {
159             cout << "c Matrix has too many rows, exiting select_columnorder" << endl;
160         }
161         return 0;
162     }
163     var_to_col.resize(largest_used_var + 1);
164 
165 
166     ColSorter c(solver);
167     std::sort(vars_needed.begin(), vars_needed.end(),c);
168     c.finishup();
169 
170     #ifdef COL_ORDER_DEBUG_VERBOSE_DEBUG
171     cout << "col order: " << endl;
172     for(auto& x: vars_needed) {
173         bool assump = false;
174         for(const auto& ass: solver->assumptions) {
175             if (solver->map_outer_to_inter(ass.lit_outer).var() == x) {
176                 assump = true;
177             }
178         }
179         cout << "assump:" << (int)assump
180         << " act: " << std::setprecision(2) << std::scientific
181         << solver->var_act_vsids[x] << std::fixed
182         << " level: " << solver->varData[x].level
183         << endl;
184     }
185     #endif
186 
187 
188     col_to_var.clear();
189     for (uint32_t v : vars_needed) {
190         assert(var_to_col[v] == unassigned_col - 1);
191         col_to_var.push_back(v);
192         var_to_col[v] = col_to_var.size() - 1;
193     }
194 
195     // for the ones that were not in the order_heap, but are marked in var_to_col
196     for (uint32_t v = 0; v != var_to_col.size(); v++) {
197         if (var_to_col[v] == unassigned_col - 1) {
198             // assert(false && "order_heap MUST be complete!");
199             col_to_var.push_back(v);
200             var_to_col[v] = col_to_var.size() - 1;
201         }
202     }
203 
204 #ifdef VERBOSE_DEBUG_MORE
205     cout << "(" << matrix_no << ") num_xorclauses: " << num_xorclauses << endl;
206     cout << "(" << matrix_no << ") col_to_var: ";
207     std::copy(col_to_var.begin(), col_to_var.end(),
208               std::ostream_iterator<uint32_t>(cout, ","));
209     cout << endl;
210     cout << "num_cols:" << num_cols << endl;
211     cout << "col is set:" << endl;
212     std::copy(col_is_set.begin(), col_is_set.end(),
213               std::ostream_iterator<char>(cout, ","));
214 #endif
215 
216     return xorclauses.size();
217 }
218 
fill_matrix()219 void EGaussian::fill_matrix() {
220     var_to_col.clear();
221 
222     // decide which variable in matrix column and the number of rows
223     num_rows = select_columnorder();
224     num_cols = col_to_var.size();
225     if (num_rows == 0 || num_cols == 0) {
226         return;
227     }
228     mat.resize(num_rows, num_cols); // initial gaussian matrix
229 
230     uint32_t matrix_row = 0;
231     for (uint32_t i = 0; i != xorclauses.size(); i++) {
232         const Xor& c = xorclauses[i];
233         mat[matrix_row].set(c, var_to_col, num_cols);
234         matrix_row++;
235     }
236     assert(num_rows == matrix_row);
237 
238     // reset
239     var_has_resp_row.clear();
240     var_has_resp_row.resize(solver->nVars(), 0);
241     row_to_var_non_resp.clear();
242 
243     delete_gauss_watch_this_matrix();
244 
245     //reset satisfied_xor state
246     assert(solver->decisionLevel() == 0);
247     satisfied_xors.clear();
248     satisfied_xors.resize(num_rows, 0);
249 }
250 
delete_gauss_watch_this_matrix()251 void EGaussian::delete_gauss_watch_this_matrix()
252 {
253     for (size_t ii = 0; ii < solver->gwatches.size(); ii++) {
254         clear_gwatches(ii);
255     }
256 }
257 
clear_gwatches(const uint32_t var)258 void EGaussian::clear_gwatches(const uint32_t var)
259 {
260     //if there is only one matrix, don't check, just empty it
261     if (solver->gmatrices.size() == 0) {
262         solver->gwatches[var].clear();
263         return;
264     }
265 
266     GaussWatched* i = solver->gwatches[var].begin();
267     GaussWatched* j = i;
268     for(GaussWatched* end = solver->gwatches[var].end(); i != end; i++) {
269         if (i->matrix_num != matrix_no) {
270             *j++ = *i;
271         }
272     }
273     solver->gwatches[var].shrink(i-j);
274 }
275 
clean_xors()276 bool EGaussian::clean_xors()
277 {
278     for(Xor& x: xorclauses) {
279         solver->clean_xor_vars_no_prop(x.get_vars(), x.rhs);
280     }
281     XorFinder f(NULL, solver);
282     if (!f.add_new_truths_from_xors(xorclauses))
283         return false;
284 
285     return true;
286 }
287 
full_init(bool & created)288 bool EGaussian::full_init(bool& created) {
289     assert(solver->ok);
290     assert(solver->decisionLevel() == 0);
291     bool do_again_gauss = true;
292     created = true;
293     if (!clean_xors()) {
294         return false;
295     }
296 
297     while (do_again_gauss) {
298         do_again_gauss = false;
299 
300         if (!solver->clauseCleaner->clean_xor_clauses(xorclauses)) {
301             return false;
302         }
303 
304         fill_matrix();
305         before_init_density = get_density();
306         if (num_rows == 0 || num_cols == 0) {
307             created = false;
308             return solver->okay();
309         }
310 
311         eliminate();
312 
313         // find some row already true false, and insert watch list
314         gret ret = adjust_matrix();
315 
316         switch (ret) {
317             case gret::confl:
318                 solver->ok = false;
319                 return false;
320                 break;
321             case gret::prop:
322                 do_again_gauss = true;
323 
324                 assert(solver->decisionLevel() == 0);
325                 solver->ok = (solver->propagate<false>().isNULL());
326                 if (!solver->ok) {
327                     return false;
328                 }
329                 break;
330             default:
331                 break;
332         }
333     }
334 
335 #ifdef SLOW_DEBUG
336     check_watchlist_sanity();
337 #endif
338 
339     if (solver->conf.verbosity >= 2) {
340         cout << "c [gauss] initialised matrix " << matrix_no << endl;
341     }
342 
343     xor_reasons.resize(num_rows);
344     uint32_t num_64b = num_cols/64+(bool)(num_cols%64);
345     for(auto& x: tofree) {
346         delete[] x;
347     }
348     tofree.clear();
349     delete cols_unset;
350     delete cols_vals;
351     delete tmp_col;
352     delete tmp_col2;
353 
354     int64_t* x = new int64_t[num_64b+1];
355     tofree.push_back(x);
356     cols_unset = new PackedRow(num_64b, x);
357 
358     x = new int64_t[num_64b+1];
359     tofree.push_back(x);
360     cols_vals = new PackedRow(num_64b, x);
361 
362     x = new int64_t[num_64b+1];
363     tofree.push_back(x);
364     tmp_col = new PackedRow(num_64b, x);
365 
366     x = new int64_t[num_64b+1];
367     tofree.push_back(x);
368     tmp_col2 = new PackedRow(num_64b, x);
369 
370     cols_vals->rhs() = 0;
371     cols_unset->rhs() = 0;
372     tmp_col->rhs() = 0;
373     tmp_col2->rhs() = 0;
374     after_init_density = get_density();
375 
376     update_cols_vals_set(true);
377     #ifdef SLOW_DEBUG
378     check_invariants();
379     #endif
380 
381 
382     return true;
383 }
384 
eliminate()385 void EGaussian::eliminate() {
386     uint32_t row = 0;
387     uint32_t col = 0;
388     PackedMatrix::iterator end_row_it = mat.begin() + num_rows;
389     PackedMatrix::iterator row_i = mat.begin();
390 
391     // Gauss-Jordan Elimination
392     while (row != num_rows && col != num_cols) {
393         PackedMatrix::iterator row_with_1_in_col = row_i;
394 
395         //Find first "1" in column.
396         for (; row_with_1_in_col != end_row_it; ++row_with_1_in_col) {
397             if ((*row_with_1_in_col)[col]) {
398                 break;
399             }
400         }
401 
402         //We have found a "1" in this column
403         if (row_with_1_in_col != end_row_it) {
404             //cout << "col zeroed:" << col << " var is: " << col_to_var[col] + 1 << endl;
405             var_has_resp_row[col_to_var[col]] = 1;
406 
407             // swap row row_with_1_in_col and rowIt
408             if (row_with_1_in_col != row_i) {
409                 (*row_i).swapBoth(*row_with_1_in_col);
410             }
411 
412             // XOR into *all* rows that have a "1" in column COL
413             // Since we XOR into *all*, this is Gauss-Jordan (and not just Gauss)
414             for (PackedMatrix::iterator k_row = mat.begin()
415                 ; k_row != end_row_it
416                 ; ++k_row
417             ) {
418                 // xor rows K and I
419                 if (k_row != row_i) {
420                     if ((*k_row)[col]) {
421                         (*k_row).xor_in(*row_i);
422                     }
423                 }
424             }
425             row++;
426             ++row_i;
427         }
428         col++;
429     }
430     //print_matrix();
431 }
432 
adjust_matrix()433 gret EGaussian::adjust_matrix()
434 {
435     assert(solver->decisionLevel() == 0);
436     assert(row_to_var_non_resp.empty());
437     assert(satisfied_xors.size() >= num_rows);
438     #ifdef VERBOSE_DEBUG
439     cout << "mat[" << matrix_no << "] adjusting matrix" << endl;
440     #endif
441 
442     PackedMatrix::iterator end = mat.begin() + num_rows;
443     PackedMatrix::iterator rowIt = mat.begin();
444     uint32_t row_n = 0;      // row index
445     uint32_t adjust_zero = 0; //  elimination row
446 
447     while (rowIt != end) {
448         uint32_t non_resp_var;
449         const uint32_t popcnt = (*rowIt).find_watchVar(
450             tmp_clause, col_to_var, var_has_resp_row, non_resp_var);
451 
452         switch (popcnt) {
453 
454             //Conflict or satisfied
455             case 0:
456                 // printf("%d:Warning: this row is all zero in adjust matrix    n",row_id);
457                 adjust_zero++;
458 
459                 // conflict
460                 if ((*rowIt).rhs()) {
461                     // printf("%d:Warring: this row is conflict in adjust matrix!!!",row_id);
462                     #ifdef VERBOSE_DEBUG
463                     cout << "-> conflict on row: " << row_n << endl;
464                     #endif
465                     return gret::confl;
466                 }
467                 #ifdef VERBOSE_DEBUG
468                 cout << "-> empty on this row. " << endl;
469                 cout << "-> Satisfied XORs set for row: " << row_n << endl;
470                 #endif
471                 satisfied_xors[row_n] = 1;
472                 break;
473 
474             //Normal propagation
475             case 1:
476             {
477                 // printf("%d:This row only one variable, need to propogation!!!! in adjust matrix
478                 // n",row_id);
479 
480                 bool xorEqualFalse = !mat[row_n].rhs();
481                 tmp_clause[0] = Lit(tmp_clause[0].var(), xorEqualFalse);
482                 assert(solver->value(tmp_clause[0].var()) == l_Undef);
483                 solver->enqueue(tmp_clause[0]); // propagation
484 
485                 #ifdef VERBOSE_DEBUG
486                 cout << "-> Propagation for " << tmp_clause[0] << endl;
487                 cout << "-> Satisfied XORs set for row: " << row_n << endl;
488                 #endif
489                 satisfied_xors[row_n] = 1;
490                 #ifdef SLOW_DEBUG
491                 assert(check_row_satisfied(row_n));
492                 #endif
493 
494                 //adjusting
495                 (*rowIt).setZero(); // reset this row all zero
496                 row_to_var_non_resp.push_back(std::numeric_limits<uint32_t>::max());
497                 var_has_resp_row[tmp_clause[0].var()] = 0;
498                 return gret::prop;
499             }
500 
501             //Binary XOR
502             case 2: {
503                 // printf("%d:This row have two variable!!!! in adjust matrix    n",row_id);
504                 bool xorEqualFalse = !mat[row_n].rhs();
505 
506                 tmp_clause[0] = tmp_clause[0].unsign();
507                 tmp_clause[1] = tmp_clause[1].unsign();
508                 solver->ok = solver->add_xor_clause_inter(tmp_clause, !xorEqualFalse, true);
509                 release_assert(solver->ok);
510 
511                 #ifdef VERBOSE_DEBUG
512                 cout << "-> bin-xor on row: " << row_n << endl;
513                 #endif
514 
515                 // reset this row all zero, no need for this row
516                 (*rowIt).rhs() = 0;
517                 (*rowIt).setZero();
518 
519                 row_to_var_non_resp.push_back(std::numeric_limits<uint32_t>::max()); // delete non-basic value in this row
520                 var_has_resp_row[tmp_clause[0].var()] = 0; // delete basic value in this row
521                 break;
522             }
523 
524             default: // need to update watch list
525                 // printf("%d:need to update watch list    n",row_id);
526                 assert(non_resp_var != std::numeric_limits<uint32_t>::max());
527 
528                 // insert watch list
529                 #ifdef VERBOSE_DEBUG
530                 cout << "-> watch 1: resp var " << tmp_clause[0].var()+1 << "for row " << row_n << endl;
531                 cout << "-> watch 2: non-resp var " << non_resp_var+1 << "for row " << row_n << endl;
532                 #endif
533                 solver->gwatches[tmp_clause[0].var()].push(
534                     GaussWatched(row_n, matrix_no)); // insert basic variable
535 
536                 solver->gwatches[non_resp_var].push(
537                     GaussWatched(row_n, matrix_no)); // insert non-basic variable
538                 row_to_var_non_resp.push_back(non_resp_var);               // record in this row non-basic variable
539                 break;
540         }
541         ++rowIt;
542         row_n++;
543     }
544     // printf("DD:nb_rows:%d %d %d    n",nb_rows.size() ,   row_n - adjust_zero  ,  adjust_zero);
545     assert(row_to_var_non_resp.size() == row_n - adjust_zero);
546 
547     mat.resizeNumRows(row_n - adjust_zero);
548     num_rows = row_n - adjust_zero;
549 
550     return gret::nothing_satisfied;
551 }
552 
553 // Delete this row because we have already add to xor clause, nothing to do anymore
delete_gausswatch(const uint32_t row_n)554 void EGaussian::delete_gausswatch(
555     const uint32_t row_n
556 ) {
557     // clear nonbasic value watch list
558     bool debug_find = false;
559     vec<GaussWatched>& ws_t = solver->gwatches[row_to_var_non_resp[row_n]];
560 
561     for (int32_t tmpi = ws_t.size() - 1; tmpi >= 0; tmpi--) {
562         if (ws_t[tmpi].row_n == row_n
563             && ws_t[tmpi].matrix_num == matrix_no
564         ) {
565             ws_t[tmpi] = ws_t.last();
566             ws_t.shrink(1);
567             debug_find = true;
568             break;
569         }
570     }
571     #ifdef VERBOSE_DEBUG
572     cout
573     << "mat[" << matrix_no << "] "
574     << "Tried cleaning watch of var: "
575     << row_to_var_non_resp[row_n]+1 << endl;
576     #endif
577     assert(debug_find);
578 }
579 
get_max_level(const GaussQData & gqd,const uint32_t row_n)580 uint32_t EGaussian::get_max_level(const GaussQData& gqd, const uint32_t row_n)
581 {
582     auto cl = get_reason(row_n);
583     uint32_t nMaxLevel = gqd.currLevel;
584     uint32_t nMaxInd = 1;
585 
586     for (uint32_t i = 1; i < cl->size(); i++) {
587         Lit l = (*cl)[i];
588         uint32_t nLevel = solver->varData[l.var()].level;
589         if (nLevel > nMaxLevel) {
590             nMaxLevel = nLevel;
591             nMaxInd = i;
592         }
593     }
594 
595     //should we??
596     if (nMaxInd != 1) {
597         std::swap((*cl)[1], (*cl)[nMaxInd]);
598     }
599     return nMaxLevel;
600 }
601 
find_truths(GaussWatched * & i,GaussWatched * & j,const uint32_t var,const uint32_t row_n,GaussQData & gqd)602 bool EGaussian::find_truths(
603     GaussWatched*& i,
604     GaussWatched*& j,
605     const uint32_t var,
606     const uint32_t row_n,
607     GaussQData& gqd
608 ) {
609     assert(gqd.ret != gauss_res::confl);
610     #ifdef LAZY_DELETE_HACK
611     if (!mat[row_n][var_to_col[var]]) {
612         //lazy delete
613         return true;
614     }
615     #endif
616     // printf("dd Watch variable : %d  ,  Wathch row num %d    n", p , row_n);
617 
618     #ifdef VERBOSE_DEBUG
619     cout << "mat[" << matrix_no << "] find_truths" << endl;
620     cout << "-> row: " << row_n << endl;
621     cout << "-> var: " << var+1 << endl;
622     cout << "-> dec lev:" << solver->decisionLevel() << endl;
623     #endif
624     #ifdef SLOW_DEBUG
625     assert(row_n < num_rows);
626     assert(satisfied_xors.size() > row_n);
627     #endif
628 
629     // this XOR is already satisfied
630     if (satisfied_xors[row_n]) {
631         #ifdef VERBOSE_DEBUG
632         cout << "-> xor satisfied as per satisfied_xors[row_n]" << endl;
633         #endif
634         #ifdef SLOW_DEBUG
635         assert(check_row_satisfied(row_n));
636         #endif
637         *j++ = *i;
638         find_truth_ret_satisfied_precheck++;
639         return true;
640     }
641 
642 
643     // swap resp and non-resp variable
644     bool was_resp_var = false;
645     if (var_has_resp_row[var] == 1) {
646         //var has a responsible row, so THIS row must be it!
647         //since if a var has a responsible row, only ONE row can have a 1 there
648         was_resp_var = true;
649         var_has_resp_row[row_to_var_non_resp[row_n]] = 1;
650         var_has_resp_row[var] = 0;
651     }
652 
653     uint32_t new_resp_var;
654     Lit ret_lit_prop;
655     #ifdef SLOW_DEBUG
656     check_cols_unset_vals();
657     #endif
658     const gret ret = mat[row_n].propGause(
659         solver->assigns,
660         col_to_var,
661         var_has_resp_row,
662         new_resp_var,
663         *tmp_col,
664         *tmp_col2,
665         *cols_vals,
666         *cols_unset,
667         ret_lit_prop);
668     find_truth_called_propgause++;
669 
670     switch (ret) {
671         case gret::confl: {
672             find_truth_ret_confl++;
673             *j++ = *i;
674 
675             xor_reasons[row_n].must_recalc = true;
676             xor_reasons[row_n].propagated = lit_Undef;
677             gqd.confl = PropBy(matrix_no, row_n);
678             gqd.ret = gauss_res::confl;
679             #ifdef VERBOSE_DEBUG
680             cout
681             << "--> conflict" << endl;
682             #endif
683 
684             if (was_resp_var) { // recover
685                 var_has_resp_row[row_to_var_non_resp[row_n]] = 0;
686                 var_has_resp_row[var] = 1;
687             }
688 
689             return false;
690         }
691 
692         case gret::prop: {
693             find_truth_ret_prop++;
694             #ifdef VERBOSE_DEBUG
695             cout
696             << "--> propagation" << endl;
697             #endif
698             *j++ = *i;
699 
700 
701             xor_reasons[row_n].must_recalc = true;
702             xor_reasons[row_n].propagated = ret_lit_prop;
703             assert(solver->value(ret_lit_prop.var()) == l_Undef);
704             if (gqd.currLevel == solver->decisionLevel()) {
705                 solver->enqueue(ret_lit_prop, gqd.currLevel, PropBy(matrix_no, row_n));
706             } else {
707                 uint32_t nMaxLevel = get_max_level(gqd, row_n);
708                 solver->enqueue(ret_lit_prop, nMaxLevel, PropBy(matrix_no, row_n));
709             }
710             update_cols_vals_set(ret_lit_prop);
711             gqd.ret = gauss_res::prop;
712 
713             if (was_resp_var) { // recover
714                 var_has_resp_row[row_to_var_non_resp[row_n]] = 0;
715                 var_has_resp_row[var] = 1;
716             }
717 
718             #ifdef VERBOSE_DEBUG
719             cout << "--> Satisfied XORs set for row: " << row_n << endl;
720             #endif
721             satisfied_xors[row_n] = 1;
722             #ifdef SLOW_DEBUG
723             assert(check_row_satisfied(row_n));
724             #endif
725             return true;
726         }
727 
728         // find new watch list
729         case gret::nothing_fnewwatch:
730             #ifdef VERBOSE_DEBUG
731             cout
732             << "--> found new watch: " << new_resp_var+1 << endl;
733             #endif
734 
735             find_truth_ret_fnewwatch++;
736             // printf("%d:This row is find new watch:%d => orig %d p:%d    n",row_n ,
737             // new_resp_var,orig_basic , p);
738 
739             if (was_resp_var) {
740                 /// clear watchlist, because only one responsible value in watchlist
741                 assert(new_resp_var != var);
742                 clear_gwatches(new_resp_var);
743                 #ifdef VERBOSE_DEBUG
744                 cout << "Cleared watchlist for new resp var: " << new_resp_var+1 << endl;
745                 cout << "After clear..."; print_gwatches(new_resp_var);
746                 #endif
747             }
748             assert(new_resp_var != var);
749             #ifdef SLOW_DEBUG
750             #ifdef VERBOSE_DEBUG
751             print_gwatches(new_resp_var);
752             #endif
753             check_row_not_in_watch(new_resp_var, row_n);
754             #endif
755             solver->gwatches[new_resp_var].push(GaussWatched(row_n, matrix_no));
756 
757             if (was_resp_var) {
758                 //it was the responsible one, so the newly watched var
759                 //is the new column it's responsible for
760                 //so elimination will be needed
761 
762                 //clear old one, add new resp
763                 var_has_resp_row[row_to_var_non_resp[row_n]] = 0;
764                 var_has_resp_row[new_resp_var] = 1;
765 
766                 // store the eliminate variable & row
767                 gqd.new_resp_var = new_resp_var;
768                 gqd.new_resp_row = row_n;
769                 if (solver->gmatrices.size() == 1) {
770                     assert(solver->gwatches[gqd.new_resp_var].size() == 1);
771                 }
772                 gqd.do_eliminate = true;
773                 return true;
774             } else {
775                 row_to_var_non_resp[row_n] = new_resp_var;
776                 return true;
777             }
778 
779         // this row already true
780         case gret::nothing_satisfied:
781             #ifdef VERBOSE_DEBUG
782             cout
783             << "--> satisfied" << endl;
784             #endif
785 
786             find_truth_ret_satisfied++;
787             // printf("%d:This row is nothing( maybe already true)     n",row_n);
788             *j++ = *i;
789             if (was_resp_var) { // recover
790                 var_has_resp_row[row_to_var_non_resp[row_n]] = 0;
791                 var_has_resp_row[var] = 1;
792             }
793 
794             #ifdef VERBOSE_DEBUG
795             cout << "--> Satisfied XORs set for row: " << row_n << endl;
796             #endif
797             satisfied_xors[row_n] = 1;
798             #ifdef SLOW_DEBUG
799             assert(check_row_satisfied(row_n));
800             #endif
801             return true;
802 
803         //error here
804         default:
805             assert(false); // cannot be here
806             break;
807     }
808 
809     assert(false);
810     return true;
811 }
812 
update_cols_vals_set(const Lit lit1)813 inline void EGaussian::update_cols_vals_set(const Lit lit1)
814 {
815     cols_unset->clearBit(var_to_col[lit1.var()]);
816     if (!lit1.sign()) {
817         cols_vals->setBit(var_to_col[lit1.var()]);
818     }
819 }
820 
update_cols_vals_set(bool force)821 void EGaussian::update_cols_vals_set(bool force)
822 {
823     //cancelled_since_val_update = true;
824     if (cancelled_since_val_update || force) {
825         cols_vals->setZero();
826         cols_unset->setOne();
827 
828         for(uint32_t col = 0; col < col_to_var.size(); col++) {
829             uint32_t var = col_to_var[col];
830             if (solver->value(var) != l_Undef) {
831                 cols_unset->clearBit(col);
832                 if (solver->value(var) == l_True) {
833                     cols_vals->setBit(col);
834                 }
835             }
836         }
837         last_val_update = solver->trail.size();
838         cancelled_since_val_update = false;
839         return;
840     }
841 
842     assert(solver->trail.size() >= last_val_update);
843     for(uint32_t i = last_val_update; i < solver->trail.size(); i++) {
844         uint32_t var = solver->trail[i].lit.var();
845         if (var_to_col.size() <= var) {
846             continue;
847         }
848         uint32_t col = var_to_col[var];
849         if (col != unassigned_col) {
850             assert (solver->value(var) != l_Undef);
851             cols_unset->clearBit(col);
852             if (solver->value(var) == l_True) {
853                 cols_vals->setBit(col);
854             }
855         }
856     }
857     last_val_update = solver->trail.size();
858 }
859 
eliminate_col(uint32_t p,GaussQData & gqd)860 void EGaussian::eliminate_col(uint32_t p, GaussQData& gqd) {
861     PackedMatrix::iterator new_resp_row = mat.begin() + gqd.new_resp_row;
862     PackedMatrix::iterator rowI = mat.begin();
863     PackedMatrix::iterator end = mat.end();
864     const uint32_t new_resp_col = var_to_col[gqd.new_resp_var];
865     uint32_t row_n = 0;
866 
867     #ifdef VERBOSE_DEBUG
868     cout
869     << "mat[" << matrix_no << "] "
870     << "** eliminating this column: " << new_resp_col << endl
871     << "-> row that will be the SOLE one having a 1: " << gqd.new_resp_row << endl
872     << "-> var associated with col: " << gqd.new_resp_var+1
873     <<  endl;
874     #endif
875     elim_called++;
876 
877     while (rowI != end) {
878         //Row has a '1' in eliminating column, and it's not the row responsible
879         if (new_resp_row != rowI && (*rowI)[new_resp_col]) {
880 
881             // detect orignal non-basic watch list change or not
882             uint32_t orig_non_resp_var = row_to_var_non_resp[row_n];
883             uint32_t orig_non_resp_col = var_to_col[orig_non_resp_var];
884             assert((*rowI)[orig_non_resp_col]);
885             #ifdef VERBOSE_DEBUG
886             cout
887             << "--> This row " << row_n
888             << " is being watched on var: " << orig_non_resp_var + 1
889             << " i.e. it must contain '1' for this var's column"
890             << endl;
891             #endif
892 
893             assert(satisfied_xors[row_n] == 0);
894             (*rowI).xor_in(*new_resp_row);
895             elim_xored_rows++;
896 
897             //NOTE: responsible variable cannot be eliminated of course
898             //      (it's the only '1' in that column).
899             //      But non-responsible can be eliminated. So let's check that
900             //      and then deal with it if we have to
901             if (!(*rowI)[orig_non_resp_col]) {
902 
903                 #ifdef VERBOSE_DEBUG
904                 cout
905                 << "--> This row " << row_n
906                 << " can no longer be watched (non-responsible), it has no '1' at col " << orig_non_resp_col
907                 << " (var " << col_to_var[orig_non_resp_col]+1 << ")"
908                 << " fixing up..."<< endl;
909                 #endif
910 
911                 // Delete orignal non-responsible var from watch list
912                 if (orig_non_resp_var != gqd.new_resp_var) {
913                     #ifndef LAZY_DELETE_HACK
914                     delete_gausswatch(row_n);
915                     #endif
916                 } else {
917                     //this does not need a delete, because during
918                     //find_truths, we already did clear_gwatches of the
919                     //orig_non_resp_var, so there is nothing to delete here
920                 }
921 
922                 Lit ret_lit_prop;
923                 uint32_t new_non_resp_var = 0;
924                 #ifdef SLOW_DEBUG
925                 check_cols_unset_vals();
926                 #endif
927                 const gret ret = (*rowI).propGause(
928                     solver->assigns,
929                     col_to_var,
930                     var_has_resp_row,
931                     new_non_resp_var,
932                     *tmp_col,
933                     *tmp_col2,
934                     *cols_vals,
935                     *cols_unset,
936                     ret_lit_prop
937                 );
938                 elim_called_propgause++;
939 
940                 switch (ret) {
941                     case gret::confl: {
942                         elim_ret_confl++;
943                         #ifdef VERBOSE_DEBUG
944                         cout
945                         << "---> conflict during fixup"<< endl;
946                         #endif
947 
948                         solver->gwatches[p].push(
949                             GaussWatched(row_n, matrix_no));
950 
951                         // update in this row non-basic variable
952                         row_to_var_non_resp[row_n] = p;
953 
954                         xor_reasons[row_n].must_recalc = true;
955                         xor_reasons[row_n].propagated = lit_Undef;
956                         gqd.confl = PropBy(matrix_no, row_n);
957                         gqd.ret = gauss_res::confl;
958                         break;
959                     }
960                     case gret::prop: {
961                         elim_ret_prop++;
962                         #ifdef VERBOSE_DEBUG
963                         cout
964                         << "---> propagation during fixup" << endl;
965                         #endif
966 
967                         // if conflicted already, just update non-basic variable
968                         if (gqd.ret == gauss_res::confl) {
969                             #ifdef SLOW_DEBUG
970                             check_row_not_in_watch(p, row_n);
971                             #endif
972                             solver->gwatches[p].push(GaussWatched(row_n, matrix_no));
973                             row_to_var_non_resp[row_n] = p;
974                             break;
975                         }
976 
977                         // update no_basic information
978                         #ifdef SLOW_DEBUG
979                         check_row_not_in_watch(p, row_n);
980                         #endif
981                         solver->gwatches[p].push(GaussWatched(row_n, matrix_no));
982                         row_to_var_non_resp[row_n] = p;
983 
984                         xor_reasons[row_n].must_recalc = true;
985                         xor_reasons[row_n].propagated = ret_lit_prop;
986                         assert(solver->value(ret_lit_prop.var()) == l_Undef);
987                         if (gqd.currLevel == solver->decisionLevel()) {
988                             solver->enqueue(ret_lit_prop, gqd.currLevel, PropBy(matrix_no, row_n));
989                         } else {
990                             uint32_t nMaxLevel = get_max_level(gqd, row_n);
991                             solver->enqueue(ret_lit_prop, nMaxLevel, PropBy(matrix_no, row_n));
992                         }
993                         update_cols_vals_set(ret_lit_prop);
994                         gqd.ret = gauss_res::prop;
995 
996                         #ifdef VERBOSE_DEBUG
997                         cout << "---> Satisfied XORs set for row: " << row_n << endl;
998                         #endif
999                         satisfied_xors[row_n] = 1;
1000                         #ifdef SLOW_DEBUG
1001                         assert(check_row_satisfied(row_n));
1002                         #endif
1003                         break;
1004                     }
1005 
1006                     // find new watch list
1007                     case gret::nothing_fnewwatch:
1008                         elim_ret_fnewwatch++;
1009                         #ifdef VERBOSE_DEBUG
1010                         cout
1011                         << "---> Nothing, clause NOT already satisfied, pushing in "
1012                         << new_non_resp_var+1 << " as non-responsible var ( "
1013                         << row_n << " row) "
1014                         << endl;
1015                         #endif
1016 
1017                         #ifdef SLOW_DEBUG
1018                         check_row_not_in_watch(new_non_resp_var, row_n);
1019                         #endif
1020                         solver->gwatches[new_non_resp_var].push(GaussWatched(row_n, matrix_no));
1021                         row_to_var_non_resp[row_n] = new_non_resp_var;
1022                         break;
1023 
1024                     // this row already satisfied
1025                     case gret::nothing_satisfied:
1026                         elim_ret_satisfied++;
1027                         #ifdef VERBOSE_DEBUG
1028                         cout
1029                         << "---> Nothing to do, already satisfied , pushing in "
1030                         << p+1 << " as non-responsible var ( "
1031                         << row_n << " row) "
1032                         << endl;
1033                         #endif
1034 
1035                         // printf("%d:This row is nothing( maybe already true) in eliminate col
1036                         // n",num_row);
1037 
1038                         #ifdef SLOW_DEBUG
1039                         check_row_not_in_watch(p, row_n);
1040                         #endif
1041                         solver->gwatches[p].push(GaussWatched(row_n, matrix_no));
1042                         row_to_var_non_resp[row_n] = p;
1043 
1044                         #ifdef VERBOSE_DEBUG
1045                         cout << "---> Satisfied XORs set for row: " << row_n << endl;
1046                         #endif
1047                         satisfied_xors[row_n] = 1;
1048                         #ifdef SLOW_DEBUG
1049                         assert(check_row_satisfied(row_n));
1050                         #endif
1051                         break;
1052                     default:
1053                         // can not here
1054                         assert(false);
1055                         break;
1056                 }
1057             } else {
1058                 #ifdef VERBOSE_DEBUG
1059                 cout
1060                 << "--> OK, this row " << row_n
1061                 << " still contains '1', can still be responsible" << endl;
1062                 #endif
1063             }
1064         }
1065         ++rowI;
1066         row_n++;
1067     }
1068 
1069     // Debug_funtion();
1070     #ifdef VERBOSE_DEBUG
1071     cout
1072     << "mat[" << matrix_no << "] "
1073     << "eliminate_col - exiting. " << endl;
1074     #endif
1075 }
1076 
print_matrix()1077 void EGaussian::print_matrix() {
1078     uint32_t row = 0;
1079     for (PackedMatrix::iterator it = mat.begin(); it != mat.end();
1080          ++it, row++) {
1081         cout << *it << " -- row:" << row;
1082         if (row >= num_rows) {
1083             cout << " (considered past the end)";
1084         }
1085         cout << endl;
1086     }
1087 }
1088 
print_matrix_stats(uint32_t verbosity)1089 void EGaussian::print_matrix_stats(uint32_t verbosity)
1090 {
1091     std::stringstream ss;
1092     ss << "c [g " << matrix_no << "] ";
1093     const std::string pre = ss.str();
1094 
1095     cout << std::left;
1096 
1097     if (verbosity >= 2) {
1098         cout << pre << "truth-find satisfied    : "
1099         << print_value_kilo_mega(find_truth_ret_satisfied_precheck, false) << endl;
1100     }
1101 
1102     if (verbosity >= 1) {
1103         cout << pre << "truth-find prop checks  : "
1104         << print_value_kilo_mega(find_truth_called_propgause, false) << endl;
1105     }
1106 
1107 
1108     if (verbosity >= 2) {
1109         cout << pre << "-> of which fnnewat     : "
1110         << std::setw(5) << std::setprecision(2) << std::right
1111         << stats_line_percent(find_truth_ret_fnewwatch, find_truth_called_propgause)
1112         << " %"
1113         << endl;
1114         cout << pre << "-> of which sat         : "
1115         << std::setw(5) << std::setprecision(2) << std::right
1116         << stats_line_percent(find_truth_ret_satisfied, find_truth_called_propgause)
1117         << " %"
1118         << endl;
1119     }
1120 
1121     if (verbosity >= 1) {
1122         cout << pre << "-> of which prop        : "
1123         << std::setw(5) << std::setprecision(2) << std::right
1124         << stats_line_percent(find_truth_ret_prop, find_truth_called_propgause)
1125         << " %"
1126         << endl;
1127         cout << pre << "-> of which confl       : "
1128         << std::setw(5) << std::setprecision(2) << std::right
1129         << stats_line_percent(find_truth_ret_confl, find_truth_called_propgause)
1130         << " %"
1131         << endl;
1132     }
1133 
1134     cout << std::left;
1135     cout << pre << "elim called             : "
1136     << print_value_kilo_mega(elim_called, false) << endl;
1137 
1138     if (verbosity >= 2) {
1139         cout << pre << "-> lead to xor rows     : "
1140         << print_value_kilo_mega(elim_xored_rows, false) << endl;
1141 
1142         cout << pre << "--> lead to prop checks : "
1143         << print_value_kilo_mega(elim_called_propgause, false) << endl;
1144 
1145         cout << pre << "---> of which satsified : "
1146         << std::setw(5) << std::setprecision(2) << std::right
1147         << stats_line_percent(elim_ret_satisfied, elim_called_propgause)
1148         << " %"
1149         << endl;
1150 
1151         cout << pre << "---> of which prop      : "
1152         << std::setw(5) << std::setprecision(2) << std::right
1153         << stats_line_percent(elim_ret_prop, elim_called_propgause)
1154         << " %"
1155         << endl;
1156 
1157         cout << pre << "---> of which fnnewat   : "
1158         << std::setw(5) << std::setprecision(2) << std::right
1159         << stats_line_percent(elim_ret_fnewwatch, elim_called_propgause)
1160         << " %"
1161         << endl;
1162 
1163         cout << pre << "---> of which confl     : "
1164         << std::setw(5) << std::setprecision(2) << std::right
1165         << stats_line_percent(elim_ret_confl, elim_called_propgause)
1166         << " %"
1167         << endl;
1168     }
1169 
1170     if (verbosity == 1) {
1171         cout << pre << "---> which lead to prop : "
1172         << std::setw(5) << std::setprecision(2) << std::right
1173         << stats_line_percent(elim_ret_prop, elim_called)
1174         << " %"
1175         << endl;
1176 
1177         cout << pre << "---> which lead to confl: "
1178         << std::setw(5) << std::setprecision(2) << std::right
1179         << stats_line_percent(elim_ret_confl, elim_called)
1180         << " %"
1181         << endl;
1182     }
1183 
1184     cout << std::left;
1185     cout << pre << "size: "
1186     << std::setw(5) << num_rows << " x "
1187     << std::setw(5) << num_cols << endl;
1188 
1189     double density = get_density();
1190 
1191     if (verbosity >= 2) {
1192         cout << pre << "density before init: "
1193         << std::setprecision(4) << std::left << before_init_density
1194         << endl;
1195         cout << pre << "density after  init: "
1196         << std::setprecision(4) << std::left << after_init_density
1197         << endl;
1198         cout << pre << "density            : "
1199         << std::setprecision(4) << std::left << density
1200         << endl;
1201     }
1202     cout << std::setprecision(2);
1203 }
1204 
get_reason(uint32_t row)1205 vector<Lit>* EGaussian::get_reason(uint32_t row)
1206 {
1207     if (!xor_reasons[row].must_recalc) {
1208         return &(xor_reasons[row].reason);
1209     }
1210     vector<Lit>& tofill = xor_reasons[row].reason;
1211     tofill.clear();
1212 
1213     mat[row].get_reason(
1214         tofill,
1215         solver->assigns,
1216         col_to_var,
1217         *cols_vals,
1218         *tmp_col2,
1219         xor_reasons[row].propagated);
1220 
1221     xor_reasons[row].must_recalc = false;
1222     return &tofill;
1223 }
1224 
1225 //////////////////
1226 // Checking functions below
1227 //////////////////
1228 
check_row_not_in_watch(const uint32_t v,const uint32_t row_num) const1229 void EGaussian::check_row_not_in_watch(const uint32_t v, const uint32_t row_num) const
1230 {
1231     for(const auto& x: solver->gwatches[v]) {
1232         if (x.matrix_num == matrix_no && x.row_n == row_num) {
1233             cout << "OOOps, row ID " << row_num << " already in watch for var: " << v+1 << endl;
1234             assert(false);
1235         }
1236     }
1237 }
1238 
print_gwatches(const uint32_t var) const1239 void EGaussian::print_gwatches(const uint32_t var) const
1240 {
1241     vec<GaussWatched> mycopy;
1242     for(const auto& x: solver->gwatches[var]) {
1243         mycopy.push(x);
1244     }
1245 
1246     std::sort(mycopy.begin(), mycopy.end());
1247     cout << "Watch for var " << var+1 << ": ";
1248     for(const auto& x: mycopy) {
1249         cout
1250         << "(Mat num: " << x.matrix_num
1251         << " row_n: " << x.row_n << ") ";
1252     }
1253     cout << endl;
1254 }
1255 
1256 
check_no_prop_or_unsat_rows()1257 void EGaussian::check_no_prop_or_unsat_rows()
1258 {
1259     #ifdef VERBOSE_DEBUG
1260     cout << "mat[" << matrix_no << "] checking invariants..." << endl;
1261     #endif
1262 
1263     for(uint32_t row = 0; row < num_rows; row++) {
1264         uint32_t bits_unset = 0;
1265         bool val = mat[row].rhs();
1266         for(uint32_t col = 0; col < num_cols; col++) {
1267             if (mat[row][col]) {
1268                 uint32_t var = col_to_var[col];
1269                 if (solver->value(var) == l_Undef) {
1270                     bits_unset++;
1271                 } else {
1272                     val ^= (solver->value(var) == l_True);
1273                 }
1274             }
1275         }
1276 
1277         bool error = false;
1278         if (bits_unset == 1) {
1279             cout << "ERROR: row " << row << " is PROP but did not propagate!!!" << endl;
1280             error = true;
1281         }
1282         if (bits_unset == 0 && val != false) {
1283             cout << "ERROR: row " << row << " is UNSAT but did not conflict!" << endl;
1284             error = true;
1285         }
1286         if (error) {
1287             for(uint32_t var = 0; var < solver->nVars(); var++) {
1288                 const auto& ws = solver->gwatches[var];
1289                 for(const auto& w: ws) {
1290                     if (w.matrix_num == matrix_no && w.row_n == row) {
1291                         cout << "       gauss watched at var: " << var+1
1292                         << " val: " << solver->value(var) << endl;
1293                     }
1294                 }
1295             }
1296 
1297             cout << "       matrix no: " << matrix_no << endl;
1298             cout << "       row: " << row << endl;
1299             uint32_t var = row_to_var_non_resp[row];
1300             cout << "       non-resp var: " << var+1 << endl;
1301             cout << "       dec level: " << solver->decisionLevel() << endl;
1302         }
1303         assert(bits_unset > 1 || (bits_unset == 0 && val == 0));
1304     }
1305 }
1306 
check_watchlist_sanity()1307 void EGaussian::check_watchlist_sanity()
1308 {
1309     for(size_t i = 0; i < solver->nVars(); i++) {
1310         for(auto w: solver->gwatches[i]) {
1311             if (w.matrix_num == matrix_no) {
1312                 assert(i < var_to_col.size());
1313             }
1314         }
1315     }
1316 }
1317 
check_tracked_cols_only_one_set()1318 void EGaussian::check_tracked_cols_only_one_set()
1319 {
1320     vector<uint32_t> row_resp_for_var(num_rows, var_Undef);
1321     for(uint32_t col = 0; col < num_cols; col++) {
1322         uint32_t var = col_to_var[col];
1323         if (var_has_resp_row[var]) {
1324             uint32_t num_ones = 0;
1325             uint32_t found_row = var_Undef;
1326             for(uint32_t row = 0; row < num_rows; row++) {
1327                 if (mat[row][col]) {
1328                     num_ones++;
1329                     found_row = row;
1330                 }
1331             }
1332             if (num_ones == 0) {
1333                 cout
1334                 << "mat[" << matrix_no << "] "
1335                 << "WARNING: Tracked col " << col
1336                 << " var: " << var+1
1337                 << " has 0 rows' bit set to 1..."
1338                 << endl;
1339             }
1340             if (num_ones > 1) {
1341                 cout
1342                 << "mat[" << matrix_no << "] "
1343                 << "ERROR: Tracked col " << col
1344                 << " var: " << var+1
1345                 << " has " << num_ones << " rows' bit set to 1!!"
1346                 << endl;
1347                 assert(num_ones <= 1);
1348             }
1349             if (num_ones == 1) {
1350                 if (row_resp_for_var[found_row] != var_Undef) {
1351                     cout << "ERROR One row can only be responsible for one col"
1352                     << " but row " << found_row << " is responsible for"
1353                     << " var: " << row_resp_for_var[found_row]+1
1354                     << " and var: " << var+1
1355                     << endl;
1356                     assert(false);
1357                 }
1358                 row_resp_for_var[found_row] = var;
1359             }
1360         }
1361     }
1362 }
1363 
check_invariants()1364 void CMSat::EGaussian::check_invariants()
1365 {
1366     check_tracked_cols_only_one_set();
1367     check_no_prop_or_unsat_rows();
1368     #ifdef VERBOSE_DEBUG
1369     cout
1370     << "mat[" << matrix_no << "] "
1371     << "Checked invariants. Dec level: " << solver->decisionLevel() << endl;
1372     #endif
1373 }
1374 
check_row_satisfied(const uint32_t row)1375 bool EGaussian::check_row_satisfied(const uint32_t row)
1376 {
1377     bool ret = true;
1378     bool fin = mat[row].rhs();
1379     for(uint32_t i = 0; i < num_cols; i++) {
1380         if (mat[row][i]) {
1381             uint32_t var = col_to_var[i];
1382             auto val = solver->value(var);
1383             if (val == l_Undef) {
1384                 cout << "Var " << var+1 << " col: " << i << " is undef!" << endl;
1385                 ret = false;
1386             }
1387             fin ^= val == l_True;
1388         }
1389     }
1390     return ret && fin == false;
1391 }
1392 
check_cols_unset_vals()1393 void EGaussian::check_cols_unset_vals()
1394 {
1395     for(uint32_t i = 0; i < num_cols; i ++) {
1396         uint32_t var = col_to_var[i];
1397         if (solver->value(var) == l_Undef) {
1398             assert((*cols_unset)[i] == 1);
1399         } else {
1400             assert((*cols_unset)[i] == 0);
1401         }
1402 
1403         if (solver->value(var) == l_True) {
1404             assert((*cols_vals)[i] == 1);
1405         } else {
1406             assert((*cols_vals)[i] == 0);
1407         }
1408     }
1409 }
1410 
must_disable(GaussQData & gqd)1411 bool EGaussian::must_disable(GaussQData& gqd)
1412 {
1413     gqd.engaus_disable_checks++;
1414     if ((gqd.engaus_disable_checks & 0x3ff) == 0x3ff //only check once in a while
1415     ) {
1416         uint64_t egcalled = elim_called + find_truth_ret_satisfied_precheck+find_truth_called_propgause;
1417         uint32_t limit = (double)egcalled*solver->conf.gaussconf.min_usefulness_cutoff;
1418         uint32_t useful = find_truth_ret_prop+find_truth_ret_confl+elim_ret_prop+elim_ret_confl;
1419         //cout << "CHECKING - limit: " << limit << " useful:" << useful << endl;
1420         if (egcalled > 200 && useful < limit) {
1421             if (solver->conf.verbosity) {
1422                 const double perc =
1423                     stats_line_percent(useful, egcalled);
1424                 cout << "c [g  <" <<  matrix_no <<  "] Disabling GJ-elim in this round. "
1425                 " Usefulness was: "
1426                 << std::setprecision(4) << std::fixed << perc
1427                 <<  "%"
1428                 << std::setprecision(2)
1429                 << "  over " << egcalled << " calls"
1430                 << endl;
1431             }
1432             return true;
1433         }
1434     }
1435 
1436     return false;
1437 }
1438