1 /******************************************
2 Copyright (c) 2016, Mate Soos
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 ***********************************************/
22 
23 #include "hyperengine.h"
24 #include "clauseallocator.h"
25 
26 using namespace CMSat;
27 
HyperEngine(const SolverConf * _conf,Solver * _solver,std::atomic<bool> * _must_interrupt_inter)28 HyperEngine::HyperEngine(
29     const SolverConf *_conf
30     , Solver* _solver
31     , std::atomic<bool>* _must_interrupt_inter) :
32     PropEngine(_conf, _solver, _must_interrupt_inter)
33 {
34 }
35 
36 HyperEngine::~HyperEngine() = default;
37 
propagate_bfs(const uint64_t timeout)38 Lit HyperEngine::propagate_bfs(const uint64_t timeout)
39 {
40     timedOutPropagateFull = false;
41     propStats.otfHyperPropCalled++;
42     #ifdef VERBOSE_DEBUG_FULLPROP
43     cout << "Prop full BFS started" << endl;
44     #endif
45 
46     PropBy confl;
47 
48     //Assert startup: only 1 enqueued, uselessBin is empty
49     assert(uselessBin.empty());
50     //assert(decisionLevel() == 1);
51 
52     //The toplevel decision has to be set specifically
53     //If we came here as part of a backtrack to decision level 1, then
54     //this is already set, and there is no need to set it
55     if (trail.size() - trail_lim.back() == 1) {
56         //Set up root node
57         Lit root = trail[qhead].lit;
58         varData[root.var()].reason = PropBy(~lit_Undef, false, false, false);
59     }
60 
61     uint32_t nlBinQHead = qhead;
62     uint32_t lBinQHead = qhead;
63 
64     needToAddBinClause.clear();
65     PropResult ret = PROP_NOTHING;
66     start:
67 
68     //Early-abort if too much time was used (from prober)
69     if (propStats.otfHyperTime + propStats.bogoProps > timeout) {
70         timedOutPropagateFull = true;
71         return lit_Undef;
72     }
73 
74     //Propagate binary irred
75     while (nlBinQHead < trail.size()) {
76         const Lit p = trail[nlBinQHead++].lit;
77         watch_subarray_const ws = watches[~p];
78         propStats.bogoProps += 1;
79         for(const Watched *k = ws.begin(), *end = ws.end()
80             ; k != end
81             ; k++
82         ) {
83 
84             //If something other than irred binary, skip
85             if (!k->isBin() || k->red())
86                 continue;
87 
88             ret = prop_bin_with_ancestor_info(p, k, confl);
89             if (ret == PROP_FAIL)
90                 return analyzeFail(confl);
91 
92         }
93         propStats.bogoProps += ws.size()*4;
94     }
95 
96     //Propagate binary redundant
97     ret = PROP_NOTHING;
98     while (lBinQHead < trail.size()) {
99         const Lit p = trail[lBinQHead].lit;
100         watch_subarray_const ws = watches[~p];
101         propStats.bogoProps += 1;
102         size_t done = 0;
103 
104         for(const Watched *k = ws.begin(), *end = ws.end(); k != end; k++, done++) {
105 
106             //If something other than redundant binary, skip
107             if (!k->isBin() || !k->red())
108                 continue;
109 
110             ret = prop_bin_with_ancestor_info(p, k, confl);
111             if (ret == PROP_FAIL) {
112                 return analyzeFail(confl);
113             } else if (ret == PROP_SOMETHING) {
114                 propStats.bogoProps += done*4;
115                 goto start;
116             } else {
117                 assert(ret == PROP_NOTHING);
118             }
119         }
120         lBinQHead++;
121         propStats.bogoProps += done*4;
122     }
123 
124     ret = PROP_NOTHING;
125     while (qhead < trail.size()) {
126         const Lit p = trail[qhead].lit;
127         watch_subarray ws = watches[~p];
128         propStats.bogoProps += 1;
129 
130         Watched* i = ws.begin();
131         Watched* j = ws.begin();
132         Watched* end = ws.end();
133         for(; i != end; i++) {
134             if (i->isBin()) {
135                 *j++ = *i;
136                 continue;
137             }
138 
139             if (i->isClause()) {
140                 ret = prop_normal_cl_with_ancestor_info(i, j, p, confl);
141                 if (ret == PROP_SOMETHING || ret == PROP_FAIL) {
142                     i++;
143                     break;
144                 } else {
145                     assert(ret == PROP_NOTHING);
146                     continue;
147                 }
148             }
149         }
150         propStats.bogoProps += ws.size()*4;
151         while(i != end)
152             *j++ = *i++;
153         ws.shrink_(end-j);
154 
155         if (ret == PROP_FAIL) {
156             return analyzeFail(confl);
157         } else if (ret == PROP_SOMETHING) {
158             propStats.bogoProps += ws.size()*4;
159             goto start;
160         }
161 
162         qhead++;
163         propStats.bogoProps += ws.size()*4;
164     }
165 
166     return lit_Undef;
167 }
168 
169 //Add binary clause to deepest common ancestor
add_hyper_bin(const Lit p)170 void HyperEngine::add_hyper_bin(const Lit p)
171 {
172     propStats.otfHyperTime += 2;
173 
174     Lit deepestAncestor = lit_Undef;
175     bool hyperBinNotAdded = true;
176     if (currAncestors.size() > 1) {
177         deepestAncestor = deepest_common_ancestor();
178 
179         #ifdef VERBOSE_DEBUG_FULLPROP
180         cout << "Adding hyper-bin clause: " << p << " , " << ~deepestAncestor << endl;
181         #endif
182         needToAddBinClause.insert(BinaryClause(p, ~deepestAncestor, true));
183         *drat << add << p << (~deepestAncestor)
184         #ifdef STATS_NEEDED
185         << 0
186         << sumConflicts
187         #endif
188         << fin;
189 
190         hyperBinNotAdded = false;
191     } else {
192         //0-level propagation is NEVER made by propFull
193         assert(currAncestors.size() > 0);
194 
195         #ifdef VERBOSE_DEBUG_FULLPROP
196         cout
197         << "Not adding hyper-bin because only ONE lit is not set at"
198         << "level 0 in long clause, but that long clause needs to be cleaned"
199         << endl;
200         #endif
201         deepestAncestor = currAncestors[0];
202         hyperBinNotAdded = true;
203     }
204 
205     enqueue_with_acestor_info(p, deepestAncestor, true);
206     varData[p.var()].reason.setHyperbin(true);
207     varData[p.var()].reason.setHyperbinNotAdded(hyperBinNotAdded);
208 }
209 
210 /**
211 We can try both ways: either binary clause can be removed.
212 Try to remove one, then the other
213 Return which one is to be removed
214 */
remove_which_bin_due_to_trans_red(Lit conflict,Lit thisAncestor,bool thisStepRed)215 Lit HyperEngine::remove_which_bin_due_to_trans_red(
216     Lit conflict
217     , Lit thisAncestor
218     , bool thisStepRed
219 ) {
220     propStats.otfHyperTime += 1;
221     const PropBy& data = varData[conflict.var()].reason;
222 
223     bool onlyIrred = !data.isRedStep();
224     Lit lookingForAncestor = data.getAncestor();
225 
226     if (thisAncestor == lit_Undef || lookingForAncestor == lit_Undef)
227         return lit_Undef;
228 
229     propStats.otfHyperTime += 1;
230     bool second_is_deeper = false;
231     bool ambivalent = true;
232     if (use_depth_trick) {
233         ambivalent = depth[thisAncestor.var()] == depth[lookingForAncestor.var()];
234         if (depth[thisAncestor.var()] < depth[lookingForAncestor.var()]) {
235             second_is_deeper = true;
236         }
237     }
238     #ifdef DEBUG_DEPTH
239     cout
240     << "1st: " << std::setw(6) << thisAncestor
241     << " depth: " << std::setw(4) << depth[thisAncestor.var()]
242     << "  2nd: " << std::setw(6) << lookingForAncestor
243     << " depth: " << std::setw(4) << depth[lookingForAncestor.var()]
244     ;
245     #endif
246 
247 
248     if ((ambivalent || !second_is_deeper) &&
249         is_ancestor_of(
250         conflict
251         , thisAncestor
252         , thisStepRed
253         , onlyIrred
254         , lookingForAncestor
255         )
256     ) {
257         #ifdef DEBUG_DEPTH
258         cout << " -- OK" << endl;
259         #endif
260         //assert(ambivalent || !second_is_deeper);
261         return thisAncestor;
262     }
263 
264     onlyIrred = !thisStepRed;
265     thisStepRed = data.isRedStep();
266     std::swap(lookingForAncestor, thisAncestor);
267     if ((ambivalent || second_is_deeper) &&
268         is_ancestor_of(
269         conflict
270         , thisAncestor
271         , thisStepRed
272         , onlyIrred
273         , lookingForAncestor
274         )
275     ) {
276         #ifdef DEBUG_DEPTH
277         cout << " -- OK" << endl;
278         #endif
279         //assert(ambivalent || second_is_deeper);
280         return thisAncestor;
281     }
282 
283     #ifdef DEBUG_DEPTH
284     cout << " -- NOTK" << endl;
285     #endif
286 
287     return lit_Undef;
288 }
289 
290 /**
291 hop backwards from thisAncestor until:
292 1) we reach ancestor of 'conflict' -- at this point, we return TRUE
293 2) we reach an invalid point. Either root, or an invalid hop. We return FALSE.
294 */
is_ancestor_of(const Lit conflict,Lit thisAncestor,const bool thisStepRed,const bool onlyIrred,const Lit lookingForAncestor)295 bool HyperEngine::is_ancestor_of(
296     const Lit conflict
297     , Lit thisAncestor
298     , const bool thisStepRed
299     , const bool onlyIrred
300     , const Lit lookingForAncestor
301 ) {
302     propStats.otfHyperTime += 1;
303     #ifdef VERBOSE_DEBUG_FULLPROP
304     cout << "is_ancestor_of."
305     << "conflict: " << conflict
306     << " thisAncestor: " << thisAncestor
307     << " thisStepRed: " << thisStepRed
308     << " onlyIrred: " << onlyIrred
309     << " lookingForAncestor: " << lookingForAncestor << endl;
310     #endif
311 
312     //Was propagated at level 0 -- clauseCleaner will remove the clause
313     if (lookingForAncestor == lit_Undef)
314         return false;
315 
316     if (lookingForAncestor == thisAncestor) {
317         #ifdef VERBOSE_DEBUG_FULLPROP
318         cout << "Last position inside prop queue is not saved during propFull" << endl
319         << "This may be the same exact binary clause -- not removing" << endl;
320         #endif
321         return false;
322     }
323 
324     #ifdef VERBOSE_DEBUG_FULLPROP
325     cout << "Looking for ancestor of " << conflict << " : " << lookingForAncestor << endl;
326     cout << "This step based on redundant cl? " << (thisStepRed ? "yes" : "false") << endl;
327     cout << "Only irred is acceptable?" << (onlyIrred ? "yes" : "no") << endl;
328     cout << "This step would be based on redundant cl?" << (thisStepRed ? "yes" : "no") << endl;
329     #endif
330 
331     if (onlyIrred && thisStepRed) {
332         #ifdef VERBOSE_DEBUG_FULLPROP
333         cout << "This step doesn't work -- is redundant but needs irred" << endl;
334         #endif
335         return false;
336     }
337 
338     //This is as low as we should search -- we cannot find what we are searchig for lower than this
339     const size_t bottom = depth[lookingForAncestor.var()];
340 
341     while(thisAncestor != lit_Undef
342         && (!use_depth_trick || bottom <= depth[thisAncestor.var()])
343     ) {
344         #ifdef VERBOSE_DEBUG_FULLPROP
345         cout << "Current acestor: " << thisAncestor
346         << " redundant step? " << varData[thisAncestor.var()].reason.isRedStep()
347         << endl;
348         #endif
349 
350         if (thisAncestor == conflict) {
351             #ifdef VERBOSE_DEBUG_FULLPROP
352             cout << "We are trying to step over the conflict."
353             << " That would create a loop." << endl;
354             #endif
355             return false;
356         }
357 
358         if (thisAncestor == lookingForAncestor) {
359             #ifdef VERBOSE_DEBUG_FULLPROP
360             cout << "Ancestor found" << endl;
361             #endif
362             return true;
363         }
364 
365         const PropBy& data = varData[thisAncestor.var()].reason;
366         if ((onlyIrred && data.isRedStep())
367             || data.getHyperbinNotAdded()
368         ) {
369             #ifdef VERBOSE_DEBUG_FULLPROP
370             cout << "Wrong kind of hop would be needed" << endl;
371             #endif
372             return false;  //reached would-be redundant hop (but this is irred)
373         }
374 
375         thisAncestor = data.getAncestor();
376         propStats.otfHyperTime += 1;
377     }
378 
379     #ifdef VERBOSE_DEBUG_FULLPROP
380     cout << "Exit, reached root" << endl;
381     #endif
382 
383     return false;
384 }
385 
add_hyper_bin(const Lit p,const Clause & cl)386 void HyperEngine::add_hyper_bin(const Lit p, const Clause& cl)
387 {
388     assert(value(p.var()) == l_Undef);
389 
390     #ifdef VERBOSE_DEBUG_FULLPROP
391     cout << "Enqueing " << p
392     << " with ancestor clause: " << cl
393     << endl;
394      #endif
395 
396     currAncestors.clear();
397     size_t i = 0;
398     for (Clause::const_iterator
399         it = cl.begin(), end = cl.end()
400         ; it != end
401         ; ++it, i++
402     ) {
403         if (*it != p) {
404             assert(value(*it) == l_False);
405             if (varData[it->var()].level != 0)
406                 currAncestors.push_back(~*it);
407         }
408     }
409 
410     add_hyper_bin(p);
411 }
412 
413 //Analyze why did we fail at decision level 1
analyzeFail(const PropBy propBy)414 Lit HyperEngine::analyzeFail(const PropBy propBy)
415 {
416     //Clear out the datastructs we will be usin
417     currAncestors.clear();
418 
419     //First, we set the ancestors, based on the clause
420     //Each literal in the clause is an ancestor. So just 'push' them inside the
421     //'currAncestors' variable
422     switch(propBy.getType()) {
423         case binary_t: {
424             const Lit lit = ~propBy.lit2();
425             if (varData[lit.var()].level != 0)
426                 currAncestors.push_back(lit);
427 
428             if (varData[failBinLit.var()].level != 0)
429                 currAncestors.push_back(~failBinLit);
430 
431             break;
432         }
433 
434         case clause_t: {
435             const uint32_t offset = propBy.get_offset();
436             const Clause& cl = *cl_alloc.ptr(offset);
437             for(size_t i = 0; i < cl.size(); i++) {
438                 if (varData[cl[i].var()].level != 0)
439                     currAncestors.push_back(~cl[i]);
440             }
441             break;
442         }
443 
444 #ifdef USE_GAUSS
445         case xor_t:
446 #endif
447         case null_clause_t:
448             assert(false);
449             break;
450     }
451 
452     Lit foundLit = deepest_common_ancestor();
453 
454     return foundLit;
455 }
456 
deepest_common_ancestor()457 Lit HyperEngine::deepest_common_ancestor()
458 {
459     //Then, we go back on each ancestor recursively, and exit on the first one
460     //that unifies ALL the previous ancestors. That is the lowest common ancestor
461     assert(toClear.empty());
462     Lit foundLit = lit_Undef;
463     while(foundLit == lit_Undef) {
464         #ifdef VERBOSE_DEBUG_FULLPROP
465         cout << "LEVEL analyzeFail" << endl;
466         #endif
467         size_t num_lit_undef = 0;
468         for (vector<Lit>::iterator
469             it = currAncestors.begin(), end = currAncestors.end()
470             ; it != end
471             ; ++it
472         ) {
473             propStats.otfHyperTime += 1;
474 
475             //We have reached the top of the graph, the other 'threads' that
476             //are still stepping back will find which literal is the lowest
477             //common ancestor
478             if (*it == lit_Undef) {
479                 #ifdef VERBOSE_DEBUG_FULLPROP
480                 cout << "seen lit_Undef" << endl;
481                 #endif
482                 num_lit_undef++;
483                 assert(num_lit_undef != currAncestors.size());
484                 continue;
485             }
486 
487             //Increase path count
488             seen[it->toInt()]++;
489 
490             //Visited counter has to be cleared later, so add it to the
491             //to-be-cleared set
492             if (seen[it->toInt()] == 1)
493                 toClear.push_back(*it);
494 
495             #ifdef VERBOSE_DEBUG_FULLPROP
496             cout << "seen " << *it << " : " << seen[it->toInt()] << endl;
497             #endif
498 
499             //Is this point where all the 'threads' that are stepping backwards
500             //reach each other? If so, we have found what we were looking for!
501             //We can exit, and return 'foundLit'
502             if (seen[it->toInt()] == currAncestors.size()) {
503                 foundLit = *it;
504                 break;
505             }
506 
507             //Update ancestor to its own ancestor, i.e. step up this 'thread'
508             *it = varData[it->var()].reason.getAncestor();
509         }
510     }
511     #ifdef VERBOSE_DEBUG_FULLPROP
512     cout << "END" << endl;
513     #endif
514     assert(foundLit != lit_Undef);
515 
516     //Clear nodes we have visited
517     propStats.otfHyperTime += toClear.size()/2;
518     for(const Lit lit: toClear) {
519         seen[lit.toInt()] = 0;
520     }
521     toClear.clear();
522 
523     return foundLit;
524 }
525 
remove_bin_clause(Lit lit)526 void HyperEngine::remove_bin_clause(Lit lit)
527 {
528     //The binary clause we should remove
529     const BinaryClause clauseToRemove(
530         ~varData[lit.var()].reason.getAncestor()
531         , lit
532         , varData[lit.var()].reason.isRedStep()
533     );
534 
535     //We now remove the clause
536     //If it's hyper-bin, then we remove the to-be-added hyper-binary clause
537     //However, if the hyper-bin was never added because only 1 literal was unbound at level 0 (i.e. through
538     //clause cleaning, the clause would have been 2-long), then we don't do anything.
539     if (!varData[lit.var()].reason.getHyperbin()) {
540         #ifdef VERBOSE_DEBUG_FULLPROP
541         cout << "Normal removing clause " << clauseToRemove << endl;
542         #endif
543         propStats.otfHyperTime += 2;
544         uselessBin.insert(clauseToRemove);
545     } else if (!varData[lit.var()].reason.getHyperbinNotAdded()) {
546         #ifdef VERBOSE_DEBUG_FULLPROP
547         cout << "Removing hyper-bin clause " << clauseToRemove << endl;
548         #endif
549         propStats.otfHyperTime += needToAddBinClause.size()/4;
550         std::set<BinaryClause>::iterator it = needToAddBinClause.find(clauseToRemove);
551 
552         //In case this is called after a backtrack to decisionLevel 1
553         //then in fact we might have already cleaned the
554         //'needToAddBinClause'. When called from probing, the IF below
555         //must ALWAYS be true
556         if (it != needToAddBinClause.end()) {
557             propStats.otfHyperTime += 2;
558             needToAddBinClause.erase(it);
559         }
560         //This will subsume the clause later, so don't remove it
561     }
562 }
563 
prop_bin_with_ancestor_info(const Lit p,const Watched * k,PropBy & confl)564 PropResult HyperEngine::prop_bin_with_ancestor_info(
565     const Lit p
566     , const Watched* k
567     , PropBy& confl
568 ) {
569     const Lit lit = k->lit2();
570     const lbool val = value(lit);
571     if (val == l_Undef) {
572         //Never propagated before
573         enqueue_with_acestor_info(lit, p, k->red());
574         return PROP_SOMETHING;
575 
576     } else if (val == l_False) {
577         //Conflict
578         #ifdef VERBOSE_DEBUG_FULLPROP
579         cout << "Conflict from " << p << " , " << lit << endl;
580         #endif //VERBOSE_DEBUG_FULLPROP
581 
582         //Update stats
583         if (k->red())
584             lastConflictCausedBy = ConflCausedBy::binred;
585         else
586             lastConflictCausedBy = ConflCausedBy::binirred;
587 
588         failBinLit = lit;
589         confl = PropBy(~p, k->red());
590         return PROP_FAIL;
591 
592     } else if (varData[lit.var()].level != 0 && perform_transitive_reduction) {
593         //Propaged already
594         assert(val == l_True);
595 
596         #ifdef VERBOSE_DEBUG_FULLPROP
597         cout << "Lit " << p << " also wants to propagate " << lit << endl;
598         #endif
599         Lit remove = remove_which_bin_due_to_trans_red(lit, p, k->red());
600 
601         //Remove this one
602         if (remove == p) {
603             Lit origAnc = varData[lit.var()].reason.getAncestor();
604             assert(origAnc != lit_Undef);
605 
606             remove_bin_clause(lit);
607 
608             //Update data indicating what lead to lit
609             varData[lit.var()].reason = PropBy(~p, k->red(), false, false);
610             assert(varData[p.var()].level != 0);
611             depth[lit.var()] = depth[p.var()] + 1;
612             //NOTE: we don't update the levels of other literals... :S
613 
614             //for correctness, we would need this, but that would need re-writing of history :S
615             //if (!onlyIrred) return PropBy();
616 
617         } else if (remove != lit_Undef) {
618             #ifdef VERBOSE_DEBUG_FULLPROP
619             cout << "Removing this bin clause" << endl;
620             #endif
621             propStats.otfHyperTime += 2;
622             uselessBin.insert(BinaryClause(~p, lit, k->red()));
623         }
624     }
625 
626     return PROP_NOTHING;
627 }
628 
629 
prop_normal_cl_with_ancestor_info(Watched * i,Watched * & j,const Lit p,PropBy & confl)630 PropResult HyperEngine::prop_normal_cl_with_ancestor_info(
631     Watched* i
632     , Watched*& j
633     , const Lit p
634     , PropBy& confl
635 ) {
636     //Blocked literal is satisfied, so clause is satisfied
637     if (value(i->getBlockedLit()) == l_True) {
638         *j++ = *i;
639         return PROP_NOTHING;
640     }
641 
642     //Dereference pointer
643     propStats.bogoProps += 4;
644     const ClOffset offset = i->get_offset();
645     Clause& c = *cl_alloc.ptr(offset);
646 
647     PropResult ret = prop_normal_helper(c, offset, j, p);
648     if (ret != PROP_TODO)
649         return ret;
650 
651     // Did not find watch -- clause is unit under assignment:
652     *j++ = *i;
653     if (value(c[0]) == l_False) {
654         return handle_normal_prop_fail(c, offset, confl);
655     }
656 
657     add_hyper_bin(c[0], c);
658 
659     return PROP_SOMETHING;
660 }
661 
mem_used() const662 size_t HyperEngine::mem_used() const
663 {
664     size_t mem = 0;
665     mem += PropEngine::mem_used();
666     mem += currAncestors.capacity()*sizeof(Lit);
667 
668     return mem;
669 }
670 
enqueue_with_acestor_info(const Lit p,const Lit ancestor,const bool redStep)671 void HyperEngine::enqueue_with_acestor_info(
672     const Lit p
673     , const Lit ancestor
674     , const bool redStep
675 ) {
676     //only called at decision level 1 during solving OR
677     //during intree probing
678     enqueue(p, decisionLevel(), PropBy(~ancestor, redStep, false, false));
679 
680     assert(varData[ancestor.var()].level != 0);
681 
682     if (use_depth_trick) {
683         depth[p.var()] = depth[ancestor.var()] + 1;
684     } else {
685         depth[p.var()] = 0;
686     }
687     #if defined(DEBUG_DEPTH) || defined(VERBOSE_DEBUG_FULLPROP)
688     cout
689     << "Enqueued "
690     << std::setw(6) << (p)
691     << " by " << std::setw(6) << (~ancestor)
692     << " at depth " << std::setw(4) << depth[p.var()]
693     << " at dec level: " << decisionLevel()
694     << endl;
695     #endif
696 }
697