Initial checkin of SAT solvers
authorbdemsky <bdemsky@uci.edu>
Thu, 25 Dec 2014 00:52:58 +0000 (16:52 -0800)
committerbdemsky <bdemsky@uci.edu>
Thu, 25 Dec 2014 00:52:58 +0000 (16:52 -0800)
79 files changed:
glucose-syrup/Changelog [new file with mode: 0644]
glucose-syrup/LICENCE [new file with mode: 0644]
glucose-syrup/README [new file with mode: 0644]
glucose-syrup/core/BoundedQueue.h [new file with mode: 0644]
glucose-syrup/core/Constants.h [new file with mode: 0644]
glucose-syrup/core/Dimacs.h [new file with mode: 0644]
glucose-syrup/core/Makefile [new file with mode: 0644]
glucose-syrup/core/Solver.cc [new file with mode: 0644]
glucose-syrup/core/Solver.h [new file with mode: 0644]
glucose-syrup/core/SolverTypes.h [new file with mode: 0644]
glucose-syrup/mtl/Alg.h [new file with mode: 0644]
glucose-syrup/mtl/Alloc.h [new file with mode: 0644]
glucose-syrup/mtl/Clone.h [new file with mode: 0644]
glucose-syrup/mtl/Heap.h [new file with mode: 0644]
glucose-syrup/mtl/IntTypes.h [new file with mode: 0644]
glucose-syrup/mtl/Map.h [new file with mode: 0644]
glucose-syrup/mtl/Queue.h [new file with mode: 0644]
glucose-syrup/mtl/Sort.h [new file with mode: 0644]
glucose-syrup/mtl/Vec.h [new file with mode: 0644]
glucose-syrup/mtl/XAlloc.h [new file with mode: 0644]
glucose-syrup/mtl/config.mk [new file with mode: 0644]
glucose-syrup/mtl/template.mk [new file with mode: 0644]
glucose-syrup/parallel/ClausesBuffer.cc [new file with mode: 0644]
glucose-syrup/parallel/ClausesBuffer.h [new file with mode: 0644]
glucose-syrup/parallel/Main.cc [new file with mode: 0644]
glucose-syrup/parallel/Makefile [new file with mode: 0644]
glucose-syrup/parallel/MultiSolvers.cc [new file with mode: 0644]
glucose-syrup/parallel/MultiSolvers.h [new file with mode: 0644]
glucose-syrup/parallel/ParallelSolver.cc [new file with mode: 0644]
glucose-syrup/parallel/ParallelSolver.h [new file with mode: 0644]
glucose-syrup/parallel/SharedCompanion.cc [new file with mode: 0644]
glucose-syrup/parallel/SharedCompanion.h [new file with mode: 0644]
glucose-syrup/parallel/SolverCompanion.cc [new file with mode: 0644]
glucose-syrup/parallel/SolverCompanion.h [new file with mode: 0644]
glucose-syrup/parallel/SolverConfiguration.cc [new file with mode: 0644]
glucose-syrup/parallel/SolverConfiguration.h [new file with mode: 0644]
glucose-syrup/simp/Main.cc [new file with mode: 0644]
glucose-syrup/simp/Makefile [new file with mode: 0644]
glucose-syrup/simp/SimpSolver.cc [new file with mode: 0644]
glucose-syrup/simp/SimpSolver.h [new file with mode: 0644]
glucose-syrup/utils/Makefile [new file with mode: 0644]
glucose-syrup/utils/Options.cc [new file with mode: 0644]
glucose-syrup/utils/Options.h [new file with mode: 0644]
glucose-syrup/utils/ParseUtils.h [new file with mode: 0644]
glucose-syrup/utils/System.cc [new file with mode: 0644]
glucose-syrup/utils/System.h [new file with mode: 0644]
lingeling/build.sh [new file with mode: 0755]
lingeling/code/COPYING [new file with mode: 0644]
lingeling/code/VERSION [new file with mode: 0644]
lingeling/code/configure.sh [new file with mode: 0755]
lingeling/code/lglbnr.c [new file with mode: 0644]
lingeling/code/lgldimacs.c [new file with mode: 0644]
lingeling/code/lgldimacs.h [new file with mode: 0644]
lingeling/code/lglib.c [new file with mode: 0644]
lingeling/code/lglib.h [new file with mode: 0644]
lingeling/code/lglmain.c [new file with mode: 0644]
lingeling/code/makefile.in [new file with mode: 0644]
lingeling/code/mkconfig.sh [new file with mode: 0755]
lingeling/license.txt [new file with mode: 0644]
lingeling/readme.txt [new file with mode: 0644]
zchaff64/Makefile [new file with mode: 0644]
zchaff64/README [new file with mode: 0644]
zchaff64/SAT.h [new file with mode: 0644]
zchaff64/cnf_stats.cpp [new file with mode: 0644]
zchaff64/run_till_fix.pl [new file with mode: 0755]
zchaff64/sat_solver.cpp [new file with mode: 0644]
zchaff64/zchaff_base.cpp [new file with mode: 0644]
zchaff64/zchaff_base.h [new file with mode: 0644]
zchaff64/zchaff_clsgen.h [new file with mode: 0644]
zchaff64/zchaff_dbase.cpp [new file with mode: 0644]
zchaff64/zchaff_dbase.h [new file with mode: 0644]
zchaff64/zchaff_header.h [new file with mode: 0644]
zchaff64/zchaff_solver.cpp [new file with mode: 0644]
zchaff64/zchaff_solver.h [new file with mode: 0644]
zchaff64/zchaff_utils.cpp [new file with mode: 0644]
zchaff64/zchaff_version.h [new file with mode: 0644]
zchaff64/zchaff_wrapper.wrp [new file with mode: 0644]
zchaff64/zminimal.cpp [new file with mode: 0644]
zchaff64/zverify_df.cpp [new file with mode: 0644]

diff --git a/glucose-syrup/Changelog b/glucose-syrup/Changelog
new file mode 100644 (file)
index 0000000..b894c73
--- /dev/null
@@ -0,0 +1,27 @@
+Version 4.0
+ - Add a Multithread version, called syrup (many glucose ;-)
+   See SAT14 paper: Lazy Clause Exchange Policy for parallel SAT solvers.
+
+ - Can work indepentently in sequential or with many cores
+
+Version 3.0 (2013)
+ - Add incremental features. 
+    See SAT13 paper: Improving Glucose for Incremental SAT Solving with Assumptions: Application to MUS Extraction
+
+ - Add certified UNSAT proof.
+
+Version 2.3 (2012)
+ - Add new restart strategy 
+    See CP12 paper: Refining Restarts Strategies For SAT and UNSAT
+
+ - Add additionnal features to speed the search
+
+Version 2.0 (2011) 
+ - Add additionnal features (freeze potential good clauses for one turn)
+
+ - Based on Minisat 2.2
+
+Version 1.0 (2009)
+ - Based on Minisat 2.0
+    First release of glucose.
+    See ijcai 2009 paper: Predicting Learnt Clauses Quality in Modern SAT Solver
\ No newline at end of file
diff --git a/glucose-syrup/LICENCE b/glucose-syrup/LICENCE
new file mode 100644 (file)
index 0000000..6fa3b63
--- /dev/null
@@ -0,0 +1,47 @@
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/glucose-syrup/README b/glucose-syrup/README
new file mode 100644 (file)
index 0000000..19cd95f
--- /dev/null
@@ -0,0 +1,24 @@
+Directory overview:
+==================
+
+mtl/            Minisat Template Library
+core/           A core version of the solver glucose (no main here)
+simp/           An extended solver with simplification capabilities
+parallel/       A multicore version of glucose
+README
+LICENSE
+Changelog
+
+To build (release version: without assertions, statically linked, etc):
+======================================================================
+Like minisat....
+
+cd { simp | parallel }
+make rs
+
+Usage:
+======
+
+in simp directory:      ./glucose --help
+
+in parallel directory:  ./glucose-syrup --help
\ No newline at end of file
diff --git a/glucose-syrup/core/BoundedQueue.h b/glucose-syrup/core/BoundedQueue.h
new file mode 100644 (file)
index 0000000..5269c9b
--- /dev/null
@@ -0,0 +1,148 @@
+/***************************************************************************************[BoundedQueue.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+
+#ifndef BoundedQueue_h
+#define BoundedQueue_h
+
+#include "mtl/Vec.h"
+
+//=================================================================================================
+
+namespace Glucose {
+
+template <class T>
+class bqueue {
+    vec<T>  elems;
+    int     first;
+       int             last;
+       unsigned long long sumofqueue;
+       int     maxsize;
+       int     queuesize; // Number of current elements (must be < maxsize !)
+       bool expComputed;
+       double exp,value;
+public:
+ bqueue(void) : first(0), last(0), sumofqueue(0), maxsize(0), queuesize(0),expComputed(false) { } 
+       
+       void initSize(int size) {growTo(size);exp = 2.0/(size+1);} // Init size of bounded size queue
+       
+       void push(T x) {
+         expComputed = false;
+               if (queuesize==maxsize) {
+                       assert(last==first); // The queue is full, next value to enter will replace oldest one
+                       sumofqueue -= elems[last];
+                       if ((++last) == maxsize) last = 0;
+               } else 
+                       queuesize++;
+               sumofqueue += x;
+               elems[first] = x;
+               if ((++first) == maxsize) {first = 0;last = 0;}
+       }
+
+       T peek() { assert(queuesize>0); return elems[last]; }
+       void pop() {sumofqueue-=elems[last]; queuesize--; if ((++last) == maxsize) last = 0;}
+       
+       unsigned long long getsum() const {return sumofqueue;}
+       unsigned int getavg() const {return (unsigned int)(sumofqueue/((unsigned long long)queuesize));}
+       int maxSize() const {return maxsize;}
+       double getavgDouble() const {
+         double tmp = 0;
+         for(int i=0;i<elems.size();i++) {
+           tmp+=elems[i];
+         }
+         return tmp/elems.size();
+       }
+       int isvalid() const {return (queuesize==maxsize);}
+       
+       void growTo(int size) {
+               elems.growTo(size); 
+               first=0; maxsize=size; queuesize = 0;last = 0;
+               for(int i=0;i<size;i++) elems[i]=0; 
+       }
+       
+       double getAvgExp() {
+         if(expComputed) return value;
+         double a=exp;
+         value = elems[first];
+         for(int i  = first;i<maxsize;i++) {
+           value+=a*((double)elems[i]);
+           a=a*exp;
+         }
+         for(int i  = 0;i<last;i++) {
+           value+=a*((double)elems[i]);
+           a=a*exp;
+         }
+         value = value*(1-exp)/(1-a);
+         expComputed = true;
+         return value;
+         
+
+       }
+       void fastclear() {first = 0; last = 0; queuesize=0; sumofqueue=0;} // to be called after restarts... Discard the queue
+       
+    int  size(void)    { return queuesize; }
+
+    void clear(bool dealloc = false)   { elems.clear(dealloc); first = 0; maxsize=0; queuesize=0;sumofqueue=0;}
+
+    void copyTo(bqueue &dest) const {
+        dest.last = last;
+        dest.sumofqueue = sumofqueue;
+        dest.maxsize = maxsize;
+        dest.queuesize = queuesize;
+        dest.expComputed = expComputed;
+        dest.exp = exp;
+        dest.value = value;
+        dest.first = first;        
+        elems.copyTo(dest.elems);
+    }
+};
+}
+//=================================================================================================
+
+#endif
diff --git a/glucose-syrup/core/Constants.h b/glucose-syrup/core/Constants.h
new file mode 100644 (file)
index 0000000..259f1b3
--- /dev/null
@@ -0,0 +1,59 @@
+/***************************************************************************************[Constants.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#define DYNAMICNBLEVEL
+#define CONSTANTREMOVECLAUSE
+
+// Constants for clauses reductions
+#define RATIOREMOVECLAUSES 2
+
+
+// Constants for restarts
+#define LOWER_BOUND_FOR_BLOCKING_RESTART 10000
+
diff --git a/glucose-syrup/core/Dimacs.h b/glucose-syrup/core/Dimacs.h
new file mode 100644 (file)
index 0000000..a2065f6
--- /dev/null
@@ -0,0 +1,89 @@
+/****************************************************************************************[Dimacs.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Dimacs_h
+#define Glucose_Dimacs_h
+
+#include <stdio.h>
+
+#include "utils/ParseUtils.h"
+#include "core/SolverTypes.h"
+
+namespace Glucose {
+
+//=================================================================================================
+// DIMACS Parser:
+
+template<class B, class Solver>
+static void readClause(B& in, Solver& S, vec<Lit>& lits) {
+    int     parsed_lit, var;
+    lits.clear();
+    for (;;){
+        parsed_lit = parseInt(in);
+        if (parsed_lit == 0) break;
+        var = abs(parsed_lit)-1;
+        while (var >= S.nVars()) S.newVar();
+        lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) );
+    }
+}
+
+template<class B, class Solver>
+static void parse_DIMACS_main(B& in, Solver& S) {
+    vec<Lit> lits;
+    int vars    = 0;
+    int clauses = 0;
+    int cnt     = 0;
+    for (;;){
+        skipWhitespace(in);
+        if (*in == EOF) break;
+        else if (*in == 'p'){
+            if (eagerMatch(in, "p cnf")){
+                vars    = parseInt(in);
+                clauses = parseInt(in);
+                // SATRACE'06 hack
+                // if (clauses > 4000000)
+                //     S.eliminate(true);
+            }else{
+                printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
+            }
+        } else if (*in == 'c' || *in == 'p')
+            skipLine(in);
+        else{
+            cnt++;
+            readClause(in, S, lits);
+            S.addClause_(lits); }
+    }
+    if (vars != S.nVars())
+        fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of variables.\n");
+    if (cnt  != clauses)
+        fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of clauses.\n");
+}
+
+// Inserts problem into solver.
+//
+template<class Solver>
+static void parse_DIMACS(gzFile input_stream, Solver& S) {
+    StreamBuffer in(input_stream);
+    parse_DIMACS_main(in, S); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/core/Makefile b/glucose-syrup/core/Makefile
new file mode 100644 (file)
index 0000000..14c4e9c
--- /dev/null
@@ -0,0 +1,3 @@
+PHONY:
+       @echo "** Careful ** Since 4.0 you have to use the simp or parallel directory only for typing make"
+
diff --git a/glucose-syrup/core/Solver.cc b/glucose-syrup/core/Solver.cc
new file mode 100644 (file)
index 0000000..8346438
--- /dev/null
@@ -0,0 +1,1708 @@
+/***************************************************************************************[Solver.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include <math.h>
+
+#include "utils/System.h"
+#include "mtl/Sort.h"
+#include "core/Solver.h"
+#include "core/Constants.h"
+
+using namespace Glucose;
+
+//=================================================================================================
+// Options:
+
+static const char* _cat = "CORE";
+static const char* _cr = "CORE -- RESTART";
+static const char* _cred = "CORE -- REDUCE";
+static const char* _cm = "CORE -- MINIMIZE";
+
+
+
+
+static DoubleOption opt_K(_cr, "K", "The constant used to force restart", 0.8, DoubleRange(0, false, 1, false));
+static DoubleOption opt_R(_cr, "R", "The constant used to block restart", 1.4, DoubleRange(1, false, 5, false));
+static IntOption opt_size_lbd_queue(_cr, "szLBDQueue", "The size of moving average for LBD (restarts)", 50, IntRange(10, INT32_MAX));
+static IntOption opt_size_trail_queue(_cr, "szTrailQueue", "The size of moving average for trail (block restarts)", 5000, IntRange(10, INT32_MAX));
+
+static IntOption opt_first_reduce_db(_cred, "firstReduceDB", "The number of conflicts before the first reduce DB", 2000, IntRange(0, INT32_MAX));
+static IntOption opt_inc_reduce_db(_cred, "incReduceDB", "Increment for reduce DB", 300, IntRange(0, INT32_MAX));
+static IntOption opt_spec_inc_reduce_db(_cred, "specialIncReduceDB", "Special increment for reduce DB", 1000, IntRange(0, INT32_MAX));
+static IntOption opt_lb_lbd_frozen_clause(_cred, "minLBDFrozenClause", "Protect clauses if their LBD decrease and is lower than (for one turn)", 30, IntRange(0, INT32_MAX));
+
+static IntOption opt_lb_size_minimzing_clause(_cm, "minSizeMinimizingClause", "The min size required to minimize clause", 30, IntRange(3, INT32_MAX));
+static IntOption opt_lb_lbd_minimzing_clause(_cm, "minLBDMinimizingClause", "The min LBD required to minimize clause", 6, IntRange(3, INT32_MAX));
+
+
+static DoubleOption opt_var_decay(_cat, "var-decay", "The variable activity decay factor (starting point)", 0.8, DoubleRange(0, false, 1, false));
+static DoubleOption opt_max_var_decay(_cat, "max-var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
+static DoubleOption opt_clause_decay(_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
+static DoubleOption opt_random_var_freq(_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
+static DoubleOption opt_random_seed(_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false));
+static IntOption opt_ccmin_mode(_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
+static IntOption opt_phase_saving(_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
+static BoolOption opt_rnd_init_act(_cat, "rnd-init", "Randomize the initial activity", false);
+static DoubleOption opt_garbage_frac(_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
+
+
+//=================================================================================================
+// Constructor/Destructor:
+
+Solver::Solver() :
+
+// Parameters (user settable):
+//
+verbosity(0)
+, showModel(0)
+, K(opt_K)
+, R(opt_R)
+, sizeLBDQueue(opt_size_lbd_queue)
+, sizeTrailQueue(opt_size_trail_queue)
+, firstReduceDB(opt_first_reduce_db)
+, incReduceDB(opt_inc_reduce_db)
+, specialIncReduceDB(opt_spec_inc_reduce_db)
+, lbLBDFrozenClause(opt_lb_lbd_frozen_clause)
+, lbSizeMinimizingClause(opt_lb_size_minimzing_clause)
+, lbLBDMinimizingClause(opt_lb_lbd_minimzing_clause)
+, var_decay(opt_var_decay)
+, max_var_decay(opt_max_var_decay)
+, clause_decay(opt_clause_decay)
+, random_var_freq(opt_random_var_freq)
+, random_seed(opt_random_seed)
+, ccmin_mode(opt_ccmin_mode)
+, phase_saving(opt_phase_saving)
+, rnd_pol(false)
+, rnd_init_act(opt_rnd_init_act)
+, garbage_frac(opt_garbage_frac)
+, certifiedOutput(NULL)
+, certifiedUNSAT(false) // Not in the first parallel version 
+, panicModeLastRemoved(0), panicModeLastRemovedShared(0)
+, useUnaryWatched(false)
+, promoteOneWatchedClause(true)
+// Statistics: (formerly in 'SolverStats')
+//
+, nbPromoted(0)
+, originalClausesSeen(0)
+, sumDecisionLevels(0)
+, nbRemovedClauses(0), nbRemovedUnaryWatchedClauses(0), nbReducedClauses(0), nbDL2(0), nbBin(0), nbUn(0), nbReduceDB(0)
+, solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0), conflictsRestarts(0)
+, nbstopsrestarts(0), nbstopsrestartssame(0), lastblockatrestart(0)
+, dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
+, curRestart(1)
+
+, ok(true)
+, cla_inc(1)
+, var_inc(1)
+, watches(WatcherDeleted(ca))
+, watchesBin(WatcherDeleted(ca))
+, unaryWatches(WatcherDeleted(ca))
+, qhead(0)
+, simpDB_assigns(-1)
+, simpDB_props(0)
+, order_heap(VarOrderLt(activity))
+, progress_estimate(0)
+, remove_satisfied(true)
+, reduceOnSize(false) // 
+, reduceOnSizeSize(12) // Constant to use on size reductions
+,lastLearntClause(CRef_Undef)
+// Resource constraints:
+//
+, conflict_budget(-1)
+, propagation_budget(-1)
+, asynch_interrupt(false)
+, incremental(false)
+, nbVarsInitialFormula(INT32_MAX)
+, totalTime4Sat(0.)
+, totalTime4Unsat(0.)
+, nbSatCalls(0)
+, nbUnsatCalls(0)
+{
+    MYFLAG = 0;
+    // Initialize only first time. Useful for incremental solving (not in // version), useless otherwise
+    // Kept here for simplicity
+    lbdQueue.initSize(sizeLBDQueue);
+    trailQueue.initSize(sizeTrailQueue);
+    sumLBD = 0;
+    nbclausesbeforereduce = firstReduceDB;
+}
+
+//-------------------------------------------------------
+// Special constructor used for cloning solvers
+//-------------------------------------------------------
+
+Solver::Solver(const Solver &s) :
+  verbosity(s.verbosity)
+, showModel(s.showModel)
+, K(s.K)
+, R(s.R)
+, sizeLBDQueue(s.sizeLBDQueue)
+, sizeTrailQueue(s.sizeTrailQueue)
+, firstReduceDB(s.firstReduceDB)
+, incReduceDB(s.incReduceDB)
+, specialIncReduceDB(s.specialIncReduceDB)
+, lbLBDFrozenClause(s.lbLBDFrozenClause)
+, lbSizeMinimizingClause(s.lbSizeMinimizingClause)
+, lbLBDMinimizingClause(s.lbLBDMinimizingClause)
+, var_decay(s.var_decay)
+, max_var_decay(s.max_var_decay)
+, clause_decay(s.clause_decay)
+, random_var_freq(s.random_var_freq)
+, random_seed(s.random_seed)
+, ccmin_mode(s.ccmin_mode)
+, phase_saving(s.phase_saving)
+, rnd_pol(s.rnd_pol)
+, rnd_init_act(s.rnd_init_act)
+, garbage_frac(s.garbage_frac)
+, certifiedOutput(NULL)
+, certifiedUNSAT(false) // Not in the first parallel version 
+, panicModeLastRemoved(s.panicModeLastRemoved), panicModeLastRemovedShared(s.panicModeLastRemovedShared)
+, useUnaryWatched(s.useUnaryWatched)
+, promoteOneWatchedClause(s.promoteOneWatchedClause)
+// Statistics: (formerly in 'SolverStats')
+//
+, nbPromoted(s.nbPromoted)
+, originalClausesSeen(s.originalClausesSeen)
+, sumDecisionLevels(s.sumDecisionLevels)
+, nbRemovedClauses(s.nbRemovedClauses), nbRemovedUnaryWatchedClauses(s.nbRemovedUnaryWatchedClauses)
+, nbReducedClauses(s.nbReducedClauses), nbDL2(s.nbDL2), nbBin(s.nbBin), nbUn(s.nbUn), nbReduceDB(s.nbReduceDB)
+, solves(s.solves), starts(s.starts), decisions(s.decisions), rnd_decisions(s.rnd_decisions)
+, propagations(s.propagations), conflicts(s.conflicts), conflictsRestarts(s.conflictsRestarts)
+, nbstopsrestarts(s.nbstopsrestarts), nbstopsrestartssame(s.nbstopsrestartssame)
+, lastblockatrestart(s.lastblockatrestart)
+, dec_vars(s.dec_vars), clauses_literals(s.clauses_literals)
+, learnts_literals(s.learnts_literals), max_literals(s.max_literals), tot_literals(s.tot_literals)
+, curRestart(s.curRestart)
+
+, ok(true)
+, cla_inc(s.cla_inc)
+, var_inc(s.var_inc)
+, watches(WatcherDeleted(ca))
+, watchesBin(WatcherDeleted(ca))
+, unaryWatches(WatcherDeleted(ca))
+, qhead(s.qhead)
+, simpDB_assigns(s.simpDB_assigns)
+, simpDB_props(s.simpDB_props)
+, order_heap(VarOrderLt(activity))
+, progress_estimate(s.progress_estimate)
+, remove_satisfied(s.remove_satisfied)
+, reduceOnSize(s.reduceOnSize) // 
+, reduceOnSizeSize(s.reduceOnSizeSize) // Constant to use on size reductions
+,lastLearntClause(CRef_Undef)
+// Resource constraints:
+//
+, conflict_budget(s.conflict_budget)
+, propagation_budget(s.propagation_budget)
+, asynch_interrupt(s.asynch_interrupt)
+, incremental(s.incremental)
+, nbVarsInitialFormula(s.nbVarsInitialFormula)
+, totalTime4Sat(s.totalTime4Sat)
+, totalTime4Unsat(s.totalTime4Unsat)
+, nbSatCalls(s.nbSatCalls)
+, nbUnsatCalls(s.nbUnsatCalls)
+{
+    // Copy clauses.
+    s.ca.copyTo(ca);
+    ca.extra_clause_field = s.ca.extra_clause_field;
+
+    // Initialize  other variables
+     MYFLAG = 0;
+    // Initialize only first time. Useful for incremental solving (not in // version), useless otherwise
+    // Kept here for simplicity
+    sumLBD = s.sumLBD;
+    nbclausesbeforereduce = s.nbclausesbeforereduce;
+   
+    // Copy all search vectors
+    s.watches.copyTo(watches);
+    s.watchesBin.copyTo(watchesBin);
+    s.unaryWatches.copyTo(unaryWatches);
+    s.assigns.memCopyTo(assigns);
+    s.vardata.memCopyTo(vardata);
+    s.activity.memCopyTo(activity);
+    s.seen.memCopyTo(seen);
+    s.permDiff.memCopyTo(permDiff);
+    s.polarity.memCopyTo(polarity);
+    s.decision.memCopyTo(decision);
+    s.trail.memCopyTo(trail);
+    s.order_heap.copyTo(order_heap);
+    s.clauses.memCopyTo(clauses);
+    s.learnts.memCopyTo(learnts);
+
+    s.lbdQueue.copyTo(lbdQueue);
+    s.trailQueue.copyTo(trailQueue);
+
+}
+
+Solver::~Solver() {
+}
+
+/****************************************************************
+ Set the incremental mode
+****************************************************************/
+
+// This function set the incremental mode to true.
+// You can add special code for this mode here.
+
+void Solver::setIncrementalMode() {
+  incremental = true;
+}
+
+// Number of variables without selectors
+void Solver::initNbInitialVars(int nb) {
+  nbVarsInitialFormula = nb;
+}
+
+bool Solver::isIncremental() {
+  return incremental;
+}
+
+
+//=================================================================================================
+// Minor methods:
+
+
+// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be
+// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
+//
+
+Var Solver::newVar(bool sign, bool dvar) {
+    int v = nVars();
+    watches .init(mkLit(v, false));
+    watches .init(mkLit(v, true));
+    watchesBin .init(mkLit(v, false));
+    watchesBin .init(mkLit(v, true));
+    unaryWatches .init(mkLit(v, false));
+    unaryWatches .init(mkLit(v, true));
+    assigns .push(l_Undef);
+    vardata .push(mkVarData(CRef_Undef, 0));
+    activity .push(rnd_init_act ? drand(random_seed) * 0.00001 : 0);
+    seen .push(0);
+    permDiff .push(0);
+    polarity .push(sign);
+    decision .push();
+    trail .capacity(v + 1);
+    setDecisionVar(v, dvar);
+    return v;
+}
+
+bool Solver::addClause_(vec<Lit>& ps) {
+
+    assert(decisionLevel() == 0);
+    if (!ok) return false;
+
+    // Check if clause is satisfied and remove false/duplicate literals:
+    sort(ps);
+
+    vec<Lit> oc;
+    oc.clear();
+
+    Lit p;
+    int i, j, flag = 0;
+    if (certifiedUNSAT) {
+        for (i = j = 0, p = lit_Undef; i < ps.size(); i++) {
+            oc.push(ps[i]);
+            if (value(ps[i]) == l_True || ps[i] == ~p || value(ps[i]) == l_False)
+                flag = 1;
+        }
+    }
+
+    for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
+        if (value(ps[i]) == l_True || ps[i] == ~p)
+            return true;
+        else if (value(ps[i]) != l_False && ps[i] != p)
+            ps[j++] = p = ps[i];
+    ps.shrink(i - j);
+
+    if (flag && (certifiedUNSAT)) {
+        for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
+            fprintf(certifiedOutput, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1));
+        fprintf(certifiedOutput, "0\n");
+
+        fprintf(certifiedOutput, "d ");
+        for (i = j = 0, p = lit_Undef; i < oc.size(); i++)
+            fprintf(certifiedOutput, "%i ", (var(oc[i]) + 1) * (-2 * sign(oc[i]) + 1));
+        fprintf(certifiedOutput, "0\n");
+    }
+
+
+    if (ps.size() == 0)
+        return ok = false;
+    else if (ps.size() == 1) {
+        uncheckedEnqueue(ps[0]);
+        return ok = (propagate() == CRef_Undef);
+    } else {
+        CRef cr = ca.alloc(ps, false);
+        clauses.push(cr);
+        attachClause(cr);
+    }
+
+    return true;
+}
+
+void Solver::attachClause(CRef cr) {
+    const Clause& c = ca[cr];
+
+    assert(c.size() > 1);
+    if (c.size() == 2) {
+        watchesBin[~c[0]].push(Watcher(cr, c[1]));
+        watchesBin[~c[1]].push(Watcher(cr, c[0]));
+    } else {
+        watches[~c[0]].push(Watcher(cr, c[1]));
+        watches[~c[1]].push(Watcher(cr, c[0]));
+    }
+    if (c.learnt()) learnts_literals += c.size();
+    else clauses_literals += c.size();
+}
+
+void Solver::attachClausePurgatory(CRef cr) {
+    const Clause& c = ca[cr];
+
+    assert(c.size() > 1);
+    unaryWatches[~c[0]].push(Watcher(cr, c[1]));
+
+}
+
+void Solver::detachClause(CRef cr, bool strict) {
+    const Clause& c = ca[cr];
+
+    assert(c.size() > 1);
+    if (c.size() == 2) {
+        if (strict) {
+            remove(watchesBin[~c[0]], Watcher(cr, c[1]));
+            remove(watchesBin[~c[1]], Watcher(cr, c[0]));
+        } else {
+            // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
+            watchesBin.smudge(~c[0]);
+            watchesBin.smudge(~c[1]);
+        }
+    } else {
+        if (strict) {
+            remove(watches[~c[0]], Watcher(cr, c[1]));
+            remove(watches[~c[1]], Watcher(cr, c[0]));
+        } else {
+            // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
+            watches.smudge(~c[0]);
+            watches.smudge(~c[1]);
+        }
+    }
+    if (c.learnt()) learnts_literals -= c.size();
+    else clauses_literals -= c.size();
+}
+
+
+// The purgatory is the 1-Watched scheme for imported clauses
+
+void Solver::detachClausePurgatory(CRef cr, bool strict) {
+    const Clause& c = ca[cr];
+
+    assert(c.size() > 1);
+    if (strict)
+        remove(unaryWatches[~c[0]], Watcher(cr, c[1]));
+    else
+        unaryWatches.smudge(~c[0]);
+}
+
+void Solver::removeClause(CRef cr, bool inPurgatory) {
+
+    Clause& c = ca[cr];
+
+    if (certifiedUNSAT) {
+        fprintf(certifiedOutput, "d ");
+        for (int i = 0; i < c.size(); i++)
+            fprintf(certifiedOutput, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
+        fprintf(certifiedOutput, "0\n");
+    }
+
+    if (inPurgatory)
+        detachClausePurgatory(cr);
+    else
+        detachClause(cr);
+    // Don't leave pointers to free'd memory!
+    if (locked(c)) vardata[var(c[0])].reason = CRef_Undef;
+    c.mark(1);
+    ca.free(cr);
+}
+
+bool Solver::satisfied(const Clause& c) const {
+    if(incremental)     
+        return (value(c[0]) == l_True) || (value(c[1]) == l_True);
+    
+    // Default mode
+    for (int i = 0; i < c.size(); i++)
+        if (value(c[i]) == l_True)
+            return true;
+    return false;
+}
+
+/************************************************************
+ * Compute LBD functions
+ *************************************************************/
+
+inline unsigned int Solver::computeLBD(const vec<Lit> & lits,int end) {
+  int nblevels = 0;
+  MYFLAG++;
+
+  if(incremental) { // ----------------- INCREMENTAL MODE
+    if(end==-1) end = lits.size();
+    int nbDone = 0;
+    for(int i=0;i<lits.size();i++) {
+      if(nbDone>=end) break;
+      if(isSelector(var(lits[i]))) continue;
+      nbDone++;
+      int l = level(var(lits[i]));
+      if (permDiff[l] != MYFLAG) {
+       permDiff[l] = MYFLAG;
+       nblevels++;
+      }
+    }
+  } else { // -------- DEFAULT MODE. NOT A LOT OF DIFFERENCES... BUT EASIER TO READ
+    for(int i=0;i<lits.size();i++) {
+      int l = level(var(lits[i]));
+      if (permDiff[l] != MYFLAG) {
+       permDiff[l] = MYFLAG;
+       nblevels++;
+      }
+    }
+  }
+
+  if (!reduceOnSize)
+    return nblevels;
+  if (lits.size() < reduceOnSizeSize) return lits.size(); // See the XMinisat paper
+    return lits.size() + nblevels;
+}
+
+inline unsigned int Solver::computeLBD(const Clause &c) {
+  int nblevels = 0;
+  MYFLAG++;
+
+  if(incremental) { // ----------------- INCREMENTAL MODE
+     unsigned int nbDone = 0;
+    for(int i=0;i<c.size();i++) {
+      if(nbDone>=c.sizeWithoutSelectors()) break;
+      if(isSelector(var(c[i]))) continue;
+      nbDone++;
+      int l = level(var(c[i]));
+      if (permDiff[l] != MYFLAG) {
+       permDiff[l] = MYFLAG;
+       nblevels++;
+      }
+    }
+  } else { // -------- DEFAULT MODE. NOT A LOT OF DIFFERENCES... BUT EASIER TO READ
+    for(int i=0;i<c.size();i++) {
+      int l = level(var(c[i]));
+      if (permDiff[l] != MYFLAG) {
+       permDiff[l] = MYFLAG;
+       nblevels++;
+      }
+    }
+  }
+  
+  if (!reduceOnSize)
+    return nblevels;
+  if (c.size() < reduceOnSizeSize) return c.size(); // See the XMinisat paper
+    return c.size() + nblevels;
+
+}
+
+/******************************************************************
+ * Minimisation with binary reolution
+ ******************************************************************/
+void Solver::minimisationWithBinaryResolution(vec<Lit> &out_learnt) {
+
+    // Find the LBD measure                                                                                                         
+    unsigned int lbd = computeLBD(out_learnt);
+    Lit p = ~out_learnt[0];
+
+    if (lbd <= lbLBDMinimizingClause) {
+        MYFLAG++;
+
+        for (int i = 1; i < out_learnt.size(); i++) {
+            permDiff[var(out_learnt[i])] = MYFLAG;
+        }
+
+        vec<Watcher>& wbin = watchesBin[p];
+        int nb = 0;
+        for (int k = 0; k < wbin.size(); k++) {
+            Lit imp = wbin[k].blocker;
+            if (permDiff[var(imp)] == MYFLAG && value(imp) == l_True) {
+                nb++;
+                permDiff[var(imp)] = MYFLAG - 1;
+            }
+        }
+        int l = out_learnt.size() - 1;
+        if (nb > 0) {
+            nbReducedClauses++;
+            for (int i = 1; i < out_learnt.size() - nb; i++) {
+                if (permDiff[var(out_learnt[i])] != MYFLAG) {
+                    Lit p = out_learnt[l];
+                    out_learnt[l] = out_learnt[i];
+                    out_learnt[i] = p;
+                    l--;
+                    i--;
+                }
+            }
+
+            out_learnt.shrink(nb);
+
+        }
+    }
+}
+
+// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
+//
+
+void Solver::cancelUntil(int level) {
+    if (decisionLevel() > level) {
+        for (int c = trail.size() - 1; c >= trail_lim[level]; c--) {
+            Var x = var(trail[c]);
+            assigns [x] = l_Undef;
+            if (phase_saving > 1 || ((phase_saving == 1) && c > trail_lim.last())) {
+                polarity[x] = sign(trail[c]);
+            }
+            insertVarOrder(x);
+        }
+        qhead = trail_lim[level];
+        trail.shrink(trail.size() - trail_lim[level]);
+        trail_lim.shrink(trail_lim.size() - level);
+    }
+}
+
+
+//=================================================================================================
+// Major methods:
+
+Lit Solver::pickBranchLit() {
+    Var next = var_Undef;
+
+    // Random decision:
+    if (drand(random_seed) < random_var_freq && !order_heap.empty()) {
+        next = order_heap[irand(random_seed, order_heap.size())];
+        if (value(next) == l_Undef && decision[next])
+            rnd_decisions++;
+    }
+
+    // Activity based decision:
+    while (next == var_Undef || value(next) != l_Undef || !decision[next])
+        if (order_heap.empty()) {
+            next = var_Undef;
+            break;
+        } else {
+            next = order_heap.removeMin();
+        }
+
+    return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]);
+}
+
+/*_________________________________________________________________________________________________
+|
+|  analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&)  ->  [void]
+|  
+|  Description:
+|    Analyze conflict and produce a reason clause.
+|  
+|    Pre-conditions:
+|      * 'out_learnt' is assumed to be cleared.
+|      * Current decision level must be greater than root level.
+|  
+|    Post-conditions:
+|      * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
+|      * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the 
+|        rest of literals. There may be others from the same level though.
+|  
+|________________________________________________________________________________________________@*/
+void Solver::analyze(CRef confl, vec<Lit>& out_learnt,vec<Lit>&selectors, int& out_btlevel,unsigned int &lbd,unsigned int &szWithoutSelectors) {
+    int pathC = 0;
+    Lit p = lit_Undef;
+
+
+    // Generate conflict clause:
+    //
+    out_learnt.push(); // (leave room for the asserting literal)
+    int index = trail.size() - 1;
+    do {
+        assert(confl != CRef_Undef); // (otherwise should be UIP)
+        Clause& c = ca[confl];
+        // Special case for binary clauses
+        // The first one has to be SAT
+        if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False) {
+
+            assert(value(c[1]) == l_True);
+            Lit tmp = c[0];
+            c[0] = c[1], c[1] = tmp;
+        }
+
+        if (c.learnt()) {
+            parallelImportClauseDuringConflictAnalysis(c,confl);
+            claBumpActivity(c);
+         } else { // original clause
+            if (!c.getSeen()) {
+                originalClausesSeen++;
+                c.setSeen(true);
+            }
+        }
+
+        // DYNAMIC NBLEVEL trick (see competition'09 companion paper)
+        if (c.learnt() && c.lbd() > 2) {
+            unsigned int nblevels = computeLBD(c);
+            if (nblevels + 1 < c.lbd()) { // improve the LBD
+                if (c.lbd() <= lbLBDFrozenClause) {
+                    c.setCanBeDel(false);
+                }
+                // seems to be interesting : keep it for the next round
+                c.setLBD(nblevels); // Update it
+            }
+        }
+
+
+        for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++) {
+            Lit q = c[j];
+
+            if (!seen[var(q)]) {
+                if (level(var(q)) == 0) {
+                } else { // Here, the old case 
+                    if(!isSelector(var(q)))
+                        varBumpActivity(var(q));
+                    seen[var(q)] = 1;
+                    if (level(var(q)) >= decisionLevel()) {
+                        pathC++;
+                        // UPDATEVARACTIVITY trick (see competition'09 companion paper)
+                        if (!isSelector(var(q)) &&  (reason(var(q)) != CRef_Undef) && ca[reason(var(q))].learnt())
+                            lastDecisionLevel.push(q);
+                    } else {
+                        if(isSelector(var(q))) {
+                            assert(value(q) == l_False);
+                            selectors.push(q);
+                        } else 
+                            out_learnt.push(q);
+                   }
+                }
+            }
+        }
+
+        // Select next clause to look at:
+        while (!seen[var(trail[index--])]);
+        p = trail[index + 1];
+        confl = reason(var(p));
+        seen[var(p)] = 0;
+        pathC--;
+
+    } while (pathC > 0);
+    out_learnt[0] = ~p;
+
+    // Simplify conflict clause:
+    //
+    int i, j;
+
+    for (int i = 0; i < selectors.size(); i++)
+        out_learnt.push(selectors[i]);
+
+    out_learnt.copyTo(analyze_toclear);
+    if (ccmin_mode == 2) {
+        uint32_t abstract_level = 0;
+        for (i = 1; i < out_learnt.size(); i++)
+            abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
+
+        for (i = j = 1; i < out_learnt.size(); i++)
+            if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level))
+                out_learnt[j++] = out_learnt[i];
+
+    } else if (ccmin_mode == 1) {
+        for (i = j = 1; i < out_learnt.size(); i++) {
+            Var x = var(out_learnt[i]);
+
+            if (reason(x) == CRef_Undef)
+                out_learnt[j++] = out_learnt[i];
+            else {
+                Clause& c = ca[reason(var(out_learnt[i]))];
+                // Thanks to Siert Wieringa for this bug fix!
+                for (int k = ((c.size() == 2) ? 0 : 1); k < c.size(); k++)
+                    if (!seen[var(c[k])] && level(var(c[k])) > 0) {
+                        out_learnt[j++] = out_learnt[i];
+                        break;
+                    }
+            }
+        }
+    } else
+        i = j = out_learnt.size();
+
+    max_literals += out_learnt.size();
+    out_learnt.shrink(i - j);
+    tot_literals += out_learnt.size();
+
+
+    /* ***************************************
+      Minimisation with binary clauses of the asserting clause
+      First of all : we look for small clauses
+      Then, we reduce clauses with small LBD.
+      Otherwise, this can be useless
+     */
+    if (!incremental && out_learnt.size() <= lbSizeMinimizingClause) {
+        minimisationWithBinaryResolution(out_learnt);
+    }
+    // Find correct backtrack level:
+    //
+    if (out_learnt.size() == 1)
+        out_btlevel = 0;
+    else {
+        int max_i = 1;
+        // Find the first literal assigned at the next-highest level:
+        for (int i = 2; i < out_learnt.size(); i++)
+            if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
+                max_i = i;
+        // Swap-in this literal at index 1:
+        Lit p = out_learnt[max_i];
+        out_learnt[max_i] = out_learnt[1];
+        out_learnt[1] = p;
+        out_btlevel = level(var(p));
+    }
+   if(incremental) {
+      szWithoutSelectors = 0;
+      for(int i=0;i<out_learnt.size();i++) {
+       if(!isSelector(var((out_learnt[i])))) szWithoutSelectors++; 
+       else if(i>0) break;
+      }
+    } else 
+      szWithoutSelectors = out_learnt.size();
+    
+    // Compute LBD
+    lbd = computeLBD(out_learnt,out_learnt.size()-selectors.size());
+     
+    // UPDATEVARACTIVITY trick (see competition'09 companion paper)
+    if (lastDecisionLevel.size() > 0) {
+        for (int i = 0; i < lastDecisionLevel.size(); i++) {
+            if (ca[reason(var(lastDecisionLevel[i]))].lbd() < lbd)
+                varBumpActivity(var(lastDecisionLevel[i]));
+        }
+        lastDecisionLevel.clear();
+    }
+
+
+
+    for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared)
+    for (int j = 0; j < selectors.size(); j++) seen[var(selectors[j])] = 0;
+}
+
+
+// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is
+// visiting literals at levels that cannot be removed later.
+
+bool Solver::litRedundant(Lit p, uint32_t abstract_levels) {
+    analyze_stack.clear();
+    analyze_stack.push(p);
+    int top = analyze_toclear.size();
+    while (analyze_stack.size() > 0) {
+        assert(reason(var(analyze_stack.last())) != CRef_Undef);
+        Clause& c = ca[reason(var(analyze_stack.last()))];
+        analyze_stack.pop(); // 
+        if (c.size() == 2 && value(c[0]) == l_False) {
+            assert(value(c[1]) == l_True);
+            Lit tmp = c[0];
+            c[0] = c[1], c[1] = tmp;
+        }
+
+        for (int i = 1; i < c.size(); i++) {
+            Lit p = c[i];
+            if (!seen[var(p)]) {
+                if (level(var(p)) > 0) {
+                    if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0) {
+                        seen[var(p)] = 1;
+                        analyze_stack.push(p);
+                        analyze_toclear.push(p);
+                    } else {
+                        for (int j = top; j < analyze_toclear.size(); j++)
+                            seen[var(analyze_toclear[j])] = 0;
+                        analyze_toclear.shrink(analyze_toclear.size() - top);
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  analyzeFinal : (p : Lit)  ->  [void]
+|  
+|  Description:
+|    Specialized analysis procedure to express the final conflict in terms of assumptions.
+|    Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
+|    stores the result in 'out_conflict'.
+|________________________________________________________________________________________________@*/
+void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) {
+    out_conflict.clear();
+    out_conflict.push(p);
+
+    if (decisionLevel() == 0)
+        return;
+
+    seen[var(p)] = 1;
+
+    for (int i = trail.size() - 1; i >= trail_lim[0]; i--) {
+        Var x = var(trail[i]);
+        if (seen[x]) {
+            if (reason(x) == CRef_Undef) {
+                assert(level(x) > 0);
+                out_conflict.push(~trail[i]);
+            } else {
+                Clause& c = ca[reason(x)];
+                //                for (int j = 1; j < c.size(); j++) Minisat (glucose 2.0) loop 
+                // Bug in case of assumptions due to special data structures for Binary.
+                // Many thanks to Sam Bayless (sbayless@cs.ubc.ca) for discover this bug.
+                for (int j = ((c.size() == 2) ? 0 : 1); j < c.size(); j++)
+                    if (level(var(c[j])) > 0)
+                        seen[var(c[j])] = 1;
+            }
+
+            seen[x] = 0;
+        }
+    }
+
+    seen[var(p)] = 0;
+}
+
+void Solver::uncheckedEnqueue(Lit p, CRef from) {
+    assert(value(p) == l_Undef);
+    assigns[var(p)] = lbool(!sign(p));
+    vardata[var(p)] = mkVarData(from, decisionLevel());
+    trail.push_(p);
+}
+
+/*_________________________________________________________________________________________________
+|
+|  propagate : [void]  ->  [Clause*]
+|  
+|  Description:
+|    Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
+|    otherwise CRef_Undef.
+|  
+|    Post-conditions:
+|      * the propagation queue is empty, even if there was a conflict.
+|________________________________________________________________________________________________@*/
+CRef Solver::propagate() {
+    CRef confl = CRef_Undef;
+    int num_props = 0;
+    int previousqhead = qhead;
+    watches.cleanAll();
+    watchesBin.cleanAll();
+    unaryWatches.cleanAll();
+    while (qhead < trail.size()) {
+        Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
+        vec<Watcher>& ws = watches[p];
+        Watcher *i, *j, *end;
+        num_props++;
+
+
+        // First, Propagate binary clauses 
+        vec<Watcher>& wbin = watchesBin[p];
+
+        for (int k = 0; k < wbin.size(); k++) {
+
+            Lit imp = wbin[k].blocker;
+
+            if (value(imp) == l_False) {
+                return wbin[k].cref;
+            }
+
+            if (value(imp) == l_Undef) {
+                uncheckedEnqueue(imp, wbin[k].cref);
+            }
+        }
+
+        // Now propagate other 2-watched clauses
+        for (i = j = (Watcher*) ws, end = i + ws.size(); i != end;) {
+            // Try to avoid inspecting the clause:
+            Lit blocker = i->blocker;
+            if (value(blocker) == l_True) {
+                *j++ = *i++;
+                continue;
+            }
+
+            // Make sure the false literal is data[1]:
+            CRef cr = i->cref;
+            Clause& c = ca[cr];
+            assert(!c.getOneWatched());
+            Lit false_lit = ~p;
+            if (c[0] == false_lit)
+                c[0] = c[1], c[1] = false_lit;
+            assert(c[1] == false_lit);
+            i++;
+
+            // If 0th watch is true, then clause is already satisfied.
+            Lit first = c[0];
+            Watcher w = Watcher(cr, first);
+            if (first != blocker && value(first) == l_True) {
+
+                *j++ = w;
+                continue;
+            }
+           if(incremental) { // ----------------- INCREMENTAL MODE
+             int choosenPos = -1;
+             for (int k = 2; k < c.size(); k++) {
+               
+               if (value(c[k]) != l_False){
+                 if(decisionLevel()>assumptions.size()) {
+                   choosenPos = k;
+                   break;
+                 } else {
+                   choosenPos = k;
+                   
+                   if(value(c[k])==l_True || !isSelector(var(c[k]))) {
+                     break;
+                   }
+                 }
+
+               }
+             }
+             if(choosenPos!=-1) {
+               c[1] = c[choosenPos]; c[choosenPos] = false_lit;
+               watches[~c[1]].push(w);
+               goto NextClause; }
+           } else {  // ----------------- DEFAULT  MODE (NOT INCREMENTAL)
+             for (int k = 2; k < c.size(); k++) {
+               
+               if (value(c[k]) != l_False){
+                 c[1] = c[k]; c[k] = false_lit;
+                 watches[~c[1]].push(w);
+                 goto NextClause; }
+             }
+           }
+            
+            // Did not find watch -- clause is unit under assignment:
+            *j++ = w;
+            if (value(first) == l_False) {
+                confl = cr;
+                qhead = trail.size();
+                // Copy the remaining watches:
+                while (i < end)
+                    *j++ = *i++;
+            } else {
+                uncheckedEnqueue(first, cr);
+
+
+            }
+NextClause:
+            ;
+        }
+        ws.shrink(i - j);
+
+       // unaryWatches "propagation"
+        if (useUnaryWatched &&  confl == CRef_Undef) {
+            confl = propagateUnaryWatches(p);
+
+        }
+    }
+
+        
+
+    propagations += num_props;
+    simpDB_props -= num_props;
+
+    return confl;
+}
+
+/*_________________________________________________________________________________________________
+|
+|  propagateUnaryWatches : [Lit]  ->  [Clause*]
+|  
+|  Description:
+|    Propagates unary watches of Lit p, return a conflict 
+|    otherwise CRef_Undef
+|  
+|________________________________________________________________________________________________@*/
+
+CRef Solver::propagateUnaryWatches(Lit p) {
+    CRef confl= CRef_Undef;
+    Watcher *i, *j, *end;
+    vec<Watcher>& ws = unaryWatches[p];
+    for (i = j = (Watcher*) ws, end = i + ws.size(); i != end;) {
+        // Try to avoid inspecting the clause:
+        Lit blocker = i->blocker;
+        if (value(blocker) == l_True) {
+            *j++ = *i++;
+            continue;
+        }
+
+        // Make sure the false literal is data[1]:
+        CRef cr = i->cref;
+        Clause& c = ca[cr];
+        assert(c.getOneWatched());
+        Lit false_lit = ~p;
+        assert(c[0] == false_lit); // this is unary watch... No other choice if "propagated"
+        //if (c[0] == false_lit)
+        //c[0] = c[1], c[1] = false_lit;
+        //assert(c[1] == false_lit);
+        i++;
+        Watcher w = Watcher(cr, c[0]);
+        for (int k = 1; k < c.size(); k++) {
+            if (value(c[k]) != l_False) {
+                c[0] = c[k];
+                c[k] = false_lit;
+                unaryWatches[~c[0]].push(w);
+                goto NextClauseUnary;
+            }
+        }
+
+        // Did not find watch -- clause is empty under assignment:
+        *j++ = w;
+
+        confl = cr;
+        qhead = trail.size();
+        // Copy the remaining watches:
+        while (i < end)
+            *j++ = *i++;
+
+        // We can add it now to the set of clauses when backtracking
+        //printf("*");
+        if (promoteOneWatchedClause) {
+            nbPromoted++;
+            // Let's find the two biggest decision levels in the clause s.t. it will correctly be propagated when we'll backtrack
+            int maxlevel = -1;
+            int index = -1;
+            for (int k = 1; k < c.size(); k++) {
+                assert(value(c[k]) == l_False);
+                assert(level(var(c[k])) <= level(var(c[0])));
+                if (level(var(c[k])) > maxlevel) {
+                    index = k;
+                    maxlevel = level(var(c[k]));
+                }
+            }
+            detachClausePurgatory(cr, true); // TODO: check that the cleanAll is ok (use ",true" otherwise)
+            assert(index != -1);
+            Lit tmp = c[1];
+            c[1] = c[index], c[index] = tmp;
+            attachClause(cr);
+            // TODO used in function ParallelSolver::reportProgressArrayImports 
+            //Override :-(
+            //goodImportsFromThreads[ca[cr].importedFrom()]++;
+            ca[cr].setOneWatched(false);
+            ca[cr].setExported(2);  
+        }
+NextClauseUnary:
+        ;
+    }
+    ws.shrink(i - j);
+
+    return confl;
+}
+
+/*_________________________________________________________________________________________________
+|
+|  reduceDB : ()  ->  [void]
+|  
+|  Description:
+|    Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
+|    clauses are clauses that are reason to some assignment. Binary clauses are never removed.
+|________________________________________________________________________________________________@*/
+
+
+void Solver::reduceDB()
+{
+  int     i, j;
+  nbReduceDB++;
+  sort(learnts, reduceDB_lt(ca));
+
+  // We have a lot of "good" clauses, it is difficult to compare them. Keep more !
+  if(ca[learnts[learnts.size() / RATIOREMOVECLAUSES]].lbd()<=3) nbclausesbeforereduce +=specialIncReduceDB; 
+  // Useless :-)
+  if(ca[learnts.last()].lbd()<=5)  nbclausesbeforereduce +=specialIncReduceDB; 
+  
+  
+  // Don't delete binary or locked clauses. From the rest, delete clauses from the first half
+  // Keep clauses which seem to be usefull (their lbd was reduce during this sequence)
+
+  int limit = learnts.size() / 2;
+
+  for (i = j = 0; i < learnts.size(); i++){
+    Clause& c = ca[learnts[i]];
+    if (c.lbd()>2 && c.size() > 2 && c.canBeDel() &&  !locked(c) && (i < limit)) {
+      removeClause(learnts[i]);
+      nbRemovedClauses++;
+    }
+    else {
+      if(!c.canBeDel()) limit++; //we keep c, so we can delete an other clause
+      c.setCanBeDel(true);       // At the next step, c can be delete
+      learnts[j++] = learnts[i];
+    }
+  }
+  learnts.shrink(i - j);
+  checkGarbage();
+}
+
+
+void Solver::removeSatisfied(vec<CRef>& cs) {
+
+    int i, j;
+    for (i = j = 0; i < cs.size(); i++) {
+        Clause& c = ca[cs[i]];
+
+
+        if (satisfied(c))
+            if (c.getOneWatched())
+                removeClause(cs[i], true);
+            else
+                removeClause(cs[i]);
+        else
+            cs[j++] = cs[i];
+    }
+    cs.shrink(i - j);
+}
+
+void Solver::rebuildOrderHeap() {
+    vec<Var> vs;
+    for (Var v = 0; v < nVars(); v++)
+        if (decision[v] && value(v) == l_Undef)
+            vs.push(v);
+    order_heap.build(vs);
+
+}
+
+/*_________________________________________________________________________________________________
+|
+|  simplify : [void]  ->  [bool]
+|  
+|  Description:
+|    Simplify the clause database according to the current top-level assigment. Currently, the only
+|    thing done here is the removal of satisfied clauses, but more things can be put here.
+|________________________________________________________________________________________________@*/
+bool Solver::simplify() {
+    assert(decisionLevel() == 0);
+
+    if (!ok) return ok = false;
+    else {
+        CRef cr = propagate();
+        if (cr != CRef_Undef) {
+            return ok = false;
+        }
+    }
+
+
+    if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
+        return true;
+
+    // Remove satisfied clauses:
+    removeSatisfied(learnts);
+    removeSatisfied(unaryWatchedClauses);
+    if (remove_satisfied) // Can be turned off.
+        removeSatisfied(clauses);
+    checkGarbage();
+    rebuildOrderHeap();
+
+    simpDB_assigns = nAssigns();
+    simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
+
+    return true;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  search : (nof_conflicts : int) (params : const SearchParams&)  ->  [lbool]
+|  
+|  Description:
+|    Search for a model the specified number of conflicts. 
+|    NOTE! Use negative value for 'nof_conflicts' indicate infinity.
+|  
+|  Output:
+|    'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
+|    all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
+|    if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
+|________________________________________________________________________________________________@*/
+lbool Solver::search(int nof_conflicts) {
+    assert(ok);
+    int backtrack_level;
+    int conflictC = 0;
+    vec<Lit> learnt_clause, selectors;
+    unsigned int nblevels,szWithoutSelectors = 0;
+    bool blocked = false;
+    starts++;
+    for (;;) {
+        if (decisionLevel() == 0) { // We import clauses FIXME: ensure that we will import clauses enventually (restart after some point)
+            parallelImportUnaryClauses();
+            
+            if (parallelImportClauses())
+                return l_False;
+
+        }
+        CRef confl = propagate();
+
+        if (confl != CRef_Undef) {
+            if(parallelJobIsFinished())
+                return l_Undef;
+            
+            
+            sumDecisionLevels += decisionLevel();
+            // CONFLICT
+            conflicts++;
+            conflictC++;
+            conflictsRestarts++;
+           if (conflicts % 5000 == 0 && var_decay < max_var_decay)
+                var_decay += 0.01;
+
+            if (verbosity >= 1 && conflicts % verbEveryConflicts == 0) {
+                printf("c | %8d   %7d    %5d | %7d %8d %8d | %5d %8d   %6d %8d | %6.3f %% |\n",
+                        (int) starts, (int) nbstopsrestarts, (int) (conflicts / starts),
+                        (int) dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int) clauses_literals,
+                        (int) nbReduceDB, nLearnts(), (int) nbDL2, (int) nbRemovedClauses, progressEstimate()*100);
+            }
+            if (decisionLevel() == 0) {
+                return l_False;
+
+            }
+
+            trailQueue.push(trail.size());
+            // BLOCK RESTART (CP 2012 paper)
+            if (conflictsRestarts > LOWER_BOUND_FOR_BLOCKING_RESTART && lbdQueue.isvalid() && trail.size() > R * trailQueue.getavg()) {
+                lbdQueue.fastclear();
+                nbstopsrestarts++;
+                if (!blocked) {
+                    lastblockatrestart = starts;
+                    nbstopsrestartssame++;
+                    blocked = true;
+                }
+            }
+
+            learnt_clause.clear();
+            selectors.clear();
+
+            analyze(confl, learnt_clause, selectors, backtrack_level, nblevels,szWithoutSelectors);
+
+            lbdQueue.push(nblevels);
+            sumLBD += nblevels;
+
+            cancelUntil(backtrack_level);
+
+            if (certifiedUNSAT) {
+                for (int i = 0; i < learnt_clause.size(); i++)
+                    fprintf(certifiedOutput, "%i ", (var(learnt_clause[i]) + 1) *
+                        (-2 * sign(learnt_clause[i]) + 1));
+                fprintf(certifiedOutput, "0\n");
+            }
+
+
+            if (learnt_clause.size() == 1) {
+                uncheckedEnqueue(learnt_clause[0]);
+                nbUn++;
+                parallelExportUnaryClause(learnt_clause[0]);
+            } else {
+                CRef cr = ca.alloc(learnt_clause, true);
+                ca[cr].setLBD(nblevels);
+                ca[cr].setOneWatched(false);
+               ca[cr].setSizeWithoutSelectors(szWithoutSelectors);
+                if (nblevels <= 2) nbDL2++; // stats
+                if (ca[cr].size() == 2) nbBin++; // stats
+                learnts.push(cr);
+                attachClause(cr);
+                lastLearntClause = cr; // Use in multithread (to hard to put inside ParallelSolver)
+                parallelExportClauseDuringSearch(ca[cr]);
+                claBumpActivity(ca[cr]);
+                uncheckedEnqueue(learnt_clause[0], cr);
+
+            }
+            varDecayActivity();
+            claDecayActivity();
+
+
+        } else {
+            // Our dynamic restart, see the SAT09 competition compagnion paper 
+            if (
+                    (lbdQueue.isvalid() && ((lbdQueue.getavg() * K) > (sumLBD / conflictsRestarts)))) {
+                lbdQueue.fastclear();
+                progress_estimate = progressEstimate();
+                int bt = 0;
+                if(incremental) // DO NOT BACKTRACK UNTIL 0.. USELESS
+                    bt = (decisionLevel()<assumptions.size()) ? decisionLevel() : assumptions.size();
+                cancelUntil(bt);
+                return l_Undef;
+            }
+
+
+            // Simplify the set of problem clauses:
+            if (decisionLevel() == 0 && !simplify()) {
+                return l_False;
+            }
+            // Perform clause database reduction !
+            if (conflicts >= ((unsigned int) curRestart * nbclausesbeforereduce)) {
+
+                if (learnts.size() > 0) {
+                    curRestart = (conflicts / nbclausesbeforereduce) + 1;
+                    reduceDB();
+                    if (!panicModeIsEnabled())
+                        nbclausesbeforereduce += incReduceDB;
+                }
+            }
+
+            lastLearntClause = CRef_Undef;
+            Lit next = lit_Undef;
+            while (decisionLevel() < assumptions.size()) {
+                // Perform user provided assumption:
+                Lit p = assumptions[decisionLevel()];
+                if (value(p) == l_True) {
+                    // Dummy decision level:
+                    newDecisionLevel();
+                } else if (value(p) == l_False) {
+                    analyzeFinal(~p, conflict);
+                    return l_False;
+                } else {
+                    next = p;
+                    break;
+                }
+            }
+
+            if (next == lit_Undef) {
+                // New variable decision:
+                decisions++;
+                next = pickBranchLit();
+                if (next == lit_Undef) {
+                    printf("c last restart ## conflicts  :  %d %d \n", conflictC, decisionLevel());
+                    // Model found:
+                    return l_True;
+                }
+            }
+
+            // Increase decision level and enqueue 'next'
+            newDecisionLevel();
+            uncheckedEnqueue(next);
+        }
+    }
+}
+
+double Solver::progressEstimate() const {
+    double progress = 0;
+    double F = 1.0 / nVars();
+
+    for (int i = 0; i <= decisionLevel(); i++) {
+        int beg = i == 0 ? 0 : trail_lim[i - 1];
+        int end = i == decisionLevel() ? trail.size() : trail_lim[i];
+        progress += pow(F, i) * (end - beg);
+    }
+
+    return progress / nVars();
+}
+
+void Solver::printIncrementalStats() {
+
+    printf("c---------- Glucose Stats -------------------------\n");
+    printf("c restarts              : %" PRIu64"\n", starts);
+    printf("c nb ReduceDB           : %" PRIu64"\n", nbReduceDB);
+    printf("c nb removed Clauses    : %" PRIu64"\n", nbRemovedClauses);
+    printf("c nb learnts DL2        : %" PRIu64"\n", nbDL2);
+    printf("c nb learnts size 2     : %" PRIu64"\n", nbBin);
+    printf("c nb learnts size 1     : %" PRIu64"\n", nbUn);
+
+    printf("c conflicts             : %" PRIu64"\n", conflicts);
+    printf("c decisions             : %" PRIu64"\n", decisions);
+    printf("c propagations          : %" PRIu64"\n", propagations);
+
+  printf("\nc SAT Calls             : %d in %g seconds\n",nbSatCalls,totalTime4Sat);
+  printf("c UNSAT Calls           : %d in %g seconds\n",nbUnsatCalls,totalTime4Unsat);
+
+    printf("c--------------------------------------------------\n");
+}
+
+// NOTE: assumptions passed in member-variable 'assumptions'.
+
+lbool Solver::solve_(bool do_simp, bool turn_off_simp) // Parameters are useless in core but useful for SimpSolver....
+{
+
+    if(incremental && certifiedUNSAT) {
+    printf("Can not use incremental and certified unsat in the same time\n");
+    exit(-1);
+  }
+    model.clear();
+    conflict.clear();
+    if (!ok) return l_False;
+    double curTime = cpuTime();
+
+    solves++;
+            
+   
+    
+    lbool   status        = l_Undef;
+    if(!incremental && verbosity>=1) {
+      printf("c ========================================[ MAGIC CONSTANTS ]==============================================\n");
+      printf("c | Constants are supposed to work well together :-)                                                      |\n");
+      printf("c | however, if you find better choices, please let us known...                                           |\n");
+      printf("c |-------------------------------------------------------------------------------------------------------|\n");
+      printf("c |                                |                                |                                     |\n"); 
+      printf("c | - Restarts:                    | - Reduce Clause DB:            | - Minimize Asserting:               |\n");
+      printf("c |   * LBD Queue    : %6d      |   * First     : %6d         |    * size < %3d                     |\n",lbdQueue.maxSize(),nbclausesbeforereduce,lbSizeMinimizingClause);
+      printf("c |   * Trail  Queue : %6d      |   * Inc       : %6d         |    * lbd  < %3d                     |\n",trailQueue.maxSize(),incReduceDB,lbLBDMinimizingClause);
+      printf("c |   * K            : %6.2f      |   * Special   : %6d         |                                     |\n",K,specialIncReduceDB);
+      printf("c |   * R            : %6.2f      |   * Protected :  (lbd)< %2d     |                                     |\n",R,lbLBDFrozenClause);
+      printf("c |                                |                                |                                     |\n"); 
+      printf("c ==================================[ Search Statistics (every %6d conflicts) ]=========================\n",verbEveryConflicts);
+      printf("c |                                                                                                       |\n"); 
+
+      printf("c |          RESTARTS           |          ORIGINAL         |              LEARNT              | Progress |\n");
+      printf("c |       NB   Blocked  Avg Cfc |    Vars  Clauses Literals |   Red   Learnts    LBD2  Removed |          |\n");
+      printf("c =========================================================================================================\n");
+    }
+
+    // Search:
+    int curr_restarts = 0;
+    while (status == l_Undef){
+      status = search(0); // the parameter is useless in glucose, kept to allow modifications
+
+        if (!withinBudget()) break;
+        curr_restarts++;
+    }
+
+    if (!incremental && verbosity >= 1)
+      printf("c =========================================================================================================\n");
+
+    if (certifiedUNSAT){ // Want certified output
+      if (status == l_False)
+       fprintf(certifiedOutput, "0\n");
+      fclose(certifiedOutput);
+    }
+
+
+    if (status == l_True){
+        // Extend & copy model:
+        model.growTo(nVars());
+        for (int i = 0; i < nVars(); i++) model[i] = value(i);
+    }else if (status == l_False && conflict.size() == 0)
+        ok = false;
+
+
+
+    cancelUntil(0);
+
+
+    double finalTime = cpuTime();
+    if(status==l_True) {
+        nbSatCalls++; 
+        totalTime4Sat +=(finalTime-curTime);
+    }
+    if(status==l_False) {
+        nbUnsatCalls++; 
+        totalTime4Unsat +=(finalTime-curTime);
+    }
+    
+
+    return status;
+
+}
+
+
+
+
+
+//=================================================================================================
+// Writing CNF to DIMACS:
+// 
+// FIXME: this needs to be rewritten completely.
+
+static Var mapVar(Var x, vec<Var>& map, Var& max) {
+    if (map.size() <= x || map[x] == -1) {
+        map.growTo(x + 1, -1);
+        map[x] = max++;
+    }
+    return map[x];
+}
+
+void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max) {
+    if (satisfied(c)) return;
+
+    for (int i = 0; i < c.size(); i++)
+        if (value(c[i]) != l_False)
+            fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max) + 1);
+    fprintf(f, "0\n");
+}
+
+void Solver::toDimacs(const char *file, const vec<Lit>& assumps) {
+    FILE* f = fopen(file, "wr");
+    if (f == NULL)
+        fprintf(stderr, "could not open file %s\n", file), exit(1);
+    toDimacs(f, assumps);
+    fclose(f);
+}
+
+void Solver::toDimacs(FILE* f, const vec<Lit>& assumps) {
+    // Handle case when solver is in contradictory state:
+    if (!ok) {
+        fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
+        return;
+    }
+
+    vec<Var> map;
+    Var max = 0;
+
+    // Cannot use removeClauses here because it is not safe
+    // to deallocate them at this point. Could be improved.
+    int cnt = 0;
+    for (int i = 0; i < clauses.size(); i++)
+        if (!satisfied(ca[clauses[i]]))
+            cnt++;
+
+    for (int i = 0; i < clauses.size(); i++)
+        if (!satisfied(ca[clauses[i]])) {
+            Clause& c = ca[clauses[i]];
+            for (int j = 0; j < c.size(); j++)
+                if (value(c[j]) != l_False)
+                    mapVar(var(c[j]), map, max);
+        }
+
+    // Assumptions are added as unit clauses:
+    cnt += assumptions.size();
+
+    fprintf(f, "p cnf %d %d\n", max, cnt);
+
+    for (int i = 0; i < assumptions.size(); i++) {
+        assert(value(assumptions[i]) != l_False);
+        fprintf(f, "%s%d 0\n", sign(assumptions[i]) ? "-" : "", mapVar(var(assumptions[i]), map, max) + 1);
+    }
+
+    for (int i = 0; i < clauses.size(); i++)
+        toDimacs(f, ca[clauses[i]], map, max);
+
+    if (verbosity > 0)
+        printf("Wrote %d clauses with %d variables.\n", cnt, max);
+}
+
+
+//=================================================================================================
+// Garbage Collection methods:
+
+void Solver::relocAll(ClauseAllocator& to) {
+    // All watchers:
+    //
+    // for (int i = 0; i < watches.size(); i++)
+    watches.cleanAll();
+    watchesBin.cleanAll();
+    unaryWatches.cleanAll();
+    for (int v = 0; v < nVars(); v++)
+        for (int s = 0; s < 2; s++) {
+            Lit p = mkLit(v, s);
+            // printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
+            vec<Watcher>& ws = watches[p];
+            for (int j = 0; j < ws.size(); j++)
+                ca.reloc(ws[j].cref, to);
+            vec<Watcher>& ws2 = watchesBin[p];
+            for (int j = 0; j < ws2.size(); j++)
+                ca.reloc(ws2[j].cref, to);
+            vec<Watcher>& ws3 = unaryWatches[p];
+            for (int j = 0; j < ws3.size(); j++)
+                ca.reloc(ws3[j].cref, to);
+        }
+
+    // All reasons:
+    //
+    for (int i = 0; i < trail.size(); i++) {
+        Var v = var(trail[i]);
+
+        if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
+            ca.reloc(vardata[v].reason, to);
+    }
+
+    // All learnt:
+    //
+    for (int i = 0; i < learnts.size(); i++)
+        ca.reloc(learnts[i], to);
+
+    // All original:
+    //
+    for (int i = 0; i < clauses.size(); i++)
+        ca.reloc(clauses[i], to);
+
+    for (int i = 0; i < unaryWatchedClauses.size(); i++)
+        ca.reloc(unaryWatchedClauses[i], to);
+}
+
+
+
+void Solver::garbageCollect() {
+    // Initialize the next region to a size corresponding to the estimated utilization degree. This
+    // is not precise but should avoid some unnecessary reallocations for the new region:
+    ClauseAllocator to(ca.size() - ca.wasted());
+
+    relocAll(to);
+    if (verbosity >= 2)
+        printf("|  Garbage collection:   %12d bytes => %12d bytes             |\n",
+            ca.size() * ClauseAllocator::Unit_Size, to.size() * ClauseAllocator::Unit_Size);
+    to.moveTo(ca);
+}
+
+//--------------------------------------------------------------
+// Functions related to MultiThread.
+// Useless in case of single core solver (aka original glucose)
+// Keep them empty if you just use core solver
+//--------------------------------------------------------------
+
+bool Solver::panicModeIsEnabled() {
+    return false;
+}
+
+void Solver::parallelImportUnaryClauses() {
+}
+
+bool Solver::parallelImportClauses() {
+    return false;
+}
+
+
+void Solver::parallelExportUnaryClause(Lit p) {
+}
+void Solver::parallelExportClauseDuringSearch(Clause &c) {
+}
+
+bool Solver::parallelJobIsFinished() { 
+    // Parallel: another job has finished let's quit
+    return false;
+}
+
+void Solver::parallelImportClauseDuringConflictAnalysis(Clause &c,CRef confl) {
+}
diff --git a/glucose-syrup/core/Solver.h b/glucose-syrup/core/Solver.h
new file mode 100644 (file)
index 0000000..63d5316
--- /dev/null
@@ -0,0 +1,581 @@
+/***************************************************************************************[Solver.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#ifndef Glucose_Solver_h
+#define Glucose_Solver_h
+
+#include "mtl/Heap.h"
+#include "mtl/Alg.h"
+#include "utils/Options.h"
+#include "core/SolverTypes.h"
+#include "core/BoundedQueue.h"
+#include "core/Constants.h"
+#include "mtl/Clone.h"
+
+
+namespace Glucose {
+
+//=================================================================================================
+// Solver -- the main class:
+
+class Solver : public Clone {
+
+    friend class SolverConfiguration;
+
+public:
+
+    // Constructor/Destructor:
+    //
+    Solver();
+    Solver(const  Solver &s);
+    
+    virtual ~Solver();
+    
+    /**
+     * Clone function
+     */
+    virtual Clone* clone() const {
+        return  new Solver(*this);
+    }   
+
+    // Problem specification:
+    //
+    virtual Var     newVar    (bool polarity = true, bool dvar = true); // Add a new variable with parameters specifying variable mode.
+    bool    addClause (const vec<Lit>& ps);                     // Add a clause to the solver. 
+    bool    addEmptyClause();                                   // Add the empty clause, making the solver contradictory.
+    bool    addClause (Lit p);                                  // Add a unit clause to the solver. 
+    bool    addClause (Lit p, Lit q);                           // Add a binary clause to the solver. 
+    bool    addClause (Lit p, Lit q, Lit r);                    // Add a ternary clause to the solver. 
+    virtual bool    addClause_(      vec<Lit>& ps);                     // Add a clause to the solver without making superflous internal copy. Will
+                                                                // change the passed vector 'ps'.
+
+    // Solving:
+    //
+    bool    simplify     ();                        // Removes already satisfied clauses.
+    bool    solve        (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions.
+    lbool   solveLimited (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions (With resource constraints).
+    bool    solve        ();                        // Search without assumptions.
+    bool    solve        (Lit p);                   // Search for a model that respects a single assumption.
+    bool    solve        (Lit p, Lit q);            // Search for a model that respects two assumptions.
+    bool    solve        (Lit p, Lit q, Lit r);     // Search for a model that respects three assumptions.
+    bool    okay         () const;                  // FALSE means solver is in a conflicting state
+
+       // Convenience versions of 'toDimacs()':
+    void    toDimacs     (FILE* f, const vec<Lit>& assumps);            // Write CNF to file in DIMACS-format.
+    void    toDimacs     (const char *file, const vec<Lit>& assumps);
+    void    toDimacs     (FILE* f, Clause& c, vec<Var>& map, Var& max);
+    void    toDimacs     (const char* file);
+    void    toDimacs     (const char* file, Lit p);
+    void    toDimacs     (const char* file, Lit p, Lit q);
+    void    toDimacs     (const char* file, Lit p, Lit q, Lit r);
+    // Display clauses and literals
+    void printLit(Lit l);
+    void printClause(CRef c);
+    void printInitialClause(CRef c);
+    
+    // Variable mode:
+    // 
+    void    setPolarity    (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
+    void    setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
+
+    // Read state:
+    //
+    lbool   value      (Var x) const;       // The current value of a variable.
+    lbool   value      (Lit p) const;       // The current value of a literal.
+    lbool   modelValue (Var x) const;       // The value of a variable in the last model. The last call to solve must have been satisfiable.
+    lbool   modelValue (Lit p) const;       // The value of a literal in the last model. The last call to solve must have been satisfiable.
+    int     nAssigns   ()      const;       // The current number of assigned literals.
+    int     nClauses   ()      const;       // The current number of original clauses.
+    int     nLearnts   ()      const;       // The current number of learnt clauses.
+    int     nVars      ()      const;       // The current number of variables.
+    int     nFreeVars  ()      const;
+
+    inline char valuePhase(Var v) {return polarity[v];}
+
+    // Incremental mode
+    void setIncrementalMode();
+    void initNbInitialVars(int nb);
+    void printIncrementalStats();
+    bool isIncremental();
+    // Resource contraints:
+    //
+    void    setConfBudget(int64_t x);
+    void    setPropBudget(int64_t x);
+    void    budgetOff();
+    void    interrupt();          // Trigger a (potentially asynchronous) interruption of the solver.
+    void    clearInterrupt();     // Clear interrupt indicator flag.
+
+    // Memory managment:
+    //
+    virtual void garbageCollect();
+    void    checkGarbage(double gf);
+    void    checkGarbage();
+
+    // Extra results: (read-only member variable)
+    //
+    vec<lbool> model;             // If problem is satisfiable, this vector contains the model (if any).
+    vec<Lit>   conflict;          // If problem is unsatisfiable (possibly under assumptions),
+                                  // this vector represent the final conflict clause expressed in the assumptions.
+
+    // Mode of operation:
+    //
+    int       verbosity;
+    int       verbEveryConflicts;
+    int       showModel;
+    
+    // Constants For restarts
+    double    K;
+    double    R;
+    double    sizeLBDQueue;
+    double    sizeTrailQueue;
+
+    // Constants for reduce DB
+    int          firstReduceDB;
+    int          incReduceDB;
+    int          specialIncReduceDB;
+    unsigned int lbLBDFrozenClause;
+
+    // Constant for reducing clause
+    int          lbSizeMinimizingClause;
+    unsigned int lbLBDMinimizingClause;
+
+    // Constant for heuristic
+    double    var_decay;
+    double    max_var_decay;
+    double    clause_decay;
+    double    random_var_freq;
+    double    random_seed;
+    int       ccmin_mode;         // Controls conflict clause minimization (0=none, 1=basic, 2=deep).
+    int       phase_saving;       // Controls the level of phase saving (0=none, 1=limited, 2=full).
+    bool      rnd_pol;            // Use random polarities for branching heuristics.
+    bool      rnd_init_act;       // Initialize variable activities with a small random value.
+    
+    // Constant for Memory managment
+    double    garbage_frac;       // The fraction of wasted memory allowed before a garbage collection is triggered.
+
+    // Certified UNSAT ( Thanks to Marijn Heule)
+    FILE*               certifiedOutput;
+    bool                certifiedUNSAT;
+
+    // Panic mode. 
+    // Save memory
+    uint32_t panicModeLastRemoved, panicModeLastRemovedShared;
+    
+    bool useUnaryWatched;            // Enable unary watched literals
+    bool promoteOneWatchedClause;    // One watched clauses are promotted to two watched clauses if found empty
+    
+    // Functions useful for multithread solving
+    // Useless in the sequential case 
+    // Overide in ParallelSolver
+    virtual void parallelImportClauseDuringConflictAnalysis(Clause &c,CRef confl);
+    virtual bool parallelImportClauses(); // true if the empty clause was received
+    virtual void parallelImportUnaryClauses();
+    virtual void parallelExportUnaryClause(Lit p);
+    virtual void parallelExportClauseDuringSearch(Clause &c);
+    virtual bool parallelJobIsFinished();
+    virtual bool panicModeIsEnabled();
+    
+    
+
+    // Statistics: (read-only member variable)
+    uint64_t    nbPromoted;          // Number of clauses from unary to binary watch scheme
+    uint64_t    originalClausesSeen; // Number of original clauses seen
+    uint64_t    sumDecisionLevels;
+    //
+    uint64_t nbRemovedClauses,nbRemovedUnaryWatchedClauses, nbReducedClauses,nbDL2,nbBin,nbUn,nbReduceDB,solves, starts, decisions, rnd_decisions, propagations, conflicts,conflictsRestarts,nbstopsrestarts,nbstopsrestartssame,lastblockatrestart;
+    uint64_t dec_vars, clauses_literals, learnts_literals, max_literals, tot_literals;
+
+protected:
+
+    long curRestart;
+    // Helper structures:
+    //
+    struct VarData { CRef reason; int level; };
+    static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; }
+
+    struct Watcher {
+        CRef cref;
+        Lit  blocker;
+        Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {}
+        bool operator==(const Watcher& w) const { return cref == w.cref; }
+        bool operator!=(const Watcher& w) const { return cref != w.cref; }
+/*        Watcher &operator=(Watcher w) {
+            this->cref = w.cref;
+            this->blocker = w.blocker;
+            return *this;
+        }
+*/
+    };
+
+    struct WatcherDeleted
+    {
+        const ClauseAllocator& ca;
+        WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
+        bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; }
+    };
+
+    struct VarOrderLt {
+        const vec<double>&  activity;
+        bool operator () (Var x, Var y) const { return activity[x] > activity[y]; }
+        VarOrderLt(const vec<double>&  act) : activity(act) { }
+    };
+
+
+    // Solver state:
+    //
+    int                lastIndexRed;
+    bool                ok;               // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used!
+    double              cla_inc;          // Amount to bump next clause with.
+    vec<double>         activity;         // A heuristic measurement of the activity of a variable.
+    double              var_inc;          // Amount to bump next variable with.
+    OccLists<Lit, vec<Watcher>, WatcherDeleted>
+                        watches;          // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
+    OccLists<Lit, vec<Watcher>, WatcherDeleted>
+                        watchesBin;          // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
+    OccLists<Lit, vec<Watcher>, WatcherDeleted>
+                        unaryWatches;       //  Unary watch scheme (clauses are seen when they become empty
+    vec<CRef>           clauses;          // List of problem clauses.
+    vec<CRef>           learnts;          // List of learnt clauses.
+    vec<CRef>           unaryWatchedClauses;  // List of imported clauses (after the purgatory) // TODO put inside ParallelSolver
+
+    vec<lbool>          assigns;          // The current assignments.
+    vec<char>           polarity;         // The preferred polarity of each variable.
+    vec<char>           decision;         // Declares if a variable is eligible for selection in the decision heuristic.
+    vec<Lit>            trail;            // Assignment stack; stores all assigments made in the order they were made.
+    vec<int>            nbpos;
+    vec<int>            trail_lim;        // Separator indices for different decision levels in 'trail'.
+    vec<VarData>        vardata;          // Stores reason and level for each variable.
+    int                 qhead;            // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat).
+    int                 simpDB_assigns;   // Number of top-level assignments since last execution of 'simplify()'.
+    int64_t             simpDB_props;     // Remaining number of propagations that must be made before next execution of 'simplify()'.
+    vec<Lit>            assumptions;      // Current set of assumptions provided to solve by the user.
+    Heap<VarOrderLt>    order_heap;       // A priority queue of variables ordered with respect to the variable activity.
+    double              progress_estimate;// Set by 'search()'.
+    bool                remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'.
+    bool reduceOnSize;
+    int  reduceOnSizeSize;                // See XMinisat paper
+    vec<unsigned int>   permDiff;           // permDiff[var] contains the current conflict number... Used to count the number of  LBD
+    
+
+    // UPDATEVARACTIVITY trick (see competition'09 companion paper)
+    vec<Lit> lastDecisionLevel; 
+
+    ClauseAllocator     ca;
+
+    int nbclausesbeforereduce;            // To know when it is time to reduce clause database
+    
+    // Used for restart strategies
+    bqueue<unsigned int> trailQueue,lbdQueue; // Bounded queues for restarts.
+    float sumLBD; // used to compute the global average of LBD. Restarts...
+    int sumAssumptions;
+    CRef lastLearntClause;
+
+
+    // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is
+    // used, exept 'seen' wich is used in several places.
+    //
+    vec<char>           seen;
+    vec<Lit>            analyze_stack;
+    vec<Lit>            analyze_toclear;
+    vec<Lit>            add_tmp;
+    unsigned int  MYFLAG;
+
+    // Initial reduceDB strategy
+    double              max_learnts;
+    double              learntsize_adjust_confl;
+    int                 learntsize_adjust_cnt;
+
+    // Resource contraints:
+    //
+    int64_t             conflict_budget;    // -1 means no budget.
+    int64_t             propagation_budget; // -1 means no budget.
+    bool                asynch_interrupt;
+
+    // Variables added for incremental mode
+    int incremental; // Use incremental SAT Solver
+    int nbVarsInitialFormula; // nb VAR in formula without assumptions (incremental SAT)
+    double totalTime4Sat,totalTime4Unsat;
+    int nbSatCalls,nbUnsatCalls;
+    vec<int> assumptionPositions,initialPositions;
+
+
+    // Main internal methods:
+    //
+    void     insertVarOrder   (Var x);                                                 // Insert a variable in the decision order priority queue.
+    Lit      pickBranchLit    ();                                                      // Return the next decision variable.
+    void     newDecisionLevel ();                                                      // Begins a new decision level.
+    void     uncheckedEnqueue (Lit p, CRef from = CRef_Undef);                         // Enqueue a literal. Assumes value of literal is undefined.
+    bool     enqueue          (Lit p, CRef from = CRef_Undef);                         // Test if fact 'p' contradicts current state, enqueue otherwise.
+    CRef     propagate        ();                                                      // Perform unit propagation. Returns possibly conflicting clause.
+    CRef     propagateUnaryWatches(Lit p);                                                  // Perform propagation on unary watches of p, can find only conflicts
+    void     cancelUntil      (int level);                                             // Backtrack until a certain level.
+    void     analyze          (CRef confl, vec<Lit>& out_learnt, vec<Lit> & selectors, int& out_btlevel,unsigned int &nblevels,unsigned int &szWithoutSelectors);    // (bt = backtrack)
+    void     analyzeFinal     (Lit p, vec<Lit>& out_conflict);                         // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
+    bool     litRedundant     (Lit p, uint32_t abstract_levels);                       // (helper method for 'analyze()')
+    lbool    search           (int nof_conflicts);                                     // Search for a given number of conflicts.
+    virtual lbool    solve_           (bool do_simp = true, bool turn_off_simp = false);                                                      // Main solve method (assumptions given in 'assumptions').
+    virtual void     reduceDB         ();                                                      // Reduce the set of learnt clauses.
+    void     removeSatisfied  (vec<CRef>& cs);                                         // Shrink 'cs' to contain only non-satisfied clauses.
+    void     rebuildOrderHeap ();
+
+    // Maintaining Variable/Clause activity:
+    //
+    void     varDecayActivity ();                      // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead.
+    void     varBumpActivity  (Var v, double inc);     // Increase a variable with the current 'bump' value.
+    void     varBumpActivity  (Var v);                 // Increase a variable with the current 'bump' value.
+    void     claDecayActivity ();                      // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead.
+    void     claBumpActivity  (Clause& c);             // Increase a clause with the current 'bump' value.
+
+    // Operations on clauses:
+    //
+    void     attachClause     (CRef cr);               // Attach a clause to watcher lists.
+    void     detachClause     (CRef cr, bool strict = false); // Detach a clause to watcher lists.
+    void     detachClausePurgatory(CRef cr, bool strict = false);
+    void     attachClausePurgatory(CRef cr);
+    void     removeClause     (CRef cr, bool inPurgatory = false);               // Detach and free a clause.
+    bool     locked           (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state.
+    bool     satisfied        (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state.
+
+    unsigned int computeLBD(const vec<Lit> & lits,int end=-1);
+    unsigned int computeLBD(const Clause &c);
+    void minimisationWithBinaryResolution(vec<Lit> &out_learnt);
+
+    virtual void     relocAll         (ClauseAllocator& to);
+
+    // Misc:
+    //
+    int      decisionLevel    ()      const; // Gives the current decisionlevel.
+    uint32_t abstractLevel    (Var x) const; // Used to represent an abstraction of sets of decision levels.
+    CRef     reason           (Var x) const;
+    int      level            (Var x) const;
+    double   progressEstimate ()      const; // DELETE THIS ?? IT'S NOT VERY USEFUL ...
+    bool     withinBudget     ()      const;
+    inline bool isSelector(Var v) {return (incremental && v>nbVarsInitialFormula);}
+
+    // Static helpers:
+    //
+
+    // Returns a random float 0 <= x < 1. Seed must never be 0.
+    static inline double drand(double& seed) {
+        seed *= 1389796;
+        int q = (int)(seed / 2147483647);
+        seed -= (double)q * 2147483647;
+        return seed / 2147483647; }
+
+    // Returns a random integer 0 <= x < size. Seed must never be 0.
+    static inline int irand(double& seed, int size) {
+        return (int)(drand(seed) * size); }
+};
+
+
+//=================================================================================================
+// Implementation of inline methods:
+
+inline CRef Solver::reason(Var x) const { return vardata[x].reason; }
+inline int  Solver::level (Var x) const { return vardata[x].level; }
+
+inline void Solver::insertVarOrder(Var x) {
+    if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); }
+
+inline void Solver::varDecayActivity() { var_inc *= (1 / var_decay); }
+inline void Solver::varBumpActivity(Var v) { varBumpActivity(v, var_inc); }
+inline void Solver::varBumpActivity(Var v, double inc) {
+    if ( (activity[v] += inc) > 1e100 ) {
+        // Rescale:
+        for (int i = 0; i < nVars(); i++)
+            activity[i] *= 1e-100;
+        var_inc *= 1e-100; }
+
+    // Update order_heap with respect to new activity:
+    if (order_heap.inHeap(v))
+        order_heap.decrease(v); }
+
+inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); }
+inline void Solver::claBumpActivity (Clause& c) {
+        if ( (c.activity() += cla_inc) > 1e20 ) {
+            // Rescale:
+            for (int i = 0; i < learnts.size(); i++)
+                ca[learnts[i]].activity() *= 1e-20;
+            cla_inc *= 1e-20; } }
+
+inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); }
+inline void Solver::checkGarbage(double gf){
+    if (ca.wasted() > ca.size() * gf)
+        garbageCollect(); }
+
+// NOTE: enqueue does not set the ok flag! (only public methods do)
+inline bool     Solver::enqueue         (Lit p, CRef from)      { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
+inline bool     Solver::addClause       (const vec<Lit>& ps)    { ps.copyTo(add_tmp); return addClause_(add_tmp); }
+inline bool     Solver::addEmptyClause  ()                      { add_tmp.clear(); return addClause_(add_tmp); }
+inline bool     Solver::addClause       (Lit p)                 { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
+inline bool     Solver::addClause       (Lit p, Lit q)          { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
+inline bool     Solver::addClause       (Lit p, Lit q, Lit r)   { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+ inline bool     Solver::locked          (const Clause& c) const { 
+   if(c.size()>2) 
+     return value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c; 
+   return 
+     (value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c)
+     || 
+     (value(c[1]) == l_True && reason(var(c[1])) != CRef_Undef && ca.lea(reason(var(c[1]))) == &c);
+ }
+inline void     Solver::newDecisionLevel()                      { trail_lim.push(trail.size()); }
+
+inline int      Solver::decisionLevel ()      const   { return trail_lim.size(); }
+inline uint32_t Solver::abstractLevel (Var x) const   { return 1 << (level(x) & 31); }
+inline lbool    Solver::value         (Var x) const   { return assigns[x]; }
+inline lbool    Solver::value         (Lit p) const   { return assigns[var(p)] ^ sign(p); }
+inline lbool    Solver::modelValue    (Var x) const   { return model[x]; }
+inline lbool    Solver::modelValue    (Lit p) const   { return model[var(p)] ^ sign(p); }
+inline int      Solver::nAssigns      ()      const   { return trail.size(); }
+inline int      Solver::nClauses      ()      const   { return clauses.size(); }
+inline int      Solver::nLearnts      ()      const   { return learnts.size(); }
+inline int      Solver::nVars         ()      const   { return vardata.size(); }
+inline int      Solver::nFreeVars     ()      const   { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
+inline void     Solver::setPolarity   (Var v, bool b) { polarity[v] = b; }
+inline void     Solver::setDecisionVar(Var v, bool b) 
+{ 
+    if      ( b && !decision[v]) dec_vars++;
+    else if (!b &&  decision[v]) dec_vars--;
+
+    decision[v] = b;
+    insertVarOrder(v);
+}
+inline void     Solver::setConfBudget(int64_t x){ conflict_budget    = conflicts    + x; }
+inline void     Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
+inline void     Solver::interrupt(){ asynch_interrupt = true; }
+inline void     Solver::clearInterrupt(){ asynch_interrupt = false; }
+inline void     Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
+inline bool     Solver::withinBudget() const {
+    return !asynch_interrupt &&
+           (conflict_budget    < 0 || conflicts < (uint64_t)conflict_budget) &&
+           (propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
+
+// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
+// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
+// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer.
+inline bool     Solver::solve         ()                    { budgetOff(); assumptions.clear(); return solve_() == l_True; }
+inline bool     Solver::solve         (Lit p)               { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; }
+inline bool     Solver::solve         (Lit p, Lit q)        { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; }
+inline bool     Solver::solve         (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; }
+inline bool     Solver::solve         (const vec<Lit>& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; }
+inline lbool    Solver::solveLimited  (const vec<Lit>& assumps){ assumps.copyTo(assumptions); return solve_(); }
+inline bool     Solver::okay          ()      const   { return ok; }
+
+inline void     Solver::toDimacs     (const char* file){ vec<Lit> as; toDimacs(file, as); }
+inline void     Solver::toDimacs     (const char* file, Lit p){ vec<Lit> as; as.push(p); toDimacs(file, as); }
+inline void     Solver::toDimacs     (const char* file, Lit p, Lit q){ vec<Lit> as; as.push(p); as.push(q); toDimacs(file, as); }
+inline void     Solver::toDimacs     (const char* file, Lit p, Lit q, Lit r){ vec<Lit> as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); }
+
+
+
+//=================================================================================================
+// Debug etc:
+
+
+inline void Solver::printLit(Lit l)
+{
+    printf("%s%d:%c", sign(l) ? "-" : "", var(l)+1, value(l) == l_True ? '1' : (value(l) == l_False ? '0' : 'X'));
+}
+
+
+inline void Solver::printClause(CRef cr)
+{
+  Clause &c = ca[cr];
+    for (int i = 0; i < c.size(); i++){
+        printLit(c[i]);
+        printf(" ");
+    }
+}
+
+inline void Solver::printInitialClause(CRef cr)
+{
+  Clause &c = ca[cr];
+    for (int i = 0; i < c.size(); i++){
+      if(!isSelector(var(c[i]))) {
+       printLit(c[i]);
+        printf(" ");
+      }
+    }
+}
+
+//=================================================================================================
+
+struct reduceDB_lt {
+    ClauseAllocator& ca;
+
+    reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {
+    }
+
+    bool operator()(CRef x, CRef y) {
+
+        // Main criteria... Like in MiniSat we keep all binary clauses
+        if (ca[x].size() > 2 && ca[y].size() == 2) return 1;
+
+        if (ca[y].size() > 2 && ca[x].size() == 2) return 0;
+        if (ca[x].size() == 2 && ca[y].size() == 2) return 0;
+
+        // Second one  based on literal block distance
+        if (ca[x].lbd() > ca[y].lbd()) return 1;
+        if (ca[x].lbd() < ca[y].lbd()) return 0;
+
+
+        // Finally we can use old activity or size, we choose the last one
+        return ca[x].activity() < ca[y].activity();
+        //return x->size() < y->size();
+
+        //return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); } 
+    }
+};
+
+
+}
+
+
+#endif
diff --git a/glucose-syrup/core/SolverTypes.h b/glucose-syrup/core/SolverTypes.h
new file mode 100644 (file)
index 0000000..a905afb
--- /dev/null
@@ -0,0 +1,506 @@
+/***************************************************************************************[SolverTypes.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+
+#ifndef Glucose_SolverTypes_h
+#define Glucose_SolverTypes_h
+
+#include <assert.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include "mtl/IntTypes.h"
+#include "mtl/Alg.h"
+#include "mtl/Vec.h"
+#include "mtl/Map.h"
+#include "mtl/Alloc.h"
+
+
+namespace Glucose {
+
+//=================================================================================================
+// Variables, literals, lifted booleans, clauses:
+
+
+// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N,
+// so that they can be used as array indices.
+
+typedef int Var;
+#define var_Undef (-1)
+
+
+struct Lit {
+    int     x;
+
+    // Use this as a constructor:
+    friend Lit mkLit(Var var, bool sign);
+
+    bool operator == (Lit p) const { return x == p.x; }
+    bool operator != (Lit p) const { return x != p.x; }
+    bool operator <  (Lit p) const { return x < p.x;  } // '<' makes p, ~p adjacent in the ordering.
+};
+
+
+inline  Lit  mkLit     (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
+inline  Lit  operator ~(Lit p)              { Lit q; q.x = p.x ^ 1; return q; }
+inline  Lit  operator ^(Lit p, bool b)      { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
+inline  bool sign      (Lit p)              { return p.x & 1; }
+inline  int  var       (Lit p)              { return p.x >> 1; }
+
+// Mapping Literals to and from compact integers suitable for array indexing:
+inline  int  toInt     (Var v)              { return v; } 
+inline  int  toInt     (Lit p)              { return p.x; } 
+inline  Lit  toLit     (int i)              { Lit p; p.x = i; return p; } 
+
+//const Lit lit_Undef = mkLit(var_Undef, false);  // }- Useful special constants.
+//const Lit lit_Error = mkLit(var_Undef, true );  // }
+
+const Lit lit_Undef = { -2 };  // }- Useful special constants.
+const Lit lit_Error = { -1 };  // }
+
+
+//=================================================================================================
+// Lifted booleans:
+//
+// NOTE: this implementation is optimized for the case when comparisons between values are mostly
+//       between one variable and one constant. Some care had to be taken to make sure that gcc 
+//       does enough constant propagation to produce sensible code, and this appears to be somewhat
+//       fragile unfortunately.
+
+#define l_True  (Glucose::lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants.
+#define l_False (Glucose::lbool((uint8_t)1))
+#define l_Undef (Glucose::lbool((uint8_t)2))
+
+class lbool {
+    uint8_t value;
+
+public:
+    explicit lbool(uint8_t v) : value(v) { }
+
+    lbool()       : value(0) { }
+    explicit lbool(bool x) : value(!x) { }
+
+    bool  operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); }
+    bool  operator != (lbool b) const { return !(*this == b); }
+    lbool operator ^  (bool  b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
+
+    lbool operator && (lbool b) const { 
+        uint8_t sel = (this->value << 1) | (b.value << 3);
+        uint8_t v   = (0xF7F755F4 >> sel) & 3;
+        return lbool(v); }
+
+    lbool operator || (lbool b) const {
+        uint8_t sel = (this->value << 1) | (b.value << 3);
+        uint8_t v   = (0xFCFCF400 >> sel) & 3;
+        return lbool(v); }
+
+    friend int   toInt  (lbool l);
+    friend lbool toLbool(int   v);
+};
+inline int   toInt  (lbool l) { return l.value; }
+inline lbool toLbool(int   v) { return lbool((uint8_t)v);  }
+
+//=================================================================================================
+// Clause -- a simple class for representing a clause:
+
+class Clause;
+typedef RegionAllocator<uint32_t>::Ref CRef;
+
+#define BITS_LBD 13
+#define BITS_SIZEWITHOUTSEL 19
+#define BITS_REALSIZE 21
+class Clause {
+    struct {
+      unsigned mark       : 2;
+      unsigned learnt     : 1;
+      unsigned szWithoutSelectors : BITS_SIZEWITHOUTSEL;
+      unsigned canbedel   : 1;
+      unsigned extra_size : 2; // extra size (end of 32bits) 0..3       
+      unsigned size       : BITS_REALSIZE;
+      unsigned seen       : 1;
+      unsigned reloced    : 1;
+      unsigned exported   : 2; // Values to keep track of the clause status for exportations
+      unsigned oneWatched : 1;
+      unsigned lbd : BITS_LBD;
+    }  header;
+
+    union { Lit lit; float act; uint32_t abs; CRef rel; } data[0];
+
+    friend class ClauseAllocator;
+
+    // NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
+    template<class V>
+    Clause(const V& ps, int _extra_size, bool learnt) {
+       assert(_extra_size < (1<<2));
+        header.mark      = 0;
+        header.learnt    = learnt;
+        header.extra_size = _extra_size;
+        header.reloced   = 0;
+        header.size      = ps.size();
+       header.lbd = 0;
+       header.canbedel = 1;
+       header.exported = 0; 
+       header.oneWatched = 0;
+       header.seen = 0;
+        for (int i = 0; i < ps.size(); i++) 
+            data[i].lit = ps[i];
+       
+        if (header.extra_size > 0){
+         if (header.learnt) 
+                data[header.size].act = 0; 
+            else 
+                calcAbstraction();
+         if (header.extra_size > 1) {
+             data[header.size+1].abs = 0; // learntFrom
+         }           
+       }
+    }
+
+public:
+    void calcAbstraction() {
+        assert(header.extra_size > 0);
+        uint32_t abstraction = 0;
+        for (int i = 0; i < size(); i++)
+            abstraction |= 1 << (var(data[i].lit) & 31);
+        data[header.size].abs = abstraction;  }
+
+    int          size        ()      const   { return header.size; }
+    void         shrink      (int i)         { assert(i <= size()); 
+                                               if (header.extra_size > 0) {
+                                                   data[header.size-i] = data[header.size];
+                                                   if (header.extra_size > 1) { // Special case for imported clauses
+                                                       data[header.size-i-1] = data[header.size-1];
+                                                   }
+                                               }
+    header.size -= i; }
+    void         pop         ()              { shrink(1); }
+    bool         learnt      ()      const   { return header.learnt; }
+    bool         has_extra   ()      const   { return header.extra_size > 0; }
+    uint32_t     mark        ()      const   { return header.mark; }
+    void         mark        (uint32_t m)    { header.mark = m; }
+    const Lit&   last        ()      const   { return data[header.size-1].lit; }
+
+    bool         reloced     ()      const   { return header.reloced; }
+    CRef         relocation  ()      const   { return data[0].rel; }
+    void         relocate    (CRef c)        { header.reloced = 1; data[0].rel = c; }
+
+    // NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for
+    //       subsumption operations to behave correctly.
+    Lit&         operator [] (int i)         { return data[i].lit; }
+    Lit          operator [] (int i) const   { return data[i].lit; }
+    operator const Lit* (void) const         { return (Lit*)data; }
+
+    float&       activity    ()              { assert(header.extra_size > 0); return data[header.size].act; }
+    uint32_t     abstraction () const        { assert(header.extra_size > 0); return data[header.size].abs; }
+
+    // Handle imported clauses lazy sharing
+    bool        wasImported() const {return header.extra_size > 1;}
+    uint32_t    importedFrom () const       { assert(header.extra_size > 1); return data[header.size + 1].abs;}
+    void setImportedFrom(uint32_t ifrom) {assert(header.extra_size > 1); data[header.size+1].abs = ifrom;}
+
+    Lit          subsumes    (const Clause& other) const;
+    void         strengthen  (Lit p);
+    void         setLBD(int i)  {if (i < (1<<(BITS_LBD-1))) header.lbd = i; else header.lbd = (1<<(BITS_LBD-1));} 
+    // unsigned int&       lbd    ()              { return header.lbd; }
+    unsigned int        lbd    () const        { return header.lbd; }
+    void setCanBeDel(bool b) {header.canbedel = b;}
+    bool canBeDel() {return header.canbedel;}
+    void setSeen(bool b) {header.seen = b;}
+    bool getSeen() {return header.seen;}
+    void setExported(unsigned int b) {header.exported = b;}
+    unsigned int getExported() {return header.exported;}
+    void setOneWatched(bool b) {header.oneWatched = b;}
+    bool getOneWatched() {return header.oneWatched;}
+    void setSizeWithoutSelectors   (unsigned int n)              {header.szWithoutSelectors = n; }
+    unsigned int        sizeWithoutSelectors   () const        { return header.szWithoutSelectors; }
+
+};
+
+
+//=================================================================================================
+// ClauseAllocator -- a simple class for allocating memory for clauses:
+
+
+const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef;
+class ClauseAllocator : public RegionAllocator<uint32_t>
+{
+    static int clauseWord32Size(int size, int extra_size){
+        return (sizeof(Clause) + (sizeof(Lit) * (size + extra_size))) / sizeof(uint32_t); }
+ public:
+    bool extra_clause_field;
+
+    ClauseAllocator(uint32_t start_cap) : RegionAllocator<uint32_t>(start_cap), extra_clause_field(false){}
+    ClauseAllocator() : extra_clause_field(false){}
+
+    void moveTo(ClauseAllocator& to){
+        to.extra_clause_field = extra_clause_field;
+        RegionAllocator<uint32_t>::moveTo(to); }
+
+    template<class Lits>
+    CRef alloc(const Lits& ps, bool learnt = false, bool imported = false)
+    {
+        assert(sizeof(Lit)      == sizeof(uint32_t));
+        assert(sizeof(float)    == sizeof(uint32_t));
+       
+        bool use_extra = learnt | extra_clause_field;
+        int extra_size = imported?3:(use_extra?1:0);
+        CRef cid = RegionAllocator<uint32_t>::alloc(clauseWord32Size(ps.size(), extra_size));
+        new (lea(cid)) Clause(ps, extra_size, learnt);
+
+        return cid;
+    }
+
+    // Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
+    Clause&       operator[](Ref r)       { return (Clause&)RegionAllocator<uint32_t>::operator[](r); }
+    const Clause& operator[](Ref r) const { return (Clause&)RegionAllocator<uint32_t>::operator[](r); }
+    Clause*       lea       (Ref r)       { return (Clause*)RegionAllocator<uint32_t>::lea(r); }
+    const Clause* lea       (Ref r) const { return (Clause*)RegionAllocator<uint32_t>::lea(r); }
+    Ref           ael       (const Clause* t){ return RegionAllocator<uint32_t>::ael((uint32_t*)t); }
+
+    void free(CRef cid)
+    {
+        Clause& c = operator[](cid);
+        RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra()));
+    }
+
+    void reloc(CRef& cr, ClauseAllocator& to)
+    {
+        Clause& c = operator[](cr);
+        
+        if (c.reloced()) { cr = c.relocation(); return; }
+        
+        cr = to.alloc(c, c.learnt(), c.wasImported());
+        c.relocate(cr);
+        
+        // Copy extra data-fields: 
+        // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
+        to[cr].mark(c.mark());
+        if (to[cr].learnt())        {
+         to[cr].activity() = c.activity();
+         to[cr].setLBD(c.lbd());
+         to[cr].setExported(c.getExported());
+         to[cr].setOneWatched(c.getOneWatched());
+         to[cr].setSeen(c.getSeen());
+         to[cr].setSizeWithoutSelectors(c.sizeWithoutSelectors());
+         to[cr].setCanBeDel(c.canBeDel());
+         if (c.wasImported()) {
+             to[cr].setImportedFrom(c.importedFrom());
+         }
+       }
+        else if (to[cr].has_extra()) to[cr].calcAbstraction();
+    }
+};
+
+
+//=================================================================================================
+// OccLists -- a class for maintaining occurence lists with lazy deletion:
+
+template<class Idx, class Vec, class Deleted>
+class OccLists
+{
+    vec<Vec>  occs;
+    vec<char> dirty;
+    vec<Idx>  dirties;
+    Deleted   deleted;
+
+ public:
+    OccLists(const Deleted& d) : deleted(d) {}
+    
+    void  init      (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); }
+    // Vec&  operator[](const Idx& idx){ return occs[toInt(idx)]; }
+    Vec&  operator[](const Idx& idx){ return occs[toInt(idx)]; }
+    Vec&  lookup    (const Idx& idx){ if (dirty[toInt(idx)]) clean(idx); return occs[toInt(idx)]; }
+
+    void  cleanAll  ();
+    void copyTo(OccLists &copy) const {
+       
+       copy.occs.growTo(occs.size());
+       for(int i = 0;i<occs.size();i++)
+           occs[i].memCopyTo(copy.occs[i]);
+       dirty.memCopyTo(copy.dirty);
+       dirties.memCopyTo(copy.dirties);
+    }
+
+    void  clean     (const Idx& idx);
+    void  smudge    (const Idx& idx){
+        if (dirty[toInt(idx)] == 0){
+            dirty[toInt(idx)] = 1;
+            dirties.push(idx);
+        }
+    }
+
+    void  clear(bool free = true){
+        occs   .clear(free);
+        dirty  .clear(free);
+        dirties.clear(free);
+    }
+};
+
+
+template<class Idx, class Vec, class Deleted>
+void OccLists<Idx,Vec,Deleted>::cleanAll()
+{
+    for (int i = 0; i < dirties.size(); i++)
+        // Dirties may contain duplicates so check here if a variable is already cleaned:
+        if (dirty[toInt(dirties[i])])
+            clean(dirties[i]);
+    dirties.clear();
+}
+
+
+template<class Idx, class Vec, class Deleted>
+void OccLists<Idx,Vec,Deleted>::clean(const Idx& idx)
+{
+    Vec& vec = occs[toInt(idx)];
+    int  i, j;
+    for (i = j = 0; i < vec.size(); i++)
+        if (!deleted(vec[i]))
+            vec[j++] = vec[i];
+    vec.shrink(i - j);
+    dirty[toInt(idx)] = 0;
+}
+
+
+//=================================================================================================
+// CMap -- a class for mapping clauses to values:
+
+
+template<class T>
+class CMap
+{
+    struct CRefHash {
+        uint32_t operator()(CRef cr) const { return (uint32_t)cr; } };
+
+    typedef Map<CRef, T, CRefHash> HashTable;
+    HashTable map;
+        
+ public:
+    // Size-operations:
+    void     clear       ()                           { map.clear(); }
+    int      size        ()                const      { return map.elems(); }
+
+    
+    // Insert/Remove/Test mapping:
+    void     insert      (CRef cr, const T& t){ map.insert(cr, t); }
+    void     growTo      (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
+    void     remove      (CRef cr)            { map.remove(cr); }
+    bool     has         (CRef cr, T& t)      { return map.peek(cr, t); }
+
+    // Vector interface (the clause 'c' must already exist):
+    const T& operator [] (CRef cr) const      { return map[cr]; }
+    T&       operator [] (CRef cr)            { return map[cr]; }
+
+    // Iteration (not transparent at all at the moment):
+    int  bucket_count() const { return map.bucket_count(); }
+    const vec<typename HashTable::Pair>& bucket(int i) const { return map.bucket(i); }
+
+    // Move contents to other map:
+    void moveTo(CMap& other){ map.moveTo(other.map); }
+
+    // TMP debug:
+    void debug(){
+        printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
+};
+
+
+/*_________________________________________________________________________________________________
+|
+|  subsumes : (other : const Clause&)  ->  Lit
+|  
+|  Description:
+|       Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
+|       by subsumption resolution.
+|  
+|    Result:
+|       lit_Error  - No subsumption or simplification
+|       lit_Undef  - Clause subsumes 'other'
+|       p          - The literal p can be deleted from 'other'
+|________________________________________________________________________________________________@*/
+inline Lit Clause::subsumes(const Clause& other) const
+{
+    //if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0)
+    //if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0))
+    assert(!header.learnt);   assert(!other.header.learnt);
+    assert(header.extra_size > 0); assert(other.header.extra_size > 0);
+    if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0)
+        return lit_Error;
+
+    Lit        ret = lit_Undef;
+    const Lit* c   = (const Lit*)(*this);
+    const Lit* d   = (const Lit*)other;
+
+    for (unsigned i = 0; i < header.size; i++) {
+        // search for c[i] or ~c[i]
+        for (unsigned j = 0; j < other.header.size; j++)
+            if (c[i] == d[j])
+                goto ok;
+            else if (ret == lit_Undef && c[i] == ~d[j]){
+                ret = c[i];
+                goto ok;
+            }
+
+        // did not find it
+        return lit_Error;
+    ok:;
+    }
+
+    return ret;
+}
+
+inline void Clause::strengthen(Lit p)
+{
+    remove(*this, p);
+    calcAbstraction();
+}
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Alg.h b/glucose-syrup/mtl/Alg.h
new file mode 100644 (file)
index 0000000..9afb455
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************************[Alg.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Alg_h
+#define Glucose_Alg_h
+
+#include "mtl/Vec.h"
+
+namespace Glucose {
+
+//=================================================================================================
+// Useful functions on vector-like types:
+
+//=================================================================================================
+// Removing and searching for elements:
+//
+
+template<class V, class T>
+static inline void remove(V& ts, const T& t)
+{
+    int j = 0;
+    for (; j < ts.size() && ts[j] != t; j++);
+    assert(j < ts.size());
+    for (; j < ts.size()-1; j++) ts[j] = ts[j+1];
+    ts.pop();
+}
+
+
+template<class V, class T>
+static inline bool find(V& ts, const T& t)
+{
+    int j = 0;
+    for (; j < ts.size() && ts[j] != t; j++);
+    return j < ts.size();
+}
+
+
+//=================================================================================================
+// Copying vectors with support for nested vector types:
+//
+
+// Base case:
+template<class T>
+static inline void copy(const T& from, T& to)
+{
+    to = from;
+}
+
+// Recursive case:
+template<class T>
+static inline void copy(const vec<T>& from, vec<T>& to, bool append = false)
+{
+    if (!append)
+        to.clear();
+    for (int i = 0; i < from.size(); i++){
+        to.push();
+        copy(from[i], to.last());
+    }
+}
+
+template<class T>
+static inline void append(const vec<T>& from, vec<T>& to){ copy(from, to, true); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Alloc.h b/glucose-syrup/mtl/Alloc.h
new file mode 100644 (file)
index 0000000..baa6095
--- /dev/null
@@ -0,0 +1,142 @@
+/*****************************************************************************************[Alloc.h]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+
+#ifndef Glucose_Alloc_h
+#define Glucose_Alloc_h
+
+#include "mtl/XAlloc.h"
+#include "mtl/Vec.h"
+
+namespace Glucose {
+
+//=================================================================================================
+// Simple Region-based memory allocator:
+
+template<class T>
+class RegionAllocator
+{
+    T*        memory;
+    uint32_t  sz;
+    uint32_t  cap;
+    uint32_t  wasted_;
+
+    void capacity(uint32_t min_cap);
+
+ public:
+    // TODO: make this a class for better type-checking?
+    typedef uint32_t Ref;
+    enum { Ref_Undef = UINT32_MAX };
+    enum { Unit_Size = sizeof(uint32_t) };
+
+    explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); }
+    ~RegionAllocator()
+    {
+        if (memory != NULL)
+            ::free(memory);
+    }
+
+
+    uint32_t size      () const      { return sz; }
+    uint32_t getCap    () const      { return cap;}
+    uint32_t wasted    () const      { return wasted_; }
+
+    Ref      alloc     (int size); 
+    void     free      (int size)    { wasted_ += size; }
+
+    // Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
+    T&       operator[](Ref r)       { assert(r >= 0 && r < sz); return memory[r]; }
+    const T& operator[](Ref r) const { assert(r >= 0 && r < sz); return memory[r]; }
+
+    T*       lea       (Ref r)       { assert(r >= 0 && r < sz); return &memory[r]; }
+    const T* lea       (Ref r) const { assert(r >= 0 && r < sz); return &memory[r]; }
+    Ref      ael       (const T* t)  { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]);
+        return  (Ref)(t - &memory[0]); }
+
+    void     moveTo(RegionAllocator& to) {
+        if (to.memory != NULL) ::free(to.memory);
+        to.memory = memory;
+        to.sz = sz;
+        to.cap = cap;
+        to.wasted_ = wasted_;
+
+        memory = NULL;
+        sz = cap = wasted_ = 0;
+    }
+
+    void copyTo(RegionAllocator& to) const {
+     //   if (to.memory != NULL) ::free(to.memory);
+        to.memory = (T*)xrealloc(to.memory, sizeof(T)*cap);
+        memcpy(to.memory,memory,sizeof(T)*cap);        
+        to.sz = sz;
+        to.cap = cap;
+        to.wasted_ = wasted_;
+    }
+
+
+
+};
+
+template<class T>
+void RegionAllocator<T>::capacity(uint32_t min_cap)
+{
+    if (cap >= min_cap) return;
+
+    uint32_t prev_cap = cap;
+    while (cap < min_cap){
+        // NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the
+        // result even by clearing the least significant bit. The resulting sequence of capacities
+        // is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when
+        // using 'uint32_t' as indices so that as much as possible of this space can be used.
+        uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1;
+        cap += delta;
+
+        if (cap <= prev_cap)
+            throw OutOfMemoryException();
+    }
+    //printf(" .. (%p) cap = %u\n", this, cap);
+
+    assert(cap > 0);
+    memory = (T*)xrealloc(memory, sizeof(T)*cap);
+}
+
+
+template<class T>
+typename RegionAllocator<T>::Ref
+RegionAllocator<T>::alloc(int size)
+{ 
+    //printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout);
+    assert(size > 0);
+    capacity(sz + size);
+
+    uint32_t prev_sz = sz;
+    sz += size;
+    
+    // Handle overflow:
+    if (sz < prev_sz)
+        throw OutOfMemoryException();
+
+    return prev_sz;
+}
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Clone.h b/glucose-syrup/mtl/Clone.h
new file mode 100644 (file)
index 0000000..c0ec225
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef Glucose_Clone_h
+#define Glucose_Clone_h
+
+
+namespace Glucose {
+
+    class Clone {
+        public:
+          virtual Clone* clone() const = 0;
+    };
+};
+
+#endif
\ No newline at end of file
diff --git a/glucose-syrup/mtl/Heap.h b/glucose-syrup/mtl/Heap.h
new file mode 100644 (file)
index 0000000..0c40c4f
--- /dev/null
@@ -0,0 +1,150 @@
+/******************************************************************************************[Heap.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Heap_h
+#define Glucose_Heap_h
+
+#include "mtl/Vec.h"
+
+namespace Glucose {
+
+//=================================================================================================
+// A heap implementation with support for decrease/increase key.
+
+
+template<class Comp>
+class Heap {
+    Comp     lt;       // The heap is a minimum-heap with respect to this comparator
+    vec<int> heap;     // Heap of integers
+    vec<int> indices;  // Each integers position (index) in the Heap
+
+    // Index "traversal" functions
+    static inline int left  (int i) { return i*2+1; }
+    static inline int right (int i) { return (i+1)*2; }
+    static inline int parent(int i) { return (i-1) >> 1; }
+
+
+
+    void percolateUp(int i)
+    {
+        int x  = heap[i];
+        int p  = parent(i);
+        
+        while (i != 0 && lt(x, heap[p])){
+            heap[i]          = heap[p];
+            indices[heap[p]] = i;
+            i                = p;
+            p                = parent(p);
+        }
+        heap   [i] = x;
+        indices[x] = i;
+    }
+
+
+    void percolateDown(int i)
+    {
+        int x = heap[i];
+        while (left(i) < heap.size()){
+            int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i);
+            if (!lt(heap[child], x)) break;
+            heap[i]          = heap[child];
+            indices[heap[i]] = i;
+            i                = child;
+        }
+        heap   [i] = x;
+        indices[x] = i;
+    }
+
+
+  public:
+    Heap(const Comp& c) : lt(c) { }
+
+    int  size      ()          const { return heap.size(); }
+    bool empty     ()          const { return heap.size() == 0; }
+    bool inHeap    (int n)     const { return n < indices.size() && indices[n] >= 0; }
+    int  operator[](int index) const { assert(index < heap.size()); return heap[index]; }
+
+
+    void decrease  (int n) { assert(inHeap(n)); percolateUp  (indices[n]); }
+    void increase  (int n) { assert(inHeap(n)); percolateDown(indices[n]); }
+
+    void copyTo(Heap& copy) const {heap.copyTo(copy.heap);indices.copyTo(copy.indices);}
+
+    // Safe variant of insert/decrease/increase:
+    void update(int n)
+    {
+        if (!inHeap(n))
+            insert(n);
+        else {
+            percolateUp(indices[n]);
+            percolateDown(indices[n]); }
+    }
+
+
+    void insert(int n)
+    {
+        indices.growTo(n+1, -1);
+        assert(!inHeap(n));
+
+        indices[n] = heap.size();
+        heap.push(n);
+        percolateUp(indices[n]); 
+    }
+
+
+    int  removeMin()
+    {
+        int x            = heap[0];
+        heap[0]          = heap.last();
+        indices[heap[0]] = 0;
+        indices[x]       = -1;
+        heap.pop();
+        if (heap.size() > 1) percolateDown(0);
+        return x; 
+    }
+
+
+    // Rebuild the heap from scratch, using the elements in 'ns':
+    void build(vec<int>& ns) {
+        for (int i = 0; i < heap.size(); i++)
+            indices[heap[i]] = -1;
+        heap.clear();
+
+        for (int i = 0; i < ns.size(); i++){
+            indices[ns[i]] = i;
+            heap.push(ns[i]); }
+
+        for (int i = heap.size() / 2 - 1; i >= 0; i--)
+            percolateDown(i);
+    }
+
+    void clear(bool dealloc = false) 
+    { 
+        for (int i = 0; i < heap.size(); i++)
+            indices[heap[i]] = -1;
+        heap.clear(dealloc); 
+    }
+};
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/IntTypes.h b/glucose-syrup/mtl/IntTypes.h
new file mode 100644 (file)
index 0000000..2d8d4e8
--- /dev/null
@@ -0,0 +1,46 @@
+/**************************************************************************************[IntTypes.h]
+Copyright (c) 2009-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_IntTypes_h
+#define Glucose_IntTypes_h
+
+#ifdef __sun
+    // Not sure if there are newer versions that support C99 headers. The
+    // needed features are implemented in the headers below though:
+
+#   include <sys/int_types.h>
+#   include <sys/int_fmtio.h>
+#   include <sys/int_limits.h>
+
+#else
+
+#   include <stdint.h>
+#   include <inttypes.h>
+
+#endif
+
+#include <limits.h>
+
+#ifndef PRIu64
+#define PRIu64 "lu"
+#define PRIi64 "ld"
+#endif
+//=================================================================================================
+
+#endif
diff --git a/glucose-syrup/mtl/Map.h b/glucose-syrup/mtl/Map.h
new file mode 100644 (file)
index 0000000..f29ae2d
--- /dev/null
@@ -0,0 +1,193 @@
+/*******************************************************************************************[Map.h]
+Copyright (c) 2006-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Map_h
+#define Glucose_Map_h
+
+#include "mtl/IntTypes.h"
+#include "mtl/Vec.h"
+
+namespace Glucose {
+
+//=================================================================================================
+// Default hash/equals functions
+//
+
+template<class K> struct Hash  { uint32_t operator()(const K& k)               const { return hash(k);  } };
+template<class K> struct Equal { bool     operator()(const K& k1, const K& k2) const { return k1 == k2; } };
+
+template<class K> struct DeepHash  { uint32_t operator()(const K* k)               const { return hash(*k);  } };
+template<class K> struct DeepEqual { bool     operator()(const K* k1, const K* k2) const { return *k1 == *k2; } };
+
+static inline uint32_t hash(uint32_t x){ return x; }
+static inline uint32_t hash(uint64_t x){ return (uint32_t)x; }
+static inline uint32_t hash(int32_t x) { return (uint32_t)x; }
+static inline uint32_t hash(int64_t x) { return (uint32_t)x; }
+
+
+//=================================================================================================
+// Some primes
+//
+
+static const int nprimes          = 25;
+static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 };
+
+//=================================================================================================
+// Hash table implementation of Maps
+//
+
+template<class K, class D, class H = Hash<K>, class E = Equal<K> >
+class Map {
+ public:
+    struct Pair { K key; D data; };
+
+ private:
+    H          hash;
+    E          equals;
+
+    vec<Pair>* table;
+    int        cap;
+    int        size;
+
+    // Don't allow copying (error prone):
+    Map<K,D,H,E>&  operator = (Map<K,D,H,E>& other) { assert(0); }
+                   Map        (Map<K,D,H,E>& other) { assert(0); }
+
+    bool    checkCap(int new_size) const { return new_size > cap; }
+
+    int32_t index  (const K& k) const { return hash(k) % cap; }
+    void   _insert (const K& k, const D& d) { 
+        vec<Pair>& ps = table[index(k)];
+        ps.push(); ps.last().key = k; ps.last().data = d; }
+
+    void    rehash () {
+        const vec<Pair>* old = table;
+
+        int old_cap = cap;
+        int newsize = primes[0];
+        for (int i = 1; newsize <= cap && i < nprimes; i++)
+           newsize = primes[i];
+
+        table = new vec<Pair>[newsize];
+        cap   = newsize;
+
+        for (int i = 0; i < old_cap; i++){
+            for (int j = 0; j < old[i].size(); j++){
+                _insert(old[i][j].key, old[i][j].data); }}
+
+        delete [] old;
+
+        // printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize);
+    }
+
+    
+ public:
+
+    Map () : table(NULL), cap(0), size(0) {}
+    Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){}
+    ~Map () { delete [] table; }
+
+    // PRECONDITION: the key must already exist in the map.
+    const D& operator [] (const K& k) const
+    {
+        assert(size != 0);
+        const D*         res = NULL;
+        const vec<Pair>& ps  = table[index(k)];
+        for (int i = 0; i < ps.size(); i++)
+            if (equals(ps[i].key, k))
+                res = &ps[i].data;
+        assert(res != NULL);
+        return *res;
+    }
+
+    // PRECONDITION: the key must already exist in the map.
+    D& operator [] (const K& k)
+    {
+        assert(size != 0);
+        D*         res = NULL;
+        vec<Pair>& ps  = table[index(k)];
+        for (int i = 0; i < ps.size(); i++)
+            if (equals(ps[i].key, k))
+                res = &ps[i].data;
+        assert(res != NULL);
+        return *res;
+    }
+
+    // PRECONDITION: the key must *NOT* exist in the map.
+    void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; }
+    bool peek   (const K& k, D& d) const {
+        if (size == 0) return false;
+        const vec<Pair>& ps = table[index(k)];
+        for (int i = 0; i < ps.size(); i++)
+            if (equals(ps[i].key, k)){
+                d = ps[i].data;
+                return true; } 
+        return false;
+    }
+
+    bool has   (const K& k) const {
+        if (size == 0) return false;
+        const vec<Pair>& ps = table[index(k)];
+        for (int i = 0; i < ps.size(); i++)
+            if (equals(ps[i].key, k))
+                return true;
+        return false;
+    }
+
+    // PRECONDITION: the key must exist in the map.
+    void remove(const K& k) {
+        assert(table != NULL);
+        vec<Pair>& ps = table[index(k)];
+        int j = 0;
+        for (; j < ps.size() && !equals(ps[j].key, k); j++);
+        assert(j < ps.size());
+        ps[j] = ps.last();
+        ps.pop();
+        size--;
+    }
+
+    void clear  () {
+        cap = size = 0;
+        delete [] table;
+        table = NULL;
+    }
+
+    int  elems() const { return size; }
+    int  bucket_count() const { return cap; }
+
+    // NOTE: the hash and equality objects are not moved by this method:
+    void moveTo(Map& other){
+        delete [] other.table;
+
+        other.table = table;
+        other.cap   = cap;
+        other.size  = size;
+
+        table = NULL;
+        size = cap = 0;
+    }
+
+    // NOTE: given a bit more time, I could make a more C++-style iterator out of this:
+    const vec<Pair>& bucket(int i) const { return table[i]; }
+};
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Queue.h b/glucose-syrup/mtl/Queue.h
new file mode 100644 (file)
index 0000000..c71e45b
--- /dev/null
@@ -0,0 +1,80 @@
+/*****************************************************************************************[Queue.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Queue_h
+#define Glucose_Queue_h
+
+#include "mtl/Vec.h"
+
+namespace Glucose {
+
+//=================================================================================================
+
+template<class T>
+class Queue {
+    vec<T>  buf;
+    int     first;
+    int     end;
+
+public:
+    typedef T Key;
+
+    Queue() : buf(1), first(0), end(0) {}
+
+    void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; }
+    int  size  () const { return (end >= first) ? end - first : end - first + buf.size(); }
+
+    
+    
+    const T& operator [] (int index) const  { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
+    T&       operator [] (int index)        { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
+
+    T    peek  () const { assert(first != end); return buf[first]; }
+    void pop   () { assert(first != end); first++; if (first == buf.size()) first = 0; }
+    
+    
+    void copyTo(Queue<T>& copy) const {
+        copy.first = first;
+        copy.end = end;
+        buf.memCopyTo(copy.buf);
+    }
+    
+    
+    void insert(T elem) {   // INVARIANT: buf[end] is always unused
+        buf[end++] = elem;
+        if (end == buf.size()) end = 0;
+        if (first == end){  // Resize:
+            vec<T>  tmp((buf.size()*3 + 1) >> 1);
+            //**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0);
+            int     i = 0;
+            for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j];
+            for (int j = 0    ; j < end       ; j++) tmp[i++] = buf[j];
+            first = 0;
+            end   = buf.size();
+            tmp.moveTo(buf);
+        }
+    }
+};
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Sort.h b/glucose-syrup/mtl/Sort.h
new file mode 100644 (file)
index 0000000..50cb448
--- /dev/null
@@ -0,0 +1,98 @@
+/******************************************************************************************[Sort.h]
+Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Sort_h
+#define Glucose_Sort_h
+
+#include "mtl/Vec.h"
+
+//=================================================================================================
+// Some sorting algorithms for vec's
+
+
+namespace Glucose {
+
+template<class T>
+struct LessThan_default {
+    bool operator () (T x, T y) { return x < y; }
+};
+
+
+template <class T, class LessThan>
+void selectionSort(T* array, int size, LessThan lt)
+{
+    int     i, j, best_i;
+    T       tmp;
+
+    for (i = 0; i < size-1; i++){
+        best_i = i;
+        for (j = i+1; j < size; j++){
+            if (lt(array[j], array[best_i]))
+                best_i = j;
+        }
+        tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+    }
+}
+template <class T> static inline void selectionSort(T* array, int size) {
+    selectionSort(array, size, LessThan_default<T>()); }
+
+template <class T, class LessThan>
+void sort(T* array, int size, LessThan lt)
+{
+    if (size <= 15)
+        selectionSort(array, size, lt);
+
+    else{
+        T           pivot = array[size / 2];
+        T           tmp;
+        int         i = -1;
+        int         j = size;
+
+        for(;;){
+            do i++; while(lt(array[i], pivot));
+            do j--; while(lt(pivot, array[j]));
+
+            if (i >= j) break;
+
+            tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+        }
+
+        sort(array    , i     , lt);
+        sort(&array[i], size-i, lt);
+    }
+}
+template <class T> static inline void sort(T* array, int size) {
+    sort(array, size, LessThan_default<T>()); }
+
+
+//=================================================================================================
+// For 'vec's:
+
+
+template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) {
+    sort((T*)v, v.size(), lt); }
+template <class T> void sort(vec<T>& v) {
+    sort(v, LessThan_default<T>()); }
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/Vec.h b/glucose-syrup/mtl/Vec.h
new file mode 100644 (file)
index 0000000..954eef7
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************************************************[Vec.h]
+Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Vec_h
+#define Glucose_Vec_h
+
+#include <assert.h>
+#include <new>
+
+#include "mtl/IntTypes.h"
+#include "mtl/XAlloc.h"
+#include<string.h>
+
+namespace Glucose {
+
+//=================================================================================================
+// Automatically resizable arrays
+//
+// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc)
+
+template<class T>
+class vec {
+    T*  data;
+    int sz;
+    int cap;
+
+    // Don't allow copying (error prone):
+    vec<T>&  operator = (vec<T>& other) { assert(0); return *this; }
+             vec        (vec<T>& other) { assert(0); }
+             
+    // Helpers for calculating next capacity:
+    static inline int  imax   (int x, int y) { int mask = (y-x) >> (sizeof(int)*8-1); return (x&mask) + (y&(~mask)); }
+    //static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; }
+    static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; }
+
+public:
+    // Constructors:
+    vec()                       : data(NULL) , sz(0)   , cap(0)    { }
+    explicit vec(int size)      : data(NULL) , sz(0)   , cap(0)    { growTo(size); }
+    vec(int size, const T& pad) : data(NULL) , sz(0)   , cap(0)    { growTo(size, pad); }
+   ~vec()                                                          { clear(true); }
+
+    // Pointer to first element:
+    operator T*       (void)           { return data; }
+
+    // Size operations:
+    int      size     (void) const     { return sz; }
+    void     shrink   (int nelems)     { assert(nelems <= sz); for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); }
+    void     shrink_  (int nelems)     { assert(nelems <= sz); sz -= nelems; }
+    int      capacity (void) const     { return cap; }
+    void     capacity (int min_cap);
+    void     growTo   (int size);
+    void     growTo   (int size, const T& pad);
+    void     clear    (bool dealloc = false);
+
+    // Stack interface:
+    void     push  (void)              { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; }
+    void     push  (const T& elem)     { if (sz == cap) capacity(sz+1); data[sz++] = elem; }
+    void     push_ (const T& elem)     { assert(sz < cap); data[sz++] = elem; }
+    void     pop   (void)              { assert(sz > 0); sz--, data[sz].~T(); }
+    // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but
+    // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not
+    // happen given the way capacities are calculated (below). Essentially, all capacities are
+    // even, but INT_MAX is odd.
+
+    const T& last  (void) const        { return data[sz-1]; }
+    T&       last  (void)              { return data[sz-1]; }
+
+    // Vector interface:
+    const T& operator [] (int index) const { return data[index]; }
+    T&       operator [] (int index)       { return data[index]; }
+
+    // Duplicatation (preferred instead):
+    void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; }
+    void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
+    void memCopyTo(vec<T>& copy) const{
+        copy.capacity(cap);
+        copy.sz = sz;
+        memcpy(copy.data,data,sizeof(T)*cap);
+    }
+
+};
+
+
+template<class T>
+void vec<T>::capacity(int min_cap) {
+    if (cap >= min_cap) return;
+    int add = imax((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1);   // NOTE: grow by approximately 3/2
+    if (add > INT_MAX - cap || ((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM)
+        throw OutOfMemoryException();
+ }
+
+
+template<class T>
+void vec<T>::growTo(int size, const T& pad) {
+    if (sz >= size) return;
+    capacity(size);
+    for (int i = sz; i < size; i++) data[i] = pad;
+    sz = size; }
+
+
+template<class T>
+void vec<T>::growTo(int size) {
+    if (sz >= size) return;
+    capacity(size);
+    for (int i = sz; i < size; i++) new (&data[i]) T();
+    sz = size; }
+
+
+template<class T>
+void vec<T>::clear(bool dealloc) {
+    if (data != NULL){
+        for (int i = 0; i < sz; i++) data[i].~T();
+        sz = 0;
+        if (dealloc) free(data), data = NULL, cap = 0; } }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/XAlloc.h b/glucose-syrup/mtl/XAlloc.h
new file mode 100644 (file)
index 0000000..f8ca4fe
--- /dev/null
@@ -0,0 +1,47 @@
+/****************************************************************************************[XAlloc.h]
+Copyright (c) 2009-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+
+#ifndef Glucose_XAlloc_h
+#define Glucose_XAlloc_h
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace Glucose {
+
+//=================================================================================================
+// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing:
+
+class OutOfMemoryException{};
+static inline void* xrealloc(void *ptr, size_t size)
+{
+    void* mem = realloc(ptr, size);
+    if (mem == NULL && errno == ENOMEM){
+        throw OutOfMemoryException();
+    }else {
+        return mem;
+       }
+}
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/mtl/config.mk b/glucose-syrup/mtl/config.mk
new file mode 100644 (file)
index 0000000..b5c36fc
--- /dev/null
@@ -0,0 +1,6 @@
+##
+##  This file is for system specific configurations. For instance, on
+##  some systems the path to zlib needs to be added. Example:
+##
+##  CFLAGS += -I/usr/local/include
+##  LFLAGS += -L/usr/local/lib
diff --git a/glucose-syrup/mtl/template.mk b/glucose-syrup/mtl/template.mk
new file mode 100644 (file)
index 0000000..6727559
--- /dev/null
@@ -0,0 +1,107 @@
+##
+##  Template makefile for Standard, Profile, Debug, Release, and Release-static versions
+##
+##    eg: "make rs" for a statically linked release version.
+##        "make d"  for a debug version (no optimizations).
+##        "make"    for the standard version (optimized, but with debug information and assertions active)
+
+PWD        = $(shell pwd)
+EXEC      ?= $(notdir $(PWD))
+
+CSRCS      = $(wildcard $(PWD)/*.cc) 
+DSRCS      = $(foreach dir, $(DEPDIR), $(filter-out $(MROOT)/$(dir)/Main.cc, $(wildcard $(MROOT)/$(dir)/*.cc)))
+CHDRS      = $(wildcard $(PWD)/*.h)
+COBJS      = $(CSRCS:.cc=.o) $(DSRCS:.cc=.o)
+
+PCOBJS     = $(addsuffix p,  $(COBJS))
+DCOBJS     = $(addsuffix d,  $(COBJS))
+RCOBJS     = $(addsuffix r,  $(COBJS))
+
+#CXX        ?= /usr/gcc-/bin/g++-4.7.0
+CXX       ?= g++
+CFLAGS    ?= -Wall -Wno-parentheses -std=c++11
+LFLAGS    ?= -Wall -lpthread 
+
+COPTIMIZE ?= -O3
+
+CFLAGS    += -I$(MROOT) -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS
+LFLAGS    += -lz
+
+.PHONY : s p d r rs clean 
+
+s:     $(EXEC)
+p:     $(EXEC)_profile
+d:     $(EXEC)_debug
+r:     $(EXEC)_release
+rs:    $(EXEC)_static
+
+libs:  lib$(LIB)_standard.a
+libp:  lib$(LIB)_profile.a
+libd:  lib$(LIB)_debug.a
+libr:  lib$(LIB)_release.a
+
+## Compile options
+%.o:                   CFLAGS +=$(COPTIMIZE) -g -D DEBUG
+%.op:                  CFLAGS +=$(COPTIMIZE) -pg -g -D NDEBUG
+%.od:                  CFLAGS +=-O0 -g -D DEBUG
+%.or:                  CFLAGS +=$(COPTIMIZE) -g -D NDEBUG
+
+## Link options
+$(EXEC):               LFLAGS += -g
+$(EXEC)_profile:       LFLAGS += -g -pg
+$(EXEC)_debug:         LFLAGS += -g
+#$(EXEC)_release:      LFLAGS += ...
+$(EXEC)_static:                LFLAGS += --static
+
+## Dependencies
+$(EXEC):               $(COBJS)
+$(EXEC)_profile:       $(PCOBJS)
+$(EXEC)_debug:         $(DCOBJS)
+$(EXEC)_release:       $(RCOBJS)
+$(EXEC)_static:                $(RCOBJS)
+
+lib$(LIB)_standard.a:  $(filter-out */Main.o,  $(COBJS))
+lib$(LIB)_profile.a:   $(filter-out */Main.op, $(PCOBJS))
+lib$(LIB)_debug.a:     $(filter-out */Main.od, $(DCOBJS))
+lib$(LIB)_release.a:   $(filter-out */Main.or, $(RCOBJS))
+
+
+## Build rule
+%.o %.op %.od %.or:    %.cc
+       @echo Compiling: $(subst $(MROOT)/,,$@)
+       @$(CXX) $(CFLAGS) -c -o $@ $<
+
+## Linking rules (standard/profile/debug/release)
+$(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static:
+       @echo Linking: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
+       @$(CXX) $^ $(LFLAGS) -o $@
+
+## Library rules (standard/profile/debug/release)
+lib$(LIB)_standard.a lib$(LIB)_profile.a lib$(LIB)_release.a lib$(LIB)_debug.a:
+       @echo Making library: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
+       @$(AR) -rcsv $@ $^
+
+## Library Soft Link rule:
+libs libp libd libr:
+       @echo "Making Soft Link: $^ -> lib$(LIB).a"
+       @ln -sf $^ lib$(LIB).a
+
+## Clean rule
+clean:
+       @rm -f $(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static \
+         $(COBJS) $(PCOBJS) $(DCOBJS) $(RCOBJS) *.core depend.mk 
+
+## Make dependencies
+depend.mk: $(CSRCS) $(CHDRS)
+       @echo Making dependencies
+       @$(CXX) $(CFLAGS) -I$(MROOT) \
+          $(CSRCS) -MM | sed 's|\(.*\):|$(PWD)/\1 $(PWD)/\1r $(PWD)/\1d $(PWD)/\1p:|' > depend.mk
+       @for dir in $(DEPDIR); do \
+             if [ -r $(MROOT)/$${dir}/depend.mk ]; then \
+                 echo Depends on: $${dir}; \
+                 cat $(MROOT)/$${dir}/depend.mk >> depend.mk; \
+             fi; \
+         done
+
+-include $(MROOT)/mtl/config.mk
+-include depend.mk
diff --git a/glucose-syrup/parallel/ClausesBuffer.cc b/glucose-syrup/parallel/ClausesBuffer.cc
new file mode 100644 (file)
index 0000000..5b18767
--- /dev/null
@@ -0,0 +1,235 @@
+/**********************************************************************************[ClausesBuffer.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+/* ClausesBuffer
+ *
+ * This class is responsible for exchanging clauses between threads.
+ * It is based on a fixed-length FIFO array of literals.
+ * If the FIFO is full, then old clauses are removed (even if it was not yet sent to all threads)
+ *
+ * a clause " l1 l2 l3" is pushed in the FIFO with the following 6 unsigned integers
+ * 3 nseen origin l1 l2 l3
+ * + 3 is the size of the pushed clause
+ * + nseen is the number of thread which imported this clause (initialized with nthreads-1)
+ *       (when set to 0, the clause is removed from the fifo)
+ * + origin is the thread id of the thread which added this clause to the fifo
+ * + l1 l2 l3 are the literals of the clause
+ *
+ * **********************************************************************************************
+ * **CAREFUL** This class is not thread-safe. In glucose-syrup, the SharedCompanion is 
+ * responsible for ensuring atomicity of main functions
+ * **********************************************************************************************
+ *
+ * */
+
+#include "parallel/ClausesBuffer.h"
+
+//=================================================================================================
+
+using namespace Glucose;
+
+extern BoolOption opt_whenFullRemoveOlder;
+extern IntOption  opt_fifoSizeByCore;
+
+// index : size clause
+// index + 1 : nbSeen
+// index + 2 : threadId
+// index + 3 : .. index + 3 + size : Lit of clause
+ClausesBuffer::ClausesBuffer(int _nbThreads, unsigned int _maxsize) : first(0), last(_maxsize-1),  
+    maxsize(_maxsize), queuesize(0), 
+    removedClauses(0),
+    forcedRemovedClauses(0), nbThreads(_nbThreads), 
+    whenFullRemoveOlder(opt_whenFullRemoveOlder), fifoSizeByCore(opt_fifoSizeByCore) {
+       lastOfThread.growTo(_nbThreads);
+       for(int i=0;i<nbThreads;i++) lastOfThread[i] = _maxsize-1;
+       elems.growTo(maxsize);
+} 
+
+ClausesBuffer::ClausesBuffer() : first(0), last(0), maxsize(0), queuesize(0), removedClauses(0), forcedRemovedClauses(0), nbThreads(0),
+                                 whenFullRemoveOlder(opt_whenFullRemoveOlder), fifoSizeByCore(opt_fifoSizeByCore) {}
+
+void ClausesBuffer::setNbThreads(int _nbThreads) {
+    unsigned int _maxsize = fifoSizeByCore*_nbThreads;
+    last = _maxsize -1;
+    maxsize = _maxsize;
+    nbThreads = _nbThreads;
+    lastOfThread.growTo(_nbThreads);
+    for(int i=0;i<nbThreads;i++) lastOfThread[i] = _maxsize-1;
+    elems.growTo(maxsize);
+}
+
+uint32_t ClausesBuffer::getCap() {
+    return elems.capacity();
+}
+inline unsigned int ClausesBuffer::nextIndex(unsigned int i) {
+    i++;
+    if (i == maxsize)
+       return 0;
+    return i;
+}
+
+inline unsigned int ClausesBuffer::addIndex(unsigned int i, unsigned int a) {
+    i += a;
+    if (i >= maxsize)
+       return i - maxsize;
+    return i;
+}
+
+void ClausesBuffer::removeLastClause() {
+    assert(queuesize > 0);
+    do {
+       unsigned int size = (unsigned int) elems[nextIndex(last)];
+       unsigned int nextlast = addIndex(last, size+headerSize);
+
+       for(int i=0;i<nbThreads;i++) {
+           if (lastOfThread[i] == last)
+               lastOfThread[i] = nextlast;
+       }
+
+       // printf("Removing clause starting at %d of size %d.\n",nextIndex(last), size);
+       for(unsigned int i=0;i<size+headerSize;i++) {
+           last = nextIndex(last);
+           assert(queuesize > 0);
+           queuesize --;
+       }       
+       removedClauses ++;
+       assert(last >= 0);
+       assert(last < maxsize);
+       assert(last == nextlast);
+    } while (queuesize > 0 && (elems[addIndex(last,2)] == 0));         
+
+}
+
+
+// Pushes a single uint to the fifo
+inline void ClausesBuffer::noCheckPush(uint32_t x) {
+    elems[first] = x;
+    first = nextIndex(first);
+}
+
+// Pops a single uint from the fifo
+inline uint32_t ClausesBuffer::noCheckPop(uint32_t & index) {
+    index = nextIndex(index);
+    uint32_t ret = elems[index];
+    return ret;
+}
+
+
+
+// Return true if the clause was succesfully added
+bool ClausesBuffer::pushClause(int threadId, Clause & c) {
+    if (!whenFullRemoveOlder && (queuesize + c.size() + headerSize >= maxsize))
+       return false; // We need to remove some old clauses
+    while (queuesize + c.size() + headerSize >= maxsize) { // We need to remove some old clauses
+       forcedRemovedClauses ++;
+       removeLastClause();
+       assert(queuesize > 0);
+    }
+    noCheckPush(c.size());
+    noCheckPush(nbThreads>1?nbThreads-1:1);
+    noCheckPush(threadId);
+    for(int i=0;i<c.size();i++)
+       noCheckPush(toInt(c[i]));
+    queuesize += c.size()+headerSize;
+    return true;
+    //  printf(" -> (%d, %d)\n", first, last);
+}
+
+bool ClausesBuffer::getClause(int threadId, int & threadOrigin, vec<Lit> & resultClause,  bool firstFound) {
+    assert(lastOfThread.size() > threadId);
+    unsigned int thislast = lastOfThread[threadId];
+    assert(!firstFound || thislast == last); // FIXME: Gilles has this assertion on his cluster
+
+    // Early exiting
+    if (nextIndex(thislast) == first) return false;
+
+    if ( ( thislast < last && last < first) ||
+           ( first < thislast && thislast < last ) ||
+           ( last < first && first < thislast) ) {
+       // Special case where last has moved and lastOfThread[threadId] is no more valid (is behind)
+       thislast = last; 
+    }
+    assert(!firstFound);
+    // Go to next clause for this thread id
+    if (!firstFound) { 
+       while (nextIndex(thislast) != first && elems[addIndex(thislast,3)] == ((unsigned int)threadId)) { // 3 = 2 + 1 
+           thislast = addIndex(thislast, elems[nextIndex(thislast)] + headerSize); // 
+           assert(thislast >= 0);
+           assert(thislast < maxsize);
+       }
+       assert(nextIndex(thislast)==first || elems[addIndex(thislast,3)] != (unsigned int)threadId);
+    }
+
+    if (nextIndex(thislast) == first) {
+       lastOfThread[threadId] = thislast;
+       return false;
+    }  
+    assert(elems[addIndex(thislast,3)] != ((unsigned int) threadId));
+    unsigned int previouslast = thislast;
+    bool removeAfter = false;
+    int csize = noCheckPop(thislast);
+    removeAfter = (--elems[addIndex(thislast,1)] == 0); // We are sure this is not one of our own clause
+    thislast = nextIndex(thislast); // Skips the removeAfter fieldr
+    threadOrigin = noCheckPop(thislast);
+    assert(threadOrigin != threadId);
+    resultClause.clear();
+    for(int i=0;i<csize;i++) {
+       resultClause.push(toLit(noCheckPop(thislast)));
+    }
+    if (last == previouslast && removeAfter) {
+       removeLastClause();
+       thislast = last;
+    }
+    lastOfThread[threadId] = thislast;
+    return true;
+}
+
+
+//=================================================================================================
+
diff --git a/glucose-syrup/parallel/ClausesBuffer.h b/glucose-syrup/parallel/ClausesBuffer.h
new file mode 100644 (file)
index 0000000..171506d
--- /dev/null
@@ -0,0 +1,114 @@
+/***************************************************************************************[ClausesBuffer.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#ifndef ClausesBuffer_h 
+#define ClausesBuffer_h
+
+#include "mtl/Vec.h"
+#include "core/SolverTypes.h"
+#include "core/Solver.h"
+
+//=================================================================================================
+
+namespace Glucose {
+    // index : size clause
+    // index + 1 : nbSeen
+    // index + 2 : threadId
+    // index + 3 : .. index + 3 + size : Lit of clause
+    class ClausesBuffer {
+       vec<uint32_t>  elems;
+       unsigned int     first;
+       unsigned int     last;
+       unsigned int     maxsize;
+       unsigned int     queuesize; // Number of current elements (must be < maxsize !)
+       unsigned int     removedClauses;
+       unsigned int     forcedRemovedClauses;
+        static const int  headerSize = 3;
+       int       nbThreads;
+       bool      whenFullRemoveOlder;
+       unsigned int fifoSizeByCore;
+       vec<unsigned int> lastOfThread; // Last value for a thread 
+
+       public:
+       ClausesBuffer(int _nbThreads, unsigned int _maxsize);
+       ClausesBuffer();
+
+       void setNbThreads(int _nbThreads);
+       unsigned int nextIndex(unsigned int i);
+       unsigned int addIndex(unsigned int i, unsigned int a); 
+       void removeLastClause(); 
+          
+       void noCheckPush(uint32_t x);
+       uint32_t noCheckPop(unsigned int & index);
+
+       // Return true if the clause was succesfully added
+        bool pushClause(int threadId, Clause & c);
+        bool getClause(int threadId, int & threadOrigin, vec<Lit> & resultClause, bool firstFound = false); 
+       
+       int maxSize() const {return maxsize;}
+        uint32_t getCap();
+       void growTo(int size) {
+           assert(0); // Not implemented (essentially for efficiency reasons)
+           elems.growTo(size); 
+           first=0; maxsize=size; queuesize = 0;last = 0;
+           for(int i=0;i<size;i++) elems[i]=0; 
+       }
+
+       void fastclear() {first = 0; last = 0; queuesize=0; } 
+
+       int  size(void)    { return queuesize; }
+
+       void clear(bool dealloc = false)   { elems.clear(dealloc); first = 0; maxsize=0; queuesize=0;}
+       inline  int  toInt     (Lit p)              { return p.x; } 
+
+    };
+}
+//=================================================================================================
+
+#endif
diff --git a/glucose-syrup/parallel/Main.cc b/glucose-syrup/parallel/Main.cc
new file mode 100644 (file)
index 0000000..d3ae7f7
--- /dev/null
@@ -0,0 +1,254 @@
+/***************************************************************************************[Main.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include <errno.h>
+
+#include <signal.h>
+#include <zlib.h>
+
+
+#include "utils/System.h"
+#include "utils/ParseUtils.h"
+#include "utils/Options.h"
+#include "core/Dimacs.h"
+#include "core/SolverTypes.h"
+
+#include "simp/SimpSolver.h"
+#include "parallel/ParallelSolver.h"
+#include "parallel/MultiSolvers.h"
+
+using namespace Glucose;
+
+
+
+static MultiSolvers* pmsolver;
+
+// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case
+// for this feature of the Solver as it may take longer than an immediate call to '_exit()'.
+//static void SIGINT_interrupt(int signum) { pmsolver->interrupt(); }
+
+
+// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls
+// destructors and may cause deadlocks if a malloc/free function happens to be running (these
+// functions are guarded by locks for multithreaded use).
+static void SIGINT_exit(int signum) {
+    printf("\n"); printf("*** INTERRUPTED ***\n");
+    if (pmsolver->verbosity() > 0){
+        pmsolver->printFinalStats();
+        printf("\n"); printf("*** INTERRUPTED ***\n"); }
+    _exit(1); }
+
+
+//=================================================================================================
+// Main:
+
+
+int main(int argc, char** argv)
+{
+    double realTimeStart = realTime();
+  printf("c\nc This is glucose-syrup 4.0 (glucose in many threads) --  based on MiniSAT (Many thanks to MiniSAT team)\nc\n");
+    try {
+        setUsageHelp("c USAGE: %s [options] <input-file> <result-output-file>\n\n  where input may be either in plain or gzipped DIMACS.\n");
+        // printf("This is MiniSat 2.0 beta\n");
+        
+#if defined(__linux__)
+        fpu_control_t oldcw, newcw;
+        _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
+        printf("c WARNING: for repeatability, setting FPU to use double precision\n");
+#endif
+        // Extra options:
+        //
+        IntOption    verb   ("MAIN", "verb",   "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2));
+        BoolOption   mod   ("MAIN", "model",   "show model.", false);
+        IntOption    vv  ("MAIN", "vv",   "Verbosity every vv conflicts", 10000, IntRange(1,INT32_MAX));
+        IntOption    cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX));
+        IntOption    mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX));
+        
+        parseOptions(argc, argv, true);
+
+       MultiSolvers msolver;
+        pmsolver = & msolver;
+        msolver.setVerbosity(verb);
+        msolver.setVerbEveryConflicts(vv);
+        msolver.setShowModel(mod);
+
+        double initial_time = cpuTime();
+
+               // Use signal handlers that forcibly quit until the solver will be able to respond to
+        // interrupts:
+       signal(SIGINT, SIGINT_exit);
+        signal(SIGXCPU,SIGINT_exit);
+
+        // Set limit on CPU-time:
+        if (cpu_lim != INT32_MAX){
+            rlimit rl;
+            getrlimit(RLIMIT_CPU, &rl);
+            if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){
+                rl.rlim_cur = cpu_lim;
+                if (setrlimit(RLIMIT_CPU, &rl) == -1)
+                    printf("c WARNING! Could not set resource limit: CPU-time.\n");
+            } }
+
+        // Set limit on virtual memory:
+        if (mem_lim != INT32_MAX){
+            rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024;
+            rlimit rl;
+            getrlimit(RLIMIT_AS, &rl);
+            if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
+                rl.rlim_cur = new_mem_lim;
+                if (setrlimit(RLIMIT_AS, &rl) == -1)
+                    printf("c WARNING! Could not set resource limit: Virtual memory.\n");
+            } }
+        
+        if (argc == 1)
+            printf("c Reading from standard input... Use '--help' for help.\n");
+        
+        gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb");
+        if (in == NULL)
+            printf("c ERROR! Could not open file: %s\n", argc == 1 ? "<stdin>" : argv[1]), exit(1);
+        
+        if (msolver.verbosity() > 0){
+            printf("c ========================================[ Problem Statistics ]===========================================\n");
+            printf("c |                                                                                                       |\n"); }
+        
+        parse_DIMACS(in, msolver);
+        gzclose(in);
+        
+
+       
+        FILE* res = (argc >= 3) ? fopen(argv[argc-1], "wb") : NULL;
+
+        if (msolver.verbosity() > 0){
+            printf("c |  Number of variables:  %12d                                                                   |\n", msolver.nVars());
+            printf("c |  Number of clauses:    %12d                                                                   |\n", msolver.nClauses()); }
+        
+        double parsed_time = cpuTime();
+        if (msolver.verbosity() > 0){
+            printf("c |  Parse time:           %12.2f s                                                                 |\n", parsed_time - initial_time);
+            printf("c |                                                                                                       |\n"); }
+        // Change to signal-handlers that will only notify the solver and allow it to terminate
+        // voluntarily:
+        //signal(SIGINT, SIGINT_interrupt);
+        //signal(SIGXCPU,SIGINT_interrupt);
+        
+       int ret2 = msolver.simplify();          
+        if(ret2) 
+          msolver.eliminate();
+        double simplified_time = cpuTime();
+        if (msolver.verbosity() > 0){
+            printf("c |  Simplification time:  %12.2f s                                                                 |\n", simplified_time - parsed_time);
+            printf("c |                                                                                                       |\n"); }
+
+        if (!ret2 || !msolver.okay()){
+            //if (S.certifiedOutput != NULL) fprintf(S.certifiedOutput, "0\n"), fclose(S.certifiedOutput);
+            if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res);
+            if (msolver.verbosity() > 0){
+               printf("c =========================================================================================================\n");
+                printf("Solved by unit propagation\n"); 
+               printf("c real time : %g s\n", realTime() - realTimeStart);
+               printf("c cpu time  : %g s\n", cpuTime());
+                printf("\n"); }
+            printf("s UNSATISFIABLE\n");
+            exit(20);
+        }
+
+      //  vec<Lit> dummy;
+        lbool ret = msolver.solve();
+       
+       
+        printf("c\n");
+       printf("c real time : %g s\n", realTime() - realTimeStart);
+       printf("c cpu time  : %g s\n", cpuTime());
+        if (msolver.verbosity() > 0){
+            msolver.printFinalStats();
+            printf("\n"); }
+
+       //-------------- Result is put in a external file
+       /* I must admit I have to print the model of one thread... But which one? FIXME !!
+         if (res != NULL){  
+         if (ret == l_True){
+           fprintf(res, "SAT\n");
+           for (int i = 0; i < S.nVars(); i++)
+             if (S.model[i] != l_Undef)
+               fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
+           fprintf(res, " 0\n");
+         }else if (ret == l_False)
+           fprintf(res, "UNSAT\n");
+         else
+           fprintf(res, "INDET\n");
+         fclose(res);
+       
+       //-------------- Want certified output
+        } else { 
+       */
+         printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s INDETERMINATE\n");
+         
+         if(msolver.getShowModel() && ret==l_True) {
+           printf("v ");
+           for (int i = 0; i < msolver.model.size() ; i++)
+             if (msolver.model[i] != l_Undef)
+               printf("%s%s%d", (i==0)?"":" ", (msolver.model[i]==l_True)?"":"-", i+1);
+           printf(" 0\n");
+         }
+
+     
+    
+#ifdef NDEBUG
+        exit(ret == l_True ? 10 : ret == l_False ? 20 : 0);     // (faster than "return", which will invoke the destructor for 'Solver')
+#else
+        return (ret == l_True ? 10 : ret == l_False ? 20 : 0);
+#endif
+    } catch (OutOfMemoryException&){
+      printf("c ===================================================================================================\n");
+        printf("INDETERMINATE\n");
+        exit(0);
+    }
+}
diff --git a/glucose-syrup/parallel/Makefile b/glucose-syrup/parallel/Makefile
new file mode 100644 (file)
index 0000000..0da6c25
--- /dev/null
@@ -0,0 +1,4 @@
+EXEC      = glucose-syrup
+DEPDIR    = mtl utils core simp
+MROOT = $(PWD)/..
+include $(MROOT)/mtl/template.mk
diff --git a/glucose-syrup/parallel/MultiSolvers.cc b/glucose-syrup/parallel/MultiSolvers.cc
new file mode 100644 (file)
index 0000000..b0c1949
--- /dev/null
@@ -0,0 +1,543 @@
+/***************************************************************************************[MultiSolvers.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include <pthread.h>
+#include "parallel/MultiSolvers.h"
+#include "mtl/Sort.h"
+#include "utils/System.h"
+#include "simp/SimpSolver.h"
+#include <errno.h>
+#include <string.h>
+#include "parallel/SolverConfiguration.h"
+
+using namespace Glucose;
+
+extern const char* _parallel ;
+extern const char* _cunstable;
+// Options at the parallel solver level
+static IntOption opt_nbsolversmultithreads (_parallel, "nthreads", "Number of core threads for syrup (0 for automatic)", 0);
+static IntOption opt_maxnbsolvers (_parallel, "maxnbthreads", "Maximum number of core threads to ask for (when nbthreads=0)", 4);
+static IntOption opt_maxmemory    (_parallel, "maxmemory", "Maximum memory to use (in Mb, 0 for no software limit)", 3000);
+static IntOption opt_statsInterval (_parallel, "statsinterval", "Seconds (real time) between two stats reports", 5);
+//
+// Shared with ClausesBuffer.cc
+BoolOption opt_whenFullRemoveOlder (_parallel, "removeolder", "When the FIFO for exchanging clauses between threads is full, remove older clauses", false);
+IntOption opt_fifoSizeByCore(_parallel, "fifosize", "Size of the FIFO structure for exchanging clauses between threads, by threads", 100000);
+//
+// Shared options with Solver.cc 
+BoolOption    opt_dontExportDirectReusedClauses (_cunstable, "reusedClauses",    "Don't export directly reused clauses", false);
+BoolOption    opt_plingeling (_cunstable, "plingeling",    "plingeling strategy for sharing clauses (exploratory feature)", false);
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static inline double cpuTime(void) {
+    struct rusage ru;
+    getrusage(RUSAGE_SELF, &ru);
+return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
+
+
+void MultiSolvers::informEnd(lbool res) {
+  result = res;
+  pthread_cond_broadcast(&cfinished);
+}
+
+MultiSolvers::MultiSolvers(ParallelSolver *s):
+  ok (true)
+  , maxnbthreads(4), nbthreads(opt_nbsolversmultithreads), nbsolvers(opt_nbsolversmultithreads)
+  , nbcompanions(4), nbcompbysolver(2)
+  , allClonesAreBuilt(0)
+  , showModel(false)
+  , winner(-1)
+  , var_decay(1 / 0.95), clause_decay(1 / 0.999),cla_inc(1), var_inc(1)
+  , random_var_freq(0.02)
+  , restart_first(100), restart_inc(1.5)
+  , learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
+  , expensive_ccmin(true)
+  , polarity_mode    (polarity_false)
+  , maxmemory(opt_maxmemory), maxnbsolvers(opt_maxnbsolvers)
+  , verb(0) , verbEveryConflicts(10000)
+  , numvar(0), numclauses(0)
+
+{
+    result = l_Undef;
+    SharedCompanion *sc = new SharedCompanion();
+    this->sharedcomp = sc;
+
+    // Generate only solver 0.
+    // It loads the formula
+    // All others solvers are clone of this one
+    solvers.push(s);
+    s->verbosity = 0; // No reportf in solvers... All is done in MultiSolver
+    s->setThreadNumber(0);
+    //s->belongsto = this;
+    s->sharedcomp = sc;
+    sc->addSolver(s);
+    assert(solvers[0]->threadNumber() == 0);
+
+    pthread_mutex_init(&m,NULL);  //PTHREAD_MUTEX_INITIALIZER;
+    pthread_mutex_init(&mfinished,NULL); //PTHREAD_MUTEX_INITIALIZER;
+    pthread_cond_init(&cfinished,NULL);
+
+    if (nbsolvers > 0 ) 
+       fprintf(stdout,"c %d solvers engines and 1 companion as a blackboard created.\n", nbsolvers);
+}
+
+MultiSolvers::MultiSolvers() : MultiSolvers(new ParallelSolver(-1)) {
+
+}
+
+MultiSolvers::~MultiSolvers()
+{}
+
+/**
+ * Generate All solvers
+ */
+
+void MultiSolvers::generateAllSolvers() {
+    assert(solvers[0] != NULL);
+    assert(allClonesAreBuilt==0);
+
+    for(int i=1;i<nbsolvers;i++) {
+       ParallelSolver *s  = (ParallelSolver*)solvers[0]->clone();
+       solvers.push(s);
+       s->verbosity = 0; // No reportf in solvers... All is done in MultiSolver
+       s->setThreadNumber(i);
+       s->sharedcomp =   this->sharedcomp;
+       this->sharedcomp->addSolver(s);
+       assert(solvers[i]->threadNumber() == i);
+    }
+
+    adjustParameters(); 
+
+    allClonesAreBuilt = 1;
+}
+
+/**
+ * Choose solver for threads i (if no given in command line see above)
+ */
+
+
+ParallelSolver* MultiSolvers::retrieveSolver(int i) {
+    return new ParallelSolver(i);
+}
+
+Var MultiSolvers::newVar(bool sign, bool dvar)
+{
+  assert(solvers[0] != NULL);
+  numvar++;
+  int v;
+  sharedcomp->newVar(sign);
+  if(!allClonesAreBuilt) { // At the beginning we want to generate only solvers 0
+    v = solvers[0]->newVar(sign,dvar);
+    assert(numvar == v+1); // Just a useless check
+  } else {
+      for(int i=0;i<nbsolvers;i++) {
+         v = solvers[i]->newVar(sign,dvar);
+      }
+  }
+  return numvar;
+}
+
+bool MultiSolvers::addClause_(vec<Lit>&ps) {
+  assert(solvers[0] != NULL); // There is at least one solver.
+  // Check if clause is satisfied and remove false/duplicate literals:
+  if (!okay())  return false;
+
+  sort(ps);
+  Lit p; int i, j;
+  for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
+    if (solvers[0]->value(ps[i]) == l_True || ps[i] == ~p)
+      return true;
+    else if (solvers[0]->value(ps[i]) != l_False && ps[i] != p)
+      ps[j++] = p = ps[i];
+  ps.shrink(i - j);
+  
+  
+  if (ps.size() == 0) {
+    return ok = false;
+  }
+  else if (ps.size() == 1){
+    assert(solvers[0]->value(ps[0]) == l_Undef); // TODO : Passes values to all threads
+    solvers[0]->uncheckedEnqueue(ps[0]);
+    if(!allClonesAreBuilt) {
+       return ok = ( (solvers[0]->propagate()) == CRef_Undef); // checks only main solver here for propagation constradiction
+    } 
+
+    // Here, all clones are built.
+    // Gives the unit clause to everybody
+    for(int i=0;i<nbsolvers;i++)
+      solvers[i]->uncheckedEnqueue(ps[0]);
+    return ok = ( (solvers[0]->propagate()) == CRef_Undef); // checks only main solver here for propagation constradiction
+  }else{
+    //         printf("Adding clause %0xd for solver %d.\n",(void*)c, thn);
+    // At the beginning only solver 0 load the formula
+    solvers[0]->addClause(ps);
+    
+    if(!allClonesAreBuilt) {
+       numclauses++;
+       return true;
+    }
+    // Clones are built, need to pass the clause to all the threads 
+    for(int i=1;i<nbsolvers;i++) {
+      solvers[i]->addClause(ps);
+    }
+    numclauses++;
+  }
+  return true;
+}
+
+
+bool MultiSolvers::simplify() {
+  assert(solvers[0] != NULL); // There is at least one solver.
+
+  if (!okay()) return false;
+  return ok = solvers[0]->simplify(); 
+}
+
+
+bool MultiSolvers::eliminate() {
+    
+    // TODO allow variable elimination when all threads are built!
+    assert(allClonesAreBuilt==false);
+    
+    SimpSolver * s = (SimpSolver*)getPrimarySolver();
+    return s->eliminate(true);
+}
+
+
+// TODO: Use a template here
+void *localLaunch(void*arg) {
+  ParallelSolver* s = (ParallelSolver*)arg;
+  
+  (void)s->solve();
+  
+  pthread_exit(NULL);
+}
+
+
+#define MAXIMUM_SLEEP_DURATION 5
+void MultiSolvers::printStats() {
+       static int nbprinted = 1;
+       double cpu_time = cpuTime();
+    printf("c\n");
+
+    printf("c |-------------------------------------------------------------------------------------------------------|\n");
+        printf("c | id | starts | decisions  |  confls    |  Init T  |  learnts | exported | imported | promoted |    %%   | \n");
+        printf("c |-------------------------------------------------------------------------------------------------------|\n");
+
+       //printf("%.0fs | ",cpu_time);
+       for(int i=0;i<solvers.size();i++) {
+           solvers[i]->reportProgress();
+    //printf(" %2d: %12ld confl. |", i,  (long int) solvers[i]->conflicts);
+    }
+       long long int totalconf = 0;
+       long long int totalprop = 0;
+       for(int i=0;i<solvers.size();i++) {
+               totalconf+=  (long int) solvers[i]->conflicts;
+               totalprop+= solvers[i]->propagations;
+    }
+    printf("c \n");
+   
+    printf("c synthesis %11lld conflicts %11lld propagations %8.0f conflicts/sec %8.0f propagations/sec\n",
+            totalconf, totalprop, (double)totalconf / cpu_time, (double) totalprop / cpu_time);
+
+
+       nbprinted ++;
+}
+
+// Still a ugly function... To be rewritten with some statistics class some day
+void MultiSolvers::printFinalStats() {
+    sharedcomp->printStats();
+    printf("c\nc\n");
+    printf("c\n");
+    printf("c |---------------------------------------- FINAL STATS --------------------------------------------------|\n");
+    printf("c\n");
+    
+    printf("c |---------------");
+    for(int i = 0;i<solvers.size();i++) 
+        printf("|------------");
+    printf("|-----------------|\n");    
+
+    printf("c | Threads       ");
+    for(int i = 0;i < solvers.size();i++) {
+        printf("| %10d ",i);
+    }
+    printf("|      Total      |\n");
+
+    printf("c |---------------");
+    for(int i = 0;i<solvers.size();i++) 
+        printf("|------------");
+    printf("|-----------------|\n");    
+
+    
+    printf("c | Conflicts     ");
+
+    long long int totalconf = 0;
+    for(int i=0;i<solvers.size();i++)  {
+       printf("| %10" PRIu64" ", solvers[i]->conflicts);
+       totalconf +=  solvers[i]->conflicts;
+    }
+    printf("| %15lld |\n",totalconf);
+   
+    printf("c | Exported      ");
+    uint64_t exported = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbexported);
+        exported += solvers[i]->nbexported;
+    }
+    printf("| %15" PRIu64" |\n", exported);
+
+    printf("c | Imported      ");
+    uint64_t imported = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbimported);
+        imported += solvers[i]->nbimported;
+    }
+    printf("| %15" PRIu64" |\n", imported);
+
+    printf("c | Good          ");
+    uint64_t importedGood = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbImportedGoodClauses);
+        importedGood += solvers[i]->nbImportedGoodClauses;
+    }
+    printf("| %15" PRIu64" |\n", importedGood);
+
+    printf("c | Purge         ");
+    uint64_t importedPurg = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbimportedInPurgatory);
+        importedPurg += solvers[i]->nbimportedInPurgatory;
+    }
+    printf("| %15" PRIu64" |\n", importedPurg);
+
+    printf("c | Promoted      ");
+    uint64_t promoted = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbPromoted);
+        promoted += solvers[i]->nbPromoted;
+    }
+    printf("| %15" PRIu64" |\n", promoted);
+
+    printf("c | Remove imp    ");
+    uint64_t removedimported = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbRemovedUnaryWatchedClauses);
+        removedimported += solvers[i]->nbRemovedUnaryWatchedClauses;
+    }
+    printf("| %15" PRIu64" |\n", removedimported);
+
+    printf("c | Blocked Reuse ");
+    uint64_t blockedreused = 0;
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbNotExportedBecauseDirectlyReused);
+        blockedreused += solvers[i]->nbNotExportedBecauseDirectlyReused;
+    }
+    printf("| %15" PRIu64" |\n",blockedreused);
+
+
+    printf("c | Orig seen     ");
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->originalClausesSeen);
+    }
+    printf("|                 |\n"); 
+
+    printf("c | Unaries       ");
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbUn);
+    }
+    printf("|                 |\n"); 
+
+    printf("c | Binaries      ");
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbBin);
+    }
+    printf("|                 |\n"); 
+
+    
+     printf("c | Glues         ");
+    for(int i=0;i<solvers.size();i++) {
+       printf("| %10" PRIu64" ", solvers[i]->nbDL2);
+    }
+    printf("|                 |\n"); 
+
+
+    int winner = -1;
+   for(int i=0;i<solvers.size();i++) {
+     if(sharedcomp->winner()==solvers[i])
+       winner = i;
+     }
+   
+   if(winner!=-1) {
+int sum = 0;
+   printf("c | Hamming       ");
+   for(int i = 0;i<solvers.size();i++) {
+     if(i==winner) {
+       printf("|      X     ");
+       continue;
+     }
+     int nb = 0;
+     for(int j = 0;j<nVars();j++) {
+       if(solvers[i]->valuePhase(j)!= solvers[winner]->valuePhase(j)) nb++;
+     }
+     printf("| %10d ",nb);
+     sum+=nb;
+
+   }
+   printf("| %15d |\n",sum/(solvers.size()>1?solvers.size()-1:1));
+   }
+   printf("c |---------------");
+   for(int i = 0;i<solvers.size();i++) 
+     printf("|------------");
+   printf("|-----------------|\n");    
+
+  
+
+}
+
+// Well, all those parameteres are just naive guesses... No experimental evidences for this.
+void MultiSolvers::adjustParameters() {
+    SolverConfiguration::configure(this,nbsolvers);
+}
+
+void MultiSolvers::adjustNumberOfCores() {
+ float mem = memUsed();
+  if (nbthreads==0) { // Automatic configuration
+      if(verb>=1) 
+          printf("c |  Automatic Adjustement of the number of solvers. MaxMemory=%5d, MaxCores=%3d.                       |\n", maxmemory, maxnbsolvers);
+      unsigned int tmpnbsolvers = maxmemory * 4 /  10 / mem;
+      if (tmpnbsolvers > maxnbsolvers) tmpnbsolvers = maxnbsolvers;
+      if (tmpnbsolvers < 1) tmpnbsolvers = 1;
+      if(verb>=1) 
+        printf("c |  One Solver is taking %.2fMb... Let's take %d solvers for this run (max 40%% of the maxmemory).       |\n", mem, tmpnbsolvers);
+      nbsolvers = tmpnbsolvers;
+      nbthreads = nbsolvers;
+  } else {
+      assert(nbthreads == nbsolvers);
+  }
+}
+
+lbool MultiSolvers::solve() {
+  pthread_attr_t thAttr; 
+  int i; 
+
+  adjustNumberOfCores();
+  sharedcomp->setNbThreads(nbsolvers); 
+  if(verb>=1) 
+    printf("c |  Generating clones                                                                                    |\n"); 
+  generateAllSolvers();
+  if(verb>=1) {
+    printf("c |  all clones generated. Memory = %6.2fMb.                                                             |\n", memUsed());
+    printf("c ========================================================================================================|\n");
+  }
+  
+  
+  model.clear();
+
+  /* Initialize and set thread detached attribute */
+  pthread_attr_init(&thAttr);
+  pthread_attr_setdetachstate(&thAttr, PTHREAD_CREATE_JOINABLE);
+  
+  
+  
+  // Launching all solvers
+  for (i = 0; i < nbsolvers; i++) {
+    pthread_t * pt = (pthread_t*)malloc(sizeof(pthread_t));
+    threads.push(pt);
+    solvers[i]->pmfinished = &mfinished;
+    solvers[i]->pcfinished = &cfinished;
+    pthread_create(threads[i], &thAttr, &localLaunch, (void*)solvers[i]); 
+  }
+  
+  bool done = false;
+  
+  (void)pthread_mutex_lock(&m);
+  while (!done) { 
+    struct timespec timeout;
+    time(&timeout.tv_sec);
+    timeout.tv_sec += MAXIMUM_SLEEP_DURATION;
+    timeout.tv_nsec = 0;
+    if (pthread_cond_timedwait(&cfinished, &mfinished, &timeout) != ETIMEDOUT) 
+           done = true;
+    else 
+      printStats();
+
+    float mem = memUsed();
+    if(verb>=1) printf("c Total Memory so far : %.2fMb\n",  mem);
+    if ( (maxmemory > 0) && (mem > maxmemory) && !sharedcomp->panicMode) 
+       printf("c ** reduceDB switching to Panic Mode due to memory limitations !\n"), sharedcomp->panicMode = true;
+    
+  }
+  (void)pthread_mutex_unlock(&m);
+  
+  for (i = 0; i < nbsolvers; i++) { // Wait for all threads to finish
+      pthread_join(*threads[i], NULL);
+  }
+  
+  assert(sharedcomp != NULL);
+  result = sharedcomp->jobStatus;
+  if (result == l_True) {
+      int n = sharedcomp->jobFinishedBy->nVars();
+       model.growTo(n);
+       for(int i = 0; i < n; i++)
+           model[i] = sharedcomp->jobFinishedBy->model[i];
+  }
+
+       
+  return result;
+  /*
+  for(int i=0;i<NBTHREADS;i++)
+    pthread_join(*threads[i],&status);
+  */
+
+}
+
diff --git a/glucose-syrup/parallel/MultiSolvers.h b/glucose-syrup/parallel/MultiSolvers.h
new file mode 100644 (file)
index 0000000..b44b75f
--- /dev/null
@@ -0,0 +1,182 @@
+/***************************************************************************************[MultiSolvers.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#ifndef MultiSolvers_h
+#define MultiSolvers_h
+
+#include "parallel/ParallelSolver.h"
+
+namespace Glucose {
+    class SolverConfiguration;
+    
+class MultiSolvers {
+    friend class SolverConfiguration;
+
+public:
+  MultiSolvers(ParallelSolver *s);
+  MultiSolvers();
+  ~MultiSolvers();
+  void printFinalStats(); 
+
+  void setVerbosity(int i);
+  int verbosity();
+  void setVerbEveryConflicts(int i);
+  void setShowModel(int i) {showModel = i;}
+  int getShowModel() {return showModel;}
+  // Problem specification:
+  //
+  Var     newVar    (bool polarity = true, bool dvar = true); // Add a new variable with parameters specifying variable mode.
+  bool    addClause (const vec<Lit>& ps);                           // Add a clause to the solver. NOTE! 'ps' may be shrunk by this method!
+  bool    addClause_(      vec<Lit>& ps);       
+  
+  bool    simplify     ();                        // Removes already satisfied clauses.
+  
+  int     nVars      ()      const;       // The current number of variables.
+  int     nClauses      ()      const;       // The current number of variables.
+  ParallelSolver *getPrimarySolver();
+  
+  void generateAllSolvers();
+  
+  // Solving:
+  //
+  lbool    solve        ();                        // Search without assumptions.
+  bool eliminate();             // Perform variable elimination
+  void adjustParameters();
+  void adjustNumberOfCores();
+  void interrupt() {}
+  vec<lbool> model;             // If problem is satisfiable, this vector contains the model (if any).
+  inline bool okay() {
+    if(!ok) return ok;
+    for(int i = 0;i<solvers.size();i++) {
+       if(!((SimpSolver*)solvers[i])->okay()) {
+           ok = false;
+           return false;
+       }
+    }
+    return true;
+  }
+
+ protected:
+       friend class ParallelSolver;
+       friend class SolverCompanion;
+       
+struct Stats {
+    uint64_t min, max, avg, std, med;
+    Stats(uint64_t _min = 0,uint64_t _max = 0,uint64_t  _avg = 0,uint64_t  _std = 0,uint64_t  _med = 0) : 
+       min(_min), max(_max), avg(_avg), std(_std), med(_med) {} 
+};
+
+       void printStats(); 
+       int ok;
+       lbool result;
+       int maxnbthreads; // Maximal number of threads
+       int nbthreads; // Current number of threads
+       int nbsolvers; // Number of CDCL solvers
+       int nbcompanions; // Number of companions
+       int nbcompbysolver; // Number of companions by solvers
+       bool immediateSharingGlue ;
+       int allClonesAreBuilt;
+        bool showModel; // show model on/off
+
+       int winner;
+
+    vec<Lit>            add_tmp;
+       
+    double    var_decay;          // Inverse of the variable activity decay factor.                                            (default 1 / 0.95)
+    double    clause_decay;       // Inverse of the clause activity decay factor.                                              (1 / 0.999)
+    double    cla_inc;          // Amount to bump next clause with.
+    double    var_inc;          // Amount to bump next variable with.  
+    double    random_var_freq;    // The frequency with which the decision heuristic tries to choose a random variable.        (default 0.02)
+    int       restart_first;      // The initial restart limit.                                                                (default 100)
+    double    restart_inc;        // The factor with which the restart limit is multiplied in each restart.                    (default 1.5)
+    double    learntsize_factor;  // The intitial limit for learnt clauses is a factor of the original clauses.                (default 1 / 3)
+    double    learntsize_inc;     // The limit for learnt clauses is multiplied with this factor each restart.                 (default 1.1)
+    bool      expensive_ccmin;    // Controls conflict clause minimization.                                                    (default TRUE)
+    int       polarity_mode;      // Controls which polarity the decision heuristic chooses. See enum below for allowed modes. (default polarity_false)
+    unsigned int maxmemory;
+    unsigned int maxnbsolvers;
+    int verb; 
+    int verbEveryConflicts;
+    int numvar; // Number of variables
+    int numclauses; // Number of clauses
+
+    enum { polarity_true = 0, polarity_false = 1, polarity_user = 2, polarity_rnd = 3 };
+
+   //ClauseAllocator     ca;
+   SharedCompanion * sharedcomp;
+
+    void informEnd(lbool res);
+    ParallelSolver* retrieveSolver(int i);
+
+    pthread_mutex_t m; // mutex for any high level sync between all threads (like reportf)
+    pthread_mutex_t mfinished; // mutex on which main process may wait for... As soon as one process finishes it release the mutex
+    pthread_cond_t cfinished; // condition variable that says that a thread has finished
+       
+    vec<ParallelSolver*> solvers; // set of plain solvers
+    vec<SolverCompanion*> solvercompanions; // set of companion solvers
+    vec<pthread_t*> threads; // all threads of this process
+    vec<int> threadIndexOfSolver; // threadIndexOfSolver[solvers[i]] is the index in threads[] of the solver i
+    vec<int> threadIndexOfSolverCompanion; // threadIndexOfSolverCompanion[solvercompanions[i]] is the index in threads[] of the solvercompanion i
+};
+
+inline bool     MultiSolvers::addClause       (const vec<Lit>& ps)    { ps.copyTo(add_tmp); return addClause_(add_tmp); }
+
+inline void MultiSolvers::setVerbosity(int i) {verb = i;}
+inline void MultiSolvers::setVerbEveryConflicts(int i) {verbEveryConflicts=i;}
+inline int      MultiSolvers::nVars         ()      const   { return numvar; }
+inline int      MultiSolvers::nClauses      ()      const   { return numclauses; }
+inline int MultiSolvers::verbosity()  {return verb;}
+inline ParallelSolver* MultiSolvers::getPrimarySolver() {return solvers[0];}
+
+
+}
+#endif
+
diff --git a/glucose-syrup/parallel/ParallelSolver.cc b/glucose-syrup/parallel/ParallelSolver.cc
new file mode 100644 (file)
index 0000000..ff948e9
--- /dev/null
@@ -0,0 +1,490 @@
+/***************************************************************************************[ParallelSolver.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include "parallel/ParallelSolver.h"
+#include "mtl/Sort.h"
+
+using namespace Glucose;
+
+const char* _cunstable = "CORE/PARALLEL -- UNSTABLE FEATURES";
+const char* _parallel = "PARALLEL";
+
+extern BoolOption opt_dontExportDirectReusedClauses; // (_cunstable, "reusedClauses",    "Don't export directly reused clauses", false);
+extern BoolOption opt_plingeling; // (_cunstable, "plingeling",    "plingeling strategy for sharing clauses (exploratory feature)", false);
+
+
+ParallelSolver::ParallelSolver(int threadId) :
+  SimpSolver()
+, thn(threadId) // The thread number of this solver
+, nbexported(0)
+, nbimported(0)
+, nbexportedunit(0), nbimportedunit(0), nbimportedInPurgatory(0), nbImportedGoodClauses(0)
+, goodlimitlbd(8)
+, goodlimitsize(30)
+, purgatory(true)
+, shareAfterProbation(!opt_plingeling) // only share clauses after probation 
+, plingeling(opt_plingeling)
+, firstSharing(5000) // Strong limit : do not share anything (except unary clauses) before this number of conflicts
+, limitSharingByGoodLBD(true) // Moving limit of what a good LBD is (median value of last learnt clauses set)
+, limitSharingByFixedLimitLBD(0) // No fixed bound (like 8 in plingeling)
+, limitSharingByFixedLimitSize(0) // No fixed boud (like 40 in plingeling) 
+, dontExportDirectReusedClauses(opt_dontExportDirectReusedClauses)
+, nbNotExportedBecauseDirectlyReused(0)
+{
+    useUnaryWatched = true; // We want to use promoted clauses here !
+}
+
+
+
+
+ParallelSolver::~ParallelSolver() {
+    printf("c Solver of thread %d ended.\n", thn);
+    fflush(stdout);
+}
+
+ParallelSolver::ParallelSolver(const ParallelSolver &s) : SimpSolver(s)
+, nbexported(s.nbexported)
+, nbimported(s.nbimported)
+, nbexportedunit(s.nbexportedunit), nbimportedunit(s.nbimportedunit), nbimportedInPurgatory(s.nbimportedInPurgatory)
+, nbImportedGoodClauses(s.nbImportedGoodClauses)
+, goodlimitlbd(s.goodlimitlbd)
+, goodlimitsize(s.goodlimitsize)
+, purgatory(s.purgatory)
+, shareAfterProbation(s.shareAfterProbation) // only share clauses after probation 
+, plingeling(s.plingeling)
+, firstSharing(s.firstSharing) // Strong limit : do not share anything (except unary clauses) before this number of conflicts
+, limitSharingByGoodLBD(s.limitSharingByGoodLBD) // Moving limit of what a good LBD is (median value of last learnt clauses set)
+, limitSharingByFixedLimitLBD(s.limitSharingByFixedLimitLBD) // No fixed bound (like 8 in plingeling)
+, limitSharingByFixedLimitSize(s.limitSharingByFixedLimitSize) // No fixed boud (like 40 in plingeling) 
+, dontExportDirectReusedClauses(s.dontExportDirectReusedClauses)
+, nbNotExportedBecauseDirectlyReused(s.nbNotExportedBecauseDirectlyReused) 
+{
+    s.goodImportsFromThreads.memCopyTo(goodImportsFromThreads);   
+    useUnaryWatched = s.useUnaryWatched;
+}
+
+
+// Strategy to reduce unary watches list
+struct reduceDB_oneWatched_lt {
+    ClauseAllocator& ca;
+
+    reduceDB_oneWatched_lt(ClauseAllocator& ca_) : ca(ca_) {
+    }
+
+    bool operator()(CRef x, CRef y) {
+
+        // Main criteria... Like in MiniSat we keep all binary clauses
+        if (ca[x].size() > 2 && ca[y].size() == 2) return 1;
+
+        if (ca[y].size() > 2 && ca[x].size() == 2) return 0;
+        if (ca[x].size() == 2 && ca[y].size() == 2) return 0;
+
+        // Second one  based on literal block distance
+        if (ca[x].size() > ca[y].size()) return 1;
+        if (ca[x].size() < ca[y].size()) return 0;
+
+        if (ca[x].lbd() > ca[y].lbd()) return 1;
+        if (ca[x].lbd() < ca[y].lbd()) return 0;
+
+        // Finally we can use old activity or size, we choose the last one
+        return ca[x].activity() < ca[y].activity();
+        //return x->size() < y->size();
+
+        //return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); } 
+    }
+};
+
+// @overide
+void ParallelSolver::reduceDB() {
+
+    int i, j;
+    nbReduceDB++;
+    sort(learnts, reduceDB_lt(ca));
+
+    int limit;
+
+    if (!panicModeIsEnabled()) {
+        // We have a lot of "good" clauses, it is difficult to compare them. Keep more !
+        if (ca[learnts[learnts.size() / RATIOREMOVECLAUSES]].lbd() <= 3) nbclausesbeforereduce += specialIncReduceDB;
+        // Useless :-)
+        if (ca[learnts.last()].lbd() <= 5) nbclausesbeforereduce += specialIncReduceDB;
+
+        // Don't delete binary or locked clauses. From the rest, delete clauses from the first half
+        // Keep clauses which seem to be usefull (their lbd was reduce during this sequence)
+
+        limit = learnts.size() / 2;
+    } else {
+        limit = panicModeLastRemoved;
+    }
+    panicModeLastRemoved = 0;
+
+    uint64_t sumsize = 0;
+    for (i = j = 0; i < learnts.size(); i++) {
+
+        Clause& c = ca[learnts[i]];
+        if (i == learnts.size() / 2)
+            goodlimitlbd = c.lbd();
+        sumsize += c.size();
+        if (c.lbd() > 2 && c.size() > 2 && c.canBeDel() && !locked(c) && (i < limit)) {
+            removeClause(learnts[i]);
+            nbRemovedClauses++;
+            panicModeLastRemoved++;
+        } else {
+            if (!c.canBeDel()) limit++; //we keep c, so we can delete an other clause
+            c.setCanBeDel(true); // At the next step, c can be delete
+            learnts[j++] = learnts[i];
+        }
+    }
+    learnts.shrink(i - j);
+
+    if (learnts.size() > 0)
+        goodlimitsize = 1 + (double) sumsize / (double) learnts.size();
+
+    // Special treatment for imported clauses
+    if (!panicModeIsEnabled())
+        limit = unaryWatchedClauses.size() - (learnts.size() * 2);
+    else
+        limit = panicModeLastRemovedShared;
+    panicModeLastRemovedShared = 0;
+    if ((unaryWatchedClauses.size() > 100) && (limit > 0)) {
+
+        sort(unaryWatchedClauses, reduceDB_oneWatched_lt(ca));
+
+        for (i = j = 0; i < unaryWatchedClauses.size(); i++) {
+            Clause& c = ca[unaryWatchedClauses[i]];
+            if (c.lbd() > 2 && c.size() > 2 && c.canBeDel() && !locked(c) && (i < limit)) {
+                removeClause(unaryWatchedClauses[i], c.getOneWatched()); // remove from the purgatory (or not)
+                nbRemovedUnaryWatchedClauses++;
+                panicModeLastRemovedShared++;
+            } else {
+                if (!c.canBeDel()) limit++; //we keep c, so we can delete an other clause
+                c.setCanBeDel(true); // At the next step, c can be delete
+                unaryWatchedClauses[j++] = unaryWatchedClauses[i];
+            }
+        }
+        unaryWatchedClauses.shrink(i - j);
+    }
+
+    checkGarbage();
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  parallelImportClauseDuringConflictAnalysis : (Clause &c,CRef confl)   ->  [void]
+|  
+|  Description:
+|    Verify if the clause using during conflict analysis is good for export
+|    @see : analyze
+|  Output:
+|________________________________________________________________________________________________@*/
+
+
+void ParallelSolver::parallelImportClauseDuringConflictAnalysis(Clause &c,CRef confl) {
+    if (dontExportDirectReusedClauses && (confl == lastLearntClause) && (c.getExported() < 2)) { // Experimental stuff
+        c.setExported(2);
+        nbNotExportedBecauseDirectlyReused++;
+    } else if (shareAfterProbation && c.getExported() != 2 && conflicts > firstSharing) {
+        c.setExported(c.getExported() + 1);
+        if (!c.wasImported() && c.getExported() == 2) { // It's a new interesting clause: 
+            if (c.lbd() == 2 || (c.size() < goodlimitsize && c.lbd() <= goodlimitlbd)) {
+                shareClause(c);
+            }
+        }
+    }
+
+}
+
+
+
+// These Two functions are useless here !!
+void ParallelSolver::reportProgress() {
+    printf("c | %2d | %6d | %10d | %10d | %8d | %8d | %8d | %8d | %8d | %6.3f |\n",(int)thn,(int)starts,(int)decisions,(int)conflicts,(int)originalClausesSeen,(int)learnts.size(),(int)nbexported,(int)nbimported,(int)nbPromoted,progressEstimate()*100);
+
+    //printf("c thread=%d confl=%lld starts=%llu reduceDB=%llu learnts=%d broadcast=%llu  blockedReuse=%lld imported=%llu promoted=%llu limitlbd=%llu limitsize=%llu\n", thn, conflicts, starts, nbReduceDB, learnts.size(), nbexported, nbNotExportedBecauseDirectlyReused, nbimported, nbPromoted, goodlimitlbd, goodlimitsize);
+}
+
+void ParallelSolver::reportProgressArrayImports(vec<unsigned int> &totalColumns) {
+    return ; // TODO : does not currently work
+    unsigned int totalImports = 0;
+    printf("c %3d | ", thn);
+    for (int i = 0; i <  sharedcomp->nbThreads; i++) {
+        totalImports += goodImportsFromThreads[i];
+        totalColumns[i] += goodImportsFromThreads[i];
+        printf(" %8d", goodImportsFromThreads[i]);
+    }
+    printf(" | %8d\n", totalImports);
+
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  shareClause : (Clause &c)   ->  [bool]
+|  
+|  Description:
+|  share a clause to other cores  
+| @see : analyze
+|  Output: true if the clause is indeed sent
+|________________________________________________________________________________________________@*/
+
+bool ParallelSolver::shareClause(Clause & c) {
+    bool sent = sharedcomp->addLearnt(this, c);
+    if (sent)
+        nbexported++;
+    return sent;
+}
+
+/*_________________________________________________________________________________________________
+|
+|  panicModeIsEnabled : ()   ->  [bool]
+|  
+|  Description:
+|  is panic mode (save memory) is enabled ?
+|________________________________________________________________________________________________@*/
+
+bool ParallelSolver::panicModeIsEnabled() {
+    return sharedcomp->panicMode;
+}
+
+/*_________________________________________________________________________________________________
+|
+|  parallelImportUnaryClauses : ()   ->  [void]
+|  
+|  Description:
+|  import all unary clauses from other cores
+|________________________________________________________________________________________________@*/
+
+void ParallelSolver::parallelImportUnaryClauses() {
+    Lit l;
+    while ((l = sharedcomp->getUnary(this)) != lit_Undef) {
+        if (value(var(l)) == l_Undef) {
+            uncheckedEnqueue(l);
+            nbimportedunit++;
+        }
+    }
+}
+
+/*_________________________________________________________________________________________________
+|
+|  parallelImportClauses : ()   ->  [bool]
+|  
+|  Description:
+|  import all clauses from other cores
+|  Output : if there is a final conflict
+|________________________________________________________________________________________________@*/
+
+bool ParallelSolver::parallelImportClauses() {
+
+    assert(decisionLevel() == 0);
+    int importedFromThread;
+    while (sharedcomp->getNewClause(this, importedFromThread, importedClause)) {
+        assert(importedFromThread <= sharedcomp->nbThreads);
+        assert(importedFromThread >= 0);
+
+        assert(importedFromThread != thn);
+
+        if (importedClause.size() == 0)
+            return true;
+
+        //printf("Thread %d imports clause from thread %d\n", threadNumber(), importedFromThread);
+        CRef cr = ca.alloc(importedClause, true, true);
+        ca[cr].setLBD(importedClause.size());
+        if (plingeling) // 0 means a broadcasted clause (good clause), 1 means a survivor clause, broadcasted
+            ca[cr].setExported(2); // A broadcasted clause (or a survivor clause) do not share it anymore
+        else {
+            ca[cr].setExported(1); // next time we see it in analyze, we share it (follow route / broadcast depending on the global strategy, part of an ongoing experimental stuff: a clause in one Watched will be set to exported 2 when promotted.
+        }
+        ca[cr].setImportedFrom(importedFromThread);
+        unaryWatchedClauses.push(cr);
+        if (plingeling || ca[cr].size() <= 2) {//|| importedRoute == 0) { // importedRoute == 0 means a glue clause in another thread (or any very good clause)
+            ca[cr].setOneWatched(false); // Warning: those clauses will never be promoted by a conflict clause (or rarely: they are propagated!)
+            attachClause(cr);
+            nbImportedGoodClauses++;
+        } else {
+            ca[cr].setOneWatched(true);
+            attachClausePurgatory(cr); // 
+            nbimportedInPurgatory++;
+        }
+        assert(ca[cr].learnt());
+        nbimported++;
+    }
+    return false;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  parallelExportUnaryClause : (Lit p)   ->  [void]
+|  
+|  Description:
+|  export unary clauses to other cores
+|________________________________________________________________________________________________@*/
+
+void ParallelSolver::parallelExportUnaryClause(Lit p) {
+    // Multithread
+    sharedcomp->addLearnt(this,p ); // TODO: there can be a contradiction here (two theads proving a and -a)
+    nbexportedunit++;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  parallelExportClauseDuringSearch : (Clause &c)   ->  [void]
+|  
+|  Description:
+|  Verify if a new learnt clause is useful for export
+|  @see search
+|  
+|________________________________________________________________________________________________@*/
+
+void ParallelSolver::parallelExportClauseDuringSearch(Clause &c) {
+    //
+    // Multithread
+    // Now I'm sharing the clause if seen in at least two conflicts analysis shareClause(ca[cr]);
+    if ((plingeling && !shareAfterProbation && c.lbd() < 8 && c.size() < 40) ||
+            (c.lbd() <= 2)) { // For this class of clauses, I'm sharing them asap (they are Glue CLauses, no probation for them)
+        shareClause(c);
+        c.setExported(2);
+    }
+
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  parallelJobIsFinished : ()   ->  [bool]
+|  
+|  Description:
+|  Is a core already finish the search
+|  
+|________________________________________________________________________________________________@*/
+
+bool ParallelSolver::parallelJobIsFinished() { 
+    // Parallel: another job has finished let's quit
+    return (sharedcomp->jobFinished());
+}
+
+// @overide
+lbool ParallelSolver::solve_(bool do_simp, bool turn_off_simp) {
+       vec<Var> extra_frozen;
+    lbool    result = l_True;
+    do_simp &= use_simplification;
+    if (do_simp){
+        // Assumptions must be temporarily frozen to run variable elimination:
+        for (int i = 0; i < assumptions.size(); i++){
+            Var v = var(assumptions[i]);
+
+            // If an assumption has been eliminated, remember it.
+            assert(!isEliminated(v));
+
+            if (!frozen[v]){
+                // Freeze and store.
+                setFrozen(v, true);
+                extra_frozen.push(v);
+            } }
+
+        result = lbool(eliminate(turn_off_simp));
+    }
+
+    model.clear();
+    conflict.clear();
+    if (!ok) return l_False;
+
+    solves++;
+
+
+    lbool status = l_Undef;
+
+    // Search:
+    int curr_restarts = 0;
+    while (status == l_Undef && !sharedcomp->jobFinished()) {
+        status = search(0); // the parameter is useless in glucose, kept to allow modifications
+        if (!withinBudget()) break;
+        curr_restarts++;
+    }
+
+    if (verbosity >= 1)
+        printf("c =========================================================================================================\n");
+
+
+/*    if (do_simp)
+        // Unfreeze the assumptions that were frozen:
+        for (int i = 0; i < extra_frozen.size(); i++)
+            setFrozen(extra_frozen[i], false);
+*/
+    
+    bool firstToFinish = false;
+    if (status != l_Undef)
+        firstToFinish = sharedcomp->IFinished(this);
+    if (firstToFinish) {
+        printf("c Thread %d is 100%% pure glucose! First thread to finish! (%s answer).\n", threadNumber(), status == l_True ? "SAT" : status == l_False ? "UNSAT" : "UNKOWN");
+        sharedcomp->jobStatus = status;
+    }
+    
+    if (firstToFinish && status == l_True) {
+        extendModel();
+
+
+        // Extend & copy model:
+        model.growTo(nVars());
+        for (int i = 0; i < nVars(); i++) model[i] = value(i);
+    } else if (status == l_False && conflict.size() == 0)
+        ok = false;
+
+
+    pthread_cond_signal(pcfinished);
+
+    //cancelUntil(0);
+
+
+    return status;
+
+}
diff --git a/glucose-syrup/parallel/ParallelSolver.h b/glucose-syrup/parallel/ParallelSolver.h
new file mode 100644 (file)
index 0000000..9701792
--- /dev/null
@@ -0,0 +1,144 @@
+/**************************************************************************************[ParallelSolver.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#ifndef PARALLELSOLVER_H
+#define        PARALLELSOLVER_H
+
+#include "core/SolverTypes.h"
+#include "core/Solver.h"
+#include "simp/SimpSolver.h"
+#include "parallel/SharedCompanion.h"
+namespace Glucose {
+//=================================================================================================
+    //class MultiSolvers;
+    //class SolverCompanion;
+ //   class MultiSolvers;
+    
+class ParallelSolver : public SimpSolver {
+    friend class MultiSolvers;
+    friend class SolverCompanion;
+    friend class SharedCompanion;
+//    friend class ReasoningCompanion;
+//    friend class SolverConfiguration;
+
+protected : 
+          // Multithread :
+    int                thn; // internal thread number
+    //MultiSolvers* belongsto; // Not working (due to incomplete types)
+    SharedCompanion *sharedcomp;
+    bool coreFUIP; // true if one core is specialized for branching on all FUIP
+    bool ImTheSolverFUIP;
+    pthread_mutex_t *pmfinished; // mutex on which main process may wait for... As soon as one process finishes it release the mutex
+    pthread_cond_t *pcfinished; // condition variable that says that a thread as finished
+
+public:
+    // Constructor/Destructor:
+    //
+    ParallelSolver(int threadId);
+    ParallelSolver(const ParallelSolver &s);
+    ~ParallelSolver();
+    
+    /**
+     * Clone function
+     */
+    virtual Clone* clone() const {
+        return  new ParallelSolver(*this);
+    }   
+
+    int  threadNumber  ()      const;
+    void setThreadNumber (int i);
+    void reportProgress();
+    void reportProgressArrayImports(vec<unsigned int> &totalColumns);
+    virtual void reduceDB();
+    virtual lbool         solve_                   (bool do_simp = true, bool turn_off_simp = false);
+
+    vec<Lit>    importedClause; // Temporary clause used to copy each imported clause
+    uint64_t    nbexported;
+    uint64_t    nbimported; 
+    uint64_t    nbexportedunit, nbimportedunit , nbimportedInPurgatory, nbImportedGoodClauses;
+    unsigned int    goodlimitlbd; // LBD score of the "good" clauses, locally
+    int    goodlimitsize;
+    bool purgatory; // mode of operation
+    bool shareAfterProbation; // Share any none glue clause only after probation (seen 2 times in conflict analysis)
+    bool plingeling; // plingeling strategy for sharing clauses (experimental)
+
+    // Stats front end
+    uint64_t   getNbExported() { return nbexported;}
+    uint64_t   getNbImported() { return nbimported;}
+    uint64_t   getNbExportedUnit() {return nbexportedunit;}
+    
+    uint32_t  firstSharing, limitSharingByGoodLBD, limitSharingByFixedLimitLBD, limitSharingByFixedLimitSize;
+    uint32_t  probationByFollowingRoads, probationByFriend;
+    uint32_t  survivorLayers; // Number of layers for a common clause to survive
+    bool dontExportDirectReusedClauses ; // When true, directly reused clauses are not exported
+    uint64_t nbNotExportedBecauseDirectlyReused;
+    
+    
+    vec<uint32_t> goodImportsFromThreads; // Stats of good importations from other threads
+
+    virtual void parallelImportClauseDuringConflictAnalysis(Clause &c,CRef confl);
+    virtual bool parallelImportClauses(); // true if the empty clause was received
+    virtual void parallelImportUnaryClauses();
+    virtual void parallelExportUnaryClause(Lit p);
+    virtual void parallelExportClauseDuringSearch(Clause &c);
+    virtual bool parallelJobIsFinished();
+    virtual bool panicModeIsEnabled();
+    bool shareClause(Clause & c); // true if the clause was succesfully sent
+
+    
+
+};
+
+
+    inline int      ParallelSolver::threadNumber  ()      const   {return thn;}
+    inline void     ParallelSolver::setThreadNumber (int i)       {thn = i;}
+}
+#endif /* PARALLELSOLVER_H */
+
diff --git a/glucose-syrup/parallel/SharedCompanion.cc b/glucose-syrup/parallel/SharedCompanion.cc
new file mode 100644 (file)
index 0000000..dadc672
--- /dev/null
@@ -0,0 +1,167 @@
+/***************************************************************************************[SharedCompanion.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include "core/Solver.h"
+#include "parallel/ParallelSolver.h"
+#include "core/SolverTypes.h"
+#include "parallel/ClausesBuffer.h"
+#include "parallel/SharedCompanion.h"
+
+
+using namespace Glucose;
+
+SharedCompanion::SharedCompanion(int _nbThreads) :
+    nbThreads(_nbThreads), 
+    bjobFinished(false),
+    jobFinishedBy(NULL),
+    panicMode(false), // The bug in the SAT2014 competition :)
+    jobStatus(l_Undef),
+    random_seed(9164825) {
+
+       pthread_mutex_init(&mutexSharedClauseCompanion,NULL); // This is the shared companion lock
+       pthread_mutex_init(&mutexSharedUnitCompanion,NULL); // This is the shared companion lock
+       pthread_mutex_init(&mutexSharedCompanion,NULL); // This is the shared companion lock
+       pthread_mutex_init(&mutexJobFinished,NULL); // This is the shared companion lock
+       if (_nbThreads> 0)  {
+           setNbThreads(_nbThreads);
+           fprintf(stdout,"c Shared companion initialized: handling of clauses of %d threads.\nc %d ints for the sharing clause buffer (not expandable) .\n", _nbThreads, clausesBuffer.maxSize());
+       }
+
+}
+
+void SharedCompanion::setNbThreads(int _nbThreads) {
+   nbThreads = _nbThreads;
+   clausesBuffer.setNbThreads(_nbThreads); 
+}
+
+void SharedCompanion::printStats() {
+}
+
+// No multithread safe
+bool SharedCompanion::addSolver(ParallelSolver* s) {
+       watchedSolvers.push(s);
+       pthread_mutex_t* mu = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+       pthread_mutex_init(mu,NULL);
+       assert(s->thn == watchedSolvers.size()-1); // all solvers must have been registered in the good order
+       nextUnit.push(0);
+
+       return true;
+}
+void SharedCompanion::newVar(bool sign) {
+   isUnary .push(l_Undef);
+}
+
+void SharedCompanion::addLearnt(ParallelSolver *s,Lit unary) {
+  pthread_mutex_lock(&mutexSharedUnitCompanion);
+  if (isUnary[var(unary)]==l_Undef) {
+      unitLit.push(unary);
+      isUnary[var(unary)] = sign(unary)?l_False:l_True;
+  } 
+  pthread_mutex_unlock(&mutexSharedUnitCompanion);
+}
+
+Lit SharedCompanion::getUnary(ParallelSolver *s) {
+  int sn = s->thn;
+  Lit ret = lit_Undef;
+
+  pthread_mutex_lock(&mutexSharedUnitCompanion);
+  if (nextUnit[sn] < unitLit.size())
+      ret = unitLit[nextUnit[sn]++];
+  pthread_mutex_unlock(&mutexSharedUnitCompanion);
+ return ret;
+}
+
+// Specialized functions for this companion
+// must be multithread safe
+// Add a clause to the threads-wide clause database (all clauses, through)
+bool SharedCompanion::addLearnt(ParallelSolver *s, Clause & c) { 
+  int sn = s->thn; // thread number of the solver
+  bool ret = false;
+  assert(watchedSolvers.size()>sn);
+
+  pthread_mutex_lock(&mutexSharedClauseCompanion);
+  ret = clausesBuffer.pushClause(sn, c);
+  pthread_mutex_unlock(&mutexSharedClauseCompanion);
+  return ret;
+}
+
+
+bool SharedCompanion::getNewClause(ParallelSolver *s, int & threadOrigin, vec<Lit>& newclause) { // gets a new interesting clause for solver s 
+  int sn = s->thn;
+  
+    // First, let's get the clauses on the big blackboard
+    pthread_mutex_lock(&mutexSharedClauseCompanion);
+    bool b = clausesBuffer.getClause(sn, threadOrigin, newclause);
+    pthread_mutex_unlock(&mutexSharedClauseCompanion);
+  return b;
+}
+
+bool SharedCompanion::jobFinished() {
+    bool ret = false;
+    pthread_mutex_lock(&mutexJobFinished);
+    ret = bjobFinished;
+    pthread_mutex_unlock(&mutexJobFinished);
+    return ret;
+}
+
+bool SharedCompanion::IFinished(ParallelSolver *s) {
+    bool ret = false;
+    pthread_mutex_lock(&mutexJobFinished);
+    if (!bjobFinished) {
+       ret = true;
+       bjobFinished = true;
+       jobFinishedBy = s;
+    }
+    pthread_mutex_unlock(&mutexJobFinished);
+    return ret;
+}
+
+
+
diff --git a/glucose-syrup/parallel/SharedCompanion.h b/glucose-syrup/parallel/SharedCompanion.h
new file mode 100644 (file)
index 0000000..9ab3461
--- /dev/null
@@ -0,0 +1,122 @@
+/***************************************************************************************[SharedCompanion.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+/* This class is responsible for protecting (by mutex) information exchange between threads.
+ * It also allows each solver to send / receive clause / unary clauses.
+ *
+ * Only one sharedCompanion is created for all the solvers
+ */
+
+
+#ifndef SharedCompanion_h
+#define SharedCompanion_h
+#include "core/SolverTypes.h"
+#include "parallel/ParallelSolver.h"
+#include "parallel/SolverCompanion.h"
+#include "parallel/ClausesBuffer.h"
+
+namespace Glucose {
+
+    
+class SharedCompanion : public SolverCompanion {
+    friend class MultiSolvers;
+    friend class ParallelSolver;
+public:
+       SharedCompanion(int nbThreads=0);
+       void setNbThreads(int _nbThreads); // Sets the number of threads (cannot by changed once the solver is running)
+       void newVar(bool sign);            // Adds a var (used to keep track of unary variables)
+       void printStats();                 // Printing statistics of all solvers
+
+       bool jobFinished();                // True if the job is over
+       bool IFinished(ParallelSolver *s); // returns true if you are the first solver to finish
+       bool addSolver(ParallelSolver*);   // attach a solver to accompany 
+       void addLearnt(ParallelSolver *s,Lit unary);   // Add a unary clause to share
+       bool addLearnt(ParallelSolver *s, Clause & c); // Add a clause to the shared companion, as a database manager
+
+       bool getNewClause(ParallelSolver *s, int &th, vec<Lit> & nc); // gets a new interesting clause for solver s 
+       Lit getUnary(ParallelSolver *s);                              // Gets a new unary literal
+       inline ParallelSolver* winner(){return jobFinishedBy;}        // Gets the first solver that called IFinished()
+
+ protected:
+
+       ClausesBuffer clausesBuffer; // A big blackboard for all threads sharing non unary clauses
+       int nbThreads;               // Number of threads
+       
+       // A set of mutex variables
+       pthread_mutex_t mutexSharedCompanion; // mutex for any high level sync between all threads (like reportf)
+       pthread_mutex_t mutexSharedClauseCompanion; // mutex for reading/writing clauses on the blackboard
+       pthread_mutex_t mutexSharedUnitCompanion; // mutex for reading/writing unit clauses on the blackboard 
+        pthread_mutex_t mutexJobFinished;
+
+       bool bjobFinished;
+       ParallelSolver *jobFinishedBy;
+       bool panicMode;                        // panicMode means no more increasing space needed
+       lbool jobStatus;                       // globale status of the job
+
+        // Shared clauses are a queue of lits...
+       //      friend class wholearnt;
+       vec<int> nextUnit; // indice of next unit clause to retrieve for solver number i 
+       vec<Lit> unitLit;  // Set of unit literals found so far
+        vec<lbool> isUnary; // sign of the unary var (if proved, or l_Undef if not)    
+       double    random_seed;
+
+       // Returns a random float 0 <= x < 1. Seed must never be 0.
+       static inline double drand(double& seed) {
+           seed *= 1389796;
+           int q = (int)(seed / 2147483647);
+           seed -= (double)q * 2147483647;
+           return seed / 2147483647; }
+
+       // Returns a random integer 0 <= x < size. Seed must never be 0.
+       static inline int irand(double& seed, int size) {
+           return (int)(drand(seed) * size); }
+
+};
+}
+#endif
diff --git a/glucose-syrup/parallel/SolverCompanion.cc b/glucose-syrup/parallel/SolverCompanion.cc
new file mode 100644 (file)
index 0000000..8cd5c51
--- /dev/null
@@ -0,0 +1,87 @@
+/***************************************************************************************[SolverCompanion.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+/* This class is a general companion for a solver.
+ * The idea is to be able to have different kind of companions:
+ * - SharedCompanion that shares clauses between threads
+ * - NetworkCompanion (Not in this version) that sends clauses over the network
+ *
+ * The implementaton is trivial. Just keep track of watched Solvers by the companion.
+ **/
+
+#include "parallel/SolverCompanion.h"
+
+using namespace Glucose;
+
+SolverCompanion::SolverCompanion()
+{}
+
+SolverCompanion::~SolverCompanion()
+{}
+
+
+bool SolverCompanion::addSolver(ParallelSolver* s) {
+       watchedSolvers.push(s);
+       return true;
+}
+
+int SolverCompanion::runOnceCompanion() {
+       int errcode = 0;
+       for(int indexSolver = 0; indexSolver<watchedSolvers.size();indexSolver++) {
+         errcode=runOnceCompanion(watchedSolvers[indexSolver]);
+               if (errcode<0) return errcode;
+       }
+       return errcode;
+}
+
+int SolverCompanion::runOnceCompanion(ParallelSolver*s) {
+       return 0;
+}
+
+
diff --git a/glucose-syrup/parallel/SolverCompanion.h b/glucose-syrup/parallel/SolverCompanion.h
new file mode 100644 (file)
index 0000000..c7dc895
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************************[SolverCompanion.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+/* This class is a general companion for a solver.
+ * The idea is to be able to have different kind of companions:
+ * - SharedCompanion that shares clauses between threads
+ * - NetworkCompanion (Not in this version) that sends clauses over the network
+ **/
+
+#ifndef SolverCompanion_h
+#define SolverCompanion_h
+#include "mtl/Vec.h"
+namespace Glucose {
+    
+    class ParallelSolver;
+    
+class SolverCompanion {
+       public:
+       SolverCompanion();
+       ~SolverCompanion();
+       
+       bool addSolver(ParallelSolver* s); // attach a solver to accompany 
+       
+       int runOnceCompanion(); // run it as a thread, but run it just once... 
+       
+       protected:
+       int runOnceCompanion(ParallelSolver*s); // run it only on this watched solver
+       friend class ParallelSolver;
+       vec<ParallelSolver*> watchedSolvers; 
+};
+}
+#endif
+
diff --git a/glucose-syrup/parallel/SolverConfiguration.cc b/glucose-syrup/parallel/SolverConfiguration.cc
new file mode 100644 (file)
index 0000000..48127c2
--- /dev/null
@@ -0,0 +1,131 @@
+/***************************************************************************************[SolverConfiguration.cc]\r
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon\r
+                                CRIL - Univ. Artois, France\r
+                                LRI  - Univ. Paris Sud, France (2009-2013)\r
+                                Labri - Univ. Bordeaux, France\r
+\r
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon\r
+                                CRIL - Univ. Artois, France\r
+                                Labri - Univ. Bordeaux, France\r
+\r
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of\r
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it \r
+is based on. (see below).\r
+\r
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel\r
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software\r
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,\r
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is \r
+furnished to do so, subject to the following conditions:\r
+\r
+- The above and below copyrights notices and this permission notice shall be included in all\r
+copies or substantial portions of the Software;\r
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot\r
+be used in any competitive event (sat competitions/evaluations) without the express permission of \r
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event\r
+using Glucose Parallel as an embedded SAT engine (single core or not).\r
+\r
+\r
+--------------- Original Minisat Copyrights\r
+\r
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson\r
+Copyright (c) 2007-2010, Niklas Sorensson\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\r
+associated documentation files (the "Software"), to deal in the Software without restriction,\r
+including without limitation the rights to use, copy, modify, merge, publish, distribute,\r
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in all copies or\r
+substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT\r
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ **************************************************************************************************/\r
+\r
+#include "parallel/MultiSolvers.h"\r
+#include "core/Solver.h"\r
+//#include "parallel/ParallelSolver.h"\r
+#include "parallel/SolverConfiguration.h"\r
+\r
+using namespace Glucose;\r
+\r
+  void SolverConfiguration::configure(MultiSolvers *ms, int nbsolvers) {\r
+\r
+   if (nbsolvers < 2 ) return;\r
+\r
+   ms->solvers[1]->var_decay = 0.94;\r
+   ms->solvers[1]->max_var_decay = 0.96;\r
+   ms->solvers[1]->firstReduceDB=600;\r
+\r
+   if (nbsolvers < 3 ) return;\r
+\r
+   ms->solvers[2]->var_decay = 0.90;\r
+   ms->solvers[2]->max_var_decay = 0.97;\r
+   ms->solvers[2]->firstReduceDB=500;\r
+\r
+   if (nbsolvers < 4 ) return;\r
+\r
+   ms->solvers[3]->var_decay = 0.85;\r
+   ms->solvers[3]->max_var_decay = 0.93;\r
+   ms->solvers[3]->firstReduceDB=400;\r
+\r
+   if (nbsolvers < 5 ) return;\r
+\r
+   // Glucose 2.0 (+ blocked restarts)\r
+   ms->solvers[4]->var_decay = 0.95;\r
+   ms->solvers[4]->max_var_decay = 0.95;\r
+   ms->solvers[4]->firstReduceDB=4000;\r
+   ms->solvers[4]->lbdQueue.growTo(100);\r
+   ms->solvers[4]->sizeLBDQueue = 100;\r
+   ms->solvers[4]->K = 0.7;\r
+   ms->solvers[4]->incReduceDB = 500;\r
+\r
+   if (nbsolvers < 6 ) return;\r
+\r
+   ms->solvers[5]->var_decay = 0.93;\r
+   ms->solvers[5]->max_var_decay = 0.96;\r
+   ms->solvers[5]->firstReduceDB=100;\r
+   ms->solvers[5]->incReduceDB = 500;\r
+\r
+   if (nbsolvers < 7 ) return;\r
+\r
+   ms->solvers[6]->var_decay = 0.75;\r
+   ms->solvers[6]->max_var_decay = 0.94;\r
+   ms->solvers[6]->firstReduceDB=2000;\r
+\r
+   if (nbsolvers < 8 ) return; \r
+\r
+   ms->solvers[7]->var_decay = 0.94;\r
+   ms->solvers[7]->max_var_decay = 0.96;\r
+   ms->solvers[7]->firstReduceDB=800;\r
+\r
+   if (nbsolvers < 9) return;\r
+\r
+   ms->solvers[8]->reduceOnSize = true;\r
+\r
+   if (nbsolvers < 10 ) return;\r
+\r
+   ms->solvers[9]->reduceOnSize = true;\r
+   ms->solvers[9]->reduceOnSizeSize = 14;\r
+\r
+   if (nbsolvers < 11 ) return;\r
+\r
+   double noisevar_decay = 0.005;\r
+   int noiseReduceDB = 50;\r
+   for (int i=10;i<nbsolvers;i++) {\r
+       ms->solvers[i]-> var_decay = ms->solvers[i%8]->var_decay;\r
+       ms->solvers[i]-> max_var_decay = ms->solvers[i%8]->max_var_decay;\r
+       ms->solvers[i]-> firstReduceDB= ms->solvers[i%8]->firstReduceDB;\r
+       ms->solvers[i]->var_decay += noisevar_decay;\r
+       ms->solvers[i]->firstReduceDB+=noiseReduceDB;\r
+       if ((i+1) % 8 == 0) {\r
+          noisevar_decay += 0.006;\r
+          noiseReduceDB += 25;\r
+       }\r
+   }\r
+ }\r
diff --git a/glucose-syrup/parallel/SolverConfiguration.h b/glucose-syrup/parallel/SolverConfiguration.h
new file mode 100644 (file)
index 0000000..475ec72
--- /dev/null
@@ -0,0 +1,68 @@
+/***************************************************************************************[SolverConfiguration.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+
+#ifndef SolverConfiguration_h
+#define SolverConfiguration_h
+
+
+
+namespace Glucose {
+
+class MultiSolvers;
+
+class SolverConfiguration {
+
+public : 
+    static void configure(MultiSolvers *ms, int nbsolvers);
+    
+};
+
+}
+#endif
diff --git a/glucose-syrup/simp/Main.cc b/glucose-syrup/simp/Main.cc
new file mode 100644 (file)
index 0000000..ca3bf42
--- /dev/null
@@ -0,0 +1,294 @@
+/***************************************************************************************[Main.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include <errno.h>
+
+#include <signal.h>
+#include <zlib.h>
+#include <sys/resource.h>
+
+#include "utils/System.h"
+#include "utils/ParseUtils.h"
+#include "utils/Options.h"
+#include "core/Dimacs.h"
+#include "simp/SimpSolver.h"
+
+using namespace Glucose;
+
+//=================================================================================================
+
+static const char* _certified = "CORE -- CERTIFIED UNSAT";
+
+void printStats(Solver& solver)
+{
+    double cpu_time = cpuTime();
+    double mem_used = 0;//memUsedPeak();
+    printf("c restarts              : %" PRIu64" (%" PRIu64" conflicts in avg)\n", solver.starts,(solver.starts>0 ?solver.conflicts/solver.starts : 0));
+    printf("c blocked restarts      : %" PRIu64" (multiple: %" PRIu64") \n", solver.nbstopsrestarts,solver.nbstopsrestartssame);
+    printf("c last block at restart : %" PRIu64"\n",solver.lastblockatrestart);
+    printf("c nb ReduceDB           : %" PRIu64"\n", solver.nbReduceDB);
+    printf("c nb removed Clauses    : %" PRIu64"\n",solver.nbRemovedClauses);
+    printf("c nb learnts DL2        : %" PRIu64"\n", solver.nbDL2);
+    printf("c nb learnts size 2     : %" PRIu64"\n", solver.nbBin);
+    printf("c nb learnts size 1     : %" PRIu64"\n", solver.nbUn);
+
+    printf("c conflicts             : %-12" PRIu64"   (%.0f /sec)\n", solver.conflicts   , solver.conflicts   /cpu_time);
+    printf("c decisions             : %-12" PRIu64"   (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions   /cpu_time);
+    printf("c propagations          : %-12" PRIu64"   (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time);
+    printf("c conflict literals     : %-12" PRIu64"   (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals);
+    printf("c nb reduced Clauses    : %" PRIu64"\n",solver.nbReducedClauses);
+    
+    if (mem_used != 0) printf("Memory used           : %.2f MB\n", mem_used);
+    printf("c CPU time              : %g s\n", cpu_time);
+}
+
+
+
+static Solver* solver;
+// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case
+// for this feature of the Solver as it may take longer than an immediate call to '_exit()'.
+static void SIGINT_interrupt(int signum) { solver->interrupt(); }
+
+// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls
+// destructors and may cause deadlocks if a malloc/free function happens to be running (these
+// functions are guarded by locks for multithreaded use).
+static void SIGINT_exit(int signum) {
+    printf("\n"); printf("*** INTERRUPTED ***\n");
+    if (solver->verbosity > 0){
+        printStats(*solver);
+        printf("\n"); printf("*** INTERRUPTED ***\n"); }
+    _exit(1); }
+
+
+//=================================================================================================
+// Main:
+
+int main(int argc, char** argv)
+{
+    try {
+      printf("c\nc This is glucose 4.0 --  based on MiniSAT (Many thanks to MiniSAT team)\nc\n");
+
+      
+      setUsageHelp("c USAGE: %s [options] <input-file> <result-output-file>\n\n  where input may be either in plain or gzipped DIMACS.\n");
+        
+        
+#if defined(__linux__)
+        fpu_control_t oldcw, newcw;
+        _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
+        //printf("c WARNING: for repeatability, setting FPU to use double precision\n");
+#endif
+        // Extra options:
+        //
+        IntOption    verb   ("MAIN", "verb",   "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2));
+        BoolOption   mod   ("MAIN", "model",   "show model.", false);
+        IntOption    vv  ("MAIN", "vv",   "Verbosity every vv conflicts", 10000, IntRange(1,INT32_MAX));
+        BoolOption   pre    ("MAIN", "pre",    "Completely turn on/off any preprocessing.", true);
+        StringOption dimacs ("MAIN", "dimacs", "If given, stop after preprocessing and write the result to this file.");
+        IntOption    cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX));
+        IntOption    mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX));
+ //       BoolOption opt_incremental ("MAIN","incremental", "Use incremental SAT solving",false);
+
+         BoolOption    opt_certified      (_certified, "certified",    "Certified UNSAT using DRUP format", false);
+         StringOption  opt_certified_file      (_certified, "certified-output",    "Certified UNSAT output file", "NULL");
+         
+        parseOptions(argc, argv, true);
+        
+        SimpSolver  S;
+        double      initial_time = cpuTime();
+
+        S.parsing = 1;
+        //if (!pre) S.eliminate(true);
+
+        S.verbosity = verb;
+        S.verbEveryConflicts = vv;
+       S.showModel = mod;
+        
+        S.certifiedUNSAT = opt_certified;
+        if(S.certifiedUNSAT) {
+            if(!strcmp(opt_certified_file,"NULL")) {
+            S.certifiedOutput =  fopen("/dev/stdout", "wb");
+            } else {
+                S.certifiedOutput =  fopen(opt_certified_file, "wb");      
+            }
+            fprintf(S.certifiedOutput,"o proof DRUP\n");
+        }
+
+        solver = &S;
+        // Use signal handlers that forcibly quit until the solver will be able to respond to
+        // interrupts:
+        signal(SIGINT, SIGINT_exit);
+        signal(SIGXCPU,SIGINT_exit);
+
+
+        // Set limit on CPU-time:
+        if (cpu_lim != INT32_MAX){
+            rlimit rl;
+            getrlimit(RLIMIT_CPU, &rl);
+            if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){
+                rl.rlim_cur = cpu_lim;
+                if (setrlimit(RLIMIT_CPU, &rl) == -1)
+                    printf("c WARNING! Could not set resource limit: CPU-time.\n");
+            } }
+
+        // Set limit on virtual memory:
+        if (mem_lim != INT32_MAX){
+            rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024;
+            rlimit rl;
+            getrlimit(RLIMIT_AS, &rl);
+            if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
+                rl.rlim_cur = new_mem_lim;
+                if (setrlimit(RLIMIT_AS, &rl) == -1)
+                    printf("c WARNING! Could not set resource limit: Virtual memory.\n");
+            } }
+        
+        if (argc == 1)
+            printf("c Reading from standard input... Use '--help' for help.\n");
+
+        gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb");
+        if (in == NULL)
+            printf("ERROR! Could not open file: %s\n", argc == 1 ? "<stdin>" : argv[1]), exit(1);
+        
+      if (S.verbosity > 0){
+            printf("c ========================================[ Problem Statistics ]===========================================\n");
+            printf("c |                                                                                                       |\n"); }
+        
+        FILE* res = (argc >= 3) ? fopen(argv[argc-1], "wb") : NULL;
+        parse_DIMACS(in, S);
+        gzclose(in);
+
+       if (S.verbosity > 0){
+            printf("c |  Number of variables:  %12d                                                                   |\n", S.nVars());
+            printf("c |  Number of clauses:    %12d                                                                   |\n", S.nClauses()); }
+        
+        double parsed_time = cpuTime();
+        if (S.verbosity > 0){
+            printf("c |  Parse time:           %12.2f s                                                                 |\n", parsed_time - initial_time);
+            printf("c |                                                                                                       |\n"); }
+
+        // Change to signal-handlers that will only notify the solver and allow it to terminate
+        // voluntarily:
+        signal(SIGINT, SIGINT_interrupt);
+        signal(SIGXCPU,SIGINT_interrupt);
+
+        S.parsing = 0;
+        if(pre/* && !S.isIncremental()*/) {
+         printf("c | Preprocesing is fully done\n");
+         S.eliminate(true);
+        double simplified_time = cpuTime();
+        if (S.verbosity > 0){
+            printf("c |  Simplification time:  %12.2f s                                                                 |\n", simplified_time - parsed_time);
+ }
+       }
+       printf("c |                                                                                                       |\n");
+        if (!S.okay()){
+            if (S.certifiedUNSAT) fprintf(S.certifiedOutput, "0\n"), fclose(S.certifiedOutput);
+            if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res);
+            if (S.verbosity > 0){
+               printf("c =========================================================================================================\n");
+               printf("Solved by simplification\n");
+                printStats(S);
+                printf("\n"); }
+            printf("s UNSATISFIABLE\n");        
+            exit(20);
+        }
+
+        if (dimacs){
+            if (S.verbosity > 0)
+                printf("c =======================================[ Writing DIMACS ]===============================================\n");
+            S.toDimacs((const char*)dimacs);
+            if (S.verbosity > 0)
+                printStats(S);
+            exit(0);
+        }
+
+        vec<Lit> dummy;
+        lbool ret = S.solveLimited(dummy);
+        
+        if (S.verbosity > 0){
+            printStats(S);
+            printf("\n"); }
+        printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s INDETERMINATE\n");
+
+        if (res != NULL){
+            if (ret == l_True){
+                printf("SAT\n");
+                for (int i = 0; i < S.nVars(); i++)
+                    if (S.model[i] != l_Undef)
+                        fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
+                fprintf(res, " 0\n");
+            } else {
+             if (ret == l_False){
+               fprintf(res, "UNSAT\n");
+             }
+           }
+            fclose(res);
+        } else {
+         if(S.showModel && ret==l_True) {
+           printf("v ");
+           for (int i = 0; i < S.nVars(); i++)
+             if (S.model[i] != l_Undef)
+               printf("%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
+           printf(" 0\n");
+         }
+
+       }
+
+        if (S.certifiedUNSAT) fprintf(S.certifiedOutput, "0\n"), fclose(S.certifiedOutput);
+
+#ifdef NDEBUG
+        exit(ret == l_True ? 10 : ret == l_False ? 20 : 0);     // (faster than "return", which will invoke the destructor for 'Solver')
+#else
+        return (ret == l_True ? 10 : ret == l_False ? 20 : 0);
+#endif
+    } catch (OutOfMemoryException&){
+               printf("c =========================================================================================================\n");
+        printf("INDETERMINATE\n");
+        exit(0);
+    }
+}
diff --git a/glucose-syrup/simp/Makefile b/glucose-syrup/simp/Makefile
new file mode 100644 (file)
index 0000000..f5d4481
--- /dev/null
@@ -0,0 +1,5 @@
+EXEC = glucose
+DEPDIR    = mtl utils core
+MROOT = $(PWD)/..
+
+include $(MROOT)/mtl/template.mk
diff --git a/glucose-syrup/simp/SimpSolver.cc b/glucose-syrup/simp/SimpSolver.cc
new file mode 100644 (file)
index 0000000..84bc725
--- /dev/null
@@ -0,0 +1,826 @@
+/***************************************************************************************[SimpSolver.cc]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#include "mtl/Sort.h"
+#include "simp/SimpSolver.h"
+#include "utils/System.h"
+
+using namespace Glucose;
+
+//=================================================================================================
+// Options:
+
+
+static const char* _cat = "SIMP";
+
+static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
+static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
+static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
+static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
+static IntOption    opt_clause_lim       (_cat, "cl-lim",       "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20,   IntRange(-1, INT32_MAX));
+static IntOption    opt_subsumption_lim  (_cat, "sub-lim",      "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
+static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.",  0.5, DoubleRange(0, false, HUGE_VAL, false));
+
+
+//=================================================================================================
+// Constructor/Destructor:
+
+
+SimpSolver::SimpSolver() :
+   Solver()
+  , grow               (opt_grow)
+  , clause_lim         (opt_clause_lim)
+  , subsumption_lim    (opt_subsumption_lim)
+  , simp_garbage_frac  (opt_simp_garbage_frac)
+  , use_asymm          (opt_use_asymm)
+  , use_rcheck         (opt_use_rcheck)
+  , use_elim           (opt_use_elim)
+  , merges             (0)
+  , asymm_lits         (0)
+  , eliminated_vars    (0)
+  , elimorder          (1)
+  , use_simplification (true)
+  , occurs             (ClauseDeleted(ca))
+  , elim_heap          (ElimLt(n_occ))
+  , bwdsub_assigns     (0)
+  , n_touched          (0)
+{
+    vec<Lit> dummy(1,lit_Undef);
+    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
+    bwdsub_tmpunit        = ca.alloc(dummy);
+    remove_satisfied      = false;
+}
+
+
+SimpSolver::~SimpSolver()
+{
+}
+
+
+
+SimpSolver::SimpSolver(const SimpSolver &s) : Solver(s)
+  , grow               (s.grow)
+  , clause_lim         (s.clause_lim)
+  , subsumption_lim    (s.subsumption_lim)
+  , simp_garbage_frac  (s.simp_garbage_frac)
+  , use_asymm          (s.use_asymm)
+  , use_rcheck         (s.use_rcheck)
+  , use_elim           (s.use_elim)
+  , merges             (s.merges)
+  , asymm_lits         (s.asymm_lits)
+  , eliminated_vars    (s.eliminated_vars)
+  , elimorder          (s.elimorder)
+  , use_simplification (s.use_simplification)
+  , occurs             (ClauseDeleted(ca))
+  , elim_heap          (ElimLt(n_occ))
+  , bwdsub_assigns     (s.bwdsub_assigns)
+  , n_touched          (s.n_touched)
+{
+    // TODO: Copy dummy... what is it???
+    vec<Lit> dummy(1,lit_Undef);
+    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
+    bwdsub_tmpunit        = ca.alloc(dummy);
+    remove_satisfied      = false;
+    //End TODO  
+    
+    
+    s.elimclauses.memCopyTo(elimclauses);
+    s.touched.memCopyTo(touched);
+    s.occurs.copyTo(occurs);
+    s.n_occ.memCopyTo(n_occ);
+    s.elim_heap.copyTo(elim_heap);
+    s.subsumption_queue.copyTo(subsumption_queue);
+    s.frozen.memCopyTo(frozen);
+    s.eliminated.memCopyTo(eliminated);
+
+    use_simplification = s.use_simplification;
+    bwdsub_assigns = s.bwdsub_assigns;
+    n_touched = s.n_touched;
+    bwdsub_tmpunit = s.bwdsub_tmpunit;
+    qhead = s.qhead;
+    ok = s.ok;
+}
+
+
+
+Var SimpSolver::newVar(bool sign, bool dvar) {
+    Var v = Solver::newVar(sign, dvar);
+    frozen    .push((char)false);
+    eliminated.push((char)false);
+
+    if (use_simplification){
+        n_occ     .push(0);
+        n_occ     .push(0);
+        occurs    .init(v);
+        touched   .push(0);
+        elim_heap .insert(v);
+    }
+    return v; }
+
+lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
+{
+    vec<Var> extra_frozen;
+    lbool    result = l_True;
+    do_simp &= use_simplification;
+
+    if (do_simp){
+        // Assumptions must be temporarily frozen to run variable elimination:
+        for (int i = 0; i < assumptions.size(); i++){
+            Var v = var(assumptions[i]);
+
+            // If an assumption has been eliminated, remember it.
+            assert(!isEliminated(v));
+
+            if (!frozen[v]){
+                // Freeze and store.
+                setFrozen(v, true);
+                extra_frozen.push(v);
+            } }
+
+        result = lbool(eliminate(turn_off_simp));
+    }
+
+    if (result == l_True)
+        result = Solver::solve_();
+    else if (verbosity >= 1)
+        printf("===============================================================================\n");
+
+    if (result == l_True)
+        extendModel();
+
+    if (do_simp)
+        // Unfreeze the assumptions that were frozen:
+        for (int i = 0; i < extra_frozen.size(); i++)
+            setFrozen(extra_frozen[i], false);
+
+
+    return result;
+}
+
+
+
+bool SimpSolver::addClause_(vec<Lit>& ps)
+{
+#ifndef NDEBUG
+    for (int i = 0; i < ps.size(); i++)
+        assert(!isEliminated(var(ps[i])));
+#endif
+    int nclauses = clauses.size();
+
+    if (use_rcheck && implied(ps))
+        return true;
+
+    if (!Solver::addClause_(ps))
+        return false;
+
+    if(!parsing && certifiedUNSAT) {
+      for (int i = 0; i < ps.size(); i++)
+        fprintf(certifiedOutput, "%i " , (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1) );
+      fprintf(certifiedOutput, "0\n");
+    }
+
+    if (use_simplification && clauses.size() == nclauses + 1){
+        CRef          cr = clauses.last();
+        const Clause& c  = ca[cr];
+
+        // NOTE: the clause is added to the queue immediately and then
+        // again during 'gatherTouchedClauses()'. If nothing happens
+        // in between, it will only be checked once. Otherwise, it may
+        // be checked twice unnecessarily. This is an unfortunate
+        // consequence of how backward subsumption is used to mimic
+        // forward subsumption.
+        subsumption_queue.insert(cr);
+        for (int i = 0; i < c.size(); i++){
+            occurs[var(c[i])].push(cr);
+            n_occ[toInt(c[i])]++;
+            touched[var(c[i])] = 1;
+            n_touched++;
+            if (elim_heap.inHeap(var(c[i])))
+                elim_heap.increase(var(c[i]));
+        }
+    }
+
+    return true;
+}
+
+
+
+void SimpSolver::removeClause(CRef cr,bool inPurgatory)
+{
+    const Clause& c = ca[cr];
+
+    if (use_simplification)
+        for (int i = 0; i < c.size(); i++){
+            n_occ[toInt(c[i])]--;
+            updateElimHeap(var(c[i]));
+            occurs.smudge(var(c[i]));
+        }
+
+    Solver::removeClause(cr,inPurgatory);
+}
+
+
+bool SimpSolver::strengthenClause(CRef cr, Lit l)
+{
+    Clause& c = ca[cr];
+    assert(decisionLevel() == 0);
+    assert(use_simplification);
+
+    // FIX: this is too inefficient but would be nice to have (properly implemented)
+    // if (!find(subsumption_queue, &c))
+    subsumption_queue.insert(cr);
+
+    if (certifiedUNSAT) {
+      for (int i = 0; i < c.size(); i++)
+        if (c[i] != l) fprintf(certifiedOutput, "%i " , (var(c[i]) + 1) * (-2 * sign(c[i]) + 1) );
+      fprintf(certifiedOutput, "0\n");
+    }
+
+    if (c.size() == 2){
+        removeClause(cr);
+        c.strengthen(l);
+    }else{
+        if (certifiedUNSAT) {
+          fprintf(certifiedOutput, "d ");
+          for (int i = 0; i < c.size(); i++)
+            fprintf(certifiedOutput, "%i " , (var(c[i]) + 1) * (-2 * sign(c[i]) + 1) );
+          fprintf(certifiedOutput, "0\n");
+        }
+
+        detachClause(cr, true);
+        c.strengthen(l);
+        attachClause(cr);
+        remove(occurs[var(l)], cr);
+        n_occ[toInt(l)]--;
+        updateElimHeap(var(l));
+    }
+
+    return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true;
+}
+
+
+// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
+bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
+{
+    merges++;
+    out_clause.clear();
+
+    bool  ps_smallest = _ps.size() < _qs.size();
+    const Clause& ps  =  ps_smallest ? _qs : _ps;
+    const Clause& qs  =  ps_smallest ? _ps : _qs;
+
+    for (int i = 0; i < qs.size(); i++){
+        if (var(qs[i]) != v){
+            for (int j = 0; j < ps.size(); j++)
+                if (var(ps[j]) == var(qs[i]))
+                    if (ps[j] == ~qs[i])
+                        return false;
+                    else
+                        goto next;
+            out_clause.push(qs[i]);
+        }
+        next:;
+    }
+
+    for (int i = 0; i < ps.size(); i++)
+        if (var(ps[i]) != v)
+            out_clause.push(ps[i]);
+
+    return true;
+}
+
+
+// Returns FALSE if clause is always satisfied.
+bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
+{
+    merges++;
+
+    bool  ps_smallest = _ps.size() < _qs.size();
+    const Clause& ps  =  ps_smallest ? _qs : _ps;
+    const Clause& qs  =  ps_smallest ? _ps : _qs;
+    const Lit*  __ps  = (const Lit*)ps;
+    const Lit*  __qs  = (const Lit*)qs;
+
+    size = ps.size()-1;
+
+    for (int i = 0; i < qs.size(); i++){
+        if (var(__qs[i]) != v){
+            for (int j = 0; j < ps.size(); j++)
+                if (var(__ps[j]) == var(__qs[i]))
+                    if (__ps[j] == ~__qs[i])
+                        return false;
+                    else
+                        goto next;
+            size++;
+        }
+        next:;
+    }
+
+    return true;
+}
+
+
+void SimpSolver::gatherTouchedClauses()
+{
+    if (n_touched == 0) return;
+
+    int i,j;
+    for (i = j = 0; i < subsumption_queue.size(); i++)
+        if (ca[subsumption_queue[i]].mark() == 0)
+            ca[subsumption_queue[i]].mark(2);
+
+    for (i = 0; i < touched.size(); i++)
+        if (touched[i]){
+            const vec<CRef>& cs = occurs.lookup(i);
+            for (j = 0; j < cs.size(); j++)
+                if (ca[cs[j]].mark() == 0){
+                    subsumption_queue.insert(cs[j]);
+                    ca[cs[j]].mark(2);
+                }
+            touched[i] = 0;
+        }
+
+    for (i = 0; i < subsumption_queue.size(); i++)
+        if (ca[subsumption_queue[i]].mark() == 2)
+            ca[subsumption_queue[i]].mark(0);
+
+    n_touched = 0;
+}
+
+
+bool SimpSolver::implied(const vec<Lit>& c)
+{
+    assert(decisionLevel() == 0);
+
+    trail_lim.push(trail.size());
+    for (int i = 0; i < c.size(); i++)
+        if (value(c[i]) == l_True){
+            cancelUntil(0);
+            return false;
+        }else if (value(c[i]) != l_False){
+            assert(value(c[i]) == l_Undef);
+            uncheckedEnqueue(~c[i]);
+        }
+
+    bool result = propagate() != CRef_Undef;
+    cancelUntil(0);
+    return result;
+}
+
+
+// Backward subsumption + backward subsumption resolution
+bool SimpSolver::backwardSubsumptionCheck(bool verbose)
+{
+    int cnt = 0;
+    int subsumed = 0;
+    int deleted_literals = 0;
+    assert(decisionLevel() == 0);
+
+    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
+
+        // Empty subsumption queue and return immediately on user-interrupt:
+        if (asynch_interrupt){
+            subsumption_queue.clear();
+            bwdsub_assigns = trail.size();
+            break; }
+
+        // Check top-level assignments by creating a dummy clause and placing it in the queue:
+        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
+            Lit l = trail[bwdsub_assigns++];
+            ca[bwdsub_tmpunit][0] = l;
+            ca[bwdsub_tmpunit].calcAbstraction();
+            subsumption_queue.insert(bwdsub_tmpunit); }
+
+        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
+        Clause& c  = ca[cr];
+
+        if (c.mark()) continue;
+
+        if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
+            printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
+
+        assert(c.size() > 1 || value(c[0]) == l_True);    // Unit-clauses should have been propagated before this point.
+
+        // Find best variable to scan:
+        Var best = var(c[0]);
+        for (int i = 1; i < c.size(); i++)
+            if (occurs[var(c[i])].size() < occurs[best].size())
+                best = var(c[i]);
+
+        // Search all candidates:
+        vec<CRef>& _cs = occurs.lookup(best);
+        CRef*       cs = (CRef*)_cs;
+
+        for (int j = 0; j < _cs.size(); j++)
+            if (c.mark())
+                break;
+            else if (!ca[cs[j]].mark() &&  cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
+                Lit l = c.subsumes(ca[cs[j]]);
+
+                if (l == lit_Undef)
+                    subsumed++, removeClause(cs[j]);
+                else if (l != lit_Error){
+                    deleted_literals++;
+
+                    if (!strengthenClause(cs[j], ~l))
+                        return false;
+
+                    // Did current candidate get deleted from cs? Then check candidate at index j again:
+                    if (var(l) == best)
+                        j--;
+                }
+            }
+    }
+
+    return true;
+}
+
+
+bool SimpSolver::asymm(Var v, CRef cr)
+{
+    Clause& c = ca[cr];
+    assert(decisionLevel() == 0);
+
+    if (c.mark() || satisfied(c)) return true;
+
+    trail_lim.push(trail.size());
+    Lit l = lit_Undef;
+    for (int i = 0; i < c.size(); i++)
+        if (var(c[i]) != v && value(c[i]) != l_False)
+            uncheckedEnqueue(~c[i]);
+        else
+            l = c[i];
+
+    if (propagate() != CRef_Undef){
+        cancelUntil(0);
+        asymm_lits++;
+        if (!strengthenClause(cr, l))
+            return false;
+    }else
+        cancelUntil(0);
+
+    return true;
+}
+
+
+bool SimpSolver::asymmVar(Var v)
+{
+    assert(use_simplification);
+
+    const vec<CRef>& cls = occurs.lookup(v);
+
+    if (value(v) != l_Undef || cls.size() == 0)
+        return true;
+
+    for (int i = 0; i < cls.size(); i++)
+        if (!asymm(v, cls[i]))
+            return false;
+
+    return backwardSubsumptionCheck();
+}
+
+
+static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
+{
+    elimclauses.push(toInt(x));
+    elimclauses.push(1);
+}
+
+
+static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
+{
+    int first = elimclauses.size();
+    int v_pos = -1;
+
+    // Copy clause to elimclauses-vector. Remember position where the
+    // variable 'v' occurs:
+    for (int i = 0; i < c.size(); i++){
+        elimclauses.push(toInt(c[i]));
+        if (var(c[i]) == v)
+            v_pos = i + first;
+    }
+    assert(v_pos != -1);
+
+    // Swap the first literal with the 'v' literal, so that the literal
+    // containing 'v' will occur first in the clause:
+    uint32_t tmp = elimclauses[v_pos];
+    elimclauses[v_pos] = elimclauses[first];
+    elimclauses[first] = tmp;
+
+    // Store the length of the clause last:
+    elimclauses.push(c.size());
+}
+
+
+
+bool SimpSolver::eliminateVar(Var v)
+{
+    assert(!frozen[v]);
+    assert(!isEliminated(v));
+    assert(value(v) == l_Undef);
+
+    // Split the occurrences into positive and negative:
+    //
+    const vec<CRef>& cls = occurs.lookup(v);
+    vec<CRef>        pos, neg;
+    for (int i = 0; i < cls.size(); i++)
+        (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
+
+    // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
+    // clause must exceed the limit on the maximal clause size (if it is set):
+    //
+    int cnt         = 0;
+    int clause_size = 0;
+
+    for (int i = 0; i < pos.size(); i++)
+        for (int j = 0; j < neg.size(); j++)
+            if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) && 
+                (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
+                return true;
+
+    // Delete and store old clauses:
+    eliminated[v] = true;
+    setDecisionVar(v, false);
+    eliminated_vars++;
+
+    if (pos.size() > neg.size()){
+        for (int i = 0; i < neg.size(); i++)
+            mkElimClause(elimclauses, v, ca[neg[i]]);
+        mkElimClause(elimclauses, mkLit(v));
+    }else{
+        for (int i = 0; i < pos.size(); i++)
+            mkElimClause(elimclauses, v, ca[pos[i]]);
+        mkElimClause(elimclauses, ~mkLit(v));
+    }
+
+
+    // Produce clauses in cross product:
+    vec<Lit>& resolvent = add_tmp;
+    for (int i = 0; i < pos.size(); i++)
+        for (int j = 0; j < neg.size(); j++)
+            if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
+                return false;
+
+    for (int i = 0; i < cls.size(); i++)
+        removeClause(cls[i]);
+
+    // Free occurs list for this variable:
+    occurs[v].clear(true);
+
+    // Free watchers lists for this variable, if possible:
+    if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
+    if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
+
+    return backwardSubsumptionCheck();
+}
+
+
+bool SimpSolver::substitute(Var v, Lit x)
+{
+    assert(!frozen[v]);
+    assert(!isEliminated(v));
+    assert(value(v) == l_Undef);
+
+    if (!ok) return false;
+
+    eliminated[v] = true;
+    setDecisionVar(v, false);
+    const vec<CRef>& cls = occurs.lookup(v);
+    
+    vec<Lit>& subst_clause = add_tmp;
+    for (int i = 0; i < cls.size(); i++){
+        Clause& c = ca[cls[i]];
+
+        subst_clause.clear();
+        for (int j = 0; j < c.size(); j++){
+            Lit p = c[j];
+            subst_clause.push(var(p) == v ? x ^ sign(p) : p);
+        }
+
+        if (!addClause_(subst_clause))
+            return ok = false;
+
+       removeClause(cls[i]);
+   }
+
+    return true;
+}
+
+
+void SimpSolver::extendModel()
+{
+    int i, j;
+    Lit x;
+
+    if(model.size()==0) model.growTo(nVars());
+    
+    for (i = elimclauses.size()-1; i > 0; i -= j){
+        for (j = elimclauses[i--]; j > 1; j--, i--)
+            if (modelValue(toLit(elimclauses[i])) != l_False)
+                goto next;
+
+        x = toLit(elimclauses[i]);
+        model[var(x)] = lbool(!sign(x));
+    next:;
+    }
+}
+
+
+bool SimpSolver::eliminate(bool turn_off_elim)
+{
+    if (!simplify()) {
+        ok = false;
+        return false;
+    }
+    else if (!use_simplification)
+        return true;
+
+    // Main simplification loop:
+    //
+
+    int toPerform = clauses.size()<=4800000;
+    
+    if(!toPerform) {
+      printf("c Too many clauses... No preprocessing\n");
+    }
+
+    while (toPerform && (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0)){
+
+        gatherTouchedClauses();
+        // printf("  ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
+        if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && 
+            !backwardSubsumptionCheck(true)){
+            ok = false; goto cleanup; }
+
+        // Empty elim_heap and return immediately on user-interrupt:
+        if (asynch_interrupt){
+            assert(bwdsub_assigns == trail.size());
+            assert(subsumption_queue.size() == 0);
+            assert(n_touched == 0);
+            elim_heap.clear();
+            goto cleanup; }
+
+        // printf("  ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
+        for (int cnt = 0; !elim_heap.empty(); cnt++){
+            Var elim = elim_heap.removeMin();
+            
+            if (asynch_interrupt) break;
+
+            if (isEliminated(elim) || value(elim) != l_Undef) continue;
+
+            if (verbosity >= 2 && cnt % 100 == 0)
+                printf("elimination left: %10d\r", elim_heap.size());
+
+            if (use_asymm){
+                // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
+                bool was_frozen = frozen[elim];
+                frozen[elim] = true;
+                if (!asymmVar(elim)){
+                    ok = false; goto cleanup; }
+                frozen[elim] = was_frozen; }
+
+            // At this point, the variable may have been set by assymetric branching, so check it
+            // again. Also, don't eliminate frozen variables:
+            if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
+                ok = false; goto cleanup; }
+
+            checkGarbage(simp_garbage_frac);
+        }
+
+        assert(subsumption_queue.size() == 0);
+    }
+ cleanup:
+
+    // If no more simplification is needed, free all simplification-related data structures:
+    if (turn_off_elim){
+        touched  .clear(true);
+        occurs   .clear(true);
+        n_occ    .clear(true);
+        elim_heap.clear(true);
+        subsumption_queue.clear(true);
+
+        use_simplification    = false;
+        remove_satisfied      = true;
+        ca.extra_clause_field = false;
+
+        // Force full cleanup (this is safe and desirable since it only happens once):
+        rebuildOrderHeap();
+        garbageCollect();
+    }else{
+        // Cheaper cleanup:
+        cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow?
+        checkGarbage();
+    }
+
+    if (verbosity >= 0 && elimclauses.size() > 0)
+        printf("c |  Eliminated clauses:     %10.2f Mb                                                                |\n", 
+               double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
+
+               
+    return ok;
+
+    
+}
+
+
+void SimpSolver::cleanUpClauses()
+{
+    occurs.cleanAll();
+    int i,j;
+    for (i = j = 0; i < clauses.size(); i++)
+        if (ca[clauses[i]].mark() == 0)
+            clauses[j++] = clauses[i];
+    clauses.shrink(i - j);
+}
+
+
+//=================================================================================================
+// Garbage Collection methods:
+
+
+void SimpSolver::relocAll(ClauseAllocator& to)
+{
+    if (!use_simplification) return;
+
+    // All occurs lists:
+    //
+    for (int i = 0; i < nVars(); i++){
+        vec<CRef>& cs = occurs[i];
+        for (int j = 0; j < cs.size(); j++)
+            ca.reloc(cs[j], to);
+    }
+
+    // Subsumption queue:
+    //
+    for (int i = 0; i < subsumption_queue.size(); i++)
+        ca.reloc(subsumption_queue[i], to);
+
+    // Temporary clause:
+    //
+    ca.reloc(bwdsub_tmpunit, to);
+}
+
+
+void SimpSolver::garbageCollect()
+{
+    // Initialize the next region to a size corresponding to the estimated utilization degree. This
+    // is not precise but should avoid some unnecessary reallocations for the new region:
+    ClauseAllocator to(ca.size() - ca.wasted()); 
+
+    cleanUpClauses();
+    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
+    relocAll(to);
+    Solver::relocAll(to);
+    if (verbosity >= 2)
+        printf("|  Garbage collection:   %12d bytes => %12d bytes             |\n", 
+               ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+    to.moveTo(ca);
+}
diff --git a/glucose-syrup/simp/SimpSolver.h b/glucose-syrup/simp/SimpSolver.h
new file mode 100644 (file)
index 0000000..5f457a8
--- /dev/null
@@ -0,0 +1,237 @@
+/***************************************************************************************[SimpSolver.h]
+ Glucose -- Copyright (c) 2009-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                LRI  - Univ. Paris Sud, France (2009-2013)
+                                Labri - Univ. Bordeaux, France
+
+ Syrup (Glucose Parallel) -- Copyright (c) 2013-2014, Gilles Audemard, Laurent Simon
+                                CRIL - Univ. Artois, France
+                                Labri - Univ. Bordeaux, France
+
+Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
+Glucose (sources until 2013, Glucose 3.0, single core) are exactly the same as Minisat on which it 
+is based on. (see below).
+
+Glucose-Syrup sources are based on another copyright. Permissions and copyrights for the parallel
+version of Glucose-Syrup (the "Software") are granted, free of charge, to deal with the Software
+without restriction, including the rights to use, copy, modify, merge, publish, distribute,
+sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+- The above and below copyrights notices and this permission notice shall be included in all
+copies or substantial portions of the Software;
+- The parallel version of Glucose (all files modified since Glucose 3.0 releases, 2013) cannot
+be used in any competitive event (sat competitions/evaluations) without the express permission of 
+the authors (Gilles Audemard / Laurent Simon). This is also the case for any competitive event
+using Glucose Parallel as an embedded SAT engine (single core or not).
+
+
+--------------- Original Minisat Copyrights
+
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************************************/
+
+#ifndef Glucose_SimpSolver_h
+#define Glucose_SimpSolver_h
+
+#include "mtl/Queue.h"
+#include "core/Solver.h"
+#include "mtl/Clone.h"
+
+namespace Glucose {
+
+//=================================================================================================
+
+
+class SimpSolver : public Solver {
+ public:
+    // Constructor/Destructor:
+    //
+    SimpSolver();
+    ~SimpSolver();
+    
+    SimpSolver(const  SimpSolver &s);
+    
+
+    /**
+     * Clone function
+    */
+    virtual Clone* clone() const {
+        return  new SimpSolver(*this);
+    }   
+
+    
+    // Problem specification:
+    //
+    virtual Var     newVar    (bool polarity = true, bool dvar = true); // Add a new variable with parameters specifying variable mode.
+    bool    addClause (const vec<Lit>& ps);
+    bool    addEmptyClause();                // Add the empty clause to the solver.
+    bool    addClause (Lit p);               // Add a unit clause to the solver.
+    bool    addClause (Lit p, Lit q);        // Add a binary clause to the solver.
+    bool    addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
+    virtual bool    addClause_(      vec<Lit>& ps);
+    bool    substitute(Var v, Lit x);  // Replace all occurences of v with x (may cause a contradiction).
+
+    // Variable mode:
+    // 
+    void    setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated.
+    bool    isEliminated(Var v) const;
+
+    // Solving:
+    //
+    bool    solve       (const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
+    lbool   solveLimited(const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
+    bool    solve       (                     bool do_simp = true, bool turn_off_simp = false);
+    bool    solve       (Lit p       ,        bool do_simp = true, bool turn_off_simp = false);       
+    bool    solve       (Lit p, Lit q,        bool do_simp = true, bool turn_off_simp = false);
+    bool    solve       (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false);
+    bool    eliminate   (bool turn_off_elim = false);  // Perform variable elimination based simplification. 
+
+    // Memory managment:
+    //
+    virtual void garbageCollect();
+
+
+    // Generate a (possibly simplified) DIMACS file:
+    //
+#if 0
+    void    toDimacs  (const char* file, const vec<Lit>& assumps);
+    void    toDimacs  (const char* file);
+    void    toDimacs  (const char* file, Lit p);
+    void    toDimacs  (const char* file, Lit p, Lit q);
+    void    toDimacs  (const char* file, Lit p, Lit q, Lit r);
+#endif
+
+    // Mode of operation:
+    //
+    int     parsing;
+    int     grow;              // Allow a variable elimination step to grow by a number of clauses (default to zero).
+    int     clause_lim;        // Variables are not eliminated if it produces a resolvent with a length above this limit.
+                               // -1 means no limit.
+    int     subsumption_lim;   // Do not check if subsumption against a clause larger than this. -1 means no limit.
+    double  simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac').
+
+    bool    use_asymm;         // Shrink clauses by asymmetric branching.
+    bool    use_rcheck;        // Check if a clause is already implied. Prett costly, and subsumes subsumptions :)
+    bool    use_elim;          // Perform variable elimination.
+    // Statistics:
+    //
+    int     merges;
+    int     asymm_lits;
+    int     eliminated_vars;
+
+ protected:
+
+    // Helper structures:
+    //
+    struct ElimLt {
+        const vec<int>& n_occ;
+        explicit ElimLt(const vec<int>& no) : n_occ(no) {}
+
+        // TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating
+        // 32-bit implementation instead then, but this will have to do for now.
+        uint64_t cost  (Var x)        const { return (uint64_t)n_occ[toInt(mkLit(x))] * (uint64_t)n_occ[toInt(~mkLit(x))]; }
+        bool operator()(Var x, Var y) const { return cost(x) < cost(y); }
+        
+        // TODO: investigate this order alternative more.
+        // bool operator()(Var x, Var y) const { 
+        //     int c_x = cost(x);
+        //     int c_y = cost(y);
+        //     return c_x < c_y || c_x == c_y && x < y; }
+    };
+
+    struct ClauseDeleted {
+        const ClauseAllocator& ca;
+        explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
+        bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } };
+
+    // Solver state:
+    //
+    int                 elimorder;
+    bool                use_simplification;
+    vec<uint32_t>       elimclauses;
+    vec<char>           touched;
+    OccLists<Var, vec<CRef>, ClauseDeleted>
+                        occurs;
+    vec<int>            n_occ;
+    Heap<ElimLt>        elim_heap;
+    Queue<CRef>         subsumption_queue;
+    vec<char>           frozen;
+    vec<char>           eliminated;
+    int                 bwdsub_assigns;
+    int                 n_touched;
+
+    // Temporaries:
+    //
+    CRef                bwdsub_tmpunit;
+
+    // Main internal methods:
+    //
+    virtual lbool         solve_                   (bool do_simp = true, bool turn_off_simp = false);
+    bool          asymm                    (Var v, CRef cr);
+    bool          asymmVar                 (Var v);
+    void          updateElimHeap           (Var v);
+    void          gatherTouchedClauses     ();
+    bool          merge                    (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause);
+    bool          merge                    (const Clause& _ps, const Clause& _qs, Var v, int& size);
+    bool          backwardSubsumptionCheck (bool verbose = false);
+    bool          eliminateVar             (Var v);
+    void          extendModel              ();
+
+    void          removeClause             (CRef cr,bool inPurgatory=false);
+    bool          strengthenClause         (CRef cr, Lit l);
+    void          cleanUpClauses           ();
+    bool          implied                  (const vec<Lit>& c);
+    virtual void          relocAll                 (ClauseAllocator& to);
+};
+
+
+//=================================================================================================
+// Implementation of inline methods:
+
+
+inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; }
+inline void SimpSolver::updateElimHeap(Var v) {
+    assert(use_simplification);
+    // if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)
+    if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef))
+        elim_heap.update(v); }
+
+
+inline bool SimpSolver::addClause    (const vec<Lit>& ps)    { ps.copyTo(add_tmp); return addClause_(add_tmp); }
+inline bool SimpSolver::addEmptyClause()                     { add_tmp.clear(); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause    (Lit p)                 { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause    (Lit p, Lit q)          { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause    (Lit p, Lit q, Lit r)   { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+inline void SimpSolver::setFrozen    (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
+
+inline bool SimpSolver::solve        (                     bool do_simp, bool turn_off_simp)  { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve        (Lit p       ,        bool do_simp, bool turn_off_simp)  { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve        (Lit p, Lit q,        bool do_simp, bool turn_off_simp)  { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve        (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp)  { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve        (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){ 
+    budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; }
+
+inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){ 
+    assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/utils/Makefile b/glucose-syrup/utils/Makefile
new file mode 100644 (file)
index 0000000..204cea5
--- /dev/null
@@ -0,0 +1,4 @@
+EXEC      = system_test
+DEPDIR    = mtl
+
+include $(MROOT)/mtl/template.mk
diff --git a/glucose-syrup/utils/Options.cc b/glucose-syrup/utils/Options.cc
new file mode 100644 (file)
index 0000000..73d7f58
--- /dev/null
@@ -0,0 +1,91 @@
+/**************************************************************************************[Options.cc]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#include "mtl/Sort.h"
+#include "utils/Options.h"
+#include "utils/ParseUtils.h"
+
+using namespace Glucose;
+
+void Glucose::parseOptions(int& argc, char** argv, bool strict)
+{
+    int i, j;
+    for (i = j = 1; i < argc; i++){
+        const char* str = argv[i];
+        if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){
+            if (*str == '\0')
+                printUsageAndExit(argc, argv);
+            else if (match(str, "-verb"))
+                printUsageAndExit(argc, argv, true);
+        } else {
+            bool parsed_ok = false;
+        
+            for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){
+                parsed_ok = Option::getOptionList()[k]->parse(argv[i]);
+
+                // fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip");
+            }
+
+            if (!parsed_ok)
+                if (strict && match(argv[i], "-"))
+                    fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1);
+                else
+                    argv[j++] = argv[i];
+        }
+    }
+
+    argc -= (i - j);
+}
+
+
+void Glucose::setUsageHelp      (const char* str){ Option::getUsageString() = str; }
+void Glucose::setHelpPrefixStr  (const char* str){ Option::getHelpPrefixString() = str; }
+void Glucose::printUsageAndExit (int argc, char** argv, bool verbose)
+{
+    const char* usage = Option::getUsageString();
+    if (usage != NULL)
+        fprintf(stderr, usage, argv[0]);
+
+        sort(Option::getOptionList(), Option::OptionLt());
+
+    const char* prev_cat  = NULL;
+    const char* prev_type = NULL;
+
+    for (int i = 0; i < Option::getOptionList().size(); i++){
+        const char* cat  = Option::getOptionList()[i]->category;
+        const char* type = Option::getOptionList()[i]->type_name;
+
+        if (cat != prev_cat)
+            fprintf(stderr, "\n%s OPTIONS:\n\n", cat);
+        else if (type != prev_type)
+            fprintf(stderr, "\n");
+
+        Option::getOptionList()[i]->help(verbose);
+
+        prev_cat  = Option::getOptionList()[i]->category;
+        prev_type = Option::getOptionList()[i]->type_name;
+    }
+
+    fprintf(stderr, "\nHELP OPTIONS:\n\n");
+    fprintf(stderr, "  --%shelp        Print help message.\n", Option::getHelpPrefixString());
+    fprintf(stderr, "  --%shelp-verb   Print verbose help message.\n", Option::getHelpPrefixString());
+    fprintf(stderr, "\n");
+    exit(0);
+}
+
diff --git a/glucose-syrup/utils/Options.h b/glucose-syrup/utils/Options.h
new file mode 100644 (file)
index 0000000..a86e4c7
--- /dev/null
@@ -0,0 +1,386 @@
+/***************************************************************************************[Options.h]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_Options_h
+#define Glucose_Options_h
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "mtl/IntTypes.h"
+#include "mtl/Vec.h"
+#include "utils/ParseUtils.h"
+
+namespace Glucose {
+
+//==================================================================================================
+// Top-level option parse/help functions:
+
+
+extern void parseOptions     (int& argc, char** argv, bool strict = false);
+extern void printUsageAndExit(int  argc, char** argv, bool verbose = false);
+extern void setUsageHelp     (const char* str);
+extern void setHelpPrefixStr (const char* str);
+
+
+//==================================================================================================
+// Options is an abstract class that gives the interface for all types options:
+
+
+class Option
+{
+ protected:
+    const char* name;
+    const char* description;
+    const char* category;
+    const char* type_name;
+
+    static vec<Option*>& getOptionList () { static vec<Option*> options; return options; }
+    static const char*&  getUsageString() { static const char* usage_str; return usage_str; }
+    static const char*&  getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; }
+
+    struct OptionLt {
+        bool operator()(const Option* x, const Option* y) {
+            int test1 = strcmp(x->category, y->category);
+            return test1 < 0 || test1 == 0 && strcmp(x->type_name, y->type_name) < 0;
+        }
+    };
+
+    Option(const char* name_, 
+           const char* desc_,
+           const char* cate_,
+           const char* type_) : 
+      name       (name_)
+    , description(desc_)
+    , category   (cate_)
+    , type_name  (type_)
+    { 
+        getOptionList().push(this); 
+    }
+
+ public:
+    virtual ~Option() {}
+
+    virtual bool parse             (const char* str)      = 0;
+    virtual void help              (bool verbose = false) = 0;
+
+    friend  void parseOptions      (int& argc, char** argv, bool strict);
+    friend  void printUsageAndExit (int  argc, char** argv, bool verbose);
+    friend  void setUsageHelp      (const char* str);
+    friend  void setHelpPrefixStr  (const char* str);
+};
+
+
+//==================================================================================================
+// Range classes with specialization for floating types:
+
+
+struct IntRange {
+    int begin;
+    int end;
+    IntRange(int b, int e) : begin(b), end(e) {}
+};
+
+struct Int64Range {
+    int64_t begin;
+    int64_t end;
+    Int64Range(int64_t b, int64_t e) : begin(b), end(e) {}
+};
+
+struct DoubleRange {
+    double begin;
+    double end;
+    bool  begin_inclusive;
+    bool  end_inclusive;
+    DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {}
+};
+
+
+//==================================================================================================
+// Double options:
+
+
+class DoubleOption : public Option
+{
+ protected:
+    DoubleRange range;
+    double      value;
+
+ public:
+    DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false))
+        : Option(n, d, c, "<double>"), range(r), value(def) {
+        // FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly.
+    }
+
+    operator      double   (void) const { return value; }
+    operator      double&  (void)       { return value; }
+    DoubleOption& operator=(double x)   { value = x; return *this; }
+
+    virtual bool parse(const char* str){
+        const char* span = str; 
+
+        if (!match(span, "-") || !match(span, name) || !match(span, "="))
+            return false;
+
+        char*  end;
+        double tmp = strtod(span, &end);
+
+        if (end == NULL) 
+            return false;
+        else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){
+            fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+            exit(1);
+        }else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){
+            fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+            exit(1); }
+
+        value = tmp;
+        // fprintf(stderr, "READ VALUE: %g\n", value);
+
+        return true;
+    }
+
+    virtual void help (bool verbose = false){
+        fprintf(stderr, "  -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n", 
+                name, type_name, 
+                range.begin_inclusive ? '[' : '(', 
+                range.begin,
+                range.end,
+                range.end_inclusive ? ']' : ')', 
+                value);
+        if (verbose){
+            fprintf(stderr, "\n        %s\n", description);
+            fprintf(stderr, "\n");
+        }
+    }
+};
+
+
+//==================================================================================================
+// Int options:
+
+
+class IntOption : public Option
+{
+ protected:
+    IntRange range;
+    int32_t  value;
+
+ public:
+    IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX))
+        : Option(n, d, c, "<int32>"), range(r), value(def) {}
+    operator   int32_t   (void) const { return value; }
+    operator   int32_t&  (void)       { return value; }
+    IntOption& operator= (int32_t x)  { value = x; return *this; }
+
+    virtual bool parse(const char* str){
+        const char* span = str; 
+
+        if (!match(span, "-") || !match(span, name) || !match(span, "="))
+            return false;
+
+        char*   end;
+        int32_t tmp = strtol(span, &end, 10);
+
+        if (end == NULL) 
+            return false;
+        else if (tmp > range.end){
+            fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+            exit(1);
+        }else if (tmp < range.begin){
+            fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+            exit(1); }
+
+        value = tmp;
+
+        return true;
+    }
+
+    virtual void help (bool verbose = false){
+        fprintf(stderr, "  -%-12s = %-8s [", name, type_name);
+        if (range.begin == INT32_MIN)
+            fprintf(stderr, "imin");
+        else
+            fprintf(stderr, "%4d", range.begin);
+
+        fprintf(stderr, " .. ");
+        if (range.end == INT32_MAX)
+            fprintf(stderr, "imax");
+        else
+            fprintf(stderr, "%4d", range.end);
+
+        fprintf(stderr, "] (default: %d)\n", value);
+        if (verbose){
+            fprintf(stderr, "\n        %s\n", description);
+            fprintf(stderr, "\n");
+        }
+    }
+};
+
+
+// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll.
+#ifndef _MSC_VER
+
+class Int64Option : public Option
+{
+ protected:
+    Int64Range range;
+    int64_t  value;
+
+ public:
+    Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX))
+        : Option(n, d, c, "<int64>"), range(r), value(def) {}
+    operator     int64_t   (void) const { return value; }
+    operator     int64_t&  (void)       { return value; }
+    Int64Option& operator= (int64_t x)  { value = x; return *this; }
+
+    virtual bool parse(const char* str){
+        const char* span = str; 
+
+        if (!match(span, "-") || !match(span, name) || !match(span, "="))
+            return false;
+
+        char*   end;
+        int64_t tmp = strtoll(span, &end, 10);
+
+        if (end == NULL) 
+            return false;
+        else if (tmp > range.end){
+            fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+            exit(1);
+        }else if (tmp < range.begin){
+            fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+            exit(1); }
+
+        value = tmp;
+
+        return true;
+    }
+
+    virtual void help (bool verbose = false){
+        fprintf(stderr, "  -%-12s = %-8s [", name, type_name);
+        if (range.begin == INT64_MIN)
+            fprintf(stderr, "imin");
+        else
+            fprintf(stderr, "%4" PRIi64, range.begin);
+
+        fprintf(stderr, " .. ");
+        if (range.end == INT64_MAX)
+            fprintf(stderr, "imax");
+        else
+            fprintf(stderr, "%4" PRIi64, range.end);
+
+        fprintf(stderr, "] (default: %" PRIi64")\n", value);
+        if (verbose){
+            fprintf(stderr, "\n        %s\n", description);
+            fprintf(stderr, "\n");
+        }
+    }
+};
+#endif
+
+//==================================================================================================
+// String option:
+
+
+class StringOption : public Option
+{
+    const char* value;
+ public:
+    StringOption(const char* c, const char* n, const char* d, const char* def = NULL) 
+        : Option(n, d, c, "<string>"), value(def) {}
+
+    operator      const char*  (void) const     { return value; }
+    operator      const char*& (void)           { return value; }
+    StringOption& operator=    (const char* x)  { value = x; return *this; }
+
+    virtual bool parse(const char* str){
+        const char* span = str; 
+
+        if (!match(span, "-") || !match(span, name) || !match(span, "="))
+            return false;
+
+        value = span;
+        return true;
+    }
+
+    virtual void help (bool verbose = false){
+        fprintf(stderr, "  -%-10s = %8s\n", name, type_name);
+        if (verbose){
+            fprintf(stderr, "\n        %s\n", description);
+            fprintf(stderr, "\n");
+        }
+    }    
+};
+
+
+//==================================================================================================
+// Bool option:
+
+
+class BoolOption : public Option
+{
+    bool value;
+
+ public:
+    BoolOption(const char* c, const char* n, const char* d, bool v) 
+        : Option(n, d, c, "<bool>"), value(v) {}
+
+    operator    bool     (void) const { return value; }
+    operator    bool&    (void)       { return value; }
+    BoolOption& operator=(bool b)     { value = b; return *this; }
+
+    virtual bool parse(const char* str){
+        const char* span = str; 
+        
+        if (match(span, "-")){
+            bool b = !match(span, "no-");
+
+            if (strcmp(span, name) == 0){
+                value = b;
+                return true; }
+        }
+
+        return false;
+    }
+
+    virtual void help (bool verbose = false){
+
+        fprintf(stderr, "  -%s, -no-%s", name, name);
+
+        for (uint32_t i = 0; i < 32 - strlen(name)*2; i++)
+            fprintf(stderr, " ");
+
+        fprintf(stderr, " ");
+        fprintf(stderr, "(default: %s)\n", value ? "on" : "off");
+        if (verbose){
+            fprintf(stderr, "\n        %s\n", description);
+            fprintf(stderr, "\n");
+        }
+    }
+};
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/utils/ParseUtils.h b/glucose-syrup/utils/ParseUtils.h
new file mode 100644 (file)
index 0000000..f411086
--- /dev/null
@@ -0,0 +1,151 @@
+/************************************************************************************[ParseUtils.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_ParseUtils_h
+#define Glucose_ParseUtils_h
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <zlib.h>
+
+namespace Glucose {
+
+//-------------------------------------------------------------------------------------------------
+// A simple buffered character stream class:
+
+static const int buffer_size = 1048576;
+
+
+class StreamBuffer {
+    gzFile        in;
+    unsigned char buf[buffer_size];
+    int           pos;
+    int           size;
+
+    void assureLookahead() {
+        if (pos >= size) {
+            pos  = 0;
+            size = gzread(in, buf, sizeof(buf)); } }
+
+public:
+    explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0) { assureLookahead(); }
+
+    int  operator *  () const { return (pos >= size) ? EOF : buf[pos]; }
+    void operator ++ ()       { pos++; assureLookahead(); }
+    int  position    () const { return pos; }
+};
+
+
+//-------------------------------------------------------------------------------------------------
+// End-of-file detection functions for StreamBuffer and char*:
+
+
+static inline bool isEof(StreamBuffer& in) { return *in == EOF;  }
+static inline bool isEof(const char*   in) { return *in == '\0'; }
+
+//-------------------------------------------------------------------------------------------------
+// Generic parse functions parametrized over the input-stream type.
+
+
+template<class B>
+static void skipWhitespace(B& in) {
+    while ((*in >= 9 && *in <= 13) || *in == 32)
+        ++in; }
+
+
+template<class B>
+static void skipLine(B& in) {
+    for (;;){
+        if (isEof(in)) return;
+        if (*in == '\n') { ++in; return; }
+        ++in; } }
+
+template<class B>
+static double parseDouble(B& in) { // only in the form X.XXXXXe-XX
+    bool    neg= false;
+       double accu = 0.0;
+       double currentExponent = 1;
+       int exponent;
+       
+    skipWhitespace(in);
+    if(*in == EOF) return 0;
+    if      (*in == '-') neg = true, ++in;
+    else if (*in == '+') ++in;
+    if (*in < '1' || *in > '9') printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
+       accu = (double)(*in - '0');
+       ++in;
+       if (*in != '.') printf("PARSE ERROR! Unexpected char: %c\n", *in),exit(3);
+       ++in; // skip dot
+       currentExponent = 0.1;
+    while (*in >= '0' && *in <= '9')
+        accu = accu + currentExponent * ((double)(*in - '0')),
+               currentExponent /= 10,
+        ++in;
+       if (*in != 'e') printf("PARSE ERROR! Unexpected char: %c\n", *in),exit(3);
+       ++in; // skip dot
+       exponent = parseInt(in); // read exponent
+       accu *= pow(10,exponent);
+       return neg ? -accu:accu;
+}
+
+
+template<class B>
+static int parseInt(B& in) {
+    int     val = 0;
+    bool    neg = false;
+    skipWhitespace(in);
+    if      (*in == '-') neg = true, ++in;
+    else if (*in == '+') ++in;
+    if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
+    while (*in >= '0' && *in <= '9')
+        val = val*10 + (*in - '0'),
+        ++in;
+    return neg ? -val : val; }
+
+
+// String matching: in case of a match the input iterator will be advanced the corresponding
+// number of characters.
+template<class B>
+static bool match(B& in, const char* str) {
+    int i;
+    for (i = 0; str[i] != '\0'; i++)
+        if (in[i] != str[i])
+            return false;
+
+    in += i;
+
+    return true; 
+}
+
+// String matching: consumes characters eagerly, but does not require random access iterator.
+template<class B>
+static bool eagerMatch(B& in, const char* str) {
+    for (; *str != '\0'; ++str, ++in)
+        if (*str != *in)
+            return false;
+    return true; }
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/glucose-syrup/utils/System.cc b/glucose-syrup/utils/System.cc
new file mode 100644 (file)
index 0000000..a516e0b
--- /dev/null
@@ -0,0 +1,95 @@
+/***************************************************************************************[System.cc]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#include "utils/System.h"
+
+#if defined(__linux__)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace Glucose;
+
+// TODO: split the memory reading functions into two: one for reading high-watermark of RSS, and
+// one for reading the current virtual memory size.
+
+static inline int memReadStat(int field)
+{
+    char  name[256];
+    pid_t pid = getpid();
+    int   value;
+
+    sprintf(name, "/proc/%d/statm", pid);
+    FILE* in = fopen(name, "rb");
+    if (in == NULL) return 0;
+
+    for (; field >= 0; field--)
+        if (fscanf(in, "%d", &value) != 1)
+            printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1);
+    fclose(in);
+    return value;
+}
+
+
+static inline int memReadPeak(void)
+{
+    char  name[256];
+    pid_t pid = getpid();
+
+    sprintf(name, "/proc/%d/status", pid);
+    FILE* in = fopen(name, "rb");
+    if (in == NULL) return 0;
+
+    // Find the correct line, beginning with "VmPeak:":
+    int peak_kb = 0;
+    while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1)
+        while (!feof(in) && fgetc(in) != '\n')
+            ;
+    fclose(in);
+
+    return peak_kb;
+}
+
+double Glucose::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); }
+double Glucose::memUsedPeak() { 
+    double peak = memReadPeak() / 1024;
+    return peak == 0 ? memUsed() : peak; }
+
+#elif defined(__FreeBSD__)
+
+double Glucose::memUsed(void) {
+    struct rusage ru;
+    getrusage(RUSAGE_SELF, &ru);
+    return (double)ru.ru_maxrss / 1024; }
+double MiniSat::memUsedPeak(void) { return memUsed(); }
+
+
+#elif defined(__APPLE__)
+#include <malloc/malloc.h>
+
+double Glucose::memUsed(void) {
+    malloc_statistics_t t;
+    malloc_zone_statistics(NULL, &t);
+    return (double)t.max_size_in_use / (1024*1024); }
+
+#else
+double Glucose::memUsed() { 
+    return 0; }
+#endif
diff --git a/glucose-syrup/utils/System.h b/glucose-syrup/utils/System.h
new file mode 100644 (file)
index 0000000..4e48fee
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************************[System.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef Glucose_System_h
+#define Glucose_System_h
+
+#if defined(__linux__)
+#include <fpu_control.h>
+#endif
+
+#include "mtl/IntTypes.h"
+
+//-------------------------------------------------------------------------------------------------
+
+namespace Glucose {
+
+static inline double cpuTime(void); // CPU-time in seconds.
+static inline double realTime(void);
+extern double memUsed();            // Memory in mega bytes (returns 0 for unsupported architectures).
+extern double memUsedPeak();        // Peak-memory in mega bytes (returns 0 for unsupported architectures).
+
+}
+
+//-------------------------------------------------------------------------------------------------
+// Implementation of inline functions:
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <time.h>
+
+static inline double Glucose::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; }
+
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static inline double Glucose::cpuTime(void) {
+    struct rusage ru;
+    getrusage(RUSAGE_SELF, &ru);
+    return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
+
+#endif
+
+// Laurent: I know that this will not compile directly under Windows... sorry for that
+static inline double Glucose::realTime() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (double)tv.tv_sec + (double) tv.tv_usec / 1000000; }
+
+#endif
diff --git a/lingeling/build.sh b/lingeling/build.sh
new file mode 100755 (executable)
index 0000000..fa09dd5
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+rm -rf binary
+mkdir binary
+cd code
+./configure.sh || exit 1
+make lingeling || exit 1
+install -m 755 -s lingeling ../binary
diff --git a/lingeling/code/COPYING b/lingeling/code/COPYING
new file mode 100644 (file)
index 0000000..b268295
--- /dev/null
@@ -0,0 +1,39 @@
+Copyright (c) 2010 - 2014, Armin Biere, Johannes Kepler University.
+
+Permission is hereby granted, free of charge, to use this software for
+evaluation and research purposes.
+
+This license does not allow this software to be used in a commercial context.
+
+It is further prohibited to use this software or a substantial portion of it
+in a competition or a similar competitive event, such as the SAT, SMT or QBF
+competitions or evaluations, without explicit written permission by the
+copyright holder.
+
+However, competition organizers are allowed to use this software as part of
+the evaluation process of a particular competition, evaluation or
+competitive event, if the copyright holder of this software submitted this
+software to this particular competition, evaluation or event explicitly.
+
+This permission of using the software as part of a submission by the
+copyright holder to a competition, evaluation or competitive event is only
+granted for one year and only for one particular instance of the competition
+to which this software was submitted by the copyright holder.
+
+If a competition, evaluation or competitive event has multiple tracks,
+categories or sub-competitions, this license is only granted for the tracks
+respectively categories or sub-competitions, to which the software was
+explicitly submitted by the copyright holder.
+
+All other usage is reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/lingeling/code/VERSION b/lingeling/code/VERSION
new file mode 100644 (file)
index 0000000..8ac1cc1
--- /dev/null
@@ -0,0 +1 @@
+ayv
diff --git a/lingeling/code/configure.sh b/lingeling/code/configure.sh
new file mode 100755 (executable)
index 0000000..1dff357
--- /dev/null
@@ -0,0 +1,270 @@
+#!/bin/sh
+
+check=undefined
+chksol=undefined
+coverage=undefined
+debug=no
+log=undefined
+lto=no
+olevel=none
+other=none
+picosat=no
+druplig=no
+profile=undefined
+static=no
+aiger=undefined
+double=no
+yalsat=undefined
+
+##########################################################################
+
+die () {
+  echo "*** configure.sh: $*" 1>&2
+  exit 1
+}
+
+##########################################################################
+
+while [ $# -gt 0 ]
+do
+  case $1 in
+    -h|--help) 
+       echo "usage: configure.sh [<option> ...]"
+       echo
+       echo "where <option> is one of the following"
+       echo
+       echo "-h | --help"
+       echo "-g | --debug    include debugging code and symbols"
+       echo "-l | --log      include logging code (default with '-g')"
+       echo "-c | --check    include checking code (default with '-g')"
+       echo "-p | --profile  compile with '-pg' for profiling"
+       echo "--coverage      compile with coverage options"
+       echo "--no-check      no checking code (overwrite default for '-g')"
+       echo "--chksol        always check solution (default for '-c')"
+       echo "--no-chksol     do not check solution"
+       echo "--softfloats    use software floats"
+       echo "--double        use hardware floats (of 'double' type)"
+       echo "--no-log        no logging code (overwrite default for '-g')"
+       echo "-O[0-4]         set optimization level unless '-g' specified"
+       echo "-flto           enable link time optimization"
+       echo "--picosat       add checking code depending on PicoSAT"
+       echo "--druplig       add checking code depending on Druplig"
+       echo "-f...|-m...     add other compiler options"
+       echo "--aiger=<dir>   specify AIGER directory (default '../aiger')"
+       echo "--no-aiger      no targets requiring AIGER library"
+       echo "--yalsat=<dir>  specify YalSAT directory (default '../yalsat')"
+       echo "--no-yalsat     do not include YalSAT code"
+       exit 0
+       ;;
+    -g|--debug) debug=yes;;
+    -l|--log) log=yes;;
+    -c|--check) check=yes;;
+    --chksol) chksol=yes;;
+    --no-chksol|--nchksol) chksol=no;;
+    --no-check) check=no;;
+    --no-log) log=no;;
+    -p|--profile) profile=yes;;
+    --softfloats) double=no;;
+    --double) double=yes;;
+    --coverage) coverage=yes;;
+    --picosat) picosat=yes;;
+    --druplig) druplig=yes;;
+    -O) debug=no;;
+    -O0|-O1|-O2|-O3|-O4) olevel=$1;;
+    -lto|-flto|--lto|--flto) lto=yes;;
+    -static) static=yes;;
+    --aiger=*) aiger=`echo "$1"|sed -e 's,^--aiger=,,' `;;
+    --no-aiger) aiger=no;;
+    --yalsat=*) yalsat=`echo "$1"|sed -e 's,^--yalsat=,,' `;;
+    --no-yalsat) yalsat=no;;
+    -f*|-m*) if [ $other = none ]; then other=$1; else other="$other $1"; fi;;
+    *) echo "*** configure.sh: invalid command line option '$1'"; exit 1;;
+  esac
+  shift
+done
+
+##########################################################################
+
+if [ x"$aiger" = xundefined ]
+then
+  if [ -d ../aiger ]
+  then
+    aiger="../aiger"
+  fi
+fi
+
+if [ x"$aiger" = xundefined ]
+then
+  aiger=no
+elif [ ! x"$aiger" = xno ]
+then
+  if [ ! -d "$aiger" ]
+  then
+    die "'$aiger' not a directory (use '--aiger' or '--no-aiger')"
+  elif [ ! -f "$aiger/aiger.h" ]
+  then
+    die "can not find '$aiger/aiger.h'"
+  elif [ ! -f "$aiger/aiger.o" ]
+  then
+    die "can not find '$aiger/aiger.o'"
+  fi
+fi
+
+##########################################################################
+
+if [ x"$yalsat" = xundefined ]
+then
+  if [ -d ../yalsat ]
+  then
+    yalsat="../yalsat"
+    echo "using $yalsat"
+  fi
+fi
+
+if [ x"$yalsat" = xundefined ]
+then
+  yalsat=no
+elif [ ! x"$yalsat" = xno ]
+then
+  if [ ! -d "$yalsat" ]
+  then
+    die "'$yalsat' not a directory (use '--yalsat' or '--no-yalsat')"
+  elif [ ! -f "$yalsat/yals.h" ]
+  then
+    die "can not find '$yalssat/yals.h'"
+  elif [ ! -f "$yalsat/libyals.a" ]
+  then
+    die "can not find '$yalsat/libyals.a'"
+  fi
+fi
+
+##########################################################################
+
+[ $log = undefined ] && log=$debug
+[ $check = undefined ] && check=$debug
+
+for CNF in profile.cnf.gz \
+           /data/cnf/sc2009/applications/simon-s03-fifo8-300.cnf \
+           /data/cnf/cmu/longmult12.dimacs \
+          log/prime65537.in \
+          none
+do
+  [ -f $CNF ] && break;
+done
+
+##########################################################################
+
+[ x"$CC" = x ] && CC=gcc
+
+CFLAGS="-Wall"
+if [ $debug = yes ]
+then
+  CFLAGS="$CFLAGS -g3"
+  [ $olevel = none ] || CFLAGS="$CFLAGS $olevel"
+else
+  [ $olevel = none ] && olevel=-O3
+  CFLAGS="$CFLAGS $olevel"
+  [ $lto = yes ] && CFLAGS="$CFLAGS -flto -fwhole-program"
+fi
+
+[ $double = no ] && CFLAGS="$CFLAGS -DNDBLSCR"
+
+LIBS="-lm"
+if [ $picosat = yes ]
+then
+  if [ ! -d ../picosat ]
+  then
+    echo "*** configure.sh: can not find '../picosat'"
+    exit 1;
+  elif [ ! -f ../picosat/picosat.h ]
+  then
+    echo "*** configure.sh: can not find '../picosat/picosat.h'"
+    exit 1;
+  elif [ ! -f ../picosat/libpicosat.a ]
+  then
+    echo "*** configure.sh: can not find '../picosat/libpicosat.a'"
+    exit 1;
+  else
+    HDEPS="../picosat/picosat.h"
+    LDEPS="../picosat/libpicosat.a"
+    LIBS="$LIBS -L../picosat -lpicosat"
+    CFLAGS="$CFLAGS -I../picosat"
+  fi
+else
+  HDEPS=""
+  LDEPS=""
+fi
+
+if [ $druplig = yes ]
+then
+  if [ ! -d ../druplig ]
+  then
+    echo "*** configure.sh: can not find '../druplig'"
+    exit 1;
+  elif [ ! -f ../druplig/druplig.h ]
+  then
+    echo "*** configure.sh: can not find '../druplig/druplig.h'"
+    exit 1;
+  elif [ ! -f ../druplig/libdruplig.a ]
+  then
+    echo "*** configure.sh: can not find '../druplig/libdruplig.a'"
+    exit 1;
+  else
+    HDEPS="../druplig/druplig.h"
+    LDEPS="../druplig/libdruplig.a"
+    LIBS="$LIBS -L../druplig -ldruplig"
+    CFLAGS="$CFLAGS -I../druplig"
+  fi
+else
+  HDEPS=""
+  LDEPS=""
+fi
+
+if [ "$aiger" = no ]
+then
+  AIGERTARGETS=""
+  AIGER=""
+else
+  AIGERTARGETS="blimc"
+  AIGER="$aiger"
+fi
+
+if [ ! "$yalsat" = no ]
+then
+  [ x"$HDEPS" = x ] || HDEPS="${HDEPS} "
+  HDEPS="${HDEPS}$yalsat/yals.h"
+  [ x"$LDEPS" = x ] || LDEPS="${LDEPS} "
+  LDEPS="${LDEPS}$yalsat/libyals.a"
+  [ x"$LIBS" = x ] || LIBS="${LIBS} "
+  LIBS="${LIBS} -L$yalsat -lyals"
+  [ x"$CFLAGS" = x ] || CFLAGS="${CFLAGS} "
+  CFLAGS="${CFLAGS} -I$yalsat"
+fi
+
+[ $chksol = undefined ] && chksol=$check
+[ $static = yes ] && CFLAGS="$CFLAGS -static"
+[ $profile = yes ] && CFLAGS="$CFLAGS -pg"
+[ $coverage = yes ] && CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs"
+[ $other = none ] || CFLAGS="$CFLAGS $other"
+[ $log = no ] && CFLAGS="$CFLAGS -DNLGLOG"
+[ $check = no ] && CFLAGS="$CFLAGS -DNDEBUG"
+[ $chksol = no ] && CFLAGS="$CFLAGS -DNCHKSOL"
+[ $picosat = no ] && CFLAGS="$CFLAGS -DNLGLPICOSAT"
+[ $druplig = no ] && CFLAGS="$CFLAGS -DNLGLDRUPLIG"
+[ $yalsat = no ] && CFLAGS="$CFLAGS -DNLGLYALSAT"
+
+echo "$CC $CFLAGS"
+
+##########################################################################
+
+rm -f makefile
+sed \
+  -e "s,@CC@,$CC," \
+  -e "s,@CFLAGS@,$CFLAGS," \
+  -e "s,@HDEPS@,$HDEPS," \
+  -e "s,@LDEPS@,$LDEPS," \
+  -e "s,@AIGERTARGETS@,$AIGERTARGETS," \
+  -e "s,@AIGER@,$AIGER," \
+  -e "s,@CNF@,$CNF," \
+  -e "s,@LIBS@,$LIBS," \
+  makefile.in > makefile
diff --git a/lingeling/code/lglbnr.c b/lingeling/code/lglbnr.c
new file mode 100644 (file)
index 0000000..8cb156b
--- /dev/null
@@ -0,0 +1,54 @@
+/*-------------------------------------------------------------------------*/
+/* Copyright 2010-2014 Armin Biere Johannes Kepler University Linz Austria */
+/*-------------------------------------------------------------------------*/
+
+#include "lglib.h"
+#include "lglcfg.h"
+#include "lglcflags.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void lglbnr (const char * name, const char * prefix, FILE * file) {
+  const char * p = LGL_CFLAGS, * q, * n;
+  int len = 78 - strlen (prefix);
+  fprintf (file, "%s%s\n", prefix, name);
+  fprintf (file, "%s\n", prefix);
+  fprintf (file, "%sVersion %s %s\n", prefix, LGL_VERSION, LGL_ID);
+  fprintf (file, "%s\n", prefix);
+  fprintf (file, 
+     "%sCopyright (C) 2010-2014 Armin Biere JKU Linz Austria.\n",
+      prefix);
+  fprintf (file, "%sAll rights reserved.\n", prefix);
+  fprintf (file, "%s\n", prefix);
+  fprintf (file, "%sreleased %s\n", prefix, LGL_RELEASED);
+  fprintf (file, "%scompiled %s\n", prefix, LGL_COMPILED);
+  fprintf (file, "%s\n", prefix);
+  fprintf (file, "%s%s\n", prefix, LGL_CC);
+  assert (*p);
+  for (;;) {
+    fputs (prefix, file);
+    for (q = p; *q && *q != ' '; q++)
+      ;
+    if (*q && q - p < len) {
+      for (;;) {
+       for (n = q + 1; *n && *n != ' '; n++)
+         ;
+       if (n - p >= len) break;
+       q = n;
+       if (!*n) break;
+      }
+    }
+    while (p < q) fputc (*p++, file);
+    fputc ('\n', file);
+    if (!*p) break;
+    assert(*p == ' ');
+    p++;
+  }
+  fprintf (file, "%s%s\n", prefix, LGL_OS);
+  fprintf (file, "%s\n", prefix);
+  fflush (file);
+}
+
+const char * lglversion (void) { return LGL_VERSION " " LGL_ID; }
diff --git a/lingeling/code/lgldimacs.c b/lingeling/code/lgldimacs.c
new file mode 100644 (file)
index 0000000..2aaa518
--- /dev/null
@@ -0,0 +1,272 @@
+#include "lgldimacs.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+
+struct LDR {
+  struct { 
+    void * state;
+    ldralloc alloc;
+    ldrdealloc dealloc;
+  } mem;
+  struct { void * state; ldropt fun; } opt;
+  struct { void * state; ldrheader fun; } header;
+  struct { void * state; ldradd fun; } add;
+  char * path;
+  char * errmsg;
+  int closefile;
+  FILE * file;
+  int lineno;
+};
+
+static void * ldrstdalloc (void * mem, size_t bytes) {
+  (void) mem;
+  return malloc (bytes);
+}
+
+static void ldrstdealloc (void * mem, void * ptr, size_t bytes) {
+  (void) mem;
+  (void) bytes;
+  free (ptr);
+}
+
+static void * ldrstdrealloc (void * mem, void * ptr, size_t ob, size_t nb) {
+  (void) mem;
+  (void) ob;
+  return realloc (ptr, nb);
+}
+
+LDR * ldrinit () {
+  return ldrminit (0, ldrstdalloc, ldrstdrealloc, ldrstdealloc);
+}
+
+LDR * ldrminit (void * state, 
+                ldralloc alloc, ldrealloc realloc, ldrdealloc dealloc) {
+  LDR * res = alloc (state, sizeof *res);
+  if (!res) return res;
+  memset (res, 0, sizeof *res);
+  res->mem.state = state;
+  res->mem.alloc = alloc;
+  res->mem.dealloc = dealloc;
+  return res;
+}
+
+static void ldrdelstr (LDR * ldr, char * str) {
+  if (str) ldr->mem.dealloc (ldr->mem.state, str, strlen (str) + 1);
+}
+
+static char * ldrstrdup (LDR * ldr, const char* str) {
+  size_t bytes = strlen (str) + 1;
+  char * res = ldr->mem.alloc (ldr->mem.state, bytes);
+  return strcpy (res, str);
+}
+
+void ldrelease (LDR * ldr) {
+  if (ldr->file) {
+    if (ldr->closefile == 1) fclose (ldr->file);
+    if (ldr->closefile == 2) pclose (ldr->file);
+  }
+  ldrdelstr (ldr, ldr->errmsg);
+  ldrdelstr (ldr, ldr->path);
+  ldr->mem.dealloc (ldr->mem.state, ldr, sizeof *ldr);
+}
+
+void ldrsetopt (LDR * ldr, void * state, ldropt fun) {
+  ldr->opt.fun = fun;
+  ldr->opt.state = state;
+}
+
+void ldrsetheader (LDR * ldr, void * state, ldrheader fun) {
+  ldr->header.fun = fun;
+  ldr->header.state = state;
+}
+
+void ldrsetadd (LDR * ldr, void * state, ldradd fun) {
+  ldr->add.fun = fun;
+  ldr->add.state = state;
+}
+
+static int ldrfilexists (const char * path) {
+  struct stat buf;
+  return !stat (path, &buf);
+}
+
+static int ldrperr (LDR * ldr, const char * msg) {
+  size_t bytes, len;
+  char * str;
+  assert (!ldr->errmsg);
+  assert (ldr->path);
+  bytes = strlen (msg) + strlen (ldr->path) + 20;
+  str = ldr->mem.alloc (ldr->mem.state, bytes);
+  sprintf (str, "%s:%d: %s", ldr->path, ldr->lineno, msg);
+  len = strlen (str) + 1;
+  ldr->errmsg = strcpy (ldr->mem.alloc (ldr->mem.state, len), str);
+  ldr->mem.dealloc (ldr->mem.state, str, bytes);
+  return 0;
+}
+
+static int ldrhas (const char * str, const char * suffix) {
+  int l = strlen (str), k = strlen (suffix);
+  if (l < k) return 0;
+  return !strcmp (str + l - k, suffix);
+}
+
+static FILE * ldrcmd (LDR * ldr, const char * fmt, const char * name) {
+  FILE * res;
+  int len = strlen (fmt) + strlen (name) + 1;
+  char * s = ldr->mem.alloc (ldr->mem.state, len);
+  sprintf (s, fmt, name);
+  res = popen (s, "r");
+  ldr->mem.dealloc (ldr->mem.state, s, len);
+  return res;
+}
+
+void ldrsetpath (LDR * ldr, const char * path) {
+  assert (!ldr->file);
+  assert (!ldr->path);
+  assert (!ldr->closefile);
+  ldr->path = ldrstrdup (ldr, path);
+  if (!ldrfilexists (path))
+    return (void) ldrperr (ldr, "file does not exist");
+  ldr->closefile = 2;
+  if (ldrhas (path, ".gz"))
+    ldr->file = ldrcmd  (ldr, "gunzip -c %s", path);
+  else if (ldrhas (path, ".bz2"))
+    ldr->file = ldrcmd (ldr, "bzcat %s", path);
+  else if (ldrhas (path, ".7z"))
+    ldr->file = ldrcmd (ldr, "7z x -so %s 2>/dev/null", path);
+  else if (ldrhas (path, ".lzma"))
+    ldr->file = ldrcmd (ldr, "lzcat %s", path);
+  else ldr->file = fopen (path, "r"), ldr->closefile = 1;
+  if (!ldr->file) return (void) ldrperr (ldr, "can not open file");
+}
+
+void ldrsetfile (LDR * ldr, FILE * file) {
+  assert (!ldr->file);
+  assert (!ldr->path);
+  assert (!ldr->closefile);
+  ldr->file = file;
+  ldr->path = ldrstrdup (ldr, "<unspecified-path>");
+}
+
+void ldrsetnamedfile (LDR * ldr, FILE * file, const char * path) {
+  assert (!ldr->file);
+  assert (!ldr->path);
+  assert (!ldr->closefile);
+  ldr->file = file;
+  ldr->path = ldrstrdup (ldr, path);
+}
+
+const char * ldrerr (LDR * ldr) { return ldr->errmsg; }
+
+static int ldrnext (LDR * ldr) {
+  int ch;
+  assert (ldr);
+  assert (ldr->file);
+  ch = getc (ldr->file);
+  if (ch == '\n') ldr->lineno++;
+  return ch;
+}
+
+int ldrparse (LDR * ldr) {
+  struct { int parsed, specified; } vars, clauses;
+  int ch, sign, lit, digit;
+  if (ldr->errmsg) return 0;
+  while ((ch = ldrnext (ldr)) == 'c') {
+    // TODO parse embedded options
+    while ((ch = ldrnext (ldr)) != '\n')
+      if (ch == EOF)
+       return ldrperr (ldr, "end-of-file in comment before header");
+  }
+  if (ch != 'p') return ldrperr (ldr, "expected 'p' or 'c'");
+  if (ldrnext (ldr) != ' ') return ldrperr (ldr, "expected space after 'p'");
+  if (ldrnext (ldr) != 'c') return ldrperr (ldr, "expected 'c' after 'p '");
+  if (ldrnext (ldr) != 'n') return ldrperr (ldr, "expected 'n' after 'p c'");
+  if (ldrnext (ldr) != 'f') return ldrperr (ldr, "expected 'f' after 'p cn'");
+  if (ldrnext (ldr) != ' ')
+    return ldrperr (ldr, "expected space after 'p cnf'");
+  ch = ldrnext (ldr);
+  if (!isdigit (ch)) return ldrperr (ldr, "expected digit after 'p cnf '");
+  vars.specified = ch - '0';
+  while (isdigit (ch = ldrnext (ldr))) {
+    if (INT_MAX/10 < vars.specified)
+NUMBER_TOO_LARGE:
+      return ldrperr (ldr, "number too large");
+    vars.specified *= 10;
+    digit = (ch - '0');
+    if (INT_MAX - digit < vars.specified) goto NUMBER_TOO_LARGE;
+    vars.specified += digit;
+  }
+  if (ch != ' ')
+    return ldrperr (ldr, "expected space after maximum variable index");
+  if (!isdigit (ch = ldrnext (ldr)))
+    return ldrperr (ldr, "expected digit after space after variable index");
+  clauses.specified = ch - '0';
+  while (isdigit (ch = ldrnext (ldr))) {
+    if (INT_MAX/10 < clauses.specified) goto NUMBER_TOO_LARGE;
+    clauses.specified *= 10;
+    digit = (ch - '0');
+    if (INT_MAX - digit < clauses.specified) goto NUMBER_TOO_LARGE;
+    clauses.specified += digit;
+  }
+  while (ch == ' ' || ch == '\t' || ch == '\r')
+    ch = ldrnext (ldr);
+  if (ch != '\n') return ldrperr (ldr, "expected new line after header");
+  if (ldr->header.fun)
+    ldr->header.fun (ldr->header.state, vars.specified, clauses.specified);
+  vars.parsed = clauses.parsed = 0;
+  lit = 0;
+  for (;;) {
+    ch = ldrnext (ldr);
+    if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') continue;
+    if (ch == 'c') {
+      while ((ch = ldrnext (ldr)) != '\n') {
+       if (ch == EOF)
+         return ldrperr (ldr, "end-of-file in comment after header");
+      }
+      continue;
+    }
+    if (ch == EOF) {
+      if (lit) return ldrperr (ldr, "zero sentinel missing at end-of-file");
+      assert (clauses.parsed <= clauses.specified);
+      if (clauses.parsed + 1 == clauses.specified)
+        return ldrperr (ldr, "one clause is missing");
+      if (clauses.parsed < clauses.specified)
+        return ldrperr (ldr, "clauses are missing");
+      break;
+    }
+    if (ch == '-') {
+      ch = ldrnext (ldr);
+      if (!isdigit (ch)) return ldrperr (ldr, "expected digit after '-'");
+      sign = -1;
+    } else if (!isdigit (ch)) return ldrperr (ldr, "expected digit or '-'");
+    else sign = 1;
+    assert (clauses.parsed <= clauses.specified);
+    if (clauses.specified == clauses.parsed)
+      return ldrperr (ldr, "too many clauses");
+    lit = ch - '0';
+    while (isdigit (ch = ldrnext (ldr))) {
+      if (INT_MAX/10 < lit) goto NUMBER_TOO_LARGE;
+      lit *= 10;
+      digit = (ch - '0');
+      if (INT_MAX - digit < lit) goto NUMBER_TOO_LARGE;
+      lit += digit;
+    }
+    assert (0 <= lit);
+    if (lit > vars.specified)
+      return ldrperr (ldr, "maximum variable index exceeded");
+    lit *= sign;
+    assert ((sign < 0) == (lit < 0));
+    if (ldr->add.fun) ldr->add.fun (ldr->add.state, lit);
+    if (lit) continue;
+    clauses.parsed++;
+    assert (clauses.parsed <= clauses.specified);
+  }
+  return 1;
+}
diff --git a/lingeling/code/lgldimacs.h b/lingeling/code/lgldimacs.h
new file mode 100644 (file)
index 0000000..4a131b0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef LGLDIMACS_h_INCLUDED
+#define LGLDIMACS_h_INCLUDED
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct LDR LDR;
+
+typedef void * (*ldralloc) (void* state, size_t);
+typedef void * (*ldrealloc) (void* state, void*, size_t, size_t);
+typedef void (*ldrdealloc) (void* state, void*, size_t);
+typedef void (*ldropt)(void *state, const char * opt, int val);
+typedef void (*ldrheader)(void *state, int vars, int clauses);
+typedef void (*ldradd)(void *state, int lit);
+
+LDR * ldrinit ();
+LDR * ldrminit (void *  state, ldralloc, ldrealloc, ldrdealloc);
+void ldrelease (LDR *);
+
+void ldrsetopt (LDR *, void * optmgr, ldropt);
+void ldrsetheader (LDR *, void * header, ldrheader);
+void ldrsetadd (LDR *, void * adder, ldradd);
+
+void ldrsetpath (LDR *, const char * path);
+void ldrsetfile (LDR *, FILE * file);
+void ldrsetnamedfile (LDR *, FILE * file, const char * path);
+
+int ldrparse (LDR *);
+
+const char * ldrerr (LDR *);
+
+#endif
diff --git a/lingeling/code/lglib.c b/lingeling/code/lglib.c
new file mode 100644 (file)
index 0000000..56a2e44
--- /dev/null
@@ -0,0 +1,26553 @@
+/*-------------------------------------------------------------------------*/
+/* Copyright 2010-2014 Armin Biere Johannes Kepler University Linz Austria */
+/*-------------------------------------------------------------------------*/
+
+#include "lglib.h"
+
+/*-------------------------------------------------------------------------*/
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef NLGLPICOSAT
+#include "picosat.h"
+#endif
+
+#ifndef NLGLYALSAT
+#include "yals.h"
+#endif
+
+#ifndef NLGLDRUPLIG
+#include "druplig.h"
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define REMOVED                INT_MAX
+#define NOTALIT                ((INT_MAX >> RMSHFT))
+#define MAXVAR         ((INT_MAX >> RMSHFT) - 2)
+
+#define GLUESHFT       4
+#define POW2GLUE       (1 << GLUESHFT)
+#define MAXGLUE                (POW2GLUE - 1)
+#define GLUEMASK       (POW2GLUE - 1)
+#define MAXREDLIDX     ((1 << (31 - GLUESHFT)) - 2)
+#define MAXIRRLIDX     ((1 << (31 - RMSHFT)) - 2)
+
+#define MAXLDFW                31      
+#define REPMOD                 22
+
+#define FUNVAR         10
+#define FUNQUADS       (1<<(FUNVAR - 6))
+#define FALSECNF       (1ll<<32)
+#define TRUECNF                0ll
+
+#define FLTPRC                 32
+#define EXPMIN                 (0x0000 ## 0000)
+#define EXPZRO                 (0x1000 ## 0000)
+#define EXPMAX         (0x7fff ## ffff)
+#define MNTBIT         (0x0000 ## 0001 ## 0000 ## 0000 ## ull)
+#define MNTMAX         (0x0000 ## 0001 ## ffff ## ffff ## ull)
+#define FLTMIN         (0x0000 ## 0000 ## 0000 ## 0000 ## ll)
+#define FLTMAX         (0x7fff ## ffff ## ffff ## ffff ## ll)
+
+#define LGL_SCORE_AVG          4
+#define LGL_SCORE_EVSIDS       5
+#define LGL_SCORE_VSIDS256     6
+#define LGL_SCORE_FAVG         7
+
+#ifdef NDBLSCR
+#define MAXSCOREXP     (1<<30)
+#else
+#define MAXSCOREXP     (1<<9)
+#endif
+
+#define DEFSCOREXP     500
+
+#define LLMAX          FLTMAX
+
+#define MAXFLTSTR      6
+#define MAXPHN         10
+
+/*------------------------------------------------------------------------*/
+#ifndef NLGLOG
+/*------------------------------------------------------------------------*/
+
+#define MAPLOGLEVEL(LEVEL) (LEVEL)
+
+#define LOG(LEVEL,FMT,ARGS...) \
+do { \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGCLS(LEVEL,CLS,FMT,ARGS...) \
+do { \
+  const int * P; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  for (P = (CLS); *P; P++) fprintf (lgl->out, " %d", *P); \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGMCLS(LEVEL,CLS,FMT,ARGS...) \
+do { \
+  const int * P; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  for (P = (CLS); *P; P++) fprintf (lgl->out, " %d", lglm2i (lgl, *P)); \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGRESOLVENT(LEVEL,FMT,ARGS...) \
+do { \
+  const int * P; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  for (P = lgl->resolvent.start; P < lgl->resolvent.top; P++) \
+    fprintf (lgl->out, " %d", *P); \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGREASON(LEVEL,LIT,REASON0,REASON1,FMT,ARGS...) \
+do { \
+  int TAG, TMP, RED, G; \
+  const int * C, * P; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  TMP = (REASON0 >> RMSHFT); \
+  RED = (REASON0 & REDCS); \
+  TAG = (REASON0 & MASKCS); \
+  if (TAG == DECISION) fputs (" decision", lgl->out); \
+  else if (TAG == UNITCS) fprintf (lgl->out, " unit %d", LIT); \
+  else if (TAG == BINCS) { \
+    fprintf (lgl->out, \
+       " %s binary clause %d %d", lglred2str (RED), LIT, TMP); \
+  } else if (TAG == TRNCS) { \
+    fprintf (lgl->out, " %s ternary clause %d %d %d", \
+           lglred2str (RED), LIT, TMP, REASON1); \
+  } else { \
+    assert (TAG == LRGCS); \
+    C = lglidx2lits (lgl, RED, REASON1); \
+    for (P = C; *P; P++) \
+      ; \
+    fprintf (lgl->out, " size %ld", (long)(P - C)); \
+    if (RED) { \
+      G = (REASON1 & GLUEMASK); \
+      fprintf (lgl->out, " glue %d redundant", G); \
+    } else fputs (" irredundant", lgl->out); \
+    fputs (" clause", lgl->out); \
+    for (P = C; *P; P++) { \
+      fprintf (lgl->out, " %d", *P); \
+    } \
+  } \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGDSCHED(LEVEL,LIT,FMT,ARGS...) \
+  do { \
+    int POS; \
+    if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+    POS = *lgldpos (lgl, LIT); \
+    lglogstart (lgl, MAPLOGLEVEL(LEVEL), "dsched[%d] = %d ", POS, LIT); \
+    printf (FMT, ##ARGS); \
+    printf (" score %s", lglscr2str (lgl, lglqvar (lgl, LIT)->score)); \
+    lglogend (lgl); \
+  } while (0)
+
+#define LOGESCHED(LEVEL,LIT,FMT,ARGS...) \
+do { \
+  int POS; \
+  EVar * EV; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  POS = *lglepos (lgl, LIT); \
+  EV = lglevar (lgl, LIT); \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), "esched[%d] = %d ", POS, LIT); \
+  fprintf (lgl->out, FMT, ##ARGS); \
+  fprintf (lgl->out, " score"); \
+  fprintf (lgl->out, " occ %d %d", EV->occ[0], EV->occ[1]); \
+  lglogend (lgl); \
+} while (0)
+
+#define LOGEQN(LEVEL,EQN,FMT,ARGS...) \
+do { \
+  const int * P, * START; \
+  if (MAPLOGLEVEL(LEVEL) > lgl->opts->log.val) break; \
+  lglogstart (lgl, MAPLOGLEVEL(LEVEL), FMT, ##ARGS); \
+  START = lgl->gauss->xors.start + (EQN); \
+  assert (START < lgl->gauss->xors.top); \
+  for (P = START; *P > 1; P++) fprintf (lgl->out, " %d", *P); \
+  fprintf (lgl->out, " = %d", *P); \
+  lglogend (lgl); \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+#else /* end of then start of else part of 'ifndef NLGLOG' */
+/*------------------------------------------------------------------------*/
+
+#define LOG(ARGS...) do { } while (0)
+#define LOGCLS(ARGS...) do { } while (0)
+#define LOGMCLS(ARGS...) do { } while (0)
+#define LOGRESOLVENT(ARGS...) do { } while (0)
+#define LOGREASON(ARGS...) do { } while (0)
+#define LOGDSCHED(ARGS...) do { } while (0)
+#define LOGESCHED(ARGS...) do { } while (0)
+#define LOGEQN(ARGS...) do { } while (0)
+
+/*------------------------------------------------------------------------*/
+#endif /* end of else part of 'ifndef NLGLOG' */
+/*------------------------------------------------------------------------*/
+
+#define ABORTIF(COND,FMT,ARGS...) \
+do { \
+  if (!(COND)) break; \
+  fprintf (stderr, "*** API usage error of '%s' in '%s'", \
+          __FILE__, __FUNCTION__); \
+  if (lgl && lgl->tid >= 0) fprintf (stderr, " (tid %d)", lgl->tid); \
+  fputs (": ", stderr); \
+  fprintf (stderr, FMT, ##ARGS); \
+  fputc ('\n', stderr); \
+  fflush (stderr); \
+  lglabort (lgl); \
+  exit (1); \
+} while (0)
+
+// Useful for using our 'sleeponabort' and other hooks 'on abort' ...
+
+#ifndef NDEBUG
+#define ASSERT(COND) \
+do { \
+  if ((COND)) break; \
+  fprintf (stderr, \
+    "liblgl.a: %s:%d: %s: Lingeling Assertion `%s' failed.", \
+    __FUNCTION__, __LINE__, __FILE__, # COND); \
+  if (lgl && lgl->tid >= 0) fprintf (stderr, " (tid %d)", lgl->tid); \
+  fputc ('\n', stderr); \
+  fflush (stderr); \
+  lglabort (lgl); \
+  exit (1); \
+} while (0)
+#else
+#define ASSERT(COND) do { } while (0)
+#endif
+
+#define COVER(COND) \
+do { \
+  if (!(COND)) break; \
+  fprintf (stderr, \
+    "liblgl.a: %s:%d: %s: Coverage target `%s' reached.", \
+    __FUNCTION__, __LINE__, __FILE__, # COND); \
+  if (lgl && lgl->tid >= 0) fprintf (stderr, " (tid %d)", lgl->tid); \
+  fputc ('\n', stderr); \
+  fflush (stderr); \
+  abort (); /* TODO: why not 'lglabort' */ \
+} while (0)
+
+#define REQINIT() \
+do { \
+  ABORTIF (!lgl, "uninitialized manager"); \
+} while (0)
+
+#define REQINITNOTFORKED() \
+do { \
+  REQINIT (); \
+  ABORTIF (lgl->forked, "forked manager"); \
+} while (0)
+
+#define REQUIRE(STATE) \
+do { \
+  REQINIT (); \
+  ABORTIF(!(lgl->state & (STATE)), "!(%s)", #STATE); \
+} while (0)
+
+#define TRANS(STATE) \
+do { \
+  assert (lgl->state != STATE); \
+  LOG (1, "transition to state " #STATE); \
+  lgl->state = STATE; \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+
+#if !defined(NDEBUG) || !defined(NLGLOG)
+#define RESOLVENT
+#endif
+
+/*------------------------------------------------------------------------*/
+
+#define TRAPI(MSG,ARGS...) \
+do { \
+  if (!lgl->apitrace) break; \
+  lgltrapi (lgl, MSG, ##ARGS); \
+} while (0)
+
+#define LGLCHKACT(ACT) \
+do { assert (NOTALIT <= (ACT) && (ACT) < REMOVED - 1); } while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define OPT(SHRT,LNG,VAL,MIN,MAX,DESCRP) \
+do { \
+  Opt * opt = &lgl->opts->LNG; \
+  opt->shrt = SHRT; \
+  opt->lng = #LNG; \
+  opt->dflt = opt->val = VAL; \
+  assert (MIN <= VAL); \
+  opt->min = MIN; \
+  assert (VAL <= MAX); \
+  opt->max = MAX; \
+  opt->descrp = DESCRP; \
+  lglgetenv (lgl, opt, #LNG); \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define NEW(P,N) \
+do { (P) = lglnew (lgl, (N) * sizeof *(P)); } while (0)
+
+#define DEL(P,N) \
+do { lgldel (lgl, (P), (N) * sizeof *(P)); (P) = 0; } while (0)
+
+#define RSZ(P,O,N) \
+do { (P) = lglrsz (lgl, (P), (O)*sizeof*(P), (N)*sizeof*(P)); } while (0)
+
+#define CLN(P,N) \
+do { memset ((P), 0, (N) * sizeof *(P)); } while (0)
+
+#define CLRPTR(P) \
+do { memset ((P), 0, sizeof *(P)); } while (0)
+
+#define CLR(P) \
+do { memset (&(P), 0, sizeof (P)); } while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define SWAP(TYPE,A,B) \
+do { TYPE TMP = (A); (A) = (B); (B) = TMP; } while (0)
+
+#define ISORTLIM 10
+
+#define CMPSWAP(TYPE,CMP,P,Q) \
+do { if (CMP (&(P), &(Q)) > 0) SWAP (TYPE, P, Q); } while(0)
+
+#define QPART(TYPE,CMP,A,L,R) \
+do { \
+  TYPE PIVOT; \
+  int J = (R); \
+  I = (L) - 1; \
+  PIVOT = (A)[J]; \
+  for (;;) { \
+    while (CMP (&(A)[++I], &PIVOT) < 0) \
+      ; \
+    while (CMP (&PIVOT, &(A)[--J]) < 0) \
+      if (J == (L)) break; \
+    if (I >= J) break; \
+    SWAP (TYPE, (A)[I], (A)[J]); \
+  } \
+  SWAP (TYPE, (A)[I], (A)[R]); \
+} while(0)
+
+#define QSORT(TYPE,CMP,A,N) \
+do { \
+  int L = 0, R = (N) - 1, M, LL, RR, I; \
+  assert (lglmtstk (&lgl->sortstk)); \
+  if (R - L <= ISORTLIM) break; \
+  for (;;) { \
+    M = (L + R) / 2; \
+    SWAP (TYPE, (A)[M], (A)[R - 1]); \
+    CMPSWAP (TYPE, CMP, (A)[L], (A)[R - 1]); \
+    CMPSWAP (TYPE, CMP, (A)[L], (A)[R]); \
+    CMPSWAP (TYPE, CMP, (A)[R - 1], (A)[R]); \
+    QPART (TYPE, CMP, (A), L + 1, R - 1); \
+    if (I - L < R - I) { LL = I + 1; RR = R; R = I - 1; } \
+    else { LL = L; RR = I - 1; L = I + 1; } \
+    if (R - L > ISORTLIM) { \
+      assert (RR - LL > ISORTLIM); \
+      lglpushstk (lgl, &lgl->sortstk, LL); \
+      lglpushstk (lgl, &lgl->sortstk, RR); \
+    } else if (RR - LL > ISORTLIM) L = LL, R = RR; \
+    else if (!lglmtstk (&lgl->sortstk)) { \
+      R = lglpopstk (&lgl->sortstk); \
+      L = lglpopstk (&lgl->sortstk); \
+    } else break; \
+  } \
+} while (0)
+
+#define ISORT(TYPE,CMP,A,N) \
+do { \
+  TYPE PIVOT; \
+  int L = 0, R = (N) - 1, I, J; \
+  for (I = R; I > L; I--) \
+    CMPSWAP (TYPE, CMP, (A)[I - 1], (A)[I]); \
+  for (I = L + 2; I <= R; I++) { \
+    J = I; \
+    PIVOT = (A)[I]; \
+    while (CMP (&PIVOT, &(A)[J - 1]) < 0) { \
+      (A)[J] = (A)[J - 1]; \
+      J--; \
+    } \
+    (A)[J] = PIVOT; \
+  } \
+} while (0)
+
+#ifdef NDEBUG
+#define CHKSORT(CMP,A,N) do { } while(0)
+#else
+#define CHKSORT(CMP,A,N) \
+do { \
+  int I; \
+  for (I = 0; I < (N) - 1; I++) \
+    assert (CMP (&(A)[I], &(A)[I + 1]) <= 0); \
+} while(0)
+#endif
+
+#define SORT(TYPE,A,N,CMP) \
+do { \
+  TYPE * AA = (A); \
+  int NN = (N); \
+  QSORT (TYPE, CMP, AA, NN); \
+  ISORT (TYPE, CMP, AA, NN); \
+  CHKSORT (CMP, AA, NN); \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define LGLPOPWTK(WTK,WRAG,LIT,OTHER,RED,REMOVED) \
+do { \
+  assert (!lglmtwtk (WTK)); \
+  (WTK)->top--; \
+  (WRAG) = (WTK)->top->wrag; \
+  (LIT) = (WTK)->top->lit; \
+  (OTHER) = (WTK)->top->other; \
+  (RED) = (WTK)->top->red ? REDCS : 0; \
+  (REMOVED) = (WTK)->top->removed; \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define CLONE(FIELD,SIZE) \
+do { \
+  NEW (lgl->FIELD, (SIZE)); \
+  memcpy (lgl->FIELD, orig->FIELD, (SIZE) * sizeof *(lgl->FIELD)); \
+} while (0)
+
+#define CLONESTK(NAME) \
+do { \
+  size_t COUNT = orig->NAME.top - orig->NAME.start; \
+  size_t SIZE = orig->NAME.end - orig->NAME.start; \
+  size_t BYTES = SIZE * sizeof *lgl->NAME.start; \
+  NEW (lgl->NAME.start, SIZE); \
+  memcpy (lgl->NAME.start, orig->NAME.start, BYTES); \
+  lgl->NAME.top = lgl->NAME.start + COUNT; \
+  lgl->NAME.end = lgl->NAME.start + SIZE; \
+} while (0)
+
+/*------------------------------------------------------------------------*/
+
+#define INCSTEPS(NAME) \
+ ((lgl->stats->steps++), (lgl->stats->NAME++))
+
+#define ADDSTEPS(NAME,INC) \
+ ((lgl->stats->steps += INC), (lgl->stats->NAME += INC))
+
+/*------------------------------------------------------------------------*/
+
+#define LGLUPDPEN(NAME,SUCCESS) \
+do { \
+  assert (!lgl->limits->NAME.del.rem); \
+  if ((SUCCESS) && lgl->limits->NAME.pen) \
+    lgl->limits->NAME.pen--; \
+  if (!(SUCCESS) && lgl->limits->NAME.pen < lgl->opts->penmax.val) \
+    lgl->limits->NAME.pen++; \
+  if ((SUCCESS) && lgl->limits->NAME.del.cur) \
+    lgl->limits->NAME.del.cur /= 2; \
+  if (!(SUCCESS) && lgl->limits->NAME.del.cur < lgl->opts->delmax.val) \
+    lgl->limits->NAME.del.cur++; \
+  lgl->limits->NAME.del.rem = lgl->limits->NAME.del.cur; \
+} while (0)
+
+/*-------------------------------------------------------------------------*/
+
+#define LGLL long long
+
+/*-------------------------------------------------------------------------*/
+
+typedef enum Tag {
+  FREEVAR = 0,
+  FIXEDVAR = 1,
+  EQUIVAR = 2,
+  ELIMVAR = 3,
+
+  DECISION = 0,
+  UNITCS = 1,
+  OCCS = 1,
+  BINCS = 2,
+  TRNCS = 3,
+  LRGCS = 4,
+  MASKCS = 7,
+
+  REDCS = 8,
+  RMSHFT = 4,
+} Tag;
+
+typedef enum State {
+  UNUSED       = (1<<0),
+  OPTSET       = (1<<1),
+  USED                 = (1<<2),
+  READY                = (1<<3),
+  UNKNOWN      = (1<<4),
+  SATISFIED    = (1<<5),
+  EXTENDED      = (1<<6),
+  UNSATISFIED  = (1<<7),
+  FAILED        = (1<<8),
+  LOOKED        = (1<<9),
+  RESET                = (1<<10),
+} State;
+
+typedef enum Wrag {
+  PREFIX = 0,
+  BEFORE = 1,
+  AFTER = 2,
+  POSTFIX = 3,
+} Wrag;
+
+typedef enum GTag { ANDTAG, ITETAG, XORTAG } GTag;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Opt {
+  char shrt;
+  const char * lng, * descrp;
+  int val, min, max, dflt;
+} Opt;
+
+typedef struct Opts {
+
+  Opt beforefirst;
+
+  Opt abstime;
+  Opt actavgmax;
+  Opt actdblarithlim;
+  Opt actgeomlim;
+  Opt actgsdul;
+  Opt acts;
+  Opt actstdmax;
+  Opt actstdmin;
+  Opt actvlim;
+  Opt agile;
+  Opt agilelim;
+  Opt agilesinint;
+  Opt bate;
+  Opt batewait;
+  Opt bca;
+  Opt bcamaxeff;
+  Opt bcaminuse;
+  Opt bcawait;
+  Opt bva;
+  Opt bias;
+  Opt binlocsdel;
+  Opt binsimpdel;
+  Opt bkwdscale;
+  Opt blkboost;
+  Opt blkboostvlim;
+  Opt blkclslim;
+  Opt blklarge;
+  Opt blkmaxeff;
+  Opt blkmineff;
+  Opt blkocclim;
+  Opt blkocclim1;
+  Opt blkocclim2;
+  Opt blkreleff;
+  Opt blkrtc;
+  Opt blksched2b2;
+  Opt blkschedmin;
+  Opt blkschedprod;
+  Opt blkschedpure;
+  Opt blkschedsum;
+  Opt blksmall;
+  Opt blksuccesslim;
+  Opt blksuccessrat;
+  Opt block;
+  Opt blockwait;
+  Opt boost;
+  Opt bumpbcplits;
+  Opt bumpclslits;
+  Opt bumpseenaftermin;
+  Opt bumpseenbeforemin;
+  Opt bumpseenlits;
+  Opt bumpseenminsize;
+  Opt card;
+  Opt cardcut;
+  Opt cardexpam1;
+  Opt cardglue;
+  Opt cardignused;
+  Opt cardmaxeff;
+  Opt cardmaxlen;
+  Opt cardmineff;
+  Opt cardminlen;
+  Opt cardocclim1;
+  Opt cardocclim2;
+  Opt cardreleff;
+  Opt cardreschedint;
+  Opt carduse;
+  Opt cardwait;
+  Opt cce;
+  Opt cceboost;
+  Opt cceboostvlim;
+  Opt cce2wait;
+  Opt cce3wait;
+  Opt ccemaxeff;
+  Opt ccemineff;
+  Opt cceonlyifstuck;
+  Opt ccereleff;
+  Opt ccertc;
+  Opt ccesuccesslim;
+  Opt ccesuccessrat;
+  Opt ccewait;
+  Opt cgrclsr;
+  Opt cgrclsrwait;
+  Opt cgreleff;
+  Opt cgrextand;
+  Opt cgrexteq;
+  Opt cgrextite;
+  Opt cgrextunits;
+  Opt cgrextxor;
+  Opt cgrmaxeff;
+  Opt cgrmaxority;
+  Opt cgrmineff;
+  Opt cintinc;
+  Opt cintincdiv;
+  Opt cintmaxhard;
+  Opt cintmaxsoft;
+  Opt cliff;
+  Opt cliffmaxeff;
+  Opt cliffmineff;
+  Opt cliffreleff;
+  Opt cliffwait;
+  Opt clim;
+  Opt compact;
+  Opt deco;
+  Opt decolim;
+  Opt decompose;
+  Opt defragfree;
+  Opt defragint;
+  Opt delmax;
+  Opt dlim;
+  Opt drup;
+  Opt druplig;
+  Opt elim;
+  Opt elmaxeff;
+  Opt elmblk;
+  Opt elmblkwait;
+  Opt elmboost;
+  Opt elmclslim;
+  Opt elmfull;
+  Opt elmineff;
+  Opt elmlitslim;
+  Opt elmocclim;
+  Opt elmocclim1;
+  Opt elmocclim2;
+  Opt elmreleff;
+  Opt elmroundlim;
+  Opt elmrtc;
+  Opt elmsched2b2;
+  Opt elmschediff;
+  Opt elmschedmin;
+  Opt elmschedprod;
+  Opt elmschedpure;
+  Opt elmschedsum;
+  Opt elmsuccesslim;
+  Opt elmsuccessrat;
+  Opt exitonabort;
+  Opt factmax;
+  Opt factor;
+  Opt flipdur;
+  Opt flipint;
+  Opt flipldmod;
+  Opt fliplevels;
+  Opt flipping;
+  Opt fliptop;
+  Opt flipvlim;
+  Opt force;
+  Opt gauss;
+  Opt gaussexptrn;
+  Opt gaussextrall;
+  Opt gaussmaxeff;
+  Opt gaussmaxor;
+  Opt gaussmineff;
+  Opt gaussreleff;
+  Opt gausswait;
+  Opt gluekeep;
+  Opt gluescale;
+  Opt import;
+  Opt incredcint;
+  Opt incredconfslim;
+  Opt incsavevisits;
+  Opt inprocessing;
+  Opt irrlim;
+  Opt itlocsdel;
+  Opt itsimpdel;
+  Opt jwhred;
+  Opt keepmaxglue;
+  Opt lftmaxeff;
+  Opt lftmineff;
+  Opt lftreleff;
+  Opt lftroundlim;
+  Opt lhbr;
+  Opt lift;
+  Opt liftlrg;
+  Opt liftwait;
+  Opt lkhd;
+  Opt lkhdmisifelmrtc;
+  Opt locs;
+  Opt locsboost;
+  Opt locscint;
+  Opt locsdec;
+  Opt locset;
+  Opt locsexport;
+  Opt locsmaxeff;
+  Opt locsmineff;
+  Opt locsclim;
+  Opt locsred;
+  Opt locsreleff;
+  Opt locsrtc;
+  Opt locsvared;
+  Opt locswait;
+  Opt maxglue;
+  Opt maxscorexp;
+  Opt mega;
+  Opt megaint;
+  Opt megawait;
+  Opt memlim;
+  Opt minimize;
+  Opt minlocalgluelim;
+  Opt minrecgluelim;
+  Opt mocint;
+  Opt move;
+  Opt otfs;
+  Opt otfsbump;
+  Opt otfsconf;
+  Opt penmax;
+  Opt phase;
+  Opt phaseflip;
+  Opt phasegluebit;
+  Opt phaseneginit;
+  Opt plain;
+  Opt plim;
+  Opt prbasic;
+  Opt prbasicmaxeff;
+  Opt prbasicmineff;
+  Opt prbasicreleff;
+  Opt prbasicroundlim;
+  Opt prbasicrtc;
+  Opt prbrtc;
+  Opt prbsimple;
+  Opt prbsimpleboost;
+  Opt prbsimpleliftdepth;
+  Opt prbsimplemaxeff;
+  Opt prbsimplemineff;
+  Opt prbsimplereleff;
+  Opt prbsimplertc;
+  Opt probe;
+  Opt psm;
+  Opt pure;
+  Opt randec;
+  Opt randecflipint;
+  Opt randecint;
+  Opt rdp;
+  Opt rdpclslim;
+  Opt rdplim;
+  Opt rdpmaxeff;
+  Opt rdpmineff;
+  Opt rdpmodelm;
+  Opt rdpreleff;
+  Opt rdpwait;
+  Opt redfixed;
+  Opt redinoutinc;
+  Opt redlbound;
+  Opt redlexpfac;
+  Opt redlinc;
+  Opt redlinit;
+  Opt redlmaxabs;
+  Opt redlmaxinc;
+  Opt redlmaxrel;
+  Opt redlminabs;
+  Opt redlmininc;
+  Opt redlminrel;
+  Opt redloutinc;
+  Opt redoutclim;
+  Opt redoutvlim;
+  Opt reduce;
+  Opt rephase;
+  Opt rephaseinc;
+  Opt restart;
+  Opt restartinit;
+  Opt restartint;
+  Opt restartintscale;
+  Opt reusetrail;
+  Opt rmincpen;
+  Opt rstinoutinc;
+  Opt saturating;
+  Opt scincinc;
+  Opt score;
+  Opt seed;
+  Opt simpdelay;
+  Opt simpen;
+  Opt simpidiv;
+  Opt simpinterdelay;
+  Opt simpiscale;
+  Opt simplify;
+  Opt simprtc;
+  Opt simpvarchg;
+  Opt simpvarlim;
+  Opt sizemaxpen;
+  Opt sizepen;
+  Opt sleeponabort;
+  Opt smallirr;
+  Opt smallve;
+  Opt smallvevars;
+  Opt smallvewait;
+  Opt sortlits;
+  Opt subl;
+  Opt synclsall;
+  Opt synclsglue;
+  Opt synclsint;
+  Opt synclslen;
+  Opt syncunint;
+  Opt tabr;
+  Opt tabrcfactor;
+  Opt tabrkeep;
+  Opt tabrvfactor;
+  Opt termint;
+  Opt ternres;
+  Opt ternresboost;
+  Opt ternresrtc;
+  Opt ternreswait;
+  Opt transred;
+  Opt transredwait;
+  Opt trdmaxeff;
+  Opt trdmineff;
+  Opt trdreleff;
+  Opt treelook;
+  Opt treelookboost;
+  Opt treelookfull;
+  Opt treelooklrg;
+  Opt treelookmaxeff;
+  Opt treelookmineff;
+  Opt treelookreleff;
+  Opt treelookrtc;
+  Opt trep;
+  Opt trepint;
+  Opt trnreleff;
+  Opt trnrmaxeff;
+  Opt trnrmineff;
+  Opt unhdatrn;
+  Opt unhdextstamp;
+  Opt unhdhbr;
+  Opt unhdlnpr;
+  Opt unhdmaxeff;
+  Opt unhdmineff;
+  Opt unhdreleff;
+  Opt unhdroundlim;
+  Opt unhide;
+  Opt unhidewait;
+  Opt wait;
+  Opt waitmax;
+  Opt witness;
+
+  Opt check;
+  Opt log;
+  Opt verbose;
+
+  Opt afterlast;
+
+} Opts;
+
+#define FIRSTOPT(lgl) (&(lgl)->opts->beforefirst + 1)
+#define LASTOPT(lgl) (&(lgl)->opts->afterlast - 1)
+
+/*------------------------------------------------------------------------*/
+
+typedef int Exp;
+typedef uint64_t Mnt;
+typedef int64_t Flt;
+typedef int64_t Cnf;
+typedef uint64_t Fun[FUNQUADS];
+typedef signed char Val;
+typedef Flt LKHD;
+
+/*------------------------------------------------------------------------*/
+#ifdef NDBLSCR
+typedef Flt Scr;
+#else
+typedef double Scr;
+#endif
+/*------------------------------------------------------------------------*/
+
+typedef struct Conf { int lit, rsn[2]; } Conf;
+typedef struct Ctk { struct Ctr * start, * top, * end; } Ctk;
+typedef struct DFOPF { int observed, pushed, flag; } DFOPF;
+typedef struct DFPR { int discovered, finished, parent, root; } DFPR;
+typedef struct EVar { int occ[2], pos, score; } EVar;
+typedef struct Ftk { Flt * start, * top, * end; } Ftk;
+typedef struct HTS { int offset, count; }  HTS;
+typedef struct ITEC { int other, other2; } ITEC;
+typedef struct Lim { int64_t confs, decs, props; } Lim;
+typedef struct PASL { int psm, act, size, lidx; } PASL;
+typedef struct PSz { int pos, size; } PSz;
+typedef struct Qnd { int prev, next; struct Qln * line; } Qnd;
+typedef struct RNG { unsigned z, w; } RNG;
+typedef struct Stk { int * start, * top, * end; } Stk;
+typedef struct Tmrs { double phase[MAXPHN]; int idx[MAXPHN], nest; } Tmrs;
+typedef struct Trv { void * state; void (*trav)(void *, int); } Trv;
+typedef struct TVar { signed int val : 30; unsigned mark : 2; } TVar;
+typedef struct Wtk { struct Work * start, * top, * end; } Wtk;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Ctr { 
+  signed int decision : 31; 
+  unsigned used : 1;
+} Ctr;
+
+typedef struct DVar { HTS hts[2]; } DVar;
+
+typedef struct QVar { Scr score; int pos; } QVar;
+
+typedef struct TD {
+  signed int level:30;
+  unsigned lrglue:1, irr:1; 
+  int rsn[2];
+} TD;
+
+typedef struct ID { int level, lit, rsn[2]; } ID;
+
+typedef struct Impls { ID * start, * top, * end; } Impls;
+
+typedef struct AVar {
+  unsigned type : 4;
+#ifndef NDEBUG
+  unsigned simp:1, wasfalse:1;
+#endif
+  unsigned equiv:1, lcamark:4;
+  signed int phase:2, bias:2, fase:2;
+  unsigned inred:2, poisoned:1, assumed:2, failed:2, gate:1;
+  unsigned donotelm:1, donotblk:1, donotcgrcls:1, donotlft:1, donoternres:1;
+  unsigned donotbasicprobe:1, donotsimpleprobe:1, donotreelook:1, mega:2;
+#ifndef NLGLYALSAT
+  signed int locsval:2;
+#endif
+  int mark, trail;
+} AVar;
+
+typedef struct Ext {
+  unsigned equiv:1,melted:1,blocking:2,eliminated:1,tmpfrozen:1,imported:1;
+  unsigned assumed:2,failed:2,internal:1,defined:1;
+  signed int val:2, oldval:2;
+  int repr, frozen;
+} Ext;
+
+typedef struct Work {
+  unsigned wrag : 2;
+  signed int lit : 30, other : 30;
+  unsigned red : 1, removed : 1;
+} Work;
+
+typedef struct DFL {
+  int discovered, finished;
+  union { int lit, sign; };
+#ifndef NLGLOG
+  int lit4logging;
+#endif
+} DFL;
+
+typedef struct Gat {
+  int lhs, minrhs;
+  unsigned tag : 2;
+  unsigned mark : 1;
+  signed int size : 29;
+  union {
+    int lits[2];
+    struct { int * cls, origlhs; };
+    struct { int cond, pos, neg; };
+  };
+} Gat;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Stats {
+  int64_t steps, trims;
+  int defrags, iterations, acts, reported, repcntdown, gcs, decomps;
+  int cutwidths;
+  struct { int64_t count, steps; struct { int max, min; } mincut; } force;
+  struct { int clauses, vars; } rescored;
+  struct { int count;
+           struct {int64_t scaled, orig; } intsum;
+           struct { int count, saturating, agile, reuse; } skipped;
+          struct { int count; int64_t sum; } kept; } restarts;
+  struct { int count, reset, geom, gul, arith, arith2, memlim; } reduced;
+  int64_t prgss, irrprgss, enlwchs, pshwchs, height, dense, sparse;
+  int64_t confs, decisions, randecs, randecsflipped, flipped, fliphases;
+  int64_t uips, decflipped;
+  struct { struct { int cur, max; int64_t add; } clauses, lits; } irr;
+  struct { int64_t sat, mosat, simp, deref, fixed, freeze, lkhd;
+          int64_t melt, add, assume, cassume, failed, repr; } calls;
+  struct { int64_t search, hits; } poison;
+  struct { int64_t search, simp, lkhd; } props, visits, travs;
+  struct { size_t current, max; } bytes;
+  struct { int bin, trn, lrg; } red;
+  struct { int cnt, simple, trn, lrg, sub; } hbr;
+  struct { int current, sum; } fixed, equiv;
+  struct { int count, bin, trn; int64_t steps; } trnr;
+  struct { int count, clauses, lits, pure; int64_t res, steps; } blk;
+  struct { int count, eq, units; int64_t esteps, csteps;
+          struct { int all, and, xor, ite; } matched;
+          struct { int all, and, xor, ite; } simplified;
+          struct { int64_t all, and, xor, ite; } extracted; } cgr;
+  struct {
+    struct { int count, failed, eqs; int64_t probed, steps; } simple;
+    struct { int count, failed, lifted; 
+             int64_t probed, steps, lastate;
+            struct { int trnr, lrg, count; } ate; } basic;
+    struct { int count, failed, lifted; int64_t probed, steps; } treelook;
+  } prb;
+  struct { int count, eqs, units, impls; int64_t probed0, probed1; } lift;
+  struct { int count, red, failed; int64_t lits, bins, steps; } trd;
+  struct { int removed, red; } bindup;
+  struct { int count, rounds;
+          struct { int trds, failed, sccs; int64_t sumsccsizes; } stamp;
+          struct { int lits, bin, trn, lrg; } failed;
+          struct { int bin, trn, lrg, red; } tauts;
+          struct { int bin, trn, lrg; } units;
+          struct { int trn, lrg, red; } hbrs;
+          struct { int trn, lrg, red; } str;
+          int64_t steps; } unhd;
+  struct {
+    int count, elmd, large, sub, str, blkd, rounds;
+    struct { int elm, tried, failed; } small;
+    int64_t resolutions, copies, subchks, strchks, ipos, steps; } elm;
+  struct {
+    int sub2, sub3, subl, str2, str3, str3self, strl, strlself;
+    struct { int64_t lits, clauses, occs; } tried;
+    int64_t steps;
+  } bkwd;
+  struct {
+    struct { struct { int irr, red; } dyn; } sub, str;
+    int64_t driving, restarting; } otfs;
+  struct { int64_t nonmin, learned; } lits;
+  struct { 
+    int64_t learned, glue, realglue, nonmaxglue, maxglue, scglue; }
+  clauses;
+  struct {
+    int clauses;
+    int64_t added, reduced, resolved, forcing, conflicts, saved;
+  } lir[POW2GLUE];
+  struct { int64_t sum; int count; } glues;
+  struct { int count; int64_t set, pos, neg; } phase;
+  struct { int count; struct { int confs, irr, vars; } limhit; } simp;
+  struct { int count; int64_t steps; } luby, inout;
+  struct { int count, gcs, units, equivs, trneqs; 
+           struct { int max; int64_t sum; } arity; 
+          struct { int64_t extr, elim; } steps;
+          int64_t extracted; } gauss;
+  struct { int count, eliminated, ate, abce, failed, lifted;
+           int64_t steps, probed;
+          struct { int64_t search, hits, cols, ins, rsz; } cache; } cce;
+  struct { int count, failed, lifted; int64_t decisions, steps; } cliff;
+  struct { 
+    int count, units, expam1, resched;
+    int64_t steps, eliminated, resolved, subsumed;
+    struct { struct { int64_t sum, cnt; } found, used; } am1, am2; } card;
+  struct { int64_t bin, trn, lrg; } moved;
+  struct { int count, inc; } rephase;
+  struct { int count; int64_t added, skipped, steps; } bca;
+  struct { int count; int64_t added, removed; } bva;
+  struct { 
+    struct {
+      int64_t produced; 
+      struct { int64_t actual, tried, calls; } consumed;
+    } cls, units;
+  } sync;
+  struct { struct { int64_t orig, red; } sum; } deco;
+  struct { int64_t min, bin, size, deco; } mincls;
+  int64_t drupped, druplig;
+  struct {
+    int64_t count, units, bin, trn, steps, elim, res;
+    struct { int64_t bound, len, model; } limhit; } rdp;
+  struct { int64_t count, tried, cands, sub; } subl;
+  struct { int count; int64_t flips, mems; int min; } locs;
+  struct { int count; } tabr;
+  struct { int count, failed, lifted, eqs, rounds; } mega;
+} Stats;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Times {
+  double all, dcp, elm, trd, gc, dfg, red, blk, ana, unhd, dec, lkhd;
+  double rsts, lft, trn, cgr, phs, srch, prep, inpr, bump, mcls, gauss;
+  double card, cce, cliff, ctw, force, bca, rdp, locs, bkwd, bva, tabr;
+  double mega;
+  struct { double all, simple, basic, treelook; } prb;
+} Times;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Del { int cur, rem; } Del;
+
+typedef struct Limits {
+  int flipint, lkhdpen;
+  int64_t randec, dfg;
+  struct {
+    int64_t visits;
+    struct { int64_t add; int start; } clauses;
+    struct { int start; } vars;
+  } inc;
+  struct { int clauses, vars; } tabr;
+  struct { int inner, outer, extra; } reduce;
+  struct { struct { int64_t otfs, confs; } vars; } rescore;
+  struct { int pen; Del del; int64_t esteps, csteps; } cgr;
+  struct { int pen; Del del; int64_t steps, irrprgss; } elm, blk, cliff;
+  struct { int pen; Del del; int64_t steps; }
+    rdp, trd, unhd, trnr, lft, cce, card;
+  struct { int pen; Del del; struct { int64_t extr, elim; } steps; } gauss;
+  struct { int64_t confs; } rephase;
+  struct { int64_t confs; int wasmaxdelta, maxdelta, luby, inout; } restart;
+  struct { int64_t steps; 
+           struct { int pen; Del del; } simple, basic, treelook; } prb;
+  struct { int64_t vars, confs; int pen, cinc; } simp;
+  struct { int64_t steps, confs; } sync;
+  struct { int64_t steps; } term;
+  struct { int64_t fixed; } gc;
+  struct { Del del; int64_t steps; } bca;
+  struct { int64_t steps, time; } trep;
+  struct { int64_t confs, inc; int vars; } locs;
+} Limits;
+
+/*------------------------------------------------------------------------*/
+
+typedef struct Cbs {
+  struct { int (*fun)(void*); void * state; int done; } term;
+  struct {
+    struct { void (*fun)(void*,int); void * state; } produce, consumed;
+    struct { void(*fun)(void*,int**,int**); void*state; } consume;
+  } units;
+  struct {
+    struct { void (*fun)(void*,int*,int); void * state; } produce;
+    struct { void(*fun)(void*,int**,int*); void*state; } consume;
+    struct { void (*fun)(void*,int); void * state; } consumed;
+  } cls;
+  struct {
+    struct { int * (*fun)(void*); void * state; } lock;
+    struct { void (*fun)(void*,int,int); void * state; } unlock;
+  } eqs;
+  struct { void(*lock)(void*); void (*unlock)(void*); void*state; } msglock;
+  double (*getime)(void);
+  void (*onabort)(void *); void * abortstate;
+} Cbs;
+
+typedef struct Cgr {
+  struct { int units, eq, all, and, xor, ite, org; } extracted;
+  struct { int all, and, xor, ite, org; } simplified;
+  struct { int all, and, xor, ite, org; } matched;
+  Stk * goccs, units; Gat * gates; int szgates;
+} Cgr;
+
+typedef struct Cliff { Stk lift, lits; } Cliff;
+
+typedef struct BCA { Stk covered; } BCA;
+
+typedef struct Dis { struct { Stk bin, trn; } red, irr; } Dis;
+
+typedef struct Elm {
+  int64_t oldsteps;
+  int pivot, negcls, necls, neglidx, round, oldelmd;
+  Stk lits, next, clv, csigs, sizes, occs, noccs, mark, m2i;
+} Elm;
+
+typedef struct RDP {
+  int * count, eliminated;
+  Stk lits, * occs;
+  double start;
+} RDP;
+
+typedef struct Card {
+  Stk atmost1, atmost2, cards, elim, * occs, units, expam1;
+  char * eliminated, * lit2used, * marked;
+  signed char * count;
+  int * lit2count;
+} Card;
+
+typedef struct FltStr { int current; char str[MAXFLTSTR][100]; } FltStr;
+
+typedef struct SPE { signed int count : 31; unsigned mark : 1, sum; } SPE;
+
+typedef struct SPrb { 
+  Stk units, impls, eqs, counted, marked;
+  SPE * spes;
+} SPrb;
+
+typedef struct Gauss { 
+  Stk xors, order, * occs; 
+  signed char * eliminated;
+  int garbage, next; 
+} Gauss;
+
+typedef struct CCE {
+  Stk cla, extend, clauses;
+  int * rem, bin, trn;
+} CCE;
+
+typedef struct Tlk { Stk stk, seen; TVar * tvars; LKHD * lkhd; } Tlk;
+
+typedef struct Mem {
+  void * state;
+  lglalloc alloc; lglrealloc realloc; lgldealloc dealloc;
+} Mem;
+
+typedef struct Wchs { Stk stk; int start[MAXLDFW], free; } Wchs;
+
+typedef struct Wrk {
+  Stk queue;
+  int count, head, size, posonly, fifo, * pos;
+} Wrk;
+
+/*------------------------------------------------------------------------*/
+
+struct LGL {
+  State state;
+
+  int probing, flipping, notflipped, tid, tids, bias, phaseneg;
+  int nvars, szvars, maxext, szext, maxdef, szdef, changed, mt, repcntdown;
+  int szdrail, bnext, next, next2, flushed, level, alevel, wait;
+  int unassigned, lrgluereasons, failed, assumed, cassumed, ncassumed;
+
+  Scr scinc, scincf, maxscore;
+
+  char lifting, cceing, gaussing, cliffing, bcaing, forcerephead;
+  char cgrclosing, searching, simp, allphaseset, flushphases, occs;
+  char unhiding, basicprobing, simpleprobing, treelooking, setuponce;
+  char eliminating, donotsched, blocking, ternresing, lkhd, allfrozen;
+  char blkall, blkrem, blkrtc, elmall, elmrem, elmrtc, decomposing;
+  char frozen, dense, notfullyconnected, forcegc, allowforce;
+  char ccertc, elmstuck, blkstuck;
+
+  LGL * parent;
+  int forked;
+
+  unsigned long long flips;
+
+  Conf conf;
+  RNG rng;
+
+  // the state above this line is copied during 'clone' with 'memcpy'
+
+  Mem * mem;
+  Opts * opts;
+  Stats * stats;
+  Times * times;
+  Tmrs * timers;
+  Limits * limits;
+  Ext * ext, * def;
+  int * i2e;
+  int * doms;
+  DVar * dvars;
+  QVar * qvars;
+  AVar * avars;
+  Val * vals;
+  Flt * jwh;
+  TD * drail;
+  Stk * red;
+  Wchs * wchs;
+
+  Ctk control;
+  Stk clause, eclause, extend, irr, trail, frames;
+  Stk dsched, eassume, assume, cassume, fassume, learned;
+#ifndef NCHKSOL
+  Stk orig;
+#endif
+
+  union {
+    Elm * elm; Cgr * cgr; SPrb * sprb; Tlk * tlk; Gauss * gauss;
+    CCE * cce; Cliff * cliff; BCA * bca; Card * card; RDP * rdp;
+  };
+  union { Stk lcaseen, sortstk, resolvent; };
+  Stk poisoned, seen, esched, minstk;
+  EVar * evars;
+  Dis * dis;
+  Wrk * wrk;
+  int * repr;
+
+  char closeapitrace;
+  FILE * out, * apitrace;
+  char * prefix;
+  Cbs * cbs;
+
+  LGL * clone;
+
+  FltStr * fltstr;
+#if !defined(NLGLPICOSAT)
+  struct { PicoSAT * solver; int res; char chk; } picosat;
+#endif
+#if !defined(NLGLDRUPLIG)
+  Druplig * druplig;
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
+
+static const char lglfloorldtab[256] =
+{
+// 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+  -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+  LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
+  LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
+};
+
+static const uint64_t lglbasevar2funtab[6] = {
+  0xaaaaaaaaaaaaaaaaull, 0xccccccccccccccccull, 0xf0f0f0f0f0f0f0f0ull,
+  0xff00ff00ff00ff00ull, 0xffff0000ffff0000ull, 0xffffffff00000000ull,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int lglfloorld (int n) {
+  assert (n >= 0);
+  if (n < (1<<8)) return lglfloorldtab[n];
+  if (n < (1<<16)) return 8 + lglfloorldtab[n>>8];
+  if (n < (1<<24)) return 16 + lglfloorldtab[n>>16];
+  return 24 + lglfloorldtab[n>>24];
+}
+
+static int lglispow2 (int n) {
+  assert (0 <= n && n <= INT_MAX);
+  return !(n & (n - 1));
+}
+
+static int lglceilld (int n) {
+  int res = lglfloorld (n);
+  if (!lglispow2 (n)) res++;
+  return res;
+}
+
+static int lglceilsqrt32 (int x) {
+  int l = 0, m, r, mm, rr;
+#ifndef NDEBUG
+  int ll = 0;
+#endif
+  if (x <= 0) return 0;
+  r = 46340; rr = r*r;
+  if (x >= rr) return r;
+  for (;;) {
+    assert (l < r);
+    assert (ll < x && x < rr);
+    if (r - l == 1) return r;
+    m = (l + r)/2;
+    mm = m*m;
+    if (mm == x) return m;
+    if (mm < x) {
+      l = m;
+#ifndef NDEBUG
+      ll = mm;
+#endif
+    } else r = m, rr = mm;
+  }
+}
+
+static int lglceilsqrt64 (int x) {
+  int64_t l = 0, m, r, mm, rr;
+#ifndef NDEBUG
+  int64_t ll = 0;
+#endif
+  if (x <= 0) return 0;
+  r = 3037000499ll; rr = r*r;
+  if (x >= rr) return r;
+  for (;;) {
+    assert (l < r);
+    assert (ll < x && x < rr);
+    if (r - l == 1) return r;
+    m = (l + r)/2;
+    mm = m*m;
+    if (mm == x) return m;
+    if (mm < x) {
+      l = m;
+#ifndef NDEBUG
+      ll = mm;
+#endif
+    } else r = m, rr = mm;
+  }
+}
+
+static void lglchkflt (Flt a) {
+#ifndef NDEBUG
+  assert (a >= 0);
+  assert (FLTMAX >= (uint64_t) a);
+#else
+  (void) a;
+#endif
+}
+
+static Exp lglexp (Flt a) {
+  Exp res = a >> FLTPRC;
+  assert (0 <= res && res <= EXPMAX);
+  res -= EXPZRO;
+  return res;
+}
+
+static Mnt lglmnt (Flt a) {
+  Mnt res = a & MNTMAX;
+  res |= MNTBIT;
+  assert (res <= MNTMAX);
+  return res;
+}
+
+static Flt lglflt (Exp e, Mnt m) {
+  Flt res;
+  if (!m) return FLTMIN;
+  if (m < MNTBIT) {
+    while (!(m & MNTBIT)) {
+      m <<= 1;
+      if (e > INT_MIN) e--;
+      else break;
+    }
+  } else {
+    while (m > MNTMAX) {
+       m >>= 1;
+       if (e > INT_MIN) e++;
+       else break;
+    }
+  }
+  if (e < -EXPZRO) return FLTMIN;
+  if (e > EXPMAX - EXPZRO) return FLTMAX;
+  e += EXPZRO;
+  assert (0 <= e && e <= EXPMAX);
+  assert (m <= MNTMAX);
+  assert (m & MNTBIT);
+  res = m & ~MNTBIT;
+  res |= ((Flt)e) << FLTPRC;
+  return res;
+}
+
+#ifdef NDBLSCR
+static Flt lglrat (unsigned n, unsigned d) {
+  Mnt m;
+  Exp e;
+  if (!n) return FLTMIN;
+  if (!d) return FLTMAX;
+  m = n;
+  e = 0;
+  while (!(m & (1ull << 63))) m <<= 1, e--;
+  m /= d;
+  return lglflt (e, m);
+}
+#endif
+
+#ifndef NDEBUG
+double lglflt2dbl (Flt a) {
+  return lglmnt (a) * pow (2.0, lglexp (a));
+}
+#endif
+
+#ifdef NDBLSCR
+static const char * lgll2str (LGL * lgl, Flt a) {
+  assert (lgl->fltstr);
+  lgl->fltstr->current++;
+  if (lgl->fltstr->current == MAXFLTSTR) lgl->fltstr->current = 0;
+  sprintf (lgl->fltstr->str[lgl->fltstr->current], "%lld", (LGLL) a);
+  return lgl->fltstr->str[lgl->fltstr->current];
+}
+#endif
+
+static const char * lglflt2str (LGL * lgl, Flt a) {
+  double d, e;
+  assert (lgl->fltstr);
+  if (a == FLTMIN) return "0";
+  if (a == FLTMAX) return "inf";
+  d = lglmnt (a);
+  d /= 4294967296ll;
+  e = lglexp (a);
+  e += 32;
+  lgl->fltstr->current++;
+  if (lgl->fltstr->current == MAXFLTSTR) lgl->fltstr->current = 0;
+  sprintf (lgl->fltstr->str[lgl->fltstr->current], "%.6fd%+03.0f", d, e);
+  return lgl->fltstr->str[lgl->fltstr->current];
+}
+
+static Flt lgladdflt (Flt a, Flt b) {
+  Exp e, f, g;
+  Mnt m, n, o;
+  lglchkflt (a);
+  lglchkflt (b);
+  if (a == FLTMAX) return FLTMAX;
+  if (b == FLTMAX) return FLTMAX;
+  if (a == FLTMIN) return b;
+  if (b == FLTMIN) return a;
+  e = lglexp (a);
+  f = lglexp (b);
+  if (e < f) g = e, e = f, f = g, o = a, a = b, b = o;
+  m = lglmnt (a);
+  n = lglmnt (b);
+  m += n >> (e - f);
+  return lglflt (e, m);
+}
+
+static Flt lglmulflt (Flt a, Flt b) {
+  Exp e, ea, eb;
+  Mnt m, ma, mb;
+  lglchkflt (a);
+  lglchkflt (b);
+  if (a == FLTMAX) return FLTMAX;
+  if (b == FLTMAX) return FLTMAX;
+  if (a == FLTMIN) return FLTMIN;
+  if (b == FLTMIN) return FLTMIN;
+  ea = lglexp (a); eb = lglexp (b);
+  if (ea > 0 && eb > 0 && (INT_MAX - ea < eb)) return FLTMAX;
+  e = ea + eb;
+  if (e > EXPMAX - EXPZRO - 32) return FLTMAX;
+  e += 32;
+  ma = lglmnt (a); mb = lglmnt (b);
+  ma >>= 1; mb >>= 1;
+  m = ma * mb;
+  assert (3ull << 62);
+  m >>= 30;
+  return lglflt (e, m);
+}
+
+#ifdef NDBLSCR
+static Flt lglshflt (Flt a, int s) {
+  Exp e;
+  Mnt m;
+  if (a == FLTMAX) return FLTMAX;
+  if (a == FLTMIN) return FLTMIN;
+  assert (0 <= s);
+  e = lglexp (a);
+  if (e < INT_MIN + s) return FLTMIN;
+  e -= s;
+  m = lglmnt (a);
+  return lglflt (e, m);
+}
+#endif
+
+/*------------------------------------------------------------------------*/
+#ifdef NDBLSCR
+
+static const char * lglscr2str (LGL * lgl, Scr scr) {
+  if (lgl->opts->score.val == LGL_SCORE_EVSIDS ||
+      lgl->opts->score.val == LGL_SCORE_AVG) return lglflt2str (lgl, scr);
+  else return lgll2str (lgl, scr);
+}
+
+static Scr lgladdscr (Scr a, Scr b) { return lgladdflt (a, b); }
+static Scr lglmulscr (Scr a, Scr b) { return lglmulflt (a, b); }
+
+#else /* !NDBLSCR */
+
+static const char * lgldbl2str (LGL * lgl, double d) {
+  assert (lgl->fltstr);
+  lgl->fltstr->current++;
+  if (lgl->fltstr->current == MAXFLTSTR) lgl->fltstr->current = 0;
+  sprintf (lgl->fltstr->str[lgl->fltstr->current], "%g", d);
+  return lgl->fltstr->str[lgl->fltstr->current];
+}
+
+static const char * lglscr2str (LGL * lgl, Scr scr) {
+  return lgldbl2str (lgl, scr);
+}
+
+static Scr lgladdscr (Scr a, Scr b) { return a + b; }
+static Scr lglmulscr (Scr a, Scr b) { return a * b; }
+
+#endif
+/*------------------------------------------------------------------------*/
+
+static void lglwrn (LGL * lgl, const char * msg, ...) {
+  va_list ap;
+  fprintf (lgl->out, "*** warning in '%s': ", __FILE__);
+  va_start (ap, msg);
+  vfprintf (lgl->out, msg, ap);
+  va_end (ap);
+  fputc ('\n', lgl->out);
+  fflush (lgl->out);
+}
+
+static void lgldie (LGL * lgl, const char * msg, ...) {
+  va_list ap;
+  fprintf (lgl->out, "*** internal error in '%s': ", __FILE__);
+  va_start (ap, msg);
+  vfprintf (lgl->out, msg, ap);
+  va_end (ap);
+  fputc ('\n', lgl->out);
+  fflush (lgl->out);
+  exit (0);
+}
+
+static void lglabort (LGL * lgl) {
+  if (!lgl) exit (1);
+  if (lgl->opts && lgl->opts->sleeponabort.val) {
+    fprintf (stderr,
+"liblgl.a: Process %d will sleep for %d seconds "
+" before continuing with 'lglabort' procedure.\n",
+      getpid (), lgl->opts->sleeponabort.val);
+    sleep (lgl->opts->sleeponabort.val);
+  }
+  if (lgl->cbs && lgl->cbs->onabort)
+    lgl->cbs->onabort (lgl->cbs->abortstate);
+  if (lgl->opts && lgl->opts->exitonabort.val) exit (1);
+  abort ();
+}
+
+static const char * lglprefix (LGL * lgl) {
+  return lgl && lgl->prefix ? lgl->prefix : "c (LGL HAS NO PREFIX YET) ";
+}
+
+static int lglmsgstart (LGL * lgl, int level) {
+#ifndef NLGLOG
+  if (lgl->opts->log.val <= 0)
+#endif
+  if (lgl->opts->verbose.val < level) return 0;
+  if (lgl->cbs && lgl->cbs->msglock.lock)
+    lgl->cbs->msglock.lock (lgl->cbs->msglock.state);
+  fputs (lglprefix (lgl), lgl->out);
+  if (lgl->tid >= 0) fprintf (lgl->out, "%d ", lgl->tid);
+  return 1;
+}
+
+static void lglmsgend (LGL * lgl) {
+  fputc ('\n', lgl->out);
+  fflush (lgl->out);
+  if (lgl->cbs && lgl->cbs->msglock.unlock)
+    lgl->cbs->msglock.unlock (lgl->cbs->msglock.state);
+}
+
+static void lglprt (LGL * lgl, int level, const char * msg, ...) {
+  va_list ap;
+#ifndef NLGLOG
+  if (lgl->opts->log.val <= 0)
+#endif
+  if (lgl->opts->verbose.val < level) return;
+  lglmsgstart (lgl, level);
+  va_start (ap, msg);
+  vfprintf (lgl->out, msg, ap);
+  va_end (ap);
+  lglmsgend (lgl);
+}
+
+#ifndef NLGLOG
+static void lglogstart (LGL * lgl, int level, const char * msg, ...) {
+  va_list ap;
+  assert (lgl->opts->log.val >= level);
+  if (lgl->cbs && lgl->cbs->msglock.lock)
+    lgl->cbs->msglock.lock (lgl->cbs->msglock.state);
+  fputs (lglprefix (lgl), lgl->out);
+  if (lgl->tid >= 0) fprintf (lgl->out, "%d ", lgl->tid);
+  fprintf (lgl->out, "LOG%d %d ", level, lgl->level);
+  va_start (ap, msg);
+  vfprintf (lgl->out, msg, ap);
+  va_end (ap);
+}
+
+#define lglogend lglmsgend
+#endif
+
+/*------------------------------------------------------------------------*/
+
+void lglsetid (LGL * lgl, int tid, int tids) {
+  REQINITNOTFORKED ();
+  ABORTIF (tid < 0, "negative id");
+  ABORTIF (tid >= tids, "id exceed number of ids");
+  lgl->tid = tid;
+  lgl->tids = tids;
+}
+
+/*------------------------------------------------------------------------*/
+
+static void lglinc (LGL * lgl, size_t bytes) {
+  lgl->stats->bytes.current += bytes;
+  if (lgl->stats->bytes.max < lgl->stats->bytes.current) {
+    lgl->stats->bytes.max = lgl->stats->bytes.current;
+    LOG (5, "maximum allocated %ld bytes", lgl->stats->bytes.max);
+  }
+}
+
+static void lgldec (LGL * lgl, size_t bytes) {
+  assert (lgl->stats->bytes.current >= bytes);
+  lgl->stats->bytes.current -= bytes;
+}
+
+static void * lglnew (LGL * lgl, size_t bytes) {
+  void * res;
+  if (!bytes) return 0;
+  if (lgl->mem->alloc) res = lgl->mem->alloc (lgl->mem->state, bytes);
+  else res = malloc (bytes);
+  if (!res) lgldie (lgl, "out of memory allocating %ld bytes", bytes);
+  assert (res);
+  LOG (5, "allocating %p with %ld bytes", res, bytes);
+  lglinc (lgl, bytes);
+  if (res) memset (res, 0, bytes);
+  return res;
+}
+
+static void lgldel (LGL * lgl, void * ptr, size_t bytes) {
+  if (!ptr) { assert (!bytes); return; }
+  lgldec (lgl, bytes);
+  LOG (5, "freeing %p with %ld bytes", ptr, bytes);
+  if (lgl->mem->dealloc) lgl->mem->dealloc (lgl->mem->state, ptr, bytes);
+  else free (ptr);
+}
+
+static void * lglrsz (LGL * lgl, void * ptr, size_t old, size_t new) {
+  void * res;
+  assert (!ptr == !old);
+  if (!ptr) return lglnew (lgl, new);
+  if (!new) { lgldel (lgl, ptr, old); return 0; }
+  if (old == new) return ptr;
+  lgldec (lgl, old);
+  if (lgl->mem->realloc)
+    res = lgl->mem->realloc (lgl->mem->state, ptr, old, new);
+  else res = realloc (ptr, new);
+  if (!res)
+    lgldie (lgl, "out of memory reallocating %ld to %ld bytes", old, new);
+  assert (res);
+  LOG (5, "reallocating %p to %p from %ld to %ld bytes", ptr, res, old, new);
+  lglinc (lgl, new);
+  if (new > old) memset (res + old, 0, new - old);
+  return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+static char * lglstrdup (LGL * lgl, const char * str) {
+  char * res;
+  NEW (res, strlen (str) + 1);
+  return strcpy (res, str);
+}
+
+static void lgldelstr (LGL * lgl, char * str) {
+  DEL (str, strlen (str) + 1);
+}
+
+/*------------------------------------------------------------------------*/
+
+static void lglinitcbs (LGL * lgl) {
+  if (!lgl->cbs) NEW (lgl->cbs, 1);
+}
+
+void lglonabort (LGL * lgl, void * abortstate, void (*onabort)(void*)) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->abortstate = abortstate;
+  lgl->cbs->onabort = onabort;
+}
+
+void lglseterm (LGL * lgl, int (*fun)(void*), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->term.fun = fun;
+  lgl->cbs->term.state = state;
+}
+
+void lglsetproduceunit (LGL * lgl, void (*fun) (void*, int), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->units.produce.fun = fun;
+  lgl->cbs->units.produce.state = state;
+}
+
+void lglsetconsumeunits (LGL * lgl,
+                        void (*fun) (void*, int **, int **),
+                        void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->units.consume.fun =  fun;
+  lgl->cbs->units.consume.state = state;
+}
+
+void lglsetconsumedunits (LGL * lgl,
+                         void (*fun) (void*, int), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->units.consumed.fun = fun;
+  lgl->cbs->units.consumed.state = state;
+}
+
+void lglsetproducecls (LGL * lgl, 
+                       void (*fun) (void*, int *, int), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->cls.produce.fun = fun;
+  lgl->cbs->cls.produce.state = state;
+}
+
+void lglsetconsumecls (LGL * lgl,
+                      void (*fun) (void*, int **, int *),
+                      void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->cls.consume.fun =  fun;
+  lgl->cbs->cls.consume.state = state;
+}
+
+void lglsetconsumedcls (LGL * lgl,
+                       void (*fun) (void*, int), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->cls.consumed.fun = fun;
+  lgl->cbs->cls.consumed.state = state;
+}
+
+void lglsetlockeq (LGL * lgl, int * (*fun)(void*), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->eqs.lock.fun = fun;
+  lgl->cbs->eqs.lock.state = state;
+}
+
+void lglsetunlockeq (LGL * lgl, void (*fun)(void*,int,int), void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->eqs.unlock.fun = fun;
+  lgl->cbs->eqs.unlock.state = state;
+}
+
+void lglsetmsglock (LGL * lgl,
+                   void (*lock)(void*), void (*unlock)(void*),
+                   void * state) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->msglock.lock = lock;
+  lgl->cbs->msglock.unlock = unlock;
+  lgl->cbs->msglock.state = state;
+}
+
+void lglsetime (LGL * lgl, double (*time)(void)) {
+  REQINITNOTFORKED ();
+  lglinitcbs (lgl);
+  lgl->cbs->getime = time;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglfullstk (Stk * s) { return s->top == s->end; }
+static int lglmtstk (Stk * s) { return s->top == s->start; }
+static size_t lglcntstk (Stk * s) { return s->top - s->start; }
+static size_t lglszstk (Stk * s) { return s->end - s->start; }
+
+static int lglpeek (Stk * s, int pos) {
+  assert (0 <= pos && pos < lglszstk (s));
+  return s->start[pos];
+}
+
+static void lglpoke (Stk * s, int pos, int val) {
+  assert (0 <= pos && pos <= lglszstk (s));
+  s->start[pos] = val;
+}
+
+static void lglenlstk (LGL * lgl, Stk * s) {
+  size_t old_size = lglszstk (s);
+  size_t new_size = old_size ? 2 * old_size : 1;
+  size_t count = lglcntstk (s);
+  RSZ (s->start, old_size, new_size);
+  s->top = s->start + count;
+  s->end = s->start + new_size;
+}
+
+static void lglrelstk (LGL * lgl, Stk * s) {
+  DEL (s->start, lglszstk (s));
+  CLRPTR (s);
+}
+
+static void lglshrstk (LGL * lgl, Stk * s, int new_size) {
+  size_t old_size, count = lglcntstk (s);
+  assert (new_size >= 0);
+  assert (count <= new_size);
+  if (new_size > 0) {
+    old_size = lglszstk (s);
+    RSZ (s->start, old_size, new_size);
+    s->top = s->start + count;
+    s->end = s->start + new_size;
+  } else lglrelstk (lgl, s);
+}
+
+static void lglfitstk (LGL * lgl, Stk * s) {
+  lglshrstk (lgl, s, lglcntstk (s));
+}
+
+static void lglpushstk (LGL * lgl, Stk * s, int elem) {
+  if (lglfullstk (s)) lglenlstk (lgl, s);
+  *s->top++ = elem;
+}
+
+static void lglrmstk (Stk * s, int elem) {
+  int * p, * q;
+  for (p = s->start; p < s->top; p++)
+    if (*p == elem) break;
+  assert (p < s->top);
+  q = p++;
+  while (p < s->top)
+    *q++ = *p++;
+  s->top = q;
+}
+
+static int lglpopstk (Stk * s) { assert (!lglmtstk (s)); return *--s->top; }
+
+static int lgltopstk (Stk * s) { assert (!lglmtstk (s)); return s->top[-1]; }
+
+static void lglrststk (Stk * s, int newsz) {
+  assert (0 <= newsz && newsz <= lglcntstk (s));
+  s->top = s->start + newsz;
+}
+
+static void lglclnstk (Stk * s) { lglrststk (s, 0); }
+
+/*------------------------------------------------------------------------*/
+
+static void lgltrapi (LGL * lgl, const char * msg, ...) {
+  va_list ap;
+  assert (lgl->apitrace);
+  va_start (ap, msg);
+  vfprintf (lgl->apitrace, msg, ap);
+  va_end (ap);
+  fputc ('\n', lgl->apitrace);
+}
+
+static void lglopenapitrace (LGL * lgl, const char * name) {
+  FILE * file;
+  char * cmd;
+  int len;
+  len = strlen (name);
+  if (len >= 3 && !strcmp (name + len - 3, ".gz")) {
+    len += 20;
+    NEW (cmd, len);
+    sprintf (cmd, "gzip -c > %s", name);
+    file = popen (cmd, "w");
+    DEL (cmd, len);
+    if (file) lgl->closeapitrace = 2;
+  } else {
+    file = fopen (name, "w");
+    if (file) lgl->closeapitrace = 1;
+  }
+  if (file) lgl->apitrace = file;
+  else lglwrn (lgl, "can not write API trace to '%s'", name);
+  TRAPI ("init");
+}
+
+void lglwtrapi (LGL * lgl, FILE * apitrace) {
+  REQUIRE (UNUSED);
+  ABORTIF (lgl->apitrace, "can only write one API trace");
+  lgl->apitrace = apitrace;
+  TRAPI ("init");
+}
+
+/*------------------------------------------------------------------------*/
+#if !defined(NLGLPICOSAT) && !defined(NDEBUG)
+
+static void lglpicosatinit (LGL * lgl) {
+  if (lgl->picosat.solver) return;
+  lgl->picosat.solver = picosat_init ();
+  picosat_set_prefix (lgl->picosat.solver, "c PST ");
+  lgl->picosat.chk = 1;
+  picosat_add (lgl->picosat.solver, 1);
+  picosat_add (lgl->picosat.solver, 0);
+  LOG (1, "PicoSAT initialized");
+}
+
+#endif
+/*------------------------------------------------------------------------*/
+
+static unsigned lglrand (LGL * lgl) {
+  unsigned res;
+  lgl->rng.z = 36969 * (lgl->rng.z & 65535) + (lgl->rng.z >> 16);
+  lgl->rng.w = 18000 * (lgl->rng.w & 65535) + (lgl->rng.w >> 16);
+  res = (lgl->rng.z << 16) + lgl->rng.w;
+  LOG (5, "rng %u", res);
+  return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglmtftk (Ftk * ftk) { return ftk->top == ftk->start; }
+
+static int lglfullftk (Ftk * ftk) { return ftk->top == ftk->end; }
+
+static int lglsizeftk (Ftk * ftk) { return ftk->end - ftk->start; }
+
+static int lglcntftk (Ftk * ftk) { return ftk->top - ftk->start; }
+
+static void lglrelftk (LGL * lgl, Ftk * ftk) {
+  DEL (ftk->start, lglsizeftk (ftk));
+  memset (ftk, 0, sizeof *ftk);
+}
+
+static void lglenlftk (LGL * lgl, Ftk * ftk) {
+  int oldsize = lglsizeftk (ftk);
+  int newsize = oldsize ? 2*oldsize : 1;
+  int count = lglcntftk (ftk);
+  RSZ (ftk->start, oldsize, newsize);
+  ftk->top = ftk->start + count;
+  ftk->end = ftk->start + newsize;
+}
+
+static void lglpushftk (LGL * lgl, Ftk * ftk, Flt f) {
+  if (lglfullftk (ftk)) lglenlftk (lgl, ftk);
+  *ftk->top++ = f;
+}
+
+static Flt lgltopftk (Ftk * ftk) {
+  assert (!lglmtftk (ftk));
+  return ftk->top[-1];
+}
+
+static Flt lglpopftk (Ftk * ftk) {
+  assert (!lglmtftk (ftk));
+  return *--ftk->top;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglfullctk (Ctk * ctk) { return ctk->top == ctk->end; }
+
+static int lglsizectk (Ctk * ctk) { return ctk->end - ctk->start; }
+
+static int lglcntctk (Ctk * ctk) { return ctk->top - ctk->start; }
+
+static void lglrelctk (LGL * lgl, Ctk * ctk) {
+  DEL (ctk->start, lglsizectk (ctk));
+  memset (ctk, 0, sizeof *ctk);
+}
+
+static void lglenlctk (LGL * lgl, Ctk * ctk) {
+  int oldsize = lglsizectk (ctk);
+  int newsize = oldsize ? 2*oldsize : 1;
+  int count = lglcntctk (ctk);
+  RSZ (ctk->start, oldsize, newsize);
+  ctk->top = ctk->start + count;
+  ctk->end = ctk->start + newsize;
+}
+
+static void lglpushcontrol (LGL * lgl, int decision) {
+  Ctk * ctk = &lgl->control;
+  Ctr * ctr;
+  if (lglfullctk (ctk)) lglenlctk (lgl, ctk);
+  ctr = ctk->top++;
+  ctr->decision = decision;
+  ctr->used = 0;
+}
+
+static void lglpopcontrol (LGL * lgl) {
+  assert (lgl->control.top > lgl->control.start);
+  --lgl->control.top;
+}
+
+static void lglrstcontrol (LGL * lgl, int count) {
+  while (lglcntctk (&lgl->control) > count)
+    lglpopcontrol (lgl);
+}
+
+static int lglevelused (LGL * lgl, int level) {
+  Ctk * ctk = &lgl->control;
+  Ctr * ctr;
+  assert (0 < level && level < lglsizectk (ctk));
+  ctr = ctk->start + level;
+  return ctr->used;
+}
+
+static void lgluselevel (LGL * lgl, int level) {
+  Ctk * ctk = &lgl->control;
+  Ctr * ctr;
+  assert (0 < level && level < lglsizectk (ctk));
+  ctr = ctk->start + level;
+  ctr->used = 1;
+}
+
+static void lglunuselevel (LGL * lgl, int level) {
+  Ctk * ctk = &lgl->control;
+  Ctr * ctr;
+  assert (0 < level);
+  assert (level < lglcntctk (ctk));  
+  assert (0 < level);
+  ctr = ctk->start + level;
+  assert (ctr->used);
+  ctr->used = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+static void lglgetenv (LGL * lgl, Opt * opt, const char * lname) {
+  const char * q, * valstr;
+  char uname[40], * p;
+  int newval, oldval;
+  assert (strlen (lname) + 3 + 1 < sizeof (uname));
+  uname[0] = 'L'; uname[1] = 'G'; uname[2] = 'L';
+  p = uname + 3;
+  for (q = lname; *q; q++) {
+    assert (p < uname + sizeof uname);
+    *p++ = toupper (*q);
+  }
+  assert (p < uname + sizeof uname);
+  *p = 0;
+  valstr = getenv (uname);
+  if (!valstr) return;
+  oldval = opt->val;
+  newval = atoi (valstr);
+  if (newval < opt->min) newval = opt->min;
+  if (newval > opt->max) newval = opt->max;
+  if (newval == oldval) return;
+  opt->val = newval;
+  TRAPI ("option %s %d", lname, newval);
+  COVER (lgl->clone);
+  if (lgl->clone) lglsetopt (lgl->clone, lname, newval);
+}
+
+static void lglchkenv (LGL * lgl) {
+  extern char ** environ;
+  char * src, *eos, * dst;
+  char ** p, * s, * d;
+  int len;
+  for (p = environ; (src = *p); p++) {
+    if (src[0] != 'L' || src[1] != 'G' || src[2] != 'L') continue;
+    for (eos = src; *eos && *eos != '='; eos++)
+      ;
+    len = eos - (src + 3);
+    NEW (dst, len + 1);
+    d = dst;
+    for (s = src + 3; s < eos; s++) *d++ = tolower (*s);
+    *d = 0;
+    if (!lglhasopt (lgl, dst) && strcmp (dst, "apitrace"))
+      lglwrn (lgl, "invalid 'LGL...' environment '%s'", src);
+    DEL (dst, len + 1);
+  }
+}
+
+#define SETPLAIN(NAME) \
+do { \
+  if (val) lgl->opts->NAME.val = 0; \
+  else lgl->opts->NAME.val = lgl->opts->NAME.dflt; \
+} while (0)
+
+#define SETDRUP SETPLAIN
+
+static void lglsetdrup (LGL * lgl, int val) {
+  SETDRUP (bca);
+  SETDRUP (card);
+  SETDRUP (decompose);
+  SETDRUP (probe);
+  SETDRUP (lift);
+  SETDRUP (cgrclsr);
+  SETDRUP (gauss);
+  SETDRUP (mega);
+  SETDRUP (rdp);
+  SETDRUP (smallve);
+  lglprt (lgl, 1, "[drup] drup solving switched %s", val ? "on" : "off");
+}
+
+#define SETDRUPLIG SETPLAIN
+
+static void lglsetdruplig (LGL * lgl, int val) {
+  SETDRUPLIG (bca);
+  SETDRUPLIG (card);
+  SETDRUPLIG (decompose);
+  SETDRUPLIG (probe);
+  SETDRUPLIG (lift);
+  SETDRUPLIG (cgrclsr);
+  SETDRUPLIG (gauss);
+  SETDRUPLIG (mega);
+  SETDRUPLIG (rdp);
+  SETDRUPLIG (smallve);
+  lglprt (lgl, 1,
+    "[druplig] druplig checking switched %s",
+    val ? "on" : "off");
+}
+
+static void lglsetplain (LGL * lgl, int val) {
+  SETPLAIN (bca);
+  SETPLAIN (bva);
+  SETPLAIN (block);
+  SETPLAIN (card);
+  SETPLAIN (cce);
+  SETPLAIN (cgrclsr);
+  SETPLAIN (cliff);
+  SETPLAIN (decompose);
+  SETPLAIN (elim);
+  SETPLAIN (gauss);
+  SETPLAIN (lift);
+  SETPLAIN (locs);
+  SETPLAIN (mega);
+  SETPLAIN (probe);
+  SETPLAIN (rdp);
+  SETPLAIN (ternres);
+  SETPLAIN (transred);
+  SETPLAIN (unhide);
+  lglprt (lgl, 1, "[plain] plain solving switched %s", val ? "on" : "off");
+}
+
+#define SETWAIT(NAME) \
+do { \
+  if (val) lgl->opts->NAME.val = lgl->opts->NAME.dflt; \
+  else lgl->opts->NAME.val = 0; \
+} while (0)
+
+static void lglsetwait (LGL * lgl, int val) {
+  SETWAIT (batewait);
+  SETWAIT (bcawait);
+  SETWAIT (blockwait);
+  SETWAIT (ccewait);
+  SETWAIT (cgrclsrwait);
+  SETWAIT (cliffwait);
+  SETWAIT (elmblkwait);
+  SETWAIT (gausswait);
+  SETWAIT (liftwait);
+  SETWAIT (smallvewait);
+  SETWAIT (ternreswait);
+  SETWAIT (transredwait);
+  SETWAIT (unhidewait);
+  lglprt (lgl, 1, "[wait] waiting %s", val ? "enabled" : "disabled");
+}
+
+static LGL * lglnewlgl (void * mem,
+                       lglalloc alloc,
+                       lglrealloc realloc,
+                       lgldealloc dealloc) {
+  LGL * lgl = alloc ? alloc (mem, sizeof *lgl) : malloc (sizeof *lgl);
+  ABORTIF (!lgl, "out of memory allocating main solver object");
+  CLRPTR (lgl);
+
+  lgl->mem = alloc ? alloc (mem, sizeof *lgl->mem) : malloc (sizeof *lgl->mem);
+  ABORTIF (!lgl->mem, "out of memory allocating memory manager object");
+
+  lgl->mem->state = mem;
+  lgl->mem->alloc = alloc;
+  lgl->mem->realloc = realloc;
+  lgl->mem->dealloc = dealloc;
+
+  lgl->opts = alloc ? alloc (mem, sizeof (Opts)) : malloc (sizeof (Opts));
+  ABORTIF (!lgl->opts, "out of memory allocating option manager object");
+  CLRPTR (lgl->opts);
+
+  lgl->stats = alloc ? alloc (mem, sizeof (Stats)) : malloc (sizeof (Stats));
+  ABORTIF (!lgl->stats, "out of memory allocating statistic counters");
+  CLRPTR (lgl->stats);
+
+  lglinc (lgl, sizeof *lgl);
+  lglinc (lgl, sizeof *lgl->mem);
+  lglinc (lgl, sizeof *lgl->opts);
+  lglinc (lgl, sizeof *lgl->stats);
+
+  return lgl;
+}
+
+static void lglinitscores (LGL * lgl) {
+  Scr oldscincf, oldmaxscore = lgl->maxscore;
+  if (lgl->opts->score.val != LGL_SCORE_EVSIDS) {
+    lgl->maxscore = (1ll << 60);
+    if (oldmaxscore != lgl->maxscore)
+      lglprt (lgl, 1,
+       "[init-scores] fixed maxium score %s",
+       lglscr2str (lgl, lgl->maxscore));
+  } else {
+    oldscincf = lgl->scincf;
+#ifdef NDBLSCR
+    lgl->scincf = lglrat (1000 + lgl->opts->scincinc.val, 1000);
+    lgl->maxscore = lglflt (lgl->opts->maxscorexp.val, 1);
+#else
+    lgl->scincf = (1000.0 + lgl->opts->scincinc.val) / 1000.0;
+    lgl->maxscore = scalbln (1.0, lgl->opts->maxscorexp.val);
+#endif
+    if (oldscincf != lgl->scincf)
+      lglprt (lgl, 1,
+       "[init-scores] score increment factor %s (--scincinc=%d)",
+       lglscr2str (lgl, lgl->scincf), lgl->opts->scincinc.val);
+
+    if (oldmaxscore != lgl->maxscore)
+      lglprt (lgl, 1,
+       "[init-scores] maxium score limit %s (--maxscorexp=%d)",
+       lglscr2str (lgl, lgl->maxscore), lgl->opts->maxscorexp.val);
+  }
+}
+
+LGL * lglminit (void * mem,
+               lglalloc alloc,
+               lglrealloc realloc,
+               lgldealloc dealloc) {
+  const int K = 1000, M = K*K, I = INT_MAX;
+  const int MG = MAXGLUE, MG0 = MG*10;
+  const char * apitracename;
+  LGL * lgl;
+  int i;
+
+  lgl = 0;
+  ABORTIF (!alloc+!realloc+!dealloc != 0 && !alloc+!realloc+!dealloc != 3,
+          "inconsistent set of external memory handlers");
+
+  assert (sizeof (long) == sizeof (void*));
+
+  assert (REMOVED > ((MAXVAR << RMSHFT) | MASKCS | REDCS));
+  assert (REMOVED > MAXREDLIDX);
+  assert (REMOVED > MAXIRRLIDX);
+
+  assert (MAXREDLIDX == MAXIRRLIDX);
+  assert (GLUESHFT == RMSHFT);
+
+  assert (INT_MAX > ((MAXREDLIDX << GLUESHFT) | GLUEMASK));
+  assert (INT_MAX > ((MAXIRRLIDX << RMSHFT) | MASKCS | REDCS));
+
+  assert (MAXGLUE < POW2GLUE);
+
+  lgl = lglnewlgl (mem, alloc, realloc, dealloc);
+  lgl->tid = -1;
+
+  lglpushcontrol (lgl, 0);
+  assert (lglcntctk (&lgl->control) == lgl->level + 1);
+
+  lgl->out = stdout;
+  lgl->prefix = lglstrdup (lgl, "c ");
+
+  apitracename = getenv ("LGLAPITRACE");
+  if (apitracename) lglopenapitrace (lgl, apitracename);
+
+  OPT(0,abstime,0,0,1,"print absolute time when reporting");
+  OPT(0,actavgmax,3*MG0/4,0,MG0,"glue average max limit for dyn acts");
+  OPT(0,actdblarithlim,3,0,MG,"glue lim for dbl arith increase");
+  OPT(0,actgeomlim,2,0,MG,"glue limit for geometric increase");
+  OPT(0,actgsdul,7,0,MG0,"glue useless standard deviation limit");
+  OPT(0,acts,2,0,2,"activity based reduction: 0=no,1=enable,2=dyn");
+  OPT(0,actstdmax,3*MG0/4,0,MG0,"glue std dev max limit for dyn acts");
+  OPT(0,actstdmin,10,0,MG0,"glue std dev min limit for dyn acts");
+  OPT(0,actvlim,200*K,0,I,"activity based reduction variable limit");
+  OPT(0,agile,1,0,2,"agility based restart skipping, 1=std, 2=sinus");
+  OPT(0,agilelim,30,0,100,"agility limit for restarts");
+  OPT(0,agilesinint,100*K,1,I,"agility limit sinus interval");
+  OPT(0,bate,1,0,1,"basic ATE removal during probing");
+  OPT(0,batewait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,bca,1,0,2,"enable blocked clause addition (1=week,2=strong)");
+  OPT(0,bcamaxeff,10*M,0,I,"BCA maximum number of steps");
+  OPT(0,bcaminuse,100,0,I,"min number of literals required to be usable");
+  OPT(0,bcawait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,bva,0,0,1,"enable bounded variable addition (BVA)");
+  OPT(0,bias,2,-1,2,"decision order initial bias (0=no,2=cw)");
+  OPT(0,binlocsdel,10,0,1000,"delay local seach after learning binary clause");
+  OPT(0,binsimpdel,2,0,1000,"delay simp after learning binary clause");
+  OPT(0,bkwdscale,2,1,1000,"backward steps scaled vs elimination steps");
+  OPT(0,blkboost,10,1,10000,"initial BCE boost");
+  OPT(0,blkboostvlim,1000000,0,I,"init BCE boost variable limit");
+  OPT(0,blkclslim,1*M,3,I,"max blocked clause size");
+  OPT(0,blklarge,1,0,1,"BCE of large clauses");
+  OPT(0,blkmaxeff,800*M,-1,I,"max effort in BCE (-1=unlimited)");
+  OPT(0,blkmineff,50*M,0,I,"min effort in BCE");
+  OPT(0,blkocclim1,100*K,1,I,"one-sided max occ of BCE");
+  OPT(0,blkocclim,1*M,3,I,"max occ in BCE");
+  OPT(0,blkocclim2,10*K,2,I,"two-sided max occ of BCE");
+  OPT(0,blkreleff,100,0,K,"rel effort in BCE");
+  OPT(0,blkrtc,0,0,1,"run BCE until completion");
+  OPT(0,blksched2b2,0,0,1,"BCE schedule 2x2 first");
+  OPT(0,blkschedmin,0,0,1,"BCE schedule based on minimum of occurrences");
+  OPT(0,blkschedprod,0,0,1,"BCE schedule based on product too");
+  OPT(0,blkschedpure,1,0,1,"BCE schedule pure literals first");
+  OPT(0,blkschedsum,1,0,1,"BCE schedule based on sum of occurrences too");
+  OPT(0,blksmall,1,0,1,"BCE of small clauses");
+  OPT(0,blksuccesslim,10*K,0,I,"BCE success limit");
+  OPT(0,blksuccessrat,1000,1,I,"BCE success ratio");
+  OPT(0,block,1,0,1,"blocked clause elimination (BCE)");
+  OPT(0,blockwait,1,0,1,"wait for BVE");
+  OPT(0,boost,1,0,1,"enable boosting of preprocessors");
+  OPT(0,bumpbcplits,0,0,1,"bump unseen but propagated literals");
+  OPT(0,bumpclslits,0,0,1,"bump literals in minimized clause");
+  OPT(0,bumpseenaftermin,0,0,1,"bump seen after minimization");
+  OPT(0,bumpseenbeforemin,1,0,1,"bump seen before minimization");
+  OPT(0,bumpseenlits,1,0,1,"bump seen literals");
+  OPT(0,bumpseenminsize,3,0,I,"minimum 1st UIP clause for bumping seen");
+  OPT(0,card,1,0,1,"cardinality constraint reasoning");
+  OPT(0,cardcut,2,0,2,"1=gomoroy-cuts,2=strengthen");
+  OPT(0,cardexpam1,3,2,I,"min length of exported at-most-one constraint");
+  OPT(0,cardglue,0,-1,MAXGLUE,"use lrg red cls too (-1=irr,0=moved,...)");
+  OPT(0,cardignused,0,0,1,"ignored already used literals in extraction");
+  OPT(0,cardmaxeff,300*M,-1,I,"max effort for cardmineff reasoning");
+  OPT(0,cardmaxlen,1000,0,I,"maximal length of cardinality constraints");
+  OPT(0,cardmineff,2*M,0,I,"min effort for cardmineff reasoning");
+  OPT(0,cardminlen,3,0,I,"minimal length of (initial) card constraints");
+  OPT(0,cardocclim1,300,0,I,"one-sided cardinality constraints occ limit");
+  OPT(0,cardocclim2,15,0,I,"two-sided cardinality constraints occ limit");
+  OPT(0,cardreleff,5,0,10*K,"rel effort for cardinality reasoning");
+  OPT(0,cardreschedint,10,1,I,"reschedule variable for card reasoning");
+  OPT(0,carduse,2,0,3,"use clauses (1=oneside,2=bothsidetoo,3=anyside)");
+  OPT(0,cardwait,0,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,cce2wait,1,0,I,"wait for ATE to finish before doing ABCE");
+  OPT(0,cce,3,0,3,"covered clause elimination (1=ate,2=abce,3=acce)");
+  OPT(0,cceboost,10,1,1000,"initial CCE boost");
+  OPT(0,cceboostvlim,1000000,0,I,"initial CCE boost variable limit");
+  OPT(0,cce3wait,2,0,I,"wait for ABCE to finish before doing ACCE");
+  OPT(0,ccemaxeff,I,-1,I,"max effort in covered clause elimination");
+  OPT(0,ccemineff,30*M,0,I,"min effort in covered clause elimination");
+  OPT(0,cceonlyifstuck,0,0,1,"ABCE+ACCE only if elm+blk stuck");
+  OPT(0,ccereleff,20,0,K,"rel effort in covered clause elimination");
+  OPT(0,ccertc,0,0,1,"run CCE until completition");
+  OPT(0,ccesuccesslim,10*K,0,I,"CCE success limit");
+  OPT(0,ccesuccessrat,1000,1,I,"CCE success ratio");
+  OPT(0,ccewait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,cgrclsr,1,0,1,"gate extraction and congruence closure");
+  OPT(0,cgrclsrwait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,cgreleff,1,0,10*K,"rel effort in congruence closure");
+  OPT(0,cgrextand,1,0,1,"extract and gates");
+  OPT(0,cgrexteq,1,0,1,"extract equivalences");
+  OPT(0,cgrextite,1,0,1,"extract ite gates");
+  OPT(0,cgrextunits,1,0,1,"extract units");
+  OPT(0,cgrextxor,1,0,1,"extract xor gates");
+  OPT(0,cgrmaxeff,8*M,-1,I,"max effort in congruence closure");
+  OPT(0,cgrmaxority,20,2,30,"maximum xor arity to be extracted");
+  OPT(0,cgrmineff,200*K,0,I,"min effort in congruence closure");
+  OPT(0,cintinc,20*K,10,M,"inprocessing conflict interval increment");
+  OPT(0,cintincdiv,1,0,3,"cintinc reduce policy: 0=no,1=div1,2=div2,3=heur");
+  OPT(0,cintmaxhard,10*M,-1,I,"hard max conflict interval limit");
+  OPT(0,cintmaxsoft,1*M,-1,I,"soft max conflict interval limit");
+  OPT(0,cliff,1,0,1,"cliffing");
+  OPT(0,cliffmaxeff,100*M,-1,I,"max effort in cliffing");
+  OPT(0,cliffmineff,10*M,0,I,"min effort in cliffing");
+  OPT(0,cliffreleff,8,0,10*K,"rel effort in cliffing");
+  OPT(0,cliffwait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,clim,-1,-1,I,"conflict limit");
+  OPT(0,compact,0,0,2,"compactify after 'lglsat/lglsimp' (1=UNS,2=SAT)");
+  OPT(0,deco,1,0,2,"learn decision-only clauses too (2=all-decisions)");
+  OPT(0,decolim,30,0,I,"decision-only clauses glue limit");
+  OPT(0,decompose,1,0,1,"enable decompose");
+  OPT(0,defragfree,50,10,K,"defragmentation free watches limit");
+  OPT(0,defragint,10*M,100,I,"defragmentation pushed watches interval");
+  OPT(0,delmax,10,0,10,"maximum delay");
+  OPT(0,dlim,-1,-1,I,"decision limit");
+  OPT(0,drup,0,0,1,"print DRUP proof");
+#if 1
+  OPT(0,druplig,0,0,1,"check proof through Druplig internally");
+#else
+  OPT(0,druplig,1,1,1,"check proof through Druplig internally");
+#endif
+  OPT(0,elim,1,0,1,"bounded variable eliminiation (BVE)");
+  OPT(0,elmaxeff,800*M,-1,I,"max effort in BVE (-1=unlimited)");
+  OPT(0,elmblk,1,0,1,"enable BCE during BVE");
+  OPT(0,elmblkwait,1,0,1,"wait for BVE to be completed once");
+  OPT(0,elmboost,40,1,1000,"initial elimination boost");
+  OPT(0,elmclslim,1*M,3,I,"max antecendent size in elimination");
+  OPT(0,elmfull,0,0,1,"no elimination limits");
+  OPT(0,elmineff,20*M,0,I,"min effort in BVE");
+  OPT(0,elmlitslim,200,0,I,"one side literals limit for elimination");
+  OPT(0,elmocclim1,1000,1,I,"one-sided max occ of BVE");
+  OPT(0,elmocclim,1*M,3,I,"max occurrences in BVE");
+  OPT(0,elmocclim2,100,2,I,"two-sided max occ of BVE");
+  OPT(0,elmreleff,200,0,10*K,"rel effort in BVE");
+  OPT(0,elmroundlim,3,1,I,"variable elimination rounds limit");
+  OPT(0,elmrtc,0,0,1,"run BVE until completion");
+  OPT(0,elmsched2b2,0,0,1,"BVE schedule 2x2 first");
+  OPT(0,elmschediff,0,0,1,"BVE schedule based on diff of occurrences too");
+  OPT(0,elmschedmin,0,0,1,"BVE schedule based on minimum of occurrences");
+  OPT(0,elmschedprod,0,0,1,"BVE schedule based on product too");
+  OPT(0,elmschedpure,1,0,1,"BVE schedule pure literals first");
+  OPT(0,elmschedsum,1,0,1,"BVE schedule based on sum of occurrences too");
+  OPT(0,elmsuccesslim,1000,0,I,"BVE success limit");
+  OPT(0,elmsuccessrat,1000,1,I,"BVE success ratio");
+  OPT(0,exitonabort,0,0,1,"exit instead abort after internal error");
+  OPT(0,factmax,100000,1,I,"maximum factor");
+  OPT(0,factor,3,0,3,"{cls,occ}lim factors (0=const1,1=ld,2=lin,3=sqr)");
+  OPT(0,flipdur,10,1,I,"flipping duration in number of conflicts");
+  OPT(0,flipint,10,0,I,"flipping interval in number top level decision");
+  OPT(0,flipldmod,4,0,30,"flipping phase log2 of mod"); 
+  OPT(0,fliplevels,6,0,30,"flipping decision levels");
+  OPT(0,flipping,1,0,1,"enable point flipping");
+  OPT(0,fliptop,1,0,1,"flipping only at the top level");
+  OPT(0,flipvlim,100*K,0,I,"no flipping beyond this number vars");
+  OPT(0,force,0,0,I,"reorder variables with force algorithm");
+  OPT(0,gauss,1,0,1,"enable gaussian elimination");
+  OPT(0,gaussexptrn,1,0,1,"export trn cls from gaussian elimination");
+  OPT(0,gaussextrall,1,0,1,"extract all xors (with duplicates)");
+  OPT(0,gaussmaxeff,50*M,-1,I,"max effort in gaussian elimination");
+  OPT(0,gaussmaxor,20,2,64,"maximum xor size in gaussian elimination");
+  OPT(0,gaussmineff,2*M,0,I,"min effort in gaussian elimination");
+  OPT(0,gaussreleff,2,0,10*K,"rel effort in gaussian elimination");
+  OPT(0,gausswait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,gluekeep,3,0,I,"keep clauses with this original glue");
+  OPT(0,gluescale,4,1,4,"glue scaling: 1=linear,2=sqrt,3=ld,4=hybrid");
+  OPT(0,import,1,0,1,"import external indices and map them");
+  OPT(0,incredcint,1,1,I,"incremental reduce conflict interval");
+  OPT(0,incredconfslim,0,0,100,"incremental reduce conflict limit");
+  OPT(0,incsavevisits,0,0,1,"incremental start new visits counter");
+  OPT(0,inprocessing,1,0,1,"enable inprocessing");
+  OPT(0,irrlim,1,0,1,"use irredundant clauses as limit for simps");
+  OPT(0,itlocsdel,100,0,100*K,"local search delay after iteration");
+  OPT(0,itsimpdel,20,0,100*K,"simplification delay after iteration");
+  OPT(0,jwhred,1,0,1,"compute JWH score based on redundant clauses too");
+  OPT(0,keepmaxglue,1,0,1,"keep maximum glue clauses");
+  OPT(0,lftmaxeff,20*M,-1,I,"max effort in lifting");
+  OPT(0,lftmineff,500*K,0,I,"min effort in lifting");
+  OPT(0,lftreleff,6,0,10*K,"rel effort in lifting");
+  OPT(0,lftroundlim,5,0,I,"lifting round limit");
+  OPT(0,lhbr,1,0,1, "enable lazy hyber binary reasoning");
+  OPT(0,lift,1,0,1,"enable double lookahead lifting");
+  OPT(0,liftlrg,3,0,I,"consider large clauses with this many unassigned");
+  OPT(0,liftwait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,lkhd,2,-1,3, "-1=LOCS,0=LIS,1=JWH,2=TREELOOK,3=LENSUM");
+  OPT(0,lkhdmisifelmrtc,0,0,1,"MIS if elimination ran to completion");
+  OPT(0,locs,0,-1,I,"use local search (-1=always otherwise how often)");
+  OPT(0,locsclim,1*M,0,(I>>8),"clause limit for local search");
+  OPT(0,locsboost,2,0,100,"initial local search boost");
+  OPT(0,locscint,10*K,1,I,"conflict interval for LOCS");
+  OPT(0,locsdec,2,0,2,"bump 1=mostflipped 2=minlits");
+  OPT(0,locset,2,0,2,"initialize local search phases (1=prev,2=cur)");
+  OPT(0,locsexport,1,0,1,"export phases from local search");
+  OPT(0,locsmaxeff,100000,0,I,"max effort in local search");
+  OPT(0,locsmineff,1000,0,I,"min effort in local search");
+  OPT(0,locsred,0,0,4,"apply local search on redundant clauses too");
+  OPT(0,locsreleff,5,0,100,"rel effort in local search");
+  OPT(0,locsrtc,0,0,1,"run local search until completion");
+  OPT(0,locsvared,100,0,1000,"max variable reduction for LOCS");
+  OPT(0,locswait,2,0,2,"wait for BCE(1) and/or BVE(2)");
+  OPT(0,maxglue,I,0,I,"min glue which is considered as MAXGLUE");
+  OPT(0,maxscorexp,DEFSCOREXP,7,MAXSCOREXP,"maximum score exponent");
+  OPT(0,mega,0,0,1,"mega probing through preprocessor look-ahead");
+  OPT(0,megaint,4,1,I,"mega probing interval");
+  OPT(0,megawait,2,0,2,"mega probing waiting for BCE / BVE");
+  OPT(0,memlim,-1,-1,I,"memory limit in MB (-1=no limit)");
+  OPT(0,minimize,2,0,2,"minimize learned clauses (1=local,2=recursive)");
+  OPT(0,minlocalgluelim,30,0,I,"glue limit for using local minimization");
+  OPT(0,minrecgluelim,20,0,I,"glue limit for using recursive minimization");
+  OPT(0,mocint,1000,1,I,"multiple objectives conflict limit interval");
+  OPT(0,move,2,0,3,"move redundant cls (1=only-binary,2=ternary,3=all)");
+  OPT(0,otfs,1,0,1,"enable on-the-fly subsumption");
+  OPT(0,otfsbump,0,0,2,"bump literals during OTFS (1=conflict,2=drive)");
+  OPT(0,otfsconf,0,0,1,"count on-the-fly restart as conflict");
+  OPT(0,penmax,4,0,16,"maximum penalty");
+  OPT(0,phase,0,-1,1,"default phase (-1=neg,0=JeroslowWang,1=pos)");
+  OPT(0,phaseflip,0,0,1,"flip Jeroslow Wang phase");
+  OPT(0,phasegluebit,0,0,I,"Glue-Bit phase selection on these levels");
+  OPT(0,phaseneginit,0,0,I,"initial zero phase conflict interval");
+  OPT(0,plain,0,0,1,"plain mode disables all preprocessing");
+  OPT(0,plim,-1,-1,I,"propagation limit (thousands)");
+  OPT(0,prbasic,1,0,2,"enable basic probing procedure (1=roots-only)");
+  OPT(0,prbasicmaxeff,100*M,-1,I,"max effort in basic probing");
+  OPT(0,prbasicmineff,M,0,I,"min effort in basic probing");
+  OPT(0,prbasicreleff,10,0,10*K,"rel effort in basic probing");
+  OPT(0,prbasicroundlim,9,1,I,"basic probing round limit");
+  OPT(0,prbasicrtc,0,0,1,"run basic probing until completion");
+  OPT(0,prbrtc,0,0,1,"run all probing until completion");
+  OPT(0,prbsimple,2,0,3,"simple probing (1=shallow,2=deep,3=touchall)");
+  OPT(0,prbsimpleboost,10,1,1000,"initial simple probing boost");
+  OPT(0,prbsimpleliftdepth,2,1,4,"simple probing lifting depth");
+  OPT(0,prbsimplemaxeff,200*M,-1,I,"max effort in simple probing");
+  OPT(0,prbsimplemineff,2*M,0,I,"min effort in simple probing");
+  OPT(0,prbsimplereleff,40,0,10*K,"rel effort in simple probing");
+  OPT(0,prbsimplertc,0,0,1,"run simple probing until completion");
+  OPT(0,probe,1,0,1,"enable probing");
+  OPT(0,psm,3,0,3,"use PSM metric (1=afteract,2=afterglue,3=first");
+  OPT(0,pure,1,0,1,"enable pure literal elimination during BCE");
+  OPT(0,randec,0,0,1,"enable random decisions");
+  OPT(0,randecflipint,0,0,I,"random decision flip phase interval");
+  OPT(0,randecint,1000,2,I/2,"random decision interval");
+  OPT(0,rdp,0,0,3,"random DP (2=redbin,3=redtrn");
+  OPT(0,rdpclslim,3,0,I,"random DP resolvent size limit");
+  OPT(0,rdplim,100,0,200,"limit #resolvents in percent original clauses");
+  OPT(0,rdpmaxeff,10*M,-1,I,"max effort in RDP");
+  OPT(0,rdpmineff,10*K,0,I,"min effort in RDP");
+  OPT(0,rdpmodelm,0,0,1,"use model elimination in RDP");
+  OPT(0,rdpreleff,2,0,10*K,"rel effort in RDP");
+  OPT(0,rdpwait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,redfixed,0,0,1,"keep a fixed size of learned clauses");
+  OPT(0,redinoutinc,100,1,1000,"reduce inner/outer relative increment");
+  OPT(0,redlbound,0,0,1,"relative and absolute bounds on learned clauses");
+  OPT(0,redlexpfac,10,0,1000,"exponential reduce limit increment factor");
+  OPT(0,redlinc,1000,1,10*M,"reduce limit increment");
+  OPT(0,redlinit,4*K,1,100*M,"initial reduce limit");
+  OPT(0,redlmaxabs,1000000,10,I/2,"maximum absolute reduce limit");
+  OPT(0,redlmaxinc,200,1,100*K,"rel max reduce limit increment");
+  OPT(0,redlmaxrel,300,10,10000,"maximum relative reduce limit");
+  OPT(0,redlminabs,500,10,1000000,"minimum absolute reduce limit");
+  OPT(0,redlmininc,10,1,100*K,"rel min reduce limit increment");
+  OPT(0,redlminrel,10,10,1000,"minimum relative reduce limit");
+  OPT(0,redloutinc,10000,0,1000000,"outer arithmetic reduce increment");
+  OPT(0,redoutclim,5000,0,I,"clause limit for outer reduce schedule");
+  OPT(0,redoutvlim,1000,0,I,"variable limit for outer reduce schedule");
+  OPT(0,reduce,2,0,4,"clause reduction (1=noouter,2=luby,3=inout,4=arith)");
+  OPT(0,rephase,1,0,2,"enable flushing and recomputation of phases (2=full)");
+  OPT(0,rephaseinc,10000,1,I,"rephasing increment");
+  OPT(0,restart,2,0,3,"enable restarting (0=no,1=fixed,2=luby,3=inout)");
+  OPT(0,restartinit,0,0,I,"initial restart interval");
+  OPT(0,restartint,5,1,I,"restart interval");
+  OPT(0,restartintscale,0,-1,1,"scale restart interval");
+  OPT(0,reusetrail,1,0,1,"reuse trail");
+  OPT(0,rmincpen,4,0,32,"logarithm of watcher removal penalty");
+  OPT(0,rstinoutinc,110,1,1000,"restart inner/outer relative increment");
+  OPT(0,saturating,70,0,1000,"saturating level (no restart)");
+  OPT(0,scincinc,200,0,10*K,"score increment increment in per mille");
+  OPT(0,score,5,0,6,"0=static,1=inc,2=vmtf,3=sum,4=avg,5=evsids,6=vsids256");
+  OPT(0,seed,0,0,I,"random number generator seed");
+  OPT(0,simpdelay,0,0,I,"initial simplification delay");
+  OPT(0,simpen,0,0,24,"logarithmic initial simplification penalty");
+  OPT(0,simpidiv,3,1,100,"simplification inter delay divisor");
+  OPT(0,simpinterdelay,2000,0,I,"inprocessing simplification delay");
+  OPT(0,simpiscale,100,1,10000,"relative simplification inter delay scale");
+  OPT(0,simplify,2,0,2,"enable simplification");
+  OPT(0,simprtc,5,1,100,"min var reduction for simplification RTC");
+  OPT(0,simpvarchg,100,1,1000, "simp remaining vars percentage change lim");
+  OPT(0,simpvarlim,100,0,I, "simp remaining vars min limit");
+  OPT(0,sizemaxpen,5,0,20,"maximum logarithmic size penalty");
+  OPT(0,sizepen,1*M,1,I,"number of clauses size penalty starting point");
+  OPT(0,sleeponabort,0,0,I,"sleep this seconds before abort/exit");
+  OPT(0,smallirr,90,0,100,"max percentage irr lits for BCE and VE");
+  OPT(0,smallve,1,0,1,"enable small number variables elimination");
+  OPT(0,smallvevars,FUNVAR,4,FUNVAR, "variables small variable elimination");
+  OPT(0,smallvewait,0,0,1,"wait with small variable elimination");
+  OPT(0,sortlits,0,0,1,"sort lits of cls during garbage collection");
+  OPT(0,subl,9,0,10*K,"try to subsume this many recent learned clauses");
+  OPT(0,synclsall,1,0,1,"always synchronize all unconsumed clauses");
+  OPT(0,synclsglue,8,0,I,"clause synchronization glue limit");
+  OPT(0,synclsint,100,0,1000,"clause synchronization confs interval");
+  OPT(0,synclslen,40,0,I,"clause synchronization length limit");
+  OPT(0,syncunint,111111,0,M,"unit synchronization steps interval");
+  OPT(0,tabr,3,0,4,"tabula rasa (1=red,2=phases,3=cinc,4=scores");
+  OPT(0,tabrcfactor,2,1,I,"tabula rasa clause factor");
+  OPT(0,tabrkeep,3,1,4,"1=none,2=bin,3=bin+trn,4=bin+trn+glue0");
+  OPT(0,tabrvfactor,4,1,I,"tabula rasa variable factor");
+  OPT(0,termint,122222,0,M,"termination check interval");
+  OPT(0,ternres,1,0,1,"generate ternary resolvents");
+  OPT(0,ternresboost,5,1,100,"initial ternary reslution boost");
+  OPT(0,ternresrtc,0,0,1,"run ternary resolvents until completion");
+  OPT(0,ternreswait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,transred,1,0,1,"enable transitive reduction");
+  OPT(0,transredwait,2,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,trdmaxeff,2*M,-1,I,"max effort in transitive reduction");
+  OPT(0,trdmineff,100*K,0,I,"min effort in transitive reduction");
+  OPT(0,trdreleff,10,0,10*K,"rel effort in transitive reduction");
+  OPT(0,treelook,1,0,2,"enable tree-based look-ahead (2=scheduleprobing)");
+  OPT(0,treelookboost,20,1,100000,"tree-based look-head boost factor");
+  OPT(0,treelookfull,0,0,1,"do not limit tree-based look-head");
+  OPT(0,treelooklrg,1,0,1,"use large clauses during tree-look");
+  OPT(0,treelookmaxeff,50*M,-1,I,"max effort in tree-look based probing");
+  OPT(0,treelookmineff,300*K,0,I,"min effort in tree-look based probing");
+  OPT(0,treelookreleff,1,0,10*K,"rel effort in tree-look based probing");
+  OPT(0,treelookrtc,0,0,1,"run tree-based look-ahead until completion");
+  OPT(0,trep,0,0,1,"enable time based interval reporting");
+  OPT(0,trepint,55555,1,I,"interval for time based reporting");
+  OPT(0,trnreleff,10,0,K,"rel effort in ternary resolutions");
+  OPT(0,trnrmaxeff,200*M,-1,I,"max effort in ternary resolutions");
+  OPT(0,trnrmineff,4*M,0,I,"min effort in ternary resolutions");
+  OPT(0,unhdatrn,2,0,2,"unhide redundant ternary clauses (1=move,2=force)");
+  OPT(0,unhdextstamp,1,0,1,"used extended stamping features");
+  OPT(0,unhdhbr,0,0,1,"enable unhiding hyper binary resolution");
+  OPT(0,unhdlnpr,3,0,I,"unhide no progress round limit");
+  OPT(0,unhdmaxeff,20*M,-1,I,"max effort in unhiding");
+  OPT(0,unhdmineff,100*K,0,I,"min effort in unhiding");
+  OPT(0,unhdreleff,2,0,10*K,"rel effort in unhiding");
+  OPT(0,unhdroundlim,20,0,100,"unhide round limit");
+  OPT(0,unhide,1,0,1,"enable unhiding");
+  OPT(0,unhidewait,0,0,2,"wait for BCE (1) and/or BVE (2)");
+  OPT(0,wait,1,0,1,"enable or disable all waiting");
+  OPT(0,waitmax,4,-1,I,"max simps to wait (-1=nomax)");
+  OPT(0,witness,1,0,1,"print witness");
+
+  OPT('c',check,0,0,3,"check level");
+  OPT('l',log,-1,-1,5,"log level");
+  OPT('v',verbose,0,-1,4,"verbosity level");
+
+  if (lgl->opts->plain.val) lglsetplain (lgl, 1);
+  if (lgl->opts->drup.val) lglsetdrup (lgl, 1);
+  if (lgl->opts->druplig.val) lglsetdruplig (lgl, 1);
+  if (!lgl->opts->wait.val) lglsetwait (lgl, 0);
+
+  if (abs (lgl->opts->bias.val) <= 1) lgl->bias = lgl->opts->bias.val;
+  else lgl->bias = 1;
+
+  NEW (lgl->times, 1);
+  NEW (lgl->timers, 1);
+  NEW (lgl->limits, 1);
+  NEW (lgl->fltstr, 1);
+  NEW (lgl->red, MAXGLUE+1);
+  NEW (lgl->wchs, 1);
+  for (i = 0; i < MAXLDFW; i++) lgl->wchs->start[i] = INT_MAX;
+  lglpushstk (lgl, &lgl->wchs->stk, INT_MAX);
+  lglpushstk (lgl, &lgl->wchs->stk, INT_MAX);
+
+#ifdef NDBLSCR
+  lgl->scinc = lglflt (0, 1);
+#else
+  lgl->scinc = 1;
+#endif
+
+  TRANS (UNUSED);
+
+  return lgl;
+}
+
+static void lglcopyclonenfork (LGL * dst, LGL * src) {
+  memcpy (dst->opts, src->opts, sizeof *src->opts);
+  dst->out = src->out;
+  if (dst->prefix) lgldelstr (dst, dst->prefix);
+  dst->prefix = lglstrdup (dst, src->prefix);
+  if (src->cbs) {
+    lglinitcbs (dst);
+    if (src->cbs->onabort) {
+      dst->cbs->abortstate = src->cbs->abortstate;
+      dst->cbs->onabort = src->cbs->onabort;
+    }
+    if (src->cbs->getime) dst->cbs->getime = src->cbs->getime;
+  }
+}
+
+static void lglcompact (LGL *);
+
+LGL * lglmclone (LGL * orig,
+                void * mem,
+                lglalloc alloc,
+                lglrealloc realloc,
+                lgldealloc dealloc) {
+  size_t max_bytes, current_bytes;
+  LGL * lgl = orig;
+  int glue;
+
+  if (!orig) return 0;
+  lglcompact (orig);
+  LOG (1, "cloning");
+  lgl = lglnewlgl (mem, alloc, realloc, dealloc);
+  memcpy (lgl, orig, ((char*)&orig->mem) - (char*) orig);
+  max_bytes = lgl->stats->bytes.max;
+  current_bytes = lgl->stats->bytes.current;
+  memcpy (lgl->stats, orig->stats, sizeof *orig->stats);
+  lgl->stats->bytes.current = current_bytes;
+  lgl->stats->bytes.max = max_bytes;
+
+  lglcopyclonenfork (lgl, orig);
+
+  CLONE (limits, 1);
+  CLONE (times, 1);
+  CLONE (timers, 1);           assert (!lgl->timers->nest);
+  CLONE (fltstr, 1);
+  CLONE (ext, orig->szext);
+  CLONE (i2e, orig->szvars);
+  CLONE (doms, 2*orig->szvars);
+  CLONE (dvars, orig->szvars);
+  CLONE (qvars, orig->szvars);
+  CLONE (avars, orig->szvars);
+  CLONE (vals, orig->szvars);
+  CLONE (jwh, 2*orig->szvars);
+  CLONE (drail, orig->szdrail);
+
+  NEW (lgl->red, MAXGLUE+1);
+  for (glue = 0; glue <= MAXGLUE; glue++) CLONESTK (red[glue]);
+
+  NEW (lgl->wchs, 1);
+  memcpy (lgl->wchs, orig->wchs, sizeof *orig->wchs);
+  CLONESTK (wchs->stk);
+
+  CLONESTK (control);
+  CLONESTK (clause);
+  CLONESTK (eclause);
+  CLONESTK (extend);
+  CLONESTK (irr);
+  CLONESTK (trail);
+  CLONESTK (frames);
+  CLONESTK (eassume);
+  CLONESTK (assume);
+  CLONESTK (fassume);
+  CLONESTK (learned);
+  CLONESTK (cassume);
+  CLONESTK (dsched);
+#ifndef NCHKSOL
+  CLONESTK (orig);
+#endif
+#ifndef NDEBUG
+  {
+    const char * p;
+    for (p = (char*)&orig->elm; p < (char*)(&orig->repr+1); p++) assert (!*p);
+  }
+#endif
+  assert (lgl->stats->bytes.current == orig->stats->bytes.current);
+  assert (lgl->stats->bytes.max <= orig->stats->bytes.max);
+  lgl->stats->bytes.max = orig->stats->bytes.max;
+  return lgl;
+}
+
+LGL * lglclone (LGL * lgl) {
+  REQINIT ();
+  return lglmclone (lgl,
+                    lgl->mem->state,
+                    lgl->mem->alloc,
+                    lgl->mem->realloc,
+                    lgl->mem->dealloc);
+}
+
+void lglchkclone (LGL * lgl) {
+  REQINITNOTFORKED ();
+  TRAPI ("chkclone");
+#ifdef NLGLPICOSAT
+  if (!lgl->opts->druplig.val) {
+    if (lgl->clone) lglrelease (lgl->clone);
+    lgl->clone = lglclone (lgl);
+  }
+#endif
+}
+
+LGL * lglinit (void) { return lglminit (0, 0, 0, 0); }
+
+static int lglmaxoptnamelen (LGL * lgl) {
+  int res = 0, len;
+  Opt * o;
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++)
+    if ((len = strlen (o->lng)) > res)
+      res = len;
+  return res;
+}
+
+void lglusage (LGL * lgl) {
+  char fmt[20];
+  int len;
+  Opt * o;
+  REQINITNOTFORKED ();
+  len = lglmaxoptnamelen (lgl);
+  sprintf (fmt, "--%%-%ds", len);
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (o->shrt) fprintf (lgl->out, "-%c|", o->shrt);
+    else fprintf (lgl->out, "   ");
+    fprintf (lgl->out, fmt, o->lng);
+    fprintf (lgl->out, " %s [%d]\n", o->descrp, o->val);
+  }
+}
+
+static int lglignopt (const char * name) {
+  if (!strcmp (name, "abstime")) return 1;
+  if (!strcmp (name, "check")) return 1;
+  if (!strcmp (name, "drup")) return 1;
+  if (!strcmp (name, "exitonabort")) return 1;
+  if (!strcmp (name, "log")) return 1;
+  if (!strcmp (name, "sleeponabort")) return 1;
+  if (!strcmp (name, "verbose")) return 1;
+  if (!strcmp (name, "witness")) return 1;
+  return 0;
+}
+
+void lglopts (LGL * lgl, const char * prefix, int ignsome) {
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (ignsome && lglignopt (o->lng)) continue;
+    fprintf (lgl->out, "%s--%s=%d\n", prefix, o->lng, o->val);
+  }
+}
+
+void lglrgopts (LGL * lgl) {
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++)
+    fprintf (lgl->out, "%s %d %d %d\n", o->lng, o->val, o->min, o->max);
+}
+
+void lglpcs (LGL * lgl, int mixed) {
+  int i, printi, printl;
+  int64_t range;
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (lglignopt (o->lng)) continue;
+    range = o->max; range -= o->min;
+    if (range >= 7 && mixed < 0) continue;
+    printi = printl = 0;
+    printf ("%s ", o->lng);
+    if (range < 7) {
+      printf ("{%d", o->min);
+      for (i = o->min + 1; i <= o->max; i++) printf (",%d", i);
+      printf ("}");
+    } else if (!mixed) {
+      printf ("[%d,%d]", o->min, o->max);
+      printi = 1;
+      printl = (o->min > 0 && range >= 100);
+    } else if (o->dflt == o->min || o->dflt == o->max) {
+      printf ("{%d,%d,%d,%d,%d}",
+        o->min,
+        (int)(o->min + (1*range + 3)/4),
+        (int)(o->min + (2*range + 3)/4),
+        (int)(o->min + (3*range + 3)/4),
+        o->max);
+    } else if (o->dflt == o->min + 1) {
+      printf ("{%d,%d,%d,%d}",
+        o->min,
+       o->dflt,
+       (int)(o->dflt + (o->max - (int64_t) o->dflt)/2),
+       o->max);
+    } else if (o->dflt + 1 == o->max) {
+      printf ("{%d,%d,%d,%d}",
+        o->min,
+       (int)(o->min + (o->dflt - (int64_t) o->min)/2),
+       o->dflt,
+       o->max);
+    } else {
+      assert (o->dflt - o->min >= 2);
+      assert (o->max - o->dflt >= 2);
+      printf ("{%d,%d,%d,%d,%d}",
+        o->min,
+       (int)(o->min + (o->dflt - (int64_t) o->min)/2),
+        o->dflt,
+        (int)(o->dflt + (o->max - (int64_t) o->min)/2),
+       o->max);
+    }
+    printf ("[%d]", o->dflt);
+    if (printi) printf ("i"); 
+    if (printl) printf ("l"); 
+    printf (" # %s\n",o->descrp);
+  }
+}
+
+int lglhasopt (LGL * lgl, const char * opt) {
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (!opt[1] && o->shrt == opt[0]) return 1;
+    if (!strcmp (o->lng, opt)) return 1;
+  }
+  return 0;
+}
+
+void * lglfirstopt (LGL * lgl) { return FIRSTOPT (lgl); }
+
+void * lglnextopt (LGL * lgl,
+                  void * current,
+                  const char **nameptr,
+                  int *valptr, int *minptr, int *maxptr) {
+  Opt * opt = current, * res = opt + 1;
+  if (res > LASTOPT (lgl)) return 0;
+  if (nameptr) *nameptr = opt->lng;
+  if (valptr) *valptr = opt->val;
+  if (minptr) *minptr = opt->min;
+  if (maxptr) *maxptr = opt->max;
+  return res;
+}
+
+void lglsetopt (LGL * lgl, const char * opt, int val) {
+  int oldval;
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (!opt[1] && o->shrt == opt[0]) break;
+    if (!strcmp (o->lng, opt)) break;
+  }
+  if (o > LASTOPT (lgl)) return;
+  if (val < o->min) val = o->min;
+  if (o->max < val) val = o->max;
+  oldval = o->val;
+  o->val = val;
+  if (o == &lgl->opts->flipping && !oldval)
+    lgl->flipping = lgl->notflipped = 0;
+  if (o == &lgl->opts->plain) {
+    if (val > 0 && !oldval) lglsetplain (lgl, 1);
+    if (!val && oldval) lglsetplain (lgl, 0);
+  }
+  if (o == &lgl->opts->drup) {
+    if (val > 0 && !oldval) lglsetdrup (lgl, 1);
+    if (!val && oldval) lglsetdrup (lgl, 0);
+  }
+  if (o == &lgl->opts->druplig) {
+    if (val > 0 && !oldval) lglsetdruplig (lgl, 1);
+    if (!val && oldval) lglsetdruplig (lgl, 0);
+  }
+  if (o == &lgl->opts->wait) {
+    if (val > 0 && !oldval) lglsetwait (lgl, 1);
+    if (!val && oldval) lglsetwait (lgl, 0);
+  }
+  if (o == &lgl->opts->phase && val != oldval) lgl->flushphases = 1;
+  if (lgl->state == UNUSED) TRANS (OPTSET);
+  TRAPI ("option %s %d", opt, val);
+}
+
+static int lglws (int ch) {
+  return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+}
+
+int lglreadopts (LGL * lgl, FILE * file) {
+  int res, ch, val, nvalbuf, noptbuf;
+  char optbuf[40], valbuf[40];
+  const char * opt;
+  res = 0;
+  for (;;) {
+    while (lglws (ch = getc (file)))
+      ;
+    if (ch == EOF) break;
+    noptbuf = 0;
+    optbuf[noptbuf++] = ch;
+    while ((ch = getc (file)) != EOF && !lglws (ch)) {
+      if (noptbuf + 1 >= sizeof optbuf) { ch = EOF; break; }
+      optbuf[noptbuf++] = ch;
+    }
+    if (ch == EOF) break;
+    assert (noptbuf < sizeof optbuf);
+    optbuf[noptbuf++] = 0;
+    assert (lglws (ch));
+    while (lglws (ch = getc (file)))
+      ;
+    if (ch == EOF) break;
+    nvalbuf = 0;
+    valbuf[nvalbuf++] = ch;
+    while ((ch = getc (file)) != EOF && !lglws (ch)) {
+      if (nvalbuf + 1 >= sizeof valbuf) break;
+      valbuf[nvalbuf++] = ch;
+    }
+    assert (nvalbuf < sizeof valbuf);
+    valbuf[nvalbuf++] = 0;
+    opt = optbuf;
+    val = atoi (valbuf);
+    lglprt (lgl, 1, "read option --%s=%d", opt, val);
+    lglsetopt (lgl, opt, val);
+    res++;
+  }
+  return res;
+}
+
+void lglsetout (LGL * lgl, FILE * out) { lgl->out = out; }
+
+FILE * lglgetout (LGL * lgl) { return lgl->out; }
+
+void lglsetprefix (LGL * lgl, const char * prefix) {
+  lgldelstr (lgl, lgl->prefix);
+  lgl->prefix = lglstrdup (lgl, prefix);
+}
+
+const char * lglgetprefix (LGL * lgl) { return lgl->prefix; }
+
+static Opt * lgligetopt (LGL * lgl, const char * opt) {
+  Opt * o;
+  REQINITNOTFORKED ();
+  for (o = FIRSTOPT (lgl); o <= LASTOPT (lgl); o++) {
+    if (!opt[1] && o->shrt == opt[0]) return o;
+    if (!strcmp (o->lng, opt)) return o;
+  }
+  return 0;
+}
+
+int lglgetopt (LGL * lgl, const char * opt) {
+  Opt * o = lgligetopt (lgl, opt);
+  return o ? o->val : 0;
+}
+
+int lglgetoptminmax (LGL * lgl, const char * opt,
+                     int * min_ptr, int * max_ptr) {
+  Opt * o = lgligetopt (lgl, opt);
+  if (!o) return 0;
+  if (min_ptr) *min_ptr = o->min;
+  if (max_ptr) *max_ptr = o->max;
+  return o->val;
+}
+
+/*------------------------------------------------------------------------*/
+
+static void lglrszvars (LGL * lgl, int new_size) {
+  int old_size = lgl->szvars;
+  assert (lgl->nvars <= new_size);
+  RSZ (lgl->vals, old_size, new_size);
+  RSZ (lgl->i2e, old_size, new_size);
+  RSZ (lgl->doms, 2*old_size, 2*new_size);
+  RSZ (lgl->dvars, old_size, new_size);
+  RSZ (lgl->avars, old_size, new_size);
+  RSZ (lgl->qvars, old_size, new_size);
+  RSZ (lgl->jwh, 2*old_size, 2*new_size);
+  lgl->szvars = new_size;
+}
+
+static void lglenlvars (LGL * lgl) {
+  size_t old_size, new_size;
+  old_size = lgl->szvars;
+  new_size = old_size ? 2 * old_size : 4;
+  LOG (3, "enlarging internal variables from %ld to %ld", old_size, new_size);
+  lglrszvars (lgl, new_size);
+}
+
+static void lglredvars (LGL * lgl) {
+  size_t old_size, new_size;
+  old_size = lgl->szvars;
+  new_size = lgl->nvars;
+  if (new_size == old_size) return;
+  LOG (3, "reducing variables from %ld to %ld", old_size, new_size);
+  lglrszvars (lgl, new_size);
+}
+
+static int lglmax (int a, int b) { return a > b ? a : b; }
+
+static int lglmin (int a, int b) { return a < b ? a : b; }
+
+/*------------------------------------------------------------------------*/
+
+static DVar * lgldvar (LGL * lgl, int lit) {
+  assert (2 <= abs (lit) && abs (lit) < lgl->nvars);
+  return lgl->dvars + abs (lit);
+}
+
+/*------------------------------------------------------------------------*/
+
+static AVar * lglavar (LGL * lgl, int lit) {
+  assert (2 <= abs (lit) && abs (lit) < lgl->nvars);
+  return lgl->avars + abs (lit);
+}
+
+static Val lglval (LGL * lgl, int lit) {
+  int idx = abs (lit);
+  Val res;
+  ASSERT (2 <= idx && idx < lgl->nvars);
+  res = lgl->vals[idx];
+  if (lit < 0) res = -res;
+  return res;
+}
+
+static int lgltrail (LGL * lgl, int lit) { return lglavar (lgl, lit)->trail; }
+
+static TD * lgltd (LGL * lgl, int lit) {
+  int pos = lgltrail (lgl, lit);
+  assert (0 <= pos && pos < lgl->szdrail);
+  return lgl->drail + pos;
+}
+
+static int lglevel (LGL * lgl, int lit) { return lgltd (lgl, lit)->level; }
+
+static int lglisfree (LGL * lgl, int lit) {
+  return lglavar (lgl, lit)->type == FREEVAR;
+}
+
+/*------------------------------------------------------------------------*/
+
+static QVar * lglqvar (LGL * lgl, int lit) {
+  assert (2 <= abs (lit) && abs (lit) < lgl->nvars);
+  return lgl->qvars + abs (lit);
+}
+
+static int * lgldpos (LGL * lgl, int lit) {
+  QVar * qv;
+  int * res;
+  qv = lglqvar (lgl, lit);
+  res = &qv->pos;
+  return res;
+}
+
+static int lglscrcmp (Scr a, Scr b) {
+  if (a < b) return -1;
+  if (a > b) return 1;
+  return 0;
+}
+
+static int lgldcmp (LGL * lgl, int l, int k) {
+  QVar * pv = lglqvar (lgl, l);
+  QVar * qv = lglqvar (lgl, k);
+  int res;
+  if ((res = lglscrcmp (pv->score, qv->score))) return res;
+  res = lgl->bias * (l - k);
+  return res;
+}
+
+#ifndef NDEBUG
+static void lglchkdsched (LGL * lgl) {
+  int * p, parent, child, ppos, cpos, size, i, tmp;
+  Stk * s = &lgl->dsched;
+  size = lglcntstk (s);
+  p = s->start;
+  for (ppos = 0; ppos < size; ppos++) {
+    parent = p[ppos];
+    tmp = *lgldpos (lgl, parent);
+    assert (ppos == tmp);
+    for (i = 0; i <= 1; i++) {
+      cpos = 2*ppos + 1 + i;
+      if (cpos >= size) continue;
+      child = p[cpos];
+      tmp = *lgldpos (lgl, child);
+      assert (cpos == tmp);
+      assert (lgldcmp (lgl, parent, child) >= 0);
+    }
+  }
+}
+#endif
+
+static void lgldup (LGL * lgl, int lit) {
+  int child = lit, parent, cpos, ppos, * p, * cposptr, * pposptr;
+  Stk * s = &lgl->dsched;
+  p = s->start;
+  cposptr = lgldpos (lgl, child);
+  cpos = *cposptr;
+  assert (cpos >= 0);
+  while (cpos > 0) {
+    ppos = (cpos - 1)/2;
+    parent = p[ppos];
+    if (lgldcmp (lgl, parent, lit) >= 0) break;
+    pposptr = lgldpos (lgl, parent);
+    assert (*pposptr == ppos);
+    p[cpos] = parent;
+    *pposptr = cpos;
+    LOGDSCHED (5, parent, "down from %d", ppos);
+    cpos = ppos;
+  }
+  if (*cposptr == cpos) return;
+#ifndef NLGLOG
+  ppos = *cposptr;
+#endif
+  *cposptr = cpos;
+  p[cpos] = lit;
+  LOGDSCHED (5, lit, "up from %d", ppos);
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 2) lglchkdsched (lgl);
+#endif
+}
+
+static void lglddown (LGL * lgl, int lit) {
+  int parent = lit, child, right, ppos, cpos;
+  int * p, * pposptr, * cposptr, size;
+  Stk * s = &lgl->dsched;
+  size = lglcntstk (s);
+  p = s->start;
+  pposptr = lgldpos (lgl, parent);
+  ppos = *pposptr;
+  assert (0 <= ppos);
+  for (;;) {
+    cpos = 2*ppos + 1;
+    if (cpos >= size) break;
+    child = p[cpos];
+    if (cpos + 1 < size) {
+      right = p[cpos + 1];
+      if (lgldcmp (lgl, child, right) < 0) cpos++, child = right;
+    }
+    if (lgldcmp (lgl, child, lit) <= 0) break;
+    cposptr = lgldpos (lgl, child);
+    assert (*cposptr = cpos);
+    p[ppos] = child;
+    *cposptr = ppos;
+    LOGDSCHED (5, child, "up from %d", cpos);
+    ppos = cpos;
+  }
+  if (*pposptr == ppos) return;
+#ifndef NLGLOG
+  cpos = *pposptr;
+#endif
+  *pposptr = ppos;
+  p[ppos] = lit;
+  LOGDSCHED (5, lit, "down from %d", cpos);
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 2) lglchkdsched (lgl);
+#endif
+}
+
+static void lgldsched (LGL * lgl, int lit) {
+  int * p = lgldpos (lgl, lit);
+  Stk * s = &lgl->dsched;
+  assert (*p < 0);
+  *p = lglcntstk (s);
+  lglpushstk (lgl, s, lit);
+  lgldup (lgl, lit);
+  lglddown (lgl, lit);
+  LOGDSCHED (4, lit, "pushed");
+}
+
+static int lgltopdsched (LGL * lgl) {
+  assert (!lglmtstk (&lgl->dsched));
+  return lgl->dsched.start[0];
+}
+
+static int lglpopdsched (LGL * lgl) {
+  Stk * s = &lgl->dsched;
+  int res, last, cnt, * p;
+  QVar * qv;
+  assert (!lglmtstk (s));
+  res = *s->start;
+  LOGDSCHED (4, res, "popped");
+  qv = lglqvar (lgl, res);
+  assert (!qv->pos);
+  qv->pos = -1;
+  last = lglpopstk (s);
+  cnt = lglcntstk (s);
+  if (!cnt) { assert (last == res); return res; }
+  p = lgldpos (lgl, last);
+  assert (*p == cnt);
+  *p = 0;
+  *s->start = last;
+  lglddown (lgl, last);
+  return res;
+}
+
+static void lgldreschedule (LGL * lgl) {
+  Stk * s = &lgl->dsched;
+  int idx, i, pos, cnt = lglcntstk (s);
+  QVar * qv;
+  LOG (1, "rescheduling %d variables", cnt);
+  for (idx = 2; idx < lgl->nvars; idx++) lglqvar (lgl, idx)->pos = -1;
+  pos = 0;
+  s->top = s->start;
+  for (i = 0; i < cnt; i++) {
+    assert (pos <= i);
+    assert (s->start + pos == s->top);
+    idx = s->start[i];
+    if (abs (idx) <= 1) continue;
+    qv = lglqvar (lgl, idx);
+    if (!lglisfree (lgl, idx)) { qv->pos = -1; continue; }
+    assert (qv->pos == -1);
+    s->start[pos] = idx;
+    qv->pos = pos++;
+    s->top++;
+    lgldup (lgl, idx);
+    lglddown (lgl, idx);
+  }
+  LOG (1, "new schedule with %d variables", lglcntstk (s));
+  lglfitstk (lgl, s);
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 1) lglchkdsched (lgl);
+#endif
+}
+
+#define RVL 2
+
+static void lglrescorevars (LGL * lgl) {
+  Scr oldscinc, oldscore, newscore, oldmaxscore = 0, newmaxscore = 0;
+  int64_t newotfs;
+  QVar * qv;
+  int idx;
+  lgl->stats->rescored.vars++;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    qv = lglqvar (lgl, idx);
+    oldscore = qv->score;
+    if (oldscore > oldmaxscore) oldmaxscore = oldscore;
+#ifdef NDBLSCR
+    if (lgl->opts->score.val == LGL_SCORE_EVSIDS ||
+        lgl->opts->score.val == LGL_SCORE_AVG)
+      newscore = lglshflt (oldscore, lgl->opts->maxscorexp.val);
+    else newscore = (oldscore >> 32);
+#else
+    newscore = oldscore / lgl->maxscore;
+#endif
+    qv->score = newscore;
+    if (qv->score > newmaxscore) newmaxscore = qv->score;
+    LOG (3, "rescored variable %d from %s to %s",
+        idx, lglscr2str (lgl, oldscore), lglscr2str (lgl, qv->score));
+  }
+  lgldreschedule (lgl);
+  newotfs = lgl->stats->otfs.driving + lgl->stats->otfs.restarting;
+  assert (newotfs >= lgl->limits->rescore.vars.otfs);
+  assert (lgl->stats->confs >= lgl->limits->rescore.vars.confs);
+  lglprt (lgl, RVL,
+    "[rescored-vars-%d] after %lld conflicts and %lld OTFS",
+    lgl->stats->rescored.vars,
+    lgl->stats->confs - lgl->limits->rescore.vars.confs,
+    newotfs - lgl->limits->rescore.vars.otfs);
+  lgl->limits->rescore.vars.confs = lgl->stats->confs;
+  lgl->limits->rescore.vars.otfs = newotfs;
+  lglprt (lgl, RVL,
+    "[rescored-vars-%d] old maximum score %s",
+    lgl->stats->rescored.vars, lglscr2str (lgl, oldmaxscore));
+  lglprt (lgl, RVL,
+    "[rescored-vars-%d] new maximum score %s",
+    lgl->stats->rescored.vars, lglscr2str (lgl, newmaxscore));
+  if (lgl->opts->score.val == LGL_SCORE_EVSIDS) {
+    oldscinc = lgl->scinc;
+#ifdef NDBLSCR
+    lgl->scinc = lglshflt (oldscinc, lgl->opts->maxscorexp.val);
+#else
+    lgl->scinc = oldscinc / lgl->maxscore;
+#endif
+    assert (lgl->scinc > 0);
+    lglprt (lgl, RVL,
+      "[rescored-vars-%d] old score increment %s",
+      lgl->stats->rescored.vars, lglscr2str (lgl, oldscinc));
+    lglprt (lgl, RVL,
+      "[rescored-vars-%d] new score increment %s",
+      lgl->stats->rescored.vars, lglscr2str (lgl, lgl->scinc));
+  }
+}
+
+static void lglbumpscinc (LGL * lgl) {
+  Scr oldscinc;
+  if (lgl->opts->score.val == LGL_SCORE_VSIDS256) {
+    if (!(lgl->stats->confs & 255)) {
+      int idx;
+      for (idx = 2; idx < lgl->nvars; idx++) {
+       QVar * qv = lglqvar (lgl, idx);
+       qv->score /= 2;
+       if (qv->pos < 0) continue;
+       lglddown (lgl, idx);
+      }
+    }
+  } else if (lgl->opts->score.val == LGL_SCORE_EVSIDS) {
+    oldscinc = lgl->scinc;
+    lgl->scinc = lglmulscr (oldscinc, lgl->scincf);
+    LOG (3, "bumped variable score increment from %s to %s",
+        lglscr2str (lgl, oldscinc), lglscr2str (lgl, lgl->scinc));
+    if (lgl->scinc < lgl->maxscore) return;
+    LOG (2, "variable max score %s hit", lglscr2str (lgl, lgl->maxscore));
+    lglrescorevars (lgl);
+  }
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglnewvar (LGL * lgl) {
+  AVar * av;
+  DVar * dv;
+  QVar * qv;
+  int res;
+  assert (!lgl->dense);
+  if (lgl->nvars == lgl->szvars) lglenlvars (lgl);
+  if (lgl->nvars) res = lgl->nvars++;
+  else res = 2, lgl->nvars = 3;
+  assert (res < lgl->szvars);
+  if (res > MAXVAR) lgldie (lgl, "more than %d variables", MAXVAR - 1);
+  assert (res <= MAXVAR);
+  assert (((res << RMSHFT) >> RMSHFT) == res);
+  assert (((-res << RMSHFT) >> RMSHFT) == -res);
+  LOG (3, "new internal variable %d", res);
+  dv = lgl->dvars + res;
+  CLRPTR (dv);
+  av = lgl->avars + res;
+  CLRPTR (av);
+  qv = lgl->qvars + res;
+  CLRPTR (qv);
+  qv->pos = -1;
+  lgldsched (lgl, res);
+  lgl->unassigned++;
+  lgl->allphaseset = 0;
+  return res;
+}
+
+static int lglsgn (int lit) { return (lit < 0) ? -1 : 1; }
+
+static Ext * lglelit2ext (LGL * lgl, int elit) {
+  int idx = abs (elit);
+  assert (0 < idx), assert (idx <= lgl->maxext);
+  return lgl->ext + idx;
+}
+
+#if 0
+static Ext * lgldlit2ext (LGL * lgl, int dlit) {
+  int idx = abs (dlit);
+  assert (0 < idx), assert (idx <= lgl->maxdef);
+  return lgl->def + idx;
+}
+#endif
+
+static int lglerepr (LGL * lgl, int elit) {
+  int res, next, tmp;
+  Ext * ext;
+  assert (0 < abs (elit)), assert (abs (elit) <= lgl->maxext);
+  res = elit;
+  for (;;) {
+    ext = lglelit2ext (lgl, res);
+    if (!ext->equiv) break;
+    next = ext->repr;
+    if (res < 0) next = -next;
+    res = next;
+  }
+  tmp = elit;
+  for (;;) {
+    ext = lglelit2ext (lgl, tmp);
+    if (!ext->equiv) { assert (tmp == res); break; }
+    next = ext->repr;
+    ext->repr = (tmp < 0) ? -res : res;
+    if (tmp < 0) next = -next;
+    tmp = next;
+  }
+  return res;
+}
+
+static void lgladjext (LGL * lgl, int eidx) {
+  size_t old, new;
+  assert (eidx >= lgl->szext);
+  assert (eidx > lgl->maxext);
+  assert (lgl->szext >= lgl->maxext);
+  old = lgl->szext;
+  new = old ? 2*old : 2;
+  while (eidx >= new) new *= 2;
+  assert (eidx < new), assert (new >= lgl->szext);
+  LOG (3, "enlarging external variables from %ld to %ld", old, new);
+  RSZ (lgl->ext, old, new);
+  lgl->szext = new;
+}
+
+#if 0
+static void lgladjdef (LGL * lgl, int didx) {
+  size_t old, new;
+  assert (didx);
+  assert (didx >= lgl->szdef);
+  assert (didx > lgl->maxdef);
+  assert (lgl->szdef > lgl->maxdef);
+  old = lgl->szdef;
+  new = old ? 2*old : 2;
+  while (didx >= new) new *= 2;
+  assert (didx < new), assert (new >= lgl->szdef);
+  LOG (3, "enlarging defined variables from %ld to %ld", old, new);
+  RSZ (lgl->def, old, new);
+  lgl->szdef = new;
+}
+#endif
+
+static void lglmelter (LGL * lgl) {
+  if (lgl->allfrozen) {
+    lglprt (lgl, 1,
+      "[melter] not all literals assumed to be frozen anymore");
+    lgl->allfrozen = 0;
+  }
+  if (lgl->limits->elm.pen || lgl->limits->blk.pen || lgl->limits->cce.pen) {
+    lglprt (lgl, 1,
+      "[melter] reset penalties: %d elm, %d blk, %d cce",
+      lgl->limits->elm.pen, lgl->limits->blk.pen, lgl->limits->cce.pen);
+    lgl->limits->elm.pen = lgl->limits->blk.pen = lgl->limits->cce.pen = 0;
+  }
+  lgl->frozen = lgl->allfrozen = 0;
+  LOG (2, "melted solver");
+}
+
+static int lglimportaux (LGL * lgl, int elit) {
+  int res, repr, eidx = abs (elit);
+  Ext * ext;
+  assert (elit);
+  if (eidx >= lgl->szext) lgladjext (lgl, eidx);
+  if (eidx > lgl->maxext) {
+    lgl->maxext = eidx;
+    lglmelter (lgl);
+  }
+  repr = lglerepr (lgl, elit);
+  ext = lglelit2ext (lgl, repr);
+  assert (!ext->equiv);
+  res = ext->repr;
+  if (!ext->imported) {
+    res = lglnewvar (lgl);
+    assert (!ext->equiv);
+    ext->repr = res;
+    ext->imported = 1;
+    assert (eidx <= INT_MAX/2);
+    lgl->i2e[res] = 2*eidx;
+    LOG (3, "mapping external variable %d to %d", eidx, res);
+    lglmelter (lgl);
+  }
+  if (repr < 0) res = -res;
+  LOG (2, "importing %d as %d", elit, res);
+  return res;
+}
+
+static int lglimport (LGL * lgl, int elit) {
+  assert (elit);
+  if (!lgl->opts->import.val) {
+    if (!lgl->maxext) (void) lglimportaux (lgl, 1);
+    while (lgl->maxext < abs (elit))
+      (void) lglimportaux (lgl, lgl->maxext + 1);
+  }
+  return lglimportaux (lgl, elit);
+}
+
+static Stk * lglidx2stk (LGL * lgl, int red, int lidx) {
+  int glue = 0;
+  Stk * s;
+  assert (red == 0 || red == REDCS);
+  assert (0 <= lidx);
+  if (!red) s = &lgl->irr;
+  else {
+    glue = lidx & GLUEMASK;
+    lidx >>= GLUESHFT;
+    assert (lidx <= MAXREDLIDX);
+    s = &lgl->red[glue];
+  }
+  return s;
+}
+
+static int * lglidx2lits (LGL * lgl, int red, int lidx) {
+  Stk * s = lglidx2stk (lgl, red, lidx);
+  int * res;
+  assert (red == 0 || red == REDCS);
+  assert (0 <= lidx);
+  res = s->start + (red ? (lidx >> GLUESHFT) : lidx);
+#ifndef NDEBUG
+  if (red && (lidx & GLUEMASK) == MAXGLUE) assert (res < s->end);
+  else assert (res < s->top);
+#endif
+  return res;
+}
+
+#ifndef NLGLOG
+static const char * lglred2str (int red) {
+  assert (!red || red == REDCS);
+  return red ? "redundant" : "irredundant";
+}
+#endif
+
+static int lgliselim (LGL * lgl, int lit) {
+  Tag tag = lglavar (lgl, lit)->type;
+  return tag == ELIMVAR;
+}
+
+#if 0
+static int lglisdef (LGL * lgl, int ilit) {
+  int iidx = abs (ilit), tidx, res;
+  assert (2 <= iidx), assert (iidx < lgl->nvars);
+  tidx = lgl->i2e[iidx];
+  res = tidx & 1;
+  return res;
+}
+#endif
+
+static int lglexport (LGL * lgl, int ilit) {
+  int iidx, tidx, eidx, def, res;
+  iidx = abs (ilit);
+  assert (2 <= iidx), assert (iidx < lgl->nvars);
+  tidx = lgl->i2e[iidx];
+  def = tidx & 1;
+  tidx >>= 1;
+  assert (tidx);
+  eidx = tidx;
+  if (def) eidx += lgl->maxext;
+  res = eidx;
+  if (ilit < 0) res = -res;
+  return res;
+}
+
+static int * lglrsn (LGL * lgl, int lit) { return lgltd (lgl, lit)->rsn; }
+
+static int lglulit (int lit) { return 2*abs (lit) + (lit < 0); }
+
+static void lglsetdom (LGL * lgl, int lit, int dom) {
+  assert (2 <= abs (lit)  && abs (lit) < lgl->nvars);
+  assert (2 <= abs (dom)  && abs (dom) < lgl->nvars);
+  ASSERT (lglval (lgl, lit) >= 0);
+  ASSERT (lglval (lgl, dom) >= 0);
+  lgl->doms[lglulit (lit)] = dom;
+  LOG (3, "literal %d dominated by %d", lit, dom);
+}
+
+static int lglgetdom (LGL * lgl, int lit) {
+  int res;
+  assert (2 <= abs (lit)  && abs (lit) < lgl->nvars);
+  assert (lglval (lgl, lit) >= 0);
+  res = lgl->doms[lglulit (lit)];
+  return res;
+}
+
+static HTS * lglhts (LGL * lgl, int lit) {
+  return lgldvar (lgl, lit)->hts + (lit < 0);
+}
+
+static int * lglhts2wchs (LGL * lgl, HTS * hts) {
+  int * res = lgl->wchs->stk.start + hts->offset;
+  assert (res < lgl->wchs->stk.top);
+  assert (res + hts->count < lgl->wchs->stk.top);
+  assert (res + hts->count < lgl->wchs->stk.top);
+  return res;
+}
+
+static void lglassign (LGL * lgl, int lit, int r0, int r1) {
+  int * p, other, other2, * c, lidx, found;
+  int idx, phase, glue, tag, dom, red, irr;
+  AVar * av = lglavar (lgl, lit);
+  TD * td;
+  LOGREASON (2, lit, r0, r1, "assign %d through", lit);
+  av->trail = lglcntstk (&lgl->trail);
+  if (av->trail >= lgl->szdrail) {
+    int newszdrail = lgl->szdrail ? 2*lgl->szdrail : 1;
+    RSZ (lgl->drail, lgl->szdrail, newszdrail);
+    lgl->szdrail = newszdrail;
+  }
+  td = lgltd (lgl, lit);
+  tag = r0 & MASKCS;
+  dom = (tag == BINCS) ? lglgetdom (lgl, -(r0 >> RMSHFT)) : lit;
+  lglsetdom (lgl, lit, dom);
+#ifndef NDEBUG
+  {
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      assert (lglval (lgl, other) < 0);
+      if (tag == TRNCS) {
+       other2 = r1;
+       assert (lglval (lgl, other2) < 0);
+      }
+    } else if (tag == LRGCS) {
+      red = r0 & REDCS;
+      lidx = r1;
+      c = lglidx2lits (lgl, red, lidx);
+      found = 0;
+      for (p = c; (other = *p); p++)
+       if (other == lit) found++;
+       else assert (lglval (lgl, other) < 0);
+      assert (found == 1);
+    } else assert (tag == DECISION || tag == UNITCS);
+  }
+  assert (!lglval (lgl, lit));
+  assert (lgl->unassigned > 0);
+  assert (!lgliselim (lgl, lit));
+#endif
+  idx = abs (lit);
+  phase = lglsgn (lit);
+  lgl->vals[idx] = phase;
+  if (!lgl->simp && !lgl->flipping && !lgl->phaseneg) {
+    lgl->flips -= lgl->flips/100000ull;
+    if (av->phase != phase) lgl->flips += 10000ull;
+    av->phase = phase;
+  }
+#ifndef NDEBUG
+  if (phase < 0) av->wasfalse = 1; else av->wasfalse = 0;
+#endif
+  td->level = lgl->level;
+  if (!lgl->level) {
+    td->irr = 1;
+    if (av->type == EQUIVAR) {
+      assert (lgl->stats->equiv.current > 0);
+      lgl->stats->equiv.current--;
+      assert (lgl->stats->equiv.sum > 0);
+      lgl->stats->equiv.sum--;
+    } else {
+      assert (av->type == FREEVAR);
+      av->type = FIXEDVAR;
+    }
+    lgl->stats->fixed.sum++;
+    lgl->stats->fixed.current++;
+    lgl->stats->prgss++;
+    lgl->stats->irrprgss++;
+    td->rsn[0] = UNITCS | (lit << RMSHFT);
+    td->rsn[1] = 0;
+    if (lgl->cbs && lgl->cbs->units.produce.fun) {
+      LOG (2, "trying to export internal unit %d external %d\n",
+          lgl->tid, lit, lglexport (lgl, lit));
+      lgl->stats->sync.units.produced++;
+      lgl->cbs->units.produce.fun (lgl->cbs->units.produce.state,
+                                  lglexport (lgl, lit));
+      LOG (2, "exporting internal unit %d external %d\n",
+             lgl->tid, lit, lglexport (lgl, lit));
+    }
+  } else {
+    td->rsn[0] = r0;
+    td->rsn[1] = r1;
+    if (lgl->level == 1) {
+      assert (tag != UNITCS);
+      if (tag == DECISION) irr = 1;
+      else if ((irr = !(red = (r0 & REDCS)))) {
+       if (tag == BINCS) {
+         other = r0 >> RMSHFT;
+         irr = lgltd (lgl, other)->irr;
+       } else if (tag == TRNCS) {
+         other = r0 >> RMSHFT;
+         if ((irr = lgltd (lgl, other)->irr)) {
+           other2 = r1;
+           irr = lgltd (lgl, other2)->irr;
+         }
+       } else {
+         assert (tag == LRGCS);
+         lidx = r1;
+         c = lglidx2lits (lgl, red, lidx);
+         found = 0;
+         for (p = c; irr && (other = *p); p++)
+           if (other == lit) found++;
+           else irr = lgltd (lgl, other)->irr;
+         assert (!irr || found == 1);
+       }
+      }
+    } else irr = 0;
+    td->irr = irr;
+  }
+
+  lglpushstk (lgl, &lgl->trail, lit);
+  if (!lgl->failed && (av->assumed & (1u << (lit > 0)))) {
+    LOG (2, "failed assumption %d", -lit);
+    lgl->failed = -lit;
+  }
+  lgl->unassigned--;
+  td->lrglue = 0;
+  if ((r0 & REDCS) && (r0 & MASKCS) == LRGCS) {
+    glue = r1 & GLUEMASK;
+    lgl->stats->lir[glue].forcing++;
+    assert (lgl->stats->lir[glue].forcing > 0);
+    if (lgl->level && 0 < glue && glue < MAXGLUE) {
+      lgl->lrgluereasons++;
+      assert (lgl->lrgluereasons > 0);
+      td->lrglue = 1;
+    }
+#ifndef NDEBUG
+    if (glue == MAXGLUE)
+      assert ((r1 >> GLUESHFT) + 4 < lglcntstk (&lgl->red[MAXGLUE]));
+#endif
+  }
+}
+
+static void lglf2rce (LGL * lgl, int lit, int other, int red) {
+  assert (lglval (lgl, other) < 0);
+  assert (!red || red == REDCS);
+  assert (!lgliselim (lgl, other));
+  lglassign (lgl, lit, ((other << RMSHFT) | BINCS | red), 0);
+}
+
+static void lglf3rce (LGL * lgl, int lit, int other, int other2, int red) {
+  assert (lglval (lgl, other) < 0);
+  assert (lglval (lgl, other2) < 0);
+  assert (!lgliselim (lgl, other));
+  assert (!lgliselim (lgl, other2));
+  assert (!red || red == REDCS);
+  lglassign (lgl, lit, ((other << RMSHFT) | TRNCS | red), other2);
+}
+
+static void lglflrce (LGL * lgl, int lit, int red, int lidx) {
+#ifndef NDEBUG
+  int * p = lglidx2lits (lgl, red, lidx), other;
+  while ((other = *p++)) {
+    assert (!lgliselim (lgl, other));
+    if (other != lit) assert (lglval (lgl, other) < 0);
+  }
+  assert (red == 0 || red == REDCS);
+#endif
+  lglassign (lgl, lit, red | LRGCS, lidx);
+}
+
+static int lgldscheduled (LGL * lgl, int lit) {
+  return lglqvar (lgl, lit)->pos >= 0;
+}
+
+static void lglunassign (LGL * lgl, int lit) {
+  int idx = abs (lit), r0, r1, tag, lidx, glue;
+  TD *  td;
+  LOG (2, "unassign %d", lit);
+  assert (lglval (lgl, lit) > 0);
+  assert (lgl->vals[idx] == lglsgn (lit));
+  lgl->vals[idx] = 0;
+  lgl->unassigned++;
+  assert (lgl->unassigned > 0);
+  if (!lgldscheduled (lgl, lit)) lgldsched (lgl, idx);
+  td = lgltd (lgl, idx);
+  r0 = td->rsn[0];
+  if (!(r0 & REDCS)) return;
+  tag = r0 & MASKCS;
+  if (tag != LRGCS) return;
+  r1 = td->rsn[1];
+  glue = r1 & GLUEMASK;
+  if (td->lrglue) {
+    assert (lgl->lrgluereasons > 0);
+    lgl->lrgluereasons--;
+  }
+  if (glue < MAXGLUE) return;
+  lidx = r1 >> GLUESHFT;
+  LOG (2, "eagerly deleting maximum glue clause at %d", lidx);
+  lglrststk (&lgl->red[glue], lidx);
+}
+
+static Val lglifixed (LGL * lgl, int lit) {
+  int res;
+  if (!(res = lglval (lgl, lit))) return 0;
+  if (lglevel (lgl, lit) > 0) return 0;
+  return res;
+}
+
+static void lglbacktrack (LGL * lgl, int level) {
+  int lit;
+  assert (level >= 0);
+  assert (lgl->level > level);
+  LOG (2, "backtracking to level %d", level);
+  assert (level <= lgl->level);
+  assert (abs (lgl->failed) != 1 || lgl->failed == -1);
+  if (lgl->failed &&
+      lgl->failed != -1 &&
+      lglevel (lgl, lgl->failed) > level) {
+    LOG (2, "resetting failed assumption %d", lgl->failed);
+    lgl->failed = 0;
+  }
+  while (!lglmtstk (&lgl->trail)) {
+    lit = lgltopstk (&lgl->trail);
+    assert (abs (lit) > 1);
+    if (lglevel (lgl, lit) <= level) break;
+    lglunassign (lgl, lit);
+    lgl->trail.top--;
+  }
+  if (!level) {
+    assert (!lgl->lrgluereasons);
+    while (!lglmtstk (&lgl->red[MAXGLUE])) {
+      int tmp = lglpopstk (&lgl->red[MAXGLUE]);
+      assert (tmp >= NOTALIT);
+      (void) tmp;
+    }
+  }
+  if (lgl->alevel > level) {
+    LOG (2,
+        "resetting assumption decision level to %d from %d",
+        level, lgl->alevel);
+    lgl->alevel = level;
+    if (lgl->assumed) {
+      LOG (2,
+          "resetting assumption queue level to 0 from %d",
+          lgl->assumed);
+      lgl->assumed = 0;
+    }
+  }
+  lgl->level = level;
+  lglrstcontrol (lgl, level + 1);
+  assert (lglcntctk (&lgl->control) == lgl->level + 1);
+  lgl->conf.lit = 0;
+  lgl->conf.rsn[0] = lgl->conf.rsn[1] = 0;
+  lgl->next2 = lgl->next = lglcntstk (&lgl->trail);
+  LOG (2, "backtracked ");
+}
+
+static int lglmarked (LGL * lgl, int lit) {
+  int res = lglavar (lgl, lit)->mark;
+  if (lit < 0) res = -res;
+  return res;
+}
+
+static void lgldrupinc (LGL * lgl) {
+  assert (lgl->opts->drup.val);
+  if (lgl->stats->drupped++) return;
+  printf ("o proof DRUP\n");
+}
+
+static void lgldrupclsaux (LGL * lgl, const int * cls) {
+  const int * p;
+  lgldrupinc (lgl);
+  for (p = cls; *p;  p++) printf ("%d ", lglexport (lgl, *p));
+  printf ("0\n");
+  fflush (stdout);
+}
+
+static void lgldrupcls (LGL * lgl) {
+  lgldrupclsaux (lgl, lgl->clause.start);
+}
+
+static void lgldrupclsarg (LGL * lgl, int first, ...) {
+  va_list ap;
+  int lit;
+  assert (lgl->opts->drup.val);
+  lgldrupinc (lgl);
+  printf ("%d", first ? lglexport (lgl, first) : 0);
+  if (first) {
+    va_start (ap, first);
+    do { 
+      lit = va_arg (ap, int);
+      printf (" %d", lit ? lglexport (lgl, lit) : 0);
+    } while (lit);
+  }
+  printf ("\n");
+  fflush (stdout);
+}
+
+#ifndef NLGLPICOSAT
+
+#define PICOSAT (assert (lgl && lgl->picosat.solver), lgl->picosat.solver)
+
+#ifndef NDEBUG
+static void lglpicosataddcls (LGL* lgl, const int * c){
+  const int * p;
+  lglpicosatinit (lgl);
+  for (p = c; *p; p++) picosat_add (PICOSAT, *p);
+  picosat_add (PICOSAT, 0);
+}
+#endif
+
+static void lglpicosatchkclsaux (LGL * lgl, int * c) {
+#ifndef NDEBUG
+  int * p;
+  lglpicosatinit (lgl);
+  if (picosat_inconsistent (PICOSAT)) {
+    LOG (3, "no need to check since PicoSAT is already inconsistent");
+    return;
+  }
+  LOGCLS (3, c, "checking consistency with PicoSAT of clause");
+  for (p = c; *p; p++) picosat_assume (PICOSAT, -*p);
+  (void) picosat_sat (PICOSAT, -1);
+  assert (picosat_res (PICOSAT) == 20);
+#endif
+}
+
+static void lglpicosatchkcls (LGL * lgl) {
+  lglpicosatchkclsaux (lgl, lgl->clause.start);
+}
+
+static void lglpicosatchkclsarg (LGL * lgl, int first, ...) {
+#ifndef NDEBUG
+  va_list ap;
+  Stk stk;
+  int lit;
+  if (!lgl->opts->check.val) return;
+  lglpicosatinit (lgl);
+  CLR (stk);
+  if (first) {
+    va_start (ap, first);
+    lglpushstk (lgl, &stk, first);
+    for (;;) {
+      lit = va_arg (ap, int);
+      if (!lit) break;
+      lglpushstk (lgl, &stk, lit);
+    }
+    va_end (ap);
+  }
+  lglpushstk (lgl, &stk, 0);
+  lglpicosatchkclsaux (lgl, stk.start);
+  lglrelstk (lgl, &stk);
+#endif
+}
+
+static void lglpicosatchkunsat (LGL * lgl) {
+#ifndef NDEBUG
+  int res, * p;
+  lglpicosatinit (lgl);
+  if (lgl->picosat.res) {
+    LOG (1, "determined earlier that PicoSAT proved unsatisfiability");
+    assert (lgl->picosat.res == 20);
+  }
+  if (picosat_inconsistent (PICOSAT)) {
+    LOG (1, "PicoSAT is already in inconsistent state");
+    return;
+  }
+  for (p = lgl->eassume.start; p < lgl->eassume.top; p++)
+    picosat_assume (PICOSAT, lglimport (lgl, *p));
+  res = picosat_sat (PICOSAT, -1);
+  assert (res == 20);
+  LOG (1, "PicoSAT proved unsatisfiability");
+#endif
+}
+#endif
+
+static void lglunitnocheck (LGL * lgl, int lit) {
+  ASSERT (!lgl->level);
+  LOG (1, "unit %d", lit);
+  lglassign (lgl, lit, (lit << RMSHFT) | UNITCS, 0);
+}
+
+#ifndef NLGLDRUPLIG
+static int lgldruplig (LGL * lgl) {
+  if (!lgl->opts->druplig.val) return 0;
+  if (!lgl->druplig) lgl->druplig = druplig_init ();
+  return 1;
+}
+#endif
+
+static void lgldrupligaddclsarg (LGL * lgl, int red, ...) {
+#ifndef NLGLDRUPLIG
+  if (lgldruplig (lgl)) {
+    va_list ap;
+    va_start (ap, red);
+    for (;;) {
+      int lit = va_arg (ap, int);
+      if (!lit) break;
+      druplig_add_literal (lgl->druplig, lglexport (lgl, lit));
+    }
+    if (red) druplig_check_and_add_redundant_clause (lgl->druplig);
+    else druplig_add_original_clause (lgl->druplig);
+  }
+#else
+  (void) lgl, (void) red;
+#endif
+}
+
+static void lglunit (LGL * lgl, int lit) {
+  if (lgl->opts->drup.val) lgldrupclsarg (lgl, lit, 0);
+#ifndef NLGLPICOSAT
+  lglpicosatchkclsarg (lgl, lit, 0);
+#endif
+  lgldrupligaddclsarg (lgl, REDCS, lglexport (lgl, lit), 0);
+  lglunitnocheck (lgl, lit);
+}
+
+static void lglmark (LGL * lgl, int lit) {
+  lglavar (lgl, lit)->mark = lglsgn (lit);
+}
+
+static void lglmarkunmarked (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  assert (!av->mark);
+  av->mark = lglsgn (lit);
+}
+
+static void lglunmark (LGL * lgl, int lit) { lglavar (lgl, lit)->mark = 0; }
+
+static void lglchksimpcls (LGL * lgl) {
+#ifndef NDEBUG
+  int *p, tmp, lit;
+  AVar * av;
+  for (p = lgl->clause.start; (lit = *p); p++) {
+    tmp = lglifixed (lgl, lit);
+    assert (!tmp);
+    av = lglavar (lgl, lit);
+    assert (!av->simp);
+    av->simp = 1;
+  }
+  while (p > lgl->clause.start)
+    lglavar (lgl,  *--p)->simp = 0;
+#endif
+}
+
+static int lglcval (LGL * lgl, int litorval) {
+  assert (litorval);
+  if (litorval == 1 || litorval == -1) return litorval;
+  return lglval (lgl, litorval);
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglsimpcls (LGL * lgl) {
+  int * p, * q = lgl->clause.start, lit, tmp, mark;
+  for (p = lgl->clause.start; (lit = *p); p++) {
+    tmp = lglcval (lgl, lit);
+    if (tmp == 1) { LOG (4, "literal %d satisfies clauses", lit); break; }
+    if (tmp == -1) { LOG (4, "removing false literal %d", lit); continue; }
+    mark = lglmarked (lgl, lit);
+    if (mark > 0)
+      { LOG (4, "removing duplicated literal %d", lit); continue; }
+    if (mark < 0)
+      { LOG (4, "literals %d and %d occur both", -lit, lit); break; }
+    *q++ = lit;
+    lglmark (lgl, lit);
+  }
+
+  *q = 0;
+  lgl->clause.top = q + 1;
+
+  while (q > lgl->clause.start) lglunmark (lgl, *--q);
+
+  if (lit) LOG (2, "simplified clause is trivial");
+  else LOGCLS (2, lgl->clause.start, "simplified clause");
+
+  return lit;
+}
+
+static void lglorderclsaux (LGL * lgl, int * start) {
+  int * p, max = 0, level, lit;
+  for (p = start; (lit = *p); p++) {
+    if (!lglval (lgl, lit)) continue;
+    level = lglevel (lgl, lit);
+    if (level <= max) continue;
+    max = level;
+    *p = start[0];
+    start[0] = lit;
+  }
+}
+
+static void lglordercls (LGL * lgl) {
+  assert (lglcntstk (&lgl->clause) > 2);
+  lglorderclsaux (lgl, lgl->clause.start);
+  LOG (3, "head literal %d", lgl->clause.start[0]);
+  lglorderclsaux (lgl, lgl->clause.start  + 1);
+  LOG (3, "tail literal %d", lgl->clause.start[1]);
+  LOGCLS (3, lgl->clause.start, "ordered clause");
+}
+/*------------------------------------------------------------------------*/
+
+
+static void lglfreewch (LGL * lgl, int oldoffset, int oldhcount) {
+  int ldoldhcount = lglceilld (oldhcount);
+  lgl->wchs->stk.start[oldoffset] = lgl->wchs->start[ldoldhcount];
+  assert (oldoffset);
+  lgl->wchs->start[ldoldhcount] = oldoffset;
+  lgl->wchs->free++;
+  assert (lgl->wchs->free > 0);
+  LOG (5, "saving watch stack at %d of size %d on free list %d",
+       oldoffset, oldhcount, ldoldhcount);
+}
+
+static void lglshrinkhts (LGL * lgl, HTS * hts, int newcount) {
+  int * p, i, oldcount = hts->count;
+  assert (newcount <= oldcount);
+  if (newcount == oldcount) return;
+  p = lglhts2wchs (lgl, hts);
+  for (i = newcount; i < oldcount; i++) p[i] = 0;
+  hts->count = newcount;
+  if (newcount) return;
+  lglfreewch (lgl, hts->offset, oldcount);
+  hts->offset = 0;
+}
+
+static long lglenlwchs (LGL * lgl, HTS * hts) {
+  int oldhcount = hts->count, oldoffset = hts->offset, newoffset;
+  int oldwcount, newwcount, oldwsize, newwsize, i, j;
+  int newhcount = oldhcount ? 2*oldhcount : 1;
+  int * oldwstart, * newwstart, * start;
+  int ldnewhcount = lglfloorld (newhcount);
+  long res = 0;
+
+  newhcount = (1<<ldnewhcount);
+  assert (newhcount > oldhcount);
+
+  LOG (5, "increasing watch stack at %d from %d to %d",
+       oldoffset, oldhcount, newhcount);
+
+  assert (!oldoffset == !oldhcount);
+
+  lgl->stats->enlwchs++;
+
+  newoffset = lgl->wchs->start[ldnewhcount];
+  start = lgl->wchs->stk.start;
+  if (newoffset != INT_MAX) {
+    lgl->wchs->start[ldnewhcount] = start[newoffset];
+    start[newoffset] = 0;
+    assert (lgl->wchs->free > 0);
+    lgl->wchs->free--;
+    LOG (5, "reusing free watch stack at %d of size %d",
+        newoffset, (1 << ldnewhcount));
+  } else {
+    assert (lgl->wchs->stk.start[hts->offset]);
+    assert (lgl->wchs->stk.top[-1] == INT_MAX);
+
+    oldwcount = lglcntstk (&lgl->wchs->stk);
+    newwcount = oldwcount + newhcount;
+    oldwsize = lglszstk (&lgl->wchs->stk);
+    newwsize = oldwsize;
+
+    assert (lgl->wchs->stk.top == lgl->wchs->stk.start + oldwcount);
+    assert (oldwcount > 0);
+
+    while (newwsize < newwcount) newwsize *= 2;
+    if (newwsize > oldwsize) {
+      newwstart = oldwstart = lgl->wchs->stk.start;
+      RSZ (newwstart, oldwsize, newwsize);
+      LOG (3, "resized global watcher stack from %d to %d",
+          oldwsize, newwsize);
+      res = newwstart - oldwstart;
+      if (res) {
+       LOG (3, "moved global watcher stack by %ld", res);
+       start = lgl->wchs->stk.start = newwstart;
+      }
+      lgl->wchs->stk.end = start + newwsize;
+    }
+    lgl->wchs->stk.top = start + newwcount;
+    lgl->wchs->stk.top[-1] = INT_MAX;
+    newoffset = oldwcount - 1;
+    LOG (5,
+        "new watch stack of size %d at end of global watcher stack at %d",
+        newhcount, newoffset);
+  }
+  assert (start == lgl->wchs->stk.start);
+  assert (start[0]);
+  j = newoffset;
+  for (i = oldoffset; i < oldoffset + oldhcount; i++) {
+    start[j++] = start[i];
+    start[i] = 0;
+  }
+  while (j < newoffset + newhcount)
+    start[j++] = 0;
+  assert (start + j <= lgl->wchs->stk.top);
+  hts->offset = newoffset;
+  if (oldhcount > 0) lglfreewch (lgl, oldoffset, oldhcount);
+  return res;
+}
+
+static long lglpushwch (LGL * lgl, HTS * hts, int wch) {
+  long res = 0;
+  int * wchs = lglhts2wchs (lgl, hts);
+  assert (sizeof (res) == sizeof (void*));
+  assert (hts->count >= 0);
+  if (wchs[hts->count]) {
+    res = lglenlwchs (lgl, hts);
+    wchs = lglhts2wchs (lgl, hts);
+  }
+  assert (!wchs[hts->count]);
+  assert (wch != INT_MAX);
+  wchs[hts->count++] = wch;
+  lgl->stats->pshwchs++;
+  assert (lgl->stats->pshwchs > 0);
+  return res;
+}
+
+static long lglwchbin (LGL * lgl, int lit, int other, int red) {
+  HTS * hts = lglhts (lgl, lit);
+  int cs = ((other << RMSHFT) | BINCS | red);
+  long res;
+  assert (red == 0 || red == REDCS);
+  res = lglpushwch (lgl, hts, cs);
+  LOG (3, "new %s binary watch %d blit %d", lglred2str (red), lit, other);
+  return res;
+}
+
+static long lglwchtrn (LGL * lgl, int a, int b, int c, int red) {
+  HTS * hts = lglhts (lgl, a);
+  int cs = ((b << RMSHFT) | TRNCS | red);
+  long res;
+  assert (red == 0 || red == REDCS);
+  res = lglpushwch (lgl, hts, cs);
+  res += lglpushwch (lgl, hts, c);
+  LOG (3, "new %s ternary watch %d blits %d %d", lglred2str (red), a, b, c);
+  return res;
+}
+
+static long lglwchlrg (LGL * lgl, int lit, int other, int red, int lidx) {
+  HTS * hts = lglhts (lgl, lit);
+  int blit = ((other << RMSHFT) | LRGCS | red);
+  long res = 0;
+  assert (red == 0 || red == REDCS);
+  res += lglpushwch (lgl, hts, blit);
+  res += lglpushwch (lgl, hts, lidx);
+#ifndef NLGLOG
+  {
+    int * p = lglidx2lits (lgl, red, lidx);
+    if (red)
+      LOG (3,
+          "watching %d with blit %d in red[%d][%d] %d %d %d %d%s",
+          lit, other, (lidx & GLUEMASK), (lidx >> GLUESHFT),
+          p[0], p[1], p[2], p[3], (p[4] ? " ..." : ""));
+    else
+      LOG (3,
+       "watching %d with blit %d in irr[%d] %d %d %d %d%s",
+       lit, other, lidx, p[0], p[1], p[2], p[3], (p[4] ? " ..." : ""));
+  }
+#endif
+  assert (sizeof (res) == sizeof (void*));
+  return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+static EVar * lglevar (LGL * lgl, int lit) {
+  int idx = abs (lit);
+  assert (1 <= idx && idx < lgl->nvars);
+  return lgl->evars + idx;
+}
+
+static int * lglepos (LGL * lgl, int lit) {
+  EVar * ev;
+  int * res;
+  ev = lglevar (lgl, lit);
+  res = &ev->pos;
+  return res;
+}
+
+static int lglecmp (LGL * lgl, int l, int k) {
+  return lglevar (lgl,k)->score - lglevar (lgl,l)->score;
+}
+
+#ifndef NDEBUG
+static void lglchkesched (LGL * lgl) {
+  int * p, parent, child, ppos, cpos, size, i, tmp;
+  Stk * s = &lgl->esched;
+  size = lglcntstk (s);
+  p = s->start;
+  for (ppos = 0; ppos < size; ppos++) {
+    parent = p[ppos];
+    tmp = *lglepos (lgl, parent);
+    assert (ppos == tmp);
+    for (i = 0; i <= 1; i++) {
+      cpos = 2*ppos + 1 + i;
+      if (cpos >= size) continue;
+      child = p[cpos];
+      tmp = *lglepos (lgl, child);
+      assert (cpos == tmp);
+      assert (lglecmp (lgl, parent, child) >= 0);
+    }
+  }
+}
+#endif
+
+static void lgleup (LGL * lgl, int lit) {
+  int child = lit, parent, cpos, ppos, * p, * cposptr, * pposptr;
+  Stk * s = &lgl->esched;
+  p = s->start;
+  cposptr = lglepos (lgl, child);
+  cpos = *cposptr;
+  assert (cpos >= 0);
+  while (cpos > 0) {
+    ppos = (cpos - 1)/2;
+    parent = p[ppos];
+    if (lglecmp (lgl, parent, lit) >= 0) break;
+    pposptr = lglepos (lgl, parent);
+    assert (*pposptr == ppos);
+    p[cpos] = parent;
+    *pposptr = cpos;
+    LOGESCHED (5, parent, "down from %d", ppos);
+    cpos = ppos;
+  }
+  if (*cposptr == cpos) return;
+#ifndef NLGLOG
+  ppos = *cposptr;
+#endif
+  *cposptr = cpos;
+  p[cpos] = lit;
+  LOGESCHED (5, lit, "up from %d", ppos);
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 2) lglchkesched (lgl);
+#endif
+}
+
+static void lgledown (LGL * lgl, int lit) {
+  int parent = lit, child, right, ppos, cpos;
+  int * p, * pposptr, * cposptr, size;
+  Stk * s = &lgl->esched;
+  size = lglcntstk (s);
+  p = s->start;
+  pposptr = lglepos (lgl, parent);
+  ppos = *pposptr;
+  assert (0 <= ppos);
+  for (;;) {
+    cpos = 2*ppos + 1;
+    if (cpos >= size) break;
+    child = p[cpos];
+    if (cpos + 1 < size) {
+      right = p[cpos + 1];
+      if (lglecmp (lgl, child, right) < 0)
+       cpos++, child = right;
+    }
+    if (lglecmp (lgl, child, lit) <= 0) break;
+    cposptr = lglepos (lgl, child);
+    assert (*cposptr = cpos);
+    p[ppos] = child;
+    *cposptr = ppos;
+    LOGESCHED (5, child, "up from %d", cpos);
+    ppos = cpos;
+  }
+  if (*pposptr == ppos) return;
+#ifndef NLGLOG
+  cpos = *pposptr;
+#endif
+  *pposptr = ppos;
+  p[ppos] = lit;
+  LOGESCHED (5, lit, "down from %d", cpos);
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 2) lglchkesched (lgl);
+#endif
+}
+
+static int lglifrozen (LGL * lgl, int ilit) {
+  int elit = lglexport (lgl, ilit);
+  Ext * ext = lglelit2ext (lgl, elit);
+  return ext->frozen || ext->tmpfrozen;
+}
+
+static void lglesched (LGL * lgl, int lit) {
+  AVar * av;
+  int * p;
+  Stk * s;
+  if (lgl->cceing) return;
+  if (lgl->cgrclosing) return;
+  if (lglifrozen (lgl, lit)) return;
+  if (!lglisfree (lgl, lit)) return;
+  if (lgl->donotsched) {
+    av = lglavar (lgl, lit);
+    if (lgl->eliminating && av->donotelm) return;
+    if (lgl->blocking && av->donotblk) return;
+  }
+  p = lglepos (lgl, lit);
+  s = &lgl->esched;
+  if (*p >= 0) return;
+  *p = lglcntstk (s);
+  lglpushstk (lgl, s, lit);
+  lgleup (lgl, lit);
+  lgledown (lgl, lit);
+  LOGESCHED (4, lit, "pushed");
+}
+
+/*------------------------------------------------------------------------*/
+
+static unsigned lglgcd (unsigned a, unsigned b) {
+  unsigned tmp;
+  assert (a), assert (b);
+  if (a < b) SWAP (unsigned, a, b);
+  while (b) tmp = b, b = a % b, a = tmp;
+  return a;
+}
+
+static uint64_t lglgcd64 (uint64_t a, uint64_t b) {
+  uint64_t tmp;
+  assert (a), assert (b);
+  if (a < b) SWAP (uint64_t, a, b);
+  while (b) tmp = b, b = a % b, a = tmp;
+  return a;
+}
+
+static int lglrandidxtrav (LGL * lgl, int (*fun)(LGL*,int idx)) {
+  int idx, delta, mod, prev, first, res;
+  first = mod = lglmax (lgl->nvars, 2);
+  idx = lglrand (lgl) % mod;
+  delta = lglrand (lgl) % mod;
+  if (!delta) delta++;
+  while (lglgcd (delta, mod) > 1)
+    if (++delta == mod) delta = 1;
+  res = 1;
+  LOG (2,
+    "random index traversal start %d delta %d mod %d",
+     idx, delta, mod);
+  while (res) {
+    if (idx >= 2 && !fun (lgl, idx)) res = 0;
+    else {
+      prev = idx;
+      idx += delta;
+      if (idx >= mod) idx -= mod;
+      if (idx == first) break;
+      if (first == mod) first = prev;
+    }
+  }
+  return res;
+}
+
+static int lglrem (LGL * lgl) {
+  int res = lgl->nvars;
+  if (!res) return 0;
+  assert (res >= 2);
+  res -= lgl->stats->fixed.current + 2;
+  assert (res >= 0);
+  return res;
+}
+
+static double lglpcnt (double n, double d) {
+  if (d <= 0 || !n) return 0.0;
+  return 100.0 * n / d;
+}
+
+static int lglecalc (LGL * lgl, EVar * ev) {
+  int oldscore = ev->score, o0 = ev->occ[0], o1 = ev->occ[1], newscore;
+  if (lgl->eliminating) {
+    if (lgl->opts->elmschedpure.val && (!o0 || !o1)) newscore = 0;
+    else if (lgl->opts->elmsched2b2.val && o0 <= 2 && o1 <= 2) newscore = 1;
+    else {
+      newscore = 0;
+      if (lgl->opts->elmschedsum.val) newscore += o0 + o1;
+      if (lgl->opts->elmschedmin.val) newscore += lglmin (o0, o1);
+      if (lgl->opts->elmschediff.val) newscore -= o0 < o1 ? o1-o0 : o0-o1;
+      if (lgl->opts->elmschedprod.val) {
+       int64_t tmp = newscore, prod = o0 * (int64_t) o1;
+       tmp += prod;
+       newscore = tmp <= INT_MAX ? tmp : INT_MAX;
+      }
+    }
+  } else {
+    assert (lgl->blocking);
+    if (lgl->opts->blkschedpure.val && (!o0 || !o1)) newscore = 0;
+    else if (lgl->opts->blksched2b2.val && o0 <= 2 && o1 <= 2) newscore = 1;
+    else {
+      newscore = 0;
+      if (lgl->opts->blkschedsum.val) newscore += o0 + o1;
+      if (lgl->opts->blkschedmin.val) newscore += lglmin (o0, o1);
+      if (lgl->opts->blkschedprod.val) {
+       int64_t tmp = newscore, prod = o0 * (int64_t) o1;
+       tmp += prod;
+       newscore = tmp <= INT_MAX ? tmp : INT_MAX;
+      }
+    }
+  }
+  ev->score = newscore;
+  return newscore - oldscore;
+}
+
+static int lglocc (LGL * lgl, int lit) {
+  if (!lgl->occs) return lglhts (lgl, lit)->count;
+  return lglevar (lgl, lit)->occ[lit < 0];
+}
+
+static void lglincocc (LGL * lgl, int lit) {
+  int idx, sign, change;
+  EVar * ev;
+  if (!lgl->occs) return;
+  idx = abs (lit), sign = (lit < 0);
+  ev = lglevar (lgl, lit);
+  assert (lglisfree (lgl, lit));
+  ev->occ[sign] += 1;
+  assert (ev->occ[sign] > 0);
+  change = lglecalc (lgl, ev);
+  LOG (3, "inc occ of %d now occs[%d] = %d %d",
+       lit, idx, ev->occ[0], ev->occ[1]);
+  if (ev->pos < 0) lglesched (lgl, idx);
+  else if (change > 0) lgledown (lgl, idx);
+  else if (change < 0) lgleup (lgl, idx);
+}
+
+static int lglisact (int act) { return NOTALIT <= act && act < REMOVED-1; }
+
+static int lglrescoreglue (LGL * lgl, int glue) {
+  int * c, * p, oldact, newact, count = 0;;
+  Stk * lir = lgl->red + glue;
+  for (c = lir->start; c < lir->top; c = p + 1) {
+    oldact = *c;
+    if (oldact == REMOVED) {
+      for (p = c + 1; p < lir->top && *p == REMOVED; p++)
+       ;
+      assert (p >= lir->top || *p < NOTALIT || lglisact (*p));
+      p--;
+    } else {
+      assert (NOTALIT <= oldact && oldact <= REMOVED - 1);
+      newact = NOTALIT + ((oldact - NOTALIT) + 1) / 2;
+      *c++ = newact;
+      LOGCLS (5, c, "rescoring activity from %d to %d of clause",
+             oldact - NOTALIT, newact - NOTALIT);
+      for (p = c; *p; p++)
+       ;
+      count++;
+    }
+  }
+  return count;
+}
+
+static void lglrescoreclauses (LGL * lgl) {
+  int glue, count = 0;;
+  lgl->stats->rescored.clauses++;
+  for (glue = 0; glue < MAXGLUE; glue++)
+    count += lglrescoreglue (lgl, glue);
+  lglprt (lgl, RVL, "[rescored-clauses-%d] rescored activity of %d clauses",
+    lgl->stats->rescored.clauses, count);
+}
+
+static void lglchkirrstats (LGL * lgl) {
+#if  0
+  int idx, sign, lit, blit, tag, red, other, other2, clauses, lits;
+  const int * p, * w, * eow, * c, * top;
+  HTS * hts;
+  clauses = lits = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       red = blit & REDCS;
+       if (red) continue;
+       if (tag == BINCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         lits += 2;
+       } else if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         lits += 3;
+       } else continue;
+       clauses++;
+      }
+    }
+  top = lgl->irr.top;
+  for (c = lgl->irr.start; c < top; c = p + 1) {
+    if (*(p = c) >= NOTALIT) continue;
+    while (*++p)
+      ;
+    lits += p - c;
+    clauses++;
+  }
+  assert (clauses == lgl->stats->irr.clauses.cur);
+  assert (lits == lgl->stats->irr.lits.cur);
+#else
+  (void) lgl;
+#endif
+}
+
+static void lglincirr (LGL * lgl, int size) {
+  if (size < 2) return;
+  lgl->stats->irr.clauses.cur++;
+  assert (lgl->stats->irr.clauses.cur > 0);
+  if (lgl->stats->irr.clauses.cur > lgl->stats->irr.clauses.max)
+    lgl->stats->irr.clauses.max = lgl->stats->irr.clauses.cur;
+  lgl->stats->irr.lits.cur += size;
+  assert (lgl->stats->irr.lits.cur >= size);
+  if (lgl->stats->irr.lits.cur > lgl->stats->irr.lits.max)
+    lgl->stats->irr.lits.max = lgl->stats->irr.lits.cur;
+  lgl->stats->irrprgss++;
+}
+
+static void lgldecirr (LGL * lgl, int size) {
+  assert (size >= 2);
+  assert (lgl->stats->irr.clauses.cur > 0);
+  lgl->stats->irr.clauses.cur--;
+  assert (lgl->stats->irr.lits.cur >= size);
+  lgl->stats->irr.lits.cur -= size;
+  assert (!lgl->stats->irr.clauses.cur == !lgl->stats->irr.lits.cur);
+  lgl->stats->irrprgss++;
+}
+
+static void lglbumplidx (LGL * lgl, int lidx) {
+  int glue = (lidx & GLUEMASK), * c, *ap, act;
+  Stk * lir = lgl->red + glue;
+  if (glue >= MAXGLUE) return;
+  lidx >>= GLUESHFT;
+  c = lir->start + lidx;
+  assert (lir->start < c && c < lir->end);
+  ap = c - 1;
+  act = *ap;
+  if (act < REMOVED - 1) {
+    LGLCHKACT (act);
+    act += 1;
+    LGLCHKACT (act);
+    *ap = act;
+  }
+  LOGCLS (4, c, "bumped activity to %d of glue %d clause", act-NOTALIT, glue);
+  lgl->stats->lir[glue].resolved++;
+  assert (lgl->stats->lir[glue].resolved > 0);
+  if (act >= REMOVED - 1) lglrescoreclauses (lgl);
+}
+
+static void lglincjwh (LGL * lgl, int lit, Flt inc) {
+  int ulit = lglulit (lit);
+  Flt old = lgl->jwh[ulit];
+  Flt new = lgladdflt (old, inc);
+  lgl->jwh[ulit] = new;
+}
+
+static int lglscaleglue (LGL * lgl, int origlue) {
+  int scaledglue, redglue;
+  assert (0 <= origlue);
+  if (origlue <= lgl->opts->gluekeep.val) scaledglue = 0;
+  else if (origlue >= lgl->opts->maxglue.val) scaledglue = MAXGLUE;
+  else {
+    redglue = origlue - lgl->opts->gluekeep.val;
+    assert (redglue >= 1);
+    switch (lgl->opts->gluescale.val) {
+      case 4:
+       scaledglue = lglceilsqrt32 (redglue);
+       if (scaledglue > MAXGLUE/2)
+        scaledglue = MAXGLUE/2 + 1 + lglceilld (scaledglue - MAXGLUE/2);
+       break;
+      case 3: scaledglue = 1 + lglceilld (redglue); break;
+      case 2: scaledglue = lglceilsqrt32 (redglue); break;
+      default: scaledglue = redglue; break;
+    }
+    assert (scaledglue > 0);
+    if (scaledglue > MAXGLUE) scaledglue = MAXGLUE;
+  }
+  if (lgl->opts->keepmaxglue.val && scaledglue == MAXGLUE)
+    scaledglue = MAXGLUE-1;
+  assert (0 <= scaledglue && scaledglue <= MAXGLUE);
+  return scaledglue;
+}
+
+static void lgldrupligaddcls (LGL * lgl, int red) {
+#ifndef NLGLDRUPLIG
+  if (lgldruplig (lgl)) {
+    const int * p;
+    int lit;
+    for (p = lgl->clause.start; p < lgl->clause.top; p++)
+      if ((lit = *p))
+       druplig_add_literal (lgl->druplig, lglexport (lgl, lit));
+    if (red) druplig_check_and_add_redundant_clause (lgl->druplig);
+    else druplig_add_original_clause (lgl->druplig);
+  }
+#else
+  (void) lgl, (void) red;
+#endif
+}
+
+static int lgladdcls (LGL * lgl, int red, int origlue, int force) {
+  int size, lit, other, other2, * p, lidx, unit, blit;
+  int scaledglue, prevglue;
+  Flt inc;
+  Val val;
+  Stk * w;
+  lgl->stats->prgss++;
+  if (lgl->eliminating) {
+    size = lglcntstk (&lgl->clause);
+    ADDSTEPS (elm.steps, size);
+  }
+  if (!red) lgl->stats->irrprgss++;
+  assert (!lglmtstk (&lgl->clause));
+  assert (!lgl->clause.top[-1]);
+  if (force) lglchksimpcls (lgl);
+#if !defined(NLGLPICOSAT) && !defined(NDEBUG)
+  lglpicosataddcls (lgl, lgl->clause.start);
+#endif
+  size = lglcntstk (&lgl->clause) - 1;
+  if (!red) lglincirr (lgl, size);
+  else if (size == 2) lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+  else if (size == 3) lgl->stats->red.trn++, assert (lgl->stats->red.trn > 0);
+  assert (size >= 0);
+  if (!size) {
+    LOG (1, "found empty clause");
+    lgl->mt = 1;
+    return 0;
+  }
+  lit = lgl->clause.start[0];
+  if (size == 1) {
+    assert (lglval (lgl, lit) >= 0);
+    if (!lglval (lgl, lit)) {
+      if (red) lglunit (lgl, lit);
+      else lglunitnocheck (lgl, lit);
+    }
+    return 0;
+  }
+  inc = lglflt (-size, 1);
+  other = lgl->clause.start[1];
+  if (size == 2) {
+    lglwchbin (lgl, lit, other, red);
+    lglwchbin (lgl, other, lit, red);
+    if (red) {
+      if (force && lglval (lgl, lit) < 0) lglf2rce (lgl, other, lit, REDCS);
+      if (force && lglval (lgl, other) < 0) lglf2rce (lgl, lit, other, REDCS);
+    } else if (lgl->dense) {
+      assert (!red);
+      lglincocc (lgl, lit);
+      lglincocc (lgl, other);
+    }
+    if (!red) lglincjwh (lgl, lit, inc), lglincjwh (lgl, other, inc);
+    return 0;
+  }
+  lglordercls (lgl);
+  lit = lgl->clause.start[0];
+  other = lgl->clause.start[1];
+  if (size == 3) {
+    other2 = lgl->clause.start[2];
+    lglwchtrn (lgl, lit, other, other2, red);
+    lglwchtrn (lgl, other, lit, other2, red);
+    lglwchtrn (lgl, other2, lit, other, red);
+    if (red) {
+      if (force && lglval (lgl, lit) < 0 && lglval (lgl, other) < 0)
+       lglf3rce (lgl, other2, lit, other, REDCS);
+      if (force && lglval (lgl, lit) < 0 && lglval (lgl, other2) < 0)
+       lglf3rce (lgl, other, lit, other2, REDCS);
+      if (force && lglval (lgl, other) < 0 && lglval (lgl, other2) < 0)
+       lglf3rce (lgl, lit, other, other2, REDCS);
+    } else if (lgl->dense) {
+      assert (!red);
+      lglincocc (lgl, lit);
+      lglincocc (lgl, other);
+      lglincocc (lgl, other2);
+    }
+    if (!red) lglincjwh (lgl, lit, inc),
+              lglincjwh (lgl, other, inc),
+             lglincjwh (lgl, other2, inc);
+    return 0;
+  }
+  assert (size > 3);
+  if (red) {
+    scaledglue = lglscaleglue (lgl, origlue);
+    lgl->stats->clauses.scglue += scaledglue;
+    if (scaledglue == MAXGLUE) lgl->stats->clauses.maxglue++;
+    else lgl->stats->clauses.nonmaxglue++;
+    w = lgl->red + scaledglue;
+    lidx = lglcntstk (w) + 1;
+    if (lidx > MAXREDLIDX) {
+      prevglue = scaledglue;
+      if (lidx > MAXREDLIDX) {
+       scaledglue = prevglue;
+       while (scaledglue + 1 < MAXGLUE && lidx > MAXREDLIDX) {
+         w = lgl->red + ++scaledglue;
+         lidx = lglcntstk (w) + 1;
+       }
+      }
+      if (lidx > MAXREDLIDX) {
+       scaledglue = prevglue;
+       while (scaledglue > 0 && lidx > MAXREDLIDX) {
+         w = lgl->red + --scaledglue;
+         lidx = lglcntstk (w) + 1;
+       }
+      }
+      if (lidx > MAXREDLIDX && scaledglue < MAXGLUE) {
+       w = lgl->red + (scaledglue = MAXGLUE);
+       lidx = lglcntstk (w) + 1;
+      }
+      if (lidx > MAXREDLIDX && scaledglue == MAXGLUE) {
+       lglbacktrack (lgl, 0);
+       lidx = lglcntstk (w);
+       assert (!lidx);
+      }
+      if (lidx > MAXREDLIDX)
+       lgldie (lgl, "number of redundant large clause literals exhausted");
+    }
+    lglpushstk (lgl, w, NOTALIT);
+    assert (lidx == lglcntstk (w));
+    lidx <<= GLUESHFT;
+    assert (0 <= lidx);
+    lidx |= scaledglue;
+    lgl->stats->lir[scaledglue].clauses++;
+    assert (lgl->stats->lir[scaledglue].clauses > 0);
+    lgl->stats->lir[scaledglue].added++;
+    assert (lgl->stats->lir[scaledglue].added > 0);
+  } else {
+    w = &lgl->irr;
+    lidx = lglcntstk (w);
+    scaledglue = 0;
+    if (lidx <= 0 && !lglmtstk (w))
+      lgldie (lgl, "number of irredundant large clause literals exhausted");
+  }
+  for (p = lgl->clause.start; (other2 = *p); p++)
+    lglpushstk (lgl, w, other2), lglincjwh (lgl, other2, inc);
+  lglpushstk (lgl, w, 0);
+  if (red) {
+    unit = 0;
+    for (p = lgl->clause.start; (other2 = *p); p++) {
+      val = lglval (lgl, other2);
+      assert (!force || val <= 0);
+      if (val < 0) continue;
+      if (unit) unit = INT_MAX;
+      else unit = other2;
+    }
+    if (force && unit && unit != INT_MAX) lglflrce (lgl, unit, red, lidx);
+  }
+  assert (red == 0 || red == REDCS);
+  if (!red || (red && scaledglue < MAXGLUE)) {
+    (void) lglwchlrg (lgl, lit, other, red, lidx);
+    (void) lglwchlrg (lgl, other, lit, red, lidx);
+  }
+  if (red && scaledglue != MAXGLUE) {
+    lglbumplidx (lgl, lidx);
+    lgl->stats->red.lrg++;
+  }
+  if (!red && lgl->dense >= 2) {
+    if (lidx > MAXIRRLIDX)
+      lgldie (lgl, "number of irredundant large clause literals exhausted");
+    blit = (lidx << RMSHFT) | OCCS;
+    for (p = lgl->clause.start; (other2 = *p); p++) {
+      lglincocc (lgl, other2);
+      lglpushwch (lgl, lglhts (lgl, other2), blit);
+    }
+  }
+  lglchkirrstats (lgl);
+  return lidx;
+}
+
+static void lgliadd (LGL * lgl, int ilit) {
+  int size;
+#ifndef NLGLOG
+  if (lglmtstk (&lgl->clause)) LOG (4, "opening irredundant clause");
+#endif
+  assert (abs (ilit) < 2 || abs (ilit) < lgl->nvars);
+  lglpushstk (lgl, &lgl->clause, ilit);
+  if (ilit) {
+    LOG (4, "added literal %d", ilit);
+  } else {
+    LOG (4, "closing irredundant clause");
+    LOGCLS (3, lgl->clause.start, "unsimplified irredundant clause");
+    if (!lglsimpcls (lgl)) {
+      lgldrupligaddcls (lgl, 0);
+      lgladdcls (lgl, 0, 0, 1);
+      lgl->stats->irr.clauses.add++;
+      size = lglcntstk (&lgl->clause) - 1;
+      assert (size >= 0);
+      lgl->stats->irr.lits.add += size;
+    }
+    lglclnstk (&lgl->clause);
+  }
+}
+
+static void lgleunassignall (LGL * lgl) {
+  int eidx;
+  for (eidx = 1; eidx <= lgl->maxext; eidx++)
+    lglelit2ext (lgl, eidx)->val = 0;
+}
+
+static void lglchkeassumeclean (LGL * lgl) {
+  assert (lglmtstk (&lgl->eassume));
+#ifndef NDEBUG
+  int eidx;
+  for (eidx = 1; eidx <= lgl->maxext; eidx++) {
+    Ext * ext = lglelit2ext (lgl, eidx);
+    assert (!ext->assumed);
+    assert (!ext->failed);
+  }
+#endif
+}
+
+static void lglchkassumeclean (LGL * lgl) {
+  assert (!lgl->failed);
+  assert (!lgl->assumed);
+  assert (!lgl->cassumed);
+  assert (!lgl->ncassumed);
+  assert (lglmtstk (&lgl->assume));
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 1) {
+    int idx;
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      AVar * av = lglavar (lgl, idx);
+      assert (!av->assumed);
+      assert (!av->failed);
+    }
+  }
+#endif
+}
+
+static void lglreset (LGL * lgl) {
+  int elit, ilit, erepr;
+  Ext * ext, * rext;
+  unsigned bit;
+  AVar * av;
+  if (lgl->state == RESET) return;
+  if (lgl->state <= USED) return;
+  assert (lgl->state & (UNKNOWN|SATISFIED|EXTENDED|UNSATISFIED|FAILED|LOOKED));
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  if (!lglmtstk (&lgl->eassume)) {
+    LOG (2, "resetting %d external assumptions", lglcntstk (&lgl->eassume));
+    while (!lglmtstk (&lgl->eassume)) {
+      elit = lglpopstk (&lgl->eassume);
+      ext = lglelit2ext (lgl, elit);
+      ext->assumed = 0;
+      if (ext->failed) {
+       ext->failed = 0;
+       erepr = lglerepr (lgl, elit);
+       if (erepr != elit) {
+         rext = lglelit2ext (lgl, erepr);
+         rext->failed = 0;
+       }
+      }
+    }
+  }
+  lglchkeassumeclean (lgl);
+  if (!lglmtstk (&lgl->assume)) {
+    LOG (2, "resetting %d internal assumptions", lglcntstk (&lgl->assume));
+    while (!lglmtstk (&lgl->assume)) {
+      ilit = lglpopstk (&lgl->assume);
+      av = lglavar (lgl, ilit);
+      bit = (1u << (ilit < 0));
+      assert (av->assumed & bit);
+      av->assumed &= ~bit;
+      av->failed &= ~bit;
+    }
+  }
+  if (!lglmtstk (&lgl->cassume)) {
+    assert (lgl->ncassumed);
+    LOG (2, "resetting assumed clause of size %d", lglcntstk (&lgl->cassume));
+    lglclnstk (&lgl->cassume);
+    lgl->cassumed = lgl->ncassumed = 0;
+  } else assert (!lgl->ncassumed), assert (!lgl->cassumed);
+  if (lgl->failed) {
+    LOG (2, "resetting internal failed assumption %d", lgl->failed);
+    lgl->failed = 0;
+  }
+  if (lgl->assumed) {
+    LOG (2, "resetting assumption queue level to 0 from %d", lgl->assumed);
+    lgl->assumed = 0;
+  }
+  lglchkassumeclean (lgl);
+#if !defined(NDEBUG) && !defined (NLGLPICOSAT)
+  if (lgl->picosat.res) {
+    LOG (2, "resetting earlier PicoSAT result %d", lgl->picosat.res);
+    lgl->picosat.res = 0;
+  }
+#endif
+  lgleunassignall (lgl);
+  if (lgl->cbs && lgl->cbs->term.done) {
+    LOG (2, "resetting forced termination done flag");
+    lgl->cbs->term.done = 0;
+  }
+  TRANS (RESET);
+}
+
+static void lgluse (LGL * lgl) {
+  if (lgl->state >= USED) return;
+  assert (lgl->state == UNUSED || lgl->state == OPTSET);
+  TRANS (USED);
+}
+
+static void lgleadd (LGL * lgl, int elit) {
+  int ilit;
+  lglreset (lgl);
+  if (elit) {
+    ilit = lglimport (lgl, elit);
+    LOG (4, "adding external literal %d as %d", elit, ilit);
+  } else {
+    ilit = 0;
+    LOG (4, "closing external clause");
+  }
+  lgliadd (lgl, ilit);
+#ifndef NCHKSOL
+  lglpushstk (lgl, &lgl->orig, elit);
+#endif
+}
+
+void lgladd (LGL * lgl, int elit) {
+  int eidx = abs (elit);
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("add %d", elit);
+  if (0 < eidx && eidx <= lgl->maxext) {
+    ext = lglelit2ext (lgl, elit);
+    ABORTIF (ext->melted, "adding melted literal %d", elit);
+  }
+  lgl->stats->calls.add++;
+  lgleadd (lgl, elit);
+  lgluse (lgl);
+  if (lgl->clone) lgladd (lgl->clone, elit);
+}
+
+static void lglisetphase (LGL * lgl, int lit, int phase) {
+  AVar * av;
+  if (lit < 0) lit = -lit, phase = -phase;
+  av = lglavar (lgl, lit);
+  av->fase = phase;
+  LOG (2, "setting phase of internal literal %d to %d", lit, phase);
+}
+
+static void lglesetphase (LGL * lgl, int elit, int phase) {
+  int ilit = lglimport (lgl, elit);
+  if (abs (ilit) >= 2) {
+    LOG (2, "setting phase of external literal %d to %d", elit, phase);
+    lglisetphase (lgl, ilit, phase);
+  } else LOG (2, "setting phase of external literal %d skipped", elit);
+}
+
+void lglsetphase (LGL * lgl, int elit) {
+  REQINITNOTFORKED ();
+  TRAPI ("setphase %d", elit);
+  ABORTIF (!elit, "invalid literal argument");
+  if (elit < 0) lglesetphase (lgl, -elit, -1);
+  else lglesetphase (lgl, elit, 1);
+  if (lgl->clone) lglsetphase (lgl->clone, elit);
+}
+
+void lglresetphase (LGL * lgl, int elit) {
+  REQINITNOTFORKED ();
+  TRAPI ("resetphase %d", elit);
+  ABORTIF (!elit, "invalid literal argument");
+  lglesetphase (lgl, elit, 0);
+  if (lgl->clone) lglresetphase (lgl->clone, elit);
+}
+
+static void lgleassume (LGL * lgl, int elit) {
+  int ilit, val;
+  unsigned bit;
+  AVar * av;
+  Ext * ext;
+  lglreset (lgl);
+  ilit = lglimport (lgl, elit);
+  LOG (2, "assuming external literal %d", elit);
+  bit = 1u << (elit < 0);
+  ext = lglelit2ext (lgl, elit);
+  if (!(ext->assumed & bit)) {
+    ext->assumed |= bit;
+    lglpushstk (lgl, &lgl->eassume, elit);
+  }
+  assert (!lgl->level);
+  if (!(val = lglcval (lgl, ilit))) {
+    av = lglavar (lgl, ilit);
+    bit = (1u << (ilit < 0));
+    if (av->assumed & bit) {
+      LOG (2, "internal literal %d already assumed", ilit);
+    } else {
+      av->assumed |= bit;
+      if (av->assumed & (bit^3))
+       LOG (2, "negation %d was also already assumed", -ilit);
+      lglpushstk (lgl, &lgl->assume, ilit);
+    }
+  } else if (val > 0) {
+    LOG (2, "externally assumed literal %d already fixed to true", elit);
+  } else {
+    assert (val < 0);
+    LOG (2, "externally assumed literal %d already fixed to false", elit);
+    if (ilit != -1) {
+      av = lglavar (lgl, ilit);
+      bit = (1u << (ilit < 0));
+      if (!(av->assumed & bit)) {
+       av->assumed |= bit;
+       lglpushstk (lgl, &lgl->assume, ilit);
+      }
+    }
+    if (!lgl->failed) lgl->failed = ilit;
+  }
+}
+
+static void lglecassume (LGL * lgl, int elit) {
+  LOG (2, "adding external literal %d to assumed clause", elit);
+}
+
+void lglassume (LGL * lgl, int elit) {
+  int eidx = abs (elit);
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("assume %d", elit);
+  lgl->stats->calls.assume++;
+  ABORTIF (!elit, "can not assume invalid literal 0");
+  if (0 < eidx && eidx <= lgl->maxext) {
+    ext = lglelit2ext (lgl, elit);
+    ABORTIF (ext->melted, "assuming melted literal %d", elit);
+  }
+  lgleassume (lgl, elit);
+  lgluse (lgl);
+  lglmelter (lgl);
+  if (lgl->clone) lglassume (lgl->clone, elit);
+}
+
+void lglcassume (LGL * lgl, int elit) {
+  int eidx = abs (elit);
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("cassume %d", elit);
+  lgl->stats->calls.cassume++;
+  if (0 < eidx && eidx <= lgl->maxext) {
+    ext = lglelit2ext (lgl, elit);
+    ABORTIF (ext->melted, "assuming melted literal %d", elit);
+  }
+  lglecassume (lgl, elit);
+  lgluse (lgl);
+  if (lgl->clone) lglcassume (lgl->clone, elit);
+}
+
+void lglfixate (LGL * lgl) {
+  const int  * p;
+  Stk eassume;
+  REQINITNOTFORKED ();
+  TRAPI ("fixate");
+  if (lgl->mt) return;
+  CLR (eassume);
+  for (p = lgl->eassume.start; p < lgl->eassume.top; p++)
+    lglpushstk (lgl, &eassume, *p);
+  for (p = eassume.start; p < eassume.top; p++)
+    lgleadd (lgl, *p), lgleadd (lgl, 0);
+  lglrelstk (lgl, &eassume);
+  lgluse (lgl);
+  if (lgl->clone) lglfixate (lgl->clone);
+}
+
+static void lglbonflict (LGL * lgl, int lit, int blit) {
+  assert (lglevel (lgl, lit) >= lglevel (lgl, blit >> RMSHFT));
+  assert (!lgliselim (lgl, blit >> RMSHFT));
+  assert (!lgliselim (lgl, lit));
+  lgl->conf.lit = lit;
+  lgl->conf.rsn[0] = blit;
+  LOG (2, "inconsistent %s binary clause %d %d",
+       lglred2str (blit & REDCS), lit, (blit >> RMSHFT));
+}
+
+static void lgltonflict (LGL * lgl, int lit, int blit, int other2) {
+  assert ((blit & MASKCS) == TRNCS);
+  assert (lglevel (lgl, lit) >= lglevel (lgl, blit >> RMSHFT));
+  assert (lglevel (lgl, lit) >= lglevel (lgl, other2));
+  assert (!lgliselim (lgl, blit >> RMSHFT));
+  assert (!lgliselim (lgl, other2));
+  assert (!lgliselim (lgl, lit));
+  lgl->conf.lit = lit;
+  lgl->conf.rsn[0] = blit;
+  lgl->conf.rsn[1] = other2;
+  LOG (2, "inconsistent %s ternary clause %d %d %d",
+       lglred2str (blit & REDCS), lit, (blit>>RMSHFT), other2);
+}
+
+static void lglonflict (LGL * lgl, int check, int lit, int red, int lidx) {
+  int glue;
+#if !defined (NLGLOG) || !defined (NDEBUG)
+  int * p, * c = lglidx2lits (lgl, red, lidx);
+#endif
+  assert (red == REDCS || !red);
+#ifndef NDEBUG
+  {
+    int found = 0;
+    for (p = c; *p; p++) {
+      if(*p == lit) found++;
+      assert (lglval (lgl, *p) <= -check);
+      assert (lglevel (lgl, lit) >= lglevel (lgl, *p));
+      assert (!lgliselim (lgl, lit));
+    }
+    assert (found == 1);
+  }
+#endif
+  lgl->conf.lit = lit;
+  lgl->conf.rsn[0] = red | LRGCS;
+  lgl->conf.rsn[1] = lidx;
+#ifndef NLGLOG
+  if (lgl->opts->log.val >= 2) {
+    lglogstart (lgl, 2, "inconsistent %s large clause", lglred2str (red));
+    for (p = c ; *p; p++)
+      fprintf (lgl->out, " %d", *p);
+    lglogend (lgl);
+  }
+#endif
+  if (red) {
+    glue = lidx & GLUEMASK;
+    lgl->stats->lir[glue].conflicts++;
+    assert (lgl->stats->lir[glue].conflicts > 0);
+  }
+}
+
+static void lgldeclscnt (LGL * lgl, int size, int red, int glue) {
+  assert (!red || red == REDCS);
+  if (!red) lgldecirr (lgl, size);
+  else if (size == 2) assert (lgl->stats->red.bin), lgl->stats->red.bin--;
+  else if (size == 3) assert (lgl->stats->red.trn), lgl->stats->red.trn--;
+  else {
+    assert (lgl->stats->red.lrg > 0);
+    lgl->stats->red.lrg--;
+    assert (lgl->stats->lir[glue].clauses > 0);
+    lgl->stats->lir[glue].clauses--;
+  }
+}
+
+static void lglrminc (LGL * lgl, const int * w, const int * eow) {
+  int inc;
+  assert (w <= eow);
+  assert (sizeof w < 8 || eow <= w + INT_MAX);
+  inc = eow - w;
+  assert (inc >= 0);
+  inc >>= lgl->opts->rmincpen.val;
+  inc++;
+  assert (lgl->blocking + lgl->eliminating + lgl->simpleprobing <= 1);
+  if (lgl->blocking) ADDSTEPS (blk.steps, inc);
+  else if (lgl->eliminating) ADDSTEPS (elm.steps, inc);
+  else if (lgl->simpleprobing) ADDSTEPS (prb.simple.steps, inc);
+}
+
+static void lglrmtwch (LGL * lgl, int lit, int other1, int other2, int red) {
+  int * p, blit, other, blit1, blit2, * w, * eow, tag;
+  HTS * hts;
+  assert (!red || red == REDCS);
+  LOG (3, "removing %s ternary watch %d blits %d %d",
+       lglred2str (red), lit, other1, other2);
+  hts = lglhts (lgl, lit);
+  assert (hts->count >= 2);
+  p = w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  lglrminc (lgl, w, eow);
+  blit1 = (other1 << RMSHFT) | red | TRNCS;
+  blit2 = (other2 << RMSHFT) | red | TRNCS;
+  for (;;) {
+    assert (p < eow);
+    blit = *p++;
+    tag = blit & MASKCS;
+    if (tag == BINCS || tag == OCCS) continue;
+    other = *p++;
+    if (tag == LRGCS) continue;
+    assert (tag == TRNCS);
+    if (blit == blit1 && other == other2) break;
+    if (blit == blit2 && other == other1) break;
+  }
+  while (p < eow) p[-2] = p[0], p++;
+  lglshrinkhts (lgl, hts, p - w - 2);
+}
+
+static void lglpopnunmarkstk (LGL * lgl, Stk * stk) {
+  while (!lglmtstk (stk))
+    lglavar (lgl, lglpopstk (stk))->mark = 0;
+}
+
+static void lglpopnunlcamarkstk (LGL * lgl, Stk * stk) {
+  while (!lglmtstk (stk))
+    lglavar (lgl, lglpopstk (stk))->lcamark = 0;
+}
+
+static int lglcamarked (LGL * lgl, int lit) {
+  switch (lglavar (lgl, lit)->lcamark) {
+    case 1: return (lit < 0) ? -1 : 1;
+    case 2: return (lit < 0) ? -2 : 2;
+    case 4: return (lit < 0) ? 1 : -1;
+    case 8: return (lit < 0) ? 2 : -2;
+    default: assert (!lglavar (lgl, lit)->lcamark); return 0;
+  }
+}
+
+static void lglcamark (LGL * lgl, int lit, int mark) {
+  int newmark;
+  AVar * av;
+  assert (mark == 1 || mark == 2);
+  av = lglavar (lgl, lit);
+  assert (!av->lcamark);
+  newmark = mark;
+  if (lit < 0) newmark <<= 2;
+  av->lcamark = newmark;
+  lglpushstk (lgl, &lgl->lcaseen, lit);
+  assert (lglcamarked (lgl, lit) == mark);
+  assert (lglcamarked (lgl, -lit) == -mark);
+}
+
+static int lglca (LGL * lgl, int a, int b) {
+  int blit, tag, mark, negmark, prevmark, c, res, prev, next, al, bl;
+  const int * p, * w, * eow;
+  HTS * hts;
+  if (!a) return b;
+  if (!b) return a;
+  if (a == b) return a;
+  if (a == -b) return 0;
+  al = lglevel (lgl, a);
+  bl = lglevel (lgl, b);
+  if (!al) return b;
+  if (!bl) return a;
+  assert (lglval (lgl, a) > 0);
+  assert (lglval (lgl, b) > 0);
+  assert (lglmtstk (&lgl->lcaseen));
+  lglcamark (lgl, a, 1);
+  lglcamark (lgl, b, 2);
+  res = next = 0;
+  while (next < lglcntstk (&lgl->lcaseen)) {
+    c = lglpeek (&lgl->lcaseen, next++);
+    assert (lglval (lgl, c) > 0);
+    assert (lglevel (lgl, c) > 0);
+    mark = lglcamarked (lgl, c);
+    assert (mark == 1 || mark == 2);
+    negmark = mark ^ 3;
+    hts = lglhts (lgl, c);
+    if (!hts->count) continue;
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    for (p = w; p < eow; p++) {
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      if (tag != BINCS) continue;
+      prev = -(blit >> RMSHFT);
+      if (!lglevel (lgl, prev)) continue;
+      if (lglval (lgl, prev) <= 0) continue;
+      if ((prevmark = lglcamarked (lgl, prev)) < 0) continue;
+      if (mark == prevmark) continue;
+      if (prevmark == negmark) { res = prev; goto DONE; }
+      lglcamark (lgl, prev, mark);
+    }
+  }
+DONE:
+  lglpopnunlcamarkstk (lgl, &lgl->lcaseen);
+  LOG (3, "least common ancestor of %d and %d is %d", a, b, res);
+  return res;
+}
+
+static void lglrmlwch (LGL * lgl, int lit, int red, int lidx) {
+  int blit, tag, * p, * q, * w, * eow, ored, olidx;
+  HTS * hts;
+#ifndef NLGLOG
+  p = lglidx2lits (lgl, red, lidx);
+  if (red)
+    LOG (3, "removing watch %d in red[%d][%d] %d %d %d %d%s",
+        lit, (lidx & GLUEMASK), (lidx >> GLUESHFT), p[0], p[1], p[2], p[3],
+        (p[4] ? " ..." : ""));
+  else
+    LOG (3, "removing watch %d in irr[%d] %d %d %d %d%s",
+        lit, lidx, p[0], p[1], p[2], p[3], (p[4] ? " ..." : ""));
+#endif
+  hts = lglhts (lgl, lit);
+  assert (hts->count >= 2);
+  p = w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  lglrminc (lgl, w, eow);
+  for (;;) {
+    assert (p < eow);
+    blit = *p++;
+    tag = blit & MASKCS;
+    if (tag == BINCS) continue;
+    if (tag == OCCS) { assert (lgl->dense); continue; }
+    olidx = *p++;
+    if (tag == TRNCS) continue;
+    assert (tag == LRGCS);
+    ored = blit & REDCS;
+    if (ored != red) continue;
+    if (olidx == lidx) break;
+  }
+  assert ((p[-2] & REDCS) == red);
+  assert (p[-1] == lidx);
+  for (q = p; q < eow; q++)
+    q[-2] = q[0];
+  lglshrinkhts (lgl, hts, q - w - 2);
+}
+
+static void lglpropsearch (LGL * lgl, int lit) {
+  int * q, * eos, blit, other, other2, other3, red, prev;
+  int tag, val, val2, lidx, * c, * l;
+  int64_t travs;
+  const int * p;
+  int visits;
+  long delta;
+  HTS * hts;
+
+  LOG (3, "propagating %d in search", lit);
+
+  assert (!lgl->simp);
+  assert (!lgl->lkhd);
+  assert (!lgl->probing);
+  assert (!lgl->lifting);
+  assert (!lgl->cliffing);
+  assert (!lgl->dense);
+  assert (!lgliselim (lgl, lit));
+  assert (lglval (lgl, lit) == 1);
+
+  hts = lglhts (lgl, -lit);
+  if (!hts->offset) return;
+  q = lglhts2wchs (lgl, hts);
+  assert (hts->count >= 0);
+  eos = q + hts->count;
+  visits = 0;
+  travs = 0;
+  for (p = q; p < eos; p++) {
+    visits++;
+    *q++ = blit = *p;
+    tag = blit & MASKCS;
+    if (tag != BINCS) {
+      assert (tag == TRNCS || tag == LRGCS);
+      *q++ = *++p;
+    }
+    other = (blit >> RMSHFT);
+    travs++;
+    val = lglval (lgl, other);
+    if (val > 0) continue;
+    red = blit & REDCS;
+    if (tag == BINCS) {
+      if (val < 0) { lglbonflict (lgl, -lit, blit); p++; break; }
+      lglf2rce (lgl, other, -lit, red);
+    } else if (tag == TRNCS) {
+      other2 = *p;
+      travs++;
+      val2 = lglval (lgl, other2);
+      if (val2 > 0) continue;
+      if (!val && !val2) continue;
+      if (val < 0 && val2 < 0) {
+       lgltonflict (lgl, -lit, blit, other2);
+       p++;
+       break;
+      }
+      if (!val) SWAP (int, other, other2);
+      else assert (val < 0);
+      lglf3rce (lgl, other2, -lit, other, red);
+    } else {
+      assert (tag == LRGCS);
+      assert (val <= 0);
+      lidx = *p;
+      travs++;
+      c = lglidx2lits (lgl, red, lidx);
+      other2 = c[0];
+      if (other2 == -lit) other2 = c[0] = c[1], c[1] = -lit;
+      else assert (c[1] == -lit);
+      if (other2 != other) {
+       other = other2;
+       travs++;
+       val = lglval (lgl, other);
+       if (val > 0) {
+         q[-2] = LRGCS | (other2 << RMSHFT) | red;
+         continue;
+       }
+      }
+      assert (!red || !lgliselim (lgl, other));
+      val2 = INT_MAX;
+      prev = -lit;
+      for (l = c + 2; (other2 = *l); l++) {
+       *l = prev;
+       travs++;
+       val2 = lglval (lgl, other2);
+       if (val2 >= 0) break;
+       assert (!red || !lgliselim (lgl, other));
+       prev = other2;
+      }
+      assert (val2 != INT_MAX);
+      if (other2 && val2 >= 0) {
+       c[1] = other2;
+       assert (other == c[0]);
+       delta = lglwchlrg (lgl, other2, other, red, lidx);
+       if (delta) p += delta, q += delta, eos += delta;
+       q -= 2;
+       continue;
+      }
+      while (l > c + 2) {
+       other3 = *--l;
+       *l = prev;
+       prev = other3;
+      }
+      assert (!other2 || val2 >= 0);
+      if (val < 0) {
+       lglonflict (lgl, 1, -lit, red, lidx);
+       p++;
+       break;
+      }
+      assert (!val);
+      lglflrce (lgl, other, red, lidx);
+    }
+  }
+  while (p < eos) *q++ = *p++;
+  lglshrinkhts (lgl, hts, hts->count - (p - q));
+  assert (!lgl->simp);
+
+  lgl->stats->visits.search += visits;
+  lgl->stats->travs.search += travs;
+}
+
+static int lglhbred (LGL * lgl, int subsumed, int red) {
+  int res = subsumed ? red : REDCS;
+  LOG (3, "hyber binary learned clause becomes %s", lglred2str (res));
+  return res;
+}
+
+static void lgldecocc (LGL *, int);    //TODO move scheduling ...
+
+static void lglrmlocc (LGL * lgl, int lit, int red, int lidx) {
+  int search, blit, tag, * p, * q, * w, * eow;
+  HTS * hts;
+  if (lgl->dense < 2) return;
+#ifndef NLGLOG
+  if (red) LOG (3, "removing occurrence %d in red[0][%d]", lit, lidx);
+  else LOG (3, "removing occurrence %d in irr[%d]", lit, lidx);
+#endif
+  assert (!red || red == REDCS);
+  hts = lglhts (lgl, lit);
+  assert (hts->count >= 1);
+  assert (lidx <= MAXIRRLIDX);
+  search = (lidx << RMSHFT) | OCCS | red;
+  assert (search >= 0);
+  p = w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  lglrminc (lgl, w, eow);
+  do {
+    assert (p < eow);
+    blit = *p++;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+  } while (blit != search);
+  assert (p[-1] == search);
+  for (q = p ; q < eow; q++)
+    q[-1] = q[0];
+  lglshrinkhts (lgl, hts, q - w - 1);
+}
+
+static void lglflushremovedoccs (LGL * lgl, int lit) {
+  HTS * hts = lglhts (lgl, lit);
+  int * w = lglhts2wchs (lgl, hts);
+  int * eow = w + hts->count;
+  int blit, tag, red, lidx;
+  int * p, * q, * c;
+  lglrminc (lgl, w, eow);
+  for (p = q = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == BINCS) *q++ = blit;
+    else if (tag == TRNCS) *q++ = blit, *q++ = *p;
+    else {
+      assert (tag == LRGCS || tag == OCCS);
+      if (!red) {
+       lidx = (tag == LRGCS) ? *p : (blit >> RMSHFT);
+       c = lglidx2lits (lgl, red, lidx);
+       if (c[0] == REMOVED) continue;
+      }
+      *q++ = blit;
+      if (tag == LRGCS) *q++ = *p;
+    }
+  }
+  lglshrinkhts (lgl, hts, q - w);
+}
+
+static void lglpropupdvisits (LGL * lgl, int visits, int64_t travs) {
+  if (lgl->lkhd) lgl->stats->visits.lkhd += visits;
+  else if (lgl->simp) lgl->stats->visits.simp += visits;
+  else lgl->stats->visits.search += visits;
+
+  if (lgl->lkhd) lgl->stats->travs.lkhd += travs;
+  else if (lgl->simp) lgl->stats->travs.simp += travs;
+  else lgl->stats->travs.search += travs;
+
+  if (lgl->basicprobing) ADDSTEPS (prb.basic.steps, visits);
+  if (lgl->simpleprobing) ADDSTEPS (prb.simple.steps, visits);
+  if (lgl->treelooking) ADDSTEPS (prb.treelook.steps, visits);
+  if (lgl->cceing) ADDSTEPS (cce.steps, visits);
+  if (lgl->cliffing) ADDSTEPS (cliff.steps, visits);
+}
+
+static void lglprop (LGL * lgl, int lit) {
+  int * p, * q, * eos, blit, other, other2, other3, red, prev;
+  int tag, val, val2, lidx, * c, * l, dom, hbred, subsumed;
+  int glue, flushoccs, visits;
+  int64_t travs;
+  long delta;
+  HTS * hts;
+  LOG (3, "propagating %d over ternary and large clauses", lit);
+  assert (!lgliselim (lgl, lit));
+  assert (lglval (lgl, lit) == 1);
+  hts = lglhts (lgl, -lit);
+  if (!hts->offset) return;
+  flushoccs = 0;
+  q = lglhts2wchs (lgl, hts);
+  assert (hts->count >= 0);
+  eos = q + hts->count;
+  visits = 0;
+  travs = 0;
+  for (p = q; p < eos; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    if (tag == OCCS) {
+      assert (lgl->dense);
+      assert (!red);
+      *q++ = blit;
+      continue;
+    }
+    visits++;
+    other = (blit >> RMSHFT);
+    travs++;
+    val = lglval (lgl, other);
+    if (tag == BINCS) {
+      *q++ = blit;
+      if (val > 0) continue;
+      if (red && lgliselim (lgl, other)) continue;
+      if (val < 0) {
+       lglbonflict (lgl, -lit, blit);
+       p++;
+       break;
+      }
+      assert (!val);
+      lglf2rce (lgl, other, -lit, red);
+    } else if (tag == TRNCS) {
+      *q++ = blit;
+      other2 = *++p;
+      *q++ = other2;
+      if (val > 0) continue;
+      travs++;
+      if (red && lgliselim (lgl, other)) continue;
+      val2 = lglval (lgl, other2);
+      if (val2 > 0) continue;
+      if (!val && !val2) continue;
+      if (red && lgliselim (lgl, other2)) continue;
+      if (val < 0 && val2 < 0) {
+       lgltonflict (lgl, -lit, blit, other2);
+       p++;
+       break;
+      }
+      if (!val) SWAP (int, other, other2); else assert (val < 0);
+      if (lgl->level &&
+         lgl->simp &&
+         lgl->opts->lhbr.val &&
+         !lgl->cgrclosing) {
+       assert (lgl->simp);
+       dom = lglgetdom (lgl, lit);
+       if (lglgetdom (lgl, -other) != dom) goto NO_HBR_JUST_F3RCE;
+       dom = lglca (lgl, lit, -other);
+       if (!dom) goto NO_HBR_JUST_F3RCE;
+       subsumed = (dom == lit || dom == -other);
+       hbred = lglhbred (lgl, subsumed, red);
+       LOG (2, "hyper binary resolved %s clause %d %d",
+            lglred2str (hbred), -dom, other2);
+        if (lgl->opts->drup.val) lgldrupclsarg (lgl, -dom, other2, 0);
+#ifndef NLGLPICOSAT
+       lglpicosatchkclsarg (lgl, -dom, other2, 0);
+#endif
+       if (subsumed) {
+         LOG (2, "subsumes %s ternary clause %d %d %d",
+              lglred2str (red), -lit, other, other2);
+         lglrmtwch (lgl, other2, other, -lit, red);
+         lglrmtwch (lgl, other, other2, -lit, red);
+         lgl->stats->hbr.sub++;
+         if (red) assert (lgl->stats->red.trn), lgl->stats->red.trn--;
+         else {
+           lgldecirr (lgl, 3);
+           if (lgl->dense) {
+             if (-dom == -lit) lgldecocc (lgl, other);
+             else { assert (-dom == other); lgldecocc (lgl, -lit); }
+           }
+         }
+       }
+       delta = 0;
+       if (dom == lit) {
+         LOG (3,
+    "replacing %s ternary watch %d blits %d %d with binary %d blit %d",
+         lglred2str (red), -lit, other, other2, -dom, other2);
+         assert (subsumed);
+         blit = (other2 << RMSHFT) | BINCS | hbred;
+         q[-2] = blit;
+         q--;
+       } else {
+         if (dom == -other) {
+           LOG (3, "removing %s ternary watch %d blits %d %d",
+                lglred2str (red), -lit, other, other2);
+           assert (subsumed);
+           q -= 2;
+         } else {
+           LOG (2, "replaces %s ternary clause %d %d %d as reason for %d",
+                lglred2str (red), -lit, other, other2, other2);
+           assert (!subsumed);
+           assert (abs (dom) != abs (lit));
+           assert (abs (other2) != abs (lit));
+         }
+         delta += lglwchbin (lgl, -dom, other2, hbred);
+       }
+       delta += lglwchbin (lgl, other2, -dom, hbred);
+       if (delta) p += delta, q += delta, eos += delta;
+       if (hbred) lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       else lglincirr (lgl, 2);
+       lglf2rce (lgl, other2, -dom, hbred);
+       lgl->stats->hbr.trn++;
+       lgl->stats->hbr.cnt++;
+       lgl->stats->prgss++;
+      } else {
+NO_HBR_JUST_F3RCE:
+       lglf3rce (lgl, other2, -lit, other, red);
+      }
+    } else {
+      assert (tag == LRGCS);
+      if (val > 0) goto COPYL;
+      lidx = p[1];
+      c = lglidx2lits (lgl, red, lidx);
+      other2 = c[0];
+      if (other2 >= NOTALIT) {
+       p++;
+       continue;
+      }
+      if (other2 == -lit) other2 = c[0] = c[1], c[1] = -lit;
+      if (other2 != other) {
+       other = other2;
+       travs++;
+       val = lglval (lgl, other);
+       blit = red;
+       blit |= LRGCS;
+       blit |= other2 << RMSHFT;
+       if (val > 0) goto COPYL;
+      }
+      if (red && lgliselim (lgl, other)) goto COPYL;
+      val2 = INT_MAX;
+      prev = -lit;
+      for (l = c + 2; (other2 = *l); l++) {
+       *l = prev;
+       travs++;
+       val2 = lglval (lgl, other2);
+       if (val2 >= 0) break;
+       if (red && lgliselim (lgl, other2)) break;
+       prev = other2;
+      }
+      assert (val2 != INT_MAX);
+      if (other2 && val2 >= 0) {
+       c[1] = other2;
+       assert (other == c[0]);
+       delta = lglwchlrg (lgl, other2, other, red, lidx);
+       if (delta) p += delta, q += delta, eos += delta;
+       p++;
+       continue;
+      }
+
+      while (l > c + 2) {
+       other3 = *--l;
+       *l = prev;
+       prev = other3;
+      }
+
+      if (other2 && val2 < 0) goto COPYL;
+
+      if (val < 0) {
+       lglonflict (lgl, 1, -lit, red, lidx);
+       break;
+      }
+
+      assert (!val);
+      if (lgl->level &&
+         lgl->simp &&
+         lgl->opts->lhbr.val &&
+         !lgl->cgrclosing) {
+       assert (lgl->simp);
+       dom = 0;
+       for (l = c; (other2 = *l); l++) {
+         if (other2 == other) continue;
+         travs++;
+         if (!lglevel (lgl, other2)) continue;
+         assert (lglval (lgl, other2) < 0);
+         if (!dom) dom = lglgetdom (lgl, -other);
+         if (dom != lglgetdom (lgl, -other2)) goto NO_HBR_JUST_FLRCE;
+       }
+       LOGCLS (2, c, "dominator %d for %s clause", dom, lglred2str (red));
+       dom = 0;
+       for (l = c; (other2 = *l); l++) {
+         if (other2 == other) continue;
+         if (!lglevel (lgl, other2)) continue;
+         dom = lglca (lgl, dom, -other2);
+       }
+       if (!dom) goto NO_HBR_JUST_FLRCE;
+       LOGCLS (2, c, "closest dominator %d", dom);
+       subsumed = 0;
+       for (l = c; !subsumed && (other2 = *l); l++)
+         subsumed = (dom == -other2);
+       assert (lit != dom || subsumed);
+       hbred = lglhbred (lgl, subsumed, red);
+       LOG (2, "hyper binary resolved %s clause %d %d",
+            lglred2str (hbred), -dom, other);
+        if (lgl->opts->drup.val) lgldrupclsarg (lgl, -dom, other, 0);
+#ifndef NLGLPICOSAT
+       lglpicosatchkclsarg (lgl, -dom, other, 0);
+#endif
+       if (subsumed) {
+         LOGCLS (2, c, "subsumes %s large clause", lglred2str (red));
+         lglrmlwch (lgl, other, red, lidx);
+         lgl->stats->hbr.sub++;
+         if (red) {
+           glue = lidx & GLUEMASK;
+           if (glue != MAXGLUE) {
+             assert (lgl->stats->red.lrg);
+             lgl->stats->red.lrg--;
+             assert (lgl->stats->lir[glue].clauses > 0);
+             lgl->stats->lir[glue].clauses--;
+           }
+         }
+         if (!red && lgl->dense) {
+           for (l = c; (other2 = *l); l++) {
+             if (other2 != -lit) lglrmlocc (lgl, other2, 0, lidx);
+             if (other2 == -dom) continue;
+             if (other2 == other) continue;
+             lgldecocc (lgl, other2);
+           }
+           flushoccs++;
+         }
+         if (red && glue < MAXGLUE) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+         for (l = c; *l; l++) *l = REMOVED;
+         if (!red) lgldecirr (lgl, l - c);
+         *l = REMOVED;
+       }
+       delta = 0;
+       if (dom == lit) {
+         assert (subsumed);
+         LOG (3,
+              "replacing %s large watch %d with binary watch %d blit %d",
+              lglred2str (red), -lit, -lit, -dom);
+         blit = (other << RMSHFT) | BINCS | hbred;
+         *q++ = blit, p++;
+       } else {
+         if (subsumed) {
+           LOG (3, "removing %s large watch %d", lglred2str (red), -lit);
+           p++;
+         } else {
+           LOGCLS (2, c,
+                   "%s binary clause %d %d becomes reasons "
+                   "for %d instead of %s large clause",
+                   lglred2str (hbred), -dom, other, other, lglred2str (red));
+           assert (hbred == REDCS);
+         }
+         delta += lglwchbin (lgl, -dom, other, hbred);
+       }
+       delta += lglwchbin (lgl, other, -dom, hbred);
+       if (delta) p += delta, q += delta, eos += delta;
+       if (hbred) lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       else lglincirr (lgl, 2);
+       lglf2rce (lgl, other, -dom, hbred);
+       lgl->stats->hbr.lrg++;
+       lgl->stats->hbr.cnt++;
+       lgl->stats->prgss++;
+       if (subsumed) continue;
+      } else {
+NO_HBR_JUST_FLRCE:
+       lglflrce (lgl, other, red, lidx);
+      }
+COPYL:
+      *q++ = blit;
+      *q++ = *++p;
+    }
+  }
+  while (p < eos) *q++ = *p++;
+  lglshrinkhts (lgl, hts, hts->count - (p - q));
+  if (flushoccs) lglflushremovedoccs (lgl, -lit);
+  lglpropupdvisits (lgl, visits, travs);
+}
+
+static void lglprop2 (LGL * lgl, int lit) {
+  int other, blit, tag, val, red, visits;
+  const int * p, * w, * eow;
+  int64_t travs;
+  HTS * hts;
+  LOG (3, "propagating %d over binary clauses", lit);
+  assert (!lgliselim (lgl, lit));
+  assert (lglval (lgl, lit) == 1);
+  visits = 0;
+  travs = 0;
+  hts = lglhts (lgl, -lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    visits++;
+    red = blit & REDCS;
+    other = blit >> RMSHFT;
+    travs++;
+    if (lgliselim (lgl, other)) { assert (red); continue; }
+    val = lglval (lgl, other);
+    if (val > 0) continue;
+    if (val < 0) { lglbonflict (lgl, -lit, blit); break; }
+    lglf2rce (lgl, other, -lit, red);
+  }
+
+  lglpropupdvisits (lgl, visits, travs);
+}
+
+static int lglbcp (LGL * lgl) {
+  int lit, trail, count;
+  assert (!lgl->mt);
+  assert (!lgl->conf.lit);
+  assert (!lgl->notfullyconnected);
+  count = 0;
+  while (!lgl->conf.lit) {
+    trail = lglcntstk (&lgl->trail);
+    if (lgl->next2 < trail) {
+      lit = lglpeek (&lgl->trail, lgl->next2++);
+      lglprop2 (lgl, lit);
+      continue;
+    }
+    if (lgl->next >= trail) break;
+    count++;
+    lit = lglpeek (&lgl->trail, lgl->next++);
+    lglprop (lgl, lit);
+  }
+  if (lgl->lkhd) ADDSTEPS (props.lkhd, count);
+  else if (lgl->simp) ADDSTEPS (props.simp, count);
+  else ADDSTEPS (props.search, count);
+  return !lgl->conf.lit;
+}
+
+static int lglbcpsearch (LGL * lgl) {
+  int lit, count = 0;
+  assert (!lgl->simp);
+  assert (!lgl->notfullyconnected);
+  while ((!lgl->failed || !lgl->level) &&
+        !lgl->conf.lit &&
+        lgl->next < lglcntstk (&lgl->trail)) {
+    lit = lglpeek (&lgl->trail, lgl->next++);
+    lglpropsearch (lgl, lit);
+    count++;
+  }
+  ADDSTEPS (props.search, count);
+  lgl->next2 = lgl->next;
+  if (lgl->conf.lit && lgl->failed) {
+    LOG (2, "inconsistency overwrites failed assumption %d", lgl->failed);
+    lgl->failed = 0;
+  }
+  return !lgl->conf.lit && !lgl->failed;
+}
+
+#ifndef NDEBUG
+static void lglchkclnvar (LGL * lgl) {
+  AVar * av;
+  int i;
+  for (i = 2; i < lgl->nvars; i++) {
+    av = lglavar (lgl, i);
+    assert (!av->mark);
+  }
+}
+#endif
+
+#ifdef RESOLVENT
+static int lglmaintainresolvent (LGL * lgl) {
+#ifndef NDEBUG
+  if (lgl->opts->check.val >= 1) return 1;
+#endif
+#ifndef NLGLOG
+  if (lgl->opts->log.val >= 2) return 1;
+#endif
+  return 0;
+}
+#endif
+
+static int lgldecision (LGL * lgl, int lit) {
+  int * rsn = lglrsn (lgl, lit);
+  int tag = rsn[0] & MASKCS;
+  return tag == DECISION;
+}
+
+static int lglassumption (LGL * lgl, int lit) {
+  return lglavar (lgl, lit)->assumed;
+}
+
+static int lglpull (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int level, res;
+  level = lglevel (lgl, lit);
+  if (!level) return 0;
+  if (av->mark) return 0;
+  av->mark = 1;
+  lglpushstk (lgl, &lgl->seen, lit);
+#ifdef RESOLVENT
+  if (lglmaintainresolvent (lgl)) {
+    lglpushstk (lgl, &lgl->resolvent, lit);
+    LOG (2, "adding %d to resolvent", lit);
+    LOGRESOLVENT (3, "resolvent after adding %d is", lit);
+  }
+#endif
+  if (level == lgl->level) {
+    LOG (2, "reason literal %d at same level %d", lit, lgl->level);
+    res = 1;
+  } else {
+    lglpushstk (lgl, &lgl->clause, lit);
+    LOG (2, "adding literal %d at upper level %d to 1st UIP clause",
+        lit, lglevel (lgl, lit));
+    if (!lglevelused (lgl, level)) {
+      lgluselevel (lgl, level);
+      lglpushstk (lgl, &lgl->frames, level);
+      LOG (2, "pulled in decision level %d", level);
+    }
+    res = 0;
+  }
+  return res;
+}
+
+static int lglpoison (LGL * lgl, int lit, Stk * stk, int local) {
+  AVar * av = lglavar (lgl, lit);
+  int level, res;
+  if (av->mark) res = 0;
+  else {
+    level = lglevel (lgl, lit);
+    if (!level) res = 0;
+    else {
+      assert (level < lgl->level);
+      if (lgldecision (lgl, lit)) res = 1;
+      else if (!lglevelused (lgl, level)) res = 1;
+      else {
+       lgl->stats->poison.search++;
+       if (av->poisoned) {
+         lgl->stats->poison.hits++;
+         res = 1;
+       } else if (local) res = 1;
+       else {
+         av->mark = 1;
+         lglpushstk (lgl, &lgl->seen, lit);
+         lglpushstk (lgl, stk, lit);
+         res = 0;
+       }
+      }
+    }
+  }
+  if (res && !av->poisoned) {
+    av->poisoned = 1;
+    lglpushstk (lgl, &lgl->poisoned, lit);
+  }
+  return res;
+}
+
+static int lglminclslit (LGL * lgl, int start, int local) {
+  int lit, tag, r0, r1, other, * p, * q, *top, old;
+  int poisoned, * rsn, found;
+  AVar * av, * bv;
+  assert (lglmarked (lgl, start));
+  lit = start;
+  rsn = lglrsn (lgl, lit);
+  r0 = rsn[0];
+  tag = (r0 & MASKCS);
+  if (tag == DECISION) return 0;
+  old = lglcntstk (&lgl->seen);
+  assert (lglmtstk (&lgl->minstk));
+  for (;;) {
+    r1 = rsn[1];
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      if (lglpoison (lgl, other, &lgl->minstk, local)) goto FAILED;
+      if (tag == TRNCS &&
+         lglpoison (lgl, r1, &lgl->minstk, local)) goto FAILED;
+    } else {
+      assert (tag == LRGCS);
+      p = lglidx2lits (lgl, (r0 & REDCS), r1);
+      found = 0;
+      while ((other = *p++)) {
+       if (other == -lit) found++;
+       else if (lglpoison (lgl, other, &lgl->minstk, local)) goto FAILED;
+      }
+      assert (found == 1);
+    }
+    if (lglmtstk (&lgl->minstk)) { lglrelstk (lgl, &lgl->minstk); return 1; }
+    lit = lglpopstk (&lgl->minstk);
+    assert (lglavar (lgl, lit)->mark);
+    rsn = lglrsn (lgl, lit);
+    r0 = rsn[0];
+    tag = (r0 & MASKCS);
+  }
+FAILED:
+  lglclnstk (&lgl->minstk);
+  p = lgl->seen.top;
+  top = lgl->seen.top = lgl->seen.start + old;
+  while (p > top) {
+    lit = *--p;
+    av = lglavar (lgl, lit);
+    assert (av->mark);
+    av->mark = 0;
+    poisoned = av->poisoned;
+    if (poisoned) continue;
+    rsn = lglrsn (lgl, lit);
+    r0 = rsn[0];
+    tag = (r0 & MASKCS);
+    assert (tag != DECISION);
+    r1 = rsn[1];
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      bv = lglavar (lgl, other);
+      if (bv->poisoned) poisoned = 1;
+      else if (tag == TRNCS) {
+       bv = lglavar (lgl, r1);
+       if (bv->poisoned) poisoned = 1;
+      }
+    } else {
+      assert (tag == LRGCS);
+      q = lglidx2lits (lgl, (r0 & REDCS), r1);
+      while (!poisoned && (other = *q++))
+       poisoned = lglavar (lgl, other)->poisoned;
+    }
+    if (!poisoned) continue;
+    assert (!av->poisoned);
+    av->poisoned = 1;
+    lglpushstk (lgl, &lgl->poisoned, lit);
+  }
+  return 0;
+}
+
+double lglprocesstime (void) {
+  struct rusage u;
+  double res;
+  if (getrusage (RUSAGE_SELF, &u)) return 0;
+  res = u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec;
+  res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec;
+  return res;
+}
+
+static double lglgetime (LGL * lgl) {
+  if (lgl->cbs && lgl->cbs->getime) return lgl->cbs->getime ();
+  else return lglprocesstime ();
+}
+
+static void lglstart (LGL * lgl, double * timestatsptr) {
+  int nest = lgl->timers->nest;
+  assert (timestatsptr);
+  assert (nest < MAXPHN);
+  assert ((double*) lgl->times <= timestatsptr);
+  assert (timestatsptr < (double*)(sizeof *lgl->times + (char*) lgl->times));
+  lgl->timers->idx[nest] = timestatsptr - (double*)lgl->times;
+  lgl->timers->phase[nest] = lglgetime (lgl);
+  lgl->timers->nest++;
+}
+
+void lglflushtimers (LGL * lgl) {
+  double time = lglgetime (lgl), delta, entered, * ptr;
+  int nest;
+  for (nest = 0; nest < lgl->timers->nest; nest++) {
+    entered = lgl->timers->phase[nest];
+    lgl->timers->phase[nest] = time;
+    delta = time - entered;
+    if (delta < 0) delta = 0;
+    ptr = lgl->timers->idx[nest] + (double*)lgl->times;
+    *ptr += delta;
+  }
+}
+
+double lglsec (LGL * lgl) {
+  REQINIT ();
+  lglflushtimers (lgl);
+  return lgl->times->all;
+}
+
+static void lglstop (LGL * lgl) {
+  lglflushtimers (lgl);
+  lgl->timers->nest--;
+  assert (lgl->timers->nest >= 0);
+}
+
+double lglmaxmb (LGL * lgl) {
+  REQINIT ();
+  return (lgl->stats->bytes.max + sizeof *lgl) / (double)(1<<20);
+}
+
+size_t lglbytes (LGL * lgl) {
+  REQINIT ();
+  return lgl->stats->bytes.current;
+}
+
+double lglmb (LGL * lgl) {
+  REQINIT ();
+  return (lgl->stats->bytes.current + sizeof *lgl) / (double)(1<<20);
+}
+
+static double lglagility (LGL * lgl) { return lgl->flips/1e7; }
+
+static double lglavg (double n, double d) {
+  return d != 0 ? n / d : 0.0;
+}
+
+static double lglheight (LGL * lgl) {
+  return lglavg (lgl->stats->height, lgl->stats->decisions);
+}
+
+static double lglglue (LGL * lgl) {
+  return lglavg (lgl->stats->glues.sum, lgl->stats->glues.count);
+}
+
+static void lglrephead (LGL * lgl) {
+  if (lgl->tid > 0) return;
+  lgl->forcerephead = 0;
+  lgl->repcntdown = REPMOD;
+  if (lgl->tid > 0) return;
+  if (lgl->cbs && lgl->cbs->msglock.lock)
+    lgl->cbs->msglock.lock (lgl->cbs->msglock.state);
+  assert (lgl->prefix);
+  fprintf (lgl->out, "%s\n", lgl->prefix);
+  fprintf (lgl->out, "%s%s"
+" seconds         irredundant          redundant clauses agility  "
+" height\n", lgl->prefix, !lgl->tid ? "  " : "");
+  fprintf (lgl->out, "%s%s"
+"         variables clauses conflicts large ternary binary    "
+"glue         MB\n", lgl->prefix, !lgl->tid ? "  " : "");
+  fprintf (lgl->out, "%s\n", lgl->prefix);
+  fflush (lgl->out);
+  if (lgl->cbs && lgl->cbs->msglock.unlock)
+    lgl->cbs->msglock.unlock (lgl->cbs->msglock.state);
+}
+
+static void lglrep (LGL * lgl, int level, char type) {
+  if (lgl->opts->verbose.val < level) return;
+  if ((level > 0 && lgl->forcerephead) || !lgl->repcntdown--)
+    lglrephead (lgl);
+  lglprt (lgl, level,
+         "%c %6.1f %7d %8d %9lld %7d %6d %5d %3.0f %4.1f %5.1f %4.0f",
+         type,
+         lgl->opts->abstime.val ? lglgetime (lgl) : lglsec (lgl),
+         lglrem (lgl),
+         lgl->stats->irr.clauses.cur,
+         (LGLL) lgl->stats->confs,
+         lgl->stats->red.lrg,
+         lgl->stats->red.trn,
+         lgl->stats->red.bin,
+         lglagility (lgl),
+         lglglue (lgl),
+         lglheight (lgl),
+         lglmb (lgl));
+  lgl->stats->reported++;
+}
+
+static void lglflshrep (LGL * lgl) {
+  if (!lgl->stats->reported) return;
+  if (lgl->stats->reported % REPMOD) lglrephead (lgl);
+  else lglprt (lgl, 1, "");
+}
+
+static void lglfitlir (LGL * lgl, Stk * lir) {
+  lglfitstk (lgl, lir);
+}
+
+static void lglchkred (LGL * lgl) {
+#ifndef NDEBUG
+  int glue, idx, sign, lit, thisum, sum, sum2, sum3;
+  int blit, tag, red, other, other2;
+  int * p, * c, * w, * eow;
+  HTS * hts;
+  Stk * lir;
+  if (lgl->mt) return;
+  sum = 0;
+  for (glue = 0; glue < MAXGLUE; glue++) {
+    lir = lgl->red + glue;
+    thisum = 0;
+    for (c = lir->start; c < lir->top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      while (*p) p++;
+      assert (p - c >= 4);
+      thisum++;
+    }
+    assert (thisum == lgl->stats->lir[glue].clauses);
+    sum += thisum;
+  }
+  assert (sum == lgl->stats->red.lrg);
+  sum2 = sum3 = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (!red || tag == LRGCS || tag == OCCS) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < idx) continue;
+       if (tag == BINCS) sum2++;
+       else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         sum3++;
+       }
+      }
+    }
+  assert (sum2 == lgl->stats->red.bin);
+  assert (sum3 == lgl->stats->red.trn);
+#endif
+}
+
+static int lglcmppasl (LGL * lgl, PASL * a, PASL * b, int glueuseless) {
+  int res, psmval, psmdiff, aglue, bglue, gluediff;
+  psmdiff = a->psm - b->psm;
+  psmval = lgl->opts->psm.val;
+  if (psmval == 3 && psmdiff) return psmdiff;
+  aglue = (a->lidx & GLUEMASK);
+  bglue = (b->lidx & GLUEMASK);
+  gluediff = aglue - bglue;
+  if (!glueuseless && gluediff) return gluediff;
+  if (psmval == 2 && psmdiff) return psmdiff;
+  if ((res = (a->act - b->act))) return res;
+  if (psmval == 1 && psmdiff) return psmdiff;
+  if ((res = (b->size - a->size))) return res;
+  if (glueuseless && gluediff) return gluediff;
+  return a->lidx - b->lidx;
+}
+
+#define LGLCMPPASL(A,B) lglcmppasl (lgl, (A), (B), glueuseless)
+
+static int lglneedacts (LGL * lgl,
+                       int * glueuselessptr,
+                       int * needmoreclausesptr) {
+  int64_t clauses = 0, weighted = 0, tmp, avg, var = 0, std, delta;
+  int glue, maxglue = 0;
+
+  for (glue = 0; glue <= MAXGLUE; glue++) {
+    tmp = lgl->stats->lir[glue].clauses;
+    if (tmp) maxglue = glue;
+    clauses += tmp;
+    weighted += glue * tmp;
+  }
+  avg = clauses ? (10*weighted)/clauses : 0;
+  lglprt (lgl, 2,
+    "[needacts-%d] existing clauses glue average %.1f",
+    lgl->stats->reduced.count, avg/10.0);
+  for (glue = 1; glue <= MAXGLUE; glue++) {
+    delta = (10*glue - avg);
+    var += delta*delta * lgl->stats->lir[glue].clauses;
+  }
+  var = clauses ? var / clauses : 0;
+  std = lglceilsqrt64 (var);
+  lglprt (lgl, 2,
+    "[needacts-%d] existing clauses glue standard deviation %.1f",
+    lgl->stats->reduced.count, std/10.0);
+
+  if (std < lgl->opts->actgsdul.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] glue useless since standard deviation %.1f < %.1f",
+      lgl->stats->reduced.count, std/10.0, lgl->opts->actgsdul.val/10.0);
+    *glueuselessptr = 1;
+  } else {
+    lglprt (lgl, 2,
+      "[needacts-%d] glue useful since standard deviation %.1f >= %.1f",
+      lgl->stats->reduced.count, std/10.0, lgl->opts->actgsdul.val/10.0);
+    *glueuselessptr = 0;
+  }
+
+  if (maxglue <= lgl->opts->actgeomlim.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] really need more clauses since maxglue %d <= %d",
+      lgl->stats->reduced.count, maxglue, lgl->opts->actgeomlim.val);
+    *needmoreclausesptr = 2;
+  } else if (maxglue <= lgl->opts->actdblarithlim.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] could use more clauses since maxglue %d <= %d",
+      lgl->stats->reduced.count, maxglue, lgl->opts->actdblarithlim.val);
+    *needmoreclausesptr = 1;
+  } else {
+    lglprt (lgl, 2,
+      "[needacts-%d] no need for more clauses since maxglue %d > %d",
+      lgl->stats->reduced.count, maxglue, lgl->opts->actdblarithlim.val);
+    *needmoreclausesptr = 0;
+  }
+
+  if (lglrem (lgl) > lgl->opts->actvlim.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] too many variables %d > %d",
+      lgl->stats->reduced.count, lglrem (lgl), lgl->opts->actvlim.val);
+    return 0;
+  }
+  if (avg > lgl->opts->actavgmax.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] very large average glue %.1f > %.1f",
+      lgl->stats->reduced.count, avg/10.0, lgl->opts->actavgmax.val/10.0);
+    return 1;
+  }
+  if (std <= lgl->opts->actstdmin.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] very small standard deviation glue %.1f <= %.1f",
+      lgl->stats->reduced.count, std/10.0, lgl->opts->actstdmin.val/10.0);
+    return 1;
+  }
+  if (std > lgl->opts->actstdmax.val) {
+    lglprt (lgl, 2,
+      "[needacts-%d] very large standard deviation glue %.1f > %.1f",
+      lgl->stats->reduced.count, std/10.0, lgl->opts->actstdmax.val/10.0);
+    return 1;
+  }
+
+  lglprt (lgl, 2,
+    "[needacts-%d] regular glue average and standard deviation",
+    lgl->stats->reduced.count);
+
+  return 0;
+}
+
+static int lglagile (LGL * lgl) {
+  switch (lgl->opts->agile.val) {
+    case 1:
+      return lgl->flips >= lgl->opts->agilelim.val * 10000000ull;
+    case 2:
+      return lgl->flips >=
+       (50*(sin(lgl->stats->confs*M_PI/2.0/lgl->opts->agilesinint.val) + 1))
+       * 10000000ull;
+  }
+ return 0;
+}
+
+static int lglsaturating (LGL * lgl) {
+  int64_t avglue, avgheight;
+  if (!lgl->opts->saturating.val) return 0;
+  if (!lgl->stats->glues.count) return 0;
+  if (!lgl->stats->decisions) return 0;
+  avglue = lgl->stats->glues.sum;
+  avglue *= 100 + lgl->opts->saturating.val;
+  avglue /= lgl->stats->glues.count;
+  avgheight = lgl->stats->height;
+  avgheight *= 100;
+  avgheight /= lgl->stats->decisions;
+  return avglue >= avgheight;
+}
+
+static void lglboundredl (LGL * lgl) {
+  int64_t minabs, minrel, maxabs, maxrel, oldlim, newlim;
+
+  newlim = oldlim = lgl->limits->reduce.inner;
+  if (!lgl->opts->redlbound.val) goto SKIP;
+
+  lglprt (lgl, 2, 
+    "[bound-reduce-limit] preliminary reduce limit %d before bounding",
+    oldlim);
+
+  minrel = lgl->opts->redlminrel.val;
+  minrel *= (lgl->stats->irr.clauses.cur + 99ll)/100ll;
+  minabs = lgl->opts->redlminabs.val;
+
+  lglprt (lgl, 2, "[bound-reduce-limit] minrel = %d, minabs = %d",
+    minrel, minabs);
+
+  if (minrel < minabs) {
+    if (minrel > lgl->limits->reduce.inner) {
+      lglprt (lgl, 2, 
+        "[bound-reduce-limit] relative minimum reduce limit %d hit", minrel);
+      newlim = minrel;
+    }
+  } else {
+    if (minabs > lgl->limits->reduce.inner) {
+      lglprt (lgl, 2, 
+        "[bound-reduce-limit] absolute minimum reduce limit of %d hit",
+       minabs);
+      newlim = minabs;
+    }
+  }
+
+  maxrel = lgl->opts->redlmaxrel.val;
+  maxrel *= (lgl->stats->irr.clauses.cur + 99ll)/100ll;
+  maxrel += lgl->opts->redlmininc.val * (int64_t) lgl->limits->reduce.extra;
+  maxabs = lgl->opts->redlmaxabs.val;
+
+  lglprt (lgl, 2,
+    "[bound-reduce-limit] maxrel = %d, maxabs = %d", maxrel, maxabs);
+
+  if (maxrel < maxabs) {
+    lgl->limits->reduce.extra++;
+    if (maxrel < lgl->limits->reduce.inner) {
+      lglprt (lgl, 2, 
+        "[bound-reduce-limit] relative maximum reduce limit %d hit", maxrel);
+      newlim = maxrel;
+    }
+  } else {
+    if (maxabs < lgl->limits->reduce.inner) {
+      lglprt (lgl, 2,
+        "[bound-reduce-limit] absolute maximum reduce limit of %d hit",
+       maxabs);
+      newlim = maxabs;
+    }
+  }
+
+SKIP:
+
+  lgl->limits->reduce.inner = newlim;
+  lglprt (lgl, 2,
+    "[bound-reduce-limit] new reduce limit of %d after %lld conflicts",
+    lgl->limits->reduce.inner, (LGLL) lgl->stats->confs);
+}
+
+static int64_t lglubyrec (LGL * lgl, int i) {
+  int64_t res = 0, s = 0;
+  int k;
+
+  for (k = 1; !res && k < 32; s++, k++) {
+    if (i == (1 << k) - 1)
+      res = 1 << (k - 1);
+  }
+
+  for (k = 1; !res; k++, s++)
+    if ((1 << (k - 1)) <= i && i < (1 << k) - 1)
+      res = lglubyrec (lgl, i - (1 << (k-1)) + 1);
+
+  lgl->stats->luby.steps += s;
+
+  assert (res > 0);
+  return res;
+}
+
+static int64_t lgluby (LGL * lgl, int i) {
+  assert (i > 0);
+  lgl->stats->luby.count++;
+  return lglubyrec (lgl, i);
+}
+
+static int64_t lglinout (LGL * lgl, int c, int relincpcnt) {
+  int64_t i = 1, o = 1;
+
+  assert (c > 0);
+
+  lgl->stats->inout.count++;
+  lgl->stats->inout.steps += c;
+
+  while (c-- > 0) {
+    i = ((100 + relincpcnt)*i + 99)/100;
+    if (i < o) continue;
+    i = 1;
+    o = ((100 + relincpcnt)*o + 99)/100;
+  }
+
+  assert (i > 0);
+  return i;
+}
+
+static int lglmemout (LGL * lgl) {
+  size_t cur;
+  int res;
+  if (lgl->opts->memlim.val < 0) return 0;
+  cur = lgl->stats->bytes.current;
+  cur >>= 20;
+  res = (cur >= lgl->opts->memlim.val);
+  if (res)
+    lglprt (lgl, 2, "memory limit of %d MB hit after allocating %lld MB",
+      lgl->opts->memlim.val, (LGLL) cur);
+  return res;
+}
+
+static Val lgliphase (LGL * lgl, int lit) {
+  Val res = lglavar (lgl, lit)->phase;
+  if (lit < 0) res = -res;
+  return res;
+}
+
+static void lglreduce (LGL * lgl, int forced) {
+  int * p, * q, * start, * c, ** maps, * sizes, * map, * eow, * rsn;
+  int nlocked, collected, sumcollected, nunlocked, moved, act, psm;
+  int glue, minredglue, maxredglue, target, rem, nkeep;
+  int inc, acts, glueuseless, needmoreclauses, delta;
+  PASL * pasls, * pasl; int npasls, szpasls;
+  int size, idx, tag, red, i, blit;
+  int r0, lidx, src, dst, lit;
+  char type = '-';
+  int64_t outer;
+  HTS * hts;
+  DVar * dv;
+  Stk * lir;
+  lglchkred (lgl);
+  lglstart (lgl, &lgl->times->red);
+  lgl->stats->reduced.count++;
+  LOG (1, "starting reduction %d", lgl->stats->reduced.count);
+  acts = lglneedacts (lgl, &glueuseless, &needmoreclauses);
+  delta = lgl->stats->red.lrg;
+  delta -= lgl->lrgluereasons;
+  delta -= lgl->stats->lir[0].clauses;
+  assert (delta >= 0);
+  if (delta > 3*lgl->limits->reduce.inner/2)
+    target = delta - lgl->limits->reduce.inner/2;
+  else target = delta/2;
+  rem = target;
+  LOG (2, "target is to collect %d clauses out of %d", target, delta);
+  for (maxredglue = MAXGLUE-1; maxredglue >= 0; maxredglue--)
+    if (lgl->stats->lir[maxredglue].clauses > 0) break;
+  LOG (2, "maximum reduction glue %d", maxredglue);
+  if (lgl->opts->acts.val < 2) acts = lgl->opts->acts.val;
+  if (acts) {
+    lgl->stats->acts++;
+    lglprt (lgl, 2,
+      "[needacts-%d] using primarily activities for reduction",
+      lgl->stats->reduced.count);
+    szpasls = lgl->stats->red.lrg;
+    minredglue = 1;
+  } else {
+    lglprt (lgl, 2,
+      "[needacts-%d] using primarily glues for reduction",
+      lgl->stats->reduced.count);
+    pasls = 0;
+    if (maxredglue > 0) {
+      for (minredglue = maxredglue;  minredglue > 1;  minredglue--) {
+       LOG (2, "%d candidate clauses with glue %d",
+            lgl->stats->lir[minredglue].clauses, minredglue);
+       if (lgl->stats->lir[minredglue].clauses >= rem) break;
+       rem -= lgl->stats->lir[minredglue].clauses;
+      }
+    } else minredglue = 1;
+    szpasls = lgl->stats->lir[minredglue].clauses;
+  }
+  LOG (2, "minum reduction glue %d with %d remaining target clauses %.0f%%",
+       minredglue, rem, lglpcnt (rem, target));
+  NEW (maps, maxredglue + 1);
+  NEW (sizes, maxredglue + 1);
+  for (glue = minredglue; glue <= maxredglue; glue++) {
+    lir = lgl->red + glue;
+    size = lglcntstk (lir);
+    assert (!size || size >= 6);
+    size = (size + 5)/6;
+    sizes[glue] = size;
+    lglfitstk (lgl, lir);
+    NEW (maps[glue], size);
+    map = maps[glue];
+    for (i = 0; i < size; i++) map[i] = -2;
+  }
+  nlocked = 0;
+  for (i = 0; i < lglcntstk (&lgl->trail); i++) {
+    lit = lglpeek (&lgl->trail, i);
+    idx = abs (lit);
+    rsn = lglrsn (lgl, idx);
+    r0 = rsn[0];
+    red = r0 & REDCS;
+    if (!red) continue;
+    tag = r0 & MASKCS;
+    if (tag != LRGCS) continue;
+    lidx = rsn[1];
+    glue = lidx & GLUEMASK;
+    if (glue == MAXGLUE) continue;
+    if (glue < minredglue) continue;
+    if (glue > maxredglue) continue;
+    lidx >>= GLUESHFT;
+#ifndef NLGLOG
+    lir = lgl->red + glue;
+    LOGCLS (5, lir->start + lidx,
+           "locking reason of literal %d glue %d clause",
+           lit, glue);
+#endif
+    lidx /= 6;
+    assert (lidx < sizes[glue]);
+    assert (maps[glue][lidx] == -2);
+    maps[glue][lidx] = -1;
+    nlocked++;
+  }
+  LOG (2, "locked %d learned clauses %.0f%%",
+       nlocked, lglpcnt (nlocked, lgl->stats->red.lrg));
+  NEW (pasls, szpasls);
+  npasls = 0;
+  for (glue = minredglue; glue <= maxredglue; glue++) {
+    lir = lgl->red + glue;
+    start = lir->start;
+    for (c = start; c < lir->top; c = p + 1) {
+      psm = 0;
+      act = *c;
+      if (act == REMOVED) {
+       for (p = c + 1; p < lir->top && *p == REMOVED; p++)
+         ;
+       p--;
+       continue;
+      }
+      for (p = ++c; (lit = *p); p++)
+       if (lgliphase (lgl, lit) >= 0) psm++;
+      assert (npasls < szpasls);
+      pasl = pasls + npasls++;
+      pasl->psm = psm;
+      pasl->act = act;
+      pasl->size = p - c;
+      pasl->lidx = ((c - start) << GLUESHFT) | glue;
+    }
+    if (!acts) { assert (glue == minredglue); break; }
+  }
+  assert (npasls <= szpasls);
+
+  if (glueuseless) {
+    lglprt (lgl, 2,
+      "[reduce-%d] ignoring useless glue",
+      lgl->stats->reduced.count);
+    lgl->stats->reduced.gul++;
+  }
+  SORT (PASL, pasls, npasls, LGLCMPPASL);
+  LOG (1, "copied and sorted %d activities", npasls);
+
+  nkeep = 0;
+  for (idx = rem; idx < npasls; idx++) {
+    pasl = pasls + idx;
+    lidx = pasl->lidx;
+    glue = lidx & GLUEMASK;
+    lidx >>= GLUESHFT;
+    lidx /= 6;
+    assert (lidx < sizes[glue]);
+    maps[glue][lidx] = -1;
+    nkeep++;
+  }
+  DEL (pasls, szpasls);
+  LOG (1, "explicity marked %d additional clauses to keep", nkeep);
+  sumcollected = 0;
+  for (glue = minredglue; glue <= maxredglue; glue++) {
+    lir = lgl->red + glue;
+    map = maps[glue];
+#ifndef NDEBUG
+    size = sizes[glue];
+#endif
+    q = start = lir->start;
+    collected = 0;
+    for (c = start; c < lir->top; c = p + 1) {
+      act = *c++;
+      if (act == REMOVED) {
+       for (p = c; p < lir->top && *p == REMOVED; p++)
+         ;
+       assert (p >= lir->top || *p < NOTALIT || lglisact (*p));
+       p--;
+       continue;
+      }
+      p = c;
+      LGLCHKACT (act);
+      src = (c - start)/6;
+      assert (src < size);
+      if (map[src] == -2) {
+       assert (collected < lgl->stats->lir[glue].clauses);
+       collected++;
+       LOGCLS (5, c, "collecting glue %d clause", glue);
+       while (*p) p++;
+      } else {
+       dst = q - start + 1;
+       map[src] = dst;
+       if (p == q) {
+         while (*p) p++;
+         q = p + 1;
+       } else {
+         *q++ = act;
+         LOGCLS (5, c, "moving from %d to %d glue %d clause",
+                 (c - start), dst, glue);
+         while (*p) *q++ = *p++;
+         *q++ = 0;
+       }
+      }
+    }
+    LOG (2, "collected %d glue %d clauses", collected, glue);
+    sumcollected += collected;
+    assert (sumcollected <= lgl->stats->red.lrg);
+    assert (lgl->stats->lir[glue].clauses >= collected);
+    lgl->stats->lir[glue].clauses -= collected;
+    lgl->stats->lir[glue].reduced += collected;
+    lir->top = q;
+    lglfitlir  (lgl, lir);
+  }
+  LOG (2, "collected altogether %d clauses", sumcollected);
+  assert (sumcollected <= lgl->stats->red.lrg);
+  lgl->stats->red.lrg -= sumcollected;
+  nunlocked = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglval (lgl, idx)) continue;
+    rsn = lglrsn (lgl, idx);
+    r0 = rsn[0];
+    red = r0 & REDCS;
+    if (!red) continue;
+    tag = r0 & MASKCS;
+    if (tag != LRGCS) continue;
+    lidx = rsn[1];
+    glue = lidx & GLUEMASK;
+    if (glue < minredglue) continue;
+    if (glue > maxredglue) continue;
+    src = (lidx >> GLUESHFT);
+    assert (src/6 < sizes[glue]);
+    dst = maps[glue][src/6];
+    assert (dst >= 0);
+    dst <<= GLUESHFT;
+    dst |= lidx & GLUEMASK;
+    rsn[1] = dst;
+    nunlocked++;
+  }
+  LOG (2, "unlocked %d reasons", nunlocked);
+  assert (nlocked == nunlocked);
+  collected = moved = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    dv = lgldvar (lgl, idx);
+    for (i = 0; i <= 1; i++) {
+      hts = dv->hts + i;
+      if (!hts->offset) continue;
+      q = lglhts2wchs (lgl, hts);
+      assert (hts->count >= 0);
+      eow = q + hts->count;
+      for (p = q; p < eow; p++) {
+       blit = *p;
+       red = blit & REDCS;
+       tag = blit & MASKCS;
+       if (red && tag == LRGCS) {
+         lidx = *++p;
+         glue = lidx & GLUEMASK;
+         if (glue < minredglue || glue > maxredglue) {
+           dst = lidx >> GLUESHFT;
+         } else {
+           src = lidx >> GLUESHFT;
+           assert (src/6 < sizes[glue]);
+           dst = maps[glue][src/6];
+         }
+         if (dst >= 0) {
+           moved++;
+           *q++ = blit;
+           *q++ = (dst << GLUESHFT) | (lidx & GLUEMASK);
+         } else collected++;
+       } else {
+         *q++ = blit;
+         if (tag != BINCS) {
+           assert (tag == TRNCS || tag == LRGCS);
+           *q++ = *++p;
+         }
+       }
+      }
+      lglshrinkhts (lgl, hts, hts->count - (p - q));
+    }
+  }
+  LOG (1, "moved %d and collected %d occurrences", moved, collected);
+  for (glue = minredglue; glue <= maxredglue; glue++)
+    DEL (maps[glue], sizes[glue]);
+  DEL (sizes, maxredglue+1);
+  DEL (maps, maxredglue+1);
+  if (lgl->opts->redfixed.val) goto NOINC;
+  if (lglmemout (lgl)) {
+    inc = 0;
+    lglprt (lgl, 2,
+      "[reduce-%d] no increase of reduce limit since memory limit was hit",
+      lgl->stats->reduced.count);
+    lgl->stats->reduced.memlim++;
+  } else if (!needmoreclauses) {
+    inc = lgl->opts->redlinc.val;
+    lglprt (lgl, 2,
+      "[reduce-%d] arithmetic increase of reduce limit",
+      lgl->stats->reduced.count);
+    lgl->stats->reduced.arith++;
+  } else if (needmoreclauses == 1) {
+    inc = 2*lgl->opts->redlinc.val;
+    lglprt (lgl, 2,
+       "[reduce-%d] double-arithmetic increase of reduce limit",
+       lgl->stats->reduced.count);
+    lgl->stats->reduced.arith2++;
+    lgl->stats->reduced.arith++;
+  } else {
+    inc = (lgl->opts->redlexpfac.val * lgl->limits->reduce.inner + 99)/100;
+    if (!inc) inc++;
+    lglprt (lgl, 2,
+      "[reduce-%d] geometric increase of reduce limit",
+      lgl->stats->reduced.count);
+    lgl->stats->reduced.geom++;
+  }
+  LOG (1, "reduce increment %d", inc);
+  lgl->limits->reduce.inner += inc;
+  assert (forced || lgl->opts->reduce.val);
+  if  (lgl->opts->reduce.val > 1 &&
+       (lglrem (lgl) < lgl->opts->redoutvlim.val ||
+        lgl->stats->irr.clauses.cur < lgl->opts->redoutclim.val) &&
+       lgl->limits->reduce.inner >= lgl->limits->reduce.outer) {
+    type = '/';
+    lgl->stats->reduced.reset++;
+    lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+    lglboundredl (lgl);
+    if (lgl->opts->reduce.val == 2) {
+      outer = lgl->limits->reduce.inner;
+      outer *= lgluby (lgl, lgl->stats->reduced.reset);
+    } else if (lgl->opts->reduce.val == 3) {
+      outer = lgl->limits->reduce.inner;
+      outer *= lglinout (lgl, lgl->stats->reduced.reset,
+                         lgl->opts->redinoutinc.val);
+    } else {
+      assert (lgl->opts->reduce.val == 4);
+      outer = lgl->limits->reduce.outer + lgl->opts->redloutinc.val;
+      if (outer < lgl->limits->reduce.inner)
+       outer = lgl->limits->reduce.inner;
+    }
+    if (outer > (int64_t) INT_MAX) outer = INT_MAX;
+    lgl->limits->reduce.outer = outer;
+  } else lglboundredl (lgl);
+NOINC:
+  lglrelstk (lgl, &lgl->learned);
+  lglrep (lgl, 1, type);
+  lglchkred (lgl);
+  lglstop (lgl);
+}
+
+void lglreducecache (LGL * lgl) {
+  REQINITNOTFORKED ();
+  TRAPI ("reduce");
+  if (lgl->mt) return;
+  lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+  lglboundredl (lgl);
+  lglreduce (lgl, 1);
+  lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+  lglboundredl (lgl);
+  lgl->limits->reduce.outer = 2*lgl->limits->reduce.inner;
+  lglprt (lgl, 1, "[reduce-cache] new limit %d", lgl->limits->reduce.inner);
+  if (lgl->clone) lglreducecache (lgl->clone);
+}
+
+#ifndef NLGLPICOSA
+static void lglpicosatrestart (LGL *);
+#endif
+
+static void lgliflushcache (LGL * lgl, int keep) {
+  int idx, sign, lit, blit, tag, red, * w, * q, lidx, glue;
+  int bin, trn, lrg, start;
+  const int * p, * eow;
+  HTS * hts;
+  assert (1 <= keep), assert (keep <= 4);
+  if (lgl->level) lglbacktrack (lgl, 0);
+  bin = trn = lrg = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      q = w;
+      for (p = q; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       red = blit & REDCS;
+       if (red) {
+         if (tag == BINCS) {
+           if (keep < 2) continue;
+         } else if (tag == TRNCS) {
+           if (keep < 3) continue;
+         } else {
+           assert (tag == LRGCS);
+           if (keep < 4) continue;
+           lidx = *p;
+           glue = lidx & GLUEMASK;
+           if (glue > 0) continue;
+         }
+       }
+       *q++ = blit;
+       if (tag == TRNCS || tag == LRGCS) *q++ = *p;
+      }
+      lglshrinkhts (lgl, hts, q - w);
+    }
+  }
+  if (keep < 2) bin = lgl->stats->red.bin, lgl->stats->red.bin = 0;
+  if (keep < 3) trn = lgl->stats->red.trn, lgl->stats->red.trn = 0;
+  start = (keep >= 4);
+  for (glue = start; glue < MAXGLUE; glue++) {
+    lrg += lgl->stats->lir[glue].clauses;
+    lgl->stats->lir[glue].clauses = 0;
+  }
+  assert (lrg <= lgl->stats->red.lrg), lgl->stats->red.lrg -= lrg;
+  lglrelstk (lgl, &lgl->learned);
+  for (glue = start; glue < MAXGLUE; glue++)
+    lglrelstk (lgl, lgl->red + glue);
+  lglprt (lgl, 1,
+    "[flush-cache] %d binary, %d ternary, %d large",
+    bin, trn, lrg);
+#ifndef NLGLPICOSA
+  lglpicosatrestart (lgl);
+#endif
+}
+
+void lglflushcache (LGL * lgl) {
+  REQINITNOTFORKED ();
+  TRAPI ("flush");
+  if (lgl->mt) return;
+  lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+  lglboundredl (lgl);
+  lgliflushcache (lgl, 1);
+  lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+  lglboundredl (lgl);
+  lgl->limits->reduce.outer = 2*lgl->limits->reduce.inner;
+  lglprt (lgl, 1, "[flush-cache] new limit %d", lgl->limits->reduce.inner);
+  if (lgl->clone) lglflushcache (lgl->clone);
+}
+
+
+static void lglrmbwch (LGL * lgl, int lit, int other, int red) {
+  int * p, blit, blit1, * w, * eow, tag;
+  HTS * hts;
+  assert (!red || red == REDCS);
+  LOG (3, "removing %s binary watch %d blit %d",
+       lglred2str (red), lit, other);
+  hts = lglhts (lgl, lit);
+  assert (hts->count >= 1);
+  p = w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  lglrminc (lgl, w, eow);
+  blit1 = (other << RMSHFT) | red | BINCS;
+  for (;;) {
+    assert (p < eow);
+    blit = *p++;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+    if (tag == OCCS) { assert (lgl->dense); continue; }
+    assert (tag == BINCS);
+    if (blit == blit1) break;
+  }
+  while (p < eow) p[-1] = p[0], p++;
+  lglshrinkhts (lgl, hts, p - w - 1);
+}
+
+static int lglpopesched (LGL * lgl) {
+  Stk * s = &lgl->esched;
+  int res, last, cnt, * p;
+  EVar * ev;
+  assert (!lglmtstk (s));
+  res = *s->start;
+  assert (!lglifrozen (lgl, res));
+  LOGESCHED (4, res, "popped");
+  ev = lglevar (lgl, res);
+  assert (!ev->pos);
+  ev->pos = -1;
+  last = lglpopstk (s);
+  cnt = lglcntstk (s);
+  if (!cnt) { assert (last == res); return res; }
+  p = lglepos (lgl, last);
+  assert (*p == cnt);
+  *p = 0;
+  *s->start = last;
+  lgledown (lgl, last);
+  return res;
+}
+
+static void lgldecocc (LGL * lgl, int lit) {
+  int idx, sign, change;
+  EVar * ev;
+  if (!lgl->occs) return;
+  idx = abs (lit), sign = (lit < 0);
+  ev = lglevar (lgl, lit);
+  assert (ev->occ[sign] > 0);
+  ev->occ[sign] -= 1;
+  if (!lglisfree (lgl, lit)) return;
+  change = lglecalc (lgl, ev);
+  LOG (3, "dec occ of %d now occs[%d] = %d %d",
+       lit, idx,  ev->occ[0], ev->occ[1]);
+  if (ev->pos < 0) lglesched (lgl, idx);
+  else if (change < 0) lgleup (lgl, idx);
+  else if (change > 0) lgledown (lgl, idx);
+}
+
+static void lglrmbcls (LGL * lgl, int a, int b, int red) {
+  lglrmbwch (lgl, a, b, red);
+  lglrmbwch (lgl, b, a, red);
+  LOG (2, "removed %s binary clause %d %d", lglred2str (red), a, b);
+  lgldeclscnt (lgl, 2, red, 0);
+  if (!red && lgl->dense) lgldecocc (lgl, a), lgldecocc (lgl, b);
+}
+
+static void lglrmtcls (LGL * lgl, int a, int b, int c, int red) {
+  lglrmtwch (lgl, a, b, c, red);
+  lglrmtwch (lgl, b, a, c, red);
+  lglrmtwch (lgl, c, a, b, red);
+  LOG (2, "removed %s ternary clause %d %d %d", lglred2str (red), a, b, c);
+  lgldeclscnt (lgl, 3, red, 0);
+  if (!red && lgl->dense)
+    lgldecocc (lgl, a), lgldecocc (lgl, b), lgldecocc (lgl, c);
+}
+
+static void lgltrimlitstk (LGL * lgl, int red, int lidx) {
+  Stk * s = lglidx2stk (lgl, red, lidx);
+  int * p = s->top;
+  while (p > s->start && p[-1] == REMOVED)
+    p--;
+  if (p < s->top) {
+    int64_t trimmed = s->top - p;
+#ifndef NLGLOG
+    if (red) LOG (4, "trimmed 'red[%d]' by %lld", (LGLL) trimmed);
+    else LOG (4, "trimmed 'irr' by %lld", (LGLL) trimmed);
+#endif
+    lgl->stats->trims += trimmed;
+    s->top = p;
+    if (red) {
+      int glue = (lidx & GLUEMASK), maxlidx;
+      assert (s == &lgl->red[glue]);
+      maxlidx = (lglcntstk (s) << GLUESHFT) | glue;
+      for (p = lgl->learned.start; p < lgl->learned.top; p += 3) {
+       int olidx = *p, oglue = (olidx & GLUEMASK);
+       if (oglue == glue && olidx >= maxlidx) *p = INT_MIN;
+      }
+    }
+  }
+}
+
+static void lglrmlcls (LGL * lgl, int lidx, int red) {
+  int * c, * p, glue, lit;
+  assert (!red || red == REDCS);
+  glue = red ? (lidx & GLUEMASK) : 0;
+  c = lglidx2lits (lgl, red, lidx);
+  if (!red || glue < MAXGLUE) {
+    lglrmlwch (lgl, c[0], red, lidx);
+    lglrmlwch (lgl, c[1], red, lidx);
+  }
+  if (!red && lgl->dense) {
+    for (p = c; (lit = *p); p++) {
+      lglrmlocc (lgl, lit, red, lidx);
+      lgldecocc (lgl, lit);
+    }
+  }
+  if (red && glue < MAXGLUE) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+  for (p = c; *p; p++) *p = REMOVED;
+  *p = REMOVED;
+  if (glue != MAXGLUE) lgldeclscnt (lgl, p - c, red, glue);
+  lgltrimlitstk (lgl, red, lidx);
+}
+
+static void lgldynsub (LGL * lgl, int lit, int r0, int r1) {
+  int red, tag;
+  tag = r0 & MASKCS;
+  LOGREASON (2, lit, r0, r1, "removing on-the-fly subsumed");
+  red = r0 & REDCS;
+  if (red) lgl->stats->otfs.sub.dyn.red++;
+  else lgl->stats->otfs.sub.dyn.irr++;
+  if (tag == BINCS) lglrmbcls (lgl, lit, (r0>>RMSHFT), red);
+  else if (tag == TRNCS) lglrmtcls (lgl, lit, (r0>>RMSHFT), r1, red);
+  else { assert (tag == LRGCS); lglrmlcls (lgl, r1, red); }
+}
+
+static void lglunflict (LGL * lgl, int lit) {
+  lgl->conf.lit = lit;
+  lgl->conf.rsn[0] = (lit << RMSHFT) | UNITCS;
+  LOG (1, "inconsistent unary clause %d", lit);
+}
+
+static void lgldynstr (LGL * lgl, int del, int lit, int r0, int r1) {
+  int * p, * c, lidx, other, red, tag, glue, other2, other3, blit;
+  tag = r0 & MASKCS;
+  LOGREASON (2, lit, r0, r1,
+    "on-the-fly strengthening by removing %d from", del);
+  red = r0 & REDCS;
+  if (red) lgl->stats->otfs.str.dyn.red++;
+  else lgl->stats->otfs.str.dyn.irr++;
+  lgl->stats->prgss++;
+  if (!red) lgl->stats->irrprgss++;
+  if (tag == BINCS) {
+    other = (del == lit) ? (r0 >> RMSHFT) : lit;
+    assert (other != del);
+    lglrmbcls (lgl, del, other, red);
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, other, 0);
+#ifndef NLGLPICOSAT
+    lglpicosatchkclsarg (lgl, other, 0);
+#endif
+    lglunflict (lgl, other);
+    return;
+  }
+  if (tag == TRNCS) {
+    if (lit == del) other = (r0 >> RMSHFT), other2 = r1;
+    else if (del == r1) other = lit, other2 = (r0 >> RMSHFT);
+    else other = lit, other2 = r1;
+    assert (del != other && del != other2);
+    lglrmtcls (lgl, del, other, other2, red);
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, other, other2, 0);
+#ifndef NLGLPICOSAT
+    lglpicosatchkclsarg (lgl, other, other2, 0);
+#endif
+    if (!red) lglincirr (lgl, 2);
+    else lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+    lglwchbin (lgl, other, other2, red);
+    lglwchbin (lgl, other2, other, red);
+    if (lglevel (lgl, other) < lglevel (lgl, other2)) SWAP (int, other, other2);
+    blit = (other2 << RMSHFT) | BINCS | red;
+    lglbonflict (lgl, other, blit);
+    return;
+  }
+  assert (tag == LRGCS);
+  lidx = r1;
+  glue = red ? (lidx & GLUEMASK) : 0;
+  c = lglidx2lits (lgl, red, lidx);
+  for (p = c; *p != del; p++)
+    assert (*p);
+  if (glue < MAXGLUE) {
+    lglrmlwch (lgl, c[0], red, lidx);
+    lglrmlwch (lgl, c[1], red, lidx);
+  }
+  while ((other = *++p)) p[-1] = other;
+  p[-1] = 0, *p = REMOVED;
+  lgltrimlitstk (lgl, red, lidx);
+  if (!red) assert (lgl->stats->irr.lits.cur), lgl->stats->irr.lits.cur--;
+  lglorderclsaux (lgl, c + 0);
+  lglorderclsaux (lgl, c + 1);
+  if (lgl->opts->drup.val) lgldrupclsaux (lgl, c);
+#ifndef NLGLPICOSAT
+  lglpicosatchkclsaux (lgl, c);
+#endif
+  assert (p - c > 3);
+  if (p - c == 4) {
+    assert (!c[3] && c[4] >= NOTALIT);
+    other = c[0], other2 = c[1], other3 = c[2];
+    if (red && glue < MAXGLUE) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+    c[0] = c[1] = c[2] = c[3] = REMOVED;
+    lgltrimlitstk (lgl, red, lidx);
+    if (lglevel (lgl, other2) < lglevel (lgl, other3))
+      SWAP (int, other2, other3);
+    if (lglevel (lgl, other) < lglevel (lgl, other2))
+      SWAP (int, other, other2);
+    lglwchtrn (lgl, other, other2, other3, red);
+    lglwchtrn (lgl, other2, other, other3, red);
+    lglwchtrn (lgl, other3, other, other2, red);
+    if (red) {
+      if (glue < MAXGLUE) {
+       assert (lgl->stats->red.lrg > 0);
+       lgl->stats->red.lrg--;
+       assert (lgl->stats->lir[glue].clauses > 0);
+       lgl->stats->lir[glue].clauses--;
+      }
+      lgl->stats->red.trn++;
+      assert (lgl->stats->red.trn > 0);
+    }
+    lgltonflict (lgl, other, (other2 << RMSHFT) | red | TRNCS, other3);
+  } else {
+    if (glue < MAXGLUE) {
+      LOG (3, "new head literal %d", c[0]);
+      (void) lglwchlrg (lgl, c[0], c[1], red, lidx);
+      LOG (3, "new tail literal %d", c[1]);
+      (void) lglwchlrg (lgl, c[1], c[0], red, lidx);
+    }
+    lglonflict (lgl, 0, c[0], red, lidx);
+  }
+}
+
+static void lglclnframes (LGL * lgl) {
+  while (!lglmtstk (&lgl->frames))
+    lglunuselevel (lgl, lglpopstk (&lgl->frames));
+}
+
+static void lglclnpoisoned (LGL * lgl) {
+  while (!lglmtstk (&lgl->poisoned)) {
+    int lit = lglpopstk (&lgl->poisoned);
+    AVar * av = lglavar (lgl, lit);
+    assert (!av->mark);
+    assert (av->poisoned);
+    av->poisoned = 0;
+  }
+}
+
+static void lglclnana (LGL * lgl) {
+#ifdef RESOLVENT
+  if (lglmaintainresolvent  (lgl)) lglclnstk (&lgl->resolvent);
+#endif
+  lglclnstk (&lgl->clause);
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  lglclnframes (lgl);
+}
+
+static void lglbumplit (LGL * lgl, int lit) {
+  int idx = abs (lit), mightneedtorescore = 0;
+  QVar * qv = lglqvar (lgl, idx);
+  Scr oldscore, newscore;
+  oldscore = qv->score;
+  switch (lgl->opts->score.val) {
+    default:
+    case 0:
+      newscore = 0;
+      break;
+    case 6:
+      assert (lgl->opts->score.val == LGL_SCORE_VSIDS256);
+    case 1:
+      newscore = oldscore + 1;
+      LOG (0,
+        "incrementing score of variable %d from %lld to %lld",
+        idx, (LGLL) oldscore, (LGLL) newscore);
+      break;
+    case 2:
+      newscore = lgl->stats->confs;
+      LOG (0,
+        "setting last conflict of variable %d from %lld to %lld",
+        idx, (LGLL) oldscore, (LGLL) newscore);
+      break;
+    case 3:
+      newscore = oldscore + lgl->stats->confs;
+      LOG (0,
+        "changing sum of conflict counts of variable %d from %lld to %lld",
+        idx, (LGLL) oldscore, (LGLL) newscore);
+      mightneedtorescore = 1;
+      break;
+    case 4:
+      assert (lgl->opts->score.val == LGL_SCORE_AVG);
+#ifdef NDBLSCR
+      newscore = lglflt (0, (uint64_t) (lgl->stats->confs + 1));
+      newscore = lgladdflt (oldscore, newscore);
+      newscore = lglshflt (newscore, 1);
+#else
+      newscore = (oldscore + lgl->stats->confs)/2.0;
+#endif
+      assert (newscore > oldscore);
+      LOG (3,
+        "averaging of %d from %s to %s after %lld conflicts",
+        idx, lglscr2str (lgl, oldscore), lglscr2str (lgl, newscore),
+       (LGLL) lgl->stats->confs);
+      break;
+    case 5:
+      assert (lgl->opts->score.val == LGL_SCORE_EVSIDS);
+      newscore = lgladdscr (oldscore, lgl->scinc);
+      LOG (3,
+        "bumping EVSIDS score of variable %d from %s to %s",
+        idx, lglscr2str (lgl, oldscore), lglscr2str (lgl, newscore));
+      assert (newscore > oldscore);
+      mightneedtorescore = 1;
+      break;
+  }
+  qv->score = newscore;
+  if (lgldscheduled (lgl, idx)) lgldup (lgl, idx);
+  if (mightneedtorescore && newscore >= lgl->maxscore) lglrescorevars (lgl);
+}
+
+static void lglbumpseenlits (LGL * lgl) {
+  const int * p;
+  if (!lgl->opts->bumpseenlits.val) return;
+  lglstart (lgl, &lgl->times->bump);
+  for (p = lgl->seen.start; p < lgl->seen.top; p++) lglbumplit (lgl, *p);
+  lglstop (lgl);
+}
+
+static void lglbumpclslits (LGL * lgl) {
+  const int * p;
+  int lit;
+  lglstart (lgl, &lgl->times->bump);
+  p = lgl->clause.start;
+  while ((lit = *p++)) lglbumplit (lgl, lit);
+  lglstop (lgl);
+}
+
+static void lglmincls (LGL * lgl, int uip, int glue) {
+  int origsize = lglcntstk (&lgl->clause) - 1;
+  int * p, * q, other, minimized, local;
+  if (!lgl->opts->minimize.val) return;
+  if (glue > lgl->opts->minlocalgluelim.val) return;
+  lglstart (lgl, &lgl->times->mcls);
+  q = lgl->clause.start;
+  minimized = 0;
+  local = lgl->opts->minimize.val <= 1 || glue > lgl->opts->minrecgluelim.val;
+  assert (lglmtstk (&lgl->poisoned));
+  for (p = q; (other = *p); p++)
+    if (other != uip && lglminclslit (lgl, other, local)) {
+      LOG (2, "removed %d", other);
+      minimized++;
+    } else *q++ = other;
+  *q++ = 0;
+  lglclnpoisoned (lgl);
+  assert (lgl->clause.top - q == minimized);
+  COVER (glue + 1 >= origsize && minimized > 0);       // unreachable ...
+  LOG (2, "clause minimized by %d literals", minimized);
+  LOGCLS (2, lgl->clause.start, "minimized clause");
+  lgl->clause.top = q;
+  lglstop (lgl);
+}
+
+static void lgliassume (LGL * lgl, int lit) {
+  lgl->level++;
+  lglpushcontrol (lgl, lit);
+  assert (lglcntctk (&lgl->control) == lgl->level + 1);
+  LOG (2, "internally assuming %d", lit);
+  lglassign (lgl, lit, DECISION, 0);
+}
+
+static void lgldassume (LGL * lgl, int lit) {
+  LOG (1, "next assumed decision %d external %d", lit, lglexport (lgl, lit));
+  lgl->stats->decisions++;
+  lgl->stats->height += lgl->level;
+  lgliassume (lgl, lit);
+  assert (lgldecision (lgl, lit));
+}
+
+void lgldeco2 (LGL * lgl) {
+  int next, level, lit, tag, r0, r1, other, count;
+  const int * p, * rsn;
+  AVar * av;
+  assert (lgl->opts->deco.val == 2);
+  assert (lglmtstk (&lgl->clause));
+  for (p = lgl->seen.start; p < lgl->seen.top; p++)
+    lglavar (lgl, *p)->mark = 0;
+  next = 0;
+  count = lglcntstk (&lgl->seen);
+  LOG (2, "starting only-decision clause analysis after seeing %d", count);
+  while (next < lglcntstk (&lgl->seen)) {
+    lit = lglpeek (&lgl->seen, next++);
+    level = lglevel (lgl, lit);
+    if (!level || level == lgl->level) continue;
+    av = lglavar (lgl, lit);
+    if (av->mark) continue;
+    av->mark = 1;
+    if (lgldecision (lgl, lit)) lglpushstk (lgl, &lgl->clause, lit);
+    else {
+      rsn = lglrsn (lgl, lit);
+      r0 = rsn[0], r1 = rsn[1];
+      tag = r0 & MASKCS;
+      if (tag == BINCS || tag == TRNCS) {
+       other = r0 >> RMSHFT;
+       lglpushstk (lgl, &lgl->seen, other);
+       if (tag == TRNCS) lglpushstk (lgl, &lgl->seen, r1);
+      } else {
+       assert (tag == LRGCS);
+        p = lglidx2lits (lgl, (r0 & REDCS), r1);
+       while ((other = *p++))
+         if (other != -lit)
+           lglpushstk (lgl, &lgl->seen, other);
+      }
+    }
+  }
+  assert (next >= count);
+  LOG (2, "saw %d more in only-decision clause analysis", next - count);
+  while (lglcntstk (&lgl->seen) > count)
+    lglavar (lgl, lglpopstk (&lgl->seen))->mark = 0;
+}
+
+void lgldeco1 (LGL * lgl, int jlevel) {
+  Ctr * p;
+  int lit;
+  assert (lgl->opts->deco.val == 1);
+  assert (lglmtstk (&lgl->clause));
+  for (p = lgl->control.start + 1; p <= lgl->control.start + jlevel; p++) {
+    assert (p < lgl->control.top);
+    lit = -p->decision;
+    assert (lgldecision (lgl, lit));
+    assert (lglevel (lgl, lit));
+    assert (lglevel (lgl, lit) <= jlevel);
+    lglpushstk (lgl, &lgl->clause, lit);
+  }
+}
+
+void lgldeco (LGL * lgl, int jlevel) {
+  assert (lgl->opts->deco.val);
+  if (lgl->opts->deco.val == 1) lgldeco1 (lgl, jlevel);
+  else lgldeco2 (lgl);
+}
+
+#define SCL 2
+
+static int lglsubl (LGL * lgl, int lidx, int size, int glue) {
+  const int * c, * p;
+  int count, lit;
+  assert (lidx);
+  assert ((lidx & GLUEMASK) < MAXGLUE);
+  c = lglidx2lits (lgl, REDCS, lidx);
+  count = 0;
+  for (p = c; count < size && (lit = *p); p++) {
+    if (lit == REMOVED) return 1;
+    if (lglmarked (lgl, lit) > 0) count++;
+  }
+  lgl->stats->subl.tried++;
+  if (count < size) {
+    LOGCLS (4, c, "only %d literals shared in clause", count);
+    return 0;
+  }
+  LOGCLS (2, c,
+    "subsuming learned scaled glue %d clause",
+    (int)(lidx & GLUEMASK));
+  LOGCLS (2, lgl->clause.start,
+    "subsumed by new size %d scaled glue %d clause",
+    size, lglscaleglue (lgl, glue));
+  lgl->stats->subl.sub++;
+  lglrmlcls (lgl, lidx, REDCS);
+  return 1;
+}
+
+static int lglana (LGL * lgl) {
+  int open, resolved, tag, lit, uip, r0, r1, other, other2, * p, * q, lidx;
+  int size, savedsize, resolventsize, level, red, glue, realglue;
+  int jlevel, mlevel, nmlevel, origsize, redsize;
+  int del, cl, c0, c1, sl, s0, s1;
+  int len, * rsn;
+  int64_t cpi;
+  int delay;
+#ifdef RESOLVENT
+  AVar * av;
+#endif
+  if (lgl->mt) return 0;
+  if (lgl->failed) return 0;
+  if (!lgl->conf.lit) return 1;
+  if (!lgl->level) {
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, 0);
+#ifndef NLGLPICOSAT
+    lglpicosatchkclsarg (lgl, 0);
+#endif
+    lgl->mt = 1;
+    return 0;
+  }
+  if (lgl->flipping) {
+    assert (lgl->flipping > 0);
+    if (lgl->flipping == 1) LOG (1, "switching off phase flipping");
+    lgl->flipping--;
+  }
+  if (lgl->phaseneg) {
+    assert (lgl->phaseneg > 0);
+    if (lgl->phaseneg == 1) LOG (1, "switching off initial negative phase");
+    lgl->phaseneg--;
+  }
+  lglstart (lgl, &lgl->times->ana);
+  lgl->stats->confs++;
+RESTART:
+  assert (lgl->conf.lit);
+  assert (lglmtstk (&lgl->seen));
+  assert (lglmtstk (&lgl->clause));
+  assert (lglmtstk (&lgl->resolvent));
+#ifndef NDEBUG
+  if (lgl->opts->check.val > 0) lglchkclnvar (lgl);
+#endif
+  open = 0;
+  lit = lgl->conf.lit, r0 = lgl->conf.rsn[0], r1 = lgl->conf.rsn[1];
+  savedsize = resolved = 0;
+  open += lglpull (lgl, lit);
+  LOG (2, "starting analysis with reason of literal %d", lit);
+  for (;;) {
+    LOGREASON (2, lit, r0, r1, "analyzing");
+    if (resolved++) {
+#ifdef RESOLVENT
+      if (lglmaintainresolvent (lgl)) {
+       LOG (2, "removing %d from resolvent", -lit);
+       lglrmstk (&lgl->resolvent, -lit);
+       LOGRESOLVENT (3, "resolvent after removing %d is", -lit);
+      }
+#endif
+    }
+    assert (lglevel (lgl, lit) == lgl->level);
+    tag = r0 & MASKCS;
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      size = lglevel (lgl, other) ? 2 : 1;
+      if (lglpull (lgl, other)) open++;
+      if (tag == TRNCS) {
+       if (lglevel (lgl, r1)) size++;
+       if (lglpull (lgl, r1)) open++;
+      }
+    } else {
+      assert (tag == LRGCS);
+      red = r0 & REDCS;
+      p = lglidx2lits (lgl, red, r1);
+      size = 0;
+      while ((other = *p++)) {
+       if (lglevel (lgl, other)) size++;
+       if (lglpull (lgl, other)) open++;
+      }
+      if (red) lglbumplidx (lgl, r1);
+    }
+    LOG (3, "open %d antecendents %d learned %d resolved %d",
+        open-1, size, lglcntstk (&lgl->clause), lglcntstk (&lgl->resolvent));
+    assert (open > 0);
+    resolventsize = open + lglcntstk (&lgl->clause);
+#ifdef RESOLVENT
+    LOGRESOLVENT (2, "resolvent");
+    if (lglmaintainresolvent (lgl))
+      assert (lglcntstk (&lgl->resolvent) == resolventsize);
+#endif
+    if (lgl->opts->otfs.val &&
+       (resolved >= 2) &&
+       resolventsize > 1 &&
+       (resolventsize < size || (resolved==2 && resolventsize<savedsize))) {
+      cl = lgl->conf.lit;
+      c0 = lgl->conf.rsn[0];
+      c1 = lgl->conf.rsn[1];
+      assert (resolved >= 2);
+      del = lit;
+      if (resolved > 2) ;
+      else if (resolventsize >= size) del = -lit, lit = cl, r0 = c0, r1 = c1;
+      else if (resolventsize >= savedsize) ;
+      else {
+       if (r0 & REDCS) {
+         sl = lit, s0 = r0, s1 = r1;
+         del = -lit, lit = cl, r0 = c0, r1 = c1;
+       } else sl = cl, s0 = c0, s1 = c1;
+       lgldynsub (lgl, sl, s0, s1);
+      }
+      lgldynstr (lgl, del, lit, r0, r1);
+      lit = lgl->conf.lit;
+      r0 = lgl->conf.rsn[0];
+      r1 = lgl->conf.rsn[1];
+      assert (lglevel (lgl, lit) == lgl->level);
+      tag = r0 & MASKCS;
+      if (tag == UNITCS) {
+       mlevel = lglevel (lgl, lit);
+       nmlevel = 1;
+       jlevel = 0;
+      } else if (tag == BINCS) {
+       jlevel = lglevel (lgl, lit);
+       other = r0 >> RMSHFT;
+       mlevel = lglevel (lgl, other);
+       if (jlevel > mlevel) { nmlevel = 1; SWAP (int, mlevel, jlevel); }
+       else if (jlevel == mlevel) nmlevel = 2;
+       else assert (jlevel < mlevel), nmlevel = 1;
+      } else if (tag== TRNCS) {
+       jlevel = lglevel (lgl, lit);
+       other = r0 >> RMSHFT;
+       level = lglevel (lgl, other);
+       other2 = r1;
+       mlevel = lglevel (lgl, other2);
+       if (jlevel > mlevel) SWAP (int, jlevel, mlevel);
+       if (level > mlevel) SWAP (int, level, mlevel);
+       if (level > jlevel) SWAP (int, level, jlevel);
+       assert (mlevel >= jlevel);
+       assert (jlevel >= level);
+       if (mlevel == jlevel) nmlevel = 2 + (jlevel == level);
+       else assert (mlevel > jlevel), nmlevel = 1;
+       assert (nmlevel == 1 + (mlevel == jlevel) + (mlevel == level));
+      } else {
+       mlevel = lglevel (lgl, lit), nmlevel = 1, jlevel = 0;
+       assert (tag == LRGCS);
+       red = r0 & REDCS;
+       p = lglidx2lits (lgl, red, r1);
+       while (jlevel < lgl->level && (other = *p++)) {
+         if (other == lit) continue;
+         assert (other != -lit);
+         level = lglevel (lgl, other);
+         if (level < mlevel) {
+           if (level > jlevel) jlevel = level;
+           continue;
+         }
+         if (level == mlevel) nmlevel++;
+         else {
+           assert (level > mlevel);
+           jlevel = mlevel;
+           mlevel = level;
+           nmlevel = 1;
+         }
+       }
+       if (red) lglbumplidx (lgl, r1);
+      }
+      if (nmlevel >= 2) {
+       LOG (2, "restarting analysis after on-the-fly strengthening");
+       lgl->stats->otfs.restarting++;
+       if (lgl->opts->otfsbump.val >= 1)
+         lglbumpseenlits (lgl), lglbumpscinc (lgl);
+       lglclnana (lgl);
+       if (lgl->level > mlevel) lglbacktrack (lgl, mlevel);
+        if (lgl->opts->otfsconf.val) lgl->stats->confs++;
+       goto RESTART;
+      }
+      assert (nmlevel == 1);
+      assert (mlevel > jlevel);
+      assert (lglevel (lgl, lit) == mlevel);
+      LOGREASON (2, lit, r0, r1,
+       "driving %d at level %d through strengthened", lit, jlevel);
+      lgl->stats->otfs.driving++;
+      lglbacktrack (lgl, jlevel);
+      if (tag == LRGCS && (r0 & REDCS) && (r1 & GLUEMASK) == MAXGLUE) {
+       // Note, that 'lit' is unassigned by 'backtrack' above and thus if
+       // it's reason is at the end of the MAXGLUE stack, then the reason
+       // becomes invalid.  See the corresponding 'assert' in 'lglassign'.
+       // Our original incorrect fix to this problem was to simply increase
+       // the size of the stack to point after the zero sentinel, which
+       // however produces garbage on the MAXGLUE stack and thus we only
+       // follow this idea if the reason of 'lit' is exactly after the
+       // current end of the MAXGLUE stack. If it starts before the end
+       // nothing has to be done.  Otherwise we have to move the reason
+       // literals and update the reason.
+       p = lglidx2lits (lgl, REDCS, r1);
+       if (p > lgl->red[MAXGLUE].top) {
+         int * q;
+         rsn = lglrsn (lgl, lit);
+         r1 = lglcntstk (&lgl->red[MAXGLUE]);
+         r1 <<= GLUESHFT;
+         r1 |= MAXGLUE;
+         rsn[1] = r1;
+         for (q = lgl->red[MAXGLUE].top; *p; p++) {
+           assert (q < p);
+           *q++ = *p;
+         }
+         *q++ = 0;
+         lgl->red[MAXGLUE].top = q;
+       } else if (p == lgl->red[MAXGLUE].top) {
+         while (*p) { assert (*p < NOTALIT); p++; }
+         if (++p > lgl->red[MAXGLUE].top) lgl->red[MAXGLUE].top = p;
+       }
+      }
+      lglassign (lgl, lit, r0, r1);
+      if (lgl->opts->otfsbump.val >= 2) 
+       lglbumpseenlits (lgl), lglbumpscinc (lgl);
+      len = INT_MAX;
+      goto DONE;
+    }
+    savedsize = size;
+    while (!lglmarked (lgl, lit = lglpopstk (&lgl->trail))) {
+      if (lgl->opts->bumpbcplits.val) lglbumplit (lgl, lit);
+      lglunassign (lgl, lit);
+    }
+    lglunassign (lgl, lit);
+    if (!--open) { uip = -lit; break; }
+    LOG (2, "analyzing reason of literal %d next", lit);
+    rsn = lglrsn (lgl, lit);
+    r0 = rsn[0], r1 = rsn[1];
+  }
+  assert (uip);
+  LOG (2, "adding UIP %d at same level %d to 1st UIP clause",
+       uip, lgl->level);
+  lglpushstk (lgl, &lgl->clause, uip);
+  assert (lglmarked (lgl, uip));
+#ifdef RESOLVENT
+  LOGRESOLVENT (3, "final resolvent before flushing fixed literals");
+  if (lglmaintainresolvent  (lgl)) {
+    int * q = lgl->resolvent.start;
+    for (p = q; p < lgl->resolvent.top; p++)
+      if (lglevel (lgl, (other = *p)))
+       *q++ = other;
+    lgl->resolvent.top = q;
+    LOGRESOLVENT (2, "final resolvent after flushing fixed literals");
+    assert (lglcntstk (&lgl->resolvent) == lglcntstk (&lgl->clause));
+    for (p = lgl->clause.start; p < lgl->clause.top; p++)
+      assert (lglavar (lgl, *p)->mark > 0);
+    for (p = lgl->resolvent.start; p < lgl->resolvent.top; p++) {
+      av = lglavar (lgl, *p); assert (av->mark > 0); av->mark = -av->mark;
+    }
+    for (p = lgl->clause.start; p < lgl->clause.top; p++)
+      assert (lglavar (lgl, *p)->mark < 0);
+    for (p = lgl->resolvent.start; p < lgl->resolvent.top; p++) {
+      av = lglavar (lgl, *p); assert (av->mark < 0); av->mark = -av->mark;
+    }
+    lglclnstk (&lgl->resolvent);
+  }
+#endif
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOGCLS (2, lgl->clause.start, "1st UIP clause");
+  if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+
+  mlevel = lgl->level;
+  jlevel = glue = realglue = 0;
+  for (p = lgl->frames.start; p < lgl->frames.top; p++) {
+    level = *p;
+    assert (0 < level && level < lgl->level);
+    if (level < mlevel) mlevel = level;
+    if (level > jlevel) jlevel = level;
+    if (level >= lgl->alevel) realglue++;
+    glue++;
+  }
+  assert (realglue <= glue);
+  assert (glue == lglcntstk (&lgl->frames));
+  LOG (2, "jump level %d", jlevel);
+  LOG (2, "minimum level %d", mlevel);
+  LOG (2, "glue %d covers %.0f%%", glue,
+       (float)(jlevel ? lglpcnt (glue, (jlevel - mlevel) + 1) : 100.0));
+
+  if (lglrsn (lgl, uip)[0]) lgl->stats->uips++;
+  else if (jlevel + 1 == lgl->level) lgl->stats->decflipped++;
+
+  origsize = lglcntstk (&lgl->clause) - 1;
+  assert (glue + 1 <= origsize);
+  if (origsize >= lgl->opts->bumpseenminsize.val &&
+      lgl->opts->bumpseenbeforemin.val) lglbumpseenlits (lgl);
+  lgl->stats->lits.nonmin += origsize;
+  redsize = jlevel + 1;
+  if (origsize == 2) {
+    lgl->stats->mincls.bin++;
+    LOGCLS (2, lgl->clause.start, "binary 1st UIP clause not minimized");
+  } else if (glue + 1 == origsize) {
+    lgl->stats->mincls.size++;
+    LOGCLS (2, lgl->clause.start,
+      "size %d 1st UIP clause with glue %d can not minimized",
+      origsize, glue);
+  } else if (jlevel > 1 &&
+      lgl->opts->deco.val &&
+      redsize < 2*origsize/3 &&
+      glue > lgl->opts->decolim.val) {
+    assert (origsize > 2);
+    lgl->stats->mincls.deco++;
+    lgl->stats->deco.sum.orig += origsize;
+    lglclnstk (&lgl->clause);
+    lgldeco (lgl, jlevel);
+    glue = lglcntstk (&lgl->clause);
+    lglpushstk (lgl, &lgl->clause, uip);
+    lgl->stats->deco.sum.red += lglcntstk (&lgl->clause);
+    lglpushstk (lgl, &lgl->clause, 0);
+    LOGCLS (2, lgl->clause.start,
+      "size %d 1st UIP clause discarded for size %d decision-only clause",
+      origsize, redsize);
+  } else {
+    lgl->stats->mincls.min++;
+    lglmincls (lgl, uip, glue);
+  }
+
+  if (origsize >= lgl->opts->bumpseenminsize.val &&
+      lgl->opts->bumpseenaftermin.val) lglbumpseenlits (lgl);
+  if (origsize < lgl->opts->bumpseenminsize.val ||
+      lgl->opts->bumpclslits.val) lglbumpclslits (lgl);
+
+  lglbumpscinc (lgl);
+  lglbacktrack (lgl, jlevel);
+
+  len = lglcntstk (&lgl->clause) - 1;
+  lgl->stats->clauses.glue += glue;
+  lgl->stats->clauses.realglue += realglue;
+  lgl->stats->lits.learned += len;
+  lgl->stats->clauses.learned++;
+  lgl->stats->glues.count++;
+  lgl->stats->glues.sum += glue;
+  if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+  lgldrupligaddcls (lgl, REDCS);
+  lidx = lgladdcls (lgl, REDCS, realglue, 1);
+
+  if (lgl->opts->subl.val) {
+    lgl->stats->subl.count++;
+    lglpopnunmarkstk (lgl, &lgl->seen);
+    size = lglcntstk (&lgl->clause) - 1;
+    if (size > 1) {
+      unsigned sig = 0;
+      p = lgl->clause.start;
+      while ((lit = *p++)) {
+       sig |= (1u << (lglulit (lit) & 31));
+       lglmark (lgl, lit);
+      }
+      q = lgl->learned.start;
+      for (p = q; p < lgl->learned.top; p += 3) {
+       int olidx = p[0], osize = p[1];
+       unsigned osig = (unsigned) p[2];
+       if (olidx < 0) continue;
+       if (osize <= size ||
+           (sig & ~osig) ||
+           !lglsubl (lgl, olidx, size, glue))
+         *q++ = olidx, *q++ = osize, *q++ = (int) osig;
+      }
+      lgl->learned.top = q;
+      if (lidx && (lidx & GLUEMASK) < MAXGLUE) {
+       lgl->stats->subl.cands++;
+       lglpushstk (lgl, &lgl->learned, lidx);
+       lglpushstk (lgl, &lgl->learned, size);
+       lglpushstk (lgl, &lgl->learned, (int) sig);
+       if (lglcntstk (&lgl->learned) / 3 > lgl->opts->subl.val) {
+         q = lgl->learned.start;
+         for (p = q + 3; p < lgl->learned.top; p++) *q++ = *p;
+         lgl->learned.top = q;
+       }
+      } 
+      p = lgl->clause.start;
+      while ((lit = *p++)) lglunmark (lgl, lit);
+    }
+  }
+
+  if (lgl->cbs &&
+      lgl->cbs->cls.produce.fun &&
+      glue <= lgl->opts->synclsglue.val &&
+      lglcntstk (&lgl->clause) - 1 <= lgl->opts->synclslen.val) {
+    assert (lglmtstk (&lgl->eclause));
+    for (p = lgl->clause.start; *p; p++)
+      lglpushstk (lgl, &lgl->eclause, lglexport (lgl, *p));
+    lglpushstk (lgl, &lgl->eclause, 0);
+    LOGCLS (SCL, lgl->eclause.start,
+      "exporting external redundant glue %d length %d clause", 
+      glue, lglcntstk (&lgl->clause) -1);
+    lgl->stats->sync.cls.produced++;
+    lgl->cbs->cls.produce.fun (lgl->cbs->cls.produce.state,
+                               lgl->eclause.start, glue);
+    lglclnstk (&lgl->eclause);
+  }
+
+DONE:
+
+  if (!lgl->simp)  {
+
+    cpi = lgl->stats->confs / (1 + lgl->stats->iterations);
+
+    if (len == 2) {
+      if ((delay = lgl->opts->binsimpdel.val)) {
+       if (cpi/2 < (int64_t) delay) delay = (int) cpi/2;
+       lgl->limits->simp.confs += delay;
+      }
+      if ((delay = lgl->opts->binlocsdel.val)) {
+       if (cpi/2 < (int64_t) delay) delay = (int) cpi/2;
+       lgl->limits->locs.confs += delay;
+      }
+      lglrep (lgl, 2, 'b');
+    }
+
+    if (!lgl->level) {
+      if ((delay = lgl->opts->itsimpdel.val)) {
+       if (cpi/2 < (int64_t) delay) delay = (int) cpi/2;
+       lgl->limits->simp.confs += delay;
+      }
+      if ((delay = lgl->opts->itlocsdel.val)) {
+       if (cpi/2 < (int64_t) delay) delay = (int) cpi/2;
+       lgl->limits->locs.confs += delay;
+      }
+      lgl->stats->iterations++;
+      lglrep (lgl, 1, 'i');
+    }
+  }
+
+  lglclnana (lgl);
+  lglstop (lgl);
+
+  return 1;
+}
+
+static int lglscalerestartint (LGL * lgl, int delta) {
+  int64_t res = delta;
+  if (lgl->opts->restartintscale.val > 0) {
+    res *= lgl->stats->decisions + 1;
+    res /= lgl->stats->confs + 1;
+  } else if (lgl->opts->restartintscale.val < 0) {
+    res *= lgl->stats->confs + 1;
+    res /= lgl->stats->decisions + 1;
+  }
+  if (res <= 1) res = 1;
+  lgl->stats->restarts.intsum.orig += delta;
+  lgl->stats->restarts.intsum.scaled += res;
+  return res;
+}
+
+static void lglincrestartlfixed (LGL * lgl) {
+  int delta = lgl->opts->restartint.val;
+  delta = lglscalerestartint (lgl, delta);
+  lgl->limits->restart.confs = lgl->stats->confs + delta;
+  lglrep (lgl, 1, 'R');
+}
+
+static void lglincrestartaux (LGL * lgl, int skip) {
+  int delta = lgl->opts->restartint.val, count;
+  if (lgl->opts->restart.val == 2) {
+    count = ++lgl->limits->restart.luby;
+    delta *= lgluby (lgl, count);
+  } else {
+    assert (lgl->opts->restart.val == 3);
+    count = ++lgl->limits->restart.inout;
+    delta *= lglinout (lgl, count, lgl->opts->rstinoutinc.val);
+  }
+  delta = lglscalerestartint (lgl, delta);
+  lgl->limits->restart.confs = lgl->stats->confs + delta;
+  if (lgl->limits->restart.wasmaxdelta)
+    lglrep (lgl, 1 + skip, skip ? 'N' : 'R');
+  else lglrep (lgl, 2, skip ? 'n' : 'r');
+  if (delta > lgl->limits->restart.maxdelta) {
+    lgl->limits->restart.wasmaxdelta = 1;
+    lgl->limits->restart.maxdelta = delta;
+  } else lgl->limits->restart.wasmaxdelta = 0;
+}
+
+static void lglincrestartl (LGL * lgl, int skip) {
+  switch (lgl->opts->restart.val) {
+    case 1: lglincrestartlfixed (lgl); break;
+    case 2: case 3: lglincrestartaux (lgl, skip); break;
+    default: break;
+  }
+}
+
+static int lglnextdecision (LGL * lgl) {
+  int res = 0;
+  if (!lgl->unassigned) return 0;
+  lglstart (lgl, &lgl->times->dec);
+  while (!res && !lglmtstk (&lgl->dsched)) {
+    int next = lgltopdsched (lgl);
+    if (!lglval (lgl, next) && lglisfree (lgl, next)) res = next;
+    else lglpopdsched (lgl);
+  }
+  LOG (2, "next decision would be %d", res);
+  lglstop (lgl);
+  return res;
+}
+
+static int lglreusetrail (LGL * lgl) {
+  int next = 0, res = 0, prev, level;
+  const Ctr * p;
+  assert (lgl->opts->reusetrail.val);
+  if (lgl->flipping) {
+    lgl->flipping = 0;
+    lglprt (lgl, 2, 
+      "[reuse-trail] no reuse after forced termination of flipping");
+    return lgl->alevel;
+  }
+  if (!(next = lglnextdecision (lgl))) return 0;
+  for (p = lgl->control.start + 1; p < lgl->control.top; p++) {
+    prev = p->decision;
+    assert (lgldecision (lgl, prev));
+    if (!lglassumption (lgl, prev) && lgldcmp (lgl, prev, next) < 0) break;
+    level = lglevel (lgl, prev);
+    assert (level == p - lgl->control.start);
+    assert (res + 1 == level);
+    res = level;
+  }
+  if (res)
+    lglprt (lgl, 2,
+    "[reuse-trail] reusing level %d from current level %d", res, lgl->level);
+  else
+    lglprt (lgl, 2, "[reuse-trail] can not reuse any level");
+  return res;
+}
+
+static void lglrestart (LGL * lgl) {
+  int skip, level;
+  int64_t kept;
+  assert (lgl->opts->restart.val);
+  lglstart (lgl, &lgl->times->rsts);
+  if (lglagile (lgl))
+    lgl->stats->restarts.skipped.agile++, skip = 1;
+  else if (lglsaturating (lgl))
+    lgl->stats->restarts.skipped.saturating++, skip = 1;
+  else skip = 0;
+  if (skip) {
+    lgl->stats->restarts.skipped.count++;
+    LOG (1, "skipping restart with agility %.0f%%", lglagility (lgl));
+  } else {
+    LOG (1, "restarting with agility %.0f%% not saturating",
+      lglagility (lgl));
+    if (!lgl->opts->reusetrail.val ||
+        lgl->opts->restart.val <= 1 ||
+        lgl->opts->phasegluebit.val) level = 0;
+    else level = lglreusetrail (lgl);
+    if (level < lgl->alevel) level = lgl->alevel;
+    else if (level > lgl->alevel) {
+      kept = (100*level) / lgl->level;
+      lgl->stats->restarts.kept.sum += kept;
+      lgl->stats->restarts.kept.count++;
+    }
+    if (level < lgl->level) {
+      lglbacktrack (lgl, level);
+      lgl->stats->restarts.count++;
+    } else {
+      lgl->stats->restarts.skipped.count++;
+      lgl->stats->restarts.skipped.reuse++;
+    }
+  }
+  lglincrestartl (lgl, skip);
+  lglstop (lgl);
+}
+
+static void lgldefrag (LGL * lgl) {
+  int * wchs, nwchs, i, idx, bit, ldsize, size, offset, * start, * q, * end;
+  const int * p, * eow, * w;
+  HTS * hts;
+  lglstart (lgl, &lgl->times->dfg);
+  lgl->stats->defrags++;
+  nwchs = lglcntstk (&lgl->wchs->stk);
+  NEW (wchs, nwchs);
+  memcpy (wchs, lgl->wchs->stk.start, nwchs * sizeof *wchs);
+  for (i = 0; i < MAXLDFW; i++) lgl->wchs->start[i] = INT_MAX;
+  lgl->wchs->free = 0;
+  start = lgl->wchs->stk.start;
+  assert (nwchs >= 1);
+  assert (start[0] == INT_MAX);
+  offset = 1;
+  for (idx = 2; idx < lgl->nvars; idx++)
+  for (bit = 0; bit <= 1; bit++) {
+    hts = lgl->dvars[idx].hts + bit;
+    if (!hts->offset) { assert (!hts->count); continue; }
+    ldsize = lglceilld (hts->count);
+    size = (1 << ldsize);
+    assert (size >= hts->count);
+    w = wchs + hts->offset;
+    hts->offset = offset;
+    eow = w + hts->count;
+    q = start + offset;
+    for (p = w; p < eow; p++) *q++ = *p;
+    offset += size;
+    end = start + offset;
+    while (q < end) *q++ = 0;
+  }
+  DEL (wchs, nwchs);
+  q = start + offset;
+  *q++ = INT_MAX;
+  assert (q <= lgl->wchs->stk.top);
+  lgl->wchs->stk.top = q;
+  lglfitstk (lgl, &lgl->wchs->stk);
+  lgl->limits->dfg = lgl->stats->pshwchs + lgl->opts->defragint.val;
+  lglrep (lgl, 2, 'F');
+  lglstop (lgl);
+}
+
+static void lgldis (LGL * lgl) {
+  int blit, nblit, tag, red, * p, * q, * eow, * w;
+  int idx, sign, lit, other, other2;
+  Stk bins, trns;
+  Val val, val2;
+  HTS * hts;
+  assert (!lgl->level);
+  CLR (bins); CLR (trns);
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = idx * sign;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      val = lglval (lgl, lit);
+      assert (hts->count > 0);
+      if (val || lgliselim (lgl, lit))
+       { lglshrinkhts (lgl, hts, 0); continue; }
+      assert (lglisfree (lgl, lit));
+      assert (lglmtstk (&bins));
+      assert (lglmtstk (&trns));
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == OCCS) continue;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       other = blit >> RMSHFT;
+       val = lglval (lgl, other);
+       if (val > 0) continue;
+       if (lgliselim (lgl, other)) continue;
+       if (tag == BINCS) {
+         assert (!val);
+         lglpushstk (lgl, &bins, blit);
+         continue;
+       }
+       assert (tag == TRNCS);
+       other2 = *p;
+       val2 = lglval (lgl, other2);
+       if (val2 > 0) continue;
+       if (lgliselim (lgl, other2)) continue;
+       if (val < 0) {
+         assert (val < 0 && !val2);
+         nblit = red | (other2<<RMSHFT) | BINCS;
+         lglpushstk (lgl, &bins, nblit);
+         continue;
+       }
+       if (val2 < 0) {
+         assert (!val && val2 < 0);
+         nblit = red | (other<<RMSHFT) | BINCS;
+         lglpushstk (lgl, &bins, nblit);
+         continue;
+       }
+       assert (!val && !val2);
+       lglpushstk (lgl, &trns, blit);
+       lglpushstk (lgl, &trns, other2);
+      }
+      q = w;
+      for (p = bins.start; p != bins.top; p++) *q++ = *p;
+      for (p = trns.start; p != trns.top; p++) *q++ = *p;
+      lglshrinkhts (lgl, hts, q - w);
+      lglclnstk (&bins);
+      lglclnstk (&trns);
+    }
+  lglrelstk (lgl, &bins);
+  lglrelstk (lgl, &trns);
+  lglrelstk (lgl, &lgl->learned);
+}
+
+static int lglcmphase (LGL * lgl, int a, int b) {
+  return lgliphase (lgl, b) - lgliphase (lgl, a);
+}
+
+#define LGLCMPHASE(A,B) lglcmphase (lgl, *(A), *(B))
+
+static void lglconnaux (LGL * lgl, int glue) {
+  int lit, satisfied, lidx, size, red, act;
+  const int * p, * c, * start, * top;
+  int * q, * d;
+  Stk * stk;
+  Val val;
+  if (glue >= 0) {
+    assert (glue < MAXGLUE);
+    red = REDCS;
+    stk = lgl->red + glue;
+  } else red = 0, stk = &lgl->irr;
+  c = start = q = stk->start;
+  top = stk->top;
+  while (c < top) {
+    act = *c;
+    if (act == REMOVED) {
+      for (p = c + 1; p < top && *p == REMOVED; p++)
+       ;
+      assert (p >= top || *p < NOTALIT || lglisact (*p));
+      c = p;
+      continue;
+    }
+    if (lglisact (act)) *q++ = *c++; else act = -1;
+    p = c;
+    d = q;
+    satisfied = 0;
+    while (assert (p < top), (lit = *p++)) {
+      assert (lit < NOTALIT);
+      if (satisfied) continue;
+      val = lglval (lgl, lit);
+      if (lgliselim (lgl, lit))  {
+       assert (lgl->eliminating || lgl->blocking);
+       satisfied = 1;
+      } else if (val > 0) satisfied = 1;
+      else if (!val) *q++ = lit;
+    }
+    if (satisfied || p == c + 1) {
+      q = d - (act >= 0);
+    } else if (!(size = q - d)) {
+      q = d - (act >= 0);
+      if (!lgl->mt) {
+       LOG (1, "empty clause during connection garbage collection phase");
+       lgl->mt = 1;
+      }
+    } else if (size == 1) {
+      q = d - (act >= 0);
+      LOG (1, "unit during garbage collection");
+      lglunit (lgl, d[0]);
+    } else if (size == 2) {
+      q = d - (act >= 0);
+      lglwchbin (lgl, d[0], d[1], red);
+      lglwchbin (lgl, d[1], d[0], red);
+    } else if (size == 3) {
+      q = d - (act >= 0);
+      lglwchtrn (lgl, d[0], d[1], d[2], red);
+      lglwchtrn (lgl, d[1], d[0], d[2], red);
+      lglwchtrn (lgl, d[2], d[0], d[1], red);
+    } else {
+      assert (size > 3);
+      if (lgl->opts->sortlits.val) SORT (int, d, size, LGLCMPHASE);
+      *q++ = 0;
+      lidx = d - start;
+      if (red) {
+       assert (lidx <= MAXREDLIDX);
+       lidx <<= GLUESHFT;
+       assert (0 <= lidx);
+       lidx |= glue;
+      }
+      (void) lglwchlrg (lgl, d[0], d[1], red, lidx);
+      (void) lglwchlrg (lgl, d[1], d[0], red, lidx);
+    }
+    c = p;
+  }
+  stk->top = q;
+}
+
+static void lglfullyconnected (LGL * lgl) {
+  if (!lgl->notfullyconnected) return;
+  LOG (1, "switching to fully connected mode");
+  lgl->notfullyconnected  = 0;
+}
+
+static void lglcon (LGL * lgl) {
+  int glue;
+  for (glue = -1; glue < MAXGLUE; glue++) lglconnaux (lgl, glue);
+  lglfullyconnected (lgl);
+}
+
+static void lglcount (LGL * lgl) {
+  int idx, sign, lit, tag, blit, red, other, other2, glue, count;
+  const int * p, * w, * c, * eow;
+  HTS * hts;
+  Stk * lir;
+  lgl->stats->irr.clauses.cur = 0;
+  lgl->stats->irr.lits.cur = 0;
+  lgl->stats->red.bin = 0;
+  lgl->stats->red.trn = 0;
+  lgl->stats->red.lrg = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       red = blit & REDCS;
+       tag = blit & MASKCS;
+       if (tag == LRGCS || tag == TRNCS) p++;
+       if (tag == LRGCS) continue;
+       assert (tag == BINCS || tag == TRNCS);
+       other = blit >> RMSHFT;
+       assert (abs (other) != abs (lit));
+       if (abs (lit) >= abs (other)) continue;
+       assert (2 == BINCS && 3 == TRNCS);
+       if (tag == TRNCS) {
+         other2 = *p;
+         assert (abs (other2) != abs (lit));
+         assert (abs (other2) != abs (other));
+         if (abs (lit) >= abs (other2)) continue;
+       }
+       if (!red) {
+         lgl->stats->irr.clauses.cur++;
+         if (tag == BINCS) lgl->stats->irr.lits.cur += 2;
+         else assert (tag == TRNCS), lgl->stats->irr.lits.cur += 3;
+       } else if (tag == BINCS) lgl->stats->red.bin++;
+       else assert (tag == TRNCS), lgl->stats->red.trn++;
+      }
+    }
+  assert (lgl->stats->red.bin >= 0 && lgl->stats->red.trn >= 0);
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    if (*(p = c) >= REMOVED) continue;
+    while (*p) p++;
+    lgl->stats->irr.lits.cur += p - c;
+    lgl->stats->irr.clauses.cur++;
+  }
+  LOG (1, "counted %d irredundant clauses with %d literals",
+       lgl->stats->irr.clauses.cur, lgl->stats->irr.lits.cur);
+  for (glue = 0; glue < MAXGLUE; glue++) {
+    lir = lgl->red + glue;
+    count = 0;
+    for (c = lir->start; c < lir->top; c++)
+      if (!*c) count++;
+    if (count)
+      LOG (1, "counted %d redundant clauses with glue %d", count, glue);
+    lgl->stats->red.lrg += count;
+    lgl->stats->lir[glue].clauses = count;
+  }
+  assert (lgl->stats->red.lrg >= 0);
+  if (lgl->stats->red.bin)
+    LOG (1, "counted %d binary redundant clauses altogether",
+        lgl->stats->red.bin);
+  if (lgl->stats->red.trn)
+    LOG (1, "counted %d ternary redundant clauses altogether",
+        lgl->stats->red.trn);
+  if (lgl->stats->red.lrg)
+    LOG (1, "counted %d large redundant clauses altogether",
+        lgl->stats->red.lrg);
+}
+
+static int lglilit (int ulit) {
+  int res = ulit/2;
+  assert (res >= 1);
+  if (ulit & 1) res = -res;
+  return res;
+}
+
+static void lgljwh (LGL * lgl) {
+  int idx, sign, lit, tag, blit, other, other2, red, size, glue;
+  const int *p, * w, * eow, * c;
+  Val val, tmp, tmp2;
+  HTS * hts;
+  Stk * s;
+  Flt inc;
+  CLN (lgl->jwh, 2*lgl->nvars);
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      val = lglval (lgl, lit);
+      if (val > 0) continue;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       if (!lgl->opts->jwhred.val && red) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < abs (lit)) continue;
+       tmp = lglval (lgl, other);
+       if (tmp > 0) continue;
+       if (tag == BINCS) {
+         assert (!tmp);
+         inc = lglflt (-2, 1);
+         lglincjwh (lgl, lit, inc);
+         lglincjwh (lgl, other, inc);
+       } else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (abs (other2) < abs (lit)) continue;
+         tmp2 = lglval (lgl, other2);
+         if (tmp2 > 0) continue;
+         assert ((val > 0) + (tmp > 0) + (tmp2 > 0) == 0);
+         assert ((val < 0) + (tmp < 0) + (tmp2 < 0) <= 1);
+         size = 3 + val + tmp + tmp2;
+         assert (2 <= size && size <= 3);
+         inc = lglflt (-size, 1);
+         if (!val) lglincjwh (lgl, lit, inc);
+         if (!tmp) lglincjwh (lgl, other, inc);
+         if (!tmp2) lglincjwh (lgl, other2, inc);
+       }
+      }
+    }
+  for (glue = -1; glue < MAXGLUE; glue++) {
+    if (glue < 0) s = &lgl->irr;
+    else if (!lgl->opts->jwhred.val) continue;
+    else s = &lgl->red[glue];
+    for (c = s->start; c < s->top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      val = -1;
+      size = 0;
+      while ((other = *p)) {
+       tmp = lglval (lgl, other);
+       if (tmp > val) val = tmp;
+       if (!tmp) size++;
+       p++;
+      }
+      if (val > 0) continue;
+      inc = lglflt (-size, 1);
+      for (p = c; (other = *p); p++)
+       if (!lglval (lgl, other))
+         lglincjwh (lgl, other, inc);
+    }
+  }
+}
+
+static int * lglis (LGL * lgl) {
+  int idx, sign, lit, tag, blit, other, other2, red, * res;
+  const int *p, * w, * eow, * c;
+  Val val, tmp, tmp2;
+  HTS * hts;
+  Stk * s;
+  NEW (res, 2*lgl->nvars);
+  res += lgl->nvars;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      val = lglval (lgl, lit);
+      if (val > 0) continue;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < abs (lit)) continue;
+       tmp = lglval (lgl, other);
+       if (tmp > 0) continue;
+       if (tag == BINCS) {
+         assert (!tmp);
+         res[lit]++,
+         res[other]++;
+       } else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (abs (other2) < abs (lit)) continue;
+         tmp2 = lglval (lgl, other2);
+         if (tmp2 > 0) continue;
+         assert ((val > 0) + (tmp > 0) + (tmp2 > 0) == 0);
+         assert ((val < 0) + (tmp < 0) + (tmp2 < 0) <= 1);
+         if (!val) res[lit]++;
+         if (!tmp) res[other]++;
+         if (!tmp2) res[other2]++;
+       }
+      }
+    }
+  s = &lgl->irr;
+  for (c = s->start; c < s->top; c = p + 1) {
+    p = c;
+    if (*p >= NOTALIT) continue;
+    val = -1;
+    while ((other = *p)) {
+      tmp = lglval (lgl, other);
+      if (tmp > val) val = tmp;
+      p++;
+    }
+    if (val > 0) continue;
+    for (p = c; (other = *p); p++)
+      if (!lglval (lgl, other))
+       res[other]++;
+  }
+  return res;
+}
+
+static int lglsetjwhbias (LGL * lgl, int idx) {
+  AVar * av = lglavar (lgl, idx);
+  Flt pos, neg;
+  int bias;
+  idx = abs (idx);
+  pos = lgl->jwh[lglulit (idx)];
+  neg = lgl->jwh[lglulit (-idx)];
+  if (av->phase) return av->phase;
+  if (lgl->opts->phaseflip.val) SWAP (int, pos, neg);
+  bias = (pos > neg) ? 1 : -1;
+  if (av->bias == bias) return bias;
+  av->bias = bias;
+  lgl->stats->phase.set++;
+  if (bias > 0) lgl->stats->phase.pos++; else lgl->stats->phase.neg++;
+  LOG (1, "JW bias %d (pos %s, neg %s)", 
+       bias * idx, lglflt2str (lgl, pos), lglflt2str (lgl, neg));
+  return bias;
+}
+
+static void lglsetallphases (LGL * lgl) {
+  int res = 1, idx;
+  for (idx = 2; res && idx < lgl->nvars; idx++)
+    res = (!lglisfree (lgl, idx) || lglavar (lgl, idx)->phase);
+  lgl->allphaseset = res;
+}
+
+static void lglflushphasesaux (LGL * lgl, int full) {
+  int idx, flushed = 0;
+  AVar * av;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    av = lglavar (lgl, idx);
+    if (!full && av->phase) continue;
+    av->phase = 0;
+    flushed++;
+  }
+  lglprt (lgl, 1,
+    "[flushphases] %d phases reset%s", 
+    flushed, (full ? " fully" : ""));
+  lgl->allphaseset = !flushed;
+  lgl->flushphases = 0;
+}
+
+static void lglflushphases (LGL * lgl) {
+  int full = (lgl->opts->rephase.val >= 2);
+  lglflushphasesaux (lgl, full);
+}
+
+static void lglphase (LGL * lgl) {
+  int64_t set = lgl->stats->phase.set;
+  int64_t pos = lgl->stats->phase.pos;
+  int64_t neg = lgl->stats->phase.neg;
+  int idx;
+  lglstart (lgl, &lgl->times->phs);
+  if (lgl->flushphases) lglflushphases (lgl);
+  if (lgl->opts->phase.val) goto DONE;
+  lglsetallphases (lgl);
+  if (lgl->allphaseset) goto DONE;
+  lgl->stats->phase.count++;
+  lgljwh (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++) lglsetjwhbias (lgl, idx);
+  set = lgl->stats->phase.set - set;
+  pos = lgl->stats->phase.pos - pos;
+  neg = lgl->stats->phase.neg - neg;
+  lglprt (lgl, 1,
+     "[phase-%d] phase bias: %lld positive %.0f%%, %lld negative %.0f%%",
+     lgl->stats->phase.count,
+     (LGLL) pos, lglpcnt (pos, set),
+     (LGLL) neg, lglpcnt (neg, set));
+DONE:
+  lglstop (lgl);
+}
+
+static int lglrephasing (LGL * lgl) {
+  if (!lgl->opts->rephase.val) return 0;
+  if (lgl->stats->confs < lgl->limits->rephase.confs) return 0;
+  return 1;
+}
+
+static void lglrephase (LGL * lgl) {
+  lgl->stats->rephase.count++;
+  lgl->stats->rephase.inc *= 2;
+  lgl->limits->rephase.confs = lgl->stats->confs + lgl->stats->rephase.inc;
+  lglprt (lgl, 1,
+     "[rephase-%d] after %lld conflicts (new increment %d, next %lld)",
+     lgl->stats->rephase.count, (LGLL) lgl->stats->confs,
+     lgl->stats->rephase.inc, (LGLL) lgl->limits->rephase.confs);
+  lglflushphases (lgl);
+}
+
+static void lglchkbcpclean (LGL * lgl, const char * where) {
+  ASSERT (lgl->next2 == lgl->next && lgl->next == lglcntstk (&lgl->trail));
+  ASSERT (!lgl->conf.lit);
+  ASSERT (!lgl->mt);
+}
+
+static void lglcutwidth (LGL * lgl) {
+  int lidx, res, l4, r4, b4, l10, r10, b10, m, oldbias;
+  int idx, sign, lit, blit, tag, red, other, other2;
+  const int * p, * w, * eow, * c, * q;
+  int * widths, max, cut, min4, min10;
+  int64_t sum, avg;
+  HTS * hts;
+  if (lgl->nvars <= 2) return;
+  lgl->stats->cutwidths++;
+  lglstart (lgl, &lgl->times->ctw);
+  oldbias = lgl->bias;
+  assert (abs (oldbias) <= 1);
+  if (abs (lgl->opts->bias.val) <= 1) {
+    lgl->bias = lgl->opts->bias.val;
+    goto DONE;
+  }
+  min4 = min10 = INT_MAX;
+  sum = max = cut = 0;
+  NEW (widths, lgl->nvars);
+  l4 = 2 + (lgl->nvars - 2 + 3)/4;
+  r4 = 2 + (3*(lgl->nvars - 2)+3)/4;
+  assert (2 <= l4 && l4 <= r4 && r4 <= lgl->nvars);
+  l10 = 2 + (lgl->nvars - 2 + 9)/10;
+  r10 = 2 + (9*(lgl->nvars - 2)+9)/10;
+  assert (2 <= l10 && l10 <= r10 && r10 <= lgl->nvars);
+  b4 = b10 = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = idx * sign;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       red = blit & REDCS;
+       tag = blit & MASKCS;
+       other = abs (blit >> RMSHFT);
+       if (tag == BINCS) {
+         if (red) continue;
+         if (other > idx) widths[other]++, cut++;
+       } else if (tag == TRNCS) {
+         other2 = abs (*++p);
+         if (red) continue;
+         if (other > idx) widths[other]++, cut++;
+         if (other2 > idx) widths[other2]++, cut++;
+       } else {
+         assert (tag == LRGCS);
+         lidx = *++p;
+         if (red) continue;
+         c = lglidx2lits (lgl, 0, lidx);
+         for (q = c; (other = abs (*q)); q++) {
+           if (other == idx) continue;
+           if (other > idx) widths[other]++, cut++;
+         }
+       }
+      }
+    }
+    assert (0 <= cut && 0 <= widths[idx]);
+    cut -= widths[idx];
+    assert (cut >= 0);
+    if (cut > max) max = cut;
+    if (l4 <= idx && idx <= r4 && cut < min4) b4 = idx, min4 = cut;
+    if (l10 <= idx && idx <= r10 && cut < min10) b10 = idx, min10 = cut;
+    sum += cut;
+    assert (sum >= 0);
+  }
+  DEL (widths, lgl->nvars);
+  assert (lgl->nvars > 0);
+  avg = sum / (LGLL) lgl->nvars;
+  assert (avg <= INT_MAX);
+  res = (int) avg;
+  lglprt (lgl, 1,
+    "[cut-width] %d, max %d, min4 %d at %.0f%%, min10 %d at %.0f%%",
+    res, max,
+    min4, lglpcnt ((b4 - 2), lgl->nvars - 2),
+    min10, lglpcnt ((b10 - 2), lgl->nvars - 2));
+  m = (lgl->nvars + 2)/2;
+  if (b4 < m && b10 < m) lgl->bias = -1;
+  if (b4 > m && b10 > m) lgl->bias = 1;
+  lglprt (lgl, 1, "[cut-width] cut-width based bias %d", lgl->bias);
+DONE:
+  lgldreschedule (lgl);
+  assert (abs (lgl->bias <= 1));
+  lglprt (lgl, 1, "[decision-order] bias %d, old %d", lgl->bias, oldbias);
+  lglstop (lgl);
+}
+
+static int lglmaplit (int * map, int lit) {
+  return map [ abs (lit) ] * lglsgn (lit);
+}
+
+static void lglmapstk (LGL * lgl, int * map, Stk * lits) {
+  int * p, * eol;
+  eol = lits->top;
+  for (p = lits->start; p < eol; p++)
+    *p = lglmaplit (map, *p);
+}
+
+static void lglmapglue (LGL * lgl, int * map, Stk * lits) {
+  int * p, * eol;
+  eol = lits->top;
+  for (p = lits->start; p < eol; p++)
+    if (!lglisact (*p)) *p = lglmaplit (map, *p);
+}
+
+static void lglmaplits (LGL * lgl, int * map) {
+  int glue;
+  lglmapstk (lgl, map, &lgl->irr);
+  for (glue = 0; glue < MAXGLUE; glue++)
+    lglmapglue (lgl, map, &lgl->red[glue]);
+}
+
+static void lglmapvars (LGL * lgl, int * map, int nvars) {
+  int i, oldnvars = lgl->nvars, sign, udst, idst, usrc, isrc;
+  DVar * dvars;
+  QVar * qvars;
+  AVar * avars;
+  Val * vals;
+  int * i2e;
+  Flt * jwh;
+
+  if (nvars > 2) assert (nvars <= oldnvars);
+  else nvars = 0;
+
+  DEL (lgl->doms, 2*lgl->szvars);
+  NEW (lgl->doms, 2*nvars);
+
+  NEW (vals, nvars);
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      vals[map[i]] = lgl->vals[i];
+  DEL (lgl->vals, lgl->szvars);
+  lgl->vals = vals;
+
+  NEW (i2e, nvars);
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      i2e[map[i]] = lgl->i2e[i];
+  DEL (lgl->i2e, lgl->szvars);
+  lgl->i2e = i2e;
+
+  NEW (dvars, nvars);
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      dvars[map[i]] = lgl->dvars[i];
+  DEL (lgl->dvars, lgl->szvars);
+  lgl->dvars = dvars;
+
+  NEW (qvars, nvars);
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      qvars[map[i]] = lgl->qvars[i];
+  DEL (lgl->qvars, lgl->szvars);
+  lgl->qvars = qvars;
+
+  NEW (jwh, 2*nvars);
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      for (sign = -1; sign <= 1; sign += 2) {
+         isrc = sign * i;
+         idst = sign * map[i];
+         usrc = lglulit (isrc);
+         udst = lglulit (idst);
+         jwh[udst] = lgladdflt (jwh[udst], lgl->jwh[usrc]);
+       }
+  DEL (lgl->jwh, 2*lgl->szvars);
+  lgl->jwh = jwh;
+
+  NEW (avars, nvars);          
+  for (i = 2; i < oldnvars; i++)
+    if (lglisfree (lgl, i))
+      avars[map[i]] = lgl->avars[i];
+  DEL (lgl->avars, lgl->szvars);
+  lgl->avars = avars;              // Last since 'lglisfree' depends on it !!!
+
+  lgl->nvars = lgl->szvars = nvars;
+  lgl->stats->fixed.current = 0;
+}
+
+static void lglmaphts (LGL * lgl, int * map) {
+  int idx, sign, lit, * w, *eow, * p, other, other2, blit, tag, red;
+  int newblit, newother, newother2;
+  HTS * hts;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->count) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       assert (tag == BINCS || tag == TRNCS || tag == LRGCS);
+       red = blit & REDCS;
+       other = blit >> RMSHFT;
+       newother = lglmaplit (map, other);
+       newblit = (newother << RMSHFT) | tag | red;
+       *p = newblit;
+       if (tag == BINCS) continue;
+       other2 = *++p;
+       if (tag == LRGCS) continue;
+       assert (tag == TRNCS);
+       newother2 = lglmaplit (map, other2);
+       *p = newother2;
+      }
+    }
+}
+
+static void lglmaptrail (LGL * lgl, int * map) {
+  int * p, * q, src, dst;
+  for (p = lgl->trail.start; p < lgl->trail.top; p++)
+    if (lglevel (lgl, *p) > 0) break;
+  for (q = lgl->trail.start; p < lgl->trail.top; p++) {
+    src = *p;
+    assert (lglevel (lgl, src) > 0);
+    dst = lglmaplit (map, src);
+    *q++ = dst;
+  }
+  lgl->trail.top = q;
+  lgl->flushed = lgl->next2 = lgl->next = lglcntstk (&lgl->trail);
+}
+
+static int lglptrjmp (int * repr, int max, int start) {
+#ifndef NDEBUG
+  int prev = 0, count = 0;
+#endif
+  int next, idx, res, sgn, tmp;
+  assert (repr);
+  next = start;
+  do {
+    res = next;
+    idx = abs (res);
+    assert (idx <= max);
+    sgn = lglsgn (res);
+    next = repr[idx];
+    next *= sgn;
+#ifndef NDEBUG
+    if (prev || next) assert (prev != next);
+    prev = res;
+    assert (count <= max);
+#endif
+  } while (next);
+  tmp = start;
+  while (tmp != res) {
+    idx = abs (tmp), sgn = lglsgn (tmp);
+    next = repr[idx] * sgn;
+    repr[idx] = sgn * res;
+    tmp = next;
+  }
+  return res;
+}
+
+static int lglirepr (LGL * lgl, int lit) {
+  assert (lgl->repr);
+  return lglptrjmp (lgl->repr, lgl->nvars - 1, lit);
+}
+
+static void lglmapext (LGL * lgl, int * map) {
+  int eidx, ilit, mlit;
+  Ext * ext;
+  for (eidx = 1; eidx <= lgl->maxext; eidx++) (void) lglerepr (lgl, eidx);
+  for (eidx = 1; eidx <= lgl->maxext; eidx++) {
+    ext = lgl->ext + eidx;
+    if (!ext->imported) continue;
+    if (ext->equiv) {
+      LOG (3, "mapping external %d to equivalent external %d",
+          eidx, ext->repr);
+      continue;
+    }
+    ilit = ext->repr;
+    mlit = lglmaplit (map, ilit);
+    LOG (3, "mapping external %d to internal %d", eidx, mlit);
+    ext->repr = mlit;
+  }
+}
+
+static void lglmapdef (LGL * lgl, int * map) {
+  int didx, mlit, recycle, recycled;
+  Ext * ext;
+  if (!lgl->maxdef) return;
+  recycled = 0;
+  for (didx = 1; didx <= lgl->maxdef; didx++) {
+    ext = lgl->def + didx;
+    assert (!ext->imported);
+    assert (ext->defined);
+    mlit = lglmaplit (map, ext->repr);
+    if (ext->blocking) {
+      LOG (3, "keeping definition %d since it was blocked", didx);
+      recycle = 0;
+    } else if (ext->eliminated) {
+      LOG (3, "keeping definition %d since it was eliminated", didx);
+      recycle = 0;
+    } else if (ext->equiv) {
+      LOG (3, "keeping definition %d since it was equivalent", didx);
+      recycle = 1;
+    } else {
+      assert (ext->repr);
+      if (abs (mlit) == 1) {
+       LOG (3,
+         "recycling definition %d since it is mapped to constant %d",
+         didx, mlit);
+       recycle = 1;
+      } else recycle = 0;
+    }
+    if (recycle) recycled++;
+    LOG (3, "definition %d mapped to internal %d", didx, mlit);
+    ext->repr = mlit;
+  }
+  LOG (2, "could have recycled %d definitions", recycled);
+}
+
+static void lglsignedmark (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (lit < 0);
+  if (av->mark & bit) return;
+  av->mark |= bit;
+}
+
+static void lglsignedunmark (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (lit < 0);
+  if (!(av->mark & bit)) return;
+  av->mark &= ~bit;
+}
+
+static int lglsignedmarked (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (lit < 0);
+  return av->mark & bit;
+}
+
+static void lglmapass (LGL * lgl, int * map) {
+  int * p, * q, iass, mass, flushed;
+  unsigned bit;
+  AVar * av;
+  if (abs (lgl->failed) != 1) lgl->failed = lglmaplit (map, lgl->failed);
+  for (p = q = lgl->assume.start; p < lgl->assume.top; p++) {
+    iass = *p;
+    mass = lglmaplit (map, iass);
+    if (mass == 1) continue;
+    if (mass == -1) {
+      if (lgl->failed != -1) {
+#ifndef NDEBUG
+       int * r;
+       for (r = lgl->eassume.start; r < lgl->eassume.top; r++)
+         if (lglimport (lgl, *r) == -1) break;
+       assert (r < lgl->eassume.top);
+#endif
+       LOG (2, "enforcing a failed assumption");
+       lgl->failed = -1;
+      }
+      continue;
+    }
+    LOG (2, "mapping previous internal assumption %d to %d", iass, mass);
+    av = lglavar (lgl, mass);
+    bit = 1u << (mass < 0);
+    if (!(av->assumed & bit)) {
+      LOG (2, "assuming new representative %d instead of %d", mass, iass);
+      av->assumed |= bit;
+    }
+    *q++ = mass;
+  }
+  lgl->assume.top = q;
+  flushed = 0;
+  for (p = q = lgl->assume.start; p < lgl->assume.top; p++) {
+    iass = *p;
+    if (lglsignedmarked (lgl, iass)) { flushed++; continue; }
+    lglsignedmark (lgl, iass);
+    *q++ = iass;
+  }
+  lgl->assume.top = q;
+  for (p = lgl->assume.start; p < lgl->assume.top; p++) {
+    iass = *p;
+    assert (lglsignedmarked (lgl, iass));
+    lglsignedunmark (lgl, iass);
+  }
+  if (flushed)
+    LOG (2, "flushed %d duplicated internal assumptions", flushed);
+}
+
+#if !defined(NDEBUG) && !defined(NLGLPICOSAT)
+static void lglpicosataddstk (LGL * lgl, const Stk * stk) {
+  const int * p;
+  int lit;
+  for (p = stk->start; p < stk->top; p++) {
+    lit = *p;
+    if (lit >= NOTALIT) continue;
+    picosat_add (PICOSAT, lit);
+  }
+}
+
+static void lglpicosataddunits (LGL * lgl) {
+  int idx, val;
+  assert (!lgl->level);
+  assert (lgl->picosat.solver);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    val = lglval (lgl, idx);
+    if (!val) continue;
+    picosat_add (PICOSAT, (val < 0) ? -idx : idx);
+    picosat_add (PICOSAT, 0);
+  }
+}
+
+static void lglpicosataddhts (LGL * lgl) {
+  int idx, sign, lit, tag, blit, other, other2;
+  const int * w, * p, * eow;
+  HTS * hts;
+  assert (lgl->picosat.solver);
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->count) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == BINCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         picosat_add (PICOSAT, lit);
+         picosat_add (PICOSAT, other);
+         picosat_add (PICOSAT, 0);
+       } else if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         other2 = *++p;
+         if (abs (other) < idx) continue;
+         if (abs (other2) < idx) continue;
+         picosat_add (PICOSAT, lit);
+         picosat_add (PICOSAT, other);
+         picosat_add (PICOSAT, other2);
+         picosat_add (PICOSAT, 0);
+       } else if (tag == LRGCS) p++;
+       else assert (lgl->dense && tag == OCCS);
+      }
+    }
+}
+#endif
+
+static void lglpicosatchkall (LGL * lgl) {
+#if !defined(NDEBUG) && !defined(NLGLPICOSAT)
+  int res, * p;
+  lglpicosatinit (lgl);
+  if (lgl->opts->check.val >= 2) {
+    for (p = lgl->eassume.start; p < lgl->eassume.top; p++)
+      picosat_assume (PICOSAT, lglimport (lgl, *p));
+    res = picosat_sat (PICOSAT, -1);
+    LOG (1, "PicoSAT returns %d", res);
+    if (lgl->picosat.res) assert (res == lgl->picosat.res);
+    lgl->picosat.res = res;
+  }
+  if (picosat_inconsistent (PICOSAT)) {
+    assert (!lgl->picosat.res || lgl->picosat.res == 20);
+    lgl->picosat.res = 20;
+  }
+#endif
+}
+
+static void lglpicosatrestart (LGL * lgl) {
+#if !defined(NDEBUG) && !defined(NLGLPICOSAT)
+  int glue;
+  if (lgl->picosat.solver) {
+    picosat_reset (lgl->picosat.solver);
+    LOG (1, "PicoSAT reset");
+    lgl->picosat.solver = 0;
+  }
+  lglpicosatinit (lgl);
+  lglpicosataddunits (lgl);
+  if (lgl->mt) picosat_add (PICOSAT, 0);
+  lglpicosataddhts (lgl);
+  lglpicosataddstk (lgl, &lgl->irr);
+  for (glue = 0; glue < MAXGLUE; glue++)
+    lglpicosataddstk (lgl, &lgl->red[glue]);
+#endif
+}
+
+static void lglmaplkhdscore (LGL * lgl, int * map, int oldnvars) {
+  LKHD * oldlkhdscore = lgl->tlk->lkhd, score;
+  int idx, src, sign, dst;
+  NEW (lgl->tlk->lkhd, 2*lgl->nvars);
+  lgl->tlk->lkhd += lgl->nvars;
+  for (idx = oldnvars-1; idx >= 2; idx--) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      src = sign * idx;
+      dst = lglmaplit (map, src);
+      if (abs (dst) <= 1) continue;
+      score = oldlkhdscore[src];
+      LOG (2, "mapping look-ahead score %s of %d as score of %d",
+          lglflt2str (lgl, score), src, dst);
+      lgl->tlk->lkhd[dst] = score;
+    }
+  }
+  oldlkhdscore -= oldnvars;
+  DEL (oldlkhdscore, 2*oldnvars);
+}
+
+static int lglmapsize (LGL * lgl) {
+  int size = 0, idx;
+  for (idx = 2; idx < lgl->nvars; idx++) 
+    if (lglisfree (lgl, idx)) size++;
+  LOG (1, "mapping %d remaining variables", size);
+  return size;
+}
+
+static void lglmapnonequiv (LGL * lgl, int * map, int size) {
+  int count = 0, idx;
+  AVar * av;
+  Val val;
+  map[0] = 0, map[1] = 1;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (map[idx]) continue;
+    av = lglavar (lgl, idx);
+    if (av->type == FREEVAR) {
+      assert (idx > 0);
+      if (map[idx]) { assert (map[idx] < idx); continue; }
+      LOG (3, "mapping free %d to %d", idx, count + 2);
+      map[idx] = count + 2;
+      count++;
+    } else if (av->type == EQUIVAR) {
+      assert (lgl->repr);
+      assert (!map[idx]);
+    } else if (av->type == FIXEDVAR) {
+      val = lgl->vals[idx];
+      assert (val);
+      LOG (3, "mapping assigned %d to %d", idx, (int) val);
+      map[idx] = val;
+    } else {
+      assert (av->type == ELIMVAR);
+      assert (!lglifrozen (lgl, idx));
+      map[idx] = 0;
+    }
+  }
+  assert (count == size);
+}
+
+static void lglmapequiv (LGL * lgl, int * map) {
+  int idx, repr, dst;
+  AVar * av;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (map[idx]) continue;
+    av = lglavar (lgl, idx);
+    if (av->type == ELIMVAR) continue;
+    assert (av->type == EQUIVAR);
+    assert (lgl->repr);
+    assert (!map[idx]);
+    repr = lglirepr (lgl, idx);
+    assert (repr != idx);
+    assert (map[abs (repr)]);
+    dst = lglmaplit (map, repr);
+    LOG (3, "mapping equivalent %d to %d", idx, dst);
+    map[idx] = dst;
+  }
+}
+
+typedef struct ForceData { int pos, count; double sum; } ForceData;
+
+static void lglincfdat (ForceData * fdat, int lit, double cog) {
+  int idx = abs (lit);
+  fdat[idx].count++;
+  fdat[idx].sum += cog;
+}
+
+static int lglcmpfdat (ForceData * fdat, int l, int k) {
+  ForceData * d, * e;
+  l = abs (l);
+  k = abs (k);
+  d = fdat + l;
+  e = fdat + k;
+  if (d->sum < e->sum) return -1;
+  if (d->sum > e->sum) return 1;
+  if (d->pos < e->pos) return -1;
+  if (d->pos > e->pos) return 1;
+  return l - k;
+}
+
+static int64_t lglsteps (LGL * lgl) {
+  int64_t res = lgl->stats->steps;
+#ifndef NDEBUG
+  // Note, this would be bulky and slow ...
+  int64_t steps = 0;
+  steps += lgl->stats->bca.steps;
+  steps += lgl->stats->blk.steps;
+  steps += lgl->stats->card.steps;
+  steps += lgl->stats->cce.steps;
+  steps += lgl->stats->cgr.csteps;
+  steps += lgl->stats->cgr.esteps;
+  steps += lgl->stats->cliff.steps;
+  steps += lgl->stats->elm.copies;
+  steps += lgl->stats->elm.resolutions;
+  steps += lgl->stats->elm.steps;
+  steps += lgl->stats->force.steps;
+  steps += lgl->stats->gauss.steps.elim;
+  steps += lgl->stats->gauss.steps.extr;
+  steps += lgl->stats->prb.basic.steps;
+  steps += lgl->stats->prb.simple.steps;
+  steps += lgl->stats->prb.treelook.steps;
+  steps += lgl->stats->props.lkhd;
+  steps += lgl->stats->props.search;
+  steps += lgl->stats->props.simp;
+  steps += lgl->stats->rdp.steps;
+  steps += lgl->stats->trd.steps;
+  steps += lgl->stats->trnr.steps;
+  steps += lgl->stats->unhd.steps;
+  assert (steps == res);
+#endif
+  return res;
+}
+
+static void lgltrep (LGL * lgl) {
+  int64_t steps, i;
+  double t;
+  if (!lgl->opts->trep.val) return;
+  if (lgl->opts->verbose.val) return;
+  steps = lglsteps (lgl);
+  if (steps < lgl->limits->trep.steps) return;
+  lgl->limits->trep.steps += lgl->opts->trepint.val;
+  t = lgl->opts->abstime.val ? lglgetime (lgl) : lglsec (lgl);
+  if (t < lgl->limits->trep.time) return;
+  lglrep (lgl, 0, (lgl->simp ? 'P' : 'S'));
+  i = lgl->limits->trep.time;
+  do {
+         if (!i)         i = 1;
+    else if (i == 1)     i = 2;
+    else if (i == 2)     i = 5;
+    else if (i < 10)     i = 10;
+    else if (i < 60)     i += 10;
+    else if (i < 300)    i += 60;
+    else if (i < 900)    i += 300;
+    else if (i < 7200)   i += 900;
+    else                 i += 3600;
+  } while (i < t);
+  lgl->limits->trep.time = i;
+}
+
+static int lglterminate (LGL * lgl) {
+  int64_t steps;
+  int res;
+  lgltrep (lgl);
+  if (!lgl->cbs) return 0;
+  if (!lgl->cbs->term.fun) return 0;
+  if (lgl->cbs->term.done) return 1;
+  steps = lglsteps (lgl);
+  if (steps < lgl->limits->term.steps) return 0;
+  res = lgl->cbs->term.fun (lgl->cbs->term.state);
+  if (res) lgl->cbs->term.done = res;
+  else lgl->limits->term.steps = steps + lgl->opts->termint.val;
+  return  res;
+}
+
+#define LGLCMPFDAT(A,B) (lglcmpfdat(fdat, *(A), *(B)))
+
+static void lglforce (LGL * lgl, int * map) {
+  int idx, lit, sign, blit, tag, red, other, other2, size, C, V, o, min, max;
+  int round = 1, first = !lgl->stats->force.count;
+  double cog, span, oldspan, mincut;
+  const int * p, * w, * eow, * c;
+  ForceData * fdat;
+  HTS * hts;
+  Stk order;
+  if (!lgl->allowforce) return;
+  if (!lgl->opts->force.val) return;
+  lglstart (lgl, &lgl->times->force);
+  span = INT_MAX;
+RESTART:
+  oldspan = span;
+  lgl->stats->force.count++;
+  NEW (fdat, lgl->nvars);
+  CLR (order);
+  V = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    fdat[idx].pos = map[idx];
+    lglpushstk (lgl, &order, idx);
+    V++;
+  }
+  if (V <= 1) goto DONE;
+  C = 0;
+  span = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      INCSTEPS (force.steps);
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       other = abs (blit >> RMSHFT);
+       if (other < idx) continue;
+       if (tag == BINCS) {
+         cog = fdat[idx].pos + fdat[other].pos;
+         cog /= 2;
+         lglincfdat (fdat, idx, cog);
+         lglincfdat (fdat, other, cog);
+         o = fdat[idx].pos, min = o, max = o;
+         o = fdat[other].pos, min = lglmin (min, o), max = lglmax (max, o);
+         span += max - min;
+         C++;
+       } else if (tag == TRNCS) {
+         other2 = abs (*p);
+         if (other2 < idx) continue;
+         cog = fdat[idx].pos + fdat[other].pos + fdat[other2].pos;
+         cog /= 3;
+         lglincfdat (fdat, idx, cog);
+         lglincfdat (fdat, other, cog);
+         lglincfdat (fdat, other2, cog);
+         o = fdat[idx].pos, min = o, max = o;
+         o = fdat[other].pos, min = lglmin (min, o), max = lglmax (max, o);
+         o = fdat[other2].pos, min = lglmin (min, o), max = lglmax (max, o);
+         span += max - min;
+         C++;
+       }
+      }
+    }
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    if (*(p = c) >= NOTALIT) continue;
+    INCSTEPS (force.steps);
+    cog = 0;
+    while ((idx = abs (*p))) cog += fdat[idx].pos, p++;
+    size = p - c;
+    assert (size >= 4);
+    assert (p >= c + 4);
+    cog /= size;
+    min = INT_MAX, max = INT_MIN;
+    for (p = c; (idx = abs (*p)); p++) {
+      o = fdat[idx].pos, min = lglmin (min, o), max = lglmax (max, o);
+      lglincfdat (fdat, idx, cog);
+    }
+    span += max - min;
+    C++;
+  }
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (!(size = fdat[idx].count)) continue;
+    fdat[idx].sum /= size;
+  }
+  assert (V > 1);
+  mincut = span / (V - 1);
+  if (C > 0) span /= C; else span = 0;
+  if (lgl->stats->force.count > 1) {
+    if (lgl->stats->force.mincut.min > mincut)
+      lgl->stats->force.mincut.min = mincut;
+    if (lgl->stats->force.mincut.max < mincut)
+      lgl->stats->force.mincut.max = mincut;
+  } else lgl->stats->force.mincut.min = lgl->stats->force.mincut.max = mincut;
+  lglprt (lgl, 1, 
+    "[force-%lld] mincut %.1f, span %.1f, %d variables, %d clauses",
+    (LGLL) lgl->stats->force.count, mincut, span, V, C);
+  SORT (int, order.start, lglcntstk (&order), LGLCMPFDAT);
+  o = 2;
+  for (p = order.start; p < order.top; p++) {
+    idx = *p;
+    assert (lglisfree (lgl, idx));
+    LOG (3, "forced mapping free %d to %d", idx, o);
+    map[idx] = o++;
+  }
+DONE:
+  DEL (fdat, lgl->nvars);
+  lglrelstk (lgl, &order);
+  if (first && !lglterminate (lgl)) {
+    if (round++ < lgl->opts->force.val) goto RESTART;
+    if (round < lglceilld (lglrem (lgl))) goto RESTART;
+    if (oldspan > span && (oldspan - span) > oldspan/100.0) goto RESTART;
+  }
+  lglstop (lgl);
+}
+
+static void lglmap (LGL * lgl) {
+  int size, * map, oldnvars, mapsize;
+#ifndef NLGLPICOSAT
+  lglpicosatchkall (lgl);
+#endif
+  assert (!lgl->level);
+  lgldreschedule (lgl);
+  size = lglmapsize (lgl);
+  oldnvars = lgl->nvars;
+  mapsize = lglmax (oldnvars, 2);
+  NEW (map, mapsize);
+  lglmapnonequiv (lgl, map, size);
+  lglmapequiv (lgl, map);
+  lglforce (lgl, map);
+  lglmaptrail (lgl, map);
+  lglmapvars (lgl, map, size + 2);
+  lglmaplits (lgl, map);
+  lglmapstk (lgl, map, &lgl->dsched);
+  if (lgl->cgrclosing) lglmapstk (lgl, map, &lgl->cgr->units);
+  lglmapext (lgl, map);
+  lglmapdef (lgl, map);
+  lglmapass (lgl, map);
+  if (lgl->treelooking && lgl->tlk && lgl->tlk->lkhd)
+    lglmaplkhdscore (lgl, map, oldnvars);
+  assert (lglmtstk (&lgl->clause));
+  lglmaphts (lgl, map);
+  DEL (map, mapsize);
+  if (lgl->repr) DEL (lgl->repr, oldnvars);
+  lglpicosatrestart (lgl);
+  lgl->unassigned = size;
+  lgldreschedule (lgl);
+}
+
+static int lglgcnotnecessary (LGL * lgl) {
+  if (lgl->forcegc) return 0;
+  if (lgl->notfullyconnected) return 0;
+  return lgl->stats->fixed.sum <= lgl->limits->gc.fixed;
+}
+
+static void lglcompact (LGL * lgl) {
+  int glue;
+  lglfitstk (lgl, &lgl->assume);
+  lglfitstk (lgl, &lgl->clause);
+  lglfitstk (lgl, &lgl->eclause);
+  lglfitstk (lgl, &lgl->dsched);
+  lglfitstk (lgl, &lgl->eassume);
+  lglfitstk (lgl, &lgl->extend);
+  lglfitstk (lgl, &lgl->fassume);
+  lglfitstk (lgl, &lgl->learned);
+  lglfitstk (lgl, &lgl->cassume);
+  lglfitstk (lgl, &lgl->frames);
+#ifndef NCHKSOL
+  lglfitstk (lgl, &lgl->orig);
+#endif
+  lglfitstk (lgl, &lgl->trail);
+  lgldefrag (lgl);
+  lglfitstk (lgl, &lgl->wchs->stk);
+
+  lglfitstk (lgl, &lgl->irr);
+  for (glue = 0; glue <= MAXGLUE; glue++)
+    lglfitlir (lgl, lgl->red + glue);
+  lglrelstk (lgl, &lgl->lcaseen);
+  lglrelstk (lgl, &lgl->minstk);
+  lglrelstk (lgl, &lgl->poisoned);
+  lglrelstk (lgl, &lgl->seen);
+  lglrelstk (lgl, &lgl->esched);
+}
+
+static void lglgc (LGL * lgl) {
+  if (lgl->mt) return;
+  lglchkred (lgl);
+  if (lglgcnotnecessary (lgl)) return;
+  lglstart (lgl, &lgl->times->gc);
+  lglchkbcpclean (lgl, "gc");
+  lglrep (lgl, 2, 'g');
+  lgl->stats->gcs++;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  for (;;) {
+    lgldis (lgl);
+    lglcon (lgl);
+    if (lgl->mt) break;
+    if (lgl->next2 == lgl->next &&
+       lgl->next == lglcntstk (&lgl->trail)) break;
+    if (!lglbcp (lgl)) {
+      assert (!lgl->mt);
+      LOG (1, "empty clause after propagating garbage collection unit");
+      lgl->mt = 1;
+      break;
+    }
+  }
+  lglcount (lgl);
+  lglmap (lgl);
+
+  lglcompact (lgl);
+
+  lgl->limits->gc.fixed = lgl->stats->fixed.sum;
+
+  lglchkred (lgl);
+  lglrep (lgl, 2, 'c');
+  lglstop (lgl);
+}
+
+static int lgltopgc (LGL * lgl) {
+  if (lgl->mt) return 0;
+  assert (!lgl->forcegc && !lgl->allowforce);
+  lgl->forcegc = lgl->allowforce = 1;
+  lglgc (lgl);
+  assert (lgl->forcegc && lgl->allowforce);
+  lgl->forcegc = lgl->allowforce = 0;
+  return !lgl->mt;
+}
+
+static int lglrandec (LGL * lgl) {
+  unsigned size, pos, start, delta;
+  int lit;
+  lgl->limits->randec = lgl->stats->decisions;
+  lgl->limits->randec += lgl->opts->randecint.val/2;
+  lgl->limits->randec += lglrand (lgl) % lgl->opts->randecint.val;
+  assert (lgl->nvars > 2);
+  size = lgl->nvars - 2;
+  if (!size) return 0;
+  pos = start = lglrand (lgl) % size;
+  lit = 2 + pos;
+  assert (2 <= lit && lit < lgl->nvars);
+  if (lglval (lgl, lit)) {
+    delta = lglrand (lgl) % size;
+    if (size == 1) return 0;
+    if (!delta) delta++;
+    while (lglgcd (delta, size) != 1)
+      if (++delta == size) delta = 1;
+    do {
+      pos += delta;
+      if (pos >= size) pos -= size;
+      if (pos == start) return 0;
+      lit = pos + 2;
+      assert (2 <= lit && lit < lgl->nvars);
+    } while (lglval (lgl, lit));
+  }
+  lgl->stats->randecs++;
+  return lit;
+}
+
+static int lgladecide (LGL * lgl) {
+  int res, val;
+  while (lgl->assumed < lglcntstk (&lgl->assume)) {
+    res = lglpeek (&lgl->assume, lgl->assumed);
+    val = lglcval (lgl, res);
+    if (val > 0) LOG (3, "assumption %d already satisfied", res);
+    lgl->assumed++;
+    LOG (3, "new assumption queue level %d", lgl->assumed);
+    assert (val >= 0);
+    if (!val) return res;
+  }
+  return 0;
+}
+
+static int lgldefphase (LGL * lgl, int idx) {
+  AVar * av;
+  int bias;
+  assert (idx > 0);
+  av = lglavar (lgl, idx);
+  if (!av->phase) {
+    bias = lgl->opts->phase.val;
+    if (!bias) bias = av->bias;
+    if (!bias) bias = lglsetjwhbias (lgl, idx);
+    av->phase = bias;
+  }
+  return av->phase;
+}
+
+static int lgldecidephase (LGL * lgl, int lit) {
+  int res = abs (lit), flipped, diff;
+  AVar * av = lglavar (lgl, lit);
+  if (av->fase) return av->fase * res;
+  if ((diff = lgl->level - lgl->alevel) < lgl->opts->phasegluebit.val) {
+    LOG (1, "Glue-Bit initial level counting");
+    if (!((lgl->stats->restarts.count >> (diff & 3)) & 1)) res = -res;
+    return res;
+  }
+  if (lgl->phaseneg || lgldefphase (lgl, res) <= 0) res = -res;
+  if (!lgl->flipping &&
+      !lgl->phaseneg &&
+      lgl->opts->flipping.val &&
+      lglrem (lgl) <= lgl->opts->flipvlim.val &&
+      lgl->level >= lgl->alevel &&
+      lgl->assumed == lglcntstk (&lgl->assume) &&
+      (!lgl->opts->fliptop.val || lgl->level == lgl->alevel)) {
+    if (lgl->notflipped >= lgl->limits->flipint) {
+      LOG (1, "switching on phase flipping");
+      lgl->stats->fliphases++;
+      lgl->limits->flipint = lgl->opts->flipint.val;
+      lgl->flipping = lgl->opts->flipdur.val;
+      lgl->notflipped = 0;
+    } else lgl->notflipped++;
+  }
+  if (lgl->flipping) {
+    const int fliplevels = lgl->opts->fliplevels.val;
+    const int ldmod = lgl->opts->flipldmod.val;
+    const int level = lgl->level - lgl->alevel;
+    int shift = fliplevels - lglmin (level, fliplevels);
+    int flip = !((lgl->stats->fliphases >> ldmod) & (1 << shift));
+    if (level > fliplevels) flip = 0;
+    assert (!lgl->phaseneg);
+    flipped = flip ? -res : res;
+    LOG (2, "flipping phase of %d to %d", res, flipped);
+    lgl->stats->flipped++;
+    res = flipped;
+  }
+  return res;
+}
+
+static int lglhasbins (LGL * lgl, int lit) {
+  int blit, tag, other, other2, val, val2, implied;
+  const int * p, * w, * eos, * q;
+  HTS * hts;
+  assert (!lgl->level);
+  assert (lglisfree (lgl, lit));
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eos = w + hts->count;
+  for (p = w; p < eos; p++) {
+    if (lgl->treelooking) INCSTEPS (prb.treelook.steps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      val = lglval (lgl, other);
+      assert (val >= 0);
+      if (!val) return 1;
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      other2= *++p;
+      val = lglval (lgl, other);
+      val2 = lglval (lgl, other2);
+      assert (val >= 0 || val2 >= 0);
+      if (val > 0 || val2 > 0) continue;
+      if (!val && val2 < 0) return 1;
+      if (val < 0 && !val2) return 1;
+    } else {
+      assert (tag == LRGCS);
+      q = lglidx2lits (lgl, (blit & REDCS), *++p);
+      implied = 0;
+      while ((other = *q++)) {
+       if (other == lit) continue;
+       val = lglval (lgl, other);
+       if (val > 0) break;
+       if (val < 0) continue;
+       if (implied) break;
+       implied = other;
+      }
+      if (other) continue;
+      if (implied) return 1;
+    }
+  }
+  return 0;
+}
+
+static int lglhasbinortrn (LGL * lgl, int lit) {
+  int blit, tag, other, other2, val, val2, implied;
+  const int * p, * w, * eos, * q;
+  HTS * hts;
+  assert (!lgl->level);
+  assert (lglisfree (lgl, lit));
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eos = w + hts->count;
+  for (p = w; p < eos; p++) {
+    if (lgl->treelooking) INCSTEPS (prb.treelook.steps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      val = lglval (lgl, other);
+      assert (val >= 0);
+      if (!val) return 1;
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      other2= *++p;
+      val = lglval (lgl, other);
+      val2 = lglval (lgl, other2);
+      assert (val >= 0 || val2 >= 0);
+      if (val <= 0 && val2 <= 0) return 1;
+    } else {
+      assert (tag == LRGCS);
+      q = lglidx2lits (lgl, (blit & REDCS), *++p);
+      implied = 0;
+      while (implied <= 2 && (other = *q++)) {
+       if (other == lit) continue;
+       val = lglval (lgl, other);
+       if (val > 0) break;
+       if (!val) implied++;
+      }
+      if (other) continue;
+      if (implied <= 2) return 1;
+    }
+  }
+  return 0;
+}
+
+static int lgldecide (LGL * lgl) {
+  int lit;
+  lglchkbcpclean (lgl, "decide");
+  if (!lgl->unassigned) return 0;
+  if ((lit = lgladecide (lgl))) {
+    LOG (2, "using assumption %d as decision", lit);
+    lgl->alevel = lgl->level + 1;
+    LOG (2, "new assumption decision level %d", lgl->alevel);
+  } else {
+    if (lgl->opts->randec.val &&
+       lgl->limits->randec <= lgl->stats->decisions) {
+      lit = lglrandec (lgl);
+      lit = lgldecidephase (lgl, lit);
+      LOG (2, "random decision %d", lit);
+      if (lgl->opts->randecflipint.val &&
+         !(lgl->stats->randecs % lgl->opts->randecflipint.val)) {
+       lit = -lit;
+       LOG (2, "flipped random decision %d", lit);
+       lgl->stats->randecsflipped++;
+      }
+    } else {
+      lit = lglnextdecision (lgl);
+      lit = lgldecidephase (lgl, lit);
+    }
+  }
+  if (lit) lgldassume (lgl, lit);
+  return 1;
+}
+
+static void lgldcpdis (LGL * lgl) {
+  int idx, sign, lit, tag, blit, red, other, other2, i;
+  const int * w, * p, * eow;
+  Val val;
+  HTS * hts;
+  Stk * s;
+  NEW (lgl->dis, 1);
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      assert (hts->count > 0);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      hts->count = hts->offset = 0;
+      val = lglval (lgl, lit);
+      if (val > 0) continue;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < idx) continue;
+       val = lglval (lgl, other);
+       if (val > 0) continue;
+       red = blit & REDCS;
+       if (red && !lglisfree (lgl, other)) continue;
+       if (tag == BINCS) {
+         s = red ? &lgl->dis->red.bin : &lgl->dis->irr.bin;
+       } else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         val = lglval (lgl, other2);
+         if (val > 0) continue;
+         if (red && !lglisfree (lgl, other2)) continue;
+         s = red ? &lgl->dis->red.trn : &lgl->dis->irr.trn;
+         lglpushstk (lgl, s, other2);
+       }
+       lglpushstk (lgl, s, other);
+       lglpushstk (lgl, s, lit);
+       lglpushstk (lgl, s, 0);
+      }
+    }
+  lglrststk (&lgl->wchs->stk, 2);
+  lgl->wchs->stk.top[-1] = INT_MAX;
+  for (i = 0; i < MAXLDFW; i++) lgl->wchs->start[i] = INT_MAX;
+  lgl->wchs->free = 0;
+  lglrelstk (lgl, &lgl->learned);
+}
+
+static void lgldcpclnstk (LGL * lgl, int red, Stk * s) {
+  int oldsz, newsz, lit, mark, satisfied, repr, act;
+  const int * p, * c, * eos = s->top;
+  int * start, * q, * r, * d;
+  Stk * t;
+  Val val;
+  q = start = s->start;
+  for (c = q; c < eos; c = p + 1) {
+    act = *c;
+    if (act == REMOVED) {
+      for (p = c + 1; p < eos && *p == REMOVED; p++)
+       ;
+      assert (p >= eos || *p < NOTALIT || lglisact (*p));
+      p--;
+      continue;
+    }
+    if (lglisact (act)) *q++ = *c++; else act = -1;
+    d = q;
+    satisfied = 0;
+#ifndef NDEBUG
+    for (p = c; assert (p < eos), (lit = *p); p++) {
+      assert (!lglavar (lgl, lit)->mark);
+      repr = lglirepr (lgl, lit);
+      assert (abs (repr) == 1 || !lglavar (lgl, lit)->mark);
+    }
+#endif
+    for (p = c; assert (p < eos), (lit = *p); p++) {
+      assert (lit < NOTALIT);
+      if (satisfied) continue;
+      repr = lglirepr (lgl, lit);
+      val = lglcval (lgl, repr);
+      if (val > 0) { satisfied = 1; continue; }
+      if (val < 0) continue;
+      mark = lglmarked (lgl, repr);
+      if (mark < 0) { satisfied = 1; continue; }
+      if (mark > 0) continue;
+      lglmark (lgl, repr);
+      *q++ = repr;
+    }
+    oldsz = p - c;
+    for (r = d; r < q; r++) lglunmark (lgl, *r);
+    if (satisfied || !oldsz) { q = d - (act >= 0); continue; }
+    newsz = q - d;
+    if (newsz >= 4) {
+      assert (act < 0 || d[-1] == act);
+      *q++ = 0;
+      assert (d <= c);
+    } else if (!newsz) {
+      LOG (1, "found empty clause while cleaning decomposition");
+      lgl->mt = 1;
+      q = d - (act >= 0);
+    } else if (newsz == 1) {
+      LOG (1, "new unit %d while cleaning decomposition", d[0]);
+      lglunit (lgl, d[0]);
+      q = d - (act >= 0);
+    } else if (newsz == 2) {
+      t = red ? &lgl->dis->red.bin : &lgl->dis->irr.bin;
+      if (s != t) {
+       lglpushstk (lgl, t, d[0]);
+       lglpushstk (lgl, t, d[1]);
+       lglpushstk (lgl, t, 0);
+       q = d - (act >= 0);
+      } else *q++ = 0;
+    } else {
+      assert (newsz == 3);
+      t = red ? &lgl->dis->red.trn : &lgl->dis->irr.trn;
+      if (s != t) {
+       lglpushstk (lgl, t, d[0]);
+       lglpushstk (lgl, t, d[1]);
+       lglpushstk (lgl, t, d[2]);
+       lglpushstk (lgl, t, 0);
+       q = d - (act >= 0);
+      } else *q++ = 0;
+    }
+  }
+  s->top = q;
+}
+
+static void lgldcpconnaux (LGL * lgl, int red, int glue, Stk * s) {
+  int * start = s->start, * q, * d, lit, size, lidx, act;
+  const int * p, * c, * eos = s->top;
+  assert (red == 0 || red == REDCS);
+  assert (!glue || red);
+  q = start;
+  for (c = q; c < eos; c = p + 1) {
+    if (lglisact (act = *c)) *q++ = *c++; else act = -1;
+    d = q;
+    for (p = c; (lit = *p); p++) {
+      assert (!lgl->repr[abs (lit)]);
+      assert (!lgl->vals[abs (lit)]);
+      *q++ = lit;
+    }
+    size = q - d;
+    if (size == 2) {
+      q = d - (act >= 0);
+      lglwchbin (lgl, d[0], d[1], red);
+      lglwchbin (lgl, d[1], d[0], red);
+    } else if (size == 3) {
+      q = d - (act >= 0);
+      lglwchtrn (lgl, d[0], d[1], d[2], red);
+      lglwchtrn (lgl, d[1], d[0], d[2], red);
+      lglwchtrn (lgl, d[2], d[0], d[1], red);
+    } else {
+      assert (size > 3);
+      *q++ = 0;
+      lidx = d - start;
+      if (red) {
+       assert (lidx <= MAXREDLIDX);
+       lidx <<= GLUESHFT;
+       assert (0 <= lidx);
+       lidx |= glue;
+      }
+      (void) lglwchlrg (lgl, d[0], d[1], red, lidx);
+      (void) lglwchlrg (lgl, d[1], d[0], red, lidx);
+    }
+  }
+  s->top = q;
+}
+
+static void lgldcpcon (LGL * lgl) {
+  Stk * lir;
+  int glue;
+  lgldcpconnaux (lgl, 0, 0, &lgl->dis->irr.bin);
+  lgldcpconnaux (lgl, REDCS, 0, &lgl->dis->red.bin);
+  lgldcpconnaux (lgl, 0, 0, &lgl->dis->irr.trn);
+  lgldcpconnaux (lgl, REDCS, 0, &lgl->dis->red.trn);
+  lglrelstk (lgl, &lgl->dis->irr.bin);
+  lglrelstk (lgl, &lgl->dis->irr.trn);
+  lglrelstk (lgl, &lgl->dis->red.bin);
+  lglrelstk (lgl, &lgl->dis->red.trn);
+  DEL (lgl->dis, 1);
+  lgldcpconnaux (lgl, 0, 0, &lgl->irr);
+  for (glue = 0; glue < MAXGLUE; glue++) {
+    lir = lgl->red + glue;
+    lgldcpconnaux (lgl, REDCS, glue, lir);
+  }
+  lglfullyconnected (lgl);
+}
+
+static void lgldcpcln (LGL * lgl) {
+  int glue, old, rounds = 0;
+  Stk * lir;
+  do {
+    rounds++;
+    old = lgl->stats->fixed.current;
+    lgldcpclnstk (lgl, 0, &lgl->irr);
+    lgldcpclnstk (lgl, 0, &lgl->dis->irr.bin);
+    lgldcpclnstk (lgl, 0, &lgl->dis->irr.trn);
+    lgldcpclnstk (lgl, REDCS, &lgl->dis->red.bin);
+    lgldcpclnstk (lgl, REDCS, &lgl->dis->red.trn);
+    for (glue = 0; glue < MAXGLUE; glue++) {
+      lir = lgl->red + glue;
+      lgldcpclnstk (lgl, REDCS, lir);
+    }
+  } while (old < lgl->stats->fixed.current);
+  LOG (1, "iterated %d decomposition cleaning rounds", rounds);
+}
+
+static void lglepush (LGL * lgl, int ilit) {
+  int elit = ilit ? lglexport (lgl, ilit) : 0;
+  lglpushstk (lgl, &lgl->extend, elit);
+  LOG (4, "pushing external %d internal %d", elit, ilit);
+}
+
+static void lglemerge (LGL * lgl, int ilit0, int ilit1) {
+  int elit0 = lglexport (lgl, ilit0), elit1 = lglexport (lgl, ilit1);
+  int repr0 = lglerepr (lgl, elit0), repr1 = lglerepr (lgl, elit1);
+  Ext * ext0 = lglelit2ext (lgl, repr0);
+#ifndef NDEBUG
+  Ext * ext1 = lglelit2ext (lgl, repr1);
+  int repr = repr1;
+#endif
+  assert (abs (repr0) != abs (repr1));
+  if (repr0 < 0) {
+#ifndef NLGLOG
+    repr0 *= -1;
+#endif
+    repr1 *= -1;
+  }
+  ext0->equiv = 1;
+  ext0->repr = repr1;
+  LOG (2, "merging external literals %d and %d", repr0, repr1);
+  assert (lglerepr (lgl, elit0) == repr);
+  assert (lglerepr (lgl, elit1) == repr);
+  assert (!(ext0->frozen || ext0->tmpfrozen) ||
+           ext1->frozen || ext1->tmpfrozen);
+  lglepush (lgl, -ilit0); lglepush (lgl, ilit1); lglepush (lgl, 0);
+  lglepush (lgl, ilit0); lglepush (lgl, -ilit1); lglepush (lgl, 0);
+  if (lgl->opts->drup.val) {
+    lgldrupclsarg (lgl, -ilit0, ilit1, 0);
+    lgldrupclsarg (lgl, ilit0, -ilit1, 0);
+  }
+}
+
+static void lglimerge (LGL * lgl, int lit, int repr) {
+  int idx = abs (lit);
+  AVar * av = lglavar (lgl, idx);
+  assert (!lglifrozen (lgl, lit) || lglifrozen (lgl, repr));
+  if (lit < 0) repr = -repr;
+  assert (av->type == FREEVAR);
+  assert (lgl->repr);
+  av->type = EQUIVAR;
+  lgl->repr[idx] = repr;
+  lgl->stats->prgss++;
+  lgl->stats->irrprgss++;
+  lgl->stats->equiv.sum++;
+  lgl->stats->equiv.current++;
+  assert (lgl->stats->equiv.sum > 0);
+  assert (lgl->stats->equiv.current > 0);
+#if 0
+  if (lgl->opts->drup.val) lgldrupclsarg (lgl, idx, -repr, 0);
+  if (lgl->opts->drup.val) lgldrupclsarg (lgl, -idx, repr, 0);
+#endif
+#ifndef NLGLPICOSAT
+  lglpicosatchkclsarg (lgl, idx, -repr, 0);
+  lglpicosatchkclsarg (lgl, -idx, repr, 0);
+#endif
+  lglemerge (lgl, idx, repr);
+}
+
+static void lglfreezer (LGL * lgl) {
+  int frozen, melted, tmpfrozen, elit, erepr, ilit;
+  Ext * ext, * rext;
+  int * p, eass;
+  if (lgl->frozen) return;
+  for (elit = 1; elit <= lgl->maxext; elit++)
+    lgl->ext[elit].tmpfrozen = 0;
+  tmpfrozen = frozen = 0;
+  if (!lglmtstk (&lgl->eassume)) {
+    for (p = lgl->eassume.start; p < lgl->eassume.top; p++) {
+      eass = *p;
+      ext = lglelit2ext (lgl, eass);
+      assert (!ext->melted);
+      assert (!ext->eliminated);
+      assert (!ext->blocking);
+      if (!ext->frozen && !ext->tmpfrozen) {
+       ext->tmpfrozen = 1;
+       tmpfrozen++;
+       LOG (2, "temporarily freezing external assumption %d", eass);
+       erepr = lglerepr (lgl, eass);
+       rext = lglelit2ext (lgl, erepr);
+       if (ext != rext && !rext->frozen && !rext->tmpfrozen) {
+         assert (!rext->equiv);
+         assert (!rext->eliminated);
+         // assert (!rext->blocking);
+         LOG (2,
+           "temporarily freezing external assumption literal %d", erepr);
+         rext->tmpfrozen = 1;
+         tmpfrozen++;
+       }
+      }
+    }
+  }
+  for (elit = 1; elit <= lgl->maxext; elit++) {
+    ext = lglelit2ext (lgl, elit);
+    if (!ext->frozen) continue;
+    frozen++;
+    assert (!ext->melted);
+    assert (!ext->eliminated);
+    assert (!ext->blocking);
+    erepr = lglerepr (lgl, elit);
+    rext = lglelit2ext (lgl, erepr);
+    if (ext == rext) continue;
+    if (rext->frozen) continue;
+    if (rext->tmpfrozen) continue;
+    // assert (!rext->melted);
+    assert (!rext->equiv);
+    assert (!rext->eliminated);
+    // assert (!rext->blocking);
+    LOG (2, "temporarily freezing external literal %d", erepr);
+    rext->tmpfrozen = 1;
+    tmpfrozen++;
+  }
+  melted = 0;
+  for (elit = 1; elit <= lgl->maxext; elit++) {
+    ext = lglelit2ext (lgl, elit);
+    if (ext->frozen) continue;
+    if (ext->melted) continue;
+    if (ext->tmpfrozen) continue;
+    if (!ext->imported) continue;
+    LOG (2, "permanently melted external %d", elit);
+    ext->melted = 1;
+    melted++;
+  }
+  LOG (2, "found %d frozen external variables", frozen);
+  LOG (2, "temporarily frozen %d external variables", tmpfrozen);
+  LOG (2, "permanently melted %d external variables", melted);
+  lgl->frozen = 1;
+  LOG (2, "frozen solver");
+  melted = frozen = 0;
+  for (ilit = 2; ilit < lgl->nvars; ilit++) {
+    if (!lglisfree (lgl, ilit)) continue;
+    if (lglifrozen (lgl, ilit)) frozen++; else melted++;
+  }
+  lgl->allfrozen = !melted;
+  if (lgl->allfrozen) 
+    lglprt (lgl, 1, "[freezer] all %d free variables frozen", frozen);
+  else
+    lglprt (lgl, 1,
+      "[freezer] frozen %d variables out of %d free variables %.0f%%",
+      frozen, frozen + melted, lglpcnt (frozen, frozen + melted));
+}
+
+static int lglcmprepr (LGL * lgl, int a, int b) {
+  int f = lglifrozen (lgl, a), g = lglifrozen (lgl, b), res;
+  if ((res = g - f)) return res;
+  if ((res = (abs (a) - abs (b)))) return res;
+  return a - b;
+}
+
+static int lgltarjan (LGL * lgl) {
+  int * dfsimap, * mindfsimap, idx, oidx, sign, lit, blit, tag, other;
+  int dfsi, mindfsi, ulit, uother, tmp, repr, res, sgn, frozen;
+  const int * p, * w, * eow;
+  Stk stk, component;
+  AVar * av;
+  HTS * hts;
+  if (!lgl->nvars) return 1;
+  assert (lgl->frozen);
+  dfsi = 0;
+  NEW (dfsimap, 2*lgl->nvars);
+  NEW (mindfsimap, 2*lgl->nvars);
+  NEW (lgl->repr, lgl->nvars);
+  CLR (stk); CLR (component);
+  res = 1;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      ulit = lglulit (lit);
+      tmp = dfsimap[ulit];
+      if (tmp) continue;
+      lglpushstk (lgl, &stk, lit);
+      while (!lglmtstk (&stk)) {
+       lit = lglpopstk (&stk);
+       if (lit) {
+         ulit = lglulit (lit);
+         if (dfsimap[ulit]) continue;
+         dfsimap[ulit] = mindfsimap[ulit] = ++dfsi;
+         lglpushstk (lgl, &component, lit);
+         assert (dfsi > 0);
+         lglpushstk (lgl, &stk, lit);
+         lglpushstk (lgl, &stk, 0);
+         hts = lglhts (lgl, -lit);
+         if (!hts->offset) continue;
+         assert (hts->count > 0);
+         w = lglhts2wchs (lgl, hts);
+         eow = w + hts->count;
+         for (p = w; p < eow; p++) {
+           blit = *p;
+           tag = blit & MASKCS;
+           if (tag != BINCS) { p++; continue; }
+           other = blit >> RMSHFT;
+           uother = lglulit (other);
+           tmp = dfsimap[uother];
+           if (tmp) continue;
+           lglpushstk (lgl, &stk, other);
+         }
+       } else {
+         assert (!lglmtstk (&stk));
+         lit = lglpopstk (&stk);
+         ulit = lglulit (lit);
+         mindfsi = dfsimap[ulit];
+         assert (mindfsi);
+         hts = lglhts (lgl, -lit);
+         w = lglhts2wchs (lgl, hts);
+         eow = w + hts->count;
+         for (p = w; p < eow; p++) {
+           blit = *p;
+           tag = blit & MASKCS;
+           if (tag != BINCS) { p++; continue; }
+           other = blit >> RMSHFT;
+           uother = lglulit (other);
+           tmp = mindfsimap[uother];
+           if (tmp >= mindfsi) continue;
+           mindfsi = tmp;
+         }
+         if (mindfsi == dfsimap[ulit]) {
+           repr = lit;
+           frozen = lglifrozen (lgl, repr);
+           for (p = component.top - 1; (other = *p) != lit; p--) {
+             if (lglcmprepr (lgl, other, repr) < 0) repr = other;
+             if (!frozen && lglifrozen (lgl, other)) frozen = 1;
+           }
+           while ((other = lglpopstk (&component)) != lit) {
+             mindfsimap[lglulit (other)] = INT_MAX;
+             if (other == repr) continue;
+             if (other == -repr) {
+               if (lgl->opts->drup.val) lgldrupclsarg (lgl, repr, 0);
+               LOG (1, "empty clause since repr[%d] = %d", repr, other);
+               lgl->mt = 1; res = 0; goto DONE;
+             }
+             sgn = lglsgn (other);
+             oidx = abs (other);
+             tmp = lgl->repr[oidx];
+             if (tmp == sgn * repr) continue;
+             LOG (2, "repr[%d] = %d", oidx, sgn * repr);
+             if (tmp) {
+               if (lgl->opts->drup.val) lgldrupclsarg (lgl, repr, 0);
+               LOG (1, "empty clause since repr[%d] = %d and repr[%d] = %d",
+                    oidx, tmp, oidx, sgn * repr);
+               lgl->mt = 1; res = 0; goto DONE;
+             } else {
+               av = lglavar (lgl, oidx);
+               assert (sgn*oidx == other);
+               if (av->type == FREEVAR) lglimerge (lgl, other, repr);
+               else assert (av->type == FIXEDVAR);
+             }
+           }
+           mindfsimap[lglulit (lit)] = INT_MAX;
+           if (frozen) {
+             LOG (2, "equivalence class of %d is frozen", repr);
+             assert (lglifrozen (lgl, repr));
+           }
+         } else mindfsimap[ulit] = mindfsi;
+       }
+      }
+    }
+  }
+DONE:
+  lglrelstk (lgl, &stk);
+  lglrelstk (lgl, &component);
+  DEL (mindfsimap, 2*lgl->nvars);
+  DEL (dfsimap, 2*lgl->nvars);
+  if (!res) DEL (lgl->repr, lgl->nvars);
+  return res;
+}
+
+static int lglsyncunits (LGL * lgl) {
+  int * units, * eou, * p, elit, erepr, ilit, res, count = 0;
+  void (*produce)(void*, int);
+  int64_t steps;
+  Ext * ext;
+  Val val;
+  if (lgl->mt) return 0;
+  if (!lgl->cbs) return 1;
+  if (!lgl->cbs->units.consume.fun) return 1;
+  assert (!lgl->simp || !lgl->level);
+  steps = lglsteps (lgl);
+  if (steps < lgl->limits->sync.steps) return 1;
+  lgl->limits->sync.steps = steps + lgl->opts->syncunint.val;
+  lgl->stats->sync.units.consumed.calls++;
+  lgl->cbs->units.consume.fun (lgl->cbs->units.consume.state, &units, &eou);
+  if (units == eou) return 1;
+  lgl->stats->sync.units.consumed.tried++;
+  produce = lgl->cbs->units.produce.fun;
+  lgl->cbs->units.produce.fun = 0;
+  for (p = units; !lgl->mt && p < eou; p++) {
+    elit = *p;
+    erepr = lglerepr (lgl, elit);
+    ext = lglelit2ext (lgl, erepr);
+    assert (!ext->equiv);
+    ilit = ext->repr;
+    if (!ilit) continue;
+    if (erepr < 0) ilit = -ilit;
+    if (ilit == 1) continue;
+    if (ilit == -1) val = -1;
+    else {
+      assert (abs (ilit) > 1);
+      val = lglval (lgl, ilit);
+      if (val && lglevel (lgl, ilit)) val = 0;
+    }
+    if (val == 1) continue;
+    if (val == -1) {
+      LOG (1, "mismatching synchronized external unit %d", elit);
+      if (lgl->level > 0) lglbacktrack (lgl, 0);
+      lgl->mt = 1;
+    } else if (!lglisfree (lgl, ilit)) continue;
+    else {
+      assert (!val);
+      if (lgl->level > 0) lglbacktrack (lgl, 0);
+      lglunit (lgl, ilit);
+      LOG (2, "importing internal unit %d external %d",
+          lgl->tid, ilit, elit);
+      count++;
+    }
+  }
+  lgl->cbs->units.produce.fun = produce;
+  if (lgl->cbs->units.consumed.fun)
+    lgl->cbs->units.consumed.fun (lgl->cbs->units.consumed.state, count);
+  if (count) lgl->stats->sync.units.consumed.actual++;
+  if (lgl->mt) return 0;
+  if (count) LOG (1, "imported %d units", count);
+  if (!count) return 1;
+  assert (!lgl->level);
+  res = lglbcp (lgl);
+  if(!res && !lgl->mt) lgl->mt = 1;
+  return res;
+}
+
+static int lglelitblockingoreliminated (LGL * lgl, int elit) {
+  Ext * ext = lglelit2ext (lgl, elit);
+  return ext->blocking || ext->eliminated;
+}
+
+static int lglsynclsexist (LGL * lgl) {
+  int len, lit, blit, tag, other, other2;
+  int * s, * p, * w, * eow;
+  HTS * hts;
+  len = lglcntstk (&lgl->clause);
+  assert (!len || lgl->clause.top[-1]);
+  if (len <= 1) return 0;
+  s = lgl->clause.start;
+  for (p = s + 1; p + 1 < lgl->clause.top; p++) {
+    assert (lglmarked (lgl, *p) > 0);
+    if (lglhts (lgl, *s)->count > lglhts (lgl, *p)->count)
+      SWAP (int, *s, *p);
+  }
+  hts = lglhts (lgl, (lit = *s));
+  assert (lglmarked (lgl, lit) > 0);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      if (lglmarked (lgl, other) > 0) return 1;
+    } else {
+      assert (tag == TRNCS);
+      if (len <= 2) continue;
+      other = blit >> RMSHFT;
+      if (lglmarked (lgl, other) > 0) return 1;
+      other2 = *p;
+      if (lglmarked (lgl, other2) > 0) return 1;
+    }
+  }
+  return 0;
+}
+
+static int lglsyncls (LGL * lgl) {
+  int maxlevel, level, nonfalse, numtrue, res, delta, glue, consumed;
+  int * cls, elit, erepr, tmp, ilit, len, newglue;
+  const int * p;
+  int64_t rate;
+  if (lgl->mt) return 0;
+  if (!lgl->cbs) return 1;
+  if (!lgl->cbs->cls.consume.fun) return 1;
+  assert (!lgl->simp);
+  if (lgl->stats->confs < lgl->limits->sync.confs) return 1;
+  delta = lgl->opts->synclsint.val;
+  if (lgl->stats->sync.cls.consumed.calls) {
+    rate = 100*lgl->stats->sync.cls.consumed.tried;
+    rate /= lgl->stats->sync.cls.consumed.calls;
+    LOG (SCL, "syncls tried/calls = %lld/%lld = %d%%",
+      (LGLL) lgl->stats->sync.cls.consumed.tried,
+      (LGLL) lgl->stats->sync.cls.consumed.calls,
+      rate);
+    if (rate) delta /= rate;
+  }
+  lgl->limits->sync.confs = lgl->stats->confs + delta;
+  lgl->stats->sync.cls.consumed.calls++;
+  consumed = 0;
+RESTART:
+  lgl->cbs->cls.consume.fun (lgl->cbs->cls.consume.state, &cls, &glue);
+  if (!cls) return 1;
+  lgl->stats->sync.cls.consumed.tried++;
+  LOGCLS (SCL, cls, "trying to import external clause");
+  assert (lglmtstk (&lgl->clause));
+  maxlevel = nonfalse = numtrue = 0;
+#ifndef NDEBUG
+  for (p = cls; (elit = *p); p++) {
+    ilit = lglimport (lgl, elit);
+    if (abs (ilit) <= 1) continue;
+    assert (!lglmarked (lgl, ilit));
+  }
+#endif
+  for (p = cls; (elit = *p); p++) {
+    erepr = lglerepr (lgl, elit);
+    if (lglelitblockingoreliminated (lgl, erepr)) break;
+    ilit = lglimport (lgl, erepr);
+    if (!ilit) break;
+    if (ilit == 1) break;
+    if (ilit == -1) continue;
+    tmp = lglifixed (lgl, ilit);
+    if (tmp > 0) break;
+    if (tmp < 0) continue;
+    tmp = lglmarked (lgl, ilit);
+    if (tmp > 0) continue;
+    if (tmp < 0) break;
+    lglpushstk (lgl, &lgl->clause, ilit);
+    lglmark (lgl, ilit);
+    tmp = lglval (lgl, ilit);
+    if (tmp > 0) numtrue++;
+    else if (!tmp) nonfalse++;
+    else if ((level = lglevel (lgl, ilit)) > maxlevel) maxlevel = level;
+  }
+  res = 1;
+  if (!elit && lglsynclsexist (lgl)) elit = INT_MAX;
+  for (p = lgl->clause.start; p < lgl->clause.top; p++)
+    lglunmark (lgl, *p);
+  if (elit) goto DONE;
+  len = lglcntstk (&lgl->clause);
+  if (!numtrue && nonfalse <= 1) {
+    if (len <= 1 || maxlevel <= 1) level = 0;
+    else {
+      level = 0;
+      for (p = lgl->clause.start; p < lgl->clause.top; p++) {
+       ilit = *p;
+       tmp = lglval (lgl, ilit);
+       assert (tmp <= 0);
+       if (!tmp) continue;
+       tmp = lglevel (lgl, ilit);
+       if (tmp < maxlevel && tmp > level) level = tmp;
+      }
+    }
+    if (level < lgl->level) {
+      LOG (SCL, "importing clause requires to backtrack to level %d", level);
+      lglbacktrack (lgl, level);
+    }
+  }
+  lglpushstk (lgl, &lgl->clause, 0);
+  newglue = glue;
+#if 0
+  if (len > 3 && glue <= lgl->opts->gluekeep.val)
+    newglue = lgl->opts->gluekeep.val + 1;
+#endif
+  LOGCLS (SCL, lgl->clause.start,
+    "successfully imported as glue %d redundant glue %d length %d clause",
+    newglue, glue, len);
+  lgl->stats->sync.cls.consumed.actual++;
+  lgldrupligaddcls (lgl, REDCS);
+  lgladdcls (lgl, REDCS, newglue, !numtrue);
+  consumed++;
+  if (lgl->mt) res = 0;
+  else res = lglbcpsearch (lgl);
+DONE:
+  lglclnstk (&lgl->clause);
+  if (res && lgl->opts->synclsall.val) goto RESTART;
+  if (lgl->cbs->cls.consumed.fun)
+    lgl->cbs->cls.consumed.fun (lgl->cbs->cls.consumed.state, consumed);
+  return res;
+}
+
+static int lglprbpull (LGL * lgl, int lit, int probe) {
+  AVar * av;
+  assert (lgl->level == 1);
+  av = lglavar (lgl, lit);
+  if (av->mark) return 0;
+  if (!lglevel (lgl, lit)) return 0;
+  assert (lglevel (lgl, lit) == 1);
+  av->mark = 1;
+  lglpushstk (lgl, &lgl->seen, -lit);
+  LOG (3, "pulled in literal %d during probing analysis", -lit);
+  return 1;
+}
+
+static int lglprbana (LGL * lgl, int probe) {
+  int open, lit, r0, r1, tag, red, other, res, * p, * rsn;
+  assert (lgl->level == 1);
+  assert (lgl->conf.lit);
+  assert (lglmtstk (&lgl->seen));
+  lit = lgl->conf.lit;
+  r0 = lgl->conf.rsn[0], r1 = lgl->conf.rsn[1];
+  open = lglprbpull (lgl, lit, probe);
+  LOG (2, "starting probing analysis with reason of literal %d", lit);
+  for (;;) {
+    assert (lglevel (lgl, lit) == 1);
+    tag = r0 & MASKCS;
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      if (lglprbpull (lgl, other, probe)) open++;
+      if (tag == TRNCS && lglprbpull (lgl, r1, probe)) open++;
+    } else {
+      assert (tag == LRGCS);
+      red = r0 & REDCS;
+      p = lglidx2lits (lgl, red, r1);
+      while ((other = *p++)) open += lglprbpull (lgl, other, probe);
+    }
+    LOG (3, "open %d antecedents in probing analysis", open-1);
+    assert (open > 0);
+    while (!lglmarked (lgl, lit = lglpopstk (&lgl->trail)))
+      lglunassign (lgl, lit);
+    lglunassign (lgl, lit);
+    if (!--open) { res = lit; break; }
+    LOG (2, "analyzing reason of literal %d in probing analysis next", lit);
+    rsn = lglrsn (lgl, lit);
+    r0 = rsn[0], r1 = rsn[1];
+  }
+  assert (res);
+  if (res == probe)
+    LOG (2, "probing analysis returns the probe %d as 1st UIP", probe);
+  else
+    LOG (2, "probing analysis returns different 1st UIP %d and not probe %d",
+        res, probe);
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  return res;
+}
+
+static int lglederef (LGL * lgl, int elit) {
+  int ilit, res;
+  Ext * ext;
+  assert (elit);
+  if (abs (elit) > lgl->maxext) return -1;
+  ext = lglelit2ext (lgl, elit);
+  if (!(res = ext->val)) {
+    assert (!ext->equiv);
+    ilit = ext->repr;
+    res = ilit ? lglcval (lgl, ilit) : -1;
+  }
+  if (elit < 0) res = -res;
+  return res;
+}
+
+static int lgldecomp (LGL *); // TODO move
+
+static int lglhasbin (LGL * lgl, int a, int b) {
+  const int * w, * eow, * p;
+  int blit, tag, other;
+  HTS * ha, * hb;
+  ha = lglhts (lgl, a);
+  hb = lglhts (lgl, b);
+  if (hb->count < ha->count) {
+    SWAP (int, a, b); SWAP (HTS *, ha, hb);
+  }
+  w = lglhts2wchs (lgl, ha);
+  eow = w + ha->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == OCCS) continue;
+    if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+    assert (tag == BINCS);
+    other = blit >> RMSHFT;
+    if (other == b) return 1;
+  }
+  return 0;
+}
+
+static void lglwrkinit (LGL * lgl, int posonly, int fifo) {
+  int size, lit;
+  NEW (lgl->wrk, 1);
+  lgl->wrk->fifo = fifo;
+  size = lgl->wrk->size = lgl->nvars;
+  if (posonly) {
+    NEW (lgl->wrk->pos, size);
+    lgl->wrk->posonly = 1;
+  } else {
+    NEW (lgl->wrk->pos, 2*size);
+    lgl->wrk->pos += size;
+    for (lit = -size + 1; lit < -1; lit++) lgl->wrk->pos[lit] = -1;
+  }
+  for (lit = 2; lit < size; lit++) lgl->wrk->pos[lit] = -1;
+}
+
+static void lglwrkreset (LGL * lgl) {
+  lglrelstk (lgl, &lgl->wrk->queue);
+  if (lgl->wrk->posonly) DEL (lgl->wrk->pos, lgl->wrk->size);
+  else {
+    lgl->wrk->pos -= lgl->wrk->size;
+    DEL (lgl->wrk->pos, 2*lgl->wrk->size);
+  }
+  DEL (lgl->wrk, 1);
+}
+
+static void lglwrkcompact (LGL * lgl) {
+  int i, j = 0, lit, tail = lglcntstk (&lgl->wrk->queue);
+  for (i = lgl->wrk->head; i < tail; i++) {
+    lit = lgl->wrk->queue.start[i];
+    if (!lit) continue;
+    assert (!lgl->wrk->posonly || 1 < lit);
+    assert (1 < abs (lit) && abs (lit) < lgl->wrk->size);
+    assert (lgl->wrk->pos[lit] == i);
+    if (!lglisfree (lgl, lit)) {
+      lgl->wrk->pos[lit] = -1;
+      assert (lgl->wrk->count > 0);
+      lgl->wrk->count--;
+    } else {
+      lgl->wrk->queue.start[j] = lit;
+      lgl->wrk->pos[lit] = j++;
+    }
+  }
+  lglrststk (&lgl->wrk->queue, j);
+  lgl->wrk->head = 0;
+}
+
+static int lglwrktouched (LGL * lgl, int lit) {
+  if (lgl->wrk->posonly) lit = abs (lit);
+  return lgl->wrk->pos[lit] >= 0;
+}
+
+static int lglwrktouch (LGL * lgl, int lit) {
+  int tail, pos;
+  if (!lglisfree (lgl, lit)) return 1;
+  if (lgl->donotsched) {
+    if (lgl->cgrclosing && lglavar (lgl, lit)->donotcgrcls) return 1;
+    if (lgl->ternresing && lglavar (lgl, lit)->donoternres) return 1;
+    if (lgl->simpleprobing && lglavar (lgl, lit)->donotsimpleprobe) return 1;
+  }
+  if (lgl->wrk->posonly) lit = abs (lit);
+  tail = lglcntstk (&lgl->wrk->queue);
+  LOG (4, "work touch %d", lit);
+  if ((pos = lgl->wrk->pos[lit]) >= 0) {
+    assert (lgl->wrk->queue.start[pos] == lit);
+    lgl->wrk->queue.start[pos] = 0;
+  }
+  lgl->wrk->count++;
+  assert (lgl->wrk->count > 0);
+  lgl->wrk->pos[lit] = tail;
+  lglpushstk (lgl, &lgl->wrk->queue, lit);
+  if (tail/2 > lgl->wrk->count) lglwrkcompact (lgl);
+  return 1;
+}
+
+static int lglwrkdeq (LGL * lgl) {
+  int res, pos;
+  while ((pos = lgl->wrk->head) < lglcntstk (&lgl->wrk->queue)) {
+    lgl->wrk->head++;
+    res = lgl->wrk->queue.start[pos];
+    if (!res) continue;
+    lgl->wrk->queue.start[pos] = 0;
+    assert (lgl->wrk->count > 0);
+    lgl->wrk->count--;
+    assert (lgl->wrk->pos[res] == pos);
+    lgl->wrk->pos[res] = -1;
+    if (lglisfree (lgl, res)) return res;
+  }
+  return 0;
+}
+
+static int lglwrkpop (LGL * lgl) {
+  int res;
+  while (lglcntstk (&lgl->wrk->queue) > lgl->wrk->head) {
+    res = lglpopstk (&lgl->wrk->queue);
+    if (!res) continue;
+#ifndef NDEBUG
+    {
+      int pos = lglcntstk (&lgl->wrk->queue);
+      assert (lgl->wrk->pos[res] == pos);
+    }
+#endif
+    lgl->wrk->pos[res] = -1;
+    if (lglisfree (lgl, res)) return res;
+  }
+  return 0;
+}
+
+static int lglwrknext (LGL * lgl) {
+  return lgl->wrk->fifo ? lglwrkdeq (lgl) : lglwrkpop (lgl);
+}
+
+static int lglrandlitrav (LGL * lgl, int (*fun)(LGL*,int lit)) {
+  int delta, mod, prev, first, ulit, count;
+  if (lgl->nvars < 2) return 0;
+  first = mod = 2*lgl->nvars;
+  ulit = lglrand (lgl) % mod;
+  delta = lglrand (lgl) % mod;
+  if (!delta) delta++;
+  while (lglgcd (delta, mod) > 1)
+    if (++delta == mod) delta = 1;
+  count = mod;
+  LOG (2,
+    "random literal traversal start %d delta %d mod %d",
+     ulit, delta, mod);
+  for (;;) {
+    count--;
+    assert (count >= 0);
+    if (ulit >= 4 && !fun (lgl, lglilit (ulit))) return 0;
+    prev = ulit;
+    ulit += delta;
+    if (ulit >= mod) ulit -= mod;
+    if (ulit == first) { assert (!count); break; }
+    if (first == mod) first = prev;
+  }
+  return 1;
+}
+
+static void lglsimpleprobeinit (LGL * lgl) {
+  int idx, rem = 0, ret = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) lgl->avars[idx].equiv = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotsimpleprobe) ret++; else rem++;
+  }
+  if (!rem) {
+    ret = 0;
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      if (!lglisfree (lgl, idx)) continue;
+      lglavar (lgl, idx)->donotsimpleprobe = 0;
+      rem++;
+    }
+  }
+  if (!ret)
+    lglprt (lgl, 1, "[simpleprobe-%d] all %d free variables schedulable",
+            lgl->stats->prb.simple.count, rem);
+  else
+    lglprt (lgl, 1,
+      "[simpleprobe-%d] %d schedulable variables %.0f%%",
+      lgl->stats->prb.simple.count, rem, lglpcnt (rem, lglrem (lgl)));
+  lglwrkinit (lgl, 0, 1);
+  assert (!lgl->donotsched), lgl->donotsched = 1;
+  lglrandlitrav (lgl, lglwrktouch);
+  assert (lgl->donotsched), lgl->donotsched = 0;
+  assert (lgl->opts->prbsimple.val);
+  lglchkirrstats (lgl);
+}
+
+static void lglsimpleprobereset (LGL * lgl, int nvars) {
+  const int * p;
+  int idx;
+  lglrelstk (lgl, &lgl->sprb->units);
+  lglrelstk (lgl, &lgl->sprb->impls);
+  lglrelstk (lgl, &lgl->sprb->eqs);
+  for (idx = 2; idx < lgl->nvars; idx++) lgl->avars[idx].donotsimpleprobe = 1;
+  for (p = lgl->wrk->queue.start; p < lgl->wrk->queue.top; p++)
+    lgl->avars[abs (*p)].donotsimpleprobe = 0;
+  lglwrkreset (lgl);
+  lglrelstk (lgl, &lgl->sprb->counted);
+  lglrelstk (lgl, &lgl->sprb->marked);
+  assert (nvars == lgl->nvars);
+  lgl->sprb->spes -= nvars;
+  DEL (lgl->sprb->spes, 2*nvars);
+}
+
+static int lglflush (LGL *);
+static void lgldense (LGL *, int);
+static void lglsparse (LGL *);
+
+static int lglsimpleprobeunits (LGL * lgl) {
+  const int * p;
+  int lit, res;
+  Val val;
+  res = 0;
+  lglchkirrstats (lgl);
+  for (p = lgl->sprb->units.start; !lgl->mt && p < lgl->sprb->units.top; p++) {
+    lit = *p;
+    val = lglval (lgl, lit);
+    if (val > 0) continue;
+    lgl->stats->prb.simple.failed++;
+    if (val < 0) {
+      if (lgl->opts->drup.val) lgldrupclsarg (lgl, lit, 0);
+      LOG (1, "inconsistent unit %d", lit);
+      lgl->mt = 1;
+    } else {
+      lglunit (lgl, lit);
+      res++;
+      if (!lglflush (lgl)) {
+       LOG (1, "propagating simple HBR unit %d results in conflict", lit);
+       lgl->mt = 1;
+      }
+    }
+  }
+  return res;
+}
+
+static int lglsimpleprobeimpls (LGL * lgl) {
+  int a, b, res;
+  res = 0;
+  while (!lglmtstk (&lgl->sprb->impls)) {
+    b = lglpopstk (&lgl->sprb->impls);
+    a = lglpopstk (&lgl->sprb->impls);
+    if (lglval (lgl, a) || lglval (lgl, b)) continue;
+    if (lglhasbin (lgl, a, b)) continue;
+    LOG (2, "adding previously detected hyper binary resolvent %d %d", a, b);
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, a, b, 0);
+#ifndef NLGLPICOSAT
+    lglpicosatchkclsarg (lgl, a, b, 0);
+#endif
+    res++;
+    lgl->stats->hbr.cnt++;
+    lgl->stats->hbr.simple++;
+    (void) lglwchbin (lgl, a, b, REDCS);
+    (void) lglwchbin (lgl, b, a, REDCS);
+    lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+    lglwrktouch (lgl, -a);
+    lglwrktouch (lgl, -b);
+    if (!lglhasbin (lgl, -a, -b)) continue;
+    LOG (2, "found equivalent literals %d and %d", -a, b);
+    lglpushstk (lgl, &lgl->sprb->eqs, -a);
+    lglpushstk (lgl, &lgl->sprb->eqs, b);
+  }
+  return res;
+}
+
+static int lglhasonlybin (LGL * lgl, int lit, int other) {
+  HTS * hts = lglhts (lgl, lit);
+  const int * w;
+  int blit;
+  if (hts->count != 1) return 0;
+  w = lglhts2wchs (lgl, hts);
+  blit = *w;
+  if ((blit & MASKCS) != BINCS) return 0;
+  return (blit >> RMSHFT) == other;
+}
+
+static int lglsimpleprobemerged (LGL * lgl, int a, int b) {
+  return lglhasonlybin (lgl, -a, b) && lglhasonlybin (lgl, -b, a);
+}
+
+static int lglflushclauses (LGL * lgl, int lit);
+
+static void lglsimpleprobeclscp (LGL * lgl, int nonrepr, int repr, Stk * stk) {
+  int blit, tag, red, other, other2, lidx, count, found, start, trivial;
+  const int * p, * w, * eow, * c, * q;
+  HTS * hts = lglhts (lgl, nonrepr);
+  assert (abs (repr) < abs (nonrepr));
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  count = 0;
+  for (p = w; p < eow; p++) {
+    INCSTEPS (prb.simple.steps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    start = lglcntstk (stk);
+    trivial = 0;
+    red = blit & REDCS;
+    lglpushstk (lgl, stk, red);
+    lglpushstk (lgl, stk, repr);
+    if (tag == BINCS || tag == TRNCS) {
+      other = blit >> RMSHFT;
+      if (other == -repr) trivial = 1;
+      else if (other != repr) lglpushstk (lgl, stk, other);
+      if (tag == TRNCS) {
+       other2 = *p;
+       if (other2 == -repr) trivial = 1;
+       else if (other2 != repr) lglpushstk (lgl, stk, other2);
+      }
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, red, lidx);
+      found = 0;
+      for (q = c; !trivial && (other = *q); q++) {
+       if (other >= NOTALIT) trivial = 1;
+       else if (other == nonrepr) found++;
+       else if (other == -repr) trivial = 1;
+       else if (other != repr) lglpushstk (lgl, stk, other);
+      }
+      assert (trivial || found);
+    }
+    if (trivial) lglrststk (stk, start);
+    else lglpushstk (lgl, stk, 0), count++;
+  }
+  LOG (2, "copied %d clauses with %d replacing %d by %d",
+       count, nonrepr, nonrepr, repr);
+}
+
+static int lglsimpleprobebinexists (LGL * lgl, int a, int b) {
+  const int * p, * w, * eow;
+  int blit, tag, red, other;
+  HTS * hts;
+  hts = lglhts (lgl, a);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    other = blit >> RMSHFT;
+    if (other == b) return 1;
+  }
+  return 0;
+}
+
+static int lglsimpleprobetrnexists (LGL * lgl, int a, int b, int c) {
+  int blit, tag, red, other, other2;
+  const int * p, * w, * eow;
+  HTS * hts;
+  hts = lglhts (lgl, a);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    red = blit & REDCS;
+    if (red) continue;
+    other = blit >> RMSHFT;
+    if (tag == BINCS) {
+      if (other == b) return 1;
+      if (other == c) return 1;
+    } else if (tag == TRNCS) {
+      other2 = *p;
+      if (other == b && other2 == c) return 1;
+      if (other == c && other2 == b) return 1;
+    }
+  }
+  return 0;
+}
+
+static int lglsimpleprobelrgexists (LGL * lgl, int a) {
+  int blit, tag, red, other, other2, lidx, res;
+  const int * p, * w, * eow, * c, * q;
+  HTS * hts;
+  for (p = lgl->clause.start; p + 1 < lgl->clause.top; p++) {
+    other = *p;
+    assert (!lglsignedmarked (lgl, other));
+    lglsignedmark (lgl, other);
+  }
+  assert (lglsignedmarked (lgl, a));
+  hts = lglhts (lgl, a);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  res = 0;
+  for (p = w; !res && p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    red = blit & REDCS;
+    if (red || tag == LRGCS) continue;
+    other = blit >> RMSHFT;
+    if (tag == BINCS) {
+      res = lglsignedmarked (lgl, other);
+    } else if (tag == TRNCS) {
+      other2 = *p;
+      res = lglsignedmarked (lgl, other) && lglsignedmarked (lgl, other2);
+    } else {
+      assert (tag == OCCS);
+      lidx = other;
+      c = lglidx2lits (lgl, 0, lidx);
+      for (q = c; (other = *q); q++)
+       if (!lglsignedmarked (lgl, other)) break;
+      res = !other;
+    }
+  }
+  for (p = lgl->clause.start; p + 1 < lgl->clause.top; p++) 
+    lglunmark (lgl, *p);
+  return res;
+}
+
+static int lglsimpleprobeclausexists (LGL * lgl) {
+  int len = lglcntstk (&lgl->clause) - 1, a, b, c, * p, * s, res;
+  assert (len >= 0);
+  assert (!lgl->clause.top[-1]);
+  s = lgl->clause.start;
+  for (p = s + 1; p + 1 < lgl->clause.top; p++)
+    if (lglhts (lgl, *s)->count > lglhts (lgl, *p)->count)
+      SWAP (int, *s, *p);
+  a = lgl->clause.start[0];
+  if (len == 2) {
+    b = lgl->clause.start[1];
+    res = lglsimpleprobebinexists (lgl, a, b);
+  } else if (len == 3) {
+    b = lgl->clause.start[1];
+    c = lgl->clause.start[2];
+    res = lglsimpleprobetrnexists (lgl, a, b, c);
+  } else if (len > 3)
+    res = lglsimpleprobelrgexists (lgl, a);
+  else res = 0;
+  if (res) LOG (2, "will not add already existing clause");
+  return res;
+}
+
+static void lglsimpleprobeaddclausesonstack (LGL * lgl, Stk * stk) {
+  int count, red, lit, size;
+  const int * c, * p, * q;
+  count = 0;
+  for (c = stk->start; c < stk->top; c = p + 1) {
+    red = *(p = c);
+    if (p[1] == REMOVED) {
+      p++;
+      while (p + 1 < stk->top && p[1] == REMOVED) p++;
+      continue;
+    }
+    assert (!red || red == REDCS);
+    assert (lglmtstk (&lgl->clause));
+    do {
+      lit = *++p;
+      lglpushstk (lgl, &lgl->clause, lit);
+    } while (lit);
+    if (!lglsimpcls (lgl) && !lglsimpleprobeclausexists (lgl)) {
+      if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+      lglpicosatchkcls (lgl);
+#endif
+      q = lgl->clause.start;
+      size = lglcntstk (&lgl->clause);
+      assert (size > 0);
+      assert (!q[size-1]);
+      size--;
+      if (size > 2 && lgl->opts->prbsimple.val >= 3)
+       while ((lit = *q++))
+         lglwrktouch (lgl, lit);
+      if (size == 2 && lgl->opts->prbsimple.val >= 2)
+       lglwrktouch (lgl, -q[0]),
+       lglwrktouch (lgl, -q[1]);
+      lgldrupligaddcls (lgl, REDCS);
+      lgladdcls (lgl, red, 0, 1);
+      count++;
+    }
+    lglclnstk (&lgl->clause);
+    if (!lglflush (lgl)) break;
+  }
+  LOG (2, "added %d non-trivial clauses", count);
+}
+
+static void lglsimpleprobeaddprbincls (LGL * lgl, int a, int b) {
+  assert (lgl->probing);
+  assert (lglmtstk (&lgl->clause));
+  assert (abs (a) != abs (b));
+  assert (!lglval (lgl, a));
+  assert (!lglval (lgl, b));
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, 0);
+  if (!lglsimpleprobeclausexists (lgl)) {
+    LOG (2, "added simple probing connecting binary clause", a, b);
+    if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+    lglpicosatchkcls (lgl);
+#endif
+    lgldrupligaddcls (lgl, REDCS);
+    lgladdcls (lgl, 0, 0, 1);
+  }
+  lglclnstk (&lgl->clause);
+}
+
+static int lglcmpilit (int * a, int * b) {
+  int res, l = *a, k = *b;
+  if ((res = abs (l) - abs (k))) return res;
+  return l - k;
+}
+
+static int lglcmpcls (LGL * lgl, const int * c, const int * d) {
+  const int * p, * q;
+  for (p = c, q = d; *p && *q == *p; p++, q++)
+    ;
+  return *p - *q;
+}
+
+static int lglcmpsz (LGL * lgl, const int * start, PSz * p, PSz * q) {
+  const int * c, * d;
+  int res;
+  if ((res = p->size - q->size)) return res;
+  c = start + p->pos, d = start + q->pos;
+  if ((res = lglcmpcls (lgl, c, d))) return res;
+  if ((res = c[-1] - d[-1])) return res;
+  return p->pos - q->pos;
+}
+
+#define LGLCMPSZ(A,B) (lglcmpsz(lgl, start, (A), (B)))
+
+static void lglrmdupclsonstack (LGL * lgl, Stk * stk, Stk * sort) {
+  int * start, * c, * p, * d, pos, size, i;
+  PSz * ps;
+  lglclnstk (sort);
+  start = stk->start;
+  for (c = start; c < stk->top; c = p + 1) {
+    c++;
+    assert (c < stk->top);
+    pos = c - start;
+    size = 0;
+    for (p = c; *p; p++) size++;
+    SORT (int, c, size, lglcmpilit);
+    lglpushstk (lgl, sort, pos);
+    lglpushstk (lgl, sort, size);
+  }
+  size = lglcntstk (sort)/2;
+  if (size <= 1) return;
+  ps = (PSz *) sort->start;
+  SORT (PSz, ps, size, LGLCMPSZ);
+  for (i = 1; i < size; i++) {
+    if (ps[i-1].size != ps[i].size) continue;
+    c = stk->start + ps[i-1].pos;
+    d = stk->start + ps[i].pos;
+    if (lglcmpcls (lgl, c, d)) continue;
+    LOGCLS (4, d, "not copying duplicate %s clause", lglred2str (d[-1]));
+    while (*d) *d++ = REMOVED;
+    *d = REMOVED;
+  }
+}
+
+static void lglsimpleprobemerge (LGL * lgl, int repr, int nonrepr) {
+  Val valrepr, valnonrepr;
+  Stk stk, sort;
+  int unit;
+  lglchkirrstats (lgl);
+  lgl->stats->prb.simple.eqs++;
+  assert (abs (repr) < abs (nonrepr));
+  lglavar (lgl, nonrepr)->equiv = 1;
+  CLR (stk); CLR (sort);
+  lglsimpleprobeclscp (lgl, nonrepr, repr, &stk);
+  lglsimpleprobeclscp (lgl, -nonrepr, -repr, &stk);
+  lglflushclauses (lgl, nonrepr);
+  lglflushclauses (lgl, -nonrepr);
+  lglrmdupclsonstack (lgl, &stk, &sort);
+  lglsimpleprobeaddclausesonstack (lgl, &stk);
+  lglrelstk (lgl, &sort);
+  lglrelstk (lgl, &stk);
+  if (lgl->mt) return;
+  valrepr = lglval (lgl, repr);
+  valnonrepr = lglval (lgl, nonrepr);
+  if (valrepr && valnonrepr == valrepr) return;
+  if (valrepr && valrepr == -valrepr) {
+    LOG (1, "equality between %d and %d became inconsistent", repr, nonrepr);
+    lgl->mt = 1;
+    return;
+  }
+  if (valrepr && !valnonrepr) unit = valrepr < 0 ? -nonrepr : nonrepr;
+  else if (!valrepr && valnonrepr) unit = valnonrepr < 0 ? -repr : repr;
+  else unit = 0, assert (!valrepr), assert (!valnonrepr);
+  if (unit) {
+    LOG (1, "new unit %d from equality between %d and %d", unit, repr, nonrepr);
+    lglunit (lgl, unit);
+    (void) lglflush (lgl);
+  } else lglsimpleprobeaddprbincls (lgl, repr, -nonrepr),
+        lglsimpleprobeaddprbincls (lgl, -repr, nonrepr);
+  lglchkirrstats (lgl);
+}
+
+static int lglsimpleprobeqs (LGL * lgl) {
+  int a, b, res;
+  res = 0;
+  while (!lgl->mt && !lglmtstk (&lgl->sprb->eqs)) {
+    a = lglpopstk (&lgl->sprb->eqs);
+    b = lglpopstk (&lgl->sprb->eqs);
+    if (lglval (lgl, a)) continue;
+    assert (!lglval (lgl, b));
+    assert (abs (a) != abs (b));
+    if (lglsimpleprobemerged (lgl, a, b)) continue;
+    if (abs (b) < abs (a)) SWAP (int, a, b);
+    lglsimpleprobemerge (lgl, a, b);
+    res++;
+  }
+  return res;
+}
+
+static SPE * lglspe (LGL * lgl, int lit) {
+  assert (2 <= abs (lit) && abs (lit) < lgl->nvars);
+  return lgl->sprb->spes + lit;
+}
+
+static void lglsimpleprobehbr (LGL * lgl, int touched, const int * c) {
+  int blit, tag, lit, other, count, val, maxcount, rem, first, second;
+  const int * p, * q, * w, * eow;
+  unsigned sum, tmp;
+  SPE * spe;
+  HTS * hts;
+  first = second = count = sum = 0;
+  for (p = c; (lit = *p); p++) {
+    if (lglwrktouched (lgl, lit)) return;
+    if ((val = lglval (lgl, lit)) > 0) return;
+    if (val < 0) continue;
+    if (!first) first = lit;
+    else if (!second) second = lit;
+    sum += (unsigned) lit;
+    count++;
+  }
+  if (count == 2) {
+    assert (first && second);
+    if (lglhasbin (lgl, -first, -second)) {
+      LOG (2, "found equivalent literals %d and %d", -first, second);
+      lglpushstk (lgl, &lgl->sprb->eqs, -first);
+      lglpushstk (lgl, &lgl->sprb->eqs, second);
+      goto DONE;
+    }
+  }
+  rem = count;
+  maxcount = 0;
+  assert (lglmtstk (&lgl->sprb->counted));
+  for (p = c; (lit = *p); p++) {
+    if (INCSTEPS (prb.simple.steps) >= lgl->limits->prb.steps) goto DONE;
+    val = lglval (lgl, lit);
+    assert (val <= 0);
+    if (val) continue;
+    hts = lglhts (lgl, -lit);
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    assert (lglmtstk (&lgl->sprb->marked));
+    for (q = w; q < eow; q++) {
+      if (INCSTEPS (prb.simple.steps) >= lgl->limits->prb.steps) goto DONE;
+      blit = *q;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) q++;
+      if (tag != BINCS) continue;
+      other = blit >> RMSHFT;
+      val = lglval (lgl, other);
+      assert (val >= 0);
+      if (val) continue;
+      if ((spe = lglspe (lgl, other))->mark) continue;
+      if (lglspe (lgl, -other)->mark) {
+       LOG (2, "unit %d through very simple hyper binary resolution", -lit);
+       lglpushstk (lgl, &lgl->sprb->units, -lit);
+       goto DONE;
+      }
+      if (!spe->count) lglpushstk (lgl, &lgl->sprb->counted, other);
+      spe->sum += (unsigned) lit;
+      spe->count++;
+      spe->mark = 1;
+      lglpushstk (lgl, &lgl->sprb->marked, other);
+      if (spe->count > maxcount) maxcount = spe->count;
+    }
+    while (!lglmtstk (&lgl->sprb->marked)) {
+      other = lglpopstk (&lgl->sprb->marked);
+      spe = lglspe (lgl, other);
+      assert (spe->mark);
+      spe->mark = 0;
+    }
+    rem--;
+    assert (maxcount + rem <= count);
+    if (maxcount + rem + 1 < count) goto DONE;
+  }
+  if (count <= 2) goto DONE;
+  for (q = lgl->sprb->counted.start; q < lgl->sprb->counted.top; q++) {
+    other = *q;
+    assert (!lglval (lgl, other));
+    spe = lglspe (lgl, other);
+    assert (spe->count <= count);
+    if (spe->count == count) {
+      LOG (2, "unit %d through simple hyper binary resolution", other);
+      lglpushstk (lgl, &lgl->sprb->units, other);
+    } else if (spe->count + 1 == count) {
+      tmp = sum - spe->sum;
+      lit = (int) tmp;
+      assert (2 <= abs (lit) && abs (lit) < lgl->nvars);
+      if (abs (lit) != abs (other) && !lglhasbin (lgl, other, lit)) {
+       LOG (2, "simple hyper binary resolvent %d %d", other, lit);
+       lglpushstk (lgl, &lgl->sprb->impls, other);
+       lglpushstk (lgl, &lgl->sprb->impls, lit);
+      }
+    }
+  }
+  for (p = c; (lit = *p); p++) {
+    if (lglval (lgl, lit)) continue;
+    spe = lglspe (lgl, lit);
+    if (spe->count + 2 != count) continue;
+    tmp = sum - spe->sum;
+    tmp -= (unsigned) lit;
+    other = (int) tmp;
+    assert (2 <= abs (other) && abs (other) < lgl->nvars);
+    if (abs (lit) != abs (other) && !lglhasbin (lgl, other, lit)) {
+      LOG (2, "self-subsuming hyper binary resolvent %d %d", other, lit);
+      lglpushstk (lgl, &lgl->sprb->impls, other);
+      lglpushstk (lgl, &lgl->sprb->impls, lit);
+    }
+  }
+DONE:
+  while (!lglmtstk (&lgl->sprb->counted)) {
+    lit = lglpopstk (&lgl->sprb->counted);
+    spe = lglspe (lgl, lit);
+    CLRPTR (spe);
+  }
+  lglclnstk (&lgl->sprb->marked);
+}
+
+static void lglpushnmarkseen (LGL * lgl, int lit) {
+  lglpushstk (lgl, &lgl->seen, lit);
+  lglmarkunmarked (lgl, lit);
+}
+
+static void lglsignedmarknpushseen (LGL * lgl, int lit) {
+  lglsignedmark (lgl, lit);
+  lglpushstk (lgl, &lgl->seen, lit);
+}
+
+static void lglsimpleliftmark (LGL * lgl, int root, int level) {
+  const int * p, * w, * eow;
+  int blit, tag, other;
+  HTS * hts;
+  INCSTEPS (prb.simple.steps);
+  assert (level > 0);
+  assert (lglsignedmarked (lgl, -root));
+  LOG (3, "next simple lifting marking from %d at level %d", root, level);
+  hts = lglhts (lgl, root);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    other = blit >> RMSHFT;
+    if (lglsignedmarked (lgl, other)) continue;
+    lglsignedmarknpushseen (lgl, other);
+    LOG (4, "next simple lifting marking from %d at level %d marked %d", 
+         root, level, other);
+    if (level > 1) lglsimpleliftmark (lgl, -other, level-1);
+  }
+}
+
+static void lglsimpleliftcollect (LGL * lgl, int root, int start, int level) {
+  const int * p, * w, * eow;
+  int blit, tag, other;
+  HTS * hts;
+  INCSTEPS (prb.simple.steps);
+  assert (level > 0);
+  LOG (3, "next simple lifting collecting from %d at level %d", start, level);
+  hts = lglhts (lgl, start);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    other = blit >> RMSHFT;
+    if (other == -root) continue;
+    if (lglsignedmarked (lgl, other)) {
+      LOG (2, "simple lifted unit %d with root %d", other, root);
+      lglpushstk (lgl, &lgl->sprb->units, other);
+    } else if (other != root && lglsignedmarked (lgl, -other)) {
+      LOG (2, "found equivalent literals %d and %d", root, other);
+      lglpushstk (lgl, &lgl->sprb->eqs, root);
+      lglpushstk (lgl, &lgl->sprb->eqs, other);
+    } 
+    if (level > 1) lglsimpleliftcollect (lgl, root, -other, level-1);
+  }
+}
+
+static void lglsimplelift (LGL * lgl, int root) {
+  int count, pos, neg;
+  pos = lglhts (lgl, root)->count;
+  neg = lglhts (lgl, -root)->count;
+  if (neg < pos) root = -root;
+  LOG (2, "next simple lifting %d", root);
+  assert (lglmtstk (&lgl->seen));
+  assert (!lglsignedmarked (lgl, -root));
+  lglsignedmarknpushseen (lgl, -root);
+  lglsimpleliftmark (lgl, root, lgl->opts->prbsimpleliftdepth.val);
+  count = lglcntstk (&lgl->seen);
+  LOG (3, "simple probing lifting marked %d literals for root %d", 
+       count, root);
+  if (!count) return;
+  lglsimpleliftcollect (lgl, root, -root, lgl->opts->prbsimpleliftdepth.val);
+#ifndef NLGLOG
+  {
+    int units = lglcntstk (&lgl->sprb->units);
+    int eqs = lglcntstk (&lgl->sprb->eqs);
+    assert (!(eqs & 1));
+    eqs >>= 1;
+    LOG (3, "found %d units through simple lifting for %d", units, root);
+    LOG (3, "found %d equivalences through simple lifting for %d", eqs, root);
+  }
+#endif
+  lglpopnunmarkstk (lgl, &lgl->seen);
+}
+
+static void lglsimpleprobelit (LGL * lgl, int lit) {
+  int blit, tag, other, other2, red, lidx, cls[4];
+  const int * p, * w, * eow, * c;
+  HTS * hts;
+  lgl->stats->prb.simple.probed++;
+  assert (!lglval (lgl, lit));
+  lglclnstk (&lgl->sprb->units);
+  lglclnstk (&lgl->sprb->impls);
+  if (!lglwrktouched (lgl, -lit)) lglsimplelift (lgl, lit);
+  LOG (2, "next simple probing %d", lit);
+  hts = lglhts (lgl, lit);
+  if (!hts->count) return;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    if (INCSTEPS (prb.simple.steps) >= lgl->limits->prb.steps) goto DONE;
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == BINCS || tag == LRGCS) continue;
+    if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      if (lglval (lgl, other)) continue;
+      other2 = *p;
+      if (lglval (lgl, other2)) continue;
+      cls[0] = lit, cls[1] = other, cls[2] = other2, cls[3] = 0;
+      lglsimpleprobehbr (lgl, lit, cls);
+    } else {
+      assert (tag == OCCS);
+      red = (blit & REDCS);
+      lidx = (blit >> RMSHFT);
+      c = lglidx2lits (lgl, red, lidx);
+      lglsimpleprobehbr (lgl, lit, c);
+    }
+  }
+DONE:
+  assert (lglmtstk (&lgl->seen));
+  lglpopnunmarkstk (lgl, &lgl->seen);
+}
+
+static void lglprtsimpleproberem (LGL * lgl) {
+  int idx, ret = 0, rem = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotsimpleprobe) ret++; else rem++;
+  }
+  if (rem)
+    lglprt (lgl, 1,
+      "[simpleprobe-%d] %d variables remain %.0f%% (%d retained)",
+      lgl->stats->prb.simple.count, rem, lglpcnt (rem, lglrem (lgl)), ret);
+  else {
+    lglprt (lgl, 1, "[simpleprobe-%d] fully completed simple probing",
+           lgl->stats->prb.simple.count);
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donotsimpleprobe = 0;
+  }
+}
+
+static int lglszpen (LGL * lgl) {
+  int res = lglceilld (lgl->stats->irr.clauses.cur/lgl->opts->sizepen.val);
+  if (res < 0) res = 0;
+  if (res > lgl->opts->sizemaxpen.val) res = lgl->opts->sizemaxpen.val;
+  return res;
+}
+
+#ifndef NLGLYALSAT
+
+static int lglitszpen (LGL * lgl) {
+  int res = lglceilld (lgl->stats->irr.lits.cur/lgl->opts->sizepen.val);
+  if (res < 0) res = 0;
+  if (res > lgl->opts->sizemaxpen.val + 2)
+    res = lgl->opts->sizemaxpen.val + 2;
+  return res;
+}
+
+#endif
+
+static int64_t lglvisearch (LGL * lgl) {
+  int64_t res = lgl->stats->visits.search;
+  assert (res >= lgl->limits->inc.visits);
+  res -= lgl->limits->inc.visits;
+  return res;
+}
+
+static void lglsetprbsimplelim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->prbsimplertc.val || lgl->opts->prbrtc.val) {
+    lgl->limits->prb.steps = LLMAX;
+    lglprt (lgl, 1,
+      "[simpleprobe-%d] no limit (run to completion)", 
+      lgl->stats->prb.simple.count);
+  } else {
+    limit = (lgl->opts->prbsimplereleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->prbsimplemineff.val) 
+      limit = lgl->opts->prbsimplemineff.val;
+    if (lgl->opts->prbsimplemaxeff.val >= 0 &&
+        limit > lgl->opts->prbsimplemaxeff.val)
+      limit = lgl->opts->prbsimplemaxeff.val;
+    if (lgl->stats->prb.simple.count <= 1 &&
+        lgl->opts->boost.val &&
+        lgl->opts->prbsimpleboost.val > 1) {
+      lglprt (lgl, 1,
+       "[simpleprobe-%d] boosting simple probing limit by %d",
+       lgl->stats->prb.simple.count, lgl->opts->prbsimpleboost.val);
+      limit *= lgl->opts->prbsimpleboost.val;
+    }
+    limit >>= (pen = lgl->limits->prb.simple.pen + lglszpen (lgl));
+    irrlim = lgl->stats->irr.clauses.cur/4;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1,
+       "[simpleprobe-%d] limit %lld based on %d irredundant clauses",
+       lgl->stats->prb.simple.count,
+       (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1,
+       "[simpleprobe-%d] limit %lld penalty %d = %d + %d",
+       lgl->stats->prb.simple.count, (LGLL) limit,
+       pen, lgl->limits->prb.simple.pen, lglszpen (lgl));
+    lgl->limits->prb.steps = lgl->stats->prb.simple.steps + limit;
+  }
+}
+
+static int lgldelaying (LGL * lgl, const char * name, int * delptr) {
+  if (!*delptr) return 0;
+  *delptr -= 1;
+  lglprt (lgl, 2,
+    "[%s-delayed] skipping this scheduled invocation and %d more",
+    name, *delptr);
+  return 1;
+}
+
+static int lglsimpleprobe (LGL * lgl) {
+  int deltarem, nunits, hbrs, neqs, oldrem = lglrem (lgl);
+  int lit, success, nvars;
+
+  if (lgldelaying (lgl, "simpleprobe",
+        &lgl->limits->prb.simple.del.rem)) return 1;
+
+  lglstart (lgl, &lgl->times->prb.simple);
+  lgl->stats->prb.simple.count++;
+
+  assert (!lgl->simp && !lgl->probing && !lgl->simpleprobing);
+  lgl->simp = lgl->probing = lgl->simpleprobing = 1;
+
+
+  NEW (lgl->sprb, 1);
+
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lglgc (lgl);
+  assert (lgl->frozen);
+  lgldense (lgl, 1);
+  lglsimpleprobeinit (lgl);
+  lglsetprbsimplelim (lgl);
+  neqs = hbrs = nunits = 0;
+
+  nvars = lgl->nvars;
+  NEW (lgl->sprb->spes, 2*nvars);
+  lgl->sprb->spes += nvars;
+
+  while (!lgl->mt && (lit = lglwrknext (lgl))) {
+    if (INCSTEPS (prb.simple.steps) >= lgl->limits->prb.steps) break;
+    if (!lglisfree (lgl, lit)) continue;
+    if (lglavar (lgl, lit)->equiv) continue;
+    lglsimpleprobelit (lgl, lit);
+    if (lgl->mt) break;
+    lglchkirrstats (lgl);
+    nunits += lglsimpleprobeunits (lgl);
+    if (lgl->mt) break;
+    hbrs += lglsimpleprobeimpls (lgl);
+    if (lgl->mt) break;
+    neqs += lglsimpleprobeqs (lgl);
+    if (!lglflush (lgl)) break;
+    if (lglterminate (lgl)) break;
+    if (!lglsyncunits (lgl)) break;
+  }
+
+  lglsimpleprobereset (lgl, nvars);
+  lglsparse (lgl);
+  if (!lgl->mt) lgldecomp (lgl);
+
+  DEL (lgl->sprb, 1);
+
+  deltarem = oldrem - lglrem (lgl);
+  success = deltarem || hbrs || nunits;
+  LGLUPDPEN (prb.simple, deltarem);
+  lglprtsimpleproberem (lgl);
+
+  lglprt (lgl, 1 + !success,
+    "[simpleprobe-%d] removed %d variables, found %d hbrs, %d units",
+    lgl->stats->prb.simple.count, deltarem, hbrs, nunits);
+
+  assert (lgl->simp && lgl->probing && lgl->simpleprobing);
+  lgl->simp = lgl->probing = lgl->simpleprobing = 0;
+  lglrep (lgl, 2, 'p');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static void lglmvbcls (LGL * lgl, int a, int b) {
+  assert (abs (a) != abs (b));
+  assert (!lglval (lgl, a));
+  assert (!lglval (lgl, b));
+  assert (lglmtstk (&lgl->clause)); 
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, 0);
+  if (!lglsimpleprobeclausexists (lgl)) {
+    LOG (2, "moving redundant binary clause %d %d", a, b);
+#ifndef NLGLPICOSAT
+    lglpicosatchkcls (lgl);
+#endif
+    lgldrupligaddcls (lgl, REDCS);
+    lgladdcls (lgl, REDCS, 0, 1);
+  }
+  lglclnstk (&lgl->clause);
+  lgl->stats->moved.bin++;
+}
+
+static void lglrmvbcls (LGL * lgl, int a, int b) {
+  lglrmbcls (lgl, a, b, 0);
+  if (lgl->opts->move.val) lglmvbcls (lgl, a, b);
+}
+
+static void lglmvtcls (LGL * lgl, int a, int b, int c) {
+  assert (abs (a) != abs (b));
+  assert (abs (a) != abs (c));
+  assert (abs (b) != abs (c));
+  assert (lglmtstk (&lgl->clause)); 
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, c);
+  lglpushstk (lgl, &lgl->clause, 0);
+  if (!lglsimpleprobeclausexists (lgl)) {
+    LOG (2, "moving redundant ternary clause %d %d %d", a, b, c);
+#ifndef NLGLPICOSAT
+    lglpicosatchkcls (lgl);
+#endif
+    lgldrupligaddcls (lgl, REDCS);
+    lgladdcls (lgl, REDCS, 0, 1);
+  }
+  lglclnstk (&lgl->clause);
+  lgl->stats->moved.trn++;
+}
+
+static void lglrmvtcls (LGL * lgl, int a, int b, int c) {
+  assert (abs (a) != abs (b));
+  assert (abs (a) != abs (c));
+  assert (abs (b) != abs (c));
+  lglrmtcls (lgl, a, b, c, 0);
+  if (lgl->opts->move.val >= 2) lglmvtcls (lgl, a, b, c);
+}
+
+static void lglmvlcls (LGL * lgl, int lidx) {
+  const int * p, * c;
+  int other;
+  assert (lglmtstk (&lgl->clause)); 
+  c = lglidx2lits (lgl, 0, lidx);
+  for (p = c; (other = *p); p++)
+    lglpushstk (lgl, &lgl->clause, other);
+  lglpushstk (lgl, &lgl->clause, 0);
+  if (!lglsimpleprobeclausexists (lgl)) {
+    LOGCLS (2, c, "moving redundant large clause");
+#ifndef NLGLPICOSAT
+    lglpicosatchkcls (lgl);
+#endif
+    lgldrupligaddcls (lgl, REDCS);
+    lgladdcls (lgl, REDCS, 0, 0);
+  }
+  lglclnstk (&lgl->clause);
+  lgl->stats->moved.lrg++;
+}
+
+static void lglrmvlcls (LGL * lgl, int lidx) {
+  if (lgl->opts->move.val >= 3) lglmvlcls (lgl, lidx);
+  lglrmlcls (lgl, lidx, 0);
+}
+
+static int lglwaiting (LGL * lgl, const char * str, int wait) {
+  if (!wait) return 0;
+  if (!lgl->wait) return 0;
+  if (wait >= 2 && lgl->opts->elim.val && !lgl->elmrtc) {
+    if (str)
+      lglprt (lgl, 2,
+       "[%s-waiting] on variable elimination to be completed", str);
+    return 1;
+  }
+  if (wait >= 1 && lgl->opts->block.val && !lgl->blkrtc) {
+    if (str)
+      lglprt (lgl, 2, 
+       "[%s-waiting] on blocked clause elimination to be completed", str);
+    return 1;
+  }
+  return 0;
+}
+
+static void lglbasicate (LGL * lgl, int lit) {
+  int blit, tag, red, other, other2, lidx;
+  const int * w, * eow, * p, * c, * l;
+  int nonfalse, numtrue, val;
+  HTS * hts;
+  if (!lgl->opts->bate.val) return;
+  if (lglwaiting (lgl, 0, lgl->opts->batewait.val)) return;
+RESTART:
+  hts = lglhts (lgl, -lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = * p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    red = blit & REDCS;
+    if (red) continue;
+    if (tag == BINCS) continue;
+    if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      numtrue = 0;
+      if ((val = lglval (lgl, other)) < 0) continue;
+      if (val > 0) {
+       if (!lglevel (lgl, other)) continue;
+       if (lgltd (lgl, other)->irr) numtrue++;
+      }
+      other2 = *p;
+      if ((val = lglval (lgl, other2)) < 0) continue;
+      if (val > 0) {
+       if (!lglevel (lgl, other2)) continue;
+       if (lgltd (lgl, other2)->irr) numtrue++;
+      }
+      if (!numtrue) continue;
+      LOG (2, "basic ATE ternary clause %d %d %d", -lit, other, other2);
+      lgl->stats->prb.basic.ate.trnr++;
+      lglrmvtcls (lgl, -lit, other, other2);
+      goto RESTART;
+    } else {
+      assert (tag == OCCS || tag == LRGCS);
+      if (tag == LRGCS && lgl->dense) continue;
+      lidx = (tag == LRGCS) ? *p : (blit >> RMSHFT);
+      assert (!red);
+      c = lglidx2lits (lgl, 0, lidx);
+      numtrue = nonfalse = 0;
+      for (l = c; (nonfalse < 2 || !numtrue) && (other = *l); l++) {
+       if (other == -lit) continue;
+       assert (other != lit);
+       if ((val = lglval (lgl, other)) >= 0) nonfalse++;
+       if (val > 0) {
+          if (!lglevel (lgl, other)) { numtrue = -1; break; }
+          if (lgltd (lgl, other)->irr) numtrue++;
+       }
+      }
+      if (numtrue > 0 && nonfalse >= 2) {
+       LOGCLS (2, c, "basic ATE large clause");
+       lgl->stats->prb.basic.ate.lrg++;
+       lglrmvlcls (lgl, lidx);
+       goto RESTART;
+      }
+    }
+  }
+}
+
+static void lglbasicatestats (LGL * lgl) {
+  int n = lgl->stats->prb.basic.ate.lrg + lgl->stats->prb.basic.ate.trnr;
+  int d = n - lgl->stats->prb.basic.lastate;
+  assert (d >= 0);
+  if (d <= 0) return;
+  lgl->stats->prb.basic.ate.count++;
+  lglprt (lgl, 1,
+    "[bate-%d] eliminated %d asymmetric tautologies during probing",
+    lgl->stats->prb.basic.ate.count, d);
+  lgl->stats->prb.basic.lastate = n;
+}
+
+static void lglbasicprobelit (LGL * lgl, int root) {
+  int old, ok, dom, lit, val;
+  Stk lift, saved;
+  const int * p;
+  CLR (lift); CLR (saved);
+  assert (lgl->simp);
+  assert (lgl->probing || lgl->cceing);
+  assert (!lgl->level);
+  LOG (2, "next probe %d positive phase", root);
+  assert (!lgl->level);
+  if (lgl->treelooking) lgl->stats->prb.treelook.probed++;
+  else if (lgl->cceing) lgl->stats->cce.probed++;
+  else assert (lgl->basicprobing), lgl->stats->prb.basic.probed++;
+  if (lglrand (lgl) & (1<<12)) root = -root;
+  lgliassume (lgl, root);
+  old = lgl->next;
+  ok = lglbcp (lgl);
+  dom = 0;
+  if (ok) {
+    lglclnstk (&saved);
+    lglbasicate (lgl, root);
+    for (p = lgl->trail.start + old; p < lgl->trail.top; p++) {
+      lit = *p;
+      if (lit == root) continue;
+      lglpushstk (lgl, &saved, lit);
+    }
+  } else dom = lglprbana (lgl, root);
+  lglbacktrack (lgl, 0);
+  if (!ok) {
+    LOG (1, "failed literal %d on probing", dom, root);
+    lglpushstk (lgl, &lift, -dom);
+    goto MERGE;
+  }
+  LOG (2, "next probe %d negative phase", -root);
+  assert (!lgl->level);
+  if (lgl->treelooking) lgl->stats->prb.treelook.probed++;
+  else if (lgl->cceing) lgl->stats->cce.probed++;
+  else assert (lgl->basicprobing), lgl->stats->prb.basic.probed++;
+  lgliassume (lgl, -root);
+  ok = lglbcp (lgl);
+  if (ok) {
+    lglbasicate (lgl, -root);
+    for (p = saved.start; p < saved.top; p++) {
+      lit = *p;
+      val = lglval (lgl, lit);
+      if (val <= 0) continue;
+      if (lgl->treelooking) lgl->stats->prb.treelook.lifted++;
+      else if (lgl->cceing) lgl->stats->cce.lifted++;
+      else assert (lgl->basicprobing), lgl->stats->prb.basic.lifted++;
+      lglpushstk (lgl, &lift, lit);
+      LOG (2, "lifted %d", lit);
+    }
+  } else dom = lglprbana (lgl, -root);
+  lglbacktrack (lgl, 0);
+  if (!ok) {
+    LOG (1, "failed literal %d on probing %d", dom, -root);
+    lglpushstk (lgl, &lift, -dom);
+  }
+MERGE:
+  while (!lglmtstk (&lift)) {
+    lit = lglpopstk (&lift);
+    val = lglval (lgl, lit);
+    if (val > 0) continue;
+    if (val < 0) goto EMPTY;
+    lglunit (lgl, lit);
+    if (lgl->treelooking) lgl->stats->prb.treelook.failed++;
+    else if (lgl->cceing) lgl->stats->cce.failed++;
+    else assert (lgl->basicprobing), lgl->stats->prb.basic.failed++;
+    if (lglbcp (lgl)) continue;
+EMPTY:
+    LOG (1, "empty clause after propagating lifted and failed literals");
+    lgl->mt = 1;
+  }
+  lglrelstk (lgl, &lift);
+  lglrelstk (lgl, &saved);
+}
+
+static TVar * lgltvar (LGL * lgl, int lit) {
+  int idx = abs (lit);
+  assert (2 <= idx && idx < lgl->nvars);
+  assert (lgl->tlk);
+  return lgl->tlk->tvars + idx;
+}
+
+static void lglsignedtlmark (LGL * lgl, int lit) {
+  TVar * tv = lgltvar (lgl, lit);
+  unsigned bit = 1u << (lit < 0);
+  if (tv->mark & bit) return;
+  tv->mark |= bit;
+}
+
+static int lglsignedtlmarked (LGL * lgl, int lit) {
+  TVar * tv = lgltvar (lgl, lit);
+  unsigned bit = 1u << (lit < 0);
+  return tv->mark & bit;
+}
+
+static void lgltlenq (LGL * lgl, int start) {
+  int lit, blit, tag, other, oldcount, newcount, * stk;
+  unsigned delta, i, j, mod;
+  const int * p, * w, * eos;
+  HTS * hts;
+  assert (!lglsignedtlmarked (lgl, start));
+  lglsignedtlmark (lgl, start);
+  lglpushstk (lgl, &lgl->tlk->stk, start);
+  while (!lglmtstk (&lgl->tlk->stk)) {
+    lit = lglpopstk (&lgl->tlk->stk);
+    LOG (2, "tree-look enqueue %d%s", lit, lit == start ? " start":"");
+    if (lit) {
+      assert (!lglval (lgl, lit));
+      assert (lglsignedtlmarked (lgl, lit));
+      lglpushstk (lgl, &lgl->tlk->seen, lit);
+      lglpushstk (lgl, &lgl->tlk->stk, 0);
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eos = w + hts->count;
+      oldcount = lglcntstk (&lgl->tlk->stk);
+      for (p = w; p < eos; p++) {
+        INCSTEPS (prb.treelook.steps);
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == OCCS) continue;
+       if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+       assert (tag == BINCS);
+       other = -(blit >> RMSHFT);
+       if (lglval (lgl, other)) assert (lglval (lgl, other) < 0);
+       else if (!lglsignedtlmarked (lgl, other)) {
+         lglsignedtlmark (lgl, other);
+         lglpushstk (lgl, &lgl->tlk->stk, other);
+       }
+      }
+      newcount = lglcntstk (&lgl->tlk->stk);
+      delta = newcount - oldcount;
+      assert (delta >= 0);
+      if ((mod = delta) <= 1) continue;
+      stk = lgl->tlk->stk.start;
+      for (i = 0; i < delta-1; i++, mod--) {
+       assert (mod > 0);
+       j = i + (lglrand (lgl) % mod);
+       assert (i <= j && j < delta);
+       if (i == j) continue;
+       SWAP (int, stk[i + oldcount], stk[j + oldcount]);
+      }
+    } else lglpushstk (lgl, &lgl->tlk->seen, 0);
+  }
+}
+
+static int lglisroot (LGL * lgl, int lit) { return !lglhasbins (lgl, lit); }
+
+static void lgltlunmarkall (LGL * lgl) {
+  int idx;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    lgl->tlk->tvars[idx].mark = 0;
+}
+
+static int lgltlschedlit (LGL * lgl, int lit) {
+  if (INCSTEPS (prb.treelook.steps) > lgl->limits->prb.steps) return 0;
+  if (!lglisfree (lgl, lit)) return 1;
+  if (lglsignedtlmarked (lgl, lit)) return 1;
+  if (!lglisroot (lgl, -lit)) return 1;
+  if (!lgl->tlk->lkhd && lglavar (lgl, lit)->donotreelook) return 1;
+  if (lgl->opts->treelook.val >= 2) {
+    lglbasicprobelit (lgl, -lit);
+    if (lgl->mt) return 0;
+    if (lglterminate (lgl)) return 0;
+    if (!lglisfree (lgl, lit)) return 1;
+    if (!lglisroot (lgl, -lit)) return 1;
+    if (!lglhasbins (lgl, lit)) return 1;
+  }
+  lgltlenq (lgl, lit);
+  return 1;
+}
+
+static int lgltlschedanylit (LGL * lgl, int lit) {
+  if (INCSTEPS (prb.treelook.steps) > lgl->limits->prb.steps) return 0;
+  if (!lglisfree (lgl, lit)) return 1;
+  if (lglsignedtlmarked (lgl, lit)) return 1;
+  if (!lgl->tlk->lkhd && lglavar (lgl, lit)->donotreelook) return 1;
+  if (lgl->opts->treelook.val >= 2) {
+    lglbasicprobelit (lgl, -lit);
+    if (lgl->mt) return 0;
+    if (lglterminate (lgl)) return 0;
+    if (!lglisfree (lgl, lit)) return 1;
+  }
+  lgltlenq (lgl, lit);
+  return 1;
+}
+
+static void lgltlsched (LGL * lgl) {
+  int idx, round, count, * p;
+  LOG (1, "scheduling tree-look literals");
+  for (round = 0; !lgl->mt && round < 2; round++) {
+    assert (lglmtstk (&lgl->tlk->seen));
+    assert (lglmtstk (&lgl->tlk->stk));
+    if (lglrandlitrav (lgl, lgltlschedlit))
+      lglrandlitrav (lgl, lgltlschedanylit);
+    lgltlunmarkall (lgl);
+    lglrelstk (lgl, &lgl->tlk->stk);
+    if (!lglmtstk (&lgl->tlk->seen)) break;
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donotreelook = 0;
+  }
+  lglfitstk (lgl, &lgl->tlk->seen);
+  count = 0;
+  for (p = lgl->tlk->seen.start; p < lgl->tlk->seen.top; p++)
+    if (*p) count++;
+  lglprt (lgl, 1,
+    "[treelook-%d] scheduled %d literals %.0f%%",
+    lgl->stats->prb.treelook.count, count, lglpcnt (count, 2*lglrem (lgl)));
+  if (!count)
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donotreelook = 0;
+}
+
+static void lgltlassign (LGL * lgl, Stk * assignment, int lit) {
+  TVar * tv;
+  LOG (2, "tree-look assign %d", lit);
+  tv = lgltvar (lgl, lit);
+  assert (!tv->val);
+  tv->val = lglsgn (lit) * (1 + lglcntstk (assignment));
+  lglpushstk (lgl, assignment, lit);
+  assert (tv->val);
+  assert (lglsgn (tv->val) == lglsgn (lit));
+}
+
+static void lgltlunassign (LGL * lgl, int lit) {
+  TVar * tv;
+  LOG (2, "tree-look unassign %d", lit);
+  tv = lgltvar (lgl, lit);
+  assert (tv->val);
+  assert (lglsgn (tv->val) == lglsgn (lit));
+  tv->val = 0;
+}
+
+static int lgltlval (LGL * lgl, int lit) {
+  TVar * tv = lgltvar (lgl, lit);
+  int res;
+  if (!tv->val) return 0;
+  res = lglsgn (tv->val);
+  if (lit < 0) res = -res;
+  return res;
+}
+
+static void lglincreducedptr (LGL * lgl, Flt * reducedptr, int size) {
+  Flt reduced = *reducedptr, inc = lglflt (-size, 1);
+  reduced = lgladdflt (reduced, inc);
+  LOG (2, "reduced score incremented to %s from %s by %s (size %d)",
+       lglflt2str (lgl, reduced), 
+       lglflt2str (lgl, *reducedptr), 
+       lglflt2str (lgl, inc),
+       size);
+  *reducedptr = reduced;
+}
+
+static int lgltlbcp (LGL * lgl,
+                     Stk * assignment, Flt * reducedptr, int dom) {
+  int next = lglcntstk (assignment), next2 = next, lit, size, implied;
+  int blit, tag, other, other2, val, lidx, red, found, trivial;
+  int numnonfalse, numfalse, firstfalse, litval, skip;
+  const int * p, * w, * eos, * c, * q;
+  HTS * hts;
+  if (lglval (lgl, dom)) return 1;
+  assert (!lgltlval (lgl, dom));
+  lgltlassign (lgl, assignment, dom);
+  lgl->stats->prb.treelook.probed++;
+  LOG (2, "starting tree-look bcp on %d", dom);
+  for (;;) {
+    if (next2 < lglcntstk (assignment)) {
+      assert (lgl->simp);
+      INCSTEPS (props.simp);
+      if (lgl->lkhd) INCSTEPS (props.lkhd);
+      lit = lglpeek (assignment, next2++);
+      assert (lgltlval (lgl, lit) > 0);
+      LOG (2, "tree-look binary clause bcp on %d", lit);
+      hts = lglhts (lgl, -lit);
+      w = lglhts2wchs (lgl, hts);
+      eos = w + hts->count;
+      for (p = w; p < eos; p++) {
+       assert (lgl->simp);
+       lgl->stats->visits.simp++;
+       if (lgl->lkhd) lgl->stats->visits.lkhd++;
+       INCSTEPS (prb.treelook.steps);
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == OCCS) continue;
+       if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+       assert (tag == BINCS);
+       other = blit >> RMSHFT;
+       val = lglval (lgl, other);
+       if (val < 0) return 0;
+       if (val > 0) continue;
+       val = lgltlval (lgl, other);
+       if (val < 0) return 0;
+       if (reducedptr) lglincreducedptr (lgl, reducedptr, 2);
+       if (val > 0) continue;
+       lgltlassign (lgl, assignment, other);
+      }
+    } else if (next < lglcntstk (assignment)) {
+      lit = lglpeek (assignment, next++);
+      litval = lgltlval (lgl, lit);
+      assert (litval > 0);
+      LOG (2, "tree-look non-binary clause bcp on %d", lit);
+      hts = lglhts (lgl, -lit);
+      w = lglhts2wchs (lgl, hts);
+      eos = w + hts->count;
+      for (p = w; p < eos; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == LRGCS || tag == TRNCS) p++;
+       if (tag == BINCS || tag == LRGCS) continue;
+       INCSTEPS (prb.treelook.steps);
+       assert (lglmtstk (&lgl->clause));
+       skip = trivial = 0;
+       if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         other2 = *p;
+         if (lglval (lgl, other) > 0 || 
+             lglval (lgl, other2) > 0) skip = 1;
+         else {
+           if (lgltlval (lgl, other) > 0 ||
+               lgltlval (lgl, other2) > 0) trivial = 1;
+           lglpushstk (lgl, &lgl->clause, -lit),
+           lglpushstk (lgl, &lgl->clause, other),
+           lglpushstk (lgl, &lgl->clause, other2);
+         }
+       } else {
+         assert (tag == OCCS);
+         red = blit & REDCS;
+         lidx = blit >> RMSHFT;
+         found = trivial = 0;
+         c = lglidx2lits (lgl, red, lidx);
+         INCSTEPS (prb.treelook.steps);
+         for (q = c; !skip && (other = *q); q++) {
+           if (other >= NOTALIT) skip = 1;
+           else if (lglval (lgl, other) > 0) skip = 1;
+           else {
+             if (other == -lit) assert (!found), found++;
+             if (lgltlval (lgl, other) > 0) trivial = 1;
+             lglpushstk (lgl, &lgl->clause, other);
+           }
+         }
+         assert (skip || found);
+       }
+       numnonfalse = numfalse = size = implied = 0;
+       firstfalse = 1;
+       if (!skip) {
+         INCSTEPS (prb.treelook.steps);
+         for (q = lgl->clause.start; q < lgl->clause.top; q++) {
+           other = *q;
+           if (lglval (lgl, other) < 0) continue;
+           size++;
+           if ((val = lgltlval (lgl, other)) < 0) {
+             if (reducedptr && -val < litval) firstfalse = 0;
+             numfalse++; 
+             continue; 
+           }
+           numnonfalse++;
+           if (implied == NOTALIT) continue;
+           else if (implied) implied = NOTALIT;
+           else implied = other;
+         }
+       }
+       lglclnstk (&lgl->clause);
+       if (skip) continue;
+       if (reducedptr && firstfalse) 
+         lglincreducedptr (lgl, reducedptr, size);
+       if (trivial) continue;
+       if (!numnonfalse) { assert (!implied); return 0; }
+       assert (implied);
+       if (implied == NOTALIT) continue;
+       assert (numnonfalse == 1);
+       if (!numfalse) continue; // TODO remove?
+       INCSTEPS (prb.treelook.steps);
+       if (tag == TRNCS) lgl->stats->hbr.trn++; else lgl->stats->hbr.lrg++;
+       LOG (2, "tree-look hyper binary resolvent %d %d", -dom, implied);
+       if (lgl->opts->drup.val) lgldrupclsarg (lgl, -dom, implied, 0);
+#ifndef NLGLPICOSAT
+       lglpicosatchkclsarg (lgl, -dom, implied, 0);
+#endif
+       (void) lglwchbin (lgl, -dom, implied, REDCS);
+       (void) lglwchbin (lgl, implied, -dom, REDCS);
+       lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       lgl->stats->hbr.cnt++;
+       lgl->stats->prgss++;
+       lgltlassign (lgl, assignment, implied);
+       assert (next > 0),  next--; // force to redo this trn/lrg literal
+       break;  // and continue outer 'next2' prop on 'implied'
+      }
+    } else break;
+  }
+  if (reducedptr) assert (lgl->tlk->lkhd), lgl->tlk->lkhd[dom] = *reducedptr;
+  return 1;
+}
+
+static void lgltreelooklit (LGL * lgl, Stk * a, Ftk * r, int lit) {
+  Flt reduced;
+  LOG (2, "treelook dequeue %d", lit);
+  if (lit) {
+    if (lgl->opts->treelook.val >= 2 &&
+       lglmtstk (a) &&
+       lglisfree (lgl, lit)) lglbasicprobelit (lgl, -lit);
+    if (r) {
+      reduced = lglmtftk (r) ? FLTMIN : lgltopftk (r);
+      lglpushftk (lgl, r, reduced);
+    }
+    lglpushstk (lgl, a, 0);
+    if (lgl->mt || !lglisfree (lgl, lit)) return;
+    if (lgltlval (lgl, -lit) > 0 ||
+       (!lgltlval (lgl, lit) && 
+        !lgltlbcp (lgl, a, r ? &reduced : 0, lit))) {
+      int tmp;
+      LOG (1, "tree-look failed literal %d", lit);
+      if (!(tmp = lglval (lgl, lit))) {
+       lgl->stats->prb.treelook.failed++;
+       lglunit (lgl, -lit);
+       if (!lglbcp (lgl)) {
+         if (!lgl->mt) lgl->mt = 1;
+         LOG (1, "inconsistent tree-look failed literal");
+       }
+      } else if (tmp > 0) {
+       lgl->stats->prb.treelook.failed++;
+       LOG (1, "tree-look failed literal literal %d inconsistent", lit);
+       if (!lgl->mt) lgl->mt = 1;
+      } else LOG (1, "tree-look failed literal %d already found", lit);
+    }
+    if (r) {
+      assert (r->start < r->top);
+      assert (r->top[-1] <= reduced);
+      r->top[-1] = reduced;
+    }
+  } else {
+    if (r) lglpopftk (r);
+    while ((lit = lglpopstk (a)))
+      lgltlunassign (lgl, lit);
+  }
+}
+
+static int64_t lglsetprbtreelooklim (LGL * lgl, int * lkhdresptr) {
+  int sizepen, lastpen, pen, boost;
+  int64_t limit, irrlim;
+  if (lgl->opts->treelookrtc.val || lgl->opts->prbrtc.val) {
+    limit = lgl->limits->prb.steps = LLMAX;
+    lglprt (lgl, 1, "[treelook-%d] no limit (run to completion)",
+            lgl->stats->prb.treelook.count);
+  } else if (lkhdresptr && lgl->opts->treelookfull.val) {
+    limit = lgl->limits->prb.steps = LLMAX;
+    lglprt (lgl, 1, "[treelook-%d] unlimited look-ahead requested",
+            lgl->stats->prb.treelook.count);
+  } else {
+    limit = (lgl->opts->treelookreleff.val*lglvisearch (lgl))/2000;
+    if (limit < lgl->opts->treelookmineff.val)
+      limit = lgl->opts->treelookmineff.val;
+    if (lgl->opts->treelookmaxeff.val >= 0 &&
+        limit > lgl->opts->treelookmaxeff.val)
+      limit = lgl->opts->treelookmaxeff.val;
+    assert (lgl->tlk);
+    sizepen = lglszpen (lgl);
+    lastpen = lgl->tlk->lkhd ? 
+      lgl->limits->lkhdpen : lgl->limits->prb.treelook.pen;
+    pen = sizepen + lastpen;
+    limit >>= pen;
+    irrlim = lgl->stats->irr.clauses.cur/4;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->boost.val && lgl->tlk->lkhd)
+      boost = lgl->opts->treelookboost.val;
+    else boost = 1;
+    limit *= boost;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1, 
+       "[treelook-%d] limit %lld based on %d irredundant clauses",
+       lgl->stats->prb.treelook.count, 
+       (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1, 
+       "[treelook-%d] limit %lld penalty %d = %d + %d boost %d",
+       lgl->stats->prb.treelook.count, (LGLL) limit,
+       pen, lastpen, sizepen, boost);
+    if (lkhdresptr)
+      lglprt (lgl, 1, "[treelook-%d] limited look-ahead requested",
+             lgl->stats->prb.treelook.count);
+    lgl->limits->prb.steps = lgl->stats->prb.treelook.steps + limit;
+  }
+
+  return limit;
+}
+
+static void lglclntlvals (LGL * lgl) {
+  int idx;
+  for (idx = 2; idx < lgl->nvars; idx++) lgl->tlk->tvars[idx].val = 0;
+}
+
+#ifndef NDEBUG
+static int lglieliminated (LGL * lgl, int ilit) {
+  return lglelit2ext (lgl, lglexport (lgl, ilit))->eliminated;
+}
+#endif
+
+static int lgliblocking (LGL * lgl, int ilit) {
+  return lglelit2ext (lgl, lglexport (lgl, ilit))->blocking;
+}
+
+static void lgltlsetlkhd (LGL * lgl, int * lkhdresptr, int remlits) {
+  LKHD lkhdrescore, lkhdscore, lkhdpos, lkhdneg;
+  Flt jwhrescore, jwhscore, jwhpos, jwhneg;
+  int idx, lkhdres, phase, elit;
+  Ext * ext;
+  assert (lkhdresptr);
+  lkhdres = 0; lkhdrescore = FLTMIN; jwhrescore = FLTMIN;
+  assert (!lgl->nvars || lgl->tlk->lkhd);
+  lgljwh (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    assert (!lglieliminated (lgl, idx));
+    if (lkhdresptr && lgliblocking (lgl, idx)) continue;
+    if (!remlits) {
+      lkhdpos = lgl->tlk->lkhd[idx];
+      lkhdneg = lgl->tlk->lkhd[-idx];
+      lkhdscore = lglmulflt (lkhdneg, lkhdpos);
+      if (lkhdscore > FLTMIN)
+       lkhdscore = lgladdflt (lkhdscore, lgladdflt (lkhdneg, lkhdpos));
+    } else lkhdscore = lkhdpos = lkhdneg = FLTMIN;
+    jwhpos = lgl->jwh[lglulit (idx)];
+    jwhneg = lgl->jwh[lglulit (-idx)];
+    jwhscore = lglmulflt (jwhpos, jwhneg);
+    jwhscore = lgladdflt (jwhscore, lgladdflt (jwhpos, jwhneg));
+    LOG (1,
+      "final tree based look-ahead score [%s,%s] "
+      "(pos [%s,%s], neg [%s,%s]) of %d",
+       lglflt2str (lgl, lkhdscore), lglflt2str (lgl,jwhscore),
+       lglflt2str (lgl, lkhdpos), lglflt2str (lgl,jwhpos),
+       lglflt2str (lgl, lkhdneg), lglflt2str (lgl,jwhneg),
+       idx);
+
+    // phase with less weighted reductions
+         if (lkhdpos > lkhdneg) phase = -1;
+    else if (lkhdpos < lkhdneg) phase = 1;
+    // then with more weighted occs
+    else if (jwhpos > jwhneg) phase = 1;
+    else if (jwhpos < jwhneg) phase = -1;
+    // otherwise negative phase
+    else phase = -1;
+
+    if (lkhdres) {
+      if (lkhdscore < lkhdrescore) continue;
+      if (lkhdscore == lkhdrescore && jwhscore <= jwhrescore) continue;
+    }
+    lkhdrescore = lkhdscore;
+    jwhrescore = jwhscore;
+    lkhdres = phase * idx;
+  }
+  if (lkhdres) {
+    elit = lglexport (lgl, lkhdres);
+    ext = lglelit2ext (lgl, elit);
+    assert (!ext->eliminated);
+    assert (!ext->blocking);
+    lglprt (lgl, 1, "[treelook-%d] best look-ahead %d score [%s,%s]",
+      lgl->stats->prb.treelook.count, lkhdres,
+      lglflt2str (lgl, lkhdrescore), lglflt2str (lgl, jwhrescore));
+    if (ext->melted) {
+      ext->melted = 0;
+      LOG (2, "tree-look-ahead winner external %d not melted anymore", elit);
+    } else
+      LOG (2,
+       "tree-look-ahead winner external %d was not melted anyhow", elit);
+  } else LOG (1, "no proper best tree-look-ahead literal found");
+  if (lkhdresptr) *lkhdresptr = lkhdres;
+}
+
+static void lglgenericreport (LGL * lgl, const char * name, int count,
+                              int probed, int nprobes, double start) {
+  int div, mod;
+  assert (nprobes >= 0);
+  if (!nprobes || lgl->opts->verbose.val < 2) return;
+  if (lgl->opts->verbose.val == 2) div = 10;
+  else if (lgl->opts->verbose.val == 3) div = 100;
+  else div = 0;
+  mod = div ? (nprobes + div - 1) / div : 1;
+  assert (mod > 0);
+  if (probed % mod) return;
+  lglprt (lgl, 1,
+    "[%s-%d] probed %d/%d (%.0f%%) %.1f sec %d vars %.0f MB",
+    name, count, probed, nprobes, lglpcnt (probed, nprobes),
+    lglgetime (lgl) - start, lglrem (lgl), lglmb (lgl));
+}
+
+static void lgltreelookreport (LGL * lgl,
+                              int probed, int nprobes, double start) {
+  lglgenericreport (lgl,
+     "treelook", lgl->stats->prb.treelook.count, probed, nprobes, start);
+}
+
+static int lgltreelookaux (LGL * lgl, int * lkhdresptr) {
+  int oldhbrs, oldrem, remvarsall, remvarslkhd, remlits, notfullyscheduled;
+  int deltavars, newhbrs, success, idx, next, lit, nseen;
+  int64_t oldsteps, steps, limit;
+  Stk assignment;
+  double start;
+  Ftk reduced;
+  TVar * tv;
+  AVar * av;
+
+  if (lgl->mt) return 0;
+  if (lkhdresptr) *lkhdresptr = 0;
+  if (!lgl->nvars) return 1;
+
+  lglstart (lgl, &lgl->times->prb.treelook);
+  lgl->stats->prb.treelook.count++;
+
+  NEW (lgl->tlk, 1);
+  NEW (lgl->tlk->tvars, lgl->nvars);
+
+  assert (!lgl->simp && !lgl->probing && !lgl->treelooking);
+  lgl->simp = lgl->probing = lgl->treelooking = 1;
+
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  oldhbrs = lgl->stats->hbr.cnt;
+  oldrem = lglrem (lgl);
+
+  assert (!lgl->tlk->lkhd);
+  if (lkhdresptr) {
+    NEW (lgl->tlk->lkhd, 2*lgl->nvars);
+    lgl->tlk->lkhd += lgl->nvars;
+    assert (lgl->tlk->lkhd);
+  }
+
+  limit = lglsetprbtreelooklim (lgl, lkhdresptr);
+  oldsteps = lgl->stats->prb.treelook.steps;
+
+  lgltlsched (lgl);
+
+  steps = lgl->stats->prb.treelook.steps - oldsteps;
+  lglprt (lgl, 1, "[treelook-%d] scheduling used %lld steps",
+    lgl->stats->prb.treelook.count, (LGLL) steps);
+
+  if (limit != LLMAX) {
+    notfullyscheduled =
+      (lgl->stats->prb.treelook.steps >= lgl->limits->prb.steps);
+    lgl->limits->prb.steps = lgl->stats->prb.treelook.steps + limit;
+    if (notfullyscheduled)
+      lglprt (lgl, 1, "[treelook-%d] not fully scheduled",
+       lgl->stats->prb.treelook.count);
+    else
+      lglprt (lgl, 1, "[treelook-%d] scheduled completely",
+       lgl->stats->prb.treelook.count);
+  } else notfullyscheduled = 0;
+
+  CLR (assignment); CLR (reduced);
+  remlits = remvarsall = remvarslkhd = 0;
+
+  nseen = lglcntstk (&lgl->tlk->seen);
+  if (!lgl->mt && nseen) {
+
+    (void) lglsetprbtreelooklim (lgl, lkhdresptr);
+    oldsteps = lgl->stats->prb.treelook.steps;
+
+    lgldense (lgl, lgl->opts->treelooklrg.val);
+    next = 0;
+    start = lglgetime (lgl);
+    lgltreelookreport (lgl, next, nseen, start);
+    while (!lgl->mt &&
+          !lglterminate (lgl) &&
+          lglsyncunits (lgl) &&
+          next < nseen &&
+          lgl->stats->prb.treelook.steps < lgl->limits->prb.steps) {
+      lit = lglpeek (&lgl->tlk->seen, next++);
+      lgltreelooklit (lgl, &assignment, lkhdresptr ? &reduced : 0, lit);
+      lgltreelookreport (lgl, next, nseen, start);
+    }
+    lgltreelookreport (lgl, next, nseen, start);
+    lglclntlvals (lgl);
+    assert (lgl->stats->prb.treelook.steps >= oldsteps);
+    steps = lgl->stats->prb.treelook.steps - oldsteps;
+    lglprt (lgl, 1, "[treelook-%d] used %lld steps",
+      lgl->stats->prb.treelook.count, (LGLL) steps);
+    while (next < lglcntstk (&lgl->tlk->seen)) {
+      lit = lglpeek (&lgl->tlk->seen, next++);
+      if (!lit) continue;
+      if (!lglisfree (lgl, lit)) continue;
+      remlits++;
+      tv = lgltvar (lgl, lit);
+      tv->val = 1;
+    }
+    for (idx = 2; idx < lgl->nvars; idx++)
+      if (lglisfree (lgl, idx)) {
+       tv = lgltvar (lgl, idx);
+       av = lglavar (lgl, idx);
+       if (tv->val) {
+          tv->val = 0;
+          if (!av->donotreelook) remvarsall++;
+          remvarslkhd++;
+       } else if (!av->donotreelook) av->donotreelook = 1;
+      }
+    assert (remvarslkhd >= remvarsall);
+
+    if (remvarsall || notfullyscheduled) {
+      lglprt (lgl, 1, "[treelook-%d] %d literals remain %.0f%%%s",
+       lgl->stats->prb.treelook.count,
+       remlits, lglpcnt (remlits, 2*lglrem (lgl)),
+        lkhdresptr ? " in look-ahead" : "");
+      if (lkhdresptr)
+       lglprt (lgl, 1, "[treelook-%d] %d look-ahead variables remain %.0f%%",
+         lgl->stats->prb.treelook.count,
+         remvarslkhd, lglpcnt (remvarslkhd, lglrem (lgl)));
+      lglprt (lgl, 1,
+       "[treelook-%d] %d variables remain to probed next time %.0f%%",
+       lgl->stats->prb.treelook.count,
+       remvarsall, lglpcnt (remvarsall, lglrem (lgl)));
+    } else {
+      lglprt (lgl, 1, 
+        "[treelook-%d] fully completed tree based probing%s",
+       lgl->stats->prb.treelook.count, lkhdresptr ? " in look-ahead" : "");
+      for (idx = 2; idx < lgl->nvars; idx++)
+       lglavar (lgl, idx)->donotreelook = 0;
+    }
+    lglsparse (lgl);
+  }
+
+  DEL (lgl->tlk->tvars, lgl->nvars);
+  lglgc (lgl);
+  lglrelftk (lgl, &reduced);
+  lglrelstk (lgl, &assignment);
+  lglrelstk (lgl, &lgl->tlk->seen);
+  if (!lgl->mt && lkhdresptr) 
+    lgltlsetlkhd (lgl, lkhdresptr, remlits || notfullyscheduled);
+  if (lgl->tlk->lkhd) {
+    lgl->tlk->lkhd -= lgl->nvars;
+    DEL (lgl->tlk->lkhd, 2*lgl->nvars);
+  }
+  DEL (lgl->tlk, 1);
+  newhbrs = lgl->stats->hbr.cnt - oldhbrs;
+  if (newhbrs && !lgl->mt && !lkhdresptr) lgldecomp (lgl);
+
+  assert (lgl->simp && lgl->probing && lgl->treelooking);
+  lgl->simp = lgl->probing = lgl->treelooking = 0;
+
+  deltavars = oldrem - lglrem (lgl);
+  success = deltavars || newhbrs;
+  if (!lkhdresptr) LGLUPDPEN (prb.treelook, deltavars);
+  else if (remlits && lgl->limits->lkhdpen < lgl->opts->penmax.val)
+    lgl->limits->lkhdpen++;
+  else if (!remlits && lgl->limits->lkhdpen)
+    lgl->limits->lkhdpen--;
+  lglprt (lgl, 1 + !success,
+         "[treelook-%d] removed %d variables, found %d hbrs",
+         lgl->stats->prb.treelook.count, deltavars, newhbrs);
+  lglrep (lgl, 2, 'p');
+  lglstop (lgl);
+  lglbasicatestats (lgl);
+  return !lgl->mt;
+}
+
+static int lgltreelook (LGL * lgl) {
+  if (lgldelaying (lgl, "treelook",
+        &lgl->limits->prb.treelook.del.rem)) return 1;
+  return lgltreelookaux (lgl, 0);
+}
+
+static int lgljwhlook (LGL * lgl) {
+  Flt best, pos, neg, score;
+  int res, idx, elit;
+  Ext * ext;
+  lgljwh (lgl);
+  best = FLTMIN;
+  res = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    assert (!lglieliminated (lgl, idx));
+    if (lgliblocking (lgl, idx)) continue;
+    pos = lgl->jwh[lglulit (idx)];
+    neg = lgl->jwh[lglulit (-idx)];
+    score = lglmulflt (pos, neg);
+    score = lgladdflt (score, lgladdflt (pos, neg));
+    if (res && score <= best) continue;
+    LOG (1, "jwh look-ahead score %s (pos %s, neg %s) of %d",
+      lglflt2str (lgl, score), lglflt2str (lgl, pos), lglflt2str (lgl, neg),
+      idx);
+    res = (pos > neg) ? idx : -idx;
+    best = score;
+  }
+  if (res) {
+    elit = lglexport (lgl, res);
+    ext = lglelit2ext (lgl, elit);
+    lglprt (lgl, 1, "[jwhlook] best look-ahead %d score %s",
+            res, lglflt2str (lgl, best));
+    if (ext->melted) {
+      ext->melted = 0;
+      LOG (2, "jwh-look-ahead winner external %d not melted anymore", elit);
+    } else
+      LOG (2, "jwh-look-ahead winner external %d was not melted anyhow", elit);
+  } else LOG (1, "no proper best jwh-look-ahead literal found");
+  return res;
+}
+
+static int lglismislook (LGL * lgl, int max) {
+  int64_t best, pos, neg, score;
+  int res, idx, elit, * scores;
+  Ext * ext;
+  scores = lglis (lgl);
+  best = res = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    assert (!lglieliminated (lgl, idx));
+    if (lgliblocking (lgl, idx)) continue;
+    pos = scores[idx], neg = scores[-idx];
+    score = pos * neg + pos + neg;
+    assert (0 <= score && pos <= score && neg <= score);
+    if (res) {
+      if (max && score <= best) continue;
+      if (!max && score >= best) continue;
+    }
+    LOG (1, "%s look-ahead score %lld (pos %lld, neg %lld) of %d",
+      (max ? "LIS" : "MIS"), (LGLL) score, (LGLL) pos, (LGLL) neg, idx);
+    res = (pos > neg) ? idx : -idx;
+    best = score;
+  }
+  scores -= lgl->nvars;
+  DEL (scores, 2*lgl->nvars);
+  if (res) {
+    elit = lglexport (lgl, res);
+    ext = lglelit2ext (lgl, elit);
+    assert (!ext->eliminated && !ext->blocking);
+    lglprt (lgl, 1, "[lislook] best %s look-ahead %d score %lld", 
+      (max ? "LIS" : "MIS"), res, (LGLL) best);
+    if (ext->melted) {
+      ext->melted = 0;
+      LOG (2, "look-ahead winner external %d not melted anymore", elit);
+    } else
+      LOG (2, "look-ahead winner external %d was not melted anyhow", elit);
+  } else LOG (1, "no proper best %s-look-ahead literal found",
+           (max ? "LIS" : "MIS"));
+  return res;
+}
+
+static int lglislook (LGL * lgl) { return lglismislook (lgl, 1); }
+static int lglmislook (LGL * lgl) { return lglismislook (lgl, 0); }
+
+static int64_t lglsatmul64 (int64_t a, int64_t b) {
+  assert (a >= 0), assert (b >= 0);
+  return (b && (LLMAX / b < a)) ? LLMAX : a * b;
+}
+
+static int64_t lglsatadd64 (int64_t a, int64_t b) {
+  assert (a >= 0), assert (b >= 0);
+  return (LLMAX - b < a) ? LLMAX : a + b;
+}
+
+static int64_t * lglsumlenscores (LGL * lgl) {
+  int idx, sign, lit, tag, blit, other, other2, red;
+  const int *p, * w, * eow, * c;
+  int64_t * res, len;
+  Val val, tmp, tmp2;
+  HTS * hts;
+  Stk * s;
+  NEW (res, 2*lgl->nvars);
+  res += lgl->nvars;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      val = lglval (lgl, lit);
+      if (val > 0) continue;
+      hts = lglhts (lgl, lit);
+      if (!hts->offset) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < abs (lit)) continue;
+       tmp = lglval (lgl, other);
+       if (tmp > 0) continue;
+       if (tag == BINCS) {
+         assert (!tmp);
+         res[lit] += 2;
+         res[other] += 2;
+       } else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (abs (other2) < abs (lit)) continue;
+         tmp2 = lglval (lgl, other2);
+         if (tmp2 > 0) continue;
+         assert ((val > 0) + (tmp > 0) + (tmp2 > 0) == 0);
+         assert ((val < 0) + (tmp < 0) + (tmp2 < 0) <= 1);
+         len = !val + !tmp + !tmp2;
+         if (!val) res[lit] += len;
+         if (!tmp) res[other] += len;
+         if (!tmp2) res[other2] += len;
+       }
+      }
+    }
+  s = &lgl->irr;
+  for (c = s->start; c < s->top; c = p + 1) {
+    p = c;
+    if (*p >= NOTALIT) continue;
+    val = -1;
+    len = 0;
+    while ((other = *p)) {
+      tmp = lglval (lgl, other);
+      if (tmp > val) val = tmp;
+      if (!tmp) len++;
+      p++;
+    }
+    if (val > 0) continue;
+    for (p = c; (other = *p); p++)
+      if (!lglval (lgl, other))
+       res[other] += len;
+  }
+  return res;
+}
+
+static int lglsumlenlook (LGL * lgl) {
+  int64_t best, pos, neg, score, * scores;
+  int res, idx, elit;
+  Ext * ext;
+  scores = lglsumlenscores (lgl);
+  best = res = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    assert (!lglieliminated (lgl, idx));
+    if (lgliblocking (lgl, idx)) continue;
+    pos = scores[idx], neg = scores[-idx];
+    score = lglsatadd64 (lglsatmul64 (pos, neg), lglsatadd64 (pos, neg));
+    assert (0 <= score), assert (pos <= score), assert (neg <= score);
+    if (res && score <= best) continue;
+    LOG (1,
+      "look-ahead score %lld (pos %lld, neg %lld) of %d",
+      (LGLL) score, (LGLL) pos, (LGLL) neg, idx);
+    res = (pos > neg) ? idx : -idx;
+    best = score;
+  }
+  scores -= lgl->nvars;
+  DEL (scores, 2*lgl->nvars);
+  if (res) {
+    elit = lglexport (lgl, res);
+    ext = lglelit2ext (lgl, elit);
+    assert (!ext->eliminated && !ext->blocking);
+    lglprt (lgl, 1,
+      "[sumlook] best look-ahead %d score %lld", 
+      res, (LGLL) best);
+    if (ext->melted) {
+      ext->melted = 0;
+      LOG (2, "look-ahead winner external %d not melted anymore", elit);
+    } else
+      LOG (2, "look-ahead winner external %d was not melted anyhow", elit);
+  } else LOG (1, "no proper best look-ahead literal found");
+  return res;
+}
+
+static int lglschedbasicprobe (LGL * lgl, Stk * probes, int round) {
+  int idx, res, i, j, donotbasicprobes, keepscheduled;
+  assert (lglmtstk (probes));
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lgl->opts->prbasic.val <= 1 &&
+        (lglhasbins (lgl, idx) == lglhasbins (lgl, -idx))) continue;
+    LOG (1, "new probe %d", idx);
+    lglpushstk (lgl, probes, idx);
+  }
+  res = lglcntstk (probes);
+  donotbasicprobes = keepscheduled = 0;
+  for (i = 0; i < res; i++) {
+    idx = lglpeek (probes, i);
+    if (!idx) continue;
+    assert (lglisfree (lgl, idx));
+    if (lglavar (lgl, idx)->donotbasicprobe) donotbasicprobes++;
+    else keepscheduled++;
+  }
+  if (!keepscheduled) {
+    for (i = 0; i < res; i++) {
+      idx = lglpeek (probes, i);
+      if (!idx) continue;
+      assert (lglisfree (lgl, idx));
+      lglavar (lgl, idx)->donotbasicprobe = 0;
+      keepscheduled++;
+    }
+    donotbasicprobes = 0;
+  }
+  for (i = 0; i < res; i++) {
+    idx = lglpeek (probes, i);
+    if (!idx) continue;
+    assert (lglisfree (lgl, idx));
+    if (lglavar (lgl, idx)->donotbasicprobe) donotbasicprobes++;
+    else keepscheduled++;
+  }
+  j = 0;
+  for (i = 0; i < res; i++) {
+    idx = lglpeek (probes, i);
+    if (!idx) continue;
+    if (!lglavar (lgl, idx)->donotbasicprobe)
+      lglpoke (probes, j++, idx);
+  }
+  lglrststk (probes, (res = j));
+  if (!res)
+    lglprt (lgl, 2, "[basicprobe-%d-%d] no potential probes found",
+           lgl->stats->prb.basic.count, round);
+  else if (!donotbasicprobes)
+    lglprt (lgl, 2, "[basicprobe-%d-%d] scheduled all %d potential probes",
+           lgl->stats->prb.basic.count, round, res);
+  else
+    lglprt (lgl, 2, "[basicprobe-%d-%d] scheduled %d probes %.0f%%",
+           lgl->stats->prb.basic.count, round,
+           res, lglpcnt (res, lglrem (lgl)));
+  return res;
+}
+
+static void lglsetprbasiclim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->prbasicrtc.val || lgl->opts->prbrtc.val) {
+    lgl->limits->prb.steps = LLMAX;
+    lglprt (lgl, 1, "[basicprobe-%d] no limit (run to completion)", 
+            lgl->stats->prb.basic.count);
+  } else {
+    limit = (lgl->opts->prbasicreleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->prbasicmineff.val)
+      limit = lgl->opts->prbasicmineff.val;
+    if (lgl->opts->prbasicmaxeff.val >= 0 &&
+       limit > lgl->opts->prbasicmaxeff.val)
+      limit = lgl->opts->prbasicmaxeff.val;
+    limit >>= (pen = lgl->limits->prb.basic.pen + lglszpen (lgl));
+    irrlim = 2*lgl->stats->irr.clauses.cur;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1,
+       "[basicprobe-%d] limit %lld based on %d irredundant clauses",
+       lgl->stats->prb.basic.count,
+       (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1, "[basicprobe-%d] limit %lld penalty %d = %d + %d",
+       lgl->stats->prb.basic.count, (LGLL) limit,
+       pen, lgl->limits->prb.basic.pen, lglszpen (lgl));
+    lgl->limits->prb.steps = lgl->stats->prb.basic.steps + limit;
+  }
+}
+
+static void lglbasicprobereport (LGL * lgl,
+                                 int probed, int nprobes, double start) {
+  lglgenericreport (lgl,
+    "basicprobe", lgl->stats->prb.basic.count, probed, nprobes, start);
+}
+
+static int lglbasicprobe (LGL * lgl) {
+#ifndef NLGLOG
+  int origprobed = lgl->stats->prb.basic.probed;
+#endif
+  int origfailed = lgl->stats->prb.basic.failed;
+  int origlifted = lgl->stats->prb.basic.lifted;
+  int orighbr = lgl->stats->hbr.cnt;
+  int root, failed, lifted, units, first, idx;
+  int oldrem, deltarem, deltahbr, remprobes;
+  int nprobes, success, round, probed;
+  int oldhbr, oldfailed, oldlifted;
+  Stk probes, lift, saved;
+  unsigned pos, delta;
+  double start;
+  if (!lgl->nvars) return 1;
+  if (!lgl->opts->probe.val) return 1;
+  if (lgldelaying (lgl, "basicprobe",
+        &lgl->limits->prb.basic.del.rem)) return 1;
+  lglstart (lgl, &lgl->times->prb.basic);
+  lgl->stats->prb.basic.count++;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  assert (!lgl->simp && !lgl->probing && !lgl->basicprobing);
+  lgl->simp = lgl->probing = lgl->basicprobing = 1;
+  CLR (lift); CLR (probes); CLR (saved);
+  lglsetprbasiclim (lgl);
+  oldfailed = origfailed;
+  oldlifted = origlifted;
+  oldhbr = lgl->stats->hbr.cnt;
+  oldrem = lglrem (lgl);
+  round = 0;
+RESTART:
+  nprobes = lglschedbasicprobe (lgl, &probes, round);
+  remprobes = 0;
+  if (!nprobes) goto DONE;
+  pos = lglrand (lgl) % nprobes;
+  delta = lglrand (lgl) % nprobes;
+  if (!delta) delta++;
+  probed = 0;
+  start = lglgetime (lgl);
+  lglbasicprobereport (lgl, probed, nprobes, start);
+  while (lglgcd (delta, nprobes) > 1)
+    if (++delta == nprobes) delta = 1;
+  LOG (1, "probing start %u delta %u mod %u", pos, delta, nprobes);
+  first = 0;
+  while (!lgl->mt) {
+    if (lgl->stats->prb.basic.steps >= lgl->limits->prb.steps) break;
+    if (lglterminate (lgl)) break;
+    if (!lglsyncunits (lgl)) break;
+    assert (pos < (unsigned) nprobes);
+    root = probes.start[pos];
+    probes.start[pos] = 0;
+    if (!root || root == first) {
+      lglprt (lgl, 1,
+        "[basicprobe-%d-%d] %d sched %.0f%%, %d failed, %d lifted, %d hbrs",
+       lgl->stats->prb.basic.count, round,
+       nprobes, lglpcnt (nprobes, lglrem (lgl)),
+        lgl->stats->prb.basic.failed - oldfailed,
+        lgl->stats->prb.basic.lifted - oldlifted,
+        lgl->stats->hbr.cnt - oldhbr);
+      for (idx = 2; idx < lgl->nvars; idx++)
+       lglavar (lgl, idx)->donotbasicprobe = 0;
+      break;
+    }
+    lglavar (lgl, root)->donotbasicprobe = 1;
+    if (!first) first = root;
+    pos += delta;
+    if (pos >= nprobes) pos -= nprobes;
+    if (!lglisfree (lgl, root)) continue;
+    lglbasicprobereport (lgl, ++probed, nprobes, start);
+    lglbasicprobelit (lgl, root);
+  }
+  lglbasicprobereport (lgl, probed, nprobes, start);
+  if (!lgl->mt) {
+    if (lgl->stats->prb.basic.steps >= lgl->limits->prb.steps) {
+      while (!lglmtstk (&probes))
+       if((idx = lglpopstk (&probes)) && lglisfree (lgl, idx)) remprobes++;
+      lglprt (lgl, 1, 
+        "[basicprobe-%d-%d] %d probes remain %.0f%% after last round",
+       lgl->stats->prb.basic.count, round,
+       remprobes, lglpcnt (remprobes, lglrem (lgl)));
+    } else if (round >= lgl->opts->prbasicroundlim.val) {
+      lglprt (lgl, 1,
+             "[basicprobe-%d-%d] round limit %d hit",
+             lgl->stats->prb.basic.count, round, 
+             lgl->opts->prbasicroundlim.val);
+    } else if (lgl->stats->prb.basic.failed > oldfailed ||
+               lgl->stats->prb.basic.lifted > oldlifted ||
+              lgl->stats->hbr.cnt > oldhbr) {
+      oldfailed = lgl->stats->prb.basic.failed;
+      oldlifted = lgl->stats->prb.basic.lifted;
+      lglclnstk (&probes);
+      if (oldhbr < lgl->stats->hbr.cnt && lgl->opts->decompose.val)
+       if (!lgldecomp (lgl)) goto DONE;
+      oldhbr = lgl->stats->hbr.cnt;
+      round++;
+      goto RESTART;
+    } else {
+      assert (!remprobes);
+      lglprt (lgl, 1,
+             "[basicprobe-%d-%d] fully completed probing",
+             lgl->stats->prb.basic.count, round);
+      for (idx = 2; idx < lgl->nvars; idx++)
+       lglavar (lgl, idx)->donotbasicprobe = 0;
+    }
+  }
+DONE:
+  lglrelstk (lgl, &lift);
+  lglrelstk (lgl, &probes);
+  lglrelstk (lgl, &saved);
+
+  assert (lgl->stats->hbr.cnt >= orighbr);
+  assert (lglrem (lgl) <= oldrem);
+  deltarem = oldrem - lglrem (lgl);
+  deltahbr = lgl->stats->hbr.cnt - orighbr;
+  success = deltarem || deltahbr;
+  LGLUPDPEN (prb.basic, deltarem);
+  assert (lgl->stats->prb.basic.failed >= origfailed);
+  assert (lgl->stats->prb.basic.lifted >= origlifted);
+  failed = lgl->stats->prb.basic.failed - origfailed;
+  lifted = lgl->stats->prb.basic.lifted - origlifted;
+#ifndef NLGLOG
+  assert (lgl->stats->prb.basic.probed >= origprobed);
+  probed = lgl->stats->prb.basic.probed - origprobed;
+  LOG (1, "%ssuccessfully probed %d out of %d probes %.1f%%",
+       success ? "" : "un", probed, nprobes, lglpcnt (probed, nprobes));
+  LOG (1, "found %d failed %.1f%% lifted %d through probing",
+       failed, lglpcnt (failed, probed), lifted);
+#endif
+  assert (lgl->probing && lgl->simp && lgl->basicprobing);
+  lgl->simp = lgl->probing = lgl->basicprobing = 0;
+  units = failed + lifted;
+  lglprt (lgl, 1 + !units,
+    "[basicprobe-%d-%d] %d units = %d failed (%.0f%%) + %d lifted (%.0f%%)",
+    lgl->stats->prb.basic.count, round,
+    units, failed, lglpcnt (failed, units), lifted, lglpcnt (lifted, units));
+  lglprt (lgl, 1 + !success,
+    "[basicprobe-%d-%d] removed %d variables, found %d hbrs",
+    lgl->stats->prb.basic.count, round, deltarem, deltahbr);
+  lglrep (lgl, 2, 'p');
+  lglstop (lgl);
+  lglbasicatestats (lgl);
+  return !lgl->mt;
+}
+
+static int lglsmallirr (LGL * lgl) {
+  int maxirrlidx = lglcntstk (&lgl->irr), limit;
+  int64_t tmp = MAXREDLIDX;
+  tmp *= lgl->opts->smallirr.val;
+  tmp /= 100;
+  limit = (tmp < INT_MAX) ? tmp : INT_MAX;
+  if (maxirrlidx >= limit) return 0;
+  return  1;
+}
+
+static int lglprobe (LGL * lgl) {
+  int res = 1, mod = 0, all, small = lglsmallirr (lgl);
+  int (*prb[3])(LGL *);
+  lglstart (lgl, &lgl->times->prb.all);
+  if (small && lgl->opts->prbsimple.val) prb[mod++] = lglsimpleprobe;
+  if (small && lgl->opts->treelook.val) prb[mod++] = lgltreelook;
+  if (lgl->opts->prbasic.val) prb[mod++] = lglbasicprobe;
+  all = lgl->stats->prb.simple.count;
+  all += lgl->stats->prb.basic.count;
+  all += lgl->stats->prb.treelook.count;
+  if (lgl->stats->simp.count == 2) {
+    int i;
+    res = 1;
+    for (i = 0; res && i < mod; i++) res = prb[i] (lgl);
+  } else res = mod ? prb[all % mod] (lgl) : 1;
+  lglstop (lgl);
+  return res;
+}
+
+static void lglinitevars (LGL * lgl) {
+  EVar * ev;
+  int idx;
+  assert (lgl->occs);
+  NEW (lgl->evars, lgl->nvars);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    ev = lgl->evars + idx;
+    ev->pos = -1;
+  }
+}
+
+static void lgldense (LGL * lgl, int occstoo) {
+  int lit, lidx, count, idx, other, other2, blit, sign, tag, red;
+  const int * start, * top, * c, * p, * eow;
+  int * q, * w;
+  EVar * ev;
+  HTS * hts;
+  LOG (1, "transition to dense mode");
+  assert (!lgl->dense);
+  assert (!lgl->evars);
+  assert (lglsmallirr (lgl));
+  assert (lglmtstk (&lgl->esched));
+  assert (!lgl->eliminating || !lgl->elm->pivot);
+  lgl->stats->dense++;
+  count = 0;
+  if (lgl->occs) lglinitevars (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->count) continue;
+      q = w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       red = blit & REDCS;
+       if (red && tag == LRGCS) continue;
+       *q++ = blit;
+       if (tag == LRGCS || tag == TRNCS) *q++ = *p;
+       if (red) continue;
+       if (tag == BINCS || tag == TRNCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         if (tag == TRNCS) {
+           other2 = *p;
+           if (abs (other2) < idx) continue;
+           lglincocc (lgl, other2), count++;
+         }
+         lglincocc (lgl, lit), count++;
+         lglincocc (lgl, other), count++;
+       } else {
+         assert (tag == LRGCS);
+       }
+      }
+      lglshrinkhts (lgl, hts, q - w);
+    }
+  if (count)
+    LOG (1, "counted %d occurrences in small irredundant clauses", count);
+  if (occstoo) {
+    count = 0;
+    start = lgl->irr.start;
+    top = lgl->irr.top;
+    for (c = start; c < top; c = p + 1) {
+      p = c;
+      if (*c >= NOTALIT) continue;
+      lidx = c - start;
+      assert (lidx < MAXIRRLIDX);
+      blit = (lidx << RMSHFT) | OCCS;
+      for (; (lit = *p); p++) {
+       hts = lglhts (lgl, lit);
+       lglpushwch (lgl, hts, blit);
+       lglincocc (lgl, lit), count++;
+      }
+    }
+  }
+  if (count)
+    LOG (1, "counted %d occurrences in large irredundant clauses", count);
+  count = 0;
+  if (lgl->occs) {
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      ev = lglevar (lgl, idx);
+      if (ev->pos >= 0) continue;
+      if (lglifrozen (lgl, idx)) continue;
+      if (lgl->donotsched) {
+       AVar * av = lglavar (lgl, idx);
+       if (lgl->eliminating && av->donotelm) continue;
+       if (lgl->blocking && av->donotblk) continue;
+      }
+      assert (!ev->occ[0] && !ev->occ[1]);
+      lglesched (lgl, idx);
+      count++;
+    }
+    if (count) LOG (1, "scheduled %d zombies", count);
+  }
+  LOG (1, "continuing in dense mode");
+  lgl->dense = 1 + occstoo;
+  lglfullyconnected (lgl);
+  if (lgl->occs && lgl->opts->verbose.val >= 1) {
+    const char * str;
+    int inst, vl;
+    count = 0;
+    if (lgl->eliminating) str = "elim", inst = lgl->stats->elm.count, vl = 1;
+    else if (lgl->blocking) str = "block", inst = lgl->stats->blk.count, vl=1;
+    else str = "dense", inst = lgl->stats->dense, vl = 2;
+    for (idx = 2; idx < lgl->nvars; idx++)
+      if (lglevar (lgl, idx)->pos >= 0) count++;
+    lglprt (lgl, vl,
+      "[%s-%d] scheduled %d variables %.0f%%",
+      str, inst, count, lglpcnt (count, lgl->nvars-2));
+  }
+}
+
+static void lglsparse (LGL * lgl) {
+  int idx, sign, lit, count, blit, tag;
+  int * w, *p, * eow, * q;
+  HTS * hts;
+  assert (!lgl->notfullyconnected);
+  assert (lgl->dense);
+  lgl->stats->sparse++;
+  count = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      if (!hts->count) continue;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = q = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == OCCS) { count++; continue; }
+       *q++ = blit;
+       if (tag == BINCS) continue;
+       assert (tag == LRGCS || tag == TRNCS);
+       assert (p + 1 < eow);
+       *q++ = *++p;
+      }
+      assert (hts->count - (p - q) == q - w);
+      lglshrinkhts (lgl, hts, q - w);
+    }
+  if (lgl->occs) {
+    DEL (lgl->evars, lgl->nvars);
+    lglrelstk (lgl, &lgl->esched);
+  }
+  LOG (1, "removed %d full irredundant occurrences", count);
+  lgl->dense = 0;
+  lgl->notfullyconnected = 1;
+  LOG (1, "large clauses not fully connected yet");
+}
+
+static int lglm2i (LGL * lgl, int mlit) {
+  int res, midx = abs (mlit);
+  assert (0 < midx);
+  res = lglpeek (&lgl->elm->m2i, midx);
+  if (mlit < 0) res = -res;
+  return res;
+}
+
+static int lgli2m (LGL * lgl, int ilit) {
+  AVar * av = lglavar (lgl, ilit);
+  int res = av->mark;
+  if (!res) {
+    res = lglcntstk (&lgl->seen) + 1;
+    av->mark = res;
+    assert (2*lglcntstk (&lgl->seen) == lglcntstk (&lgl->elm->noccs) - 2);
+    assert (2*lglcntstk (&lgl->seen) == lglcntstk (&lgl->elm->mark) - 2);
+    assert (2*lglcntstk (&lgl->seen) == lglcntstk (&lgl->elm->occs) - 2);
+    assert (lglcntstk (&lgl->seen) == lglcntstk (&lgl->elm->m2i) - 1);
+    lglpushstk (lgl, &lgl->seen, abs (ilit));
+    lglpushstk (lgl, &lgl->elm->noccs, 0);
+    lglpushstk (lgl, &lgl->elm->noccs, 0);
+    lglpushstk (lgl, &lgl->elm->mark, 0);
+    lglpushstk (lgl, &lgl->elm->mark, 0);
+    lglpushstk (lgl, &lgl->elm->occs, 0);
+    lglpushstk (lgl, &lgl->elm->occs, 0);
+    lglpushstk (lgl, &lgl->elm->m2i, abs (ilit));
+    LOG (4, "mapped internal variable %d to marked variable %d",
+        abs (ilit), res);
+  }
+  if (ilit < 0) res = -res;
+  return res;
+}
+
+static unsigned lglsig (int lit) {
+  unsigned ulit = lglulit (lit), res;
+  assert (ulit >= 2);
+  ulit -= 2;
+  res = (1u << (ulit & 31));
+  return res;
+}
+
+static void lgladdecl (LGL * lgl, const int * c) {
+  int ilit, mlit, umlit, size = 0, next, prev;
+  unsigned csig = 0;
+  const int * p;
+  Val val;
+#if !defined (NDEBUG) || !defined (NLGLOG)
+  int lidx;
+#endif
+  LOGCLS (3, c, "copying irredundant clause");
+  INCSTEPS (elm.copies);
+  size = 0;
+  for (p = c; (ilit = *p); p++) {
+    val = lglval (lgl, ilit);
+    assert (val <= 0);
+    if (val < 0) continue;
+    size++;
+    if (abs (ilit) == lgl->elm->pivot) continue;
+    mlit = lgli2m (lgl, ilit);
+    assert (abs (mlit) != 1);
+    csig |= lglsig (mlit);
+  }
+  assert (size >= 1);
+  next = lglcntstk (&lgl->elm->lits);
+#if !defined (NDEBUG) || !defined (NLGLOG)
+  lidx = next;
+#endif
+  assert (next > 0);
+  for (p = c; (ilit = *p); p++) {
+    val = lglval (lgl, ilit);
+    if (val < 0) continue;
+    mlit = lgli2m (lgl, ilit);
+    lglpushstk (lgl, &lgl->elm->lits, mlit);
+    umlit = lglulit (mlit);
+    prev = lglpeek (&lgl->elm->occs, umlit);
+    lglpushstk (lgl, &lgl->elm->next, prev);
+    lglpoke (&lgl->elm->occs, umlit, next++);
+    lglpushstk (lgl, &lgl->elm->csigs, csig);
+    lglpushstk (lgl, &lgl->elm->sizes, size);
+    lgl->elm->noccs.start[umlit]++;
+  }
+  lglpushstk (lgl, &lgl->elm->lits, 0);
+  lglpushstk (lgl, &lgl->elm->next, 0);
+  lglpushstk (lgl, &lgl->elm->csigs, 0);
+  lglpushstk (lgl, &lgl->elm->sizes, 0);
+  lgl->elm->necls++;
+  LOGCLS (4, lgl->elm->lits.start + lidx, "copied and mapped clause");
+#ifndef NDEBUG
+  LOGMCLS (4, lgl->elm->lits.start + lidx, "copied and remapped clause");
+  {
+    int i, j = 0;
+    for (i = 0; c[i]; i++) {
+      Val val = lglval (lgl, c[i]);
+      assert (val <= 0);
+      if (val < 0) continue;
+      assert (c[i] == lglm2i (lgl, lglpeek (&lgl->elm->lits, lidx + j++)));
+    }
+  }
+#endif
+}
+
+static int lglecls (LGL * lgl, int lit) {
+  int blit, tag, red, other, lidx, count;
+  const int * p, * w, * eow, * c;
+  int d[4];
+  HTS * hts;
+  LOG (3, "copying irredundant clauses with %d", lit);
+  count = 0;
+  hts = lglhts (lgl, lit);
+  if (!hts->count) return 0;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    if (tag == BINCS || tag == TRNCS) {
+      d[0] = lit;
+      other = blit >> RMSHFT;
+      d[1] = other;
+      if (tag == TRNCS) d[2] = *p, d[3] = 0;
+      else d[2] = 0;
+      c = d;
+    } else {
+      assert (tag == OCCS);
+      lidx = (tag == OCCS) ? (blit >> RMSHFT) : *p;
+      c = lglidx2lits (lgl, 0, lidx);
+    }
+    lgladdecl (lgl, c);
+    count++;
+  }
+  return count;
+}
+
+static void lglrstecls (LGL * lgl)  {
+  assert (lgl->elm->pivot);
+  lglclnstk (&lgl->elm->lits);
+  lglclnstk (&lgl->elm->next);
+  lglclnstk (&lgl->elm->csigs);
+  lglclnstk (&lgl->elm->sizes);
+  lglclnstk (&lgl->elm->occs);
+  lglclnstk (&lgl->elm->noccs);
+  lglclnstk (&lgl->elm->mark);
+  lglclnstk (&lgl->elm->m2i);
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  lgl->elm->pivot = 0;
+}
+
+static void lglrelecls (LGL * lgl)  {
+  lglrelstk (lgl, &lgl->elm->lits);
+  lglrelstk (lgl, &lgl->elm->next);
+  lglrelstk (lgl, &lgl->elm->csigs);
+  lglrelstk (lgl, &lgl->elm->sizes);
+  lglrelstk (lgl, &lgl->elm->occs);
+  lglrelstk (lgl, &lgl->elm->noccs);
+  lglrelstk (lgl, &lgl->elm->mark);
+  lglrelstk (lgl, &lgl->elm->m2i);
+  lglrelstk (lgl, &lgl->elm->clv);
+}
+
+static void lglinitecls (LGL * lgl, int idx) {
+#ifndef NLGLOG
+  int clauses;
+#endif
+  assert (!lgl->elm->pivot);
+  assert (idx >= 2);
+  assert (lglmtstk (&lgl->elm->lits));
+  assert (lglmtstk (&lgl->elm->next));
+  assert (lglmtstk (&lgl->elm->csigs));
+  assert (lglmtstk (&lgl->elm->sizes));
+  assert (lglmtstk (&lgl->elm->occs));
+  assert (lglmtstk (&lgl->elm->noccs));
+  assert (lglmtstk (&lgl->elm->m2i));
+  assert (lglmtstk (&lgl->seen));
+  lgl->elm->pivot = idx;
+  lglpushstk (lgl, &lgl->elm->mark, 0);
+  lglpushstk (lgl, &lgl->elm->mark, 0);
+  lglpushstk (lgl, &lgl->elm->occs, 0);
+  lglpushstk (lgl, &lgl->elm->occs, 0);
+  lglpushstk (lgl, &lgl->elm->noccs, 0);
+  lglpushstk (lgl, &lgl->elm->noccs, 0);
+  lglpushstk (lgl, &lgl->elm->m2i, 0);
+  (void) lgli2m (lgl, idx);
+  lglpushstk (lgl, &lgl->elm->lits, 0);
+  lglpushstk (lgl, &lgl->elm->next, 0);
+  lglpushstk (lgl, &lgl->elm->csigs, 0);
+  lglpushstk (lgl, &lgl->elm->sizes, 0);
+  lgl->elm->necls = 0;
+#ifndef NLGLOG
+  clauses =
+#endif
+  lglecls (lgl, idx);
+  lgl->elm->negcls = lgl->elm->necls;
+  lgl->elm->neglidx = lglcntstk (&lgl->elm->lits);
+#ifndef NLGLOG
+  clauses +=
+#endif
+  lglecls (lgl, -idx);
+  LOG (2, "found %d variables in %d clauses with %d or %d",
+       lglcntstk (&lgl->seen), clauses, idx, -idx);
+  assert (lgl->elm->pivot);
+}
+
+static void lglelrmcls (LGL * lgl, int lit, int * c, int clidx) {
+  int lidx, i, other, ulit, * lits, * csigs, blit, tag, red, other2;
+  int * p, * eow, * w, count;
+  HTS * hts;
+#ifndef NDEBUG
+  int size;
+#endif
+  lits = lgl->elm->lits.start;
+  csigs = lgl->elm->csigs.start;
+  assert (lits < c && c < lgl->elm->lits.top - 1);
+  lidx = c - lits;
+  LOGCLS (2, c, "removing clause");
+  for (i = lidx; (other = lits[i]); i++) {
+    assert (other < NOTALIT);
+    lits[i] = REMOVED;
+    csigs[i] = 0;
+    ulit = lglulit (other);
+    assert (ulit < lglcntstk (&lgl->elm->noccs));
+    assert (lgl->elm->noccs.start[ulit] > 0);
+    lgl->elm->noccs.start[ulit] -= 1;
+  }
+#ifndef NDEBUG
+  size = lglpeek (&lgl->elm->sizes, lidx);
+#endif
+  hts = lglhts (lgl, lit);
+  assert (hts->count > 0 && hts->count >= clidx);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  blit = tag = count = 0;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    if (count == clidx) break;
+    count++;
+  }
+  assert (count == clidx);
+  assert (blit && tag);
+  assert (p < eow);
+  if (tag == BINCS) {
+    assert (size >= 2);
+    other = blit >> RMSHFT;
+    lglrmbcls (lgl, lit, other, 0);
+  } else if (tag == TRNCS) {
+    other = blit >> RMSHFT;
+    other2 = *p;
+    lglrmtcls (lgl, lit, other, other2, 0);
+  } else {
+    assert (tag == OCCS);
+    lidx = (tag == OCCS) ? (blit >> RMSHFT) : *p;
+#ifndef NDEBUG
+    {
+      int * q, * d = lglidx2lits (lgl, 0, lidx);
+      for (q = d; *q; q++)
+       ;
+      assert (q - d >= size);
+    }
+#endif
+    lglrmlcls (lgl, lidx, 0);
+  }
+}
+
+#define BWL 2
+
+static int lglbacksub (LGL * lgl, int * c, int str) {
+  int * start = lgl->elm->lits.start, * p, * q, marked = 0, res, * d;
+  int lit, ulit, occ, next, osize, other, uolit, size, plit, phase, clidx;
+  unsigned ocsig, csig = 0, masksig;
+#ifndef NLGLOG
+  const char * mode = str ? "strengthening" : "subsumption";
+#endif
+  LOGMCLS (BWL + 1, c, "backward %s check for clause", mode);
+  LOGCLS (BWL + 1, c, "backward %s check for mapped clause", mode);
+  phase = (c - start) >= lgl->elm->neglidx;
+  for (p = c; (lit = *p); p++)
+    if (abs (lit) != 1)
+      csig |= lglsig (lit);
+  size = p - c;
+  assert (csig == lglpeek (&lgl->elm->csigs, c - start));
+  assert (size == lglpeek (&lgl->elm->sizes, c - start));
+  res = 0;
+
+  if (str) phase = !phase;
+  lit = phase ? -1 : 1;
+  masksig = ~(lglsig (-lit) | lglsig (lit));
+
+  ulit = lglulit (lit);
+  occ = lglpeek (&lgl->elm->noccs, ulit);
+  if (!str && occ <= 1) return 0;
+  if (str && !occ) return 0;
+  for (next = lglpeek (&lgl->elm->occs, ulit);
+       !res && next;
+       next = lglpeek (&lgl->elm->next, next)) {
+      INCSTEPS (elm.steps);
+      if (next == p - start) continue;
+      if (phase != (next >= lgl->elm->neglidx)) continue;
+      plit = lglpeek (&lgl->elm->lits, next);
+      if (plit >= NOTALIT) continue;
+      assert (plit == lit);
+      osize = lglpeek (&lgl->elm->sizes, next);
+      if (osize > size) continue;
+      ocsig = lglpeek (&lgl->elm->csigs, next);
+      assert (ocsig);
+      ocsig &= masksig;
+      if ((ocsig & ~csig)) continue;
+      if (!marked) {
+       for (q = c; (other = *q); q++) {
+         if (str && abs (other) == 1) other = -other;
+         uolit = lglulit (other);
+         assert (!lglpeek (&lgl->elm->mark, uolit));
+         lglpoke (&lgl->elm->mark, uolit, 1);
+       }
+       marked = 1;
+      }
+      d = lgl->elm->lits.start + next;
+      if (c <= d && d < c + size) continue;
+      if (str) lgl->stats->elm.strchks++; else lgl->stats->elm.subchks++;
+      while (d[-1]) d--;
+      assert (c != d);
+      LOGMCLS (BWL + 1, d, "backward %s check with clause", mode);
+      res = 1;
+      for (q = d; res && (other = *q); q++) {
+       uolit = lglulit (other);
+       res = lglpeek (&lgl->elm->mark, uolit);
+      }
+      if (!res || !str || osize < size) continue;
+      LOGMCLS (BWL, d,
+        "static double strengthened by double self-subsuming resolution");
+      assert ((c - start) < lgl->elm->neglidx);
+      assert ((d - start) >= lgl->elm->neglidx);
+      assert (phase);
+      clidx = 0;
+      q = lgl->elm->lits.start + lgl->elm->neglidx;
+      while (q < d) {
+       other = *q++;
+       if (other >= NOTALIT) { while (*q++) ; continue; }
+       if (!other) clidx++;
+      }
+      LOGMCLS (BWL, d,
+       "strengthened and subsumed original irredundant clause");
+      LOGCLS (BWL, d,
+        "strengthened and subsumed mapped irredundant clause");
+      lglelrmcls (lgl, -lgl->elm->pivot, d, clidx);
+  }
+  if (marked) {
+    for (p = c; (lit = *p); p++) {
+      if (str && abs (lit) == 1) lit = -lit;
+      ulit = lglulit (lit);
+      assert (lglpeek (&lgl->elm->mark, ulit));
+      lglpoke (&lgl->elm->mark, ulit, 0);
+    }
+  }
+  return res;
+}
+
+static void lglelmsub (LGL * lgl) {
+  int clidx, count, subsumed, pivot, * c;
+  count = clidx = subsumed = 0;
+  pivot = lgl->elm->pivot;
+  for (c = lgl->elm->lits.start + 1;
+       c < lgl->elm->lits.top &&
+        lgl->limits->elm.steps > lgl->stats->elm.steps;
+       c++) {
+    INCSTEPS (elm.steps);
+    if (count++ == lgl->elm->negcls) clidx = 0, pivot = -pivot;
+    if (lglbacksub (lgl, c, 0)) {
+      subsumed++;
+      lgl->stats->elm.sub++;
+      LOGMCLS (BWL, c, "subsumed original irredundant clause");
+      LOGCLS (3, c, "subsumed mapped irredundant clause");
+      lglelrmcls (lgl, pivot, c, clidx);
+    } else clidx++;
+    while (*c) c++;
+  }
+  LOG (BWL + !subsumed,
+    "subsumed %d clauses containing %d or %d",
+    subsumed, lgl->elm->pivot, -lgl->elm->pivot);
+}
+
+static int lglelmstr (LGL * lgl) {
+  int clidx, count, strengthened, pivot, * c, * p, mlit, ilit, res, found;
+  int size;
+  count = clidx = strengthened = 0;
+  pivot = lgl->elm->pivot;
+  res = 0;
+  LOG (3, "strengthening with pivot %d", pivot);
+  for (c = lgl->elm->lits.start + 1;
+       c < lgl->elm->lits.top &&
+        lgl->limits->elm.steps > lgl->stats->elm.steps;
+       c++) {
+    INCSTEPS (elm.steps);
+    if (count++ == lgl->elm->negcls) {
+      clidx = 0, pivot = -pivot;
+      LOG (3, "strengthening with pivot %d", pivot);
+    }
+    if (*c == REMOVED) {
+      while (*c) { assert (*c == REMOVED); c++; }
+      continue;
+    }
+    if (lglbacksub (lgl, c, 1)) {
+      strengthened++;
+      lgl->stats->elm.str++;
+      LOGMCLS (2, c, "strengthening original irredundant clause");
+      LOGCLS (3, c, "strengthening mapped irredundant clause");
+      assert (lglmtstk (&lgl->clause));
+      found = 0;
+      size = 0;
+      for (p = c; (mlit = *p); p++) {
+       ilit = lglm2i (lgl, *p);
+       if (ilit == pivot) { found++; continue; }
+       assert (!lglval (lgl, ilit));
+       lglpushstk (lgl, &lgl->clause, ilit);
+       size++;
+      }
+      assert (found);
+      lglpushstk (lgl, &lgl->clause, 0);
+      LOGCLS (2, lgl->clause.start, "static strengthened irredundant clause");
+      if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+      lglpicosatchkcls (lgl);
+#endif
+      lglelrmcls (lgl, pivot, c, clidx);
+      lgldrupligaddcls (lgl, REDCS);
+      lgladdcls (lgl, 0, 0, 1);
+      lglclnstk (&lgl->clause);
+      if (size == 1) { res = 1; break; }
+    } else clidx++;
+    while (*c) c++;
+  }
+  LOG (2, "strengthened %d clauses containing %d or %d",
+       strengthened, lgl->elm->pivot, -lgl->elm->pivot);
+  return res;
+}
+
+static int lglflushclauses (LGL * lgl, int lit) {
+  int blit, tag, red, other, other2, count, glue, res;
+  const int * p, * w, * eow;
+  int lidx, glidx, slidx;
+  int * c, * q;
+  HTS * hts;
+  Stk * s;
+#ifndef NDEBUG
+  int occs;
+#endif
+  lglchkirrstats (lgl);
+  assert (lgl->probing || lgl->lkhd || lgl->dense);
+  hts = lglhts (lgl, lit);
+  if (!hts->count) return 0;
+#ifndef NDEBUG
+  occs = lgl->occs ? lglocc (lgl, lit) : 0;
+#endif
+  res = 0;
+  LOG (2, "flushing clauses with literal %d", lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  count = 0;
+  for (p = w; p < eow; p++) {
+    if (lgl->blocking) INCSTEPS (blk.steps);
+    if (lgl->eliminating) INCSTEPS (elm.steps);
+    if (lgl->simpleprobing) INCSTEPS (prb.simple.steps);
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    other = blit >> RMSHFT;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == BINCS) {
+      lglrmbwch (lgl, other, lit, red);
+      LOG (2, "flushed %s binary clause %d %d", lglred2str (red), lit, other);
+      lgldeclscnt (lgl, 2, red, 0);
+      if (!red) lgldecocc (lgl, lit), lgldecocc (lgl, other), res++;
+      count++;
+    } else if (tag == TRNCS) {
+      other2 = *p;
+      lglrmtwch (lgl, other2, lit, other, red);
+      lglrmtwch (lgl, other, lit, other2, red);
+      LOG (2, "flushed %s ternary clause %d %d %d",
+          lglred2str (red), lit, other, other2);
+      lgldeclscnt (lgl, 3, red, 0);
+      if (!red)  {
+       lgldecocc (lgl, lit);
+       lgldecocc (lgl, other);
+       lgldecocc (lgl, other2);
+       res++;
+      }
+      count++;
+    } else {
+      assert (tag == OCCS || tag == LRGCS);
+      if (tag == LRGCS) {
+       lidx = *p;
+       s = lglidx2stk (lgl, red, lidx);
+       if (red) {
+         glue = lidx & GLUEMASK;
+         c = s->start + (lidx >> GLUESHFT);
+       } else {
+         glue = 0;
+         c = s->start + lidx;
+       }
+      } else {
+       lidx = (blit >> RMSHFT);
+       s = &lgl->irr;
+       c = s->start + lidx;
+       glue = 0;
+      }
+      if (c >= s->top || (other = c[0]) >= NOTALIT) continue;
+      LOGCLS (2, c, "flushed %s large clause", lglred2str (red));
+      if (tag == LRGCS) {
+       if (other == lit) other = c[1];
+       assert (abs (other) != abs (lit));
+       lglrmlwch (lgl, other, red, lidx);
+      } else {
+       glidx = lidx;
+       if (red) glidx <<= GLUESHFT;
+       if (c[1] != lit) lglrmlwch (lgl, c[1], red, glidx);
+       if (other != lit) lglrmlwch (lgl, other, red, glidx);
+      }
+      if (red) {
+       assert (!glue);
+       LGLCHKACT (c[-1]);
+       c[-1] = REMOVED;
+      } else lgldecocc (lgl, lit);
+      for (q = c; (other = *q); q++) { assert (other < NOTALIT);
+       *q = REMOVED;
+       if (other == lit) continue;
+       if (red && glue) continue;
+       slidx = lidx;
+       if (red && tag == LRGCS) slidx >>= GLUESHFT;
+       lglrmlocc (lgl, other, red, slidx);
+       if (!red) lgldecocc (lgl, other);
+      }
+      *q = REMOVED;
+      lgldeclscnt (lgl, q - c, red, glue);
+      lgltrimlitstk (lgl, red, lidx);
+      if (!red) res++;
+      count++;
+    }
+  }
+#ifndef NDEBUG
+  if (lgl->occs) assert (occs == res);
+#endif
+  lglshrinkhts (lgl, hts, 0);
+  LOG (2, "flushed %d clauses with %d including %d irredundant",
+       count, lit, res);
+  lglchkirrstats (lgl);
+  return res;
+}
+
+static int lglflushlits (LGL * lgl, int lit) {
+  int blit, tag, red, other, other2, size, satisfied, d[3], glue;
+  int * p, * w, * eow, * c, * l, * k;
+  int lidx, slidx, glidx;
+  int count, res;
+  Val val, val2;
+  long delta;
+  Stk * s;
+
+// Some compilers do not like local functions, thus we use macros instead.
+//
+#define FIXPTRS() do { p += delta, w += delta, eow += delta; } while (0)
+
+  HTS * hts;
+  LOG (2, "flushing literal %d from clauses", lit);
+  assert (!lgl->level);
+  assert (lglifixed (lgl, lit) < 0);
+  assert (lgl->dense);
+  lglchkirrstats (lgl);
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  res = count = 0;
+  for (p = w; p < eow; p++) {
+    if (lgl->blocking) INCSTEPS (blk.steps);
+    if (lgl->eliminating) INCSTEPS (elm.steps);
+    if (lgl->simpleprobing) INCSTEPS (prb.simple.steps);
+    count++;
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      assert ((red && lgliselim (lgl, other)) || lglval (lgl, other) > 0);
+      lglrmbwch (lgl, other, lit, red);
+      LOG (2, "flushed %s binary clause %d %d", lglred2str (red), lit, other);
+      lgldeclscnt (lgl, 2, red, 0);
+      if (!red) {
+       if (lgl->dense) lgldecocc (lgl, lit), lgldecocc (lgl, other);
+       res++;
+      }
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      other2 = *++p;
+      lglrmtwch (lgl, other2, lit, other, red);
+      lglrmtwch (lgl, other, lit, other2, red);
+      LOG (2, "flushed %s ternary clause %d %d %d",
+          lglred2str (red), lit, other, other2);
+      lgldeclscnt (lgl, 3, red, 0);
+      if (!red)  {
+       if (lgl->dense) {
+         lgldecocc (lgl, lit);
+         lgldecocc (lgl, other);
+         lgldecocc (lgl, other2);
+       }
+       res++;
+      }
+      val = lglval (lgl, other);
+      val2 = lglval (lgl, other2);
+      if (!val && !val2) {
+       LOG (2,
+  "reducing flushed %s ternary clause %d %d %d to binary %s clause %d %d",
+            lglred2str (red),
+            lit, other, other2,
+            lglred2str (red),
+            other, other2);
+       delta = lglwchbin (lgl, other, other2, red);
+       delta += lglwchbin (lgl, other2, other, red);
+       if (lgl->simpleprobing && lgl->opts->prbsimple.val >= 2)
+         lglwrktouch (lgl, -other), lglwrktouch (lgl, -other2);
+       if (delta) FIXPTRS ();
+       if (red) {
+         lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       } else {
+         lglincirr (lgl, 2);
+         if (lgl->dense) lglincocc (lgl, other), lglincocc (lgl, other2);
+       }
+      } else {
+#ifndef NDEBUG
+       if (!red || (!lgliselim (lgl, other) && !lgliselim (lgl, other2)))
+         assert (val > 0 || val2 > 0);
+#endif
+      }
+    } else {
+      assert (tag == OCCS || tag == LRGCS);
+      lidx = (tag == LRGCS) ? *++p : (blit >> RMSHFT);
+      s = lglidx2stk (lgl, red, lidx);
+      c = s->start + (red ? (lidx >> GLUESHFT) : lidx);
+      if (c >= s->top || c[0] >= NOTALIT) continue;
+      size = satisfied = 0;
+      for (l = c; (other = *l); l++) {
+       if (other == lit) continue;
+       if ((val = lglval (lgl, other)) < 0) continue;
+       if (val > 0) { satisfied = 1; break; }
+       if (size < 3) d[size] = other;
+       size++;
+      }
+      if (!satisfied && size == 2) {
+       LOGCLS (2, c,
+         "reducing to binary %s clause %d %d flushed large %s clause",
+            lglred2str (red), d[0], d[1], lglred2str (red));
+       delta = lglwchbin (lgl, d[0], d[1], red);
+       delta += lglwchbin (lgl, d[1], d[0], red);
+       if (delta) FIXPTRS ();
+       if (red) {
+         lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       } else {
+         lglincirr (lgl, 2);
+         if (lgl->dense) lglincocc (lgl, d[0]), lglincocc (lgl, d[1]);
+       }
+       if (lgl->simpleprobing && lgl->opts->prbsimple.val >= 2)
+         lglwrktouch (lgl, -d[0]), lglwrktouch (lgl, -d[1]);
+      }
+      if (!satisfied && size == 3) {
+       LOGCLS (2, c,
+         "reducing to ternary %s clause %d %d %d flushed large %s clause",
+            lglred2str (red), d[0], d[1], d[2], lglred2str (red));
+       delta = lglwchtrn (lgl, d[0], d[1], d[2], red);
+       delta += lglwchtrn (lgl, d[1], d[0], d[2], red);
+       delta += lglwchtrn (lgl, d[2], d[0], d[1], red);
+       if (delta) FIXPTRS ();
+       if (red) {
+         lgl->stats->red.trn++, assert (lgl->stats->red.trn > 0);
+       } else {
+         lglincirr (lgl, 3);
+         if (lgl->dense) {
+           lglincocc (lgl, d[0]);
+           lglincocc (lgl, d[1]);
+           lglincocc (lgl, d[2]);
+         }
+       }
+       if (lgl->simpleprobing && lgl->opts->prbsimple.val >= 3)
+         lglwrktouch (lgl, d[0]),
+         lglwrktouch (lgl, d[1]),
+         lglwrktouch (lgl, d[2]); 
+      }
+      if (lgl->dense && !red) {
+       for (l = c; (other = *l); l++) {
+         if (satisfied || size <= 3 || lglval (lgl, other) < 0) {
+           if (!red) lgldecocc (lgl, other);
+           if (other != lit) {
+             slidx = lidx;
+             if (red && tag == LRGCS) slidx >>= GLUESHFT;
+             lglrmlocc (lgl, other, red, slidx);
+           }
+         }
+       }
+      }
+      glidx = lidx;
+      if (red && tag == OCCS) glidx <<= GLUESHFT;
+      if (c[0] != lit) lglrmlwch (lgl, c[0], red, glidx);
+      if (c[1] != lit) lglrmlwch (lgl, c[1], red, glidx);
+      if (satisfied || size <= 3) {
+       if (red) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+       for (k = c; (other = *k); k++) *k = REMOVED;
+       *k = REMOVED;
+       if (red) {
+         glue = (tag == LRGCS) ? (lidx & GLUEMASK) : 0;
+         assert (lgl->stats->lir[glue].clauses > 0);
+         lgl->stats->lir[glue].clauses--;
+         assert (lgl->stats->red.lrg > 0);
+         lgl->stats->red.lrg--;
+       } else lgldecirr (lgl, k - c);
+      } else {
+       for (l = k = c; (other = *l); l++) {
+         if ((val = lglval (lgl, other)) < 0) continue;
+         if (lgl->simpleprobing && lgl->opts->prbsimple.val >= 3)
+           lglwrktouch (lgl, other);
+         assert (abs (other) != abs (lit));
+         assert (!val);
+         *k++ = other;
+       }
+       assert (size == k - c);
+       if (!red && k < l) {
+         assert (lgl->stats->irr.lits.cur >= l - k);
+         lgl->stats->irr.lits.cur -= l - k;
+       }
+       *k++ = 0;
+       while (k <= l) *k++ = REMOVED;
+       delta = lglwchlrg (lgl, c[0], c[1], red, glidx);
+       delta += lglwchlrg (lgl, c[1], c[0], red, glidx);
+       if (delta) FIXPTRS ();
+      }
+      lgltrimlitstk (lgl, red, lidx);
+    }
+  }
+  hts = lglhts (lgl, lit);
+  lglshrinkhts (lgl, hts, 0);
+  LOG (2, "flushed %d occurrences of literal %d including %d irredundant",
+       count, lit, res);
+  lglchkirrstats (lgl);
+  return res;
+
+#undef FIXPTRS
+
+}
+
+static int lglflush (LGL * lgl) {
+  int lit, count;
+  if (lgl->mt) return 0;
+  lglchkirrstats (lgl);
+  assert (!lgl->level);
+  assert (lgl->probing || lgl->lkhd || lgl->dense);
+  if (lgl->flushed == lglcntstk (&lgl->trail)) return 1;
+  if (!lglbcp (lgl)) { lgl->mt = 1; return 0; }
+  if (!lglsyncunits (lgl)) { assert (lgl->mt); return 0; }
+  count = 0;
+  while  (lgl->flushed < lglcntstk (&lgl->trail)) {
+    lit = lglpeek (&lgl->trail, lgl->flushed++);
+    lglflushclauses (lgl, lit);
+    lglflushlits (lgl, -lit);
+    count++;
+  }
+  LOG (2, "flushed %d literals", count);
+  assert (!lgl->mt);
+  return 1;
+}
+
+static void lglblockinglit (LGL * lgl, int ilit) {
+  int elit = lglexport (lgl, ilit), sgnbit = (1 << (elit < 0));
+  Ext * ext = lglelit2ext (lgl, elit);
+  assert (!ext->equiv);
+  assert (!ext->eliminated);
+  assert (abs (ext->repr) == abs (ilit));
+  if (ext->blocking & sgnbit) return;
+  ext->blocking |= sgnbit;
+  LOG (3, "marking external %d internal %d as blocking", elit, ilit);
+  lgl->stats->blk.lits++;
+}
+
+static void lglelmfrelit (LGL * lgl, int mpivot,
+                         int * sop, int * eop, int * son, int * eon) {
+  int ipivot = mpivot * lgl->elm->pivot, clidx, ilit, tmp, cover, maxcover;
+  int * c, * d, * p, * q, lit, nontrivial, idx, sgn, clen, reslen;
+  assert (mpivot == 1 || mpivot == -1);
+  assert (ipivot);
+  LOG (3,
+       "blocked clause elimination and forced resolution of clauses with %d",
+       ipivot);
+  clidx = 0;
+  cover = lglpeek (&lgl->elm->noccs, lglulit (-mpivot));
+  for (c = sop; c < eop; c = p + 1) {
+    if (lgl->eliminating) INCSTEPS (elm.steps);
+    if (*c == REMOVED) { for (p = c + 1; *p; p++) ; continue; }
+    maxcover = 0;
+    for (p = c; (lit = *p); p++) {
+      if (lit == mpivot) continue;
+      assert (lit != -mpivot);
+      maxcover += lglpeek (&lgl->elm->noccs, lglulit (-lit));
+    }
+    if (maxcover < cover - 1) { clidx++; continue; }
+    for (p = c; (lit = *p); p++) {
+      if (lit == mpivot) continue;
+      assert (lit != -mpivot);
+      idx = abs (lit);
+      assert (!lglpeek (&lgl->elm->mark, idx));
+      sgn = lglsgn (lit);
+      lglpoke (&lgl->elm->mark, idx, sgn);
+    }
+    nontrivial = 0;
+    clen = p - c;
+    for (d = son; !nontrivial && d < eon; d = q + 1) {
+      INCSTEPS (elm.steps);
+      if (*d == REMOVED) { for (q = d + 1; *q; q++) ; continue; }
+      INCSTEPS (elm.resolutions);
+      LOGMCLS (3, c, "trying forced resolution 1st antecedent");
+      LOGMCLS (3, d, "trying forced resolution 2nd antecedent");
+      assert (clen > 0);
+      reslen = clen - 1;
+      for (q = d; (lit = *q); q++) {
+       if (lit == -mpivot) continue;
+       assert (lit != mpivot);
+       idx = abs (lit), sgn = lglsgn (lit);
+       tmp = lglpeek (&lgl->elm->mark, idx);
+       if (tmp == -sgn) break;
+       if (tmp != sgn) reslen++;
+      }
+      if (lit) {
+       while (*++q) ;
+       LOG (3, "trying forced resolution ends with trivial resolvent");
+      } else {
+       LOG (3, "non trivial resolvent in blocked clause elimination");
+       nontrivial = INT_MAX;
+      }
+    }
+    for (p = c; (lit = *p); p++) {
+      if (lit == mpivot) continue;
+      assert (lit != -mpivot);
+      idx = abs (lit);
+      assert (lglpeek (&lgl->elm->mark, idx) == lglsgn (lit));
+      lglpoke (&lgl->elm->mark, idx, 0);
+    }
+    assert (lgl->opts->elim.val);
+    if (!nontrivial &&
+        lgl->opts->block.val &&
+       lgl->opts->elmblk.val &&
+       (!lgl->opts->elmblkwait.val || !lgl->opts->elim.val || lgl->elmrtc)) {
+      assert (maxcover >= cover);
+      lgl->stats->elm.blkd++;
+      LOGMCLS (2, c, "blocked on %d clause", ipivot);
+      lglepush (lgl, ipivot);
+      for (p = c; (lit = *p); p++) {
+       if (lit == mpivot) continue;
+       assert (lit != -mpivot);
+       ilit = lglm2i (lgl, lit);
+       lglepush (lgl, ilit);
+      }
+      lglepush (lgl, 0);
+      lglelrmcls (lgl, ipivot, c, clidx);
+      lglblockinglit (lgl, ipivot);
+      continue;
+    }
+    clidx++;
+    if (lgl->limits->elm.steps <= lgl->stats->elm.steps) {
+      LOG (2, "maximum number of steps in elimination exhausted");
+      return;
+    }
+  }
+}
+
+static void lglelmfre (LGL * lgl) {
+  int * sop, * eop, * son, * eon;
+  assert (lgl->elm->pivot);
+  sop = lgl->elm->lits.start + 1;
+  eop = son = lgl->elm->lits.start + lgl->elm->neglidx;
+  eon = lgl->elm->lits.top;
+  lglelmfrelit (lgl, 1, sop, eop, son, eon);
+  lglelmfrelit (lgl, -1, son, eon, sop, eop);
+}
+
+static void lgleliminated (LGL * lgl, int pivot) {
+  AVar * av;
+  int elit;
+  Ext * e;
+  assert (!lglifrozen (lgl, pivot));
+  av = lglavar (lgl, pivot);
+  assert (av->type == FREEVAR);
+  av->type = ELIMVAR;
+  lgl->stats->elm.elmd++;
+  assert (lgl->stats->elm.elmd > 0);
+  lglflushclauses (lgl, pivot);
+  lglflushclauses (lgl, -pivot);
+  LOG (2, "eliminated %d", pivot);
+  elit = lglexport (lgl, pivot);
+  e = lglelit2ext (lgl, elit);
+  assert (!e->eliminated);
+  assert (!e->equiv);
+  e->eliminated = 1;
+}
+
+static void lglepusheliminated (LGL * lgl, int idx) {
+  const int * p, * w, * eow, * c, * l;
+  int lit, blit, tag, red, other;
+  HTS * hts;
+  lit = (lglocc (lgl, idx) < lglocc (lgl, -idx)) ? idx : -idx;
+  LOG (3, "keeping clauses with %d for extending assignment", lit);
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    lglepush (lgl, lit);
+    if (tag == BINCS || tag == TRNCS) {
+      lglepush (lgl, blit >> RMSHFT);
+      if (tag == TRNCS)
+       lglepush (lgl, *p);
+    } else {
+      assert (tag == OCCS);
+      c = lglidx2lits (lgl, 0, blit >> RMSHFT);
+      for (l = c; (other = *l); l++)
+       if (other != lit)
+         lglepush (lgl, other);
+    }
+    lglepush (lgl, 0);
+  }
+  lglepush (lgl, -lit);
+  lglepush (lgl, 0);
+  lgleliminated (lgl, idx);
+}
+
+static int lglunhimpl (const DFPR * dfpr, int a, int b) {
+  int u = lglulit (a), v = lglulit (b), c, d, f, g;
+  c = dfpr[u].discovered; if (!c) return 0;
+  d = dfpr[v].discovered; if (!d) return 0;
+  f = dfpr[u].finished, g = dfpr[v].finished;
+  assert (0 < c && c < f);
+  assert (0 < d && d < g);
+  return c < d && g < f;
+}
+
+static int lglunhimplies2 (const DFPR * dfpr, int a, int b) {
+  return lglunhimpl (dfpr, a, b) || lglunhimpl (dfpr, -b, -a);
+}
+
+static int lglunhimplincl (const DFPR * dfpr, int a, int b) {
+  int u = lglulit (a), v = lglulit (b), c, d, f, g;
+  c = dfpr[u].discovered; if (!c) return 0;
+  d = dfpr[v].discovered; if (!d) return 0;
+  f = dfpr[u].finished, g = dfpr[v].finished;
+  assert (0 < c && c < f);
+  assert (0 < d && d < g);
+  return c <= d && g <= f;
+}
+
+static int lglunhimplies2incl (const DFPR * dfpr, int a, int b) {
+  return lglunhimplincl (dfpr, a, b) || lglunhimplincl (dfpr, -b, -a);
+}
+
+static int lglhastrn (LGL * lgl, int a, int b, int c) {
+  int blit, tag, other, other2;
+  const int * w, * eow, * p;
+  HTS * ha, * hb, * hc;
+  ha = lglhts (lgl, a);
+  hb = lglhts (lgl, b);
+  if (hb->count < ha->count) { SWAP (int, a, b); SWAP (HTS *, ha, hb); }
+  hc = lglhts (lgl, c);
+  if (hc->count < ha->count) { SWAP (int, a, c); SWAP (HTS *, ha, hc); }
+  w = lglhts2wchs (lgl, ha);
+  eow = w + ha->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == OCCS) continue;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      if (other == b || other == c) return 1;
+      continue;
+    }
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    assert (tag == TRNCS);
+    other = blit >> RMSHFT;
+    if (other != b && other != c) continue;
+    other2 = *p;
+    if (other2 == b || other2 == c) return 1;
+  }
+  if (hc->count < hb->count) { SWAP (int, b, c); SWAP (HTS *, hb, hc); }
+  w = lglhts2wchs (lgl, hb);
+  eow = w + hb->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == OCCS) continue;
+    if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+    assert (tag == BINCS);
+    other = blit >> RMSHFT;
+    if (other == c) return 1;
+  }
+  return 0;
+}
+
+static int64_t lglfactor (LGL * lgl, int lim, int count) {
+  int64_t factor, res;
+  if (!count) return lim;
+  switch (lgl->opts->factor.val) {
+    default: factor = 1; break;
+    case 1: factor = lglceilld (count); break;
+    case 2: factor = count; break;
+    case 3: factor = count*(int64_t)count; break;
+  }
+  if (!factor) factor = 1;
+  if (factor > lgl->opts->factmax.val) factor = lgl->opts->factmax.val;
+  res = lim * factor;
+  return res;
+}
+
+static int lglforcedve (LGL * lgl, int idx) {
+  int pocc = lglocc (lgl, idx);
+  int nocc = lglocc (lgl, -idx);
+  int count = lgl->stats->elm.count;
+  if (!pocc) return 1;
+  if (!nocc) return 1;
+  if (lgl->opts->elmfull.val) return 0;
+  if (pocc >= lglfactor (lgl, lgl->opts->elmocclim1.val, count)) return -1;
+  if (nocc >= lglfactor (lgl, lgl->opts->elmocclim1.val, count)) return -1;
+  if (pocc < lglfactor (lgl, lgl->opts->elmocclim2.val, count)) return 0;
+  if (nocc < lglfactor (lgl, lgl->opts->elmocclim2.val, count)) return 0;
+  return -1;
+}
+
+static int lgltrylargeve (LGL * lgl) {
+  const int * c, * d, * sop, * eop, * son, * eon, * p, * q, * start, * end;
+  int lit, idx, sgn, tmp, ip, ilit, npocc, nnocc, limit, count, i, res;
+  int clen, dlen, reslen, maxreslen;
+  ip = lgl->elm->pivot;
+  assert (ip);
+  if ((res = lglforcedve (lgl, ip))) return res > 0;
+  sop = lgl->elm->lits.start + 1;
+  eop = son = lgl->elm->lits.start + lgl->elm->neglidx;
+  eon = lgl->elm->lits.top;
+  npocc = lglpeek (&lgl->elm->noccs, lglulit (1));
+  nnocc = lglpeek (&lgl->elm->noccs, lglulit (-1));
+  limit = npocc + nnocc;
+  count = 0;
+  for (i = 0; i <= 1; i++) {
+    start = i ? son : sop;
+    end = i ? eon : eop;
+    for (c = start; c < end; c++) {
+      INCSTEPS (elm.steps);
+      if (*c == REMOVED) { while (*c) c++; continue; }
+      while ((lit = *c)) {
+       (void) lglm2i (lgl, lit);
+       c++;
+      }
+      count++;
+    }
+  }
+  assert (count == limit);
+  LOG (3, "trying clause distribution for %d with limit %d", ip, limit);
+  maxreslen = 0;
+  for (c = sop; c < eop && limit >= 0; c = p + 1) {
+    INCSTEPS (elm.steps);
+    if (*c == REMOVED) { for (p = c + 1; *p; p++) ; continue; }
+    assert (lglmtstk (&lgl->resolvent));
+    clen = 0;
+    for (p = c; (lit = *p); p++) {
+      if (lit == 1) continue;
+      assert (lit != -1);
+      idx = abs (lit);
+      assert (!lglpeek (&lgl->elm->mark, idx));
+      sgn = lglsgn (lit);
+      lglpoke (&lgl->elm->mark, idx, sgn);
+      ilit = lglm2i (lgl, lit);
+      lglpushstk (lgl, &lgl->resolvent, ilit);
+      clen++;
+    }
+    for (d = son; limit >= 0 && d < eon; d = q + 1) {
+      INCSTEPS (elm.steps);
+      if (*d == REMOVED) { for (q = d + 1; *q; q++) ; continue; }
+      INCSTEPS (elm.resolutions);
+      LOGMCLS (3, c, "trying resolution 1st antecedent");
+      LOGMCLS (3, d, "trying resolution 2nd antecedent");
+      dlen = 0;
+      reslen = clen;
+      for (q = d; (lit = *q); q++) {
+       if (lit == -1) continue;
+       dlen++;
+       assert (lit != 1);
+       idx = abs (lit), sgn = lglsgn (lit);
+       tmp = lglpeek (&lgl->elm->mark, idx);
+       if (tmp == -sgn) break;
+       if (tmp == sgn) continue;
+       ilit = lglm2i (lgl, lit);
+       lglpushstk (lgl, &lgl->resolvent, ilit);
+       reslen++;
+      }
+      assert (reslen == lglcntstk (&lgl->resolvent));
+      if (!lit && reslen == 1) {
+       LOG (3, "trying resolution ends with unit clause");
+       lit = lglpeek (&lgl->resolvent, 0);
+       limit += lglevar (lgl, lit)->occ[lit < 0];
+      } else if (lit) {
+       while (*++q) ;
+       LOG (3, "trying resolution ends with trivial resolvent");
+      } else {
+       limit--;
+       LOG (3,
+            "trying resolution with non trivial resolvent remaining %d",
+            limit);
+       if (reslen > maxreslen) maxreslen = reslen;
+      }
+      assert (!*q);
+      lglrststk (&lgl->resolvent, clen);
+    }
+    lglclnstk (&lgl->resolvent);
+    for (p = c; (lit = *p); p++) {
+      if (lit == 1) continue;
+      assert (lit != -1);
+      idx = abs (lit);
+      assert (lglpeek (&lgl->elm->mark, idx) == lglsgn (lit));
+      lglpoke (&lgl->elm->mark, idx, 0);
+    }
+    if (lgl->limits->elm.steps <= lgl->stats->elm.steps) {
+      LOG (2, "maximum number of steps in elimination exhausted");
+      return 0;
+    }
+  }
+  assert (lglm2i (lgl, 1) == ip);
+  if (limit < 0) {
+    LOG (3, "resolving away %d would increase number of clauses", ip);
+    return 0;
+  }
+  if (limit) LOG (2, "resolving away %d removes %d clauses", ip, limit);
+  else LOG (2, "resolving away %d does not change number of clauses", ip);
+  return 1;
+}
+
+static void lgldolargeve (LGL * lgl) {
+  const int * c, * d, * sop, * eop, * son, * eon, * p, * q, * start, * end;
+  int lit, idx, sgn, tmp, ip, ilit, mp, npocc, nnocc;
+  int clen, dlen, reslen;
+  Val val;
+  ip = lgl->elm->pivot;
+  assert (ip);
+  sop = lgl->elm->lits.start + 1;
+  eop = son = lgl->elm->lits.start + lgl->elm->neglidx;
+  eon = lgl->elm->lits.top;
+  npocc = lglpeek (&lgl->elm->noccs, lglulit (1));
+  nnocc = lglpeek (&lgl->elm->noccs, lglulit (-1));
+  LOG (2, "(large) variable elimination of %d", lgl->elm->pivot);
+  lglflushclauses (lgl, ip);
+  lglflushclauses (lgl, -ip);
+  if (npocc < nnocc) start = sop, end = eop, mp = 1;
+  else start = son, end = eon, ip = -ip, mp = -1;
+  LOG (3, "will save clauses with %d for extending assignment", ip);
+  for (c = start; c < end; c = p + 1) {
+    INCSTEPS (elm.steps);
+    if (*c == REMOVED) { for (p = c + 1; *p; p++) ; continue; }
+    lglepush (lgl, ip);
+    for (p = c; (lit = *p); p++)  {
+      if (lit == mp) continue;
+      assert (lit != -mp);
+      ilit = lglm2i (lgl, lit);
+      lglepush (lgl, ilit);
+    }
+    lglepush (lgl, 0);
+  }
+  lglepush (lgl, -ip);
+  lglepush (lgl, 0);
+  for (c = sop; c < eop; c = p + 1) {
+    INCSTEPS (elm.steps);
+    if (*c == REMOVED) { for (p = c + 1; *p; p++) ; continue; }
+    assert (lglmtstk (&lgl->resolvent));
+    clen = 0;
+    for (p = c; (lit = *p); p++) {
+      if (lit == 1) continue;
+      assert (lit != -1);
+      idx = abs (lit);
+      assert (!lglpeek (&lgl->elm->mark, idx));
+      sgn = lglsgn (lit);
+      lglpoke (&lgl->elm->mark, idx, sgn);
+      ilit = lglm2i (lgl, lit);
+      lglpushstk (lgl, &lgl->resolvent, ilit);
+      clen++;
+    }
+    for (d = son; d < eon; d = q + 1) {
+      INCSTEPS (elm.steps);
+      if (*d == REMOVED) { for (q = d + 1; *q; q++) ; continue; }
+      INCSTEPS (elm.resolutions);
+      assert (lglmtstk (&lgl->clause));
+      dlen = 0;
+      reslen = clen;
+      for (q = d; (lit = *q); q++) {
+       if (lit == -1) continue;
+       dlen++;
+       assert (lit != 1);
+       idx = abs (lit), sgn = lglsgn (lit);
+       tmp = lglpeek (&lgl->elm->mark, idx);
+       if (tmp == sgn) continue;
+       if (tmp == -sgn) break;
+       ilit = lglm2i (lgl, lit);
+       val = lglval (lgl, ilit);
+       if (val < 0) continue;
+       if (val > 0) break;
+       lglpushstk (lgl, &lgl->clause, ilit);
+       ilit = lglm2i (lgl, lit);
+       lglpushstk (lgl, &lgl->resolvent, ilit);
+       reslen++;
+      }
+      assert (reslen == lglcntstk (&lgl->resolvent));
+      if (!lit && reslen == 1) {
+       goto RESOLVE;
+      } if (lit) {
+       while (*++q) ;
+      } else {
+RESOLVE:
+       LOGMCLS (3, c, "resolving variable elimination 1st antecedent");
+       LOGMCLS (3, d, "resolving variable elimination 2nd antecedent");
+       for (p = c; (lit = *p); p++) {
+         if (lit == 1) continue;
+         assert (lit != -1);
+         ilit = lglm2i (lgl, lit);
+         val = lglval (lgl, ilit);
+         if (val < 0) continue;
+         if (val > 0) break;
+         lglpushstk (lgl, &lgl->clause, ilit);
+       }
+       if (!lit) {
+         lglpushstk (lgl, &lgl->clause, 0);
+         LOGCLS (3, lgl->clause.start, "variable elimination resolvent");
+         lgldrupligaddcls (lgl, REDCS);
+         lgladdcls (lgl, 0, 0, 1);
+         if (lgl->opts->drup.val) lgldrupcls (lgl);
+       }
+      }
+      lglclnstk (&lgl->clause);
+      assert (!*q);
+      lglrststk (&lgl->resolvent, clen);
+    }
+    lglclnstk (&lgl->resolvent);
+    for (p = c; (lit = *p); p++) {
+      if (lit == 1) continue;
+      assert (lit != -1);
+      idx = abs (lit);
+      assert (lglpeek (&lgl->elm->mark, idx) == lglsgn (lit));
+      lglpoke (&lgl->elm->mark, idx, 0);
+    }
+  }
+  lgleliminated (lgl, lgl->elm->pivot);
+  lgl->stats->elm.large++;
+}
+
+static void lglelimlitaux (LGL * lgl, int idx) {
+  lglelmsub (lgl);
+  if (lglelmstr (lgl)) return;
+  lglelmfre (lgl);
+  if (lgltrylargeve (lgl)) lgldolargeve (lgl);
+}
+
+static int lgls2m (LGL * lgl, int ilit) {
+  AVar * av = lglavar (lgl, ilit);
+  int res = av->mark;
+  if (!res) {
+    res = lglcntstk (&lgl->seen) + 1;
+    if (res > lgl->opts->smallvevars.val + 1) return 0;
+    av->mark = res;
+    assert (lglcntstk (&lgl->seen) == lglcntstk (&lgl->elm->m2i) - 1);
+    lglpushstk (lgl, &lgl->seen, abs (ilit));
+    lglpushstk (lgl, &lgl->elm->m2i, abs (ilit));
+    LOG (4, "mapped internal variable %d to marked variable %d",
+        abs (ilit), res);
+  }
+  if (ilit < 0) res = -res;
+  return res;
+}
+
+static void lglvar2funaux (int v, Fun res, int negate) {
+  uint64_t tmp;
+  int i, j, p;
+  assert (0 <= v && v < FUNVAR);
+  if (v < 6) {
+    tmp = lglbasevar2funtab[v];
+    if (negate) tmp = ~tmp;
+    for (i = 0; i < FUNQUADS; i++)
+      res[i] = tmp;
+  } else {
+    tmp = negate ? ~0ull : 0ull;
+    p = 1 << (v - 6);
+    j = 0;
+    for (i = 0; i < FUNQUADS; i++) {
+      res[i] = tmp;
+      if (++j < p) continue;
+      tmp = ~tmp;
+      j = 0;
+    }
+  }
+}
+
+static void lglvar2fun (int v, Fun res) {
+  lglvar2funaux (v, res, 0);
+}
+
+static void lglnegvar2fun (int v, Fun res) {
+  lglvar2funaux (v, res, 1);
+}
+
+static void lglfuncpy (Fun dst, const Fun src) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    dst[i] = src[i];
+}
+
+static void lglfalsefun (Fun res) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    res[i] = 0ll;
+}
+
+static void lgltruefun (Fun res) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    res[i] = ~0ll;
+}
+
+static int lglisfalsefun (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (f[i] != 0ll) return 0;
+  return 1;
+}
+
+static int lglistruefun (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (f[i] != ~0ll) return 0;
+  return 1;
+}
+
+static void lglorfun (Fun a, const Fun b) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] |= b[i];
+}
+
+static void lglornegfun (Fun a, const Fun b) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] |= ~b[i];
+}
+
+static void lglor3fun (Fun a, const Fun b, const Fun c) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] = b[i] | c[i];
+}
+
+static void lglor3negfun (Fun a, const Fun b, const Fun c) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] = b[i] | ~c[i];
+}
+
+static void lglandornegfun (Fun a, const Fun b, const Fun c) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] &= b[i] | ~c[i];
+}
+
+static void lglandfun (Fun a, const Fun b) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] &= b[i];
+}
+
+static void lgland3fun (Fun a, const Fun b, const Fun c) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] = b[i] & c[i];
+}
+
+static void lgland3negfun (Fun a, const Fun b, const Fun c) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    a[i] = b[i] & ~c[i];
+}
+
+static void lglsrfun (Fun a, int shift) {
+  uint64_t rest, tmp;
+  int i, j, q, b, l;
+  assert (0 <= shift);
+  b = shift & 63;
+  q = shift >> 6;
+  j = 0;
+  i = q;
+  assert (i >= 0);
+  l = 64 - b;
+  while (j < FUNQUADS) {
+    if (i < FUNQUADS) {
+      tmp = a[i] >> b;
+      rest = (b && i+1 < FUNQUADS) ? (a[i+1] << l) : 0ull;
+      a[j] = rest | tmp;
+    } else a[j] = 0ull;
+    i++, j++;
+  }
+}
+
+static void lglslfun (Fun a, int shift) {
+  uint64_t rest, tmp;
+  int i, j, q, b, l;
+  assert (0 <= shift);
+  b = shift & 63;
+  q = shift >> 6;
+  j = FUNQUADS - 1;
+  i = j - q;
+  l = 64 - b;
+  while (j >= 0) {
+    if (i >= 0) {
+      tmp = a[i] << b;
+      rest = (b && i > 0) ? (a[i-1] >> l) : 0ll;
+      a[j] = rest | tmp;
+    } else a[j] = 0ll;
+    i--, j--;
+  }
+}
+
+static void lgls2fun (int mlit, Fun res) {
+  int midx = abs (mlit), sidx = midx - 2;
+  assert (0 <= sidx && sidx < FUNVAR);
+  if (mlit < 0) lglnegvar2fun (sidx, res);
+  else lglvar2fun (sidx, res);
+}
+
+static int lglinitsmallve (LGL * lgl, int lit, Fun res) {
+  int blit, tag, red, other, other2, lidx, mlit;
+  const int * p, * w, * eow, * c, * q;
+  Fun cls, tmp;
+  HTS * hts;
+  Val val;
+  assert (!lglval (lgl, lit));
+  LOG (3, "initializing small variable eliminiation for %d", lit);
+#ifndef NDEBUG
+  mlit =
+#endif
+  lgls2m (lgl, lit);
+  assert (abs (mlit) == 1);
+  hts = lglhts (lgl, lit);
+  lgltruefun (res);
+  if (!hts->count) goto DONE;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    INCSTEPS (elm.steps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    lglfalsefun (cls);
+    if (tag == BINCS || tag == TRNCS) {
+      other = blit >> RMSHFT;
+      val = lglval (lgl, other);
+      assert (val <= 0);
+      if (!val) {
+       mlit = lgls2m (lgl, other);
+       if (!mlit) return 0;
+       lgls2fun (mlit, tmp);
+       lglorfun (cls, tmp);
+      }
+      if (tag == TRNCS) {
+       other2 = *p;
+       val = lglval (lgl, other2);
+       assert (val <= 0);
+       if (!val) {
+         mlit = lgls2m (lgl, other2);
+         if (!mlit) return 0;
+         lgls2fun (mlit, tmp);
+         lglorfun (cls, tmp);
+       }
+      }
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, 0, lidx);
+      for (q = c; (other = *q); q++) {
+       if (other == lit) continue;
+       assert (other != -lit);
+       val = lglval (lgl, other);
+       assert (val <= 0);
+       if (!val) {
+         mlit = lgls2m (lgl, other);
+         if (!mlit) return 0;
+         lgls2fun (mlit, tmp);
+         lglorfun (cls, tmp);
+       }
+      }
+    }
+    assert (!lglisfalsefun (cls));
+    assert (!lglistruefun (cls));
+    lglandfun (res, cls);
+    INCSTEPS (elm.copies);
+  }
+DONE:
+  return 1;
+}
+
+static void lglresetsmallve (LGL * lgl) {
+  lglclnstk (&lgl->elm->m2i);
+  lglclnstk (&lgl->elm->clv);
+  lglpopnunmarkstk (lgl, &lgl->seen);
+}
+
+static void lglsmallevalcls (unsigned cls, Fun res) {
+  Fun tmp;
+  int v;
+  lglfalsefun (res);
+  for (v = 0; v < FUNVAR; v++) {
+    if (cls & (1 << (2*v + 1))) {
+      lglvar2fun (v, tmp);
+      lglornegfun (res, tmp);
+    } else if (cls & (1 << (2*v))) {
+      lglvar2fun (v, tmp);
+      lglorfun (res, tmp);
+    }
+  }
+}
+
+static Cnf lglpos2cnf (int pos) { assert (pos >=0 ); return pos; }
+static Cnf lglsize2cnf (int s) { assert (s >=0 ); return ((Cnf)s) << 32; }
+static int lglcnf2pos (Cnf cnf) { return cnf & 0xfffffll; }
+static int lglcnf2size (Cnf cnf) { return cnf >> 32; }
+
+static Cnf lglcnf (int pos, int size) {
+  return lglpos2cnf (pos) | lglsize2cnf (size);
+}
+
+static void lglsmallevalcnf (LGL * lgl, Cnf cnf, Fun res) {
+  Fun tmp;
+  int i, n, p, cls;
+  p = lglcnf2pos (cnf);
+  n = lglcnf2size (cnf);
+  lgltruefun (res);
+  for (i = 0; i < n; i++) {
+    cls = lglpeek (&lgl->elm->clv, p + i);
+    lglsmallevalcls (cls, tmp);
+    lglandfun (res, tmp);
+  }
+}
+
+static void lglnegcofactorfun (const Fun f, int v, Fun res) {
+  Fun mask, masked;
+  lglvar2fun (v, mask);
+  lgland3negfun (masked, f, mask);
+  lglfuncpy (res, masked);
+  lglslfun (masked, (1 << v));
+  lglorfun (res, masked);
+}
+
+static void lglposcofactorfun (const Fun f, int v, Fun res) {
+  Fun mask, masked;
+  lglvar2fun (v, mask);
+  lgland3fun (masked, f, mask);
+  lglfuncpy (res, masked);
+  lglsrfun (masked, (1 << v));
+  lglorfun (res, masked);
+}
+
+static int lglsmallfundeps0 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xaaaaaaaaaaaaaaaaull)>>1) !=
+         (f[i] & 0x5555555555555555ull)) return 1;
+  return 0;
+}
+
+static int lglsmallfundeps1 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xccccccccccccccccull)>>2) !=
+         (f[i] & 0x3333333333333333ull)) return 1;
+  return 0;
+}
+
+static int lglsmallfundeps2 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xf0f0f0f0f0f0f0f0ull)>>4) !=
+         (f[i] & 0x0f0f0f0f0f0f0f0full)) return 1;
+  return 0;
+}
+
+static int lglsmallfundeps3 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xff00ff00ff00ff00ull)>>8) !=
+         (f[i] & 0x00ff00ff00ff00ffull)) return 1;
+  return 0;
+}
+
+static int lglsmallfundeps4 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xffff0000ffff0000ull)>>16) !=
+         (f[i] & 0x0000ffff0000ffffull)) return 1;
+  return 0;
+}
+
+static int lglsmallfundeps5 (const Fun f) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (((f[i] & 0xffffffff00000000ull)>>32) !=
+         (f[i] & 0x00000000ffffffffull)) return 1;
+  return 0;
+}
+
+static int lglsmallfundepsgen (const Fun f, int min) {
+  const int c = (1 << (min - 6));
+  int i, j;
+  assert (min >= 6);
+  for (i = 0; i < FUNQUADS; i += (1 << (min - 5)))
+    for (j = 0; j < c; j++)
+      if (f[i + j] != f[i + c + j]) return 1;
+  return 0;
+}
+
+static int lglsmalltopvar (const Fun f, int min) {
+  int i;
+  switch (min) {
+    case 0: if (lglsmallfundeps0 (f)) return 0;
+    case 1: if (lglsmallfundeps1 (f)) return 1;
+    case 2: if (lglsmallfundeps2 (f)) return 2;
+    case 3: if (lglsmallfundeps3 (f)) return 3;
+    case 4: if (lglsmallfundeps4 (f)) return 4;
+    case 5: if (lglsmallfundeps5 (f)) return 5;
+  }
+  for (i = lglmax (6, min); i <= FUNVAR - 2; i++)
+    if (lglsmallfundepsgen (f, i)) return i;
+  return i;
+}
+
+static Cnf lglsmalladdlit2cnf (LGL * lgl, Cnf cnf, int lit) {
+  int p, m, q, n, i, cls;
+  Cnf res;
+  p = lglcnf2pos (cnf);
+  m = lglcnf2size (cnf);
+  q = lglcntstk (&lgl->elm->clv);
+  for (i = 0; i < m; i++) {
+    cls = lglpeek (&lgl->elm->clv, p + i);
+    assert (!(cls & lit));
+    cls |= lit;
+    lglpushstk (lgl, &lgl->elm->clv, cls);
+  }
+  n = lglcntstk (&lgl->elm->clv) - q;
+  res = lglcnf (q, n);
+  return res;
+}
+
+#ifndef NDEBUG
+static int lglefun (const Fun a, const Fun b) {
+  int i;
+  for (i = 0; i < FUNQUADS; i++)
+    if (a[i] & ~b[i]) return 0;
+  return 1;
+}
+#endif
+
+// The dual version of Minato's algorithm for computing an irredundant
+// product of sums.   The original algorithm computes an irredundant sum of
+// products. It uses BDDs for representing boolean functions and ZDDs for
+// manipulating sum of product.  We work with function tables stored as bit
+// maps and plain CNFs stored as lists of clauses instead.
+
+static Cnf lglsmallipos (LGL * lgl, const Fun U, const Fun L, int min) {
+  Fun U0, U1, L0, L1, Unew, ftmp;
+  Cnf c0, c1, cstar, ctmp, res;
+  int x, y, z;
+  assert (lglefun (L, U));
+  if (lglistruefun (U)) return TRUECNF;
+  if (lglisfalsefun (L)) return FALSECNF;
+  lgl->stats->elm.ipos++;
+  assert (min < lglcntstk (&lgl->elm->m2i));
+  y = lglsmalltopvar (U, min);
+  z = lglsmalltopvar (L, min);
+  INCSTEPS (elm.steps);
+  x = (y < z) ? y : z;
+  assert (x < FUNVAR);
+  lglnegcofactorfun (U, x, U0); lglposcofactorfun (U, x, U1);
+  lglnegcofactorfun (L, x, L0); lglposcofactorfun (L, x, L1);
+  lglor3negfun (ftmp, U0, L1);
+  c0 = lglsmallipos (lgl, ftmp, L0, min+1);
+  lglor3negfun (ftmp, U1, L0);
+  c1 = lglsmallipos (lgl, ftmp, L1, min+1);
+  lglsmallevalcnf (lgl, c0, ftmp);
+  lglor3negfun (Unew, U0, ftmp);
+  lglsmallevalcnf (lgl, c1, ftmp);
+  lglandornegfun (Unew, U1, ftmp);
+  lglor3fun (ftmp, L0, L1);
+  cstar = lglsmallipos (lgl, Unew, ftmp, min+1);
+  assert (cstar != FALSECNF);
+  ctmp = lglsmalladdlit2cnf (lgl, c1, (1 << (2*x + 1)));
+  res = lglcnf2pos (ctmp);
+  ctmp = lglsmalladdlit2cnf (lgl, c0, (1 << (2*x)));
+  if (res == TRUECNF) res = lglcnf2pos (ctmp);
+  ctmp = lglsmalladdlit2cnf (lgl, cstar, 0);
+  if (res == TRUECNF) res = lglcnf2pos (ctmp);
+  res |= lglsize2cnf (lglcntstk (&lgl->elm->clv) - res);
+  return res;
+}
+
+static void lglsmallve (LGL * lgl, Cnf cnf) {
+  int * soc = lgl->elm->clv.start + lglcnf2pos (cnf);
+  int * eoc = soc + lglcnf2size (cnf);
+  int * p, cls, v, lit, trivial;
+  Val val;
+  for (p = soc; !lgl->mt && p < eoc; p++) {
+    cls = *p;
+    assert (lglmtstk (&lgl->clause));
+    trivial = 0;
+    for (v = 0; v < FUNVAR; v++) {
+      if (cls & (1 << (2*v + 1))) lit = -lglm2i (lgl, v+2);
+      else if (cls & (1 << (2*v))) lit = lglm2i (lgl, v+2);
+      else continue;
+      val = lglval (lgl, lit);
+      if (val < 0) continue;
+      if (val > 0) trivial = 1;
+      lglpushstk (lgl, &lgl->clause, lit);
+    }
+    if (!trivial) {
+      INCSTEPS (elm.resolutions);
+      lglpushstk (lgl, &lgl->clause, 0);
+      LOGCLS (3, lgl->clause.start, "small elimination resolvent");
+      if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+      lglpicosatchkcls (lgl);
+#endif
+      lgladdcls (lgl, 0, 0, 1);
+    }
+    lglclnstk (&lgl->clause);
+  }
+}
+
+static int lglsmallisunitcls (LGL * lgl, int cls) {
+  int fidx, fsign, flit, mlit, ilit;
+  ilit = 0;
+  for (fidx = 0; fidx < FUNVAR; fidx++)
+    for (fsign = 0; fsign <= 1; fsign++) {
+      flit = 1<<(2*fidx + fsign);
+      if (!(cls & flit)) continue;
+      if (ilit) return 0;
+      mlit = (fidx + 2) * (fsign ? -1 : 1);
+      ilit = lglm2i (lgl, mlit);
+    }
+  return ilit;
+}
+
+static int lglsmallcnfunits (LGL * lgl, Cnf cnf) {
+  int p, m, i, res, cls, ilit;
+  p = lglcnf2pos (cnf);
+  m = lglcnf2size (cnf);
+  res = 0;
+  for (i = 0; i < m; i++) {
+    cls = lglpeek (&lgl->elm->clv, p + i);
+    ilit = lglsmallisunitcls (lgl, cls);
+    if (!ilit) continue;
+    assert (lglval (lgl, ilit) >= 0);
+    lglunit (lgl, ilit);
+    res++;
+  }
+  return res;
+}
+
+static int lgltrysmallve (LGL * lgl, int idx) {
+  int res, new, old, units;
+  Fun pos, neg, fun;
+  EVar * ev;
+  Cnf cnf;
+  assert (lglmtstk (&lgl->elm->m2i));
+  assert (lglmtstk (&lgl->seen));
+  assert (lglmtstk (&lgl->elm->clv));
+  if (!lgl->opts->smallve.val) return 0;
+  if (lgl->opts->smallvewait.val && !lgl->elmrtc) return 0;
+  lglpushstk (lgl, &lgl->elm->m2i, 0);
+  lglpushstk (lgl, &lgl->elm->clv, 0);
+  res = 0;
+  if (lglinitsmallve (lgl, idx, pos) && lglinitsmallve (lgl, -idx, neg)) {
+    lglor3fun (fun, pos, neg);
+    cnf = lglsmallipos (lgl, fun, fun, 0);
+    new = lglcnf2size (cnf);
+    units = lglsmallcnfunits (lgl, cnf);
+    assert (units <= new);
+    new -= units;
+    ev = lglevar (lgl, idx);
+    old = ev->occ[0] + ev->occ[1];
+    LOG (2, "small elimination of %d replaces "
+           "%d old with %d new clauses and %d units",
+        idx, old, new, units);
+    lgl->stats->elm.small.tried++;
+    if (new <= old) {
+      LOG (2, "small elimination of %d removes %d clauses", idx, old - new);
+      lglepusheliminated (lgl, idx);
+      lglflushclauses (lgl, idx);
+      lglflushclauses (lgl, -idx);
+      lglsmallve (lgl, cnf);
+      lgl->stats->elm.small.elm++;
+      res = 1;
+    } else {
+      LOG (2, "small elimination of %d would add %d clauses", idx, new - old);
+      if (units > 0) res = 1;
+      else lgl->stats->elm.small.failed++;
+    }
+  } else LOG (2, "too many variables for small elimination");
+  lglresetsmallve (lgl);
+  return res;
+}
+
+static int lgl2manyoccs4elm (LGL * lgl, int lit) {
+  return lglocc (lgl, lit) > 
+           lglfactor (lgl, lgl->opts->elmocclim.val, lgl->stats->elm.count);
+}
+
+static int lglchkoccs4elmlit (LGL * lgl, int lit) {
+  int blit, tag, red, other, other2, lidx, size, lits, count;
+  const int * p, * w, * eow, * c, * l;
+  int64_t litslim;
+  HTS * hts;
+  if (lgl->opts->elmfull.val) return 1;
+  count = lgl->stats->elm.count;
+  litslim = lglfactor (lgl, lgl->opts->elmlitslim.val, count);
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  lits = 0;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (red || tag == LRGCS) continue;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      if (lgl2manyoccs4elm (lgl, other)) return 0;
+      lits += 2;
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      if (lgl2manyoccs4elm (lgl, other)) return 0;
+      other2 = *p;
+      if (lgl2manyoccs4elm (lgl, other2)) return 0;
+      lits += 3;
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, 0, lidx);
+      size = 0;
+      for (l = c; (other = *l); l++) {
+        if (lgl2manyoccs4elm (lgl, other)) return 0;
+        if (++size > lglfactor (lgl, lgl->opts->elmclslim.val, count))
+         return 0;
+      }
+      lits += size;
+    }
+    if (lits > litslim) return 0;
+  }
+  return 1;
+}
+
+static int lglchkoccs4elm (LGL * lgl, int idx) {
+  int res;
+  if ((res = lglforcedve (lgl, idx)) > 0) return 1;
+  if (res < 0) return 0;
+  if (lgl2manyoccs4elm (lgl, idx)) return 0;
+  if (lgl2manyoccs4elm (lgl, -idx)) return 0;
+  if (!lglchkoccs4elmlit (lgl, idx)) return 0;
+  if (!lglchkoccs4elmlit (lgl, -idx)) return 0;
+  return 1;
+}
+
+static void lglelimlit (LGL * lgl, int idx) {
+  int forced;
+  if (!lglisfree (lgl, idx)) return;
+  if (!lglchkoccs4elm (lgl, idx)) return;
+  LOG (2, "trying to eliminate %d", idx);
+  if ((forced = lglforcedve (lgl, idx)) < 0) return;
+  if (!forced && lgltrysmallve (lgl, idx)) return;
+  lglinitecls (lgl, idx);
+  lglelimlitaux (lgl, idx);
+  if (lgl->elm->pivot) lglrstecls (lgl);
+}
+
+static int lglblockcls (LGL * lgl, int lit) {
+  int blit, tag, red, other, other2, lidx, val, count, size;
+  const int * p, * w, * eow, * c, *l;
+  int bc = lgl->stats->blk.count;
+  HTS * hts;
+  INCSTEPS (blk.steps);
+  hts = lglhts (lgl, lit);
+  if (!hts->count) return 1;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  count = 0;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    count++;
+    lgl->stats->blk.res++;
+    INCSTEPS (blk.steps);
+    if (tag == BINCS || tag == TRNCS) {
+      other = blit >> RMSHFT;
+      val = lglmarked (lgl, other);
+      if (val < 0) continue;
+      if (tag == TRNCS) {
+       other2 = *p;
+       val = lglmarked (lgl, other2);
+       if (val < 0) continue;
+      }
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, 0, lidx);
+      size = 0;
+      for (l = c; (other = *l); l++) {
+       val = lglmarked (lgl, other);
+       if (++size > lglfactor (lgl, lgl->opts->blkclslim.val, bc)) return 0;
+       if (val < 0) break;
+      }
+      if (other) continue;
+    }
+    return 0;
+  }
+  LOG (3, "resolved %d trivial resolvents on %d", count, lit);
+  return 1;
+}
+
+static int lglpurelit (LGL * lgl, int lit) {
+  int res;
+  LOG(1, "pure literal %d", lit);
+  lgl->stats->blk.pure++;
+  assert (!lglocc (lgl, -lit));
+  res = lglflushclauses (lgl, lit);
+  lgl->stats->blk.clauses += res;
+  if (lgl->blocking) ADDSTEPS (blk.steps, res);
+  lglepusheliminated (lgl, lit);
+  return res;
+}
+
+static int lgl2manyoccs4blk (LGL * lgl, int lit) {
+  return lglhts (lgl, lit)->count >
+           lglfactor (lgl, lgl->opts->blkocclim.val, lgl->stats->blk.count);
+}
+
+static int lgldonotblocklit (LGL * lgl, int lit) {
+  int pocc = lglocc (lgl, lit);
+  int nocc = lglocc (lgl, -lit);
+  int count = lgl->stats->blk.count;
+  if (pocc >= lglfactor (lgl, lgl->opts->blkocclim1.val, count)) return 1;
+  if (nocc >= lglfactor (lgl, lgl->opts->blkocclim1.val, count)) return 1;
+  if (pocc < lglfactor (lgl, lgl->opts->blkocclim2.val, count)) return 0;
+  if (nocc < lglfactor (lgl, lgl->opts->blkocclim2.val, count)) return 0;
+  return 1;
+}
+
+static int lglblocklit (LGL * lgl, int lit, Stk * stk) {
+  int blit, tag, red, blocked, other, other2, lidx, count, size;
+  int bc = lgl->stats->blk.count;
+  int * p, * w, * eow, * c, * l;
+  HTS * hts;
+  if (lglval (lgl, lit)) return 0;
+  if (lgldonotblocklit (lgl, lit)) return 0;
+  if (lgl2manyoccs4blk (lgl, lit)) return 0;
+  hts = lglhts (lgl, lit);
+  assert (!lgl->opts->pure.val || hts->count > 0);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  count = 0;
+  assert (lglmtstk (stk+2) && lglmtstk (stk+3) && lglmtstk (stk+4));
+  for (p = w; p < eow; p++) {
+    if (INCSTEPS (blk.steps) >= lgl->limits->blk.steps) break;
+    if (lglterminate (lgl)) break;
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    assert (lglmtstk (&lgl->seen));
+    blocked = 0;
+    if (tag == BINCS || tag == TRNCS) {
+      if (!lgl->opts->blksmall.val) continue;
+      other = blit >> RMSHFT;
+      if (lgl2manyoccs4blk (lgl, other)) continue;
+      lglpushnmarkseen (lgl, other);
+      if (tag == TRNCS) {
+       other2 = *p;
+        if (lgl2manyoccs4blk (lgl, other2)) goto CONTINUE;
+       lglpushnmarkseen (lgl, other2);
+      }
+    } else {
+      assert (tag == OCCS);
+      if (!lgl->opts->blklarge.val) continue;
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, 0, lidx);
+      size = 0;
+      for (l = c; (other = *l); l++) {
+       if (other == lit) continue;
+        if (lgl2manyoccs4blk (lgl, other)) goto CONTINUE;
+       if (++size > lglfactor (lgl, lgl->opts->blkclslim.val, bc))
+         goto CONTINUE;
+       lglpushnmarkseen (lgl, other);
+      }
+    }
+    blocked = lglblockcls (lgl, -lit);
+CONTINUE:
+    lglpopnunmarkstk (lgl, &lgl->seen);
+    if (!blocked) continue;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      lglpushstk (lgl, stk+2, other);
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      lglpushstk (lgl, stk+3, other);
+      other2 = *p;
+      lglpushstk (lgl, stk+3, other2);
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      lglpushstk (lgl, stk+4, lidx);
+    }
+  }
+  while (!lglmtstk (stk+2)) {
+    if (INCSTEPS (blk.steps) >= lgl->limits->blk.steps) break;
+    count++;
+    other = lglpopstk (stk+2);
+    LOG (2, "blocked binary clause %d %d on %d", lit, other, lit);
+    lglrmbcls (lgl, lit, other, 0);
+    lglepush (lgl, lit);
+    lglepush (lgl, other);
+    lglepush (lgl, 0);
+    if (lgl->opts->move.val) lglmvbcls (lgl, lit, other);
+  }
+  while (!lglmtstk (stk+3)) {
+    if (INCSTEPS (blk.steps) >= lgl->limits->blk.steps) break;
+    count++;
+    other2 = lglpopstk (stk+3);
+    other = lglpopstk (stk+3);
+    LOG (2, "blocked ternary clause %d %d %d on %d", lit, other, other2, lit);
+    lglrmtcls (lgl, lit, other, other2, 0);
+    lglepush (lgl, lit);
+    lglepush (lgl, other);
+    lglepush (lgl, other2);
+    lglepush (lgl, 0);
+    if (lgl->opts->move.val >= 2) lglmvtcls (lgl, lit, other, other2);
+  }
+  while (!lglmtstk (stk+4)) {
+    if (INCSTEPS (blk.steps) >= lgl->limits->blk.steps) break;
+    lidx = lglpopstk (stk+4);
+    count++;
+    c = lglidx2lits (lgl, 0, lidx);
+    LOGCLS (2, c, "blocked on %d large clause", lit);
+    lglepush (lgl, lit);
+    for (l = c; (other = *l); l++)
+      if (other != lit) lglepush (lgl, other);
+    lglepush (lgl, 0);
+    lglrmvlcls (lgl, lidx);
+  }
+  LOG (2, "found %d blocked clauses with %d", count, lit);
+  lgl->stats->blk.clauses += count;
+  if (count > 0) lglblockinglit (lgl, lit);
+  lglclnstk (stk+2), lglclnstk (stk+3), lglclnstk (stk+4);
+  return count;
+}
+
+static void lglsetblklim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->blkrtc.val) {
+    lgl->limits->blk.steps = LLMAX;
+    lglprt (lgl, 1, "[block-%d] no limit", lgl->stats->blk.count);
+  } else {
+    limit = (lgl->opts->blkreleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->blkmineff.val) limit = lgl->opts->blkmineff.val;
+    if (lgl->opts->blkmaxeff.val >= 0 && limit > lgl->opts->blkmaxeff.val)
+      limit = lgl->opts->blkmaxeff.val;
+    if (lgl->stats->blk.count <= 1 &&
+        lgl->opts->boost.val &&
+       lgl->nvars < lgl->opts->blkboostvlim.val) {
+      lglprt (lgl, 1,
+        "[block-%d] boosting limit by %d",
+       lgl->stats->blk.count, lgl->opts->blkboost.val);
+      limit *= lgl->opts->blkboost.val;
+    }
+    limit >>= (pen = lgl->limits->blk.pen + lglszpen (lgl));
+    irrlim = lgl->stats->irr.clauses.cur/2;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1, 
+       "[block-%d] limit of %lld steps based on %d irredundant clauses",
+       lgl->stats->blk.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1, 
+       "[block-%d] limit of %lld steps penalty %d = %d + %d",
+       lgl->stats->blk.count, (LGLL) limit,
+       pen, lgl->limits->blk.pen, lglszpen (lgl));
+    lgl->limits->blk.steps = lgl->stats->blk.steps + limit;
+  }
+}
+
+static int lgleschedrem (LGL * lgl, int this_time) {
+  int idx, res = 0, count;
+  const char * str;
+  AVar * av;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglifrozen (lgl, idx)) continue;
+    if (!lglisfree (lgl, idx)) continue;
+    av = lglavar (lgl, idx);
+    if (lgl->eliminating && av->donotelm) continue;
+    if (lgl->blocking && av->donotblk) continue;
+    res++;
+  }
+  assert (lgl->eliminating || lgl->blocking);
+  if (lgl->eliminating) count = lgl->stats->elm.count, str = "elim";
+  else assert (lgl->blocking), count = lgl->stats->blk.count, str = "block";
+  if (res)
+    lglprt (lgl, 1,
+      "[%s-%d] %d variables %.0f%% %s time",
+      str, count,
+      res, lglpcnt (res, lglrem (lgl)),
+      this_time ? "will be scheduled this" : "remain to be tried next");
+  else {
+    lglprt (lgl, 1,
+      "[%s-%d] no untried remaining variables left",
+      str, count);
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      av = lglavar (lgl, idx);
+      if (lgl->eliminating) av->donotelm = 0;
+      if (lgl->blocking) av->donotblk = 0;
+    }
+  }
+  return res;
+}
+
+static void lglsetdonotesched (LGL * lgl, int completed) {
+  AVar * av;
+  EVar * ev;
+  int idx;
+  assert (lgl->eliminating + lgl->blocking == 1);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    av = lglavar (lgl, idx);
+    ev = lglevar (lgl, idx);
+    if (lgl->eliminating) {
+      if (completed) av->donotelm = 0;
+      else if (ev->pos < 0) av->donotelm = 1;
+    }
+    if (lgl->blocking) {
+      if (completed) av->donotblk = 0;
+      else if (ev->pos < 0) av->donotblk = 1;
+    }
+  }
+}
+
+static int lglblkdone (LGL * lgl) {
+  if (!lglsmallirr (lgl)) return 1;
+  if (lglterminate (lgl)) return 1;
+  if (lglmtstk (&lgl->esched)) return 1;
+  if (lgl->stats->blk.steps >= lgl->limits->blk.steps) return 1;
+  return 0;
+}
+
+static int lglispure (LGL * lgl, int lit) {
+  if (!lgl->opts->pure.val) return 0;
+  if (lglifrozen (lgl, lit)) return 0;
+  return !lglocc (lgl, -lit);
+}
+
+static void lglblock (LGL * lgl) {
+  int oldrem = lgl->blkrem, oldall = lgl->blkall;
+  int oldirr = lgl->stats->irr.clauses.cur;
+  int idx, count, all, rem, success;
+  Stk blocked[5];
+  assert (lglsmallirr (lgl));
+  assert (!lgl->simp);
+  assert (!lgl->dense);
+  assert (!lgl->eliminating);
+  assert (!lgl->blocking);
+  assert (!lgl->occs);
+  lglstart (lgl, &lgl->times->blk);
+  if (lgl->level) lglbacktrack (lgl, 0);
+  lgl->simp = lgl->blocking = lgl->occs = 1;
+  lgl->stats->blk.count++;
+  lglgc (lgl);
+  assert (lgl->frozen);
+  assert (!(oldall && !oldrem));
+  all = !oldrem || !oldall;
+  if (all)
+    lglprt (lgl, 1,
+      "[block-%d] scheduling all variables this time",
+      lgl->stats->blk.count);
+  else if (!lgleschedrem (lgl, 1)) all = 1, oldrem = 0;
+  if (!all) assert (!lgl->donotsched), lgl->donotsched = 1;
+  lgldense (lgl, 1);
+  if (!all) assert (lgl->donotsched), lgl->donotsched = 0;
+  lglsetblklim (lgl);
+  CLR (blocked);
+  count = 0;
+  while (!lglblkdone (lgl)) {
+    idx = lglpopesched (lgl);
+    lglavar (lgl, idx)->donotblk = 1;
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglispure (lgl, -idx)) count += lglpurelit (lgl, -idx);
+    else if (lglispure (lgl, idx)) count += lglpurelit (lgl, idx);
+    else {
+      if (lglocc (lgl, -idx) > lglocc (lgl, idx)) idx = -idx;
+      count += lglblocklit (lgl, idx, blocked);
+      count += lglblocklit (lgl, -idx, blocked);
+    }
+  }
+  rem = lglcntstk (&lgl->esched);
+  if (!rem) {
+    lglprt (lgl, 1,
+      "[block-%d] fully completed",
+      lgl->stats->blk.count);
+    lgl->blkrtc = 1;
+  } else {
+    lglprt (lgl, 1,
+      "[block-%d] incomplete %d not tried %.0f%%",
+      lgl->stats->blk.count, rem, lglpcnt (rem, lgl->nvars - 2));
+  }
+  lglsetdonotesched (lgl, !rem);
+  lglrelstk (lgl, &lgl->esched);
+  lglsparse (lgl);
+  lglgc (lgl);
+  lglrelstk (lgl, blocked+2);
+  lglrelstk (lgl, blocked+3);
+  lglrelstk (lgl, blocked+4);
+  lgl->blkrem = rem > 0;
+  lgl->blkall = all && lgl->blkrem;
+  lglprt (lgl, 1,
+    "[block-%d] transition to [ all %d rem %d ] state",
+    lgl->stats->blk.count, lgl->blkall, lgl->blkrem);
+  assert (lgl->simp && lgl->blocking && lgl->occs);
+  lgl->blocking = lgl->simp = lgl->occs = 0;
+  lgl->stats->irrprgss += count;
+  lglprt (lgl, 1,
+    "[block-%d] eliminated %d blocked clauses",
+    lgl->stats->blk.count, count);
+  if (oldirr < lgl->opts->blksuccesslim.val) success = count;
+  else if (count) {
+    success = (oldirr/lgl->opts->blksuccessrat.val <= count);
+    if (!success)
+      lglprt (lgl, 1,
+       "[block-%d] %d < 1/%d * %d = %d considered unsuccessful",
+       lgl->stats->blk.count, count, lgl->opts->blksuccessrat.val,
+       oldirr, oldirr/lgl->opts->blksuccessrat.val);
+  } else success = 0;
+  LGLUPDPEN (blk, success);
+  lgl->blkstuck = !rem && !count;
+  if (lgl->blkstuck)
+    lglprt (lgl, 2,
+      "[block-%d] completed but nothing eliminated thus stuck",
+      lgl->stats->blk.count);
+  lglrep (lgl, 2, 'k');
+  lglstop (lgl);
+  assert (!lgl->mt);
+}
+
+static void lglsetccelim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->ccertc.val) {
+    lgl->limits->cce.steps = LLMAX;
+    lglprt (lgl, 1, "[cce-%d] no limit", lgl->stats->cce.count);
+  } else {
+    limit = (lgl->opts->ccereleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->ccemineff.val) limit = lgl->opts->ccemineff.val;
+    if (lgl->opts->ccemaxeff.val >= 0 && limit > lgl->opts->ccemaxeff.val)
+      limit = lgl->opts->ccemaxeff.val;
+    if (lgl->stats->cce.count <= 1 &&
+        lgl->opts->boost.val &&
+       lgl->nvars < lgl->opts->cceboostvlim.val) {
+      lglprt (lgl, 1,
+        "[cce-%d] boosting limit by %d",
+       lgl->stats->cce.count, lgl->opts->cceboost.val);
+      limit *= lgl->opts->cceboost.val;
+    }
+    limit >>= (pen = lgl->limits->cce.pen + lglszpen (lgl));
+    irrlim = lgl->stats->irr.clauses.cur/2;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1,
+       "[cce-%d] limit of %lld steps based on %d irredundant clauses",
+       lgl->stats->cce.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1,
+       "[cce-%d] limit of %lld steps penalty %d = %d + %d",
+       lgl->stats->cce.count, (LGLL) limit,
+       pen, lgl->limits->cce.pen, lglszpen (lgl));
+    lgl->limits->cce.steps = lgl->stats->cce.steps + limit;
+  }
+}
+
+#define CCELOGLEVEL 2
+
+static void lglsignedmark2 (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (2 + (lit < 0));
+  if (av->mark & bit) return;
+  av->mark |= bit;
+}
+
+static void lglsignedunmark2 (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (2 + (lit < 0));
+  if (!(av->mark & bit)) return;
+  av->mark &= ~bit;
+}
+
+static int lglsignedmarked2 (LGL * lgl, int lit) {
+  AVar * av = lglavar (lgl, lit);
+  int bit = 1 << (2 + (lit < 0));
+  return av->mark & bit;
+}
+
+static int lglabcecls (LGL * lgl, int lit, const int * c) {
+  int other, found = 0;
+  const int * p;
+  for (p = c; (other = *p); p++)
+    if (other == -lit) found++;
+    else if (lglsignedmarked (lgl, -other)) return 1;
+  assert (found == 1);
+  return 0;
+}
+
+static int lglabce (LGL * lgl, int lit) {
+  const int * p, * w, * eow, * c;
+  int blit, tag, other, cls[4];
+  HTS * hts;
+  assert (!lglifrozen (lgl, lit));
+  hts = lglhts (lgl, -lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  cls[0] = -lit, cls[3] = 0;
+  for (p = w; p < eow; p++) {
+    if (lgl->limits->cce.steps <= INCSTEPS (cce.steps)) return 0;
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (blit & REDCS) continue;
+    if (tag == LRGCS) continue;
+    other = blit >> RMSHFT;
+    cls[1] = other;
+    if (tag == BINCS) cls[2] = 0, c = cls;
+    else if (tag == TRNCS) cls[2] = *p, c = cls;
+    else assert (tag == OCCS), c = lglidx2lits (lgl, 0, other);
+    if (!lglabcecls (lgl, lit, c)) return 0;
+  }
+  return 1;
+}
+
+static int lglcceclause (LGL * lgl,
+                         const int * c, 
+                        int igntag,
+                        int cce) {
+  int other, res, nextala, nextcla, lit, blit, tag, other2, i, j, n;
+  const int * p, * eow, * w, * d, * q;
+  int unit, first, old, prev;
+  HTS * hts;
+  int * r;
+  LOGCLS (CCELOGLEVEL, c, "trying CCE on clause");
+  assert (lglmtstk (&lgl->cce->extend));
+  assert (lglmtstk (&lgl->cce->cla));
+  assert (lglmtstk (&lgl->seen));
+  for (p = c; (other = *p); p++) {
+    assert (!lglmarked (lgl, other));
+    lglpushstk (lgl, &lgl->seen, other);
+    lglpushstk (lgl, &lgl->cce->cla, other);
+    lglsignedmark (lgl, other);
+  }
+  n = lglcntstk (&lgl->seen);
+  for (i = n-1; i > 0; i--) {
+    j = lglrand (lgl) % (i + 1);
+    if (j == i) continue;
+    SWAP (int, lgl->seen.start[i], lgl->seen.start[j]);
+    SWAP (int, lgl->cce->cla.start[i], lgl->cce->cla.start[j]);
+  }
+  nextcla = nextala = res = 0;
+ALA:
+  while (!res && nextala < lglcntstk (&lgl->seen)) {
+    lit = lglpeek (&lgl->seen, nextala++);
+    assert (lglsignedmarked (lgl, lit));
+    assert (!lglsignedmarked (lgl, -lit));
+    hts = lglhts (lgl, lit);
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    for (p = w; !res && p < eow; p++) {
+      if (lgl->limits->cce.steps <= INCSTEPS (cce.steps)) goto DONE;
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      if (tag == LRGCS) continue;
+      if (blit & REDCS) continue;
+      other = blit >> RMSHFT;
+      if (tag == BINCS) {
+       if (lglsignedmarked (lgl, -other)) continue;
+       else if (lglsignedmarked (lgl, other)) {
+         if (igntag == BINCS) {
+           if (c[0] == lit && c[1] == other) continue;
+           if (c[1] == lit && c[0] == other) continue;
+         }
+         LOG (CCELOGLEVEL, 
+              "ALA on binary clause %d %d results in ATE", lit, other);
+         res = 1;
+       } else {
+         assert (!lglmarked (lgl, other));
+         LOG (CCELOGLEVEL, "ALA %d through binary clause %d %d", 
+              -other, lit, other);
+         lglsignedmark (lgl, -other);
+         lglpushstk (lgl, &lgl->seen, -other);
+       }
+      } else if (tag == TRNCS) {
+       if (lglsignedmarked (lgl, -other)) continue;
+       other2 = *p;
+       if (lglsignedmarked (lgl, -other2)) continue;
+       if (lglsignedmarked (lgl, other)) {
+         if (lglsignedmarked (lgl, other2)) {
+           if (igntag == TRNCS) {
+             if (c[0] == lit && c[1] == other && c[2] == other2) continue;
+             if (c[0] == lit && c[2] == other && c[1] == other2) continue;
+             if (c[1] == lit && c[0] == other && c[2] == other2) continue;
+             if (c[1] == lit && c[2] == other && c[0] == other2) continue;
+             if (c[2] == lit && c[0] == other && c[1] == other2) continue;
+             if (c[2] == lit && c[1] == other && c[0] == other2) continue;
+           }
+           LOG (CCELOGLEVEL,
+             "ALA on ternary clause %d %d %d results in ATE",
+             lit, other, other2);
+           res = 1;
+         } else {
+           assert (!lglmarked (lgl, other2));
+           LOG (CCELOGLEVEL, 
+                "ALA %d through ternary clause %d %d %d (1st case)",
+                -other2, lit, other, other2);
+           lglsignedmark (lgl, -other2);
+           lglpushstk (lgl, &lgl->seen, -other2);
+         }
+       } else if (lglsignedmarked (lgl, other2)) {
+         assert (!lglmarked (lgl, other));
+         LOG (CCELOGLEVEL, 
+             "ALA %d through ternary clause %d %d %d (2nd case)",
+             -other, lit, other, other2);
+         lglsignedmark (lgl, -other);
+         lglpushstk (lgl, &lgl->seen, -other);
+       }
+      } else {
+       assert (tag == OCCS);
+       d = lglidx2lits (lgl, 0, other);
+       if (d == c) { assert (igntag == OCCS); continue; }
+       unit = 0;
+       for (q = d; (other = *q); q++) {
+         if (other == lit) continue;
+         if (lglsignedmarked (lgl, -other)) break;
+         if (lglsignedmarked (lgl, other)) continue;
+         if (unit) break;
+         unit = -other;
+       }
+       if (other) continue;
+       if (!unit) {
+         LOGCLS (CCELOGLEVEL, d, "ATE after ALA on large clause");
+         res = 1;
+       } else {
+         assert (!lglmarked (lgl, unit));
+         LOGCLS (CCELOGLEVEL, d, "ALA %d through large clause", unit);
+         lglsignedmark (lgl, unit);
+         lglpushstk (lgl, &lgl->seen, unit);
+       }
+      }
+    }
+  }
+  if (res || !lgl->opts->block.val || cce < 3) goto SKIPCLA;
+  while (!res && nextcla < lglcntstk (&lgl->cce->cla)) {
+    lit = lglpeek (&lgl->cce->cla, nextcla++);
+    if (lglifrozen (lgl, lit)) continue;
+    assert (lglsignedmarked (lgl, lit));
+    assert (!lglsignedmarked (lgl, -lit));
+    hts = lglhts (lgl, -lit);
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    old = lglcntstk (&lgl->cce->cla);
+    first = 1;
+    for (p = w; p < eow; p++) {
+      if (lgl->limits->cce.steps <= INCSTEPS (cce.steps)) goto DONE;
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      if (tag == LRGCS) continue;
+      if (blit & REDCS) continue;
+      other = blit >> RMSHFT;
+      if (first) {
+       if (tag == BINCS) {
+         if (lglsignedmarked (lgl, -other)) continue;
+         if (!lglsignedmarked (lgl, other))
+           lglpushstk (lgl, &lgl->cce->cla, other);
+       } else if (tag == TRNCS) {
+         if (lglsignedmarked (lgl, -other)) continue;
+         if (lglsignedmarked (lgl, -*p)) continue;
+         if (!lglsignedmarked (lgl, other))
+           lglpushstk (lgl, &lgl->cce->cla, other);
+         if (!lglsignedmarked (lgl, *p))
+           lglpushstk (lgl, &lgl->cce->cla, *p);
+       } else { 
+         assert (tag == OCCS);
+         d = lglidx2lits (lgl, 0, other);
+         assert (d != c);
+         for (q = d; (other = *q); q++)
+           if (other != -lit && lglsignedmarked (lgl, -other)) break;
+         if (other) continue;
+         for (q = d; (other = *q); q++)
+           if (other != -lit && !lglsignedmarked (lgl, other))
+             lglpushstk (lgl, &lgl->cce->cla, other);
+       }
+       first = 0;
+      } else {
+       r = lgl->cce->cla.start + old;
+       if (tag == BINCS) {
+         if (lglsignedmarked (lgl, -other)) continue;
+         for (q = r; q < lgl->cce->cla.top; q++)
+           if (*q == other) *r++ = *q;
+       } else if (tag == TRNCS) {
+         if (lglsignedmarked (lgl, -other)) continue;
+         if (lglsignedmarked (lgl, -(other2 = *p))) continue;
+         for (q = r; q < lgl->cce->cla.top; q++)
+           if (*q == other || *q == other2) *r++ = *q;
+       } else {
+         assert (tag == OCCS);
+         d = lglidx2lits (lgl, 0, other);
+         assert (d != c);
+         for (q = d; (other = *q); q++)
+           if (other != -lit && lglsignedmarked (lgl, -other)) break;
+         if (other) continue;
+         for (q = d; (other = *q); q++) {
+           if (other == -lit) continue;
+           assert (other != lit);
+           assert (!lglsignedmarked2 (lgl, other));
+           assert (!lglsignedmarked2 (lgl, -other));
+           lglsignedmark2 (lgl, other);
+         }
+         for (q = r; q < lgl->cce->cla.top; q++)
+           if (lglsignedmarked2 (lgl, (other = *q)))
+             *r++ = other;
+         for (q = d; (other = *q); q++) {
+           if (other == -lit) continue;
+           assert (other != lit);
+           assert (lglsignedmarked2 (lgl, other));
+           lglsignedunmark2 (lgl, other);
+         }
+       }
+       if ((lgl->cce->cla.top = r) == lgl->cce->cla.start + old) break;
+      }
+    } 
+    if (lglcntstk (&lgl->cce->cla) > old) {
+      nextcla = 0;
+      lglpushstk (lgl, &lgl->cce->extend, lit);
+      for (q = lgl->cce->cla.start; q < lgl->cce->cla.start + old; q++)
+       if (*q != lit) lglpushstk (lgl, &lgl->cce->extend, *q);
+      lglpushstk (lgl, &lgl->cce->extend, 0);
+    }
+    for (q = lgl->cce->cla.start + old; !res && q < lgl->cce->cla.top; q++) {
+      if (lglsignedmarked (lgl, -*q)) {
+       LOG (CCELOGLEVEL, "CLA on %d results in ATE", *q);
+       res = 1;
+      } else {
+       LOG (CCELOGLEVEL, "CLA %d on %d", *q, lit);
+       lglpushstk (lgl, &lgl->seen, *q);
+       lglsignedmark (lgl, *q);
+      }
+    }
+    if (!res && p == eow && nextala < lglcntstk (&lgl->seen)) goto ALA;
+  }
+SKIPCLA:
+  if (res) {
+    LOGCLS (CCELOGLEVEL, c, "ATE clause");
+    lgl->stats->cce.ate++;
+  } else if (lgl->opts->block.val && cce >= 2) {
+   for (p = lgl->cce->cla.start; p < lgl->cce->cla.top; p++)
+     if (!lglifrozen (lgl, (other = *p)) && (res = lglabce (lgl, other))) 
+       break;
+    if (res) {
+      LOGCLS (CCELOGLEVEL, c, "ABCE on %d clause", other);
+      lglpushstk (lgl, &lgl->cce->extend, other);
+      for (p = lgl->cce->cla.start; p < lgl->cce->cla.top; p++)
+        if (*p != other) lglpushstk (lgl, &lgl->cce->extend, *p);
+      lglpushstk (lgl, &lgl->cce->extend, 0);
+      lgl->stats->cce.abce++;
+    }
+  }
+  if (res) lgl->stats->cce.eliminated++;
+DONE:
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  lglclnstk (&lgl->cce->cla);
+  if (res && !lglmtstk (&lgl->cce->extend)) {
+    assert (cce >= 2);
+    assert (lgl->opts->block.val);
+    prev = 0;
+    for (p = lgl->cce->extend.start; p < lgl->cce->extend.top; p++) {
+      lit = *p;
+      lglepush (lgl, lit);
+      if (!prev) assert (!lglifrozen (lgl, lit)), lglblockinglit (lgl, lit);
+      prev = lit;
+    }
+  }
+  lglclnstk (&lgl->cce->extend);
+  return res;
+}
+
+static const char * lglcce2str (int cce) {
+  assert (0 <= cce), assert (cce <= 3);
+  if (cce == 3) return "ACCE";
+  else if (cce == 2) return "ABCE";
+  else if (cce == 1) return "ATE";
+  else return "none";
+}
+
+static int lglccesmallclauses (LGL * lgl, int lit) {
+  int idx = abs (lit), blit, tag, red, other, other2;
+  HTS * hts = lglhts (lgl, lit);
+  const int * p, * w, * eow;
+  CCE * cce = lgl->cce;
+  Stk * clauses;
+  assert (cce);
+  if (!lglisfree (lgl, lit)) return 1;
+  clauses = &cce->clauses;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  INCSTEPS (cce.steps);
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == OCCS) continue;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    other = blit >> RMSHFT;
+    if (abs (other) < idx) continue;
+    if (!lglisfree (lgl, other)) continue;
+    if (tag == TRNCS) {
+      other2 = *p;
+      if (abs (other2) < idx) continue;
+      if (abs (other2) < abs (other)) continue;
+      if (!lglisfree (lgl, other2)) continue;
+      lglpushstk (lgl, clauses, other2);
+      cce->trn++;
+    } else {
+      assert (tag == BINCS);
+      cce->bin++;
+    }
+    lglpushstk (lgl, clauses, other);
+    lglpushstk (lgl, clauses, lit);
+    lglpushstk (lgl, clauses, 0);
+  }
+  return 1;
+}
+
+static void lglccesmall (LGL * lgl, int cce) {
+  int count, valid, invalid, tried, eliminated, elim2, elim3;
+  int size, lit, tag;
+  const int * p, * c;
+  Stk * clauses;
+  assert (lgl->cce);
+  clauses = &lgl->cce->clauses;
+  assert (!lgl->cce->clauses.start);
+  lglrandlitrav (lgl, lglccesmallclauses);
+  lglfitstk (lgl, &lgl->cce->clauses);
+  count = lgl->cce->bin + lgl->cce->trn;
+  lglprt (lgl, 1,
+    "[cce-%d] scheduling %d clauses = %d binary + %d ternary",
+    lgl->stats->cce.count, count, lgl->cce->bin, lgl->cce->trn);
+  tried = eliminated = invalid = elim2 = elim3 = 0;
+  for (c = clauses->start; c < clauses->top; c = p + 1) {
+    if (lgl->mt) break;
+    if (lglterminate (lgl)) break;
+    if (lgl->limits->cce.steps <= lgl->stats->cce.steps) break;
+    valid = 1;
+    for (p = c; (lit = *p); p++)
+      if (!lglisfree (lgl, lit))
+       valid = 0;
+    if (valid) {
+      tried++;
+      size = p - c;
+      assert (2 <= size), assert (size <= 3);
+      tag = size == 2 ? BINCS : TRNCS;
+      if (!lglcceclause (lgl, c, tag, cce)) continue;
+      eliminated++;
+      if (size == 2) {
+        lglrmvbcls (lgl, c[0], c[1]);
+       elim2++;
+      } else {
+       assert (size == 3);
+        lglrmvtcls (lgl, c[0], c[1], c[2]);
+       elim3++;
+      }
+    } else invalid++;
+  }
+  assert (count >= tried + invalid);
+  lglrelstk (lgl, &lgl->cce->clauses);
+  if (tried)
+    lglprt (lgl, 1,
+      "[cce-%d] tried to eliminate %d small clauses %.0f%%",
+      lgl->stats->cce.count, tried, lglpcnt (tried, count));
+  if (eliminated)
+    lglprt (lgl, 1,
+      "[cce-%d] eliminated %d small clauses %.0f%%",
+      lgl->stats->cce.count, eliminated, lglpcnt (eliminated, count));
+  if (elim2)
+    lglprt (lgl, 1,
+      "[cce-%d] eliminated %d binary clauses %.0f%%",
+      lgl->stats->cce.count, elim2, lglpcnt (elim2, lgl->cce->bin));
+  if (elim3)
+    lglprt (lgl, 1,
+      "[cce-%d] eliminated %d ternary clauses %.0f%%",
+      lgl->stats->cce.count, elim3, lglpcnt (elim3, lgl->cce->trn));
+}
+
+static int lglcce (LGL * lgl) {
+  int oldvars = lgl->nvars, cce, lenlim, startirr, success;
+  int oldirr, eliminated, total, idx, round;
+  int completedsmall, completedlarge;
+  int64_t oldsteps, deltasteps;
+  int elmlarge, elmsmall;
+  lglstart (lgl, &lgl->times->cce);
+  lgl->stats->cce.count++;
+  lglsetccelim (lgl);
+#if 0
+  if (lglprogressincelastcce (lgl)) {
+    lglprt (lgl, 2,
+      "[cce-%d] there was progress since last CCE so focusing on ATE first",
+      lgl->stats->cce.count);
+    lgl->ccertc = 0;           // TODO keep this?
+  } else {
+    lglprt (lgl, 2,
+      "[cce-%d] no progress since last CCE so keeping ccertc=%s",
+      lgl->stats->cce.count, lglcce2str (lgl->ccertc));
+  }
+#endif
+  round = total = 0;
+  lenlim = INT_MAX;
+  startirr = lgl->stats->irr.clauses.cur;
+RESTART:
+  round++;
+  cce = lgl->opts->cce.val;
+  if (cce == 3 && lgl->ccertc < 2 &&
+      lgl->opts->cce3wait.val >= lgl->stats->cce.count) {
+    lglprt (lgl, 2,
+      "[cce-%d-%d] restricted to ABCE since ccertc=%s",
+      lgl->stats->cce.count, round, lglcce2str (lgl->ccertc));
+    cce = 2;
+  }
+  if (cce == 2 && lgl->ccertc < 1 &&
+      lgl->opts->cce2wait.val >= lgl->stats->cce.count) {
+    lglprt (lgl, 2,
+      "[cce-%d-%d] restricted to ATE since ccertc=%s",
+      lgl->stats->cce.count, round, lglcce2str (lgl->ccertc));
+   cce = 1;
+  }
+  oldirr = lgl->stats->irr.clauses.cur;
+  lglprt (lgl, 2, "[cce-%d-%d] starting round %d (%s)",
+          lgl->stats->cce.count, round, round, lglcce2str (cce));
+  assert (!lgl->simp && !lgl->cceing && !lgl->occs);
+  lgl->cceing = lgl->simp = 1;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  NEW (lgl->cce, 1);
+  NEW (lgl->cce->rem, oldvars);
+  for (idx = 2; idx < oldvars; idx++) lgl->cce->rem[idx] = INT_MAX;
+  lglgc (lgl);
+  assert (lgl->frozen);
+  lgldense (lgl, 1);
+  oldsteps = lgl->stats->cce.steps;
+  elmlarge = 0;
+  while (!lgl->mt && 
+         lenlim > 4 &&
+        !lglterminate (lgl) &&
+        lgl->limits->cce.steps > lgl->stats->cce.steps) {
+    int maxlen = 0, count;
+    const int * p, * c;
+    Stk lidcs;
+    CLR (lidcs);
+    for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+      int len, lidx;
+      if (*(p = c) >= NOTALIT) continue;
+      while (*p) p++;
+      len = p - c;
+      if (len >= lenlim) continue;
+      if (len < maxlen) continue;
+      if (len > maxlen) {
+       lglclnstk (&lidcs);
+       maxlen = len;
+      }
+      lidx = c - lgl->irr.start;
+      lglpushstk (lgl, &lidcs, lidx);
+    }
+    ADDSTEPS (cce.steps, lglcntstk (&lgl->irr)/128);
+    count = lglcntstk (&lidcs);
+    lglprt (lgl, 2,
+      "[cce-%d-%d] scheduling %d clauses of length %d",
+      lgl->stats->cce.count, round, count, maxlen);
+    eliminated = 0;
+    for (p = lidcs.start;
+         p < lidcs.top &&
+        !lgl->mt &&
+        !lglterminate (lgl) &&
+        lgl->limits->cce.steps > lgl->stats->cce.steps; 
+        p++) {
+      int lidx = *p;
+      c = lgl->irr.start + lidx;
+      if (*c >= NOTALIT) continue;
+      if (!lglcceclause (lgl, c, OCCS, cce)) continue;
+      lglrmvlcls (lgl, lidx);
+      eliminated++;
+    }
+    elmlarge += eliminated;
+    lglrelstk (lgl, &lidcs);
+    lenlim = maxlen;
+    lglprt (lgl, 1 + !eliminated,
+      "[cce-%d-%d] eliminated %d clauses out of %d (%.0f%%) of length %d",
+      lgl->stats->cce.count, round,
+      eliminated, count, lglpcnt (eliminated, count), maxlen);
+  }
+  completedlarge = (lgl->limits->cce.steps > lgl->stats->cce.steps);
+  if (completedlarge)
+    lglprt (lgl, 1,
+      "[cce-%d-%d] completed large round (%s)",
+      lgl->stats->cce.count, round, lglcce2str (cce));
+  else
+    lglprt (lgl, 1, 
+      "[cce-%d-%d] incomplete large round (%s)",
+      lgl->stats->cce.count, round, lglcce2str (cce));
+  deltasteps = lgl->stats->cce.steps - oldsteps;
+  lglprt (lgl, 1 + !elmlarge,
+    "[cce-%d-%d] eliminated %d large clauses in %lld steps",
+    lgl->stats->cce.count, round, elmlarge, (LGLL) deltasteps);
+  deltasteps /= 2;
+  if (LLMAX - deltasteps > lgl->limits->cce.steps) {
+    lgl->limits->cce.steps += deltasteps;
+    lglprt (lgl, 1,
+      "[cce-%d-%d] allowing another %lld steps for small clauses",
+      lgl->stats->cce.count, round, deltasteps);
+  } else {
+    lgl->limits->cce.steps = LLMAX;
+    lglprt (lgl, 1,
+      "[cce-%d-%d] unlimited number of steps for small clauses",
+      lgl->stats->cce.count, round);
+  }
+  lglccesmall (lgl, cce);
+  elmsmall = oldirr - lgl->stats->irr.clauses.cur - elmlarge;
+  lglprt (lgl, 1 + !elmsmall,
+    "[cce-%d-%d] eliminated %d small clauses in %lld steps",
+    lgl->stats->cce.count, round, elmsmall,
+    (LGLL) lgl->stats->cce.steps - oldsteps - deltasteps);
+  completedsmall = (lgl->limits->cce.steps > lgl->stats->cce.steps);
+  COVER (!completedsmall && lgl->opts->ccertc.val);
+  if (completedsmall)
+    lglprt (lgl, 1,
+      "[cce-%d-%d] completed small round (%s)",
+      lgl->stats->cce.count, round, lglcce2str (cce));
+  else
+    lglprt (lgl, 1, 
+      "[cce-%d-%d] incomplete small round (%s)",
+      lgl->stats->cce.count, round, lglcce2str (cce));
+  if (completedsmall && completedlarge) {
+    if (lgl->ccertc < cce) {
+      lgl->ccertc = cce;
+      lglprt (lgl, 1, 
+       "[cce-%d-%d] completed small and large (%s)",
+       lgl->stats->cce.count, round, lglcce2str (cce));
+    }
+  }
+  lglsparse (lgl);
+  lglgc (lgl);
+  lglrelstk (lgl, &lgl->cce->extend);
+  lglrelstk (lgl, &lgl->cce->cla);
+  DEL (lgl->cce->rem, oldvars);
+  DEL (lgl->cce, 1);
+  assert (oldirr >= lgl->stats->irr.clauses.cur);
+  eliminated = oldirr - lgl->stats->irr.clauses.cur;
+  total += eliminated;
+  lglprt (lgl, 1,
+    "[cce-%d-%d] eliminated %d covered clauses in round %d",
+    lgl->stats->cce.count, round, eliminated, round);
+  assert (lgl->simp && lgl->cceing);
+  lgl->cceing = lgl->simp = 0;
+  if (!lgl->mt &&
+      eliminated &&
+      !lglterminate (lgl) &&
+      lgl->limits->cce.steps > lgl->stats->cce.steps) goto RESTART;
+  lglprt (lgl, 1,
+    "[cce-%d] eliminated %d covered clauses in TOTAL during %d rounds",
+    lgl->stats->cce.count, total, round);
+  if (startirr < lgl->opts->ccesuccesslim.val) success = total;
+  else if (total) {
+    success = (startirr/lgl->opts->ccesuccessrat.val <= total);
+    if (!success)
+      lglprt (lgl, 1,
+       "[cce-%d] %d < 1/%d * %d = %d considered unsuccessful",
+       lgl->stats->cce.count, total, lgl->opts->ccesuccessrat.val,
+       startirr, startirr/lgl->opts->ccesuccessrat.val);
+  } else success = 0;
+  LGLUPDPEN (cce, success);
+  lglrep (lgl, 2, 'E');
+  lglstop (lgl);
+  lglbasicatestats (lgl);
+  return !lgl->mt;
+}
+
+static void lglcliffclause (LGL * lgl, const int * c) {
+  int lit, start, i, first, dom, other, * r;
+  const int * p, * q;
+  for (p = c; (lit = *p);  p++) if (lglval (lgl, lit) > 0) return;
+  LOGCLS (2, c, "cliffing clause");
+  assert (lgl->cliff);
+  assert (lglmtstk (&lgl->cliff->lift));
+  assert (!lgl->level);
+  assert (!lgl->mt);
+  start = lglcntstk (&lgl->trail);
+  first = 1;
+  for (p = c; (lit = *p); p++) {
+    if (lglval (lgl, lit) < 0) continue;
+    lgl->stats->cliff.decisions++;
+    lgliassume (lgl, lit);
+    if (!lglbcp (lgl)) {
+      LOG (1, "cliffing failed literal %d", lit);
+      dom = lglprbana (lgl, lit);
+      lglbacktrack (lgl, 0);
+      lgl->stats->cliff.failed++;
+      lglunit (lgl, -dom);
+      if (!lglbcp (lgl)) {
+       LOG (1, "empty clause after propagating %d", -dom);
+       lgl->mt = 1;
+      }
+      goto DONE;
+    } 
+    if (first) {
+      for (i = start; i < lglcntstk (&lgl->trail); i++) {
+       other = lglpeek (&lgl->trail, i);
+       lglpushstk (lgl, &lgl->cliff->lift, other);
+      }
+      first = 0;
+    } else {
+      r = lgl->cliff->lift.start;
+      for (q = r; q < lgl->cliff->lift.top; q++)
+       if (lglval (lgl, (other = *q)) > 0)
+         *r++ = other;
+      lgl->cliff->lift.top = r;
+    }
+    lglbacktrack (lgl, 0);
+    if (lglmtstk (&lgl->cliff->lift)) return;
+  }
+  while (!lglmtstk (&lgl->cliff->lift)) {
+    lit = lglpopstk (&lgl->cliff->lift);
+    LOG (1, "cliffing lifted unit %d", lit);
+    lgl->stats->cliff.lifted++;
+    if (lglval (lgl, lit) > 0) continue;
+    if (lglval (lgl, lit) < 0) {
+      LOG (1, "inconsistent lifted unit %d", lit);
+      lgl->mt = 1;
+      goto DONE;
+    }
+    lglunit (lgl, lit);
+    if (!lglbcp (lgl)) {
+      LOG (1, "empty clause after propagating lifted unit %d", lit);
+      lgl->mt = 1;
+      goto DONE;
+    }
+  }
+DONE:
+  lglclnstk (&lgl->cliff->lift);
+}
+
+static int lglcliffclauses (LGL * lgl, Stk * stk) {
+  const int * c, * p;
+  for (c = stk->start; c < stk->top; c = p + 1) {
+    if (*(p = c) >= NOTALIT) continue;
+    if (INCSTEPS (cliff.steps) >= lgl->limits->cliff.steps) return 0;
+    if (lglterminate (lgl)) return 0;
+    lglcliffclause (lgl, c);
+    if (lgl->mt) return 0;
+    for (p = c; *p; p++)
+      ;
+  }
+  return 1;
+}
+
+static int lglclifflitrn (LGL * lgl, int lit) {
+  const int * w, * eow, * p;
+  int res, blit, tag, other, other2;
+  HTS * hts;
+  assert (lglmtstk (&lgl->cliff->lits));
+  if (!lglisfree (lgl, lit)) return 1;
+  if (INCSTEPS (cliff.steps) >= lgl->limits->cliff.steps) return 0;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == BINCS) continue;
+    if (tag == LRGCS) continue;
+    assert (tag == TRNCS);
+    other = blit >> RMSHFT;
+    if (abs (other) < abs (lit)) continue;
+    other2 = *p;
+    if (abs (other2) < abs (lit)) continue;
+    lglpushstk (lgl, &lgl->cliff->lits, lit);
+    lglpushstk (lgl, &lgl->cliff->lits, other);
+    lglpushstk (lgl, &lgl->cliff->lits, other2);
+    lglpushstk (lgl, &lgl->cliff->lits, 0);
+  }
+  res = lglcliffclauses (lgl, &lgl->cliff->lits);
+  lglclnstk (&lgl->cliff->lits);
+  return res && !lgl->mt;
+}
+
+static int lglcliffred (LGL * lgl) {
+  int glue;
+  for (glue = 0; glue < MAXGLUE; glue++)
+    if (!lglcliffclauses (lgl, &lgl->red[glue]))
+      return 0;
+  return 1;
+}
+
+static void lglsetclifflim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->cliffreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->cliffmineff.val) limit = lgl->opts->cliffmineff.val;
+  if (lgl->opts->cliffmaxeff.val >= 0 && limit > lgl->opts->cliffmaxeff.val)
+    limit = lgl->opts->cliffmaxeff.val;
+  limit >>= (pen = lgl->limits->cliff.pen + lglszpen (lgl));
+  irrlim = 2*lgl->stats->irr.clauses.cur;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[cliff-%d] limit of %lld steps based on %d irredundant clauses",
+      lgl->stats->cliff.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[cliff-%d] limit of %lld steps penalty %d = %d + %d",
+           lgl->stats->cliff.count, (LGLL) limit,
+           pen, lgl->limits->cliff.pen, lglszpen (lgl));
+  lgl->limits->cliff.steps = lgl->stats->cliff.steps + limit;
+}
+
+static int lglcliff (LGL * lgl) {
+  int lifted, failed, oldlifted, oldfailed, success;
+  lglstart (lgl, &lgl->times->cliff);
+  lgl->stats->cliff.count++;
+  assert (!lgl->simp && !lgl->cliffing);
+  lgl->simp = lgl->cliffing = 1;
+  assert (!lgl->cliff);
+  NEW (lgl->cliff, 1);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  oldlifted = lgl->stats->cliff.lifted;
+  oldfailed = lgl->stats->cliff.failed;
+  lglsetclifflim (lgl);
+  if (lglcliffclauses (lgl, &lgl->irr))
+    if (lglrandlitrav (lgl, lglclifflitrn))
+      (void) lglcliffred (lgl);
+  lifted = lgl->stats->cliff.lifted - oldlifted;
+  failed = lgl->stats->cliff.failed - oldfailed;
+  lglprt (lgl, 1, "[cliff-%d] failed %d, lifted %d",
+          lgl->stats->cliff.count, failed, lifted);
+  assert (lgl->simp && lgl->cliffing);
+  lgl->simp = lgl->cliffing = 0;
+  lglrelstk (lgl, &lgl->cliff->lift);
+  lglrelstk (lgl, &lgl->cliff->lits);
+  DEL (lgl->cliff, 1);
+  success = failed || lifted;
+  LGLUPDPEN (cliff, success);
+  lglrep (lgl, 2, 'K');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static void lglsetelmlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->elmrtc.val) {
+    lgl->limits->elm.steps = LLMAX;
+    lglprt (lgl, 1, "[elim-%d] no limit", lgl->stats->elm.count);
+  } else {
+    limit = (lgl->opts->elmreleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->elmineff.val) limit = lgl->opts->elmineff.val;
+    if (lgl->opts->elmaxeff.val >= 0 && limit > lgl->opts->elmaxeff.val)
+      limit = lgl->opts->elmaxeff.val;
+    if (lgl->stats->elm.count <= 1 &&
+        lgl->opts->boost.val &&
+        lgl->opts->elmboost.val > 1) {
+      lglprt (lgl, 1,
+        "[elim-%d] boosting limit by %d",
+       lgl->stats->elm.count, lgl->opts->elmboost.val);
+      limit *= lgl->opts->elmboost.val;
+    }
+    limit >>= (pen = lgl->limits->elm.pen + lglszpen (lgl));
+    irrlim = lgl->stats->irr.clauses.cur;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1,
+       "[elim-%d] limit of %lld steps based on %d irredundant clauses",
+       lgl->stats->elm.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1,
+        "[elim-%d] limit of %lld steps penalty %d = %d + %d",
+       lgl->stats->elm.count, (LGLL) limit,
+       pen, lgl->limits->elm.pen, lglszpen (lgl));
+    lgl->limits->elm.steps = lgl->stats->elm.steps + limit;
+  }
+}
+
+static int lglforceschedall (LGL * lgl) {
+  int idx, res = 0;
+  AVar * av;
+  assert (lgl->eliminating);
+  assert (lglmtstk (&lgl->esched));
+  lgl->donotsched = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglifrozen (lgl, idx)) continue;
+    if (!lglisfree (lgl, idx)) continue;
+    av = lglavar (lgl, idx);
+    av->donotelm = 0;
+    lglesched (lgl, idx);
+    res++;
+  }
+  lglprt (lgl, 1,
+    "[elim-%d-%d] fully rescheduled %d variables %.0f%%",
+    lgl->stats->elm.count, lgl->elm->round,
+    res, lglpcnt (res, lgl->nvars - 2));
+  return res;
+}
+
+static void lgladdstrbincls (LGL * lgl, int a, int b) {
+  assert (lglisfree (lgl, a));
+  assert (lglisfree (lgl, b));
+  assert (lglmtstk (&lgl->clause));
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOG (BWL, "strengthened binary clause", a, b);
+  if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+  lgldrupligaddcls (lgl, REDCS);
+  lgladdcls (lgl, 0, 0, 1);
+  lglclnstk (&lgl->clause);
+}
+
+static int lglbackwardlit (LGL * lgl,
+                          const int * clause, const int * skip,
+                          int size, int minlit,
+                          int *subptr, int *strptr) {
+  int res, blit, tag, red, other, other2, lidx, count, remove, hit;
+  const int * p, * w, * eow, * c, * l;
+  int marked, marked2, val;
+  HTS * hts;
+  assert (!lgl->level);
+  lgl->stats->bkwd.tried.lits++;
+  LOGCLS (BWL, clause,
+    "backward subsume and strengthen clauses with %d by size %d clause",
+    minlit, size);
+  hit = res = 0;
+  hts = lglhts (lgl, minlit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; !res && p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (p == skip) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    lgl->stats->bkwd.tried.occs++;
+    INCSTEPS (elm.steps);
+    if (tag == BINCS) {
+      if (size > 2) continue;
+      other = blit >> RMSHFT;
+      if (!lglisfree (lgl, other)) continue;
+      marked = lglmarked (lgl, other);
+      if (marked > 0) {
+       if (size == 2 && !hit++) continue;
+       LOG (BWL, "subsumed binary clause %d %d", minlit, other);
+       assert (!(w <= skip && skip < eow) || skip < p);
+       ADDSTEPS (elm.steps, 2);
+       lglrmbcls (lgl, minlit, other, 0);
+       lgl->stats->bkwd.sub2++;
+       *subptr += 1;
+       res = 1;
+      } else if (marked < 0) {
+       LOG (BWL,
+         "removing %d and thus strengthening binary clause %d %d",
+         other, minlit, other);
+       assert (p != skip);
+       ADDSTEPS (elm.steps, 2);
+       lglunit (lgl, minlit);
+       lgl->stats->bkwd.str2++;
+       *strptr += 1;
+       res = 1;
+      }
+    } else if (tag == TRNCS) {
+      if (size > 3) continue;
+      other = blit >> RMSHFT;
+      other2 = *p;
+      if (!lglisfree (lgl, other)) continue;
+      if (!lglisfree (lgl, other2)) continue;
+      marked = lglmarked (lgl, other);
+      marked2 = lglmarked (lgl, other2);
+      if ((size == 2 && (marked > 0 || marked2 > 0)) ||
+          (size == 3 && marked > 0 && marked2 > 0)) {
+       if (size == 3 && !hit++) continue;
+       assert (!(w <= skip && skip < eow) || skip < p);
+       LOG (BWL,
+         "subsumed ternary clause %d %d %d",
+         minlit, other, other2);
+       ADDSTEPS (elm.steps, 3);
+       lglrmtcls (lgl, minlit, other, other2, 0);
+       lgl->stats->bkwd.sub3++;
+       *subptr += 1;
+       res = 1;
+      } else {
+       if (marked < 0 && marked2 > 0) {
+         int tmp = other; other = other2; other2 = tmp;
+       } else if (marked <= 0 || marked2 >= 0) continue;
+       LOG (BWL,
+         "removing %d and thus strengthening ternary clause %d %d %d",
+         other2, minlit, other, other2);
+       assert (lglmarked (lgl, other) > 0);
+       assert (lglmarked (lgl, other2) < 0);
+       lgladdstrbincls (lgl, minlit, other);
+       lglrmtcls (lgl, minlit, other, other2, 0);
+       if (size == 3) {
+         LOG (BWL,
+           "removing %d and thus strengthening ternary clause %d %d %d",
+           other2, minlit, other, -other2);
+         lglrmtcls (lgl, minlit, other, -other2, 0);
+         lgl->stats->bkwd.str3self++;
+       }
+       ADDSTEPS (elm.steps, 3);
+       lgl->stats->bkwd.str3++;
+       *strptr += 1;
+       res = 1;
+      }
+    } else {
+      assert (tag == OCCS);
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, 0, lidx);
+      if (c == skip) continue;
+      INCSTEPS (elm.steps);
+      count = size;
+      remove = 0;
+      for (l = c; (other = *l); l++) {
+       val = lglval (lgl, other);
+       if (val > 0) { remove = INT_MAX; break; }
+       if (val < 0) continue;
+       assert (!val);
+       marked = lglmarked (lgl, other);
+       if (!marked) continue;
+       count--;
+       if (marked > 0) continue;
+       if (remove) { remove = INT_MAX; break; }
+       remove = other;
+      }
+      if (count > 0) continue;
+      if (remove == INT_MAX) continue;
+      if (!remove) {
+       assert (!(w <= skip && skip < eow) || skip < p);
+       LOGCLS (BWL, c, "subsumed large clause");
+       ADDSTEPS (elm.steps, (l - c));
+       lglrmlcls (lgl, lidx, 0);
+       lgl->stats->bkwd.subl++;
+       *subptr += 1;
+       res = 1;
+      } else if (lglsmallirr (lgl)) {
+       LOGCLS (BWL, c, "removing %d and thus strengthening clause", remove);
+       assert (lglmtstk (&lgl->clause));
+       for (l = c; (other = *l); l++) {
+         if (other == remove) continue;
+         val = lglval (lgl, other);
+         if (val < 0) continue;
+         assert (!val);
+         lglpushstk (lgl, &lgl->clause, other);
+       }
+       lglpushstk (lgl, &lgl->clause, 0);
+       LOGCLS (BWL, lgl->clause.start, "strengthened clause");
+       if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+       lglpicosatchkcls (lgl);
+#endif
+       ADDSTEPS (elm.steps, (l - c));
+       lglrmlcls (lgl, lidx, 0);
+       if (l - c == size) lgl->stats->bkwd.strlself++;
+       lgldrupligaddcls (lgl, REDCS);
+       lgladdcls (lgl, 0, 0, 1);
+       lglclnstk (&lgl->clause);
+       lgl->stats->bkwd.strl++;
+       *strptr += 1;
+       res = 1;
+      }
+    }
+  }
+  return res;
+}
+
+static int lglbackwardclause (LGL * lgl,
+                              const int * clause, const int * skip,
+                             int * subsumedptr, int * strengthenedptr) {
+  int lit, size, minlit, minlit2, minocc, minocc2, tmpocc, res, large;
+  const int * p;
+  long delta;
+  lgl->stats->bkwd.tried.clauses++;
+  INCSTEPS (elm.steps);
+  minocc = minlit = minocc2 = minlit2 = 0;
+  for (p = clause; (lit = *p); p++) {
+    lglmarkunmarked (lgl, lit);
+    tmpocc = lglocc (lgl, lit);
+    if (!minlit || tmpocc < minocc) {
+      minocc2 = minocc, minlit2 = minlit;
+      minocc = tmpocc, minlit = lit;
+    } else if (!minlit2 || tmpocc < minocc2) {
+      minocc2 = tmpocc, minlit2 = lit;
+    }
+  }
+  size = p - clause;
+  assert (size >= 2);
+  LOG (BWL, "minimum occurrence %d of literal %d", minocc, minlit);
+  LOG (BWL, "next minimum occurrence %d of literal %d", minocc2, minlit2);
+  large = (lgl->irr.start <= clause && clause < lgl->irr.top);
+  delta = large ? clause - lgl->irr.start : 0;
+  res = lglbackwardlit (lgl, clause, skip,
+                       size, minlit, subsumedptr, strengthenedptr);
+  if (!res) {
+    res = lglbackwardlit (lgl, clause, skip,
+                         size, minlit2, subsumedptr, strengthenedptr);
+  }
+  if (res && large) clause = lgl->irr.start + delta;
+  for (p = clause; (lit = *p); p++)
+    lglunmark (lgl, lit);
+  return res;
+}
+
+static void lglbackward (LGL * lgl, int * u, int * t, int64_t steps) {
+  int idx, sign, lit, blit, red, tag, other, other2, clause[4], * w;
+  int64_t limit, delta, scaled;
+  const int * p, * eow, * c;
+  HTS * hts;
+  Stk stk;
+  long i;
+  lglstart (lgl, &lgl->times->bkwd);
+  CLR (stk);
+  *u = *t = 0;
+  if (LLMAX/lgl->opts->bkwdscale.val <= steps) scaled = LLMAX;
+  else scaled = steps * lgl->opts->bkwdscale.val;
+  if (lgl->limits->elm.steps - scaled <= lgl->stats->elm.steps)
+    limit = lgl->limits->elm.steps;
+  else limit = lgl->stats->elm.steps + scaled;
+  delta = limit - lgl->stats->elm.steps;
+  lglprt (lgl, 1,
+    "[elim-%d-%d] backward subsumption/strengthening limit %lld",
+    lgl->stats->elm.count, lgl->elm->round, delta);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+RESTART:
+      if (lgl->mt) goto DONE;
+      if (lglterminate (lgl)) goto DONE;
+
+      // TODO DID NOT WORK?  REMOVE OR FIX?
+      // if (!lglsyncunits (lgl)) goto DONE;
+
+      if (!lglisfree (lgl, idx)) continue;
+      if (INCSTEPS (elm.steps) >= limit) goto DONE;
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      lglclnstk (&stk);
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag != BINCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       lglpushstk (lgl, &stk, blit);
+      }
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag != TRNCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       lglpushstk (lgl, &stk, blit);
+       lglpushstk (lgl, &stk, *p);
+      }
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       red = blit & REDCS;
+       if (!red && (tag == BINCS || tag == TRNCS)) continue;
+       lglpushstk (lgl, &stk, blit);
+       if (tag == TRNCS || tag == LRGCS)
+         lglpushstk (lgl, &stk, *p);
+      }
+      assert (lglcntstk (&stk) == hts->count);
+      memcpy (w, stk.start, lglcntstk (&stk) * sizeof *w);
+      clause[0] = lit;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       if (INCSTEPS (elm.steps) >= limit) goto DONE;
+       if (tag == BINCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         clause[1] = other, clause[2] = 0;
+         if (!lglbackwardclause (lgl, clause, p, u, t)) continue;
+       } else if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         clause[1] = other, clause[2] = other2, clause[3] = 0;
+         if (!lglbackwardclause (lgl, clause, p, u, t)) continue;
+       } else { assert (tag == OCCS); continue; }
+       if (lglflush (lgl)) goto RESTART;
+       else goto DONE;
+      }
+    }
+  }
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    if (!lglsmallirr (lgl)) goto DONE;
+    if (INCSTEPS (elm.steps) >= limit) goto DONE;
+    if (*(p = c) >= NOTALIT) continue;
+    while (*p) p++;
+    i = p - lgl->irr.start;
+    if (lglbackwardclause (lgl, c, c, u, t)) p = lgl->irr.start + i;
+  }
+DONE:
+  lglrelstk (lgl, &stk);
+  lglstop (lgl);
+}
+
+static int lglelmdone (LGL * lgl, int * allptr) {
+  int newelmd, eliminated, subsumed, strengthened;
+  int64_t steps, oldsteps;
+  if (!lglsmallirr (lgl)) return 1;
+  if (lglterminate (lgl)) return 1;
+  if (lgl->limits->elm.steps <= lgl->stats->elm.steps) return 1;
+  if (!lglmtstk (&lgl->esched)) return 0;
+  steps = ((oldsteps = lgl->stats->elm.steps) - lgl->elm->oldsteps);
+  eliminated = (newelmd = lgl->stats->elm.elmd) - lgl->elm->oldelmd;
+  assert (eliminated >= 0);
+  if (eliminated <= 0) {
+    lglprt (lgl, 1,
+      "[elim-%d-%d] no variable eliminated in round %d in %lld steps",
+      lgl->stats->elm.count, lgl->elm->round,
+      lgl->elm->round, (LGLL) steps);
+    return 1;
+  }
+  lglprt (lgl, 1,
+    "[elim-%d-%d] eliminated %d variables %.0f%% in round %d in %lld steps",
+    lgl->stats->elm.count, lgl->elm->round, eliminated, 
+    lglpcnt (eliminated, lgl->nvars - 2), lgl->elm->round, (LGLL) steps);
+  lglbackward (lgl, &subsumed, &strengthened, steps);
+  steps = lgl->stats->elm.steps - oldsteps;
+  lglprt (lgl, 1,
+    "[elim-%d-%d] subsumed %d and strengthened %d clauses in %lld steps",
+    lgl->stats->elm.count, lgl->elm->round, subsumed, strengthened,
+    (LGLL) steps);
+  lgl->stats->elm.rounds++;
+  lgl->elm->oldelmd = newelmd;
+  lgl->elm->oldsteps = lgl->stats->elm.steps;
+  if (lgl->mt) return 1;
+  if (lgl->limits->elm.steps <= lgl->stats->elm.steps) return 1;
+  if (lgl->elm->round >= lgl->opts->elmroundlim.val) return 1;
+  if (!lglmtstk (&lgl->esched)) {
+    lglprt (lgl, 1,
+      "[elim-%d-%d] rescheduled %d variables %.0f%% by backward subsumption",
+      lgl->stats->elm.count, lgl->elm->round,
+      lglcntstk (&lgl->esched),
+      lglpcnt (lglcntstk (&lgl->esched), lglrem (lgl)));
+    lgl->elm->round++;
+    return 0;
+  }
+  if (*allptr) return 1;
+  *allptr = 1;
+  if (!lglforceschedall (lgl)) return 1;
+  lgl->elm->round++;
+  return 0;
+}
+
+static int lglelim (LGL * lgl) {
+  int res = 1, idx, elmd, oldnvars, success, all, rem;
+  int oldrem = lgl->elmrem, oldall = lgl->elmall;
+  assert (lgl->opts->elim.val);
+  assert (!lgl->mt);
+  assert (lgl->nvars > 2);
+  assert (!lgl->eliminating);
+  assert (!lgl->simp);
+  assert (!lgl->occs);
+  lglstart (lgl, &lgl->times->elm);
+  lgl->stats->elm.count++;
+  lgl->eliminating = lgl->simp = lgl->occs = 1;
+  NEW (lgl->elm, 1);
+  lgl->elm->oldelmd = lgl->stats->elm.elmd;
+  lgl->elm->round = 1;
+  lgl->elm->oldsteps = lgl->stats->elm.steps;
+  lgl->stats->elm.rounds++;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  oldnvars = lglrem (lgl);
+  lglgc (lgl);
+  assert (lgl->frozen);
+  assert (!(oldall && !oldrem));
+  all = !oldrem || !oldall;
+  if (all)
+    lglprt (lgl, 1,
+      "[elim-%d] scheduling all variables this time",
+       lgl->stats->elm.count);
+  else if (!lgleschedrem (lgl, 1)) all = 1, oldrem = 0;
+  if (!all) assert (!lgl->donotsched), lgl->donotsched = 1;
+  lgldense (lgl, 1);
+  if (!all) assert (lgl->donotsched), lgl->donotsched = 0;
+  lglsetelmlim (lgl);
+  while (res && !lglelmdone (lgl, &all)) {
+    idx = lglpopesched (lgl);
+    lglavar (lgl, idx)->donotelm = 1;
+    lglelimlit (lgl, idx);
+    res = lglflush (lgl);
+    assert (res || lgl->mt);
+  }
+  rem = lglcntstk (&lgl->esched);
+  if (!rem) {
+    lglprt (lgl, 1,
+      "[elim-%d] fully completed in %d rounds",
+      lgl->stats->elm.count, lgl->elm->round);
+    lgl->elmrtc = 1;
+  } else {
+    lglprt (lgl, 1,
+      "[elim-%d] incomplete %d not tried %.0f%% in round %d",
+      lgl->stats->elm.count,
+      rem, lglpcnt (rem, lgl->nvars - 2),
+      lgl->elm->round);
+  }
+  lglsetdonotesched (lgl, !rem);
+  lglrelstk (lgl, &lgl->esched);
+  lglrelecls (lgl);
+  lglsparse (lgl);
+  lglgc (lgl);
+  DEL (lgl->elm, 1);
+  lgl->elmrem = rem > 0;
+  lgl->elmall = all && lgl->elmrem;
+  lglprt (lgl, 1,
+    "[elim-%d] transition to [ all %d rem %d ] state",
+    lgl->stats->elm.count, lgl->elmall, lgl->elmrem);
+  elmd = oldnvars - lglrem (lgl);
+  lgl->stats->irrprgss += elmd;
+  lglprt (lgl, 1,
+    "[elim-%d] eliminated %d = %.0f%% variables out of %d",
+    lgl->stats->elm.count, elmd, lglpcnt (elmd, oldnvars), oldnvars);
+  if (oldnvars < lgl->opts->elmsuccesslim.val) success = elmd;
+  else if (elmd) {
+    success = (oldnvars/lgl->opts->elmsuccessrat.val <= elmd);
+    if (!success)
+      lglprt (lgl, 1,
+       "[elim-%d] %d < 1/%d * %d = %d considered unsuccessful",
+       lgl->stats->elm.count, elmd, lgl->opts->elmsuccessrat.val,
+       oldnvars, oldnvars/lgl->opts->elmsuccessrat.val);
+  } else success = 0;
+  LGLUPDPEN (elm, success);
+  lgl->elmstuck = !rem && !success;
+  if (lgl->elmstuck)
+    lglprt (lgl, 2,
+      "[elim-%d] completed but nothing eliminated thus stuck",
+      lgl->stats->elm.count);
+  lglrep (lgl, 2, 'e');
+  assert (lgl->eliminating && lgl->simp && lgl->occs);
+  lgl->eliminating = lgl->simp = lgl->occs = 0;
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lglsynceqs (LGL * lgl) {
+  int * ereprs, emax = lgl->maxext;
+  int elit1, erepr1, elit2, erepr2;
+  int ilit1, irepr1, ilit2, irepr2;
+  int consumed = 0, produced = 0;
+  assert (!lgl->mt);
+  assert (!lgl->level);
+  if (!lgl->nvars) return 1;
+  if (!lgl->cbs) return 1;
+  if (!lgl->cbs->eqs.lock.fun) return 1;
+  assert (lgl->repr);
+  ereprs = lgl->cbs->eqs.lock.fun (lgl->cbs->eqs.lock.state);
+  produced = consumed = 0;
+  for (elit1 = 1; elit1 <= emax; elit1++) {
+    if (lglelitblockingoreliminated (lgl, elit1)) continue;
+    elit2 = lglptrjmp (ereprs, emax, elit1);
+    if (elit2 == elit1) continue;
+    if (lglelitblockingoreliminated (lgl, elit2)) continue;
+    assert (elit2 != -elit1);
+    erepr1 = lglerepr (lgl, elit1);
+    if (lglelitblockingoreliminated (lgl, erepr1)) continue;
+    erepr2 = lglerepr (lgl, elit2);
+    if (lglelitblockingoreliminated (lgl, erepr2)) continue;
+    if (erepr1 == erepr2) continue;
+    if (erepr1 == -erepr2) {
+INCONSISTENT:
+      LOG (1, "inconsistent external equivalence %d %d", elit1, elit2);
+      assert (!lgl->level);
+      lgl->mt = 1;
+      goto DONE;
+    }
+    ilit1 = lglimport (lgl, elit1);
+    ilit2 = lglimport (lgl, elit2);
+    if (ilit1 == ilit2) continue;
+    if (ilit1 == -ilit2) goto INCONSISTENT;
+    if (abs (ilit1) <= 1) continue;
+    if (abs (ilit2) <= 1) continue;
+    irepr1 = lglirepr (lgl, ilit1);
+    irepr2 = lglirepr (lgl, ilit2);
+    if (irepr1 == irepr2) continue;
+    if (irepr1 == -irepr2) goto INCONSISTENT;
+    if (abs (irepr1) <= 1) continue;
+    if (abs (irepr2) <= 1) continue;
+    LOG (2, "importing external equivalence %d %d as internal %d %d",
+        elit1, elit2, irepr1, irepr2);
+    if (!lglisfree (lgl, irepr1)) continue;
+    if (!lglisfree (lgl, irepr2)) continue;
+    consumed++;
+    lglimerge (lgl, irepr1, irepr2);
+  }
+  LOG (1, "consumed %d equivalences", consumed);
+  for (elit1 = 1; elit1 <= emax; elit1++) {
+    elit2 = lglerepr (lgl, elit1);
+    if (elit1 == elit2) continue;
+    assert (elit1 != -elit2);
+    erepr1 = lglptrjmp (ereprs, emax, elit1);
+    erepr2 = lglptrjmp (ereprs, emax, elit2);
+    if (erepr1 == erepr2) continue;
+    assert (erepr1 != -erepr2);
+    LOG (2, "exporting external equivalence %d %d", erepr1, erepr2);
+    produced++;
+    ereprs[abs (erepr1)] = (erepr1 < 0) ? -erepr2 : erepr2;
+  }
+  LOG (1, "produced %d equivalences", produced);
+DONE:
+  if (lgl->cbs->eqs.unlock.fun)
+    lgl->cbs->eqs.unlock.fun (lgl->cbs->eqs.unlock.state, consumed, produced);
+  return !lgl->mt;
+}
+
+static int lgldecomp (LGL * lgl) {
+  int res = 1, oldnvars = lgl->nvars, removed;
+  assert (lgl->opts->decompose.val || lgl->probing || lgl->gaussing);
+  assert (!lgl->decomposing);
+  lglstart (lgl, &lgl->times->dcp);
+  lgl->stats->decomps++;
+  lgl->decomposing = 1;
+  lgl->simp++;
+  assert (lgl->simp > 0);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  res = 0;
+  lglgc (lgl);
+  if (!lglsyncunits (lgl)) goto DONE;
+  lglgc (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgltarjan (lgl)) goto DONE;
+  if (!lglsynceqs (lgl)) goto DONE;
+  lglchkred (lgl);
+  lgldcpdis (lgl);
+  lgldcpcln (lgl);
+  lgldcpcon (lgl);
+  lglcompact (lgl);
+  lglmap (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lglbcp (lgl)) { if (!lgl->mt) lgl->mt = 1; goto DONE; }
+  lglcount (lgl);
+  lglgc (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgl->mt) { lglpicosatchkall (lgl); lglpicosatrestart (lgl); }
+  res = 1;
+DONE:
+  if (lgl->repr) DEL (lgl->repr, lgl->nvars);
+  assert (lgl->decomposing);
+  lgl->decomposing = 0;
+  ASSERT (lgl->simp > 0);
+  lgl->simp--;
+  removed = oldnvars - lgl->nvars;
+  if (removed) lglprt (lgl, 1, "[decomp-%d] removed %d variables",
+                       lgl->stats->decomps, removed);
+  lglrep (lgl, 2, 'd');
+  lglstop (lgl);
+  return res;
+}
+
+int lglnvars (LGL * lgl) { return lglrem (lgl); }
+
+int lglnclauses (LGL * lgl) { return lgl->stats->irr.clauses.cur; }
+
+static int lglcgrepr (LGL * lgl, int lit) {
+  return lglptrjmp (lgl->repr, lgl->nvars - 1, lit);
+}
+
+static void lglpushgocc (LGL * lgl, int lit, int gidx) {
+  int idx, repr;
+  Stk * goccs;
+  repr = lglcgrepr (lgl, lit);
+  if (abs (repr) == 1) repr = lit;
+  idx = abs (repr);
+  assert (2 <= idx && idx < lgl->nvars);
+  goccs = lgl->cgr->goccs + idx;
+  lglpushstk (lgl, goccs, gidx);
+}
+
+static void lglenlargegates (LGL * lgl) {
+  int oldsize = lgl->cgr->szgates;
+  int newsize = oldsize ? 2*oldsize : 1;
+  RSZ (lgl->cgr->gates, oldsize, newsize);
+  lgl->cgr->szgates = newsize;
+}
+
+static int lglcgreprnotconst (LGL * lgl, int lit) {
+  int res;
+  assert (abs (lit) != 1);
+  res = lglcgrepr (lgl, lit);
+  if (abs (res) == 1) res = lit;
+  return res;
+}
+
+static Gat * lglnewgate (LGL * lgl, GTag tag, int lhs, int size) {
+  Gat * res;
+  int gidx;
+  assert (size >= 2);
+  if (lgl->cgr->extracted.all >= lgl->cgr->szgates) lglenlargegates (lgl);
+  assert (lgl->cgr->extracted.all < lgl->cgr->szgates);
+  lgl->stats->cgr.extracted.all++;
+  gidx = lgl->cgr->extracted.all++;
+  res = lgl->cgr->gates + gidx;
+  CLR (*res);
+  lhs = lglcgreprnotconst (lgl, lhs);
+  res->lhs = lhs;
+  lglpushgocc (lgl, lhs, gidx);
+  lglavar (lgl, lhs)->gate = 1;
+  res->tag = tag;
+  res->size = size;
+  return res;
+}
+
+static Gat * lglgidx2gat (LGL * lgl, int gidx) {
+  assert (0 <= gidx && gidx < lgl->cgr->extracted.all);
+  return lgl->cgr->gates + gidx;
+}
+
+static int lglgat2idx (LGL * lgl, Gat * g) {
+  assert (lgl->cgr->gates <= g && 
+          g < lgl->cgr->gates + lgl->cgr->extracted.all);
+  return g - lgl->cgr->gates;
+}
+
+static int lglcgeq (LGL * lgl, int a, int b) {
+  return lglcgrepr (lgl, a) == lglcgrepr (lgl, b);
+}
+
+static int lglhasitegate (LGL * lgl, int lhs, int cond, int pos, int neg) {
+  const int * p;
+  int repr;
+  Stk * s;
+  repr = lglcgrepr (lgl, lhs);
+  if (abs (repr) == 1) repr = lhs;
+  s = lgl->cgr->goccs + abs (repr);
+  Gat * g;
+  for (p = s->start; p < s->top; p++) {
+    g = lglgidx2gat (lgl, *p);
+    if (g->tag != ITETAG) continue;
+    assert (g->size == 2);
+    if (g->lhs != lhs) continue;
+    if (!lglcgeq (lgl, g->cond, cond)) continue;
+    if (!lglcgeq (lgl, g->pos, pos)) continue;
+    if (!lglcgeq (lgl, g->neg, neg)) continue;
+    return 1;
+  }
+  return 0;
+}
+
+#define EL 1
+
+static void lglnewitegate (LGL * lgl, int lhs, int cond, int pos, int neg) {
+  int gidx;
+  Gat * g;
+  lhs = lglcgreprnotconst (lgl, lhs);
+  if (lhs < 0) lhs = -lhs, pos = -pos, neg = -neg;
+  if ((pos < 0 && neg > 0) || (cond < 0 && lglsgn (pos) == lglsgn (neg))) {
+    SWAP (int, pos, neg);
+    cond = -cond;
+  }
+  cond = lglcgreprnotconst (lgl, cond);
+  pos = lglcgreprnotconst (lgl, pos);
+  neg = lglcgreprnotconst (lgl, neg);
+  assert (abs (pos) != -abs (neg));
+  if (lglhasitegate (lgl, lhs, cond, pos, neg)) return;
+  g = lglnewgate (lgl, ITETAG, lhs, 2);
+  gidx = lglgat2idx (lgl, g);
+  g->cond = cond, g->pos = pos, g->neg = neg;
+  lglpushgocc (lgl, cond, gidx);
+  lglpushgocc (lgl, pos, gidx);
+  lglpushgocc (lgl, neg, gidx);
+  LOG (EL, "extracted ite gate %d = %d ? %d : %d", lhs, cond, pos, neg);
+  lgl->stats->cgr.extracted.ite++;
+  lgl->cgr->extracted.ite++;
+}
+
+static int lglhasbingate (LGL * lgl, GTag tag, int lhs, int rhs0, int rhs1) {
+  const int * p;
+  Stk * s;
+  Gat * g;
+  lhs = lglcgreprnotconst (lgl, lhs);
+  rhs0 = lglcgreprnotconst (lgl, rhs0);
+  rhs1 = lglcgreprnotconst (lgl, rhs1);
+  s = lgl->cgr->goccs + abs (lhs);
+  for (p = s->start; p < s->top; p++) {
+    g = lglgidx2gat (lgl, *p);
+    if (g->tag != tag) continue;
+    if (g->size != 2) continue;
+    if (g->lhs != lhs) continue;
+    if (!lglcgeq (lgl, g->lits[0], rhs0)) continue;
+    if (!lglcgeq (lgl, g->lits[1], rhs1)) continue;
+    return 1;
+  }
+  return 0;
+}
+
+static int lglnewbingate (LGL * lgl, GTag tag, int lhs, int rhs0, int rhs1) {
+  int gidx;
+  Gat * g;
+  lhs = lglcgreprnotconst (lgl, lhs);
+  rhs0 = lglcgreprnotconst (lgl, rhs0);
+  rhs1 = lglcgreprnotconst (lgl, rhs1);
+  if (abs (rhs0) > abs (rhs1)) SWAP (int, rhs0, rhs1);
+  if (tag == XORTAG && lhs < 0) lhs = -lhs, rhs0 = -rhs0;
+  if (tag == XORTAG && rhs0 < 0) rhs0 = -rhs0, rhs1 = -rhs1;
+  if (lglhasbingate (lgl, tag, lhs, rhs0, rhs1)) return 0;
+  g = lglnewgate (lgl, tag, lhs, 2);
+  gidx = lglgat2idx (lgl, g);
+  g->lits[0] = rhs0, g->lits[1] = rhs1;
+  lglpushgocc (lgl, rhs0, gidx);
+  lglpushgocc (lgl, rhs1, gidx);
+  if (tag == ANDTAG) {
+    lgl->cgr->extracted.and++;
+    lgl->stats->cgr.extracted.and++;
+    LOG (EL, "extracted binary and gate %d = %d & %d", lhs, -rhs0, -rhs1);
+  } else if (tag == XORTAG) {
+    lgl->cgr->extracted.xor++;
+    lgl->stats->cgr.extracted.xor++;
+    LOG (EL, "extracted binary xor gate %d = %d ^ %d", -lhs, rhs0, rhs1);
+  }
+  return 1;
+}
+
+static void lglnewlrgate (LGL * lgl, GTag tag, int lhs, int * cls, int size) {
+  int gidx, other, lhsrepr;
+  const int * p;
+  Gat * g;
+  assert (size >= 3);
+  lhsrepr = lglcgreprnotconst (lgl, lhs);
+  g = lglnewgate (lgl, tag, lhsrepr, size);
+  g->origlhs = lhs;
+  gidx = lglgat2idx (lgl, g);
+  g->cls = cls;
+  for (p = cls; (other = *p); p++) {
+    if (abs (other) == lhs) continue;
+    other = lglcgreprnotconst (lgl, other);
+    lglpushgocc (lgl, other, gidx);
+  }
+  if (tag == ANDTAG) lgl->cgr->extracted.and++, lgl->stats->cgr.extracted.and++;
+  if (tag == XORTAG) lgl->cgr->extracted.xor++, lgl->stats->cgr.extracted.xor++;
+#ifndef NLGLOG
+  if (lgl->opts->log.val >= EL) {
+    if (tag == ANDTAG) {
+      int count = 0;
+      lglogstart (lgl, EL, "extracted %d-ary and gate %d = ", size, lhsrepr);
+      for (p = cls; (other = *p); p++) {
+       if (abs (other) == abs (lhs)) continue;
+       if (count++) fputs (" & ",  lgl->out);
+       fprintf (lgl->out, "%d", -lglcgrepr (lgl, other));
+      }
+      lglogend (lgl);
+    } else if (tag == XORTAG) {
+      int count = 0;
+      lglogstart (lgl, EL, "extracted %d-ary xor gate %d = ", size, -lhs);
+      for (p = cls; (other = *p); p++) {
+       if (abs (other) == abs (lhs)) continue;
+       if (count++) fputs (" ^ ",  lgl->out);
+       fprintf (lgl->out, "%d", lglcgrepr (lgl, other));
+      }
+      lglogend (lgl);
+    } else COVER (1);
+  }
+#endif
+}
+
+static void lglcgmerge (LGL * lgl, int other, int repr) {
+  int * p, * q, gidx;
+  Stk * from, * to;
+  Gat * g;
+  assert (lgl->cgrclosing);
+  if (abs (other) == 1) SWAP (int, other, repr);
+  if (repr == -1) other = -other, repr = 1;
+  assert (lglcgrepr (lgl, other) == other);
+  assert (abs (repr) != abs (other));
+  if (repr == 1) {
+    assert (abs (other) >= 2);
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, other, 0);
+#ifndef NLGLPICOSAT
+    if (lgl->picosat.chk) lglpicosatchkclsarg (lgl, other, 0);
+#endif
+    if (other < 0) other = -other, repr = -repr;
+    lgl->repr[other] = repr;
+    lglwrktouch (lgl, other);
+  } else {
+    assert (abs (repr) >= 2);
+    assert (lglcgrepr (lgl, repr) == repr);
+    if (lglcmprepr (lgl, other, repr) < 0) SWAP (int, repr, other);
+    if (other < 0) other = -other, repr = -repr;
+    lglimerge (lgl, other, repr);
+    assert (0 < other);
+    from = lgl->cgr->goccs + abs (other);
+    to = lgl->cgr->goccs + abs (repr);
+    q = to->start;
+    for (p = q; p < to->top; p++) {
+      g = lglgidx2gat (lgl, (gidx = *p));
+      if (g->mark) continue;
+      *q++ = gidx;
+      g->mark = 1;
+    }
+    to->top = q;
+    LOG (2, "merging %d gate occurrences of %d with %d occurrences of %d",
+        lglcntstk (from), other, lglcntstk (to), repr);
+    for (p = from->start; p < from->top; p++) {
+      g = lglgidx2gat (lgl, (gidx = *p));
+      if (g->mark) continue;
+      g->mark = 1;
+      lglpushstk (lgl, to, gidx);
+    }
+    lglrelstk (lgl, from);
+    for (p = to->start; p < to->top; p++) {
+      g = lglgidx2gat (lgl, *p); assert (g->mark); g->mark = 0;
+    }
+    lglwrktouch (lgl, repr);
+  }
+}
+
+static int lglcmpocc (LGL * lgl, int a, int b) {
+  return lglocc (lgl, a) - lglocc (lgl, b);
+}
+
+#define LGLCMPOCC(A,B) lglcmpocc (lgl, *(A), *(B))
+
+static int lglcgextractlimhit (LGL * lgl) {
+  return lgl->stats->cgr.esteps >= lgl->limits->cgr.esteps;
+}
+
+static int lglincextractlimhit (LGL * lgl) {
+  INCSTEPS (cgr.esteps);
+  return lglcgextractlimhit (lgl);
+}
+
+static int lglcgunit (LGL * lgl, int lit) {
+  int next, repr, other, ok;
+  Val val = lglval (lgl, lit);
+  if (val > 0) return 1;
+  if (val < 0) {
+    LOG (1, "extracted unit already %d falsified", lit);
+    lgl->mt = 1;
+    return 0;
+  }
+  next = lgl->next;
+  lglunit (lgl, lit);
+  if ((ok = lglbcp (lgl))) {
+    while (next < lgl->next) {
+      other = lglpeek (&lgl->trail, next++);
+      repr = lglcgrepr (lgl, other);
+      if (repr == 1) continue;
+      if (repr == -1) { ok = 0; break; }
+      assert (repr != -1);
+      lglcgmerge (lgl, repr, 1);
+    }
+  }
+  if (!ok) {
+    LOG (1, "propagation of congruence closure unit %d failed", lit);
+    lgl->mt = 1;
+  }
+  return ok;
+}
+
+static int lglcgextractands (LGL * lgl, int lit) {
+  int blit, tag, other, other2, lidx, size, tmp, repr;
+  const int * p, * w, * eow, * l;
+  HTS * hts;
+  Val val;
+  int * c;
+  if (!lgl->opts->cgrextand.val) return 1;
+  repr = lglcgrepr (lgl, lit);
+  if (lglval (lgl, lit)) { assert (abs (repr) == 1); return 1; }
+  if (abs (repr) == 1) return 1;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    if (lglincextractlimhit (lgl)) return 0;
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS) {
+      if (!lgl->opts->cgrexteq.val && !lgl->opts->cgrextunits.val) continue;
+      tmp = blit >> RMSHFT;
+      if ((val = lglval (lgl, tmp))) { assert (val > 0); continue; }
+      repr = lglcgrepr (lgl, lit);
+      other = lglcgrepr (lgl, -tmp);
+      if (repr == other) continue;
+      if (lglincextractlimhit (lgl)) return 0;
+      if (lgl->opts->cgrextunits.val &&
+         repr != 1 &&
+         lglhasbin (lgl, lit, -tmp)) {
+       LOG (EL, "extracted unit %d with %d %d and %d %d",
+            lit, lit, tmp, lit, -tmp);
+       lgl->cgr->extracted.units++;
+       lgl->stats->cgr.units++;
+       if (repr == -1) {
+         LOG (1, "extracted unit %d in conflict with previous unit %d",
+              lit, -lit);
+         lgl->mt = 1;
+         return 0;
+       }
+       if (!lglcgunit (lgl, repr)) return 0;
+       if (lglval (lgl, lit)) return 1;
+      } else if (lgl->opts->cgrexteq.val && lglhasbin (lgl, -lit, -tmp)) {
+       lgl->cgr->extracted.eq++;
+       lgl->stats->cgr.eq++;
+       LOG (EL, "extracted equivalence %d = %d with representatives %d = %d",
+            lit, -tmp, repr, other);
+       if (repr == -other) {
+         assert (!lgl->mt);
+         LOG (1, "merging equivalence classes of opposite literals");
+         lgl->mt = 1;
+         return 0;
+       }
+       lglcgmerge (lgl, other, repr);
+      }
+      continue;
+    }
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      other2 = *p;
+      if (lglocc (lgl, other) > lglocc (lgl, other2)) SWAP (int, other, other2);
+      if (lglincextractlimhit (lgl)) return 0;
+      if (!lglhasbin (lgl, -lit, -other)) continue;
+      if (lglincextractlimhit (lgl)) return 0;
+      if (!lglhasbin (lgl, -lit, -other2)) continue;
+      lglnewbingate (lgl, ANDTAG, lit, other, other2);
+    } else  {
+      assert (tag == OCCS);
+      if (lglincextractlimhit (lgl)) return 0;
+      assert (lglmtstk (&lgl->clause));
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, (blit & REDCS), lidx);
+      for (l = c; (other = *l); l++)
+       if (other != lit) lglpushstk (lgl, &lgl->clause, other);
+      size = l - c - 1;
+      assert (size >= 3);
+      SORT (int, lgl->clause.start, size, LGLCMPOCC);
+      for (l = lgl->clause.start; l < lgl->clause.top; l++) {
+       if (lglincextractlimhit (lgl)) { lglclnstk (&lgl->clause); return 0; }
+       if (!lglhasbin (lgl, -lit, -*l)) break;
+      }
+      if (l == lgl->clause.top) lglnewlrgate (lgl, ANDTAG, lit, c, size);
+      lglclnstk (&lgl->clause);
+    }
+  }
+  return 1;
+}
+
+static int lglparity (LGL * lgl) {
+  const int * p;
+  int res = 0;
+  for (p = lgl->clause.start; p < lgl->clause.top; p++)
+    if (*p < 0) res = !res;
+  return res;
+}
+
+static void lglinclause (LGL * lgl, int parity) {
+  int * p;
+  assert (lglparity (lgl) == parity);
+  do {
+    for (p = lgl->clause.start; p < lgl->clause.top; p++)
+      if ((*p = -*p) < 0) break;
+  } while (lglparity (lgl) != parity);
+}
+
+static int lglxorhascls (LGL * lgl) {
+  int lit, res, minlit = 0, minoccs = INT_MAX, litoccs, blit, tag, lidx;
+  const int * p, * w, * eow, * l, * c;
+  HTS * hts;
+  for (p = lgl->clause.start; p < lgl->clause.top; p++) {
+    lit = *p;
+    litoccs = lglocc (lgl, lit);
+    if (litoccs < minoccs) minlit = lit, minoccs = litoccs;
+    lglsignedmark (lgl, lit);
+  }
+  res = 0;
+  hts = lglhts (lgl, minlit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; !res && p < eow; p++) {
+    blit = *p;
+    if (lglincextractlimhit (lgl)) { assert (!res); break; }
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != OCCS) continue;
+    lidx = blit >> RMSHFT;
+    if (lglincextractlimhit (lgl)) { assert (!res); break; }
+    c = lglidx2lits (lgl, (blit & REDCS), lidx);
+    for (l = c; (lit = *l); l++) if (!lglsignedmarked (lgl, lit)) break;
+    if (!lit) res = 1;
+  }
+  for (p = lgl->clause.start; p < lgl->clause.top; p++) lglunmark (lgl, *p);
+  return res;
+}
+
+static int lglcgextractxors (LGL * lgl, int lit) {
+  int blit, tag, other, other2, lidx, size, count, parity, * c;
+  const int * p, * w, * eow, * l;
+  HTS * hts;
+  if (!lgl->opts->cgrextxor.val) return 1;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    if (lglincextractlimhit (lgl)) return 0;
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS) continue;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (tag == TRNCS) {
+      if ((other = blit >> RMSHFT) < 0) continue;
+      if ((other2 = *p) < 0) continue;
+      INCSTEPS (cgr.esteps);
+      if (!lglhastrn (lgl, lit, -other, -other2)) continue;
+      INCSTEPS (cgr.esteps);
+      if (!lglhastrn (lgl, -lit, other, -other2)) continue;
+      INCSTEPS (cgr.esteps);
+      if (!lglhastrn (lgl, -lit, -other, other2)) continue;
+      lglnewbingate (lgl, XORTAG, lit, other, other2);
+    } else {
+      assert (tag == OCCS);
+      if (lglincextractlimhit (lgl)) return 0;
+      assert (lglmtstk (&lgl->clause));
+      lidx = blit >> RMSHFT;
+      c = lglidx2lits (lgl, (blit & REDCS), lidx);
+      for (l = c; (other = *l); l++) {
+       if (other != lit && other < 0) break;
+       lglpushstk (lgl, &lgl->clause, other);
+      }
+      if (!other && (size = l - c - 1) <= lgl->opts->cgrmaxority.val) {
+       assert (3 <= size && size <= 30);
+       count = (1 << size);
+       assert (count > 0);
+       parity = (lit < 0);
+       while (--count) {
+         lglinclause (lgl, parity);
+         INCSTEPS (cgr.esteps);
+         if (!lglxorhascls (lgl)) break;
+       }
+       if (!count) {
+#ifndef NDEBUG
+         int i;
+         lglinclause (lgl, parity);
+         for (i = 0; i <= size; i++) assert (lgl->clause.start[i] == c[i]);
+#endif
+         lglnewlrgate (lgl, XORTAG, lit, c, size);
+       }
+      }
+      lglclnstk (&lgl->clause);
+    }
+  }
+  return !lglcgextractlimhit (lgl);
+}
+
+static int lglcmpitecands (const ITEC * c, const ITEC * d) {
+  int a = c->other, b = d->other;
+  int res = abs (a) - abs (b);
+  if (res) return res;
+  if ((res = a - b)) return res;
+  return c->other2 - d->other2;
+}
+
+static int lglcgmergelhsrhs (LGL * lgl, int lhs, int rhs) {
+  int conflict = 0;
+  lhs = lglcgrepr (lgl, lhs);
+  rhs = lglcgrepr (lgl, rhs);
+  if (lhs == rhs) return 0;
+  if (lhs == -rhs) conflict = 1;
+  else if (lhs == 1) {
+    if (rhs == -1) conflict = 1;
+    else assert (rhs != 1), conflict = !lglcgunit (lgl, rhs);
+  } else if (lhs == -1) {
+    if (rhs == 1) conflict = 1;
+    else assert (rhs != -1), conflict = !lglcgunit (lgl, -rhs);
+  } else if (rhs == 1) conflict = !lglcgunit (lgl, lhs);
+  else if (rhs == -1) conflict = !lglcgunit (lgl, -lhs);
+  else lglcgmerge (lgl, lhs, rhs);
+  return conflict;
+}
+
+static void lglcgextractitecands (LGL * lgl, int lhs, ITEC * cands, int ncands) {
+  int cond, pos, neg;
+  int l, m, r, i, j;
+  for (l = 0; l < ncands; l = r) {
+    for (r = l + 1; r < ncands; r++)
+      if (abs (cands[l].other) != abs (cands[r].other)) break;
+    if (cands[l].other == cands[r-1].other) continue;
+    assert (cands[l].other < 0);
+    assert (cands[r-1].other > 0);
+    assert (cands[l].other == -cands[r-1].other);
+    for (m = l + 1; cands[m].other < 0; m++) assert (m + 1 < r);
+    for (i = l; i + 1 < m; i++) assert (cands[i].other == cands[i+1].other);
+    for (i = m; i + 1 < r; i++) assert (cands[i].other == cands[i+1].other);
+    for (i = l; i < m; i++) {
+      for (j = m; j < r; j++) {
+       lhs = lglcgreprnotconst (lgl, lhs);
+       INCSTEPS (cgr.esteps);
+       cond = -cands[l].other;
+       pos = -cands[l].other2;
+       neg = -cands[m].other2;
+       pos = lglcgreprnotconst (lgl, pos);
+       neg = lglcgreprnotconst (lgl, neg);
+       if (pos == -neg) continue;              // skip XORTAGs
+       if (pos == neg) {
+         if (lhs != pos && lglcgmergelhsrhs (lgl, lhs, pos)) return;
+       } else lglnewitegate (lgl, lhs, cond, pos, neg);
+      }
+    }
+  }
+}
+
+static int lglcgextractites (LGL * lgl, int lit) {
+  int blit, tag, other, other2;
+  ITEC * cands; int ncands;
+  const int * p, * w, * eow;
+  HTS * hts;
+  if (!lgl->opts->cgrextite.val) return 1;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    INCSTEPS (cgr.esteps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS || tag == OCCS) continue;
+    p++;
+    if (tag == LRGCS) continue;
+    assert (tag == TRNCS);
+    other = blit >> RMSHFT;
+    other2 = *p;
+    lglsignedmark (lgl, other);
+    lglsignedmark (lgl, other2);
+  }
+  assert (lglmtstk (&lgl->seen));
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS || tag == OCCS) continue;
+    p++;
+    if (tag == LRGCS) continue;
+    INCSTEPS (cgr.esteps);
+    assert (tag == TRNCS);
+    other = blit >> RMSHFT;
+    other2 = *p;
+    if (lglsignedmarked (lgl, -other)) {
+      INCSTEPS (cgr.esteps);
+      if (lglhastrn (lgl, -lit, other, -other2)) {
+       lglpushstk (lgl, &lgl->seen, other);
+       lglpushstk (lgl, &lgl->seen, other2);
+      }
+    }
+    if (lglsignedmarked (lgl, -other2)) {
+      INCSTEPS (cgr.esteps);
+      if (lglhastrn (lgl, -lit, -other, other2)) {
+       lglpushstk (lgl, &lgl->seen, other2);
+       lglpushstk (lgl, &lgl->seen, other);
+      }
+    }
+  }
+  for (p = w; p < eow; p++) {
+    INCSTEPS (cgr.esteps);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == BINCS || tag == OCCS) continue;
+    p++;
+    if (tag == LRGCS) continue;
+    assert (tag == TRNCS);
+    other = blit >> RMSHFT;
+    other2 = *p;
+    lglunmark (lgl, other);
+    lglunmark (lgl, other2);
+  }
+  if ((ncands = lglcntstk (&lgl->seen))) {
+    cands = (ITEC *) lgl->seen.start;
+    assert (!(ncands & 1));
+    ncands /= 2;
+    SORT (ITEC, cands, ncands, lglcmpitecands);
+    lglcgextractitecands (lgl, lit, cands, ncands);
+  }
+  lglclnstk (&lgl->seen);
+  return !lglcgextractlimhit (lgl);
+}
+
+static int lglcgextractidx (LGL * lgl, int idx) {
+  if (!lglisfree (lgl, idx)) return 1;
+  if (lglavar (lgl, idx)->donotcgrcls) return 1;
+  if (lglcgextractlimhit (lgl)) return 0;
+  if (lglterminate (lgl)) return 0;
+  if (!lgl->mt && !lglcgextractands (lgl, idx)) return 0;
+  if (!lgl->mt && !lglcgextractands (lgl, -idx)) return 0;
+  if (!lgl->mt && !lglcgextractxors (lgl, idx)) return 0;
+  if (!lgl->mt && !lglcgextractxors (lgl, -idx)) return 0;
+  if (!lgl->mt && !lglcgextractites (lgl, idx)) return 0;
+  if (!lgl->mt && !lglcgextractites (lgl, -idx)) return 0;
+  return 1;
+}
+
+static void lglgateextract (LGL * lgl) {
+  int idx, count;
+  LOG (EL, "starting new extraction %d", lgl->stats->cgr.count);
+  lglrandidxtrav (lgl, lglcgextractidx);
+  count = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) count += lgl->avars[idx].gate;
+  if (lgl->cgr->extracted.units)
+    lglprt (lgl, 2, "[extract-%d] extracted %d units",
+      lgl->stats->cgr.count, lgl->cgr->extracted.units);
+  if (lgl->cgr->extracted.eq)
+    lglprt (lgl, 2, "[extract-%d] extracted %d equivalences",
+      lgl->stats->cgr.count, lgl->cgr->extracted.eq);
+  if (lgl->cgr->extracted.all)
+    lglprt (lgl, 2,
+      "[extract-%d] extracted %d gates for %d variables %.0f%%",
+      lgl->stats->cgr.count, lgl->cgr->extracted.all,
+      count, lglpcnt (count, lgl->nvars));
+  if (lgl->cgr->extracted.and)
+    lglprt (lgl, 2,
+      "[extract-%d] %d and gates %.0f%% of all extracted gates",
+      lgl->stats->cgr.count,
+      lgl->cgr->extracted.and, lglpcnt (lgl->cgr->extracted.and, lgl->cgr->extracted.all));
+  if (lgl->cgr->extracted.xor)
+    lglprt (lgl, 2,
+      "[extract-%d] %d xor gates %.0f%% of all extracted gates",
+      lgl->stats->cgr.count,
+      lgl->cgr->extracted.xor, lglpcnt (lgl->cgr->extracted.xor, lgl->cgr->extracted.all));
+  if (lgl->cgr->extracted.ite)
+    lglprt (lgl, 2,
+      "[extract-%d] %d ite gates %.0f%% of all extracted gates",
+      lgl->stats->cgr.count,
+      lgl->cgr->extracted.ite, lglpcnt (lgl->cgr->extracted.ite, lgl->cgr->extracted.all));
+}
+
+static void lglprtcgrem (LGL * lgl) {
+  int idx, ret = 0, rem = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotcgrcls) ret++; else rem++;
+  }
+  if (rem)
+    lglprt (lgl, 1, "[cgrclsr-%d] %d variables remain %.0f%% (%d retained)",
+           lgl->stats->cgr.count, rem, lglpcnt (rem, lglrem (lgl)), ret);
+  else {
+    lglprt (lgl, 1, "[cgrclsr-%d] fully completed congruence closure",
+           lgl->stats->cgr.count);
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donotcgrcls = 0;
+  }
+}
+
+static void lglcginit (LGL * lgl) {
+  int idx, schedulable = 0, donotcgrcls = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotcgrcls) donotcgrcls++;
+    else schedulable++;
+  }
+  if (!schedulable) {
+    donotcgrcls = 0;
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      if (!lglisfree (lgl, idx)) continue;
+      lglavar (lgl, idx)->donotcgrcls = 0;
+      schedulable++;
+    }
+  }
+  if (!donotcgrcls)
+    lglprt (lgl, 1, "[cgrclsr-%d] all %d free variables schedulable",
+            lgl->stats->cgr.count, schedulable);
+  else
+    lglprt (lgl, 1,
+      "[cgrclsr-%d] %d schedulable variables %.0f%%",
+      lgl->stats->cgr.count, schedulable, lglpcnt (schedulable, lglrem (lgl)));
+  lglwrkinit (lgl, 1, 1);
+  assert (!lgl->donotsched), lgl->donotsched = 1;
+  lglrandidxtrav (lgl, lglwrktouch);
+  assert (lgl->donotsched), lgl->donotsched = 0;
+  NEW (lgl->cgr->goccs, lgl->nvars);
+}
+
+static void lglcgreset (LGL * lgl) {
+  const int * p;
+  int idx;
+  for (idx = 2; idx < lgl->nvars; idx++) lgl->avars[idx].donotcgrcls = 1;
+  for (p = lgl->wrk->queue.start; p < lgl->wrk->queue.top; p++)
+    lgl->avars[abs (*p)].donotcgrcls = 0;
+  lglwrkreset (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++) lgl->avars[idx].gate = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) lglrelstk (lgl, lgl->cgr->goccs + idx);
+  DEL (lgl->cgr->goccs, lgl->nvars);
+  DEL (lgl->cgr->gates, lgl->cgr->szgates);
+  lgl->cgr->szgates = 0;
+}
+
+static void lglsetbinminrhs (LGL * lgl, Gat * g) {
+  int a = lglcgrepr (lgl, g->lits[0]);
+  int b = lglcgrepr (lgl, g->lits[1]);
+  assert (g->size == 2);
+  assert (g->tag != ITETAG);
+  if (abs (a) == 1 && abs (b) == 1) g->minrhs = INT_MAX;
+  else if (abs (a) == 1) g->minrhs = b;
+  else if (abs (b) == 1) g->minrhs = a;
+  else g->minrhs = (abs (a) < abs (b)) ? a : b;
+}
+
+static void lglsetlrgminrhs (LGL * lgl, Gat * g) {
+  int * p, other;
+  assert (g->size >= 3);
+  g->minrhs = INT_MAX;
+  for (p = g->cls; (other = *p); p++) {
+    if (abs (other) == abs (g->lhs)) continue;
+    other = lglcgrepr (lgl, other);
+    if (abs (other) == 1) continue;
+    if (abs (g->minrhs) > abs (other)) g->minrhs = other;
+  }
+  assert (g->minrhs);
+}
+
+static void lglsetiteminrhs (LGL * lgl, Gat * g) {
+  assert (g->tag == ITETAG);
+  g->minrhs = lglcgrepr (lgl, g->cond);
+}
+
+static void lglsetminrhs (LGL * lgl, Gat * g) {
+  if (g->tag == ITETAG) lglsetiteminrhs (lgl, g);
+  else if (g->size == 2) lglsetbinminrhs (lgl, g);
+  else lglsetlrgminrhs (lgl, g);
+  if (g->tag != ANDTAG && g->minrhs < 0) g->minrhs = -g->minrhs;
+}
+
+static int lglcmpgoccs (LGL * lgl, int a, int b) {
+  Gat * g = lglgidx2gat (lgl, a);
+  Gat * h = lglgidx2gat (lgl, b);
+  int res = (g->tag - h->tag); if (res) return res;
+  if ((res = (g->size - h->size))) return res;
+  if ((res = g->minrhs - h->minrhs)) return res;
+  return a - b;
+}
+
+#define LGLCMPGOCCS(A,B) lglcmpgoccs (lgl, *(A), *(B))
+
+static int lglgoccsmatchcand (LGL * lgl, int a, int b) {
+  Gat * g = lglgidx2gat (lgl, a);
+  Gat * h = lglgidx2gat (lgl, b);
+  return g->tag == h->tag && g->size == h->size && g->minrhs == h->minrhs;
+}
+
+static int lglmatchitegate (LGL * lgl, Gat * g, Gat * h) {
+  int gc = lglcgrepr (lgl, g->cond);
+  int gp = lglcgrepr (lgl, g->pos);
+  int gn = lglcgrepr (lgl, g->neg);
+  int hc = lglcgrepr (lgl, h->cond);
+  int hp = lglcgrepr (lgl, h->pos);
+  int hn = lglcgrepr (lgl, h->neg);
+  assert (g->tag == ITETAG);
+  assert (g->size == 2);
+  INCSTEPS (cgr.csteps);
+  if (gc == 1) {
+    if (hc == 1 && gp == hp) return 1;
+    if (hc == -1 && gp == hn) return 1;
+  } else if (gc == -1) {
+    if (hc == 1 && gn == hp) return 1;
+    if (hc == -1 && gn == hn) return 1;
+  } else if (gc == hc) {
+    if (gp == hp && gn == hn) return 1;
+    if (gp == -hp && gn == -hn) return -1;
+  } else if (gc == -hc) {
+    if (gp == hn && gn == hp) return 1;
+    if (gp == -hn && gn == -hp) return -1;
+  }
+  return 0;
+}
+
+static int lglmatchbingate (LGL * lgl, Gat * g, Gat * h) {
+  int g0 = lglcgrepr (lgl, g->lits[0]);
+  int g1 = lglcgrepr (lgl, g->lits[1]);
+  int h0 = lglcgrepr (lgl, h->lits[0]);
+  int h1 = lglcgrepr (lgl, h->lits[1]);
+  int sign;
+  INCSTEPS (cgr.csteps);
+  assert (g->size == 2);
+  if (g->tag == XORTAG) {
+    sign = 1;
+    if (g0 < 0) sign = -sign, g0 = -g0;
+    if (g1 < 0) sign = -sign, g1 = -g1;
+    if (h0 < 0) sign = -sign, h0 = -h0;
+    if (h1 < 0) sign = -sign, h1 = -h1;
+  } else sign = 1;
+  if (g0 == h0 && g1 == h1) return sign;
+  if (g0 == h1 && g1 == h0) return sign;
+  return 0;
+}
+
+static int lglmatchlrgandaux (LGL * lgl, Gat * g, Gat * h) {
+  int * p, other, repr, bit, res, jumped, gfalse, gtrue, htrue, hfalse;
+  int found;
+  AVar * u;
+  assert (g->tag == ANDTAG);
+  jumped = 1;
+  gtrue = 1, gfalse = 0;
+  found = 0;
+  for (p = g->cls; (other = *p); p++) {
+    INCSTEPS (cgr.csteps);
+    if (abs (other) == abs (g->origlhs)) {
+      assert (other == g->origlhs);
+      found++;
+      continue;
+    }
+    repr = lglcgrepr (lgl, -other);
+    if (repr == -1) { gfalse = 1; break; }
+    if (repr == 1) continue;
+    gtrue = 0;
+    if (repr != other) jumped = -1;
+    u = lglavar (lgl, repr);
+    bit = 1 << (repr < 0);
+    if (u->mark & (bit^3)) gfalse = 1;
+    if (u->mark & bit) continue;
+    u->mark |= bit;
+  }
+  assert (other || found);
+  res = 1;
+  htrue  = 1, hfalse = 0;
+  found = 0;
+  for (p = h->cls; res && (other = *p); p++) {
+    if (abs (other) == abs (h->origlhs)) {
+      found++;
+      assert (other == h->origlhs);
+      continue;
+    }
+    repr = lglcgrepr (lgl, -other);
+    if (repr == -1) { hfalse = 1; break; }
+    if (repr == 1) continue;
+    htrue = 0;
+    if (repr != other) jumped = -1;
+    u = lglavar (lgl, repr);
+    bit = 1 << (repr < 0);
+    if (!(u->mark & bit)) res = 0;
+  }
+  assert (!res || other || found);
+  found = 0;
+  for (p = g->cls; (other = *p); p++) {
+    if (abs (other) == abs (g->origlhs)) { found++; continue; }
+    repr = lglcgrepr (lgl, other);
+    if (abs (repr) == 1) continue;
+    u = lglavar (lgl, repr);
+    u->mark = 0;
+  }
+  assert (found);
+  if (gfalse) {
+    lglcgmergelhsrhs (lgl, g->lhs, -1);
+    res = 0;
+  } else if (res && gtrue) {
+    lglcgmergelhsrhs (lgl, g->lhs, 1);
+    res = 0;
+  }
+  if (hfalse) {
+    lglcgmergelhsrhs (lgl, h->lhs, -1);
+    res = 0;
+  } else if (htrue) {
+    lglcgmergelhsrhs (lgl, h->lhs, 1);
+    res = 0;
+  }
+  return jumped * res;
+}
+
+static int lglmatchlrgand (LGL * lgl, Gat * g, Gat * h) {
+  int res = lglmatchlrgandaux (lgl, g, h);
+  if (res >= 0) return res;
+  res = lglmatchlrgandaux (lgl, h, g);
+  return abs (res);
+}
+
+static int lglmatchlrgxor (LGL * lgl, Gat * g, Gat * h) {
+  int * p, other, repr, res, gconst, hconst, hpar, gpar, sign, found;
+  AVar * u;
+  gconst = 1, gpar = -1;
+  sign = 1;
+  found = 0;
+  for (p = g->cls; (other = *p); p++) {
+    INCSTEPS (cgr.csteps);
+    if (abs (other) == abs (g->origlhs)) {
+      assert (other == g->origlhs);
+      found++;
+      continue;
+    }
+    repr = lglcgrepr (lgl, other);
+    if (repr < 0) sign = -sign, gpar = -gpar;
+    if (abs (repr) == 1) continue;
+    else gconst = 0;
+    u = lglavar (lgl, repr);
+    u->mark = !u->mark;
+  }
+  assert (found);
+  hconst = 1, hpar = -1;
+  found = 0;
+  for (p = h->cls; (other = *p); p++) {
+    if (abs (other) == abs (h->origlhs)) {
+      assert (other == h->origlhs);
+      found++;
+      continue;
+    }
+    repr = lglcgrepr (lgl, other);
+    if (abs (repr) != 1) hconst = 0;
+    if (repr < 0) sign = -sign, hpar = -hpar;
+    if (abs (repr) == 1) continue;
+    else gconst = 0;
+    u = lglavar (lgl, repr);
+    u->mark = !u->mark;
+  }
+  assert (found);
+  res = 1;
+  found = 0;
+  for (p = g->cls; (other = *p); p++) {
+    if (abs (other) == abs (g->origlhs)) { found++; continue; }
+    repr = lglcgrepr (lgl, other);
+    if (abs (repr) == 1) continue;
+    u = lglavar (lgl, repr);
+    if (!u->mark) continue;
+    u->mark = 0;
+    res = 0;
+  }
+  assert (found);
+  found = 0;
+  for (p = h->cls; (other = *p); p++) {
+    if (abs (other) == abs (h->origlhs)) { found++; continue; }
+    repr = lglcgrepr (lgl, other);
+    if (abs (repr) == 1) continue;
+    u = lglavar (lgl, repr);
+    if (!u->mark) continue;
+    u->mark = 0;
+    res = 0;
+  }
+  assert (found);
+  if (gconst) {
+    lglcgmergelhsrhs (lgl, g->lhs, gpar);
+    res = 0;
+  }
+  if (hconst) {
+    lglcgmergelhsrhs (lgl, h->lhs, hpar);
+    res = 0;
+  }
+  return sign*res;
+}
+
+static int lglmatchgate (LGL * lgl, int fixed, Gat * g, Gat * h) {
+  int l = lglcgrepr (lgl, g->lhs);
+  int k = lglcgrepr (lgl, h->lhs);
+  int repr, other, s;
+  assert (g != h);
+  INCSTEPS (cgr.csteps);
+  assert (g->tag == h->tag);
+  assert (g->size == h->size);
+  assert (g->minrhs == h->minrhs);
+  assert (g->size >= 2);
+  if (g->tag == ITETAG) { if (!(s = lglmatchitegate (lgl, g, h))) return 0; }
+  else if (g->size == 2) { if (!(s = lglmatchbingate (lgl, g, h))) return 0; }
+  else if (g->tag == ANDTAG) { if (!(s = lglmatchlrgand (lgl, g, h))) return 0; }
+  else if (g->tag == XORTAG) { if (!(s = lglmatchlrgxor (lgl, g, h))) return 0; }
+  else return 0;
+  repr = s*l, other = k;
+  if (repr == other) return 0;
+  lgl->stats->cgr.matched.all++;
+  lgl->cgr->matched.all++;
+  if (g->tag == ANDTAG) lgl->cgr->matched.and++, lgl->stats->cgr.matched.and++;
+  if (g->tag == XORTAG) lgl->cgr->matched.xor++, lgl->stats->cgr.matched.xor++;
+  if (g->tag == ITETAG) lgl->cgr->matched.ite++, lgl->stats->cgr.matched.ite++;
+  if (repr == -other) {
+    assert (!lgl->mt);
+    LOG (1, "gate match to same literal only differing in sign");
+    lgl->mt = 1;
+    return 0;
+  }
+  LOG (1, "gates with lhs %d and %d match", g->lhs, h->lhs);
+  lglcgmerge (lgl, other, repr);
+  if (abs (fixed) == abs (other)) return 1;
+  if (abs (fixed) == abs (repr)) return 1;
+  return 0;
+}
+
+static int lglcgrlimhit (LGL * lgl) {
+  return lgl->stats->cgr.csteps >= lgl->limits->cgr.csteps;
+}
+
+static int lglsimpbinand (LGL * lgl, Gat * g) {
+  int lhs, a, b, res, conflict;
+  assert (g->tag == ANDTAG && g->size == 2);
+  lhs = lglcgrepr (lgl, g->lhs);
+  a = lglcgrepr (lgl, -g->lits[0]);
+  b = lglcgrepr (lgl, -g->lits[1]);
+  conflict = res = 0;
+  if (a == 1 && b == 1) {
+    if (lhs == 1) return 0;
+    res = 1;
+    LOG (2, "binary and gate with lhs %d simplified to true", g->lhs);
+    if (lhs == -1) conflict = 1; else conflict = !lglcgunit (lgl, lhs);
+  } else if (a == -1 || b == -1 || a == -b) {
+    if (lhs == -1) return 0;
+    res = 1;
+    LOG (2, "binary and gate with lhs %d simplified to false", g->lhs);
+    if (lhs == 1) conflict = 1; else conflict = !lglcgunit (lgl, -lhs);
+  } else {
+    if (b == 1) SWAP (int, a, b);
+    if (a == 1) {
+      if (lhs == b) return 0;
+      res = 1;
+      LOG (2, "binary and gate with lhs %d simplifies to %d", g->lhs, b);
+      if (lhs == -b) conflict = 1; else lglcgmerge (lgl, lhs, b);
+    }
+  }
+  if (res) {
+    lgl->cgr->simplified.all++;
+    lgl->stats->cgr.simplified.all++;
+    lgl->cgr->simplified.and++;
+    lgl->stats->cgr.simplified.and++;
+  }
+  if (conflict) {
+    LOG (1,
+      "simplifying binary and gate with lhs %d leads to conflict", g->lhs);
+    lgl->mt = 1;
+    assert (res);
+  }
+  return res;
+}
+
+static int lglsimplrgand (LGL * lgl, Gat * g) {
+  int * p, lhs, other, repr, conflict, res, foundfalse, rhs, bit, found;
+  AVar * u;
+  assert (g->tag == ANDTAG && g->size > 2);
+  lhs = lglcgrepr (lgl, g->lhs);
+  rhs = foundfalse = 0;
+  found = 0;
+  for (p = g->cls; !foundfalse && (other = *p); p++) {
+    if (other == g->origlhs) { found++; continue; }
+    INCSTEPS (cgr.csteps);
+    repr = lglcgrepr (lgl, -other);
+    if (repr == 1) continue;
+    if (repr == -1) { foundfalse = 1; break; }
+    if (rhs) rhs = INT_MAX; else { assert (repr); rhs = repr; }
+    u = lglavar (lgl, repr);
+    bit = (1 << (repr < 0));
+    if (u->mark & bit) continue;
+    if (u->mark & (bit^3)) { foundfalse = 1; break; }
+    u->mark |= bit;
+  }
+  assert (foundfalse || found);
+  for (p = g->cls; (other = *p); p++) {
+    if (other == g->origlhs) continue;
+    repr = lglcgrepr (lgl, other);
+    if (abs (repr) == 1) continue;
+    lglavar (lgl, repr)->mark = 0;
+  }
+  conflict = res = 0;
+  if (foundfalse) {
+    if (lhs != -1) {
+      res = 1;
+      LOG (2, "gate with lhs %d simplifies to false", g->lhs);
+      if (lhs == 1) conflict = 1; else conflict = !lglcgunit (lgl, -lhs);
+    }
+  } else if (!rhs) {
+    if (lhs != 1) {
+      res = 1;
+      LOG (2, "large and gate with lhs %d simplifies to true", g->lhs);
+      if (lhs == -1) conflict = 1; else conflict = !lglcgunit (lgl, lhs);
+    }
+  } else if (rhs != INT_MAX) {
+    if (lhs != rhs) {
+      res = 1;
+      LOG (2, "large and gate with lhs %d simplifies to %d", g->lhs, rhs);
+      if (lhs == -rhs) conflict = 1; else lglcgmerge (lgl, lhs, rhs);
+    }
+  }
+  if (res) {
+    lgl->cgr->simplified.all++;
+    lgl->stats->cgr.simplified.all++;
+    lgl->cgr->simplified.and++;
+    lgl->stats->cgr.simplified.and++;
+  }
+  if (conflict) {
+    LOG (1,
+      "simplifying large and gate with lhs %d leads to conflict", g->lhs);
+    lgl->mt = 1;
+    assert (res);
+  }
+  return res;
+}
+
+static int lglsimpand (LGL * lgl, Gat * g) {
+  assert (g->tag == ANDTAG);
+  if (g->size == 2) return lglsimpbinand (lgl, g);
+  else return lglsimplrgand (lgl, g);
+}
+
+static int lglsimpbinxor (LGL * lgl, Gat * g) {
+  int res, conflict, lhs, rhs, a, b;
+  assert (g->size == 2);
+  assert (g->tag == XORTAG);
+  lhs = -lglcgrepr (lgl, g->lhs);
+  a = lglcgrepr (lgl, g->lits[0]);
+  b = lglcgrepr (lgl, g->lits[1]);
+  rhs = conflict = res = 0;
+  if (a == b) rhs = -1;
+  else if (a == -b) rhs = 1;
+  else if (a == 1) rhs = -b;
+  else if (a == -1) rhs = b;
+  else if (b == 1) rhs = -a;
+  else if (b == -1) rhs = a;
+  else if (lhs == 1) lhs = a, rhs = -b;
+  else if (lhs == -1) lhs = a, rhs = b;
+  if (rhs && rhs != lhs) res = 1;
+  if (res) {
+    LOG (2, "simplified binary xor gate with lhs %d", g->lhs);
+    assert (rhs);
+    assert (lhs != rhs);
+    lgl->cgr->simplified.all++;
+    lgl->stats->cgr.simplified.all++;
+    lgl->cgr->simplified.xor++;
+    lgl->stats->cgr.simplified.xor++;
+    conflict = lglcgmergelhsrhs (lgl, lhs, rhs);
+  }
+  if (conflict) {
+    LOG (1,
+      "simplifying binary xor gate with lhs %d leads to conflict", g->lhs);
+    lgl->mt = 1;
+    assert (res);
+  }
+  return res;
+}
+
+static int lglsimplrgxor (LGL * lgl, Gat * g) {
+  int conflict, lhs, rhs, other, repr, * p, found;
+  assert (g->size > 2);
+  assert (g->tag == XORTAG);
+  lhs = -lglcgrepr (lgl, g->lhs);
+  rhs = -1;
+  found = 0;
+  for (p = g->cls; (other = *p); p++) {
+    if (other == g->origlhs) { found++; continue; }
+    repr = lglcgrepr (lgl, other);
+    if (repr == -1) continue;
+    else if (repr == 1) rhs = -rhs;
+    else if (repr == rhs) rhs = -1;
+    else if (repr == lhs) lhs = -1;
+    else if (repr == -lhs) lhs = 1;
+    else if (lhs == -1) lhs = repr;
+    else if (lhs == 1) lhs = -repr;
+    else if (abs (rhs) != 1) return 0;
+    else if (rhs == -1) rhs = repr;
+    else { assert (rhs == 1); rhs = -repr; }
+  }
+  assert (found);
+  if (lhs == rhs) return 0;
+  LOG (2, "simplified large xor gate with lhs %d", g->lhs);
+  assert (lhs != rhs);
+  lgl->cgr->simplified.all++;
+  lgl->stats->cgr.simplified.all++;
+  lgl->cgr->simplified.xor++;
+  lgl->stats->cgr.simplified.xor++;
+  conflict = lglcgmergelhsrhs (lgl, lhs, rhs);
+  if (conflict) {
+    LOG (1,
+      "simplifying large xor gate with lhs %d leads to conflict", g->lhs);
+    lgl->mt = 1;
+  }
+  return 1;
+}
+
+static int lglsimpxor (LGL * lgl, Gat * g) {
+  assert (g->tag == XORTAG);
+  if (g->size == 2) return lglsimpbinxor (lgl, g);
+  else return lglsimplrgxor (lgl, g);
+}
+
+static int lglsimpite (LGL * lgl, Gat * g) {
+  int glhs = g->lhs;
+  int lhs = lglcgrepr (lgl, glhs);
+  int gc = lglcgrepr (lgl, g->cond);
+  int gp = lglcgrepr (lgl, g->pos);
+  int gn = lglcgrepr (lgl, g->neg);
+  int res, conflict, rhs, gate;
+  assert (g->tag == ITETAG);
+  assert (g->size == 2);
+  gate = rhs = conflict = res = 0;
+  if (gc == 1 || gp == gn) res = 1, rhs = gp;
+  else if (gc == -1) res = 1, rhs = gn;
+  else if (gp == 1 && gn == -1) res = 1, rhs = gc;
+  else if (gp == -1 && gn == 1) res = 1, rhs = -gc;
+  else if (gn == -1 || gc == gn) {
+    // (lhs = gc ? gp : -1) => lhs = gc & gp
+    // (lhs = gc ? gp : gc) => lhs = gc & gp
+    // COVER ("simplified ite to 'gc & gp'");
+    if (gp == 1) res = 1, rhs = gc;
+    else if (gp == -1) {
+      assert (gn != -1 && gc == gn);
+      res = 1, rhs = -1;
+    } else {
+      res = lglnewbingate (lgl, ANDTAG, glhs, -gc, -gp);
+      gate = 1;
+    }
+  } else if (gp == -1 || gc == -gp) {
+    // (lhs = gc ? -1 : gn) => lhs = -gc & gn
+    // (lhs = gc ? -gc : gn) => lhs = -gc & gn
+    // COVER ("simplified ite to '-gc & gn'");
+    assert (gn != -1);
+    if (gn == 1) res = 1, rhs = -gc;
+    else {
+      assert (gn != -1);
+      res = lglnewbingate (lgl, ANDTAG, glhs, gc, -gn);
+      gate = 1;
+    }
+  } else if (gp == 1 || gc == gp) {
+    // (lhs = gc ? 1 : gn) => lhs = gc | gn
+    // (lhs = gc ? gp : gn) => lhs = gc | gn
+    // COVER ("simplified ite to 'gc | gn'");
+    if (gn == 1) res = 1, rhs = 1;
+    else {
+      assert (gn != -1);
+      res = lglnewbingate (lgl, ANDTAG, -glhs, gc, gn);
+      gate = 1;
+    }
+  } else if (gn == 1 || gc == -gn) {
+    // (lhs = gc ? gp : 1) => lhs = gc gp | -gc = gp | -gc
+    // (lhs = gc ? gp : -gc) => lhs = gc gp | -gc = gp | -gc
+    // COVER ("simplified ite to 'gp | -gc'");
+    if (gp == 1) res = 1, rhs = 1;
+    else {
+      assert (gp != -1);
+      res = lglnewbingate (lgl, ANDTAG, -glhs, gp, -gc);
+      gate = 1;
+    }
+  } else if (gp == -gn) {
+    // (lhs = gc ? -gn : gn) => lhs = gc&-gn | -gc&gn = gc ^ gn
+    // COVER ("simplified ite to 'gc ^ gn'");
+    res = lglnewbingate (lgl, XORTAG, -glhs, gc, gn);
+    gate = 1;
+  }
+  if (res && !gate && lhs == rhs) res = 0;
+  if (res && (gate || lhs != rhs)) {
+    LOG (2, "simplified ite gate with lhs %d", glhs);
+    lgl->cgr->simplified.all++;
+    lgl->stats->cgr.simplified.all++;
+    lgl->cgr->simplified.ite++;
+    lgl->stats->cgr.simplified.ite++;
+    if (!gate) {
+      assert (rhs);
+      assert (lhs != rhs);
+      if (lhs != rhs) conflict = lglcgmergelhsrhs (lgl, lhs, rhs);
+      else res = 0;
+    }
+  }
+  if (conflict) {
+    LOG (1, "simplifying ite gate with lhs %d leads to conflict", glhs);
+    lgl->mt = 1;
+    assert (res);
+  }
+  return res;
+}
+
+static int lglsimpgate (LGL * lgl,  Gat * g) {
+  if (g->tag == ANDTAG) return lglsimpand (lgl, g);
+  else if (g->tag == ITETAG) return lglsimpite (lgl, g);
+  else { assert (g->tag == XORTAG); return lglsimpxor (lgl, g); }
+}
+
+static void lglcgrlit (LGL * lgl, int lit) {
+  int * p, * q, * l, * r, round;
+  Gat * g, * h;
+  Stk * goccs;
+  round = 0;
+RESTART:
+  if (lgl->mt) return;
+  goccs = lgl->cgr->goccs + abs (lit);
+  if (lglmtstk (goccs)) return;
+  round++;
+  LOG (2, "simplifying gates with lhs %d", lit);
+  for (l = goccs->start; !lgl->mt && l < goccs->top; l++) {
+    INCSTEPS (cgr.csteps);
+    if (lglcgrlimhit (lgl)) return;
+    g = lglgidx2gat (lgl, *l);
+    if (lglsimpgate (lgl, g)) goto RESTART;// goccs->start moves
+  }
+  LOG (2,
+       "checking congruences of %d gates with rhs %d round %d",
+       lglcntstk (goccs), lit, round);
+  for (p = goccs->start; p < goccs->top; p++) {
+    INCSTEPS (cgr.csteps);
+    if (lglcgrlimhit (lgl)) return;
+    g = lglgidx2gat (lgl, *p);
+    lglsetminrhs (lgl, g);
+  }
+  SORT (int, goccs->start, lglcntstk (goccs), LGLCMPGOCCS);
+  q = goccs->start + 1;
+  for (p = q; p < goccs->top; p++) if (*p != q[-1]) *q++ = *p;
+  goccs->top = q;
+  for (l = goccs->start; !lgl->mt && l < goccs->top; l = r) {
+    INCSTEPS (cgr.csteps);
+    if (lglcgrlimhit (lgl)) return;
+    for (r = l + 1; r < goccs->top && lglgoccsmatchcand (lgl, *l, *r); r++)
+      ;
+    for (p = l; !lgl->mt && p + 1 < r; p++) {
+      g = lglgidx2gat (lgl, *p);
+      if (abs (lglcgrepr (lgl, g->lhs)) == 1) continue;
+      for (q = p + 1; !lgl->mt && q < r; q++) {
+       // if (lglsimpgate (lgl, g)) goto RESTART;// goccs->start moves
+       h = lglgidx2gat (lgl, *q);
+       if (abs (lglcgrepr (lgl, h->lhs)) == 1) continue;
+       if (lglsimpgate (lgl, h)) goto RESTART;// goccs->start moves
+       if (lglmatchgate (lgl, lit, g, h)) goto RESTART;// goccs->start moves
+      }
+    }
+  }
+}
+
+static void lglclsr (LGL * lgl) {
+  int lit;
+  while (!lgl->mt &&
+        !lglterminate (lgl) &&
+        (lit = lglwrknext (lgl)) &&
+        !lglcgrlimhit (lgl)) {
+    lglcgrlit (lgl, lit);
+    if (!lgl->mt && !lglcgrlimhit (lgl)) lglcgrlit (lgl, -lit);
+  }
+
+  if (lgl->cgr->simplified.all)
+    lglprt (lgl, 2, "[closure-%d] simplified %d gates",
+          lgl->stats->cgr.count, lgl->cgr->simplified.all);
+  if (lgl->cgr->simplified.and)
+    lglprt (lgl, 2, "[closure-%d] simplified %d and gates",
+           lgl->stats->cgr.count, lgl->cgr->simplified.and);
+  if (lgl->cgr->simplified.xor)
+    lglprt (lgl, 2, "[closure-%d] simplified %d xor gates",
+           lgl->stats->cgr.count, lgl->cgr->simplified.xor);
+  if (lgl->cgr->simplified.ite)
+    lglprt (lgl, 2, "[closure-%d] simplified %d ite gates",
+           lgl->stats->cgr.count, lgl->cgr->simplified.ite);
+
+  if (lgl->cgr->matched.all)
+    lglprt (lgl, 2, "[closure-%d] matched %d gates",
+           lgl->stats->cgr.count, lgl->cgr->matched.all);
+  if (lgl->cgr->matched.and)
+    lglprt (lgl, 2, "[closure-%d] matched %d and gates %.0f%%",
+           lgl->stats->cgr.count, lgl->cgr->matched.and,
+           lglpcnt (lgl->cgr->matched.and, lgl->cgr->matched.all));
+  if (lgl->cgr->matched.xor)
+    lglprt (lgl, 2, "[closure-%d] matched %d xor gates %.0f%%",
+           lgl->stats->cgr.count, lgl->cgr->matched.xor,
+           lglpcnt (lgl->cgr->matched.xor, lgl->cgr->matched.all));
+  if (lgl->cgr->matched.ite)
+    lglprt (lgl, 2, "[closure-%d] matched %d ite gates %.0f%%",
+           lgl->stats->cgr.count, lgl->cgr->matched.ite,
+           lglpcnt (lgl->cgr->matched.ite, lgl->cgr->matched.all));
+}
+
+static int lgladdunits (LGL * lgl) {
+  int idx, lit, repr;
+  Val val;
+  assert (!lgl->mt);
+  assert (lglmtstk (&lgl->cgr->units));
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    repr = lglcgrepr (lgl, idx);
+    if (abs (repr) >= 2) continue;
+    lit = (repr > 0) ? idx : -idx;
+    val = lglval (lgl, lit);
+    if (val > 0) continue;
+    if (val < 0) {
+      LOG (1, "inconsistent congruence closure unit %d", lit);
+      lgl->mt = 1;
+      return 0;
+    }
+    LOG (1, "adding congruence closure unit %d", lit);
+    lglpushstk (lgl, &lgl->cgr->units, lit);
+  }
+  return 1;
+}
+
+static int lglpropunits (LGL * lgl) {
+  int lit;
+  Val val;
+  assert (!lgl->mt);
+  assert (!lgl->level);
+  while (!lglmtstk (&lgl->cgr->units)) {
+    lit = lglpopstk (&lgl->cgr->units);
+    val = lglcval (lgl, lit);
+    if (val > 0) continue;
+    if (val < 0) {
+      LOG (1, "inconsistent congruence closure unit %d", lit);
+      lgl->mt = 1;
+    } else {
+      LOG (1, "assigning congruence closure unit %d", lit);
+      lglunitnocheck (lgl, lit);
+#if !defined(NLGLPICOSAT) && !defined(NDEBUG)
+      {
+       int cls[2]; cls[0] = lit; cls[1] = 0;
+       lglpicosataddcls (lgl, cls);
+      }
+#endif
+      if (lglbcp (lgl)) continue;
+      LOG (1, "conflict after assigning congruence closure unit %d", lit);
+      lgl->mt = 1;
+    }
+  }
+  return !lgl->mt;
+}
+
+static void lglsetcgrclsrlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->cgreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->cgrmineff.val) limit = lgl->opts->cgrmineff.val;
+  if (lgl->opts->cgrmaxeff.val >= 0 && limit > lgl->opts->cgrmaxeff.val)
+    limit = lgl->opts->cgrmaxeff.val;
+  limit >>= (pen = lgl->limits->cgr.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur/2;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[cgrclsr-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->cgr.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[cgrclsr-%d] limit %lld penalty %d = %d + %d",
+      lgl->stats->cgr.count, (LGLL) limit,
+      pen, lgl->limits->cgr.pen, lglszpen (lgl));
+  lgl->limits->cgr.esteps = lgl->stats->cgr.esteps + limit;
+  lgl->limits->cgr.csteps = lgl->stats->cgr.csteps + 2*limit;
+}
+
+static int lglcgrclsr (LGL * lgl) {
+  int nvars, oldrem, removed;
+
+  assert (lgl->opts->cgrclsr.val);
+  assert (lglsmallirr (lgl));
+  assert (!lgl->cgrclosing && !lgl->simp);
+
+  lglstart (lgl, &lgl->times->cgr);
+
+  oldrem = lglrem (lgl);
+
+  lgl->stats->cgr.count++;
+  lgl->cgrclosing = lgl->simp = 1;
+
+  NEW (lgl->cgr, 1);
+
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lglgc (lgl);
+
+  assert (lgl->frozen);
+  lgldense (lgl, 1);
+
+  nvars = lgl->nvars;
+  NEW (lgl->repr, nvars);
+
+  lglsetcgrclsrlim (lgl);
+
+  lglcginit (lgl);
+  lglgateextract (lgl);
+  if (!lgl->mt) lglclsr (lgl);
+  lglcgreset (lgl);
+
+  lglsparse (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgladdunits (lgl)) { assert (lgl->mt); goto DONE; }
+  lglchkred (lgl);
+  lgldcpdis (lgl);
+  lgldcpcln (lgl);
+  lgldcpcon (lgl);
+  lglcompact (lgl);
+  lglmap (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lglbcp (lgl)) goto DONE;
+  if (!lglpropunits (lgl)) { assert (lgl->mt); goto DONE; }
+  lglcount (lgl);
+  lglgc (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgl->mt) { lglpicosatchkall (lgl); lglpicosatrestart (lgl); }
+
+DONE:
+
+  lglrelstk (lgl, &lgl->cgr->units);
+  if (lgl->repr) { assert (lgl->mt); DEL (lgl->repr, nvars); }
+  removed = oldrem - lglrem (lgl);
+  LGLUPDPEN (cgr, removed);
+  DEL (lgl->cgr, 1);
+  assert (lgl->simp && lgl->cgrclosing);
+  lgl->cgrclosing = lgl->simp = 0;
+  lglprtcgrem (lgl);
+  lglprt (lgl, 1 + !removed,
+    "[cgrclsr-%d] removed %d variables", lgl->stats->cgr.count, removed);
+  lglrep (lgl, 2, 'C');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lglrandomprobe (LGL * lgl, Stk * outer) {
+  unsigned pos, delta, mod, first;
+  int res;
+  mod = lglcntstk (outer);
+  if (!mod) return 0;
+  first = pos = lglrand (lgl) % mod;
+  res = lglpeek (outer, pos);
+  if (!lglval (lgl, res)) return res;
+  if (mod == 1) return 0;
+  delta = lglrand (lgl) % mod;
+  if (!delta) delta++;
+  while (lglgcd (delta, mod) != 1)
+    if (++delta == mod) { delta = 1; break; }
+  assert (1 <= delta && delta < mod);
+  for (;;) {
+    pos += delta;
+    if (pos >= mod) pos -= mod;
+    assert (0 <= pos && pos < mod);
+    if (pos == first) break;
+    res = lglpeek (outer, pos);
+    if (!lglval (lgl, res)) return res;
+  }
+  return 0;
+}
+
+static int lglinnerprobe (LGL * lgl, int old,  Stk * outer,
+                          Stk * tmp1, Stk * tmp2) {
+  int i, lit, blit, tag, other, other2, red, lidx, res, val, count;
+  const int * w, * eow, * p, * c, * q;
+  HTS * hts;
+  assert (old < lglcntstk (&lgl->trail));
+  assert (!tmp2 || lglmtstk (tmp2));
+  for (p = tmp1->start; p < tmp1->top; p++) {
+    assert (!lglmarked (lgl, *p));
+    lglmark (lgl, *p);
+  }
+  for (i = old; i < lglcntstk (&lgl->trail); i++) {
+    lit = lglpeek (&lgl->trail, i);
+    hts = lglhts (lgl, -lit);
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    for (p = w; p < eow; p++) {
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      if (tag == BINCS) continue;
+      if (tag == TRNCS) {
+       other = blit >> RMSHFT;
+       if (lglval (lgl, other) > 0) continue;
+       other2 = *p;
+       if (lglval (lgl, other2) > 0) continue;
+       assert (!lglval (lgl, other));
+       assert (!lglval (lgl, other2));
+       other = abs (other);
+       if (!lglmarked (lgl, other)) {
+         lglmark (lgl, other);
+         lglpushstk (lgl, tmp1, other);
+         LOG (4, "potential inner probe %d for %d", other, lit);
+       }
+       other2 = abs (other2);
+       if (!lglmarked (lgl, other2)) {
+         lglmark (lgl, other2);
+         lglpushstk (lgl, tmp1, other2);
+         LOG (3, "potential inner probe %d for %d", other2, lit);
+       }
+      } else if (tmp2 && lgl->opts->liftlrg.val) {
+       assert (tag == LRGCS);
+       lidx = *p;
+       red = blit & REDCS;
+       c = lglidx2lits (lgl, red, lidx);
+       count = lgl->opts->liftlrg.val;
+       for (q = c; (other = *q) && count > 0; q++) {
+         if (other == -lit) continue;
+         assert (other != lit);
+         val = lglval (lgl, other);
+         if (val > 0) break;
+         if (!val) count--;
+       }
+       if (other) continue;
+       for (q = c; (other = *q); q++) {
+         if (other == -lit) continue;
+         assert (other != lit);
+         val = lglval (lgl, other);
+         COVER (!val);
+         if (val < 0) continue;
+         assert (!val);
+         if (lglmarked (lgl, other)) continue;
+         lglmark (lgl, other);
+         lglpushstk (lgl, tmp2, other);
+         LOG (3, "potential inner probe %d for %d", other, lit);
+       }
+      }
+    }
+  }
+  LOG (2, "found %d inner probes", lglcntstk (tmp1));
+  res = lglrandomprobe (lgl, tmp1);
+  lglpopnunmarkstk (lgl, tmp1);
+  if (!res) res = lglrandomprobe (lgl, outer);
+  if (tmp2)
+    for (p = tmp2->start; p < tmp2->top; p++) lglunmark (lgl, *p);
+  return res;
+}
+
+static void lglcleanrepr (LGL * lgl, Stk * represented, int * repr) {
+  int idx;
+  while (!lglmtstk (represented)) {
+    idx = lglpopstk (represented);
+    assert (2 <= idx && idx < lgl->nvars);
+    assert (repr[idx]);
+    repr[idx] = 0;
+  }
+}
+
+static void lgladdliftbincls (LGL * lgl, int a, int b) {
+  assert (lgl->lifting);
+  assert (lglmtstk (&lgl->clause));
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOG (2, "lifted binary clause", a, b);
+  if (lgl->opts->drup.val) lgldrupcls (lgl);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+  lgldrupligaddcls (lgl, REDCS);
+  lgladdcls (lgl, REDCS, 0, 1);
+  lglclnstk (&lgl->clause);
+  lgl->stats->lift.impls++;
+}
+
+static int64_t lglobalftlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->lftreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->lftmineff.val) limit = lgl->opts->lftmineff.val;
+  if (lgl->opts->lftmaxeff.val >= 0 && limit > lgl->opts->lftmaxeff.val)
+    limit = lgl->opts->lftmaxeff.val;
+  limit >>= (pen = lgl->limits->lft.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur/4;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[lift-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->lift.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[lift-%d] limit %lld with penalty %d = %d + %d",
+      lgl->stats->lift.count, (LGLL) limit,
+      pen, lgl->limits->lft.pen, lglszpen (lgl));
+  return limit;
+}
+
+static void lglprtlftrem (LGL * lgl) {
+  int idx, ret = 0, rem = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotlft) ret++; else rem++;
+  }
+  if (rem)
+    lglprt (lgl, 1, "[lift-%d] %d variables remain %.0f%% (%d retained)",
+           lgl->stats->lift.count, rem, lglpcnt (rem, lglrem (lgl)), ret);
+  else {
+    lglprt (lgl, 1, "[lift-%d] fully completed lifting",
+            lgl->stats->lift.count);
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donotlft = 0;
+  }
+}
+
+static int lgliftaux (LGL * lgl) {
+  int deltaunits, deltaimpls, origeqs, origunits, origimpls, units, impls, eqs;
+  int lit1, lit2, repr1, repr2, orepr1, orepr2, tobeprobed, notobeprobed;
+  int i, idx, lit, * reprs[3], first, outer, inner, round, branch;
+  Stk probes, represented[2], saved, tmp1, tmp2;
+  int ok, oldouter, dom, repr, other;
+  unsigned pos, delta, mod;
+  Val val, val1, val2;
+  int64_t global;
+#ifndef NDEBUG
+  int oldinner;
+#endif
+  assert (lgl->simp && lgl->lifting && !lgl->level);
+  NEW (lgl->repr, lgl->nvars);
+  CLR (probes); CLR (saved); CLR (tmp1); CLR (tmp2);
+  CLR (represented[0]); CLR (represented[1]);
+  NEW (reprs[0], lgl->nvars);
+  NEW (reprs[1], lgl->nvars);
+  NEW (reprs[2], lgl->nvars);
+  global = lgl->stats->visits.simp + lglobalftlim (lgl);
+  tobeprobed = notobeprobed = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotlft) notobeprobed++;
+    else if (lglhasbinortrn (lgl, idx) && lglhasbinortrn (lgl, -idx))
+      tobeprobed++;
+  }
+  if (!tobeprobed) {
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      if (!lglisfree (lgl, idx)) continue;
+      lglavar (lgl, idx)->donotlft = 0;
+      tobeprobed++;
+    }
+  }
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donotlft) continue;
+    if (!lglhasbinortrn (lgl, idx)) continue;
+    if (!lglhasbinortrn (lgl, -idx)) continue;
+    LOG (1, "new outer probe %d", idx);
+    lit = (lglrand (lgl) & 1) ? idx : -idx;
+    lglpushstk (lgl, &probes, lit);
+  }
+  mod = lglcntstk (&probes);
+  lglprt (lgl, 1, "[lift-%d] using %d probes %.0f%%",
+    lgl->stats->lift.count, mod, lglpcnt (mod, (lgl->nvars - 2)));
+  round = 1;
+  origimpls = impls = lgl->stats->lift.impls;
+  origunits = units = lgl->stats->lift.units;
+  origeqs = lgl->stats->lift.eqs;
+  if (!(mod)) goto DONE;
+  LOG (1, "found %u active outer probes out of %d variables %.1f%%",
+       mod, lgl->nvars - 1, lglpcnt (mod, lgl->nvars-1));
+  pos = lglrand (lgl)  % mod;
+  delta = lglrand (lgl) % mod;
+  if (!delta) delta++;
+  while (lglgcd (delta, mod) > 1)
+    if (++delta == mod) delta = 1;
+  LOG (1, "lifting start %u delta %u mod %u", pos, delta, mod);
+  first = 0;
+  assert (lgl->simp);
+  while (!lgl->mt) {
+    if (lgl->stats->visits.simp >= global) break;
+    if (lglterminate (lgl)) break;
+    if (!lglsyncunits (lgl)) break;
+    assert (pos < (unsigned) mod);
+    outer = probes.start[pos];
+    lglavar (lgl, outer)->donotlft = 1;
+    if (outer == first) {
+      assert (impls <= lgl->stats->lift.impls);
+      assert (units <= lgl->stats->lift.units);
+      deltaimpls = lgl->stats->lift.impls - impls;
+      deltaunits = lgl->stats->lift.units - units;
+      lglprt (lgl, 1, "[lift-%d-%d] found %d units %d impls in round %d",
+         lgl->stats->lift.count, round, deltaunits, deltaimpls, round);
+      impls = lgl->stats->lift.impls;
+      units = lgl->stats->lift.units;
+      if (round++ >= lgl->opts->lftroundlim.val) break;
+    }
+    if (!first) first = outer;
+    pos += delta;
+    if (pos >= mod) pos -= mod;
+    if (lglval (lgl, outer)) continue;
+    lgl->stats->lift.probed0++;
+    LOG (2, "1st outer branch %d during lifting", outer);
+    oldouter = lglcntstk (&lgl->trail);
+    lgliassume (lgl, outer);
+    ok = lglbcp (lgl);
+    if (!ok) {
+FIRST_OUTER_BRANCH_FAILED:
+      dom = lglprbana (lgl, outer);
+      LOG (1, "1st outer branch failed literal %d during lifting", outer);
+      lgl->stats->lift.units++;
+      lglbacktrack (lgl, 0);
+      lglunit (lgl, -dom);
+      if (lglbcp (lgl)) continue;
+      LOG (1, "empty clause after propagating outer probe during lifting");
+      assert (!lgl->mt);
+      lgl->mt = 1;
+      break;
+    }
+    lglclnstk (&tmp2);
+    inner = lglinnerprobe (lgl, oldouter, &probes, &tmp1, &tmp2);
+    assert (lglmtstk (&represented[0]));
+    if (!inner) {
+FIRST_OUTER_BRANCH_WIHOUT_INNER_PROBE:
+      LOG (2, "no inner probe for 1st outer probe %d", outer);
+      for (i = oldouter; i < lglcntstk (&lgl->trail); i++) {
+       lit = lglpeek (&lgl->trail, i);
+       idx = abs (lit);
+       assert (!reprs[0][idx]);
+       reprs[0][idx] = lglsgn (lit);
+       lglpushstk (lgl, &represented[0], idx);
+      }
+      assert (lgl->level == 1);
+      goto END_OF_FIRST_OUTER_BRANCH;
+    }
+#ifndef NDEBUG
+    oldinner = lglcntstk (&lgl->trail);
+#endif
+    LOG (2, "1st inner branch %d in outer 1st branch %d", inner, outer);
+    lgl->stats->lift.probed1++;
+    lgliassume (lgl, inner);
+    ok = lglbcp (lgl);
+    if (!ok) {
+      LOG (1, "1st inner branch failed literal %d on 1st outer branch %d",
+         inner, outer);
+      lglbacktrack (lgl, 1);
+      assert (lglcntstk (&lgl->trail) == oldinner);
+      lgladdliftbincls (lgl, -inner, -outer);
+      assert (lglcntstk (&lgl->trail) == oldinner + 1);
+      ok = lglbcp (lgl);
+      if (ok) goto FIRST_OUTER_BRANCH_WIHOUT_INNER_PROBE;
+      LOG (1, "conflict after propagating negation of 1st inner branch");
+      goto FIRST_OUTER_BRANCH_FAILED;
+    }
+    lglclnstk (&saved);
+    for (i = oldouter; i < lglcntstk (&lgl->trail); i++)
+      lglpushstk (lgl, &saved, lglpeek (&lgl->trail, i));
+    LOG (3, "saved %d assignments of 1st inner branch %d in 1st outer branch",
+        lglcntstk (&saved), inner, outer);
+    lglbacktrack (lgl, 1);
+    assert (lglcntstk (&lgl->trail) == oldinner);
+    LOG (2, "2nd inner branch %d in 1st outer branch %d", -inner, outer);
+    lgl->stats->lift.probed1++;
+    lgliassume (lgl, -inner);
+    ok = lglbcp (lgl);
+    if (!ok) {
+      LOG (2, "2nd inner branch failed literal %d on 1st outer branch %d",
+          -inner, outer);
+      lglbacktrack (lgl, 1);
+      assert (lglcntstk (&lgl->trail) == oldinner);
+      lgladdliftbincls (lgl, inner, -outer);
+      assert (lglcntstk (&lgl->trail) == oldinner + 1);
+      ok = lglbcp (lgl);
+      if (ok) goto FIRST_OUTER_BRANCH_WIHOUT_INNER_PROBE;
+      LOG (1, "conflict after propagating negation of 2nd inner branch");
+      goto FIRST_OUTER_BRANCH_FAILED;
+    }
+    while (!lglmtstk (&saved)) {
+      lit = lglpopstk (&saved);
+      idx = abs (lit);
+      val1 = lglsgn (lit);
+      val2 = lglval (lgl, idx);
+      if (val1 == val2) {
+       assert (!reprs[0][idx]);
+       reprs[0][idx] = val1;
+       lglpushstk (lgl, &represented[0], idx);
+      } else if (lit != inner && val1 == -val2) {
+       assert (lit != -inner);
+       repr = lglptrjmp (reprs[0], lgl->nvars-1, inner);
+       other = lglptrjmp (reprs[0], lgl->nvars-1, lit);
+       if (lglcmprepr (lgl, other, repr) < 0) SWAP (int, repr, other);
+       if (other < 0) other = -other, repr = -repr;
+       assert (!reprs[0][other]);
+       reprs[0][other] = repr;
+       lglpushstk (lgl, &represented[0], other);
+      } else assert (lit == inner || !val2);
+    }
+    lglbacktrack (lgl, 1);
+END_OF_FIRST_OUTER_BRANCH:
+    assert (lgl->level == 1);
+#ifndef NLGLOG
+    {
+      LOG (1, "start of 1st outer branch %d equivalences:", outer);
+      for (i = 0; i < lglcntstk (&represented[0]); i++) {
+       other = lglpeek (&represented[0], i);
+       repr = reprs[0][other];
+       LOG (1, "  1st branch equivalence %d : %d = %d", i + 1, other, repr);
+      }
+      LOG (1, "end of 1st outer branch %d equivalences.", outer);
+    }
+#endif
+    lglbacktrack (lgl, 0);
+    assert (lglcntstk (&lgl->trail) == oldouter);
+    lgl->stats->lift.probed0++;
+    LOG (2, "2nd outer branch %d during lifting", -outer);
+    lgliassume (lgl, -outer);
+    ok = lglbcp (lgl);
+    if (!ok) {
+SECOND_OUTER_BRANCH_FAILED:
+      dom = lglprbana (lgl, -outer);
+      LOG (1, "2nd branch outer failed literal %d during lifting", -outer);
+      lgl->stats->lift.units++;
+      lglbacktrack (lgl, 0);
+      lglunit (lgl, -dom);
+      if (lglbcp (lgl)) goto CONTINUE;
+      assert (!lgl->mt);
+      lgl->mt = 1;
+      goto CONTINUE;
+    }
+    assert (lglmtstk (&represented[1]));
+#ifndef NDEBUG
+    oldinner = lglcntstk (&lgl->trail);
+#endif
+    if (!inner || lglval (lgl, inner))
+      inner = lglinnerprobe (lgl, oldouter, &probes, &tmp2, 0);
+    if (!inner) {
+SECOND_OUTER_BRANCH_WIHOUT_INNER_PROBE:
+      LOG (2, "no inner probe for 2nd outer branch %d", -outer);
+      for (i = oldouter; i < lglcntstk (&lgl->trail); i++) {
+       lit = lglpeek (&lgl->trail, i);
+       idx = abs (lit);
+       assert (!reprs[1][idx]);
+       reprs[1][idx] = lglsgn (lit);
+       lglpushstk (lgl, &represented[1], idx);
+      }
+      assert (lgl->level == 1);
+      goto END_OF_SECOND_BRANCH;
+    }
+    LOG (2, "1st inner branch %d in outer 2nd branch %d", inner, -outer);
+    lgl->stats->lift.probed1++;
+    lgliassume (lgl, inner);
+    ok = lglbcp (lgl);
+    if (!ok) {
+      LOG (1, "1st inner branch failed literal %d on 2nd outer branch %d",
+          inner, -outer);
+      lglbacktrack (lgl, 1);
+      assert (lglcntstk (&lgl->trail) == oldinner);
+      lgladdliftbincls (lgl, -inner, outer);
+      assert (lglcntstk (&lgl->trail) == oldinner + 1);
+      ok = lglbcp (lgl);
+      if (ok) goto SECOND_OUTER_BRANCH_WIHOUT_INNER_PROBE;
+      LOG (1, "conflict after propagating negation of 1st inner branch");
+      goto SECOND_OUTER_BRANCH_FAILED;
+    }
+    lglclnstk (&saved);
+    for (i = oldouter; i < lglcntstk (&lgl->trail); i++)
+      lglpushstk (lgl, &saved, lglpeek (&lgl->trail, i));
+    LOG (3,
+        "saved %d assignments of 1st inner branch %d in 2nd outer branch %d",
+        lglcntstk (&saved), inner, -outer);
+    lglbacktrack (lgl, 1);
+    assert (lglcntstk (&lgl->trail) == oldinner);
+    LOG (2, "2nd inner branch %d in 2nd outer branch %d", -inner, -outer);
+    lgl->stats->lift.probed1++;
+    lgliassume (lgl, -inner);
+    ok = lglbcp (lgl);
+    if (!ok) {
+      LOG (1, "2nd inner branch failed literal %d on 2nd outer branch %d",
+          -inner, -outer);
+      lglbacktrack (lgl, 1);
+      assert (lglcntstk (&lgl->trail) == oldinner);
+      lgladdliftbincls (lgl, inner, outer);
+      assert (lglcntstk (&lgl->trail) == oldinner + 1);
+      ok = lglbcp (lgl);
+      if (ok) goto SECOND_OUTER_BRANCH_WIHOUT_INNER_PROBE;
+      LOG (1, "conflict after propagating negation of 2nd inner branch");
+      goto SECOND_OUTER_BRANCH_FAILED;
+    }
+    while (!lglmtstk (&saved)) {
+      lit = lglpopstk (&saved);
+      idx = abs (lit);
+      val1 = lglsgn (lit);
+      val2 = lglval (lgl, idx);
+      if (val1 == val2) {
+       assert (!reprs[1][idx]);
+       reprs[1][idx] = val1;
+       lglpushstk (lgl, &represented[1], idx);
+      } else if (lit != inner && val1 == -val2) {
+       assert (lit != -inner);
+       repr = lglptrjmp (reprs[1], lgl->nvars-1, inner);
+       other = lglptrjmp (reprs[1], lgl->nvars-1, lit);
+       if (lglcmprepr (lgl, other, repr) < 0) SWAP (int, repr, other);
+       if (other < 0) other = -other, repr = -repr;
+       assert (!reprs[1][other]);
+       reprs[1][other] = repr;
+       lglpushstk (lgl, &represented[1], other);
+      } else assert (lit == inner || !val2);
+    }
+    lglbacktrack (lgl, 1);
+END_OF_SECOND_BRANCH:
+    assert (lgl->level == 1);
+#ifndef NLGLOG
+    {
+      LOG (1, "start of 2nd outer branch %d equivalences:", -outer);
+      for (i = 0; i < lglcntstk (&represented[1]); i++) {
+       other = lglpeek (&represented[1], i);
+       repr = reprs[1][other];
+       LOG (1, "  2nd branch equivalence %d : %d = %d", i + 1, other, repr);
+      }
+      LOG (1, "end of 2nd outer branch %d equivalences.", outer);
+    }
+#endif
+    lglbacktrack (lgl, 0);
+    for (branch = 0; branch <= 1; branch++) {
+      assert (lglptrjmp (reprs[!branch], lgl->nvars-1, 1) == 1);
+      assert (lglptrjmp (reprs[!branch], lgl->nvars-1, -1) == -1);
+      for (i = 0; i < lglcntstk (&represented[branch]); i++) {
+       lit1 = lglpeek (&represented[branch], i);
+       assert (2 <= lit1 && lit1 < lgl->nvars);
+       lit2 = reprs[branch][lit1];
+       assert (lit2);
+       if (abs (lit2) == 1) {
+         val = lglval (lgl, lit1);
+         assert (!val || val == lit2);
+         if (val) continue;
+         repr1 = lglptrjmp (reprs[!branch], lgl->nvars-1, lit1);
+         if (repr1 != lit2) continue;
+         LOG (1, "  common constant equivalence : %d = %d  (branch %d)",
+              lit1, lit2, branch);
+         lglunit (lgl, lit2*lit1);
+         lgl->stats->lift.units++;
+       } else {
+         repr1 = lglptrjmp (reprs[2], lgl->nvars-1, lit1);
+         repr2 = lglptrjmp (reprs[2], lgl->nvars-1, lit2);
+         if (repr1 == repr2) continue;
+         orepr1 = lglptrjmp (reprs[!branch], lgl->nvars-1, lit1);
+         orepr2 = lglptrjmp (reprs[!branch], lgl->nvars-1, lit2);
+         if (orepr1 != orepr2) continue;
+         assert (abs (repr1) > 1 && abs (repr2) > 1);
+         if (lglcmprepr (lgl, repr2, repr1) < 0) SWAP (int, repr1, repr2);
+         if (repr2 < 0) repr2 = -repr2, repr1 = -repr1;
+         LOG (2, "  common equivalence candidate : %d = %d   (branch %d)",
+              repr2, repr1, branch);
+         reprs[2][repr2] = repr1;
+       }
+      }
+    }
+    if (!lglbcp (lgl)) lgl->mt = 1;
+CONTINUE:
+    assert (!lgl->level);
+    lglcleanrepr (lgl, &represented[0], reprs[0]);
+    lglcleanrepr (lgl, &represented[1], reprs[1]);
+  }
+  if (lgl->mt) goto DONE;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    (void) lglptrjmp (reprs[2], lgl->nvars-1, idx);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    repr = lglptrjmp (reprs[2], lgl->nvars-1, idx);
+    val = lglval (lgl, idx);
+    if (!val) continue;
+    if (repr == -val) {
+      LOG (1, "inconsistent assigned members of equivalence classe");
+      lgl->mt = 1;
+      goto DONE;
+    }
+    if (repr < 0) repr = -repr, val = -val;
+    if (repr == 1) { assert (val == 1); continue; }
+    reprs[2][repr] = val;
+  }
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    repr = lglptrjmp (reprs[2], lgl->nvars-1, idx);
+    assert (repr);
+    assert (repr != -idx);
+    if (repr == idx) continue;
+    if (abs (repr) == 1) continue;
+    lgl->stats->lift.eqs++;
+    LOG (1, "  real common equivalence : %d = %d", idx, repr);
+    lglimerge (lgl, idx, repr);
+  }
+DONE:
+  assert (origimpls <= lgl->stats->lift.impls);
+  assert (origunits <= lgl->stats->lift.units);
+  assert (origeqs <= lgl->stats->lift.eqs);
+  impls = lgl->stats->lift.impls - origimpls;
+  units = lgl->stats->lift.units - origunits;
+  eqs = lgl->stats->lift.eqs - origeqs;
+  lglprt (lgl, 1, "[lift-%d] %d units, %d impls, %d eqs in %d rounds",
+     lgl->stats->lift.count, units, impls, eqs, round);
+  assert (!lgl->level);
+  DEL (reprs[0], lgl->nvars);
+  DEL (reprs[1], lgl->nvars);
+  DEL (reprs[2], lgl->nvars);
+  lglrelstk (lgl, &probes);
+  lglrelstk (lgl, &represented[0]);
+  lglrelstk (lgl, &represented[1]);
+  lglrelstk (lgl, &saved);
+  lglrelstk (lgl, &tmp1);
+  lglrelstk (lgl, &tmp2);
+  if (lgl->mt) DEL (lgl->repr, lgl->nvars);
+  return !lgl->mt;
+}
+
+static int lglift (LGL * lgl) {
+  int oldrem = lglrem (lgl), removed;
+  assert (lgl->opts->lift.val);
+  lglstart (lgl, &lgl->times->lft);
+  assert (!lgl->lifting);
+  lgl->lifting = 1;
+  lgl->stats->lift.count++;
+  assert (!lgl->simp);
+  lgl->simp = 1;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  if (!lglbcp (lgl)) goto DONE;
+  lglgc (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgliftaux (lgl)) { assert (lgl->mt); goto DONE; }
+  if (!lglsynceqs (lgl)) { assert (lgl->mt); goto DONE; }
+  lglchkred (lgl);
+  lgldcpdis (lgl);
+  lgldcpcln (lgl);
+  lgldcpcon (lgl);
+  lglcompact (lgl);
+  lglmap (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lglbcp (lgl)) goto DONE;
+  lglcount (lgl);
+  lglgc (lgl);
+  if (lgl->mt) goto DONE;
+  if (!lgl->mt) { lglpicosatchkall (lgl); lglpicosatrestart (lgl); }
+DONE:
+  removed = oldrem - lglrem (lgl);
+  LGLUPDPEN (lft, removed);
+  assert (lgl->lifting && lgl->simp);
+  lgl->lifting = lgl->simp = 0;
+  lglprtlftrem (lgl);
+  lglprt (lgl, 1 + !removed,
+    "[lift-%d] removed %d variables", lgl->stats->lift.count, removed);
+  lglrep (lgl, 2, '^');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lgldstpull (LGL * lgl, int lit) {
+  AVar * av;
+  av = lglavar (lgl, lit);
+  assert ((lit > 0) == av->wasfalse);
+  if (av->mark) return 0;
+  if (!lglevel (lgl, lit)) return 0;
+  av->mark = 1;
+  if (lgldecision (lgl, lit)) {
+    lglpushstk (lgl, &lgl->clause, lit);
+    LOG (3, "added %d to learned clause", lit);
+  } else {
+    lglpushstk (lgl, &lgl->seen, -lit);
+    LOG (3, "pulled in distillation literal %d", -lit);
+  }
+  return 1;
+}
+
+static int lglanalit (LGL * lgl, int lit) {
+  int r0, r1, antecedents, other, next, tag, * p, * rsn;
+  AVar * av;
+  assert (lglmtstk (&lgl->seen));
+  assert (lglmtstk (&lgl->clause));
+  antecedents = 1;
+  av = lglavar (lgl, lit);
+  rsn = lglrsn (lgl, lit);
+  r0 = rsn[0], r1 = rsn[1];
+  LOGREASON (2, lit, r0, r1, "starting literal analysis for %d with", lit);
+  LOG (3, "added %d to learned clause", lit);
+  lglpushstk (lgl, &lgl->clause, lit);
+  assert ((lit < 0) == av->wasfalse);
+  assert (!av->mark);
+  av->mark = 1;
+  next = 0;
+  for (;;) {
+    tag = r0 & MASKCS;
+    if (tag == BINCS || tag == TRNCS) {
+      other = r0 >> RMSHFT;
+      lgldstpull (lgl, other);
+      if (tag == TRNCS) lgldstpull (lgl, r1);
+    } else if (tag == UNITCS) assert (!lglevel (lgl, lit));
+    else if (tag == DECISION) assert (lglavar (lgl, lit)->assumed);
+    else {
+      assert (tag == LRGCS);
+      for (p = lglidx2lits (lgl, (r0 & REDCS), r1); (other = *p); p++)
+       if (other != lit) lgldstpull (lgl, *p);
+    }
+    if (next == lglcntstk (&lgl->seen)) break;
+    lit = lglpeek (&lgl->seen, next++);
+    assert ((lit < 0) == lglavar (lgl, lit)->wasfalse);
+    rsn = lglrsn (lgl, lit);
+    r0 = rsn[0], r1 = rsn[1];
+    LOGREASON (2, lit, r0, r1, "literal analysis of");
+    antecedents++;
+  }
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  LOG (2, "literal analysis used %d antecedents", antecedents);
+  assert (lglcntstk (&lgl->clause) >= 1);
+  return antecedents;
+}
+
+static int lglfailedass (LGL * lgl) {
+  assert (lgl->level >= lgl->alevel);
+  return lgl->level == lgl->alevel && lgl->failed;
+}
+
+static void lglanafailed (LGL * lgl) {
+  int ilit, elit, erepr, failed, size;
+  unsigned bit, rbit, ibit, count;
+  Ext * ext, * rext;
+  const int * p;
+  AVar * av;
+  assert (lgl->mt || lglfailedass (lgl));
+  if (lgl->mt) {
+    LOG (1, "no failed assumptions since CNF unconditionally inconsistent");
+  } else if ((failed = lgl->failed) == -1) {
+    assert (!lgl->level);
+    elit = 0;
+    for (p = lgl->eassume.start; !elit && p < lgl->eassume.top; p++) {
+      erepr = lglerepr (lgl, *p);
+      if (lglederef (lgl, erepr) < 0) elit = *p;
+    }
+    assert (elit);
+    LOG (1, "found single external failed assumption %d", elit);
+    ext = lglelit2ext (lgl, elit);
+    assert (!ext->failed);
+    bit = 1u << (elit < 0);
+    assert (ext->assumed & bit);
+    ext->failed |= bit;
+  } else {
+    assert (abs (failed) > 1);
+    if ((av = lglavar (lgl, failed))->assumed == 3) {
+      LOG (1, "inconsistent internal assumptions %d and %d", failed, -failed);
+      assert (!av->failed);
+      av->failed = 3;
+    } else {
+      lglanalit (lgl, -failed);
+      for (p = lgl->clause.start; p < lgl->clause.top; p++) {
+       ilit = *p;
+       av = lglavar (lgl, ilit);
+       bit = (1u << (ilit > 0));
+       assert (av->assumed & bit);
+       assert (!(av->failed & bit));
+       av->failed |= bit;
+      }
+      size = lglcntstk (&lgl->clause);
+      assert (size > 0);
+      lglpushstk (lgl, &lgl->clause, 0);
+      lglprt (lgl, 2,
+        "[analyze-final] learned clause with size %d out of %d",
+        size, lglcntstk (&lgl->eassume));
+      LOGCLS (2, lgl->clause.start, "failed assumption clause");
+      lgldrupligaddcls (lgl, REDCS);
+      lgladdcls (lgl, REDCS, size, 0);
+      lglpopstk (&lgl->clause);
+      lglpopnunmarkstk (lgl, &lgl->clause);
+    }
+    count = 0;
+    for (p = lgl->eassume.start; p < lgl->eassume.top; p++) {
+      elit =  *p;
+      bit = 1u << (elit < 0);
+      ext = lglelit2ext (lgl, elit);
+      assert (!ext->eliminated && !ext->blocking);
+      assert (ext->assumed & bit);
+      if (ext->failed & bit) continue;
+      if (ext->equiv) {
+       erepr = ext->repr;
+       rbit = bit;
+       if (erepr < 0) rbit ^= 3;
+       if (elit < 0) erepr = -erepr;
+       rext = lglelit2ext (lgl, erepr);
+       assert (!rext->equiv);
+       if (rext->failed & rbit) continue;
+       ilit = rext->repr;
+       ibit = rbit;
+       if (ilit < 0) ilit = -ilit, ibit ^= 3;
+       if (ilit == 1) continue;
+       assert (ilit && ilit != -1);
+       av = lglavar (lgl, ilit);
+       if (!(av->failed & ibit)) continue;
+       rext->failed |= rbit;
+       count++;
+       if (rext->assumed & rbit) {
+         LOG (2,
+              "found representative external failed assumption %d",
+              erepr);
+       } else {
+         LOG (2,
+              "found non representative external failed assumption %d",
+              elit);
+         ext->failed |= bit;
+       }
+      } else {
+       ilit = ext->repr;
+       ibit = bit;
+       if (ilit < 0) ilit = -ilit, ibit ^= 3;
+       if (ilit == 1) continue;
+       assert (ilit && ilit != -1);
+       av = lglavar (lgl, ilit);
+       if (!(av->failed & ibit)) continue;
+       LOG (2, "found external failed assumption %d", elit);
+       ext->failed |= bit;
+       count++;
+      }
+    }
+    LOG (1, "found %u external failed assumptions", count);
+  }
+  TRANS (FAILED);
+}
+
+static void lglternreslit (LGL * lgl, int lit) {
+  int * pw, * peow, * nw, * neow, * p, * n;
+  int pblit, ptag, pother, pother2, pdelta;
+  int nblit, ntag, nother, nother2, ndelta;
+  HTS * phts, * nhts;
+  int a, b, c;
+
+  phts = lglhts (lgl, lit);
+  pw = lglhts2wchs (lgl, phts);
+  peow = pw + phts->count;
+  nhts = lglhts (lgl, -lit);
+  nw = lglhts2wchs (lgl, nhts);
+  neow = nw + nhts->count;
+  for (n = nw; n < neow; n++) {
+    if (INCSTEPS (trnr.steps) >= lgl->limits->trnr.steps) return;
+    nblit = *n;
+    ntag = nblit & MASKCS;
+    if (ntag == BINCS || ntag == OCCS) continue;
+    if (ntag == TRNCS) break;
+    assert (ntag == LRGCS);
+    n++;
+  }
+  if (n >= neow) return;
+  for (p = pw;
+       p < peow && lgl->stats->trnr.steps < lgl->limits->trnr.steps;
+       p++) {
+    INCSTEPS (trnr.steps);
+    pblit = *p;
+    ptag = pblit & MASKCS;
+    if (ptag == BINCS || ptag == OCCS) continue;
+    if (ptag == TRNCS || ptag == LRGCS) p++;
+    if (ptag == LRGCS) continue;
+    assert (ptag == TRNCS);
+    pother = pblit >> RMSHFT;
+    if (lglval (lgl, pother)) continue;
+    pother2 = *p;
+    if (lglval (lgl, pother2)) continue;
+    for (n = nw;
+        n < neow && lgl->stats->trnr.steps < lgl->limits->trnr.steps;
+        n++) {
+      INCSTEPS (trnr.steps);
+      nblit = *n;
+      ntag = nblit & MASKCS;
+      if (ntag == BINCS || ntag == OCCS) continue;
+      if (ntag == TRNCS || ntag == LRGCS) n++;
+      if (ntag == LRGCS) continue;
+      assert (ntag == TRNCS);
+      nother = nblit >> RMSHFT;
+      if (lglval (lgl, nother)) continue;
+      nother2 = *n;
+      if (lglval (lgl, nother2)) continue;
+      if ((nother == pother && nother2 == pother2) ||
+         (nother == pother2 && nother2 == pother)) {
+       a = nother, b = nother2;
+       if (lglhasbin (lgl, a, b)) continue;
+       lgl->stats->trnr.bin++;
+       LOG (2, "ternary resolvent %d %d", a, b);
+        if (lgl->opts->drup.val) lgldrupclsarg (lgl, a, b, 0);
+#ifndef NLGLPICOSAT
+       lglpicosatchkclsarg (lgl, a, b, 0);
+#endif
+       lglwchbin (lgl, a, b, REDCS);
+       lglwchbin (lgl, b, a, REDCS);
+       lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+       lglwrktouch (lgl, a);
+       lglwrktouch (lgl, b);
+      } else {
+       a = nother, b = nother2;
+       if (nother == pother || nother2 == pother) c = pother2;
+       else if (nother == pother2 || nother2 == pother2) c = pother;
+       else continue;
+       assert (a != b && b != c && a != c);
+       assert (a != -b);
+       if (a == -c || b == -c) continue;
+       if (lglhastrn (lgl, a, b, c)) continue;
+       lgl->stats->trnr.trn++;
+       LOG (2, "ternary resolvent %d %d %d", a, b, c);
+        if (lgl->opts->drup.val) lgldrupclsarg (lgl, a, b, c, 0);
+#ifndef NLGLPICOSAT
+       lglpicosatchkclsarg (lgl, a, b, c, 0);
+#endif
+       lglwchtrn (lgl, a, b, c, REDCS);
+       lglwchtrn (lgl, b, a, c, REDCS);
+       lglwchtrn (lgl, c, a, b, REDCS);
+       lgl->stats->red.trn++, assert (lgl->stats->red.trn > 0);
+       lglwrktouch (lgl, a);
+       lglwrktouch (lgl, b);
+       lglwrktouch (lgl, c);
+      }
+      pdelta = p - pw;
+      phts = lglhts (lgl, lit);
+      pw = lglhts2wchs (lgl, phts);
+      peow = pw + phts->count;
+      p = pw + pdelta;
+      ndelta = n - nw;
+      nhts = lglhts (lgl, -lit);
+      nw = lglhts2wchs (lgl, nhts);
+      neow = nw + nhts->count;
+      n = nw + ndelta;
+    }
+  }
+}
+
+static void lglternresidx (LGL * lgl, int idx) {
+  lglternreslit (lgl, idx);
+  lglternreslit (lgl, -idx);
+}
+
+static void lglseternreslim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  if (lgl->opts->ternresrtc.val) {
+    lgl->limits->trnr.steps = LLMAX;
+    lglprt (lgl, 1, "[ternres-%d] no limit (run to completion)",
+           lgl->stats->trnr.count);
+  } else {
+    limit = (lgl->opts->trnreleff.val*lglvisearch (lgl))/1000;
+    if (limit < lgl->opts->trnrmineff.val) limit = lgl->opts->trnrmineff.val;
+    if (lgl->opts->trnrmaxeff.val >= 0 && limit > lgl->opts->trnrmaxeff.val)
+      limit = lgl->opts->trnrmaxeff.val;
+    if (lgl->stats->trnr.count <= 1 &&
+        lgl->opts->boost.val &&
+        lgl->opts->ternresboost.val > 1) {
+      lglprt (lgl, 1,
+        "[ternres-%d] boosting ternary resolution limit by %d",
+       lgl->stats->trnr.count, lgl->opts->ternresboost.val);
+      limit *= lgl->opts->ternresboost.val;
+    }
+    limit >>= (pen = lgl->limits->trnr.pen + lglszpen (lgl));
+    irrlim = 4*lgl->stats->irr.clauses.cur;
+    irrlim >>= lgl->limits->simp.pen;
+    if (lgl->opts->irrlim.val && limit < irrlim) {
+      limit = irrlim;
+      lglprt (lgl, 1,
+        "[ternres-%d] limit %lld based on %d irredundant clauses",
+       lgl->stats->trnr.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+    } else
+      lglprt (lgl, 1, "[ternres-%d] limit %lld with penalty %d = %d + %d",
+       lgl->stats->trnr.count, (LGLL) limit,
+       pen, lgl->limits->trnr.pen, lglszpen (lgl));
+    lgl->limits->trnr.steps = lgl->stats->trnr.steps + limit;
+  }
+}
+
+static void lglprternresrem (LGL * lgl) {
+  int idx, ret = 0, rem = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donoternres) ret++; else rem++;
+  }
+  if (rem)
+    lglprt (lgl, 1, "[ternres-%d] %d variables remain %.0f%% (%d retained)",
+           lgl->stats->trnr.count, rem, lglpcnt (rem, lglrem (lgl)), ret);
+  else {
+    lglprt (lgl, 1, "[ternres-%d] fully completed ternary resolution",
+           lgl->stats->trnr.count);
+    for (idx = 2; idx < lgl->nvars; idx++)
+      lglavar (lgl, idx)->donoternres = 0;
+  }
+}
+
+static void lglternresinit (LGL * lgl) {
+  int idx, schedulable = 0, donoternres = 0;
+  lglwrkinit (lgl, 1, 1);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    if (lglavar (lgl, idx)->donoternres) donoternres++;
+    else schedulable++;
+  }
+  if (!schedulable) {
+    donoternres = 0;
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      if (!lglisfree (lgl, idx)) continue;
+      lglavar (lgl, idx)->donoternres = 0;
+      schedulable++;
+    }
+  }
+  if (!donoternres)
+    lglprt (lgl, 1, "[ternres-%d] all %d free variables schedulable",
+            lgl->stats->trnr.count, schedulable);
+  else
+    lglprt (lgl, 1,
+      "[ternres-%d] %d schedulable variables %.0f%%",
+      lgl->stats->trnr.count, schedulable, lglpcnt (schedulable, lgl->nvars-2));
+  assert (!lgl->donotsched), lgl->donotsched = 1;
+  lglrandidxtrav (lgl, lglwrktouch);
+  assert (lgl->donotsched), lgl->donotsched = 0;
+}
+
+static int lglternres (LGL * lgl) {
+  int before, after, delta;
+  int before2, after2, delta2;
+  int before3, after3, delta3;
+  int success, lit;
+  if (lgl->nvars <= 2) return 1;
+  lglstart (lgl, &lgl->times->trn);
+  ASSERT (!lgl->simp && !lgl->ternresing);
+  lgl->simp = lgl->ternresing = 1;
+  lgl->stats->trnr.count++;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lglseternreslim (lgl);
+
+  lglternresinit (lgl);
+
+  before2 = lgl->stats->trnr.bin;
+  before3 = lgl->stats->trnr.trn;
+  while (lgl->stats->trnr.steps < lgl->limits->trnr.steps) {
+    if (lglterminate (lgl)) break;
+    if (!lglsyncunits (lgl)) break;
+    if (!(lit = lglwrknext (lgl))) {
+      lglprt (lgl, 2,  "[ternres-%d] saturated", lgl->stats->trnr.count);
+      break;
+    }
+    INCSTEPS (trnr.steps);
+    assert (lit > 0);
+    if (!lglisfree (lgl, lit)) continue;
+    lglavar (lgl, lit)->donoternres = 1;
+    lglternresidx (lgl, lit);
+  }
+  after2 = lgl->stats->trnr.bin;
+  after3 = lgl->stats->trnr.trn;
+  after = after2 + after3;
+  before = before2 + before3;
+  delta2 = after2 - before2;
+  delta3 = after3 - before3;
+  delta = after - before;
+  success = before < after;
+  lglprt (lgl, 1, "[ternres-%d] %d ternary resolvents (%d bin, %d trn)",
+          lgl->stats->trnr.count, delta, delta2, delta3);
+  LGLUPDPEN (trnr, success);
+  assert (lgl->simp && lgl->ternresing);
+  lgl->simp = lgl->ternresing = 0;
+  lglprternresrem (lgl);
+  lglrep (lgl, 2, 'T');
+  lglwrkreset (lgl);
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lgltrdbin (LGL * lgl, int start, int target, int irr) {
+  int lit, next, blit, tag, red, other, * p, * w, * eow, res, ign, val;
+  HTS * hts;
+  assert (lglmtstk (&lgl->seen));
+  assert (abs (start) < abs (target));
+  LOG (2, "trying transitive reduction of %s binary clause %d %d",
+       lglred2str (irr^REDCS), start, target);
+  lgl->stats->trd.bins++;
+  lglpushnmarkseen (lgl, -start);
+  next = 0;
+  res = 0;
+  ign = 1;
+  while (next < lglcntstk (&lgl->seen)) {
+    lit = lglpeek (&lgl->seen, next++);
+    INCSTEPS (trd.steps);
+    LOG (3, "transitive reduction search step %d", lit);
+    val = lglval (lgl, lit);
+    if (val) continue;
+    hts = lglhts (lgl, -lit);
+    if (!hts->count) continue;
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    for (p = w; p < eow; p++) {
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == LRGCS || tag == TRNCS) p++;
+      if (tag != BINCS) continue;
+      red = blit & REDCS;
+      if (irr && red) continue;
+      other = blit >> RMSHFT;
+      if (other == start) continue;
+      if (other == target) {
+       if (lit == -start && ign) { ign = 0; continue; }
+       LOG (2, "transitive path closed with %s binary clause %d %d",
+            lglred2str (red), -lit, other);
+       res = 1;
+       goto DONE;
+      }
+      val = lglmarked (lgl, other);
+      if (val > 0) continue;
+      if (val < 0) {
+       assert (lgl->level == 0);
+       lgl->stats->trd.failed++;
+       LOG (1, "failed literal %d in transitive reduction", -start);
+       lglunit (lgl, start);
+       val = lglbcp (lgl);
+       if (!val && !lgl->mt) lgl->mt = 1;
+       assert (val || lgl->mt);
+       res = -1;
+       goto DONE;
+      }
+      lglpushnmarkseen (lgl, other);
+      LOG (3, "transitive reduction follows %s binary clause %d %d",
+          lglred2str (red), -lit, other);
+    }
+  }
+DONE:
+  lglpopnunmarkstk (lgl, &lgl->seen);
+  return res;
+}
+
+static void lgltrdlit (LGL * lgl, int start) {
+  int target, * w, * p, * eow, blit, tag, red, val;
+#ifndef NDEBUG
+  int unassigned = lgl->unassigned;
+#endif
+  HTS * hts;
+  val = lglval (lgl, start);
+  if (val) return;
+  LOG (2, "transitive reduction of binary clauses with %d", start);
+  assert (lglmtstk (&lgl->seen));
+  hts = lglhts (lgl, start);
+  if (!hts->count) return;
+  lgl->stats->trd.lits++;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w;
+       p < eow && (lgl->stats->trd.steps < lgl->limits->trd.steps);
+       p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    target = blit >> RMSHFT;
+    if (abs (start) > abs (target)) continue;
+    red = blit & REDCS;
+    val = lgltrdbin (lgl, start, target, red^REDCS);
+    if (!val) continue;
+    if (val < 0) { assert (lgl->mt || lgl->unassigned < unassigned); break; }
+    LOG (2, "removing transitive redundant %s binary clause %d %d",
+        lglred2str (red), start, target);
+    lgl->stats->trd.red++;
+    lgl->stats->prgss++;
+    lglrmbwch (lgl, start, target, red);
+    lglrmbwch (lgl, target, start, red);
+    assert (!lgl->dense);
+    if (red) assert (lgl->stats->red.bin > 0), lgl->stats->red.bin--;
+    else lgldecirr (lgl, 2);
+    break;
+  }
+}
+
+static void lglsetrdlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->trdreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->trdmineff.val) limit = lgl->opts->trdmineff.val;
+  if (lgl->opts->trdmaxeff.val >= 0 && limit > lgl->opts->trdmaxeff.val)
+    limit = lgl->opts->trdmaxeff.val;
+  limit >>= (pen = lgl->limits->trd.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[transred-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->trd.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[transred-%d] limit %lld with penalty %d = %d + %d",
+      lgl->stats->trd.count, (LGLL) limit,
+      pen, lgl->limits->trd.pen, lglszpen (lgl));
+  lgl->limits->trd.steps = lgl->stats->trd.steps + limit;
+}
+
+static int lgltrd (LGL * lgl) {
+  unsigned pos, delta, mod, ulit, first, last;
+  int failed = lgl->stats->trd.failed;
+  int red = lgl->stats->trd.red;
+  int lit, count, success;
+  if (lgl->nvars <= 2) return 1;
+  lgl->stats->trd.count++;
+  lglstart (lgl, &lgl->times->trd);
+  assert (!lgl->simp);
+  lgl->simp = 1;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lglsetrdlim (lgl);
+  mod = 2*(lgl->nvars - 2);
+  assert (mod > 0);
+  pos = lglrand (lgl) % mod;
+  delta = lglrand (lgl) % mod;
+  if (!delta) delta++;
+  while (lglgcd (delta, mod) > 1)
+    if (++delta == mod) delta = 1;
+  LOG (1, "transitive reduction start %u delta %u mod %u", pos, delta, mod);
+  first = mod;
+  count = 0;
+  while (lgl->stats->trd.steps < lgl->limits->trd.steps) {
+    if (lglterminate (lgl)) break;
+    if (!lglsyncunits (lgl)) break;
+    ulit = pos + 4;
+    lit = lglilit (ulit);
+    lgltrdlit (lgl, lit);
+    count++;
+    assert (count <= mod);
+    if (lgl->mt) break;
+    last = pos;
+    pos += delta;
+    if (pos >= mod) pos -= mod;
+    if (pos == first) { assert (count == mod); break; }
+    if (mod == 1) break;
+    if (first == mod) first = last;
+  }
+  failed = lgl->stats->trd.failed - failed;
+  red = lgl->stats->trd.red - red;
+  success = failed || red;
+  LGLUPDPEN (trd, success);
+  assert (lgl->simp);
+  lglprt (lgl, 1,
+    "[transred-%d] removed %d transitive binary clauses",
+    lgl->stats->trd.count, red);
+  lglprt (lgl, 1 + !failed,
+    "[transred-%d] found %d units",
+    lgl->stats->trd.count, failed);
+  lgl->simp = 0;
+  lglrep (lgl, 2, 't');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lglunhdhasbins (LGL * lgl, const DFPR * dfpr,
+                          int lit, int irronly) {
+  int blit, tag, other, val, red, ulit;
+  const int * p, * w, * eos;
+  HTS * hts;
+  assert (!lglval (lgl, lit));
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eos = w + hts->count;
+  for (p = w; p < eos; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == OCCS) continue;
+    if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+    red = blit & REDCS;
+    if (irronly && red) continue;
+    other = blit >> RMSHFT;
+    val = lglval (lgl, other);
+    assert (val >= 0);
+    if (val > 0) continue;
+    ulit = lglulit (other);
+    if (!dfpr[ulit].discovered) return 1;
+  }
+  return 0;
+}
+
+static int lglunhdisroot (LGL * lgl, int lit, DFPR * dfpr, int irronly) {
+  int res = !lglunhdhasbins (lgl, dfpr, lit, irronly);
+  assert (!res || !dfpr[lglulit (lit)].discovered);
+  return res;
+}
+
+static int lglmtwtk (Wtk * wtk) { return wtk->top == wtk->start; }
+
+static int lglfullwtk (Wtk * wtk) { return wtk->top == wtk->end; }
+
+static int lglsizewtk (Wtk * wtk) { return wtk->end - wtk->start; }
+
+static int lglcntwtk (Wtk * wtk) { return wtk->top - wtk->start; }
+
+static void lglrelwtk (LGL * lgl, Wtk * wtk) {
+  DEL (wtk->start, lglsizewtk (wtk));
+  memset (wtk, 0, sizeof *wtk);
+}
+
+static void lglenlwtk (LGL * lgl, Wtk * wtk) {
+  int oldsize = lglsizewtk (wtk);
+  int newsize = oldsize ? 2*oldsize : 1;
+  int count = lglcntwtk (wtk);
+  RSZ (wtk->start, oldsize, newsize);
+  wtk->top = wtk->start + count;
+  wtk->end = wtk->start + newsize;
+}
+
+static void lglpushwtk (LGL * lgl, Wtk * wtk,
+                       Wrag wrag, int lit, int other, int red) {
+  Work w;
+  if (lglfullwtk (wtk)) lglenlwtk (lgl, wtk);
+  w.wrag = wrag;
+  w.other = other;
+  w.red = red ? 1 : 0;
+  w.removed = 0;
+  w.lit = lit;
+  *wtk->top++ = w;
+}
+
+static int lglstamp (LGL * lgl, int root,
+                    DFPR * dfpr, DFOPF * dfopf,
+                    Wtk * work, Stk * units, Stk * sccs, Stk * trds,
+                    int * visitedptr, int stamp, int irronly) {
+  int uroot, lit, ulit, blit, tag, red, other, failed, uother, unotother;
+  int observed, discovered, pos, undiscovered;
+  unsigned start, end, mod, i, j, sccsize;
+  const int * p, * w, * eos;
+  int startstamp;
+  const Work * r;
+  int removed;
+  HTS * hts;
+  Wrag wrag;
+  if (lglval (lgl, root)) return stamp;
+  uroot =  lglulit (root);
+  if (dfpr[uroot].discovered) return stamp;
+  assert (!dfpr[uroot].finished);
+  assert (lglmtwtk (work));
+  assert (lglmtstk (units));
+  assert (lglmtstk (sccs));
+  assert (lglmtstk (trds));
+  LOG (3, "stamping dfs %s %d %s",
+       (lglunhdisroot (lgl, root, dfpr, irronly) ? "root" : "start"), root,
+       irronly ? "only over irredundant clauses" :
+                "also over redundant clauses");
+  startstamp = 0;
+  lglpushwtk (lgl, work, PREFIX, root, 0, 0);
+  while (!lglmtwtk (work)) {
+    INCSTEPS (unhd.steps);
+    LGLPOPWTK (work, wrag, lit, other, red, removed);
+    if (removed) continue;
+    if (wrag == PREFIX) {
+      ulit = lglulit (lit);
+      if (dfpr[ulit].discovered) {
+       dfopf[ulit].observed = stamp;
+       LOG (3, "stamping %d observed %d", lit, stamp);
+       continue;
+      }
+      assert (!dfpr[ulit].finished);
+      dfpr[ulit].discovered = ++stamp;
+      dfopf[ulit].observed = stamp;
+      LOG (3, "stamping %d observed %d", lit, stamp);
+      *visitedptr += 1;
+      if (!startstamp) {
+       startstamp = stamp;
+       LOG (3, "root %d with stamp %d", lit, startstamp);
+       dfpr[ulit].root = lit;
+       LOG (4, "stamping %d root %d", lit, lit);
+       assert (!dfpr[ulit].parent);
+       LOG (4, "stamping %d parent %d", lit, 0);
+      }
+      LOG (4, "stamping %d discovered %d", lit, stamp);
+      lglpushwtk (lgl, work, POSTFIX, lit, 0, 0);
+      assert (dfopf[ulit].pushed < 0);
+      dfopf[ulit].pushed = lglcntwtk (work);
+      assert (!dfopf[ulit].flag);
+      dfopf[ulit].flag = 1;
+      lglpushstk (lgl, sccs, lit);
+      hts = lglhts (lgl, -lit);
+      w = lglhts2wchs (lgl, hts);
+      eos = w + hts->count;
+      for (undiscovered = 0; undiscovered <= 1 ; undiscovered++) {
+       start = lglcntwtk (work);
+       for (p = w; p < eos; p++) {
+         blit = *p;
+         tag = blit & MASKCS;
+         if (tag == OCCS) continue;
+         if (tag == TRNCS || tag == LRGCS) { p++; continue; }
+         assert (tag == BINCS);
+         red = blit & REDCS;
+         if (irronly && red) continue;
+         other = blit >> RMSHFT;
+         if (lglval (lgl, other)) continue;
+         uother = lglulit (other);
+         if (undiscovered != !dfpr[uother].discovered) continue;
+         // Kind of defensive, since 'lglrmbindup' should avoid it
+         // and this fix may not really work anyhow since it does
+         // not distinguish between irredundant and redundant clauses.
+         // Thus we put a hard COVER here.
+         COVER (lglsignedmarked (lgl, other) > 0);
+         if (lglsignedmarked (lgl, other) > 0) {
+           LOG (2, "stamping skips duplicated edge %d %d", lit, other);
+           continue;
+         }
+         lglsignedmark (lgl, other);
+         lglpushwtk (lgl, work, BEFORE, lit, other, red);
+       }
+       end = lglcntwtk (work);
+       for (r = work->start + start; r < work->top; r++)
+         lglunmark (lgl, r->other);
+       mod = (end - start);
+       if (mod <= 1) continue;
+       for (i = start; i < end - 1;  i++) {
+         assert (1 < mod && mod == (end - i));
+         j = lglrand (lgl) % mod--;
+         if (!j) continue;
+         j = i + j;
+         SWAP (Work, work->start[i], work->start[j]);
+       }
+      }
+    } else if (wrag == BEFORE) {       // before recursive call
+      LOG (2, "stamping edge %d %d before recursion", lit, other);
+      lglpushwtk (lgl, work, AFTER, lit, other, red);
+      ulit = lglulit (lit);
+      uother = lglulit (other);
+      unotother = lglulit (-other);
+      if (lgl->opts->unhdextstamp.val && (irronly || red) &&
+         dfopf[uother].observed > dfpr[ulit].discovered) {
+       LOG (2, "transitive edge %d %d during stamping", lit, other);
+       lgl->stats->unhd.stamp.trds++;
+       lgl->stats->prgss++;
+       if (red) lgl->stats->unhd.tauts.red++;
+       lglrmbcls (lgl, -lit, other, red);
+       if ((pos = dfopf[unotother].pushed) >= 0) {
+         while (pos  < lglcntwtk (work)) {
+           if (work->start[pos].lit != -other) break;
+           if (work->start[pos].other == -lit) {
+             LOG (3, "removing edge %d %d from DFS stack", -other, -lit);
+             work->start[pos].removed = 1;
+           }
+           pos++;
+         }
+       }
+       work->top--;
+       assert (dfpr[uother].discovered); // and thus 'parent' + 'root' set
+       continue;
+      }
+      observed = dfopf[unotother].observed;
+      if (lgl->opts->unhdextstamp.val && startstamp <= observed) {
+       LOG (1, "stamping failing edge %d %d", lit, other);
+       for (failed = lit;
+            dfpr[lglulit (failed)].discovered > observed;
+            failed = dfpr[lglulit (failed)].parent)
+         assert (failed);
+       LOG (1, "stamping failed literal %d", failed);
+       lglpushstk (lgl, units, -failed);
+       lgl->stats->unhd.stamp.failed++;
+       if (dfpr[unotother].discovered && !dfpr[unotother].finished) {
+         LOG (2, "stamping skips edge %d %d after failed literal %d",
+              lit, other, failed);
+         work->top--;
+         continue;
+       }
+      }
+      if (!dfpr[uother].discovered) {
+       dfpr[uother].parent = lit;
+       LOG (4, "stamping %d parent %d", other, lit);
+       dfpr[uother].root = root;
+       LOG (4, "stamping %d root %d", other, root);
+       lglpushwtk (lgl, work, PREFIX, other, 0, 0);
+      }
+    } else if (wrag == AFTER) {                // after recursive call
+      LOG (2, "stamping edge %d %d after recursion", lit, other);
+      uother = lglulit (other);
+      ulit = lglulit (lit);
+      if (lgl->opts->unhdextstamp.val && !dfpr[uother].finished &&
+         dfpr[uother].discovered < dfpr[ulit].discovered) {
+       LOG (2, "stamping back edge %d %d", lit, other);
+       dfpr[ulit].discovered = dfpr[uother].discovered;
+       LOG (3, "stamping %d reduced discovered to %d",
+            lit, dfpr[ulit].discovered);
+       if (dfopf[ulit].flag) {
+         LOG (2, "stamping %d as being part of a non-trivial SCC", lit);
+         dfopf[ulit].flag = 0;
+       }
+      }
+      dfopf[uother].observed = stamp;
+      LOG (3, "stamping %d observed %d", other, stamp);
+    } else {
+      assert (wrag == POSTFIX);
+      LOG (2, "stamping postfix %d", lit);
+      ulit = lglulit (lit);
+      if (dfopf[ulit].flag) {
+       stamp++;
+       sccsize = 0;
+       discovered = dfpr[ulit].discovered;
+       do {
+         other = lglpopstk (sccs);
+         uother = lglulit (other);
+         dfopf[uother].pushed = -1;
+         dfopf[uother].flag = 0;
+         dfpr[uother].discovered = discovered;
+         dfpr[uother].finished = stamp;
+         LOG (3, "stamping %d interval %d %d parent %d root %d",
+              other, dfpr[uother].discovered, dfpr[uother].finished,
+              dfpr[uother].parent, dfpr[uother].root);
+         sccsize++;
+       } while (other != lit);
+       assert (lgl->opts->unhdextstamp.val || sccsize == 1);
+       if (sccsize > 1) {
+         LOG (2, "stamping non trivial SCC of size %d", sccsize);
+         lgl->stats->unhd.stamp.sumsccsizes += sccsize;
+         lgl->stats->unhd.stamp.sccs++;
+       }
+      } else assert (lgl->opts->unhdextstamp.val);
+    }
+  }
+  assert (lglmtwtk (work));
+  assert (lglmtstk (sccs));
+  return stamp;
+}
+
+static int lglunhlca (LGL * lgl, const DFPR * dfpr, int a, int b) {
+  const DFPR * c, * d;
+  int u, v, p;
+  if (a == b) return a;
+  u = lglulit (a), v = lglulit (b);
+  c = dfpr + u, d = dfpr + v;
+  if (c->discovered <= d->discovered) {
+    p = a;
+  } else {
+    assert (c->discovered > d->discovered);
+    p = b;
+    SWAP (const DFPR *, c, d);
+  }
+  for (;;) {
+    assert (c->discovered <= d->discovered);
+    if (d->finished <= c->finished) break;
+    p = c->parent;
+    if (!p) break;
+    u = lglulit (p);
+    c = dfpr + u;
+  }
+  LOG (3, "unhiding least common ancestor of %d and %d is %d", a, b, p);
+  return p;
+}
+
+static int lglunhidefailed (LGL * lgl, const DFPR * dfpr) {
+  int idx, sign, lit, unit, nfailed = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      if (lglterminate (lgl)) return 0;
+      if (!lglsyncunits (lgl)) return 0;
+      INCSTEPS (unhd.steps);
+      lit = sign * idx;
+      if (lglval (lgl, lit)) continue;
+      if (!dfpr[lglulit (lit)].discovered) continue;
+      if (lglunhimplincl (dfpr, lit, -lit)) {
+       unit = -lit;
+       LOG (2, "unhiding %d implies %d", lit, -lit);
+      } else if (lglunhimplincl (dfpr, -lit, lit)) {
+       unit = lit;
+       LOG (2, "unhiding %d implies %d", -lit, lit);
+      } else continue;
+      LOG (1, "unhiding failed literal %d", -unit);
+      lglunit (lgl, unit);
+      lgl->stats->unhd.failed.lits++;
+      nfailed++;
+      if (lglbcp (lgl)) continue;
+      LOG (1, "empty clause after propagating unhidden failed literal");
+      assert (!lgl->mt);
+      lgl->mt = 1;
+      return 0;
+    }
+  }
+  LOG (1, "unhiding %d failed literals in this round", nfailed);
+  return 1;
+}
+
+static int lglunhroot (const DFPR * dfpr, int lit) {
+  return dfpr[lglulit (lit)].root;
+}
+
+static int lglunhidebintrn (LGL * lgl, const DFPR * dfpr, int irronly) {
+  int idx, sign, lit, blit, tag, red, other, other2, unit, root, lca;
+  int nbinred, ntrnred, nbinunits, ntrnunits, ntrnstr, ntrnhbrs;
+  const int * p, * eow;
+  int ulit, uother;
+  int * w , * q;
+  long delta;
+  HTS * hts;
+  nbinred = ntrnred = nbinunits = ntrnunits = ntrnstr = ntrnhbrs = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      if (lglterminate (lgl)) return 0;
+      if (!lglsyncunits (lgl)) return 0;
+      INCSTEPS (unhd.steps);
+      lit = sign * idx;
+      if (lglval (lgl, lit)) continue;
+      ulit = lglulit (lit);
+      if (!dfpr[ulit].discovered) continue;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      q = w;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       *q++ = blit;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) *q++ = *++p;
+       if (tag == LRGCS) continue;
+       red = blit & REDCS;
+       other = blit >> RMSHFT;
+       if (lglval (lgl, other)) continue;
+       uother = lglulit (other);
+       if (tag == BINCS) {
+         if (lglunhimplies2 (dfpr, other, lit)) {
+           LOG (2, "unhiding removal of literal %d "
+                   "with implication %d %d from binary clause %d %d",
+                other, other, lit, lit, other);
+           lgl->stats->unhd.units.bin++;
+           nbinunits++;
+           unit = lit;
+UNIT:
+           lglunit (lgl, unit);
+           p++;
+           while (p < eow) *q++ = *p++;
+           lglshrinkhts (lgl, hts, hts->count - (p - q));
+           if (lglbcp (lgl)) goto NEXTIDX;
+           LOG (1, "empty clause after propagating unhidden lifted unit");
+           assert (!lgl->mt);
+           lgl->mt = 1;
+           return 0;
+         } else if ((root = lglunhroot (dfpr, -lit)) &&
+                    !lglval (lgl, root) &&
+                    root == lglunhroot (dfpr, -other)) {
+           LOG (2, "negated literals in binary clause %d %d implied by %d",
+                lit, other, root);
+           lgl->stats->unhd.failed.bin++;
+           lca = lglunhlca (lgl, dfpr, -lit, -other);
+           unit = -lca;
+           assert (unit);
+           goto UNIT;
+         } else if (!irronly && !red) continue;
+         else {
+           if (dfpr[uother].parent == -lit) continue;
+           if (dfpr[ulit].parent == -other) continue;
+           if (!lglunhimplies2 (dfpr, -lit, other)) continue;
+           LOG (2, "unhiding tautological binary clause %d %d", lit, other);
+           lgl->stats->unhd.tauts.bin++;
+           lgl->stats->prgss++;
+           if (red) lgl->stats->unhd.tauts.red++;
+           nbinred++;
+           lglrmbwch (lgl, other, lit, red);
+           LOG (2, "removed %s binary clause %d %d",
+                lglred2str (red), lit, other);
+           lgldeclscnt (lgl, 2, red, 0);
+           assert (!lgl->dense);
+           q--;
+         }
+       } else {
+         assert (tag == TRNCS);
+         other2 = *p;
+         if (lglval (lgl, other2)) continue;
+         if (lglunhimplies2incl (dfpr, other, lit) &&
+             lglunhimplies2incl (dfpr, other2, lit)) {
+           LOG (2,
+                "unhiding removal of literals %d and %d with implications "
+                "%d %d and %d %d from ternary clause %d %d %d",
+                other, other2,
+                other, lit,
+                other2, lit,
+                lit, other, other2);
+           lgl->stats->unhd.str.trn += 2;
+           if (red) lgl->stats->unhd.str.red += 2;
+           lgl->stats->unhd.units.trn++;
+           ntrnunits++;
+           unit = lit;
+           goto UNIT;
+         } else if ((root = lglunhroot (dfpr, -lit)) &&
+                    !lglval (lgl, root) &&
+                    root == lglunhroot (dfpr, -other) &&
+                    root == lglunhroot (dfpr, -other2)) {
+           LOG (2,
+             "negation of literals in ternary clauses %d %d %d "
+             "implied by %d", lit, other, other2, root);
+           lgl->stats->unhd.failed.trn++;
+           lca = lglunhlca (lgl, dfpr, -lit, -other);
+           assert (lca);
+           lca = lglunhlca (lgl, dfpr, lca, -other2);
+           assert (lca);
+           unit = -lca;
+           goto UNIT;
+         } else if ((red || irronly) &&
+                    (lglunhimplies2incl (dfpr, -lit, other) ||
+                     lglunhimplies2incl (dfpr, -lit, other2))) {
+
+           if (!lgl->opts->unhdatrn.val) continue;
+           if (red && lgl->opts->unhdatrn.val == 1) continue;
+
+           LOG (2, "unhiding %s tautological ternary clause %d %d %d",
+                lglred2str (red), lit, other, other2);
+           lgl->stats->unhd.tauts.trn++;
+           lgl->stats->prgss++;
+           if (red) lgl->stats->unhd.tauts.red++;
+           ntrnred++;
+           lglrmtwch (lgl, other, lit, other2, red);
+           lglrmtwch (lgl, other2, lit, other, red);
+           LOG (2, "removed %s ternary clause %d %d %d",
+                lglred2str (red), lit, other, other2);
+           lgldeclscnt (lgl, 3, red, 0);
+           assert (!lgl->dense);
+           if (!red && lgl->opts->move.val >= 2) {
+             long delta;
+             assert (q >= w);
+             assert (q[-2] == blit);
+             assert (q[-1] == other2);
+             q[-2] |= REDCS;
+             delta = lglwchtrn (lgl, other, lit, other2, REDCS);
+             delta += lglwchtrn (lgl, other2, lit, other, REDCS);
+             if (delta) w += delta, eow += delta, p += delta, q += delta;
+             LOG (2, "moved ternary clause %d %d %d", lit, other, other2);
+              lgl->stats->red.trn++, assert (lgl->stats->red.trn > 0);
+             lgl->stats->moved.trn++;
+           } else q -= 2;
+         } else if (lglunhimplies2incl (dfpr, other2, lit)) {
+TRNSTR:
+           LOG (2,
+                "unhiding removal of literal %d with implication "
+                "%d %d from ternary clause %d %d %d",
+                other2, other2, lit, lit, other, other2);
+           lgl->stats->unhd.str.trn++;
+           lgl->stats->prgss++;
+           if (red) lgl->stats->unhd.str.red++;
+           ntrnstr++;
+           lglrmtwch (lgl, other, lit, other2, red);
+           lglrmtwch (lgl, other2, lit, other, red);
+           LOG (2, "removed %s ternary clause %d %d %d",
+                lglred2str (red), lit, other, other2);
+           lgldeclscnt (lgl, 3, red, 0);
+           if (!red) lglincirr (lgl, 2);
+           else lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+           delta = lglwchbin (lgl, other, lit, red);
+           if (delta) { p += delta, q += delta, eow += delta, w += delta; }
+           (--q)[-1] = red | BINCS | (other << RMSHFT);
+           if (lgl->opts->drup.val) lgldrupclsarg (lgl, lit, other, 0);
+#ifndef NLGLPICOSAT
+           lglpicosatchkclsarg (lgl, lit, other, 0);
+#endif
+           continue;
+         } else if (lglunhimplies2incl (dfpr, other, lit)) {
+           SWAP (int, other, other2);
+           goto TRNSTR;
+         } else if (lgl->opts->unhdhbr.val &&
+                    (root = lglunhroot (dfpr, -lit)) &&
+                    !lglval (lgl, root)) {
+           if (root == lglunhroot (dfpr, -other2)) {
+             lca = lglunhlca (lgl, dfpr, -lit, -other2);
+           } else if (root == lglunhroot (dfpr, -other)) {
+             lca = lglunhlca (lgl, dfpr, -lit, -other);
+             SWAP (int, other, other2);
+           } else if (lglunhimplies2incl (dfpr, root, -other2)) lca = root;
+           else if (lglunhimplies2incl (dfpr, root, -other)) {
+             lca = root;
+             SWAP (int, other, other2);
+           } else continue;
+           assert (lca);
+           if (abs (lca) == abs (lit)) continue;
+           if (abs (lca) == abs (other)) continue;
+           if (abs (lca) == abs (other2)) continue;
+           if (lglunhimplies2incl (dfpr, lca, other)) continue;
+           LOG (2,
+             "negations of literals %d %d in ternary clause %d %d %d "
+             "implied by %d", lit, other2, lit, other, other2, lca);
+           lgl->stats->unhd.hbrs.trn++;
+           if (red) lgl->stats->unhd.hbrs.red++;
+           lgl->stats->prgss++;
+           ntrnhbrs++;
+           LOG (2, "unhidden hyper binary resolved clause %d %d",-lca,other);
+           if (lgl->opts->drup.val) lgldrupclsarg (lgl, -lca, other, 0);
+#ifndef NLGLPICOSAT
+           lglpicosatchkclsarg (lgl, -lca, other, 0);
+#endif
+           assert (lca != -lit);
+           lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+           delta = lglwchbin (lgl, -lca, other, REDCS);
+           if (delta) { p += delta, q += delta, eow += delta, w += delta; }
+           delta = lglwchbin (lgl, other, -lca, REDCS);
+           if (delta) { p += delta, q += delta, eow += delta, w += delta; }
+         }
+       }
+      }
+      lglshrinkhts (lgl, hts, hts->count - (p - q));
+    }
+NEXTIDX:
+    ;
+  }
+  if (nbinred) LOG (2, "unhiding %d tautological binary clauses", nbinred);
+  if (nbinunits) LOG (2, "unhiding %d units in binary clauses", nbinunits);
+  if (ntrnred) LOG (2, "unhiding %d tautological ternary clauses", ntrnred);
+  if (ntrnstr) LOG (2, "unhiding %d strengthened ternary clauses", ntrnstr);
+  if (ntrnunits) LOG (2, "unhiding %d units in ternary clauses", ntrnunits);
+  if (ntrnstr) LOG (2, 
+    "unhidden %d hyper binary resolution from ternary clauses", ntrnhbrs);
+  return 1;
+}
+
+static int lglcmpdfl (const DFL * a, const DFL * b) {
+  return a->discovered - b->discovered;
+}
+
+static int lglunhideglue (LGL * lgl, const DFPR * dfpr, int glue, int irronly) {
+  DFL * dfl, * eodfl, * d, * e; int szdfl, posdfl, negdfl, ndfl, res;
+  int oldsize, newsize, hastobesatisfied, satisfied, tautological;
+  int watched, lit, ulit, val, sign, nonfalse, root, lca, unit;
+  int ntaut = 0, nstr = 0, nunits = 0, nhbrs = 0, lidx;
+  int * p, * q, * c, * eoc, red;
+  int lca1, lca2, root1, root2;
+  Stk * lits;
+#ifndef NLGLOG
+  char type[20];
+  if (glue < 0) sprintf (type, "irredundant");
+  else sprintf (type, "redundant glue %d", glue);
+#endif
+  assert (!lgl->mt);
+  assert (-1 <= glue && glue < MAXGLUE);
+  if (glue < 0) {
+    lits = &lgl->irr;
+    red = 0;
+  } else {
+    lits = lgl->red + glue;
+    red = REDCS;
+  }
+  res = 1;
+  dfl = 0; szdfl = 0;
+  // go through all clauses of this glue and for each do:
+  //
+  //   SHRINK  simplify clause according to current assignment
+  //   FAILED  check if it is a hidden failed literal
+  //   HTE     check if it is a hidden tautology
+  //   STRNEG  remove hidden literals using complement literals
+  //   STRPOS  remove hidden literals using positive literals
+  //   HBR     perform unhiding hyper binary resolution
+  //   NEXT    clean up, unwatch if necessary, reconnect bin/trn, bcp unit
+  //
+  for (c = lits->start; !lgl->mt && c < lits->top; c = eoc + 1) {
+    if (lglterminate (lgl) || !lglsyncunits (lgl)) { res = 0; break; }
+    if ((lit = *(eoc = c)) >= NOTALIT) continue;
+    INCSTEPS (unhd.steps);
+    lidx = c - lits->start;
+    if (red) { lidx <<= GLUESHFT; lidx |= glue; }
+    watched = 1;
+    while (*eoc) eoc++;
+    oldsize = eoc - c;
+
+    unit = hastobesatisfied = satisfied = tautological = ndfl = 0;
+//SHRINK: check satisfied + remove false literals + count visited
+    q = c;
+    nonfalse = posdfl = negdfl = 0;
+    for (p = c; p < eoc; p++) {
+      lit = *p;
+      val = lglval (lgl, lit);
+      if (val > 0) {
+       satisfied = 1;
+       q = c + 2;
+       break;
+      }
+      if (val < 0) {
+       if (p < c + 2) {
+         *q++ = lit;           // watched, so have to keep it
+         hastobesatisfied = 1; // for assertion checking only
+       }
+       continue;
+      }
+      *q++ = lit;
+      nonfalse++;
+      if (dfpr[lglulit (lit)].discovered) posdfl++;    // count pos in BIG
+      if (dfpr[lglulit (-lit)].discovered) negdfl++;   // count neg in BIG
+    }
+    *(eoc = q) = 0;
+    assert (eoc - c >= 2);     // we assume bcp done before
+    ndfl = posdfl + negdfl;    // number of literals in BIG
+    if (hastobesatisfied) assert (satisfied);
+    if (satisfied || ndfl < 2) goto NEXT;
+    assert (nonfalse = eoc - c);
+    assert (nonfalse >= negdfl);
+//FAILED: find root implying all negated literals
+    if (nonfalse != negdfl) goto HTE;  // not enough complement lits in BIG
+    assert (c < eoc);
+    root = lglunhroot (dfpr, -*c);
+    if (lglval (lgl, root)) goto HTE;
+    for (p = c + 1; p < eoc && lglunhroot (dfpr, -*p) == root; p++)
+      ;
+    if (p < eoc) goto HTE;             // at least two roots
+    LOGCLS (2, c, "unhiding failed literal through large %s clause",type);
+    LOG (2, "unhiding that all negations are implied by root %d", root);
+    lca = -*c;
+    for (p = c + 1; p < eoc; p++)
+      lca = lglunhlca (lgl, dfpr, -*p, lca);
+    assert (!lglval (lgl, lca));
+    LOG (2, "unhiding failed large %s clause implied by LCA %d", type, lca);
+    lgl->stats->unhd.failed.lrg++;
+    unit = -lca;
+    goto NEXT;  // otherwise need to properly unwatch and restart etc.
+               // which is too difficult to implement so leave further
+               // simplification of this clause to next unhiding round
+HTE:
+    if (glue < 0 && !irronly) goto STRNEG; // skip tautology checking if
+                                          // redundant clauses used and
+                                          // we work on irredundant clauses
+    if (posdfl < 2 || negdfl < 2) goto STRNEG;
+    if (ndfl > szdfl) { RSZ (dfl, szdfl, ndfl); szdfl = ndfl; }
+    ndfl = 0;
+    // copy all literals and their complements to 'dfl'
+    for (p = c; p < eoc; p++) {
+      for (sign = -1; sign <= 1; sign += 2) {
+       lit = *p;
+       ulit = lglulit (sign * lit);
+       if (!dfpr[ulit].discovered) continue;   // not in BIG so skip
+       assert (ndfl < szdfl);
+       dfl[ndfl].discovered = dfpr[ulit].discovered;
+       dfl[ndfl].finished = dfpr[ulit].finished;
+       dfl[ndfl].sign = sign;
+#ifndef NLGLOG
+       dfl[ndfl].lit4logging = lit;
+#endif
+       ndfl++;
+      }
+    }
+    ADDSTEPS (unhd.steps, 6);                          // rough guess
+    SORT (DFL, dfl, ndfl, lglcmpdfl);
+    eodfl = dfl + ndfl;
+    // Now check if there are two consecutive literals, the first
+    // a complement of a literal in the clause, which implies another
+    // literal actually occurring positive in the clause, where
+    // 'd' ranges over complement literals
+    // 'e' ranges over original literals
+    for (d = dfl; d < eodfl - 1; d++)
+      if (d->sign < 0) break;                  // get first negative pos
+    while (d < eodfl - 1) {
+      assert (d->sign < 0);
+      for (e = d + 1; e < eodfl && e->finished < d->finished; e++) {
+       if (e->sign < 0) continue;              // get next positive pos
+       assert (d->sign < 0 && e->sign > 0);
+       assert (d->discovered <= e->discovered);
+       assert (e ->finished <= d->finished);
+       LOGCLS (2, c,
+               "unhiding with implication %d %d tautological %s clause",
+               -d->lit4logging, e->lit4logging, type);
+       ntaut++;
+       lgl->stats->unhd.tauts.lrg++;
+       if (red) lgl->stats->unhd.tauts.red++;
+       lgl->stats->prgss++;
+       tautological = 1;
+       goto NEXT;
+      }
+      for (d = e; d < eodfl && d->sign > 0; d++)
+       ;
+    }
+STRNEG:
+    if (negdfl < 2) goto STRPOS;
+    if (negdfl > szdfl) { RSZ (dfl, szdfl, negdfl); szdfl = negdfl; }
+    INCSTEPS (unhd.steps);
+    ndfl = 0;
+    // copy complement literals to 'dfl'
+    for (p = c; p < eoc; p++) {
+      lit = *p;
+      ulit = lglulit (-lit);                   // NOTE: '-lit' not 'lit'
+      if (!dfpr[ulit].discovered) continue;
+      assert (ndfl < szdfl);
+      dfl[ndfl].discovered = dfpr[ulit].discovered;    // of '-lit'
+      dfl[ndfl].finished = dfpr[ulit].finished;                // of '-lit'
+      dfl[ndfl].lit = lit;                     // NOTE: but 'lit' here
+      ndfl++;
+    }
+    if (ndfl < 2) goto STRPOS;
+    ADDSTEPS (unhd.steps, 3);                  // rough guess
+    SORT (DFL, dfl, ndfl, lglcmpdfl);
+    eodfl = dfl + ndfl;
+    for (d = dfl; d < eodfl - 1; d = e) {
+      assert (d->discovered);
+      for (e = d + 1; e < eodfl && d->finished >= e->finished; e++) {
+       assert (d->discovered <= e->discovered);
+       lit = e->lit;
+       LOGCLS (2, c,
+               "unhiding removal of literal %d "
+               "with implication %d %d from large %s clause",
+               lit, -d->lit, -e->lit, type);
+       e->lit = 0;
+       nstr++;
+       lgl->stats->unhd.str.lrg++;
+       if (red) lgl->stats->unhd.str.red++;
+       lgl->stats->prgss++;
+       if (!watched) continue;
+       if (lit != c[0] && lit != c[1]) continue;
+       lglrmlwch (lgl, c[0], red, lidx);
+       lglrmlwch (lgl, c[1], red, lidx);
+       watched = 0;
+      }
+    }
+    assert (eoc - c >= 1 );
+    q = c;
+    if (watched) q += 2;                       // keep watched literals
+                                               // if we still watch
+    // move non BIG literals
+    for (p = q; p < eoc; p++) {
+      lit = *p;
+      ulit = lglulit (-lit);                   // NOTE: '-lit' not 'lit'
+      if (dfpr[ulit].discovered) continue;
+      *q++ = lit;
+    }
+    // copy from 'dfl' unremoved BIG literals back to clause
+    for (d = dfl; d < eodfl; d++) {
+      lit = d->lit;
+      if (!lit) continue;
+      if (watched && lit == c[0]) continue;
+      if (watched && lit == c[1]) continue;
+      *q++ = lit;
+    }
+    *(eoc = q) = 0;
+STRPOS:
+    if (posdfl < 2) goto HBR;
+    if (posdfl > szdfl) { RSZ (dfl, szdfl, posdfl); szdfl = posdfl; }
+    ndfl = 0;
+    // copy original literals to 'dfl' but sort reverse wrt 'discovered'
+    for (p = c; p < eoc; p++) {
+      lit = *p;
+      ulit = lglulit (lit);                    // NOTE: now 'lit'
+      if (!dfpr[ulit].discovered) continue;
+      assert (ndfl < szdfl);
+      dfl[ndfl].discovered = -dfpr[ulit].discovered;   // of 'lit'
+      dfl[ndfl].finished = -dfpr[ulit].finished;               // of 'lit'
+      dfl[ndfl].lit = lit;
+      ndfl++;
+    }
+    if (ndfl < 2) goto NEXT;
+    ADDSTEPS (unhd.steps, 3);                  // rough guess
+    SORT (DFL, dfl, ndfl, lglcmpdfl);
+    eodfl = dfl + ndfl;
+    for (d = dfl; d < eodfl - 1; d = e) {
+      assert (d->discovered);
+      for (e = d + 1; e < eodfl && d->finished >= e->finished; e++) {
+       assert (d->discovered <= e->discovered);
+       lit = e->lit;
+       LOGCLS (2, c,
+               "unhiding removal of literal %d "
+               "with implication %d %d from large %s clause",
+               lit, e->lit, d->lit, type);
+       e->lit = 0;
+       nstr++;
+       lgl->stats->unhd.str.lrg++;
+       if (red) lgl->stats->unhd.str.red++;
+       lgl->stats->prgss++;
+       if (!watched) continue;
+       if (lit != c[0] && lit != c[1]) continue;
+       lglrmlwch (lgl, c[0], red, lidx);
+       lglrmlwch (lgl, c[1], red, lidx);
+       watched = 0;
+      }
+    }
+    assert (eoc - c >= 1 );
+    q = c;
+    if (watched) q += 2;
+    for (p = q; p < eoc; p++) {
+      lit = *p;
+      ulit = lglulit (lit);                    // NOTE: now 'lit'
+      if (dfpr[ulit].discovered) continue;
+      *q++ = lit;
+    }
+    for (d = dfl; d < eodfl; d++) {
+      lit = d->lit;
+      if (!lit) continue;
+      if (watched && lit == c[0]) continue;
+      if (watched && lit == c[1]) continue;
+      *q++ = lit;
+    }
+    *(eoc = q) = 0;
+HBR:
+    if (!lgl->opts->unhdhbr.val) goto NEXT;
+    if (eoc - c < 3) goto NEXT;
+    root1 = root2 = lca1 = lca2 = 0;
+    for (p = c; (lit = *p); p++) {
+      root = lglunhroot (dfpr, -lit);
+      if (!root) root = -lit;
+      if (!root1) { root1 = root; continue; }
+      if (root1 == root) continue;
+      if (!root2) { root2 = root; continue; }
+      if (root2 == root) continue;
+      if (lglunhimplies2incl (dfpr, root1, -lit)) { lca1 = root1; continue; }
+      if (lglunhimplies2incl (dfpr, root2, -lit)) { lca2 = root2; continue; }
+      goto NEXT;                       // else more than two roots ...
+    }
+    assert (root1);
+    if (!root2) goto NEXT;
+    if (root1 == -root2) goto NEXT;
+    if (lglunhimplies2incl (dfpr, root1, -root2)) goto NEXT;
+    LOGCLS (2, c, "root hyper binary resolution %d %d of %s clause",
+           -root1, -root2, type);
+    if (!lca1 && !lca2) {
+      for (p = c; (lit = *p); p++) {
+       root = lglunhroot (dfpr, -lit);
+       if (root) {
+         if (root == root1)
+           lca1 = lca1 ? lglunhlca (lgl, dfpr, lca1, -lit) : -lit;
+         if (root == root2)
+           lca2 = lca2 ? lglunhlca (lgl, dfpr, lca2, -lit) : -lit;
+       } else {
+         assert (!lca2);
+         if (lca1) lca2 = -lit; else lca1 = -lit;
+       }
+      }
+    } else {
+      if (!lca1) lca1 = root1;
+      if (!lca2) lca2 = root2;
+    }
+    if (lca1 == -lca2) goto NEXT;
+    if (lglunhimplies2incl (dfpr, lca1, -lca2)) goto NEXT;
+    LOGCLS (2, c, "lca hyper binary resolution %d %d of %s clause",
+           -lca1, -lca2, type);
+    lgl->stats->unhd.hbrs.lrg++;
+    if (red) lgl->stats->unhd.hbrs.red++;
+    if (lgl->opts->drup.val) lgldrupclsarg (lgl, -lca1, -lca2, 0);
+#ifndef NLGLPICOSAT
+    lglpicosatchkclsarg (lgl, -lca1, -lca2, 0);
+#endif
+    lglwchbin (lgl, -lca1, -lca2, REDCS);
+    lglwchbin (lgl, -lca2, -lca1, REDCS);
+    lgl->stats->red.bin++;
+    assert (lgl->stats->red.bin > 0);
+NEXT:
+    newsize = eoc - c;
+    assert (satisfied || tautological || newsize >= 1);
+    if (newsize <= 3 || satisfied || tautological) {
+      lgldeclscnt (lgl, oldsize, red, glue);
+      if (watched) {
+       lglrmlwch (lgl, c[0], red, lidx);
+       lglrmlwch (lgl, c[1], red, lidx);
+      }
+    } else if (!red) {
+      assert (lgl->stats->irr.lits.cur >= c + oldsize - eoc);
+      lgl->stats->irr.lits.cur -= c + oldsize - eoc;
+    }
+    assert (!*eoc);
+    for (p = c + oldsize; p > eoc; p--) *p = REMOVED;
+    if (satisfied || tautological) {
+      while (p >= c) *p-- = REMOVED;
+      if (red) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+      eoc = c + oldsize;
+      continue;
+    }
+    if (newsize < oldsize) {
+      if (lgl->opts->drup.val) lgldrupclsaux (lgl, c);
+#ifndef NLGLPICOSAT
+      lglpicosatchkclsaux (lgl, c);
+#endif
+    }
+    if (red && newsize <= 3) { LGLCHKACT (c[-1]); c[-1] = REMOVED; }
+    if (newsize > 3 && !watched) {
+      (void) lglwchlrg (lgl, c[0], c[1], red, lidx);
+      (void) lglwchlrg (lgl, c[1], c[0], red, lidx);
+    } else if (newsize == 3) {
+      LOGCLS (2, c, "large %s clause became ternary", type);
+      lglwchtrn (lgl, c[0], c[1], c[2], red);
+      lglwchtrn (lgl, c[1], c[0], c[2], red);
+      lglwchtrn (lgl, c[2], c[0], c[1], red);
+      if (!red) lglincirr (lgl, 3);
+      else lgl->stats->red.trn++, assert (lgl->stats->red.trn > 0);
+      c[0] = c[1] = c[2] = *eoc = REMOVED;
+    } else if (newsize == 2) {
+      LOGCLS (2, c, "large %s clause became binary", type);
+      lglwchbin (lgl, c[0], c[1], red);
+      lglwchbin (lgl, c[1], c[0], red);
+      if (!red) lglincirr (lgl, 2);
+      else lgl->stats->red.bin++, assert (lgl->stats->red.bin > 0);
+      c[0] = c[1] = *eoc = REMOVED;
+    } else if (newsize == 1) {
+      LOGCLS (2, c, "large %s clause became unit", type);
+      unit = c[0];             // even works if unit already set
+      c[0] = *eoc = REMOVED;
+      lgl->stats->unhd.units.lrg++;
+      nunits++;
+    }
+    if (!unit) continue;
+    lglunit (lgl, unit);
+    if (lglbcp (lgl)) continue;
+    assert (!lgl->mt);
+    lgl->mt = 1;
+    LOG (1, "unhiding large clause produces empty clause");
+    res = 0;
+  }
+  if (nunits)
+    LOG (1, "unhiding %d units from large %s clauses", nunits, type);
+  if (ntaut)
+    LOG (1, "unhiding %d large tautological %s clauses", ntaut, type);
+  if (nstr)
+    LOG (1, "unhiding removal of %d literals in %s clauses", nstr, type);
+  if (nhbrs)
+    LOG (1, "unhiding %d hyper binary resolutions in %s clauses", nhbrs, type);
+  if (dfl) DEL (dfl, szdfl);
+  return res;
+}
+
+static void lglfixlrgwchs (LGL * lgl) {
+  int idx, sign, lit, blit, tag, red, lidx, fixed;
+  const int * p, * eow, * c;
+  int * q, * w;
+  HTS * hts;
+  fixed = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      q = w;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == BINCS) { *q++ = blit; continue; }
+       lidx = *++p;
+       if (tag == TRNCS) { *q++ = blit; *q++ = lidx; continue; }
+       assert (tag == LRGCS);
+       red = blit & REDCS;
+       c = lglidx2lits (lgl, red, lidx);
+       if (*c >= NOTALIT) { fixed++; continue; }
+       *q++ = blit;
+       *q++ = lidx;
+      }
+      lglshrinkhts (lgl, hts, hts->count - (p - q));
+    }
+  }
+  assert (!(fixed & 1));
+  if (fixed) LOG (1, "fixed %d large watches", fixed);
+}
+
+static int lglunhidelrg (LGL * lgl, const DFPR * dfpr, int irronly) {
+  int glue, res = 1;
+  for (glue = -1; res && glue < MAXGLUE; glue++)
+    res = lglunhideglue (lgl, dfpr, glue, irronly);
+  lglfixlrgwchs (lgl);
+  return res;
+}
+
+static int lglunhdunits (LGL * lgl) {
+  int res = lgl->stats->unhd.units.bin;
+  res += lgl->stats->unhd.units.trn;
+  res += lgl->stats->unhd.units.lrg;
+  return res;
+}
+
+static int lglunhdfailed (LGL * lgl) {
+  int res = lgl->stats->unhd.stamp.failed;
+  res += lgl->stats->unhd.failed.lits;
+  res += lgl->stats->unhd.failed.bin;
+  res += lgl->stats->unhd.failed.trn;
+  res += lgl->stats->unhd.failed.lrg;
+  return res;
+}
+
+static int lglunhdhbrs (LGL * lgl) {
+  int res = lgl->stats->unhd.hbrs.trn;
+  res += lgl->stats->unhd.hbrs.lrg;
+  return res;
+}
+
+static int lglunhdtauts (LGL * lgl) {
+  int res = lgl->stats->unhd.stamp.trds;
+  res += lgl->stats->unhd.tauts.bin;
+  res += lgl->stats->unhd.tauts.trn;
+  res += lgl->stats->unhd.tauts.lrg;
+  return res;
+}
+
+static int lglunhdstrd (LGL * lgl) {
+  int res = lgl->stats->unhd.units.bin;        // shared!
+  res += lgl->stats->unhd.str.trn;
+  res += lgl->stats->unhd.str.lrg;
+  return res;
+}
+
+static void lglrmbindup (LGL * lgl) {
+  int idx, sign, lit, blit, tag, red, other, round, redrem, irrem;
+  int * w, * eow, * p, * q;
+  HTS * hts;
+  redrem = irrem = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      assert (lglmtstk (&lgl->seen));
+      for (round = 0; round < 2; round++) {
+       hts = lglhts (lgl, lit);
+       w = lglhts2wchs (lgl, hts);
+       eow = w + hts->count;
+       q = w;
+       for (p = w; p < eow; p++) {
+         blit = *p;
+         tag = blit & MASKCS;
+         if (tag != BINCS) *q++ = blit;
+         if (tag== LRGCS || tag == TRNCS) *q++ = *++p;
+         if (tag != BINCS) continue;
+         red = blit & REDCS;
+         other = blit >> RMSHFT;
+         if (lglsignedmarked (lgl, other)) {
+           if (round && !red) goto ONLYCOPY;
+           if (red) redrem++; else irrem++;
+           if (abs (lit) > abs (other)) {
+             LOG (2,
+               "removing duplicated %s binary clause %d %d and 2nd watch %d",
+               lglred2str (red), lit, other, other);
+             lgldeclscnt (lgl, 2, red, 0);
+             if (!red && lgl->dense)
+               lgldecocc (lgl, lit), lgldecocc (lgl, other);
+             lgl->stats->bindup.removed++;
+             if (red) lgl->stats->bindup.red++;
+           } else
+             LOG (2,
+               "removing 1st watch %d of duplicated %s binary clause %d %d",
+               other, lglred2str (red), other, lit);
+         } else {
+           if ((!round && !red) || (round && red))
+             lglsignedmarknpushseen (lgl, other);
+ONLYCOPY:
+           *q++ = blit;
+         }
+       }
+       lglshrinkhts (lgl, hts, hts->count - (p - q));
+      }
+      lglpopnunmarkstk (lgl, &lgl->seen);
+    }
+  }
+  assert (!(irrem & 1));
+  assert (!(redrem & 1));
+}
+
+static DFPR * lglstampall (LGL * lgl, int irronly) {
+  int roots, searches, noimpls, unassigned, visited;
+  unsigned pos, delta, mod, ulit, first, last, count;
+  int root, stamp, rootsonly, lit;
+  Stk units, sccs, trds;
+  DFOPF * dfopf, * q;
+  DFPR * dfpr;
+  Wtk work;
+  Val val;
+  if (lgl->nvars <= 2) return 0;
+  lglrmbindup (lgl);
+  NEW (dfpr, 2*lgl->nvars);
+  NEW (dfopf, 2*lgl->nvars);
+  CLR (work); CLR (sccs); CLR (trds); CLR (units);
+  for (q = dfopf; q < dfopf + 2*lgl->nvars; q++) q->pushed = -1;
+  searches = roots = noimpls = unassigned = stamp = visited = 0;
+  for (rootsonly = 1; rootsonly >= 0; rootsonly--) {
+    count = 0;
+    first = mod = 2*(lgl->nvars - 2);
+    assert (mod > 0);
+    pos = lglrand (lgl) % mod;
+    delta = lglrand (lgl) % mod;
+    if (!delta) delta++;
+    while (lglgcd (delta, mod) > 1)
+      if (++delta == mod) delta = 1;
+    LOG (2, "unhiding %s round start %u delta %u mod %u",
+        (rootsonly ? "roots-only": "non-root"), pos, delta, mod);
+    for (;;) {
+      if (lglterminate (lgl)) { searches = 0; goto DONE; }
+      if (!lglsyncunits (lgl)) { assert (lgl->mt); goto DONE; }
+      ulit = pos + 4;
+      root = lglilit (ulit);
+      INCSTEPS (unhd.steps);
+      count++;
+      if (lglval (lgl, root)) goto CONTINUE;
+      if (rootsonly) unassigned++;
+      if (dfpr[lglulit (root)].discovered) goto CONTINUE;
+      if (rootsonly &&
+         !lglunhdisroot (lgl, root, dfpr, irronly)) goto CONTINUE;
+      if (!lglunhdhasbins (lgl, dfpr, -root, irronly)) {
+       if (rootsonly) noimpls++; goto CONTINUE;
+      }
+      if (rootsonly) roots++;
+      searches++;
+      assert (lglmtstk (&units));
+      stamp = lglstamp (lgl, root, dfpr, dfopf,
+                       &work, &units, &sccs, &trds, &visited,
+                       stamp, irronly);
+      while (!lglmtstk (&units)) {
+       lit = lglpopstk (&units);
+       val = lglval (lgl, lit);
+       if (val > 0) continue;
+       if (val < 0) {
+         assert (!lgl->mt);
+         LOG (1, "unhidding stamp unit %d already false", lit);
+         lgl->mt = 1;
+         goto DONE;
+       }
+       lglunit (lgl, lit);
+       if (!lglbcp (lgl)) {
+         assert (!lgl->mt);
+         LOG (1, "propagating unhidden stamp unit %d failed", lit);
+         lgl->mt = 1;
+         goto DONE;
+       }
+      }
+CONTINUE:
+      last = pos;
+      pos += delta;
+      if (pos >= mod) pos -= mod;
+      if (pos == first) { assert (count == mod); break; }
+      if (mod == 1) break;
+      if (first == mod) first = last;
+    }
+  }
+  assert (searches >= roots);
+  lglprt (lgl, 2,
+         "[unhd-%d-%d] %d unassigned variables out of %d (%.0f%%)",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         lgl->unassigned, lgl->nvars - 2,
+           lglpcnt (lgl->unassigned, lgl->nvars - 2));
+  lglprt (lgl, 2,
+         "[unhd-%d-%d] %d root literals out of %d (%.0f%%)",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         roots, unassigned, lglpcnt (roots, unassigned));
+  lglprt (lgl, 2,
+    "[unhd-%d-%d] %d additional non-root searches out of %d (%.0f%%)",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         searches - roots, unassigned,
+           lglpcnt (searches - roots, unassigned));
+  lglprt (lgl, 2,
+         "[unhd-%d-%d] %d literals not in F2 out of %d (%.0f%%)",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         noimpls, unassigned, lglpcnt (noimpls, unassigned));
+  lglprt (lgl, 2,
+         "[unhd-%d-%d] %d visited literals out of %d (%.0f%%)",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         visited, unassigned, lglpcnt (visited, unassigned));
+  lglprt (lgl, 2,
+         "[unhd-%d-%d] %.2f average number visited literals per search",
+         lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+         lglavg (visited, searches));
+DONE:
+  if (!searches || lgl->mt) { DEL (dfpr, 2*lgl->nvars); dfpr = 0; }
+  lglrelwtk (lgl, &work);
+  lglrelstk (lgl, &units);
+  lglrelstk (lgl, &sccs);
+  lglrelstk (lgl, &trds);
+  DEL (dfopf, 2*lgl->nvars);
+  return dfpr;
+}
+
+static void lglsetunhdlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->unhdreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->unhdmineff.val) limit = lgl->opts->unhdmineff.val;
+  if (lgl->opts->unhdmaxeff.val >= 0 && limit > lgl->opts->unhdmaxeff.val)
+    limit = lgl->opts->unhdmaxeff.val;
+  limit >>= (pen = lgl->limits->unhd.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur/2;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[unhide-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->unhd.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[unhide-%d] limit %lld with penalty %d = %d + %d",
+      lgl->stats->unhd.count, (LGLL) limit,
+      pen, lgl->limits->unhd.pen, lglszpen (lgl));
+  lgl->limits->unhd.steps = lgl->stats->unhd.steps + limit;
+}
+
+static int lglunhide (LGL * lgl) {
+  int irronly, round, maxrounds, noprgssrounds, success;
+  int oldunits, oldfailed, oldtauts, oldhbrs, oldstrd;
+  int deltaunits, deltafailed;
+  int64_t roundprgss = 0;
+  DFPR * dfpr = 0;
+  assert (lgl->opts->unhide.val);
+  if (lgl->nvars <= 2) return 1;
+  lgl->stats->unhd.count++;
+  assert (!lgl->unhiding);
+  lgl->unhiding = 1;
+  assert (!lgl->simp);
+  lgl->simp = 1;
+  lglstart (lgl, &lgl->times->unhd);
+  irronly = !lgl->stats->red.bin || (lgl->stats->unhd.count & 1);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  maxrounds = lgl->opts->unhdroundlim.val;
+  lglsetunhdlim (lgl);
+  oldunits = lglunhdunits (lgl);
+  oldfailed = lglunhdfailed (lgl);
+  oldtauts = lglunhdtauts (lgl);
+  oldhbrs = lglunhdhbrs (lgl);
+  oldstrd = lglunhdstrd (lgl);
+  noprgssrounds = round = 0;
+  while (!lgl->mt) {
+    if (round >= maxrounds) break;
+    if (round > 0 &&
+        roundprgss == lgl->stats->prgss &&
+       noprgssrounds++ == lgl->opts->unhdlnpr.val) {
+      LOG (1, "too many non progress unhiding rounds");
+      break;
+    }
+    round++;
+    roundprgss = lgl->stats->prgss;
+    lgl->stats->unhd.rounds++;
+    lglgc (lgl);
+    if (!lgl->nvars || lgl->mt) break;
+    assert (!dfpr);
+    dfpr = lglstampall (lgl, irronly);
+    if (!dfpr) break;
+    if (!lglunhidefailed (lgl, dfpr)) break;
+    if (!lglunhidebintrn (lgl, dfpr, irronly)) break;
+    if (!lglunhidelrg (lgl, dfpr, irronly)) break;
+    if (lgl->stats->unhd.steps >= lgl->limits->unhd.steps) break;
+    irronly = !lgl->stats->red.bin || !irronly;
+    DEL (dfpr, 2*lgl->nvars);
+    assert (!dfpr);
+  }
+  if (dfpr) DEL (dfpr, 2*lgl->nvars);
+  lglprt (lgl, 1,
+    "[unhide-%d-%d] %d units, %d failed, %d tauts, %d hbrs, %d literals",
+    lgl->stats->unhd.count, lgl->stats->unhd.rounds,
+    (deltaunits = lglunhdunits (lgl) - oldunits),
+    (deltafailed = lglunhdfailed (lgl) - oldfailed),
+    lglunhdtauts (lgl) - oldtauts,
+    lglunhdhbrs (lgl) - oldhbrs,
+    lglunhdstrd (lgl) - oldstrd);
+  success = deltaunits + deltafailed;
+  LGLUPDPEN (unhd, success);
+  assert (lgl->simp);
+  lgl->simp = 0;
+  assert (lgl->unhiding);
+  lgl->unhiding = 0;
+  lglrep (lgl, 2, 'u');
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+static int lglpar64 (uint64_t i) {
+  unsigned x;
+  int res = 0;
+  for (x = i; x; x = x & (x - 1))
+    res = !res;
+  return res;
+}
+
+static uint64_t lgldec64 (uint64_t i) {
+  uint64_t res;
+  for (res = i - 1; lglpar64 (res); res--)
+    ;
+  return res;
+}
+
+static void lglgdump (LGL * lgl) {
+#ifndef NLGLOG
+  const int * p, * start, * top;
+  start = lgl->gauss->xors.start;
+  top = lgl->gauss->xors.top;
+  for (p = start; p < top; p++) {
+    if (*p >= NOTALIT) continue;
+    fprintf (lgl->out, "c eqn[%lld]", (LGLL)(p - start));
+    while (*p > 1) fprintf (lgl->out, " %d", *p++);
+    fprintf (lgl->out, " = %d\n", *p);
+  }
+#endif
+}
+
+static int lglgaussubclsaux (LGL * lgl, uint64_t signs,  const int * c) {
+  int lit, i, min, minocc, tmpocc, blit, tag, other, other2, red, lidx;
+  const int * p, * w, * eow, * d, * q;
+  HTS * hts;
+  assert (lgl->dense);
+  minocc = INT_MAX;
+  min = i = 0;
+  INCSTEPS (gauss.steps.extr);
+  for (p = c; (lit = *p); p++) {
+    if (lglmarked (lgl, lit)) return 0;
+    assert (i < 8 * sizeof signs);
+    if (signs & (1ull << i++)) lit = -lit;
+    lglsignedmark (lgl, lit);
+    tmpocc = lglocc (lgl, lit) + lglhts (lgl, lit)->count;
+    assert (tmpocc < INT_MAX);
+    if (tmpocc >= minocc) continue;
+    minocc = tmpocc;
+    min = lit;
+  }
+  assert (min);
+  hts = lglhts (lgl, min);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    INCSTEPS (gauss.steps.extr);
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (tag == BINCS) {
+      other = blit >> RMSHFT;
+      if (lglsignedmarked (lgl, other)) return 1;
+    } else if (tag == TRNCS) {
+      other = blit >> RMSHFT;
+      if (!lglsignedmarked (lgl, other)) continue;
+      other2 = *p;
+      if (lglsignedmarked (lgl, other2)) return 1;
+    } else {
+      assert (tag == OCCS);
+      red = blit & REDCS;
+      lidx = blit >> RMSHFT;
+      d = lglidx2lits (lgl, red, lidx);
+      for (q = d; (other = *q); q++)
+       if (!lglsignedmarked (lgl, other)) break;
+      if (!other) return 1;
+    }
+  }
+  return 0;
+}
+
+static int lglgaussubcls (LGL * lgl, uint64_t signs,  const int * c) {
+  int res = lglgaussubclsaux (lgl, signs, c), lit;
+  const int * p;
+  for (p = c; (lit = *p); p++) lglunmark (lgl, lit);
+  return res;
+}
+
+#define GL 2
+
+static int lglgaussextractxoraux (LGL * lgl, const int * c) {
+  int lit, val, size, maxsize, negs, start, max, *d, * q;
+  int allxors = lgl->opts->gaussextrall.val;
+  uint64_t signs;
+  const int * p;
+  assert (!lgl->level);
+  maxsize = lgl->opts->gaussmaxor.val;
+  max = negs = size = 0;
+  start = lglcntstk (&lgl->gauss->xors);
+  for (p = c; (lit = *p); p++) {
+    if ((val = lglval (lgl, lit)) > 0) return 0;
+    if (val < 0) continue;
+    if (lit < 0) { 
+      if (!allxors && negs) return 0;
+      negs = !negs; 
+    }
+    if (!max || abs (max) < abs (lit)) max = lit;
+    lglpushstk (lgl, &lgl->gauss->xors, lit);
+    if (++size > maxsize) return 0;
+  }
+  assert (negs == 0 || negs == 1);
+  if (size <= 1) return 0;
+  if (!allxors && negs && max > 0) return 0;
+  lglpushstk (lgl, &lgl->gauss->xors, 0);
+  d = lgl->gauss->xors.start + start;
+  assert (size <= 8 * sizeof signs);
+  signs = lgldec64 (1ull << size);
+  do {
+    if (!lglgaussubcls (lgl, signs, d)) break;
+    signs = lgldec64 (signs);
+  } while (signs &&
+           lgl->stats->gauss.steps.extr < lgl->limits->gauss.steps.extr);
+  if (signs) return 0;
+  for (q = d; (lit = *q); q++) *q = abs (lit);
+  *q = !negs;
+  LOGEQN (GL, start, "extracted %d-ary XOR constraint",  size);
+  lgl->stats->gauss.arity.sum += size;
+  if (lgl->stats->gauss.arity.max < size) lgl->stats->gauss.arity.max = size;
+  lgl->stats->gauss.extracted++;
+  return 1;
+}
+
+static int lglgaussextractxor (LGL * lgl, const int * c) {
+  int old = lglcntstk (&lgl->gauss->xors), res;
+  if (!(res = lglgaussextractxoraux (lgl, c)))
+    lglrststk (&lgl->gauss->xors, old);
+  return res;
+}
+
+static int lglgaussextractsmallit (LGL * lgl, int lit) {
+  int allxors = lgl->opts->gaussextrall.val;
+  int cls[4], blit, tag, other, other2;
+  const int * w, * eow, * p;
+  HTS * hts;
+  if (lgl->stats->gauss.steps.extr >= lgl->limits->gauss.steps.extr) 
+    return 0;
+  if (lglval (lgl, lit) > 0) return 1;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == OCCS || tag == LRGCS) continue;
+    other = blit >> RMSHFT;
+    if (!allxors && abs (other) < lit) continue;
+    cls[0] = lit;
+    cls[1] = other;
+    if (tag == TRNCS) {
+      other2 = *p;
+      if (!allxors && abs (other2) < lit) continue;
+      cls[2] = other2;
+      cls[3] = 0;
+    } else {
+      assert (tag == BINCS);
+      cls[2] = 0;
+    }
+    lglgaussextractxor (lgl, cls);
+  }
+  return 1;
+}
+
+static int lglgaussextractsmall (LGL * lgl) {
+  int64_t before = lgl->stats->gauss.extracted, after, delta;
+  int res;
+  lglrandlitrav (lgl, lglgaussextractsmallit);
+  after = lgl->stats->gauss.extracted;
+  delta = after - before;
+  res = (delta > INT_MAX) ? INT_MAX : delta;
+  return res;
+}
+
+static int lglgaussextractlarge (LGL * lgl) {
+  const int * p, * c;
+  int res = 0;
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    if (lgl->stats->gauss.steps.extr >= lgl->limits->gauss.steps.extr) break;
+    if (*(p = c) >= NOTALIT) continue;
+    res += lglgaussextractxor (lgl, c);
+    while (*p) p++;
+  }
+  return res;
+}
+
+static void lglgaussconeqn (LGL * lgl, int eqn) {
+  const int * xors = lgl->gauss->xors.start;
+  int i, var;
+  INCSTEPS (gauss.steps.elim);
+  for (i = eqn; (var = xors[i]) > 1; i++)
+    lglpushstk (lgl, lgl->gauss->occs + var, eqn);
+}
+
+static void lglgaussdiseqn (LGL * lgl, int eqn) {
+  int * xors = lgl->gauss->xors.start, i, var;
+  for (i = eqn; (var = xors[i]) > 1; i++) {
+    xors[i] = NOTALIT;
+    lgl->gauss->garbage++;
+    INCSTEPS (gauss.steps.elim);
+    lglrmstk (lgl->gauss->occs + var, eqn);
+  }
+  xors[i] = NOTALIT;
+  lgl->gauss->garbage++;
+}
+
+static void lglgaussconnect (LGL * lgl) {
+  int c, i, eox = lglcntstk (&lgl->gauss->xors), connected, var, vars;
+  const int * xors = lgl->gauss->xors.start;
+  Stk * occs;
+  LOG (2,  "connecting equations");
+  assert (!lgl->gauss->occs);
+  NEW (lgl->gauss->occs, lgl->nvars);
+  vars = connected = 0;
+  for (c = 0; c < eox; c = i + 1) {
+    INCSTEPS (gauss.steps.elim);
+    for (i = c; (var = xors[i]) > 1; i++) {
+      occs = lgl->gauss->occs + var;
+      if (lglmtstk (occs)) vars++;
+      lglpushstk (lgl, lgl->gauss->occs + var, c);
+      connected++;
+    }
+  }
+  lglprt (lgl, 1, 
+     "[gauss-%d] connected %d occurrences of %d variables (average %.1f)",
+      lgl->stats->gauss.count, connected, vars, lglavg (connected, vars));
+}
+
+static int lglgaussorderidx (LGL * lgl,  int var) {
+  assert (2 <= var && var < lgl->nvars);
+  if (!lglmtstk (lgl->gauss->occs + var))
+    lglpushstk (lgl, &lgl->gauss->order, var);
+  return 1;
+}
+
+static void lglgaussorder (LGL * lgl) {
+  lglrandidxtrav (lgl, lglgaussorderidx);
+  NEW (lgl->gauss->eliminated, lgl->nvars);
+}
+
+static void lglgaussdisconnect (LGL * lgl) {
+  int idx;
+  assert (lgl->gauss->occs);
+  LOG (2, "disconnecting equations");
+  for (idx = 2; idx < lgl->nvars; idx++)
+    lglrelstk (lgl, lgl->gauss->occs + idx);
+  DEL (lgl->gauss->occs, lgl->nvars);
+  assert (!lgl->gauss->occs);
+}
+
+static void lglgaussextract (LGL * lgl) {
+  int extracted, lits;
+  assert (lglsmallirr (lgl));
+  if (lgl->level) lglbacktrack (lgl, 0);
+  lglgc (lgl);
+  if (lgl->mt) return;
+  lgldense (lgl, 1);
+  extracted = lglgaussextractsmall (lgl);
+  extracted += lglgaussextractlarge (lgl);
+  lits = lglcntstk (&lgl->gauss->xors) - extracted;
+  lglprt (lgl, 1,
+    "[gauss-%d] extracted %d xors of average arity %.1f",
+    lgl->stats->gauss.count, extracted, lglavg (lits, extracted));
+  lglsparse (lgl);
+  lglgc (lgl);
+  if (lgl->mt) return;
+  lglfitstk (lgl, &lgl->gauss->xors);
+}
+
+static int lglgaussoccs (LGL * lgl, int a) {
+  return lglcntstk (lgl->gauss->occs + a);
+}
+
+static int lglcmpgauss (LGL * lgl, int a, int b) {
+  int res = lglgaussoccs (lgl, a) - lglgaussoccs (lgl, b);
+  if (!res) res = a - b;
+  return res;
+}
+
+#define LGLCMPGAUSS(A,B) lglcmpgauss (lgl, *(A), *(B))
+
+static void lglgaussort (LGL * lgl) {
+  int max = lglcntstk (&lgl->gauss->order), rest, * start;
+  assert (lgl->gauss->next <= max);
+  rest = max - lgl->gauss->next;
+  start = lgl->gauss->order.start + lgl->gauss->next;
+  ADDSTEPS (gauss.steps.elim, rest);
+  SORT (int, start, rest, LGLCMPGAUSS);
+  lglprt (lgl, 3, 
+     "[gauss-%d] sorted %d remaining variables",
+      lgl->stats->gauss.count, rest);
+}
+
+static int lglgausspickeqn (LGL * lgl, int pivot) {
+  int res, cand, weight, size, tmp, other, found;
+  const int * p, * e, * q;
+  Stk * occs;
+  assert (lglgaussoccs (lgl, pivot));
+  res = -1;
+  weight = INT_MAX; size = INT_MAX;
+  occs = lgl->gauss->occs + pivot;
+  for (p = occs->start; p < occs->top; p++) {
+    e = lgl->gauss->xors.start + (cand = *p);
+    found = tmp = 0;
+    INCSTEPS (gauss.steps.elim);
+    for (q = e; (other = *q) > 1; q++) {
+      if (lgl->gauss->eliminated[other]) break;
+      if (other == pivot) { assert (!found); found++; continue; }
+      tmp += lglgaussoccs (lgl, other) - 1;
+    }
+    if (other > 1) continue;
+    assert (found);
+    if (res >= 0 && q - e >= size) continue;
+    if (res >= 0 && q - e == size && tmp >= weight) continue;
+    weight = tmp;
+    size = q - e;
+    res = cand;
+  }
+  if (res >= 0)
+    LOGEQN (2, res, "picking size %d weight %d equation", size, weight);
+  else
+    LOG (2, "no uneliminated equation for pivot %d left", pivot);
+  return res;
+}
+
+static void lglcpystk (LGL * lgl, Stk * dst, Stk * src) {
+  const int * p;
+  for (p = src->start; p < src->top; p++)
+    lglpushstk (lgl, dst, *p);
+}
+
+static int lglgaussaddeqn (LGL * lgl, int eqn) {
+  const int * p;
+  AVar * av;
+  int var;
+  for (p = lgl->gauss->xors.start + eqn; (var = *p) > 1; p++) {
+    av = lglavar (lgl, var);
+    if (!av->mark) lglpushstk (lgl, &lgl->clause, var);
+    av->mark = !av->mark;
+  }
+  return var;
+}
+
+static void lglgaussubst (LGL * lgl, int pivot, int subst) {
+  Stk * occs = lgl->gauss->occs + pivot;
+  int eqn, rhs, res;
+  const int * p;
+  int * q;
+  assert (lglcntstk (occs) > 1);
+  while (lglcntstk (occs) > 1) {
+    if (lglterminate (lgl)) return;
+    eqn = occs->start[0];
+    if (eqn == subst) eqn = occs->start[1];
+    assert (lglmtstk (&lgl->clause));
+    LOGEQN (2, subst, "  1st row (kept)     ");
+    rhs = lglgaussaddeqn (lgl, eqn);
+    LOGEQN (2, eqn, "  2nd row (replaced) ");
+    if (lglgaussaddeqn (lgl, subst)) rhs = !rhs;
+    lglgaussdiseqn (lgl, eqn);
+    q = lgl->clause.start;
+    for (p = q; p < lgl->clause.top; p++)
+      if (lglmarked (lgl, *p)) *q++ = *p;
+    lgl->clause.top = q;
+    if (!lglmtstk (&lgl->clause)) {
+      res = lglcntstk (&lgl->gauss->xors);
+      lglcpystk (lgl, &lgl->gauss->xors, &lgl->clause);
+      lglpushstk (lgl, &lgl->gauss->xors, rhs);
+      LOGEQN (2, res, "  result row         ");
+      lglgaussconeqn (lgl, res);
+    } else if (rhs == 0) {
+      LOG (2, "trivial result row 0 = 0");
+    } else {
+      assert (rhs == 1);
+      LOG (1, "inconsistent result row 0 = 1 from gaussian elimination");
+      lgl->mt= 1;
+    }
+    lglpopnunmarkstk (lgl, &lgl->clause);
+  }
+}
+
+static void lglgausschkeliminated (LGL * lgl) {
+#ifndef NDEBUG
+  int idx, eliminated, occs;
+  if (!lgl->opts->check.val) return;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    eliminated = lgl->gauss->eliminated[idx];
+    occs = lglgaussoccs (lgl, idx);
+    if (eliminated == 1) assert (occs == 1);
+    if (eliminated == 2) assert (occs == 0);
+  }
+#endif
+}
+
+static void lglgaussgc (LGL * lgl) {
+  int count = lglcntstk (&lgl->gauss->xors), * q;
+  const int * p;
+  if (lgl->gauss->garbage < count/2 + 10000) return;
+  lgl->stats->gauss.gcs++;
+  lglprt (lgl, 2, 
+     "[gauss-%d] collecting %d garbage out of %d",
+     lgl->stats->gauss.count, lgl->gauss->garbage, count);
+  lglgaussdisconnect (lgl);
+  q = lgl->gauss->xors.start;
+  for (p = q; p < lgl->gauss->xors.top; p++)
+    if (*p != NOTALIT) *q++ = *p;
+  lgl->gauss->xors.top = q;
+  lglfitstk (lgl, &lgl->gauss->xors);
+  lglgaussconnect (lgl);
+  lgl->gauss->garbage = 0;
+}
+
+static int lglgausselimvar (LGL * lgl, int pivot) {
+  int subst, changed, occs, eliminated;
+  LOG (2, "eliminating variable %d occurring %d times",
+       pivot, lglgaussoccs (lgl, pivot));
+  assert (!lgl->gauss->eliminated[pivot]);
+  if (!(occs = lglgaussoccs (lgl, pivot))) {
+    LOG (2, "variable %d disappeared ", pivot);
+    eliminated = 2;
+    changed = 0;
+  } else if (occs == 1) {
+    LOG (2, "eliminated variable %d occurrs exactly once", pivot);
+    eliminated = 1;
+    changed = 0;
+  } else {
+    lglgaussgc (lgl);
+    subst = lglgausspickeqn (lgl, pivot);
+    if (subst >= 0) {
+      lglgaussubst (lgl, pivot, subst);
+      eliminated = 1;
+      changed = 1;
+    } else {
+      eliminated = 3;
+      changed = 0;
+    }
+  }
+  lgl->gauss->eliminated[pivot] = eliminated;
+  lglgausschkeliminated (lgl);
+  return changed;
+}
+
+static void lglgausselim (LGL * lgl) {
+  int pivot, changed = 1;
+  while (!lgl->mt && lgl->gauss->next < lglcntstk (&lgl->gauss->order)) {
+    if (lgl->stats->gauss.steps.elim >= lgl->limits->gauss.steps.elim) break;
+    if (lglterminate (lgl)) break;
+    if (changed) lglgaussort (lgl);
+    pivot = lglpeek (&lgl->gauss->order, lgl->gauss->next++);
+    changed = lglgausselimvar (lgl, pivot);
+  }
+}
+
+static void lglgaussinit (LGL * lgl) {
+  assert (!lgl->gauss);
+  NEW (lgl->gauss, 1);
+}
+
+static void lglgaussreset (LGL * lgl) {
+  assert (lgl->gauss);
+  if (lgl->gauss->occs) lglgaussdisconnect (lgl);
+  if (lgl->gauss->eliminated) DEL (lgl->gauss->eliminated, lgl->nvars);
+  lglrelstk (lgl, &lgl->gauss->xors);
+  lglrelstk (lgl, &lgl->gauss->order);
+  DEL (lgl->gauss, 1);
+}
+
+static int lglgaussexp2 (LGL * lgl, int a, int b) {
+  assert (lgl->gaussing);
+  assert (lglmtstk (&lgl->clause));
+  if (lglhasbin (lgl, a, b)) return 0;
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOGCLS (2, lgl->clause.start, "gauss exported binary clause");
+  assert (!lgl->opts->drup.val);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+  lgladdcls (lgl, REDCS, 0, 0);
+  lglclnstk (&lgl->clause);
+  return 1;
+}
+
+static int lglgaussexp3 (LGL * lgl, int a, int b, int c) {
+  assert (lgl->gaussing);
+  assert (lglmtstk (&lgl->clause));
+  if (lglhastrn (lgl, a, b, c)) return 0;
+  lglpushstk (lgl, &lgl->clause, a);
+  lglpushstk (lgl, &lgl->clause, b);
+  lglpushstk (lgl, &lgl->clause, c);
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOGCLS (2, lgl->clause.start, "gauss exported ternary clause");
+  assert (!lgl->opts->drup.val);
+#ifndef NLGLPICOSAT
+  lglpicosatchkcls (lgl);
+#endif
+  lgladdcls (lgl, REDCS, 0, 0);
+  lglclnstk (&lgl->clause);
+  return 1;
+}
+
+static int lglgaussexport (LGL * lgl) {
+  int var, size, val, rhs, unit, a, b, c, exported;
+  const int * e, * p, * q;
+  for (e = lgl->gauss->xors.start; e < lgl->gauss->xors.top; e = p + 1) {
+    if (*(p = e) >= NOTALIT) continue;
+    while ((var = *p) > 1) p++;
+    rhs = *p;
+    assert (lglmtstk (&lgl->clause));
+    for (q = e; q < p; q++) {
+      var = *q;
+      val = lglval (lgl, var);
+      if (val < 0) continue;
+      if (val > 0) { rhs = !rhs; continue; }
+      lglpushstk (lgl, &lgl->clause, var);
+    }
+    size = lglcntstk (&lgl->clause);
+    if (!size && !rhs) continue;
+    if (!size && rhs) {
+      LOGEQN (1, e - lgl->gauss->xors.start, 
+              "gauss exporting inconsistent equation");
+      return 0;
+    }
+    a = (size > 0) ? lgl->clause.start[0] : 0;
+    b = (size > 1) ? lgl->clause.start[1] : 0;
+    c = (size > 2) ? lgl->clause.start[2] : 0;
+    lglclnstk (&lgl->clause);
+    if (size == 1) {
+      unit = a;
+      if (!rhs) unit = -unit;
+      LOG (1, "gauss exporting unit %d", unit);
+      lgl->stats->gauss.units++;
+      lglunit (lgl, unit);
+    } else if (size == 2) {
+      if (rhs) b = -b;
+      exported = lglgaussexp2 (lgl, -a, b);
+      exported |= lglgaussexp2 (lgl, a, -b);
+      if (exported) {
+       LOG (1, "gauss exporting equivalence %d = %d", a, b);
+       lgl->stats->gauss.equivs++;
+      }
+    } else if (size == 3 && lgl->opts->gaussexptrn.val) {
+      if (!rhs) c = -c;
+      exported = lglgaussexp3 (lgl, a, b, c);
+      exported |= lglgaussexp3 (lgl, a, -b, -c);
+      exported |= lglgaussexp3 (lgl, -a, b, -c);
+      exported |= lglgaussexp3 (lgl, -a, -b, c);
+      if (exported) {
+       LOG (1, "gauss exporting ternary equation %d + %d + %d = 1", 
+            a, b, c);
+       lgl->stats->gauss.trneqs++;
+      }
+    }
+  }
+  return 1;
+}
+
+static void lglsetgausslim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->gaussreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->gaussmineff.val) limit = lgl->opts->gaussmineff.val;
+  if (lgl->opts->gaussmaxeff.val >= 0 && limit > lgl->opts->gaussmaxeff.val)
+    limit = lgl->opts->gaussmaxeff.val;
+  limit >>= (pen = lgl->limits->gauss.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur/2;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1, "[gauss-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->gauss.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[gauss-%d] limit %lld penalty %d = %d + %d",
+      lgl->stats->gauss.count, (LGLL) limit,
+      pen, lgl->limits->gauss.pen, lglszpen (lgl));
+  lgl->limits->gauss.steps.extr = lgl->stats->gauss.steps.extr + limit;
+  lgl->limits->gauss.steps.elim = lgl->stats->gauss.steps.elim + limit;
+}
+
+static int lglgauss (LGL * lgl) {
+  int oldunits, oldequivs, oldtrneqs;
+  int units, equivs, trneqs;
+  int success;
+  assert (lgl->opts->gauss.val);
+  if (lgl->mt) return 0;
+  if (lgl->nvars <= 2) return 1;
+  lglstart (lgl, &lgl->times->gauss);
+  assert (!lgl->simp && !lgl->gaussing);
+  lgl->simp = lgl->gaussing = 1;
+  lgl->stats->gauss.count++;
+  lglsetgausslim (lgl);
+  lglgaussinit (lgl);
+  lglgaussextract (lgl);
+  oldunits = lgl->stats->gauss.units;
+  oldequivs = lgl->stats->gauss.equivs;
+  oldtrneqs = lgl->stats->gauss.trneqs;
+  if (!lglmtstk (&lgl->gauss->xors)) {
+    lglgaussconnect (lgl);
+    lglgaussorder (lgl);
+    lglsetgausslim (lgl);
+    lglgausselim (lgl);
+    if (!lgl->mt && !lglterminate (lgl)) {
+      if (lgl->opts->verbose.val >= 3) lglgdump (lgl);
+      lglgaussdisconnect (lgl);
+      if (!lglgaussexport (lgl) || !lglbcp (lgl)) lgl->mt = 1;
+      else if (lgl->limits->gauss.steps.extr > lgl->stats->gauss.steps.extr &&
+               lgl->limits->gauss.steps.elim > lgl->stats->gauss.steps.elim)
+       lglprt (lgl, 1, "[gauss-%d] fully completed", lgl->stats->gauss.count);
+    }
+  }
+  lglgaussreset (lgl);
+  units = lgl->stats->gauss.units - oldunits;
+  equivs = lgl->stats->gauss.equivs - oldequivs;
+  trneqs = lgl->stats->gauss.trneqs - oldtrneqs;
+  success = units || equivs;
+  if (!lgl->mt && success && !lglterminate (lgl) && lgl->opts->decompose.val)
+    lgldecomp (lgl);
+  if (trneqs) success = 1;
+  if (lgl->mt)
+    lglprt (lgl, 1, "[gauss-%d] proved unsatisfiability",
+      lgl->stats->gauss.count);
+  else {
+    lglprt (lgl, 1, 
+      "[gauss-%d] exported %d unary, %d binary and %d ternary equations",
+      lgl->stats->gauss.count, units, equivs, trneqs);
+  }
+  LGLUPDPEN (gauss, success);
+  lglrep (lgl, 2, 'G');
+  assert (lgl->simp && lgl->gaussing);
+  lgl->simp = lgl->gaussing = 0;
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+/*------------------------------------------------------------------------*/
+
+#define CARDLOGLEVEL 2
+
+static int lglcardsub (LGL * lgl, const int * lits, int bound) {
+  int count, size, res, minlit, minocc, nocc, lit, pos, otherbound;
+  Card * card = lgl->card;
+  const int * p, * c, * q;
+  Stk * s;
+  minocc = INT_MAX;
+  minlit = 0;
+  for (p = lits; minocc && (lit = *p); p++) {
+    lglmarkunmarked (lgl, lit);
+    s = card->occs + lit;
+    INCSTEPS (card.steps);
+    nocc = lglcntstk (s);
+    if (nocc > minocc) continue;
+    minlit = lit;
+    minocc = nocc;
+  }
+  res = 0;
+  if (minocc && minlit) {
+    size = p - lits;
+    s = card->occs + minlit;
+    for (p = s->start; p < s->top; p++) {
+      pos = *p;
+      c = card->cards.start + pos;
+      INCSTEPS (card.steps);
+      otherbound = *c;
+      if (otherbound > bound) continue;
+      count = 0;
+      INCSTEPS (card.steps);
+      for (q = c + 1; *q; q++) count++;
+      if (count < size) continue;
+      count = 0;
+      INCSTEPS (card.steps);
+      for (q = c + 1; (count < size) && (lit = *q); q++)
+       if (lglmarked (lgl, lit) > 0) count++;
+      if (count >= size) {
+       LOGCLS (CARDLOGLEVEL, lits,
+         "subsumed cardinality constraint %d >=", bound);
+       LOGCLS (CARDLOGLEVEL, c + 1,
+         "subsuming cardinality constraint %d >=", otherbound);
+       res = 1;
+      }
+    }
+  }
+  for (p = lits; (lit = *p); p++) lglunmark (lgl, lit);
+  return res;
+}
+
+static int lglcard1sub (LGL * lgl, const int * lits) {
+  int res, minlit, minocc, nocc, lit, count, size;
+  Card * card = lgl->card;
+  const int * p, * c, * q;
+  Stk * s;
+  minocc = INT_MAX;
+  minlit = 0;
+  for (p = lits; minocc && (lit = *p); p++) {
+    lglmarkunmarked (lgl, lit);
+    s = card->occs + lit;
+    INCSTEPS (card.steps);
+    nocc = lglcntstk (s);
+    if (nocc > minocc) continue;
+    minlit = lit;
+    minocc = nocc;
+  }
+  res = 0;
+  if (!minocc || !minlit) goto DONE;
+  size = p - lits;
+  s = card->occs + minlit;
+  count = 0;
+  for (p = s->start; !res && p < s->top; p++) {
+    c = card->atmost1.start + *p;
+    for (q = c; (lit = *q); q++)
+      if (lglmarked (lgl, lit) && ++count >= size)
+       break;
+    if (!lit) continue;
+    LOGCLS (CARDLOGLEVEL, lits,
+      "subsumed at-most-one cardinality constraint 1 >=");
+    LOGCLS (CARDLOGLEVEL, c,
+      "subsuming at-most-one cardinality constraint 1 >=");
+    res = 1;
+  }
+DONE:
+  for (p = lits; (lit = *p); p++) lglunmark (lgl, lit);
+  return res;
+}
+
+static int lglcard2sub (LGL * lgl, const int * lits, int * minlitptr) {
+  int res, minlit, minocc, nocc, lit, count, size;
+  Card * card = lgl->card;
+  const int * p, * c, * q;
+  Stk * s;
+  minocc = INT_MAX;
+  minlit = 0;
+  for (p = lits; minocc && (lit = *p); p++) {
+    lglmarkunmarked (lgl, lit);
+    s = card->occs + lit;
+    INCSTEPS (card.steps);
+    nocc = lglcntstk (s);
+    if (nocc > minocc) continue;
+    minlit = lit;
+    minocc = nocc;
+  }
+  assert (!minocc || p + 1 == card->atmost2.top);
+  res = 0;
+  if (!minocc || !minlit || *minlitptr == minlit) goto DONE;
+  *minlitptr = minlit;
+  size = p - lits;
+  s = card->occs + minlit;
+  count = 0;
+  for (p = s->start; !res && p < s->top; p++) {
+    c = card->atmost2.start + *p;
+    for (q = c; (lit = *q); q++)
+      if (lglmarked (lgl, lit) && ++count >= size)
+       break;
+    if (!lit) continue;
+    LOGCLS (CARDLOGLEVEL, lits,
+      "subsumed at-most-two cardinality constraint 2 >=");
+    LOGCLS (CARDLOGLEVEL, c,
+      "subsuming at-most-two cardinality constraint 2 >=");
+    res = 1;
+  }
+DONE:
+  for (p = lits; (lit = *p); p++) lglunmark (lgl, lit);
+  return res;
+}
+
+static int lgladdcard (LGL * lgl, const int * lits, int bound) {
+  Card * card = lgl->card;
+  const int * p;
+  int start, lit;
+#if !defined(NDEBUG) || !defined(NLGLOG)
+  int size = 0;
+  for (p = lits; *p; p++) size++;
+#endif
+  if (lglcardsub (lgl, lits, bound)) {
+    lgl->stats->card.subsumed++;
+    return 0;
+  }
+  LOGCLS (CARDLOGLEVEL, lits,
+    "new %s cardinality constraint %d >=",
+    (bound + 1 < size ? "real" : "pseudo"), bound);
+  assert (bound <= size);
+  assert (size <=
+    lglfactor (lgl, lgl->stats->card.count, lgl->opts->cardmaxlen.val));
+#ifndef NDEBUG
+  for (p = lits; (lit = *p); p++) assert (!card->eliminated[abs (lit)]);
+  for (p = lits; (lit = *p); p++) assert (!card->count[abs (lit)]);
+#endif
+  assert (card);
+  start = lglcntstk (&card->cards);
+  lglpushstk (lgl, &card->cards, bound);
+  for (p = lits; (lit = *p); p++) {
+    lglpushstk (lgl, &card->cards, lit);
+    lglpushstk (lgl, card->occs + lit, start);
+  }
+  lglpushstk (lgl, &card->cards, 0);
+  return 1;
+}
+
+static void lglcardfmstep (LGL * lgl, int pivot,
+                           int cardposidx, int cardnegidx) {
+  int bn, bp, ln, lp, b, c, s, lit, idx, addcard, len, unit[2], div, elim;
+  const int cardcut = lgl->opts->cardcut.val;
+  const int * p, * q, * cn, * cp;
+  int * r, divsame, cardmaxlen;
+  Card * card = lgl->card;
+  INCSTEPS (card.steps);
+  lgl->stats->card.resolved++;
+  assert (0 <= cardposidx && cardposidx < lglcntstk (&card->cards));
+  assert (0 <= cardnegidx && cardnegidx < lglcntstk (&card->cards));
+  cp = card->cards.start + cardposidx;
+  cn = card->cards.start + cardnegidx;
+  bp = *cp++; assert (bp >= 0);
+  bn = *cn++; assert (bp >= 0);
+  LOGCLS (CARDLOGLEVEL, cp,
+    "first antecedent fourier-motzkin on %d cardinality constraint %d >=",
+    pivot, bp);
+  LOGCLS (CARDLOGLEVEL, cn,
+    "second antecedent fourier-motzkin on %d cardinality constraint %d >=",
+    -pivot, bn);
+  b = bp + bn;
+  LOG (CARDLOGLEVEL, "starting with bound %d", b);
+  assert (lglmtstk (&lgl->clause));
+  for (p = cp; (lit = *p); p++) {
+    idx = abs (lit);
+    assert (!card->count[idx]);
+    lglpushstk (lgl, &lgl->clause, idx);
+    card->count[idx] += lglsgn (lit);
+  }
+  lp = p - cp;
+  assert (bp < lp);
+  elim = 0;
+  div = 1;
+  for (q = cn; (lit = *q); q++) {
+    idx = abs (lit);
+    c = card->count[idx];
+    assert (!c || abs (c) == 1);
+    s = lglsgn (lit);
+    if (!c) lglpushstk (lgl, &lgl->clause, idx);
+    card->count[idx] += s;
+    if (c && c != s) elim++;
+    if (c == s) div = 2;
+  }
+  ln = q - cn;
+  assert (bn < ln);
+  divsame = 1;
+  for (p = lgl->clause.start; divsame && p < lgl->clause.top; p++) {
+    idx = abs (*p);
+    c = card->count[idx];
+    if (!c) continue;
+    if (c < 0) c = -c;
+    divsame = (c == div);
+  }
+#ifndef NLGLOG
+  if (lgl->opts->log.val >= CARDLOGLEVEL) {
+    int first = 1;
+    lglogstart (lgl, CARDLOGLEVEL,
+      "pseudo-boolean resolvent %d - %d >= ", b, elim);
+    for (p = lgl->clause.start; p < lgl->clause.top; p++) {
+      idx = *p;
+      assert (1 < idx), assert (idx < lgl->nvars);
+      c = card->count[idx];
+      if (!c) continue;
+      if (!first)
+       fprintf (lgl->out, " %c ", (c < 0) ? '-' : '+');
+      else if (c < 0)
+       fputs ("-", lgl->out);
+      first = 0;
+      c = abs (c);
+      assert (c > 0);
+      if (c != 1) fprintf (lgl->out, "%d*", c);
+      fprintf (lgl->out, "%d", idx);
+    }
+    if (first) fputs ("0", lgl->out);
+    lglogend (lgl);
+  }
+#endif
+  LOG (CARDLOGLEVEL,
+    "size %d cardinalty resolvent contains %d eliminated division %d %s", 
+    lglcntstk (&lgl->clause) - elim, elim, div, divsame ? "all" : "some");
+  r = lgl->clause.start;
+  for (p = r; p < lgl->clause.top; p++) {
+    idx = *p;
+    c = card->count[idx];
+    if (divsame || cardcut == 1) c /= div;
+    else if (abs (c) != 1 && cardcut == 2 && div == 2) c = 0;
+    if (!c) continue;
+    lit = (c < 0) ? -idx : idx;
+    *r++ = lit;
+  }
+  lgl->clause.top = r;
+  b -= elim;
+  assert (div == 1 || div == 2);
+  if ((divsame || cardcut == 1) && div == 2) b /= 2;
+  len = lglcntstk (&lgl->clause);
+  lglpushstk (lgl, &lgl->clause, 0);
+  addcard = 0;
+  cardmaxlen =
+    lglfactor (lgl, lgl->stats->card.count, lgl->opts->cardmaxlen.val);
+  if (!cardcut && div > 1) {
+    LOG (CARDLOGLEVEL,
+      "ignoring resolved cardinality constraint which requires cut");
+    assert (!addcard);
+  } else if (b < 0) {
+    assert (!addcard);
+    assert (!lgl->mt);
+    LOGCLS (CARDLOGLEVEL, lgl->clause.start,
+      "inconsistent cardinality constraint %d >=", b);
+    lgl->mt = 1;
+  } else if (b == 0) {
+    assert (!addcard);
+    LOGCLS (CARDLOGLEVEL, lgl->clause.start,
+      "forcing cardinality constraint %d >=", b);
+    for (p = lgl->clause.start; p < lgl->clause.top - 1; p++) {
+      lit = *p;
+      assert (lit);
+      lgl->stats->card.units++;
+      lglpushstk (lgl, &lgl->card->units, -lit);
+      card->count[abs (lit)] = 0;
+      unit[0] = lit;
+      unit[1] = 0;
+      (void) lgladdcard (lgl, unit, 0);
+    }
+  } else if (b >= len) {
+    LOGCLS (CARDLOGLEVEL, lgl->clause.start,
+      "trivial resolved cardinality constraint %d >=", b);
+    assert (!addcard);
+  } else if (len > cardmaxlen) {
+    LOGCLS (CARDLOGLEVEL, lgl->clause.start, 
+      "length %d exceeds limit %d of resolved cardinality constraint %d >=",
+      len, cardmaxlen, b);
+  } else {
+    addcard = 1;
+    assert (0 < b);
+    LOGCLS (CARDLOGLEVEL, lgl->clause.start,
+      "resolved cardinality constraint %d >=", b);
+    if (b == 1 && 
+        ((ln >= 3 && lp >= 3) ||
+         lglcntstk (&lgl->clause) > 
+          lglfactor (lgl,
+            lgl->stats->card.count, lgl->opts->cardexpam1.val))) {
+      LOGCLS (CARDLOGLEVEL, lgl->clause.start,
+        "saving to export at-most-one constraint 1 >=");
+      for (p = lgl->clause.start; p < lgl->clause.top; p++)
+       lglpushstk (lgl, &lgl->card->expam1, *p);
+    }
+  }
+  cp = card->cards.start + cardposidx + 1;
+  cn = card->cards.start + cardnegidx + 1;
+  for (p = cp; (lit = *p); p++) card->count[abs (lit)] = 0;
+  for (q = cn; (lit = *q); q++) card->count[abs (lit)] = 0;
+  if (addcard > 0) (void) lgladdcard (lgl, lgl->clause.start, b);
+  lglclnstk (&lgl->clause);
+  // COVER (cardcut == 2 && div == 2 && divsame);
+}
+
+static void lglrmcardexcept (LGL * lgl, int cardidx, int except) {
+  Card * card = lgl->card;
+  int * c, * p, lit;
+  assert (0 <= cardidx && cardidx < lglcntstk (&card->cards));
+  c = card->cards.start + cardidx + 1;
+  LOGCLS (CARDLOGLEVEL, c, "removing cardinality constraint %d >=", c[-1]);
+  for (p = c; (lit = *p); p++)
+    if (lit != except)
+      lglrmstk (card->occs + lit, cardidx);
+}
+
+static int lglcardocc (LGL * lgl, int a) {
+  return lglcntstk (lgl->card->occs + a);
+}
+
+static int lglcmpcard (LGL * lgl, int a, int b) {
+  int64_t s = lglcardocc (lgl, a) * (int64_t) lglcardocc (lgl, -a);
+  int64_t t = lglcardocc (lgl, b) * (int64_t) lglcardocc (lgl, -b);
+  if (s > t) return -1;
+  if (s < t) return 1;
+  return b - a;
+}
+
+#define LGLCMPCARD(A,B) lglcmpcard (lgl, *(A), *(B))
+
+static void lglcardresched (LGL * lgl) {
+  Stk * elim = &lgl->card->elim;
+  int count = lglcntstk (elim);
+  ADDSTEPS (card.steps, 4*count);
+  SORT (int, elim->start, lglcntstk (elim), LGLCMPCARD);
+  lgl->stats->card.resched++;
+}
+
+static void lglcardfmlit (LGL * lgl, int pivot) {
+  Stk * poccs = lgl->card->occs + pivot, * noccs = lgl->card->occs - pivot;
+  int pcnt = lglcntstk (poccs), ncnt = lglcntstk (noccs);
+  int count = lgl->stats->card.count;
+  const int * p, * q;
+  assert (pivot > 0);
+  assert (!lgl->card->eliminated[pivot]);
+  if (!pcnt || !ncnt) goto DONE;
+  if (pcnt > lglfactor (lgl, lgl->opts->cardocclim1.val, count)) goto DONE;
+  if (ncnt > lglfactor (lgl, lgl->opts->cardocclim1.val, count)) goto DONE;
+  if (pcnt > lglfactor (lgl, lgl->opts->cardocclim2.val, count) &&
+      ncnt > lglfactor (lgl, lgl->opts->cardocclim2.val, count)) goto DONE;
+  lgl->stats->card.eliminated++;
+  lgl->card->eliminated[pivot] = 1;
+  LOG (CARDLOGLEVEL,
+    "fourier-motzkin pivot %d with %d positive and %d negative occurrences",
+    pivot, pcnt, ncnt);
+  for (p = poccs->start; !lgl->mt && p < poccs->top; p++)
+    for (q = noccs->start; !lgl->mt && q < noccs->top; q++)
+      lglcardfmstep (lgl, pivot, *p, *q);
+DONE:
+  for (p = poccs->start; !lgl->mt && p < poccs->top; p++) {
+    lglrmcardexcept (lgl, *p, pivot);
+    INCSTEPS (card.steps);
+  }
+  for (q = noccs->start; !lgl->mt && q < noccs->top; q++) {
+    lglrmcardexcept (lgl, *q, -pivot);
+    INCSTEPS (card.steps);
+  }
+  lglrelstk (lgl, poccs);
+  lglrelstk (lgl, noccs);
+  if (!(lgl->stats->card.eliminated % lgl->opts->cardreschedint.val))
+    lglcardresched (lgl);
+}
+
+static void lglcardfm (LGL * lgl) {
+  Stk * elim;
+  lglcardresched (lgl);
+  elim = &lgl->card->elim;
+  while (!lgl->mt && 
+         !lglmtstk (elim) &&
+         !lglterminate (lgl) &&
+         lgl->limits->card.steps >= INCSTEPS (card.steps))
+    lglcardfmlit (lgl, lglpopstk (elim));
+}
+
+static int64_t lglsetcardlim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->cardreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->cardmineff.val) limit = lgl->opts->cardmineff.val;
+  if (lgl->opts->cardmaxeff.val >= 0 && limit > lgl->opts->cardmaxeff.val)
+    limit = lgl->opts->cardmaxeff.val;
+  limit >>= (pen = lgl->limits->card.pen + lglszpen (lgl));
+  irrlim = lgl->stats->irr.clauses.cur/4;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[card-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->card.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[card-%d] limit %lld penalty %d = %d + %d",
+      lgl->stats->card.count, (LGLL) limit,
+      pen, lgl->limits->card.pen, lglszpen (lgl));
+  lgl->limits->card.steps = lgl->stats->card.steps + limit;
+  return limit;
+}
+
+static void lglsetcardlimagain (LGL * lgl, int64_t limit) {
+  lglprt (lgl, 1,
+    "[card-%d] using previous limit %lld for elimination",
+    lgl->stats->card.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  lgl->limits->card.steps = lgl->stats->card.steps + limit;
+}
+
+static int lglcard1extractlit (LGL * lgl, int lit) {
+  const int ignused = lgl->opts->cardignused.val;
+  int start, size, trivial, subsumed;
+  int blit, tag, other, other2, i;
+  const int * p, * w, * eow;
+  Card * card;
+  HTS * hts;
+  if (lglterminate (lgl)) return 0;
+  if (lgl->limits->card.steps < INCSTEPS (card.steps)) return 0;
+  card = lgl->card;
+  if (ignused && card->lit2used[lit]) return 1;
+  start = lglcntstk (&card->atmost1);
+  LOG (CARDLOGLEVEL + 1,
+    "starting at-most-one clique[%d] for %d",
+    start, lit);
+  lglpushstk (lgl, &card->atmost1, lit);
+  card->marked[lit] = 1;
+  hts = lglhts (lgl, -lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  INCSTEPS (card.steps);
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    other = -(blit >> RMSHFT);
+    if (ignused && card->lit2used[other]) continue;
+    for (i = start + 1; i < lglcntstk (&card->atmost1); i++) {
+      other2 = lglpeek (&card->atmost1, i);
+      INCSTEPS (card.steps);
+      if (!lglhasbin (lgl, -other, -other2)) break;
+    }
+    if (i < lglcntstk (&card->atmost1)) continue;
+    card->marked[other] = 1;
+    lglpushstk (lgl, &card->atmost1, other);
+    LOG (CARDLOGLEVEL + 1,
+       "adding %d to at-most-one clique[%d] for %d", other, start, lit);
+  }
+  size = lglcntstk (&card->atmost1) - start;
+  trivial = (size <= 2);
+  if (!ignused) {
+    lglpushstk (lgl, &card->atmost1, 0);
+    subsumed = lglcard1sub (lgl, card->atmost1.start + start);
+    lglpopstk (&card->atmost1);
+  } else subsumed = 0;
+  for (p = card->atmost1.start + start; p < card->atmost1.top; p++) {
+    other = *p;
+    assert (card->marked[other]);
+    card->marked[other] = 0;
+    if (!trivial && !subsumed) card->lit2used[other] = 1;
+  }
+  if (trivial || subsumed) {
+    LOG (CARDLOGLEVEL + 1,
+      "resetting at-most-one clique[%d] for %d of trivial size %d",
+      start, lit, size);
+    lglrststk (&card->atmost1, start);
+  } else {
+#ifndef NLGLOG
+    if (lgl->opts->log.val >= CARDLOGLEVEL) {
+      lglogstart (lgl, CARDLOGLEVEL,
+       "non trivial size %d at-most-one constraint 1 >= ", size);
+      for (i = start; i < start + size; i++) {
+       if (i > start) fputs (" + ", lgl->out);
+       fprintf (lgl->out, "%d", lglpeek (&card->atmost1, i));
+      }
+      lglogend (lgl);
+    }
+#endif
+    if (!ignused) {
+      for (i = start; i < start + size; i++) {
+       other = lglpeek (&card->atmost1, i);
+       lglpushstk (lgl, &card->occs[other], start);
+      }
+    }
+    lglpushstk (lgl, &card->atmost1, 0);
+    lgl->stats->card.am1.found.sum += size;
+    lgl->stats->card.am1.found.cnt++;
+  }
+  return 1;
+}
+
+static void lglcardreloccs (LGL * lgl) {
+  Card * card = lgl->card;
+  int sign, idx, lit;
+  assert (card), assert (!lgl->nvars || card->occs);
+  for (sign = -1; sign <= 1; sign += 2)
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      lit = sign * idx;
+      lglrelstk (lgl, &card->occs[lit]);
+    }
+  card->occs -= lgl->nvars;
+  DEL (card->occs, 2*lgl->nvars);
+}
+
+static int lglcard1extract (LGL * lgl) {
+  struct { int cnt; int64_t sum; } before, after, delta;
+  const int ignused = lgl->opts->cardignused.val;
+  Card * card = lgl->card;
+
+  lglpushstk (lgl, &card->atmost1, 0);
+
+  NEW (card->lit2used, 2*lgl->nvars);
+  card->lit2used += lgl->nvars;
+  NEW (card->marked, 2*lgl->nvars);
+  card->marked += lgl->nvars;
+  if (!ignused) {
+    NEW (card->occs, 2*lgl->nvars);
+    card->occs += lgl->nvars;
+  }
+
+  before.cnt = lgl->stats->card.am1.found.cnt;
+  before.sum = lgl->stats->card.am1.found.sum;
+
+  lglrandlitrav (lgl, lglcard1extractlit);
+
+  after.cnt = lgl->stats->card.am1.found.cnt;
+  after.sum = lgl->stats->card.am1.found.sum;
+  assert (after.cnt >= before.cnt);
+  assert (after.sum >= before.sum);
+  delta.cnt = after.cnt - before.cnt;
+  delta.sum = after.sum - before.sum;
+
+  card->lit2used -= lgl->nvars;
+  DEL (card->lit2used, 2*lgl->nvars);
+  card->marked -= lgl->nvars;
+  DEL (card->marked, 2*lgl->nvars);
+  if (!ignused) lglcardreloccs (lgl);
+
+  if (delta.cnt)
+    lglprt (lgl, 1, 
+      "[card-%d] found %d at-most-one constraints of average size %.1f",
+      lgl->stats->card.count, delta.cnt, lglavg (delta.sum, delta.cnt));
+  else
+    lglprt (lgl, 1,
+      "[card-%d] no at-most-one constraint found",
+      lgl->stats->card.count);
+
+  return delta.cnt;
+}
+
+static int lglcard2extractlit (LGL * lgl, int lit) {
+  int blit, tag, other, other2, other3, i, j, k, res = 1;
+  const int ignused = lgl->opts->cardignused.val;
+  int start, size, minlit;
+  const int * p, * w, * eow;
+  int * q;
+  Card * card;
+  HTS * hts;
+  if (lglterminate (lgl)) return 0;
+  if (lgl->limits->card.steps < INCSTEPS (card.steps)) return 0;
+  card = lgl->card;
+  if (ignused && card->lit2used[lit]) return 1;
+
+  start = lglcntstk (&card->atmost2);
+  LOG (CARDLOGLEVEL + 1, "starting at-most-two clique[%d] for %d", start, lit);
+  assert (!card->lit2count[lit]);
+  hts = lglhts (lgl, -lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  INCSTEPS (card.steps);
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != TRNCS) continue;
+    other = -(blit >> RMSHFT);
+    other2 = -*p;
+    if (card->lit2count[-other] || card->lit2count[-other2]) continue;
+    if (!card->lit2count[lit]++) lglpushstk (lgl, &card->atmost2, lit);
+    if (!card->lit2count[other]++) lglpushstk (lgl, &card->atmost2, other);
+    if (!card->lit2count[other2]++) lglpushstk (lgl, &card->atmost2, other2);
+  }
+  q = card->atmost2.start + start;
+  for (p = q; p < card->atmost2.top; p++) {
+    if (card->lit2count [other =*p] > 1) *q++ = other;
+    else card->lit2count[other] = 0;
+  }
+  card->atmost2.top = q;
+  size = lglcntstk (&card->atmost2) - start;
+  if (size < 4) {
+    LOG (CARDLOGLEVEL + 1,
+      "less than 4 literals occuring 2 times in ternary clauses with %d",
+       -lit);
+FAILED:
+    while (lglcntstk (&card->atmost2) > start) {
+      int lit = lglpopstk (&card->atmost2);
+      assert (card->lit2count[lit] > 0);
+      card->lit2count[lit] = 0;
+    }
+    return res;
+  }
+  minlit = 0;
+RESTART:
+  if (!ignused) {
+    int subsumed;
+    lglpushstk (lgl, &card->atmost2, 0);
+    subsumed = lglcard2sub (lgl, card->atmost2.start + start, &minlit);
+    lglpopstk (&card->atmost2);
+    if (subsumed) goto FAILED;
+  }
+  LOG (CARDLOGLEVEL + 1, "trying to connect %d literals", size-1);
+  for (i = 0; i < size-2; i++) {
+    other = -lglpeek (&card->atmost2, start + i);
+    for (j = i+1; j < size-1; j++) {
+      other2 = -lglpeek (&card->atmost2, start + j);
+      for (k = j+1; k < size; k++) {
+       if (lgl->limits->card.steps < INCSTEPS (card.steps)) {
+         LOG (CARDLOGLEVEL + 1, "cardinality extraction step limit hit");
+         res = 0;
+         goto FAILED;
+       }
+       other3 = -lglpeek (&card->atmost2, start + k);
+       if (!lglhastrn (lgl, other, other2, other3)) {
+         LOG (CARDLOGLEVEL + 1,
+           "ternary clause %d %d %d missing", other, other2, other3);
+         assert (size >= 4);
+         if (size == 4) goto FAILED;
+         int l, tmp;
+         if (k > j + 1) l = k;
+         else {
+           int occ2 = card->lit2count[-other2];
+           int occ3 = card->lit2count[-other3];
+           if (occ2 > occ3) l = k;
+           else if (occ2 < occ3) l = j;
+           else {
+             occ2 = lglhts (lgl, other2)->count;
+             occ3 = lglhts (lgl, other3)->count;
+             if (occ2 > occ3) l = k;
+             else if (occ2 < occ3) l = j;
+             else l = (lglrand (lgl) & 1) ? j : k;
+           }
+         }
+         tmp = lglpeek (&card->atmost2, start + l);
+         assert (abs (tmp) != abs (lit));
+         assert (card->lit2count[tmp] > 0);
+         card->lit2count[tmp] = 0;
+         while (l + 1 < size) {
+           tmp = lglpeek (&card->atmost2, start + l + 1);
+           assert (abs (tmp) != abs (lit));
+           lglpoke (&card->atmost2, start + l++, tmp);
+         }
+         assert (l == size - 1);
+         card->atmost2.top--;
+         size--;
+         assert (size >= 4);
+         assert (card->atmost2.start + start + size == card->atmost2.top);
+         goto RESTART;
+       }
+      }
+    }
+  }
+#ifndef NLGLOG
+  if (lgl->opts->log.val >= CARDLOGLEVEL) {
+    lglogstart (lgl, CARDLOGLEVEL,
+      "non trivial size %d at-most-two constraint 2 >= ", size);
+    for (i = start; i < start + size; i++) {
+      if (i > start) fputs (" + ", lgl->out);
+      fprintf (lgl->out, "%d", lglpeek (&card->atmost2, i));
+    }
+    lglogend (lgl);
+  }
+#endif
+  for (i = start; i < start + size; i++) {
+    other = lglpeek (&card->atmost2, i);
+    card->lit2count[other] = 0;
+    card->lit2used[other] = 1;
+    if (!ignused) lglpushstk (lgl, &card->occs[other], start);
+  }
+  lglpushstk (lgl, &card->atmost2, 0);
+  lgl->stats->card.am2.found.sum += size;
+  lgl->stats->card.am2.found.cnt++;
+  return res;
+}
+
+static int lglcard2extract (LGL * lgl) {
+  struct { int cnt; int64_t sum; } before, after, delta;
+  const int ignused = lgl->opts->cardignused.val;
+  Card * card = lgl->card;
+
+  lglpushstk (lgl, &card->atmost2, 0);
+  NEW (card->lit2used, 2*lgl->nvars);
+  card->lit2used += lgl->nvars;
+  NEW (card->lit2count, 2*lgl->nvars);
+  card->lit2count += lgl->nvars;
+  if (!ignused) {
+    NEW (card->occs, 2*lgl->nvars);
+    card->occs += lgl->nvars;
+  }
+
+  before.cnt = lgl->stats->card.am2.found.cnt;
+  before.sum = lgl->stats->card.am2.found.sum;
+
+  lglrandlitrav (lgl, lglcard2extractlit);
+
+  after.cnt = lgl->stats->card.am2.found.cnt;
+  after.sum = lgl->stats->card.am2.found.sum;
+  assert (after.cnt >= before.cnt);
+  assert (after.sum >= before.sum);
+  delta.cnt = after.cnt - before.cnt;
+  delta.sum = after.sum - before.sum;
+
+  card->lit2used -= lgl->nvars;
+  DEL (card->lit2used, 2*lgl->nvars);
+  card->lit2count -= lgl->nvars;
+  DEL (card->lit2count, 2*lgl->nvars);
+  if (!ignused) lglcardreloccs (lgl);
+
+  if (delta.cnt)
+    lglprt (lgl, 1, 
+      "[card-%d] found %d at-most-two constraints of average size %.1f",
+      lgl->stats->card.count, delta.cnt, lglavg (delta.sum, delta.cnt));
+  else
+    lglprt (lgl, 1,
+      "[card-%d] no at-most-two constraint found",
+      lgl->stats->card.count);
+
+  return delta.cnt;
+}
+
+static int lglcarduseclswithlit (LGL * lgl, int lit) {
+  int pos = !lglmtstk (lgl->card->occs + lit);
+  int neg = !lglmtstk (lgl->card->occs - lit);
+  int level = lgl->opts->carduse.val;
+  switch (level) {
+    case 0: return 0;
+    case 1: return pos && !neg;
+    case 2: return pos;
+    default: assert (level == 3); return pos || neg;
+  }
+}
+
+static int lglcardelim (LGL * lgl, int count) {
+  int blit, tag, other, other2, bound, used;
+  int idx, sign, lit, start, len, res, glue;
+  const int * p, * w, * eow, * c, * q;
+  Card * card = lgl->card;
+  int cardmaxlen;
+  int clause[4];
+  HTS * hts;
+  Stk * s;
+
+  NEW (card->occs, 2*lgl->nvars);
+  NEW (card->eliminated, lgl->nvars);
+  NEW (card->count, lgl->nvars);
+  card->occs += lgl->nvars;
+  used = 0;
+  cardmaxlen =
+    lglfactor (lgl, lgl->stats->card.count, lgl->opts->cardmaxlen.val);
+  for (start = 1; start < lglcntstk (&card->atmost1); start++) {
+    for (len = 0; lglpeek (&card->atmost1, start + len); len++)
+      ;
+    if (len >= lgl->opts->cardminlen.val &&
+       len <= cardmaxlen &&
+        lgladdcard (lgl, card->atmost1.start + start, 1)) {
+      lgl->stats->card.am1.used.sum += len;
+      lgl->stats->card.am1.used.cnt++;
+      used++;
+    }
+    start += len;
+  }
+  for (start = 1; start < lglcntstk (&card->atmost2); start++) {
+    for (len = 0; lglpeek (&card->atmost2, start + len); len++)
+      ;
+    if (len >= lgl->opts->cardminlen.val &&
+       len <= cardmaxlen &&
+        lgladdcard (lgl, card->atmost2.start + start, 2)) {
+      lgl->stats->card.am2.used.sum += len;
+      lgl->stats->card.am2.used.cnt++;
+      used++;
+    }
+    start += len;
+  }
+  if (used) {
+    lglprt (lgl, 1,
+      "[card-%d] %d out of %d constraints (%.0f%%) meet size limits",
+      lgl->stats->card.count, used, count, lglpcnt (used, count));
+  } else {
+    lglprt (lgl, 1,
+      "[card-%d] no constraint out of %d meets size limits",
+      lgl->stats->card.count, count);
+    goto SKIP;
+  }
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglmtstk (card->occs + idx) &&
+       lglmtstk (card->occs - idx)) continue;
+    LOG (CARDLOGLEVEL, "variable %d scheduled for elimination", idx);
+    lglpushstk (lgl, &card->elim, idx);
+  }
+  if (!lgl->opts->carduse.val) goto DO_NOT_USE_CLAUSES;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglterminate (lgl) ||
+       lgl->limits->card.steps < INCSTEPS (card.steps)) goto SKIP;
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      if (!lglcarduseclswithlit (lgl, lit)) continue;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == BINCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         clause[0] = -lit, clause[1] = -other, clause[2] = 0;
+         (void) lgladdcard (lgl, clause, 1);
+       } else if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         clause[0] = -lit, clause[1] = -other,
+         clause[2] = -other2, clause[3] = 0;
+         (void) lgladdcard (lgl, clause, 2);
+       } else assert (tag == LRGCS);
+      }
+    }
+  }
+  for (glue = -1; glue <= lgl->opts->cardglue.val; glue++) {
+    s = (glue < 0) ? &lgl->irr : lgl->red + glue;
+    for (c = s->start; c < s->top; c = p + 1) {
+      if (*(p = c) >= NOTALIT) continue;
+      for (p = c; *p; p++)
+       ;
+      for (q = c; (lit = *q); q++)
+       if (lglcarduseclswithlit (lgl, lit)) break;
+      if (!lit) continue;
+      len = p - c;
+      if (len > cardmaxlen) continue;
+      assert (len >= 4);
+      bound = len - 1;
+      assert (lglmtstk (&lgl->clause));
+      for (q = c; (lit = *q); q++)
+       lglpushstk (lgl, &lgl->clause, -lit);
+      lglpushstk (lgl, &lgl->clause, 0);
+      (void) lgladdcard (lgl, lgl->clause.start, bound);
+      lglclnstk (&lgl->clause);
+      if (lglterminate (lgl) ||
+         lgl->limits->card.steps < INCSTEPS (card.steps)) goto SKIP;
+    }
+  }
+DO_NOT_USE_CLAUSES:
+  lglcardfm (lgl);
+SKIP:
+  lglcardreloccs (lgl);
+  DEL (card->count, lgl->nvars);
+  lglrelstk (lgl, &card->cards);
+  lglrelstk (lgl, &card->elim);
+  DEL (card->eliminated, lgl->nvars);
+  if (lgl->mt)
+    lglprt (lgl, 1,
+      "[card-%d] produced empty clause",
+      lgl->stats->card.count);
+  else if (!lglmtstk (&card->units)) {
+    lglprt (lgl, 1,
+       "[card-%d] found %d units",
+       lgl->stats->card.count, lglcntstk (&card->units));
+    while (!lgl->mt && !lglmtstk (&card->units)) {
+      lit = lglpopstk (&card->units);
+      if (lglval (lgl, lit) > 0) continue;
+      if (lglval (lgl, lit) < 0) {
+       lglprt (lgl, 1,
+         "[card-%d] found inconsistent unit",
+         lgl->stats->card.count);
+       lgl->mt = 1;
+      } else {
+       lglunit (lgl, lit);
+       if (!lglbcp (lgl)) {
+         lglprt (lgl, 1,
+           "[card-%d] inconsistent unit propagation",
+           lgl->stats->card.count);
+         assert (!lgl->mt);
+         lgl->mt = 1;
+       }
+      }
+    }
+  }
+  res = lglcntstk (&card->units);
+  lglrelstk (lgl, &card->units);
+  if (!lgl->mt) {
+    if (res)
+      lglprt (lgl, 1, 
+       "[card-%d] found %d units", lgl->stats->card.count, res);
+    else
+      lglprt (lgl, 1, "[card-%d] no units found", lgl->stats->card.count);
+
+    if (!lglmtstk (&card->expam1)) {
+      int generated = 0, exported = 0, genused = 0;
+      for (c = card->expam1.start; c < card->expam1.top; c = p + 1) {
+       int a, usefull = 0;
+       generated++;
+       for (p = c; (a = *p); p++) if (lglval (lgl, a)) break;
+       if (a) { while (*++p) ; continue; }
+       for (p = c; (a = -*p); p++) {
+         int b;
+         for (q = p + 1; (b = -*q); q++)
+           if (!lglhasbin (lgl, a, b)) {
+             LOG (CARDLOGLEVEL,
+               "exporting at-most-one constraint binary clause %d %d",
+               a, b);
+             assert (lglmtstk (&lgl->clause));
+             lglpushstk (lgl, &lgl->clause, a);
+             lglpushstk (lgl, &lgl->clause, b);
+             lglpushstk (lgl, &lgl->clause, 0);
+             lgladdcls (lgl, REDCS, 0, 1);
+             lglclnstk (&lgl->clause);
+             lgl->stats->card.expam1++;
+             exported++;
+             usefull = 1;
+             assert (!lgl->opts->drup.val);
+#ifndef NLGLPICOSAT
+             lglpicosatchkclsarg (lgl, a, b, 0);
+#endif
+           }
+       }
+       if (usefull) genused++;
+      }
+      lglprt (lgl, 1,
+        "[card-%d] generated %d at-most-one constraints, %d used %.0f%%",
+        lgl->stats->card.count,
+       generated, genused, lglpcnt (genused, generated));
+      lglprt (lgl, 1,
+       "[card-%d] exported %d binary clauses, %.1f per/constraint",
+        lgl->stats->card.count, exported, lglavg (exported, genused));
+    } else
+      lglprt (lgl, 1, 
+        "[card-%d] no at-most-one constraints generated",
+        lgl->stats->card.count);
+  }
+  lglrelstk (lgl, &card->expam1);
+  return res;
+}
+
+static int lglcard (LGL * lgl) {
+  int success, count;
+  int64_t limit;
+  assert (!lgl->mt);
+  lglstart (lgl, &lgl->times->card);
+  lgl->stats->card.count++;
+  if (lgl->level) lglbacktrack (lgl, 0);
+  limit = lglsetcardlim (lgl);
+  assert (!lgl->card);
+  NEW (lgl->card, 1);
+  count = lglcard1extract (lgl) + lglcard2extract (lgl);
+  if (!lglterminate (lgl) && count) {
+    lglsetcardlimagain (lgl, limit);
+    success = lglcardelim (lgl, count);
+  } else success = 0;
+  lglrelstk (lgl, &lgl->card->atmost1);
+  lglrelstk (lgl, &lgl->card->atmost2);
+  DEL (lgl->card, 1);
+  LGLUPDPEN (card, success);
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglrdpclslim (LGL * lgl) {
+  int64_t res64;
+  int res;
+  res64 = lgl->opts->rdpclslim.val + (int64_t) lgl->stats->rdp.count;
+  res = res64 > INT_MAX ? INT_MAX : res64;
+  return res;
+}
+
+static void lglrdpaddcls (LGL * lgl, const int * c) {
+  int cidx = lglcntstk (&lgl->rdp->lits), lit;
+  const int * p;
+  for (p = c; (lit = *p); p++)
+    ;
+  if (p - c > lglrdpclslim (lgl) + 1) return;
+  for (p = c; (lit = *p); p++) {
+    lgl->rdp->count[lit]++;
+    lglpushstk (lgl, &lgl->rdp->occs[lit], cidx);
+    lglpushstk (lgl, &lgl->rdp->lits, lit);
+  }
+  lglpushstk (lgl, &lgl->rdp->lits, 0);
+}
+
+static void lglrdpconbintrn (LGL *  lgl) {
+  int idx, sign, lit, blit, tag, red, other, other2, cls[4];
+  const int * p, * w, * eow;
+  HTS * hts;
+  for (sign = -1; sign <= 1; sign += 2)
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == LRGCS) continue;
+       if (tag == BINCS) {
+         if (red && lgl->opts->rdp.val < 2) continue;
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         cls[0] = lit, cls[1] = other, cls[2] = 0;
+       } else if (tag == TRNCS) {
+         if (red && lgl->opts->rdp.val < 3) continue;
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         cls[0] = lit, cls[1] = other, cls[2] = other2, cls[3] = 0;
+       }
+       lglrdpaddcls (lgl, cls);
+      }
+    }
+}
+
+static void lglrdpconlrg (LGL * lgl) {
+  const int * c, * p;
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    if (*(p = c) >= NOTALIT) continue;
+    assert (*p);
+    while (*++p)
+      ;
+    lglrdpaddcls (lgl, c);
+  }
+}
+
+static void lglrdpreport (LGL * lgl) {
+  lglgenericreport (lgl,
+    "rdp", lgl->stats->rdp.count,
+    lgl->rdp->eliminated, lgl->nvars, lgl->rdp->start);
+}
+
+static void lglrdpinit (LGL * lgl) {
+  NEW (lgl->rdp, 1);
+  lgl->rdp->start = lglgetime (lgl);
+  lglrdpreport (lgl);
+  NEW (lgl->rdp->count, 2*lgl->nvars);
+  lgl->rdp->count += lgl->nvars;
+  NEW (lgl->rdp->occs, 2*lgl->nvars);
+  lgl->rdp->occs += lgl->nvars;
+  lglrdpconbintrn (lgl);
+  lglrdpconlrg (lgl);
+  lglfitstk (lgl, &lgl->rdp->lits);
+}
+
+static void lglrdpreset (LGL * lgl) {
+  int nvars = lgl->nvars;
+  Stk * p;
+  for (p = lgl->rdp->occs - nvars; p < lgl->rdp->occs + nvars; p++)
+    lglrelstk (lgl, p);
+  lgl->rdp->occs -= nvars;
+  DEL (lgl->rdp->occs, 2*nvars);
+  lgl->rdp->count -= nvars;
+  DEL (lgl->rdp->count, 2*nvars);
+  lglrelstk (lgl, &lgl->rdp->lits);
+  DEL (lgl->rdp, 1);
+}
+
+#define RDPL 2
+
+static void lglrdpcollect (LGL * lgl, Stk * s) {
+  int * q = s->start;
+  const int * p;
+  for (p = q; p < s->top; p++) {
+    int cidx = *p;
+    const int * c = lgl->rdp->lits.start + cidx;
+    assert (c < lgl->rdp->lits.top);
+    if (*c != REMOVED) *q++ = cidx;
+  }
+  LOG (RDPL, "collected %ld references", (long)(s->top - q));
+  s->top = q;
+}
+
+static void lglrdpflush (LGL * lgl, Stk * s) {
+  const int * p, * q;
+  for (p = s->start; p < s->top; p++) {
+    int cidx = *p, * c = lgl->rdp->lits.start + cidx, lit;
+    assert (c < lgl->rdp->lits.top);
+    INCSTEPS (rdp.steps);
+    for (q = c; (lit = *q); q++) {
+      assert (lgl->rdp->count[lit] > 0);
+      lgl->rdp->count[lit]--;
+    }
+    *c = REMOVED;
+  }
+  LOG (RDPL, "flushed %d references", lglcntstk (s));
+}
+
+static int lglrdpresolve (LGL * lgl, int pivot, int cidx, int didx) {
+  int res, lit, val, csize, dsize, rsize, resolventsize, conlypos, donlypos;
+  const int * c = lgl->rdp->lits.start + cidx, * p;
+  const int * d = lgl->rdp->lits.start + didx;
+  const int64_t lim = lglrdpclslim (lgl);
+  res = resolventsize = 0;
+  assert (pivot > 0);
+  assert (c < lgl->rdp->lits.top);
+  assert (d < lgl->rdp->lits.top);
+  assert (lglmtstk (&lgl->clause));
+  INCSTEPS (rdp.steps);
+  lgl->stats->rdp.res++;
+  LOGCLS (RDPL+1, c, "RDP resolution 1st antecedent");
+  conlypos = 1;
+  for (p = c; resolventsize <= lim && (lit = *p); p++) {
+    if (lit == pivot) continue;
+    if (lit < 0) conlypos = 0;
+    assert (lit != -pivot);
+    val = lglval (lgl, lit);
+    if (val < 0) continue;
+    if (val > 0) {
+      assert (!res);
+      LOG (RDPL + 1, "1st antecedent statisfied");
+      goto DONE;
+    }
+    lglpushstk (lgl, &lgl->clause, lit);
+    lglmark (lgl, lit);
+    resolventsize++;
+  }
+  csize = p - c;
+  LOGCLS (RDPL+1, d, "RDP resolution 2nd antecedent");
+  donlypos = 1;
+  for (p = d; resolventsize <= lim && (lit = *p); p++) {
+    if (-lit == pivot) continue;
+    if (lit < 0) donlypos = 0;
+    assert (lit != -pivot);
+    val = lglval (lgl, lit);
+    if (val < 0) continue;
+    if (val > 0) {
+      assert (!res);
+      LOG (RDPL + 1, "2nd antecedent statisfied");
+      goto DONE;
+    }
+    val = lglmarked (lgl, lit);
+    if (val > 0) continue;
+    if (val < 0) {
+      assert (!res);
+      LOG (RDPL + 1, "skipping trivial RDP resolvent");
+      goto DONE;
+    } 
+    lglpushstk (lgl, &lgl->clause, lit);
+    resolventsize++;
+  }
+  if (resolventsize > lim) {
+    LOG (RDPL+1, "RDP larger than %d literals", lim);
+    lgl->stats->rdp.limhit.len++;
+    assert (!res);
+    goto DONE;
+  }
+  if (resolventsize > 1 &&
+      lgl->opts->rdpmodelm.val && !conlypos && !donlypos) {
+    LOG (RDPL+1, "RDP model elimination prohibits resolution");
+    lgl->stats->rdp.limhit.model++;
+    assert (!res);
+    goto DONE;
+  }
+  dsize = p - d;
+  rsize = lglcntstk (&lgl->clause);
+  assert (rsize == resolventsize);
+  lglpushstk (lgl, &lgl->clause, 0);
+  LOGCLS (RDPL+1, lgl->clause.start, "add non-trivial RDP resolvent");
+  lglrdpaddcls (lgl, lgl->clause.start);
+  if (!rsize) {
+    LOG (1, "RDP produced empty clause");
+    lgl->mt = 1;
+  } else if (rsize == 1) {
+    lit = lglpeek (&lgl->clause, 0);
+    val = lglval (lgl, lit);
+    if (val < 0) {
+      LOG (1, "RDP produced inconsistent unit %d", lit);
+      lgl->mt = 1;
+    } else if (!val) {
+      LOG (1, "RDP produced unit %d", lit);
+      lgl->stats->rdp.units++;
+      lglunit (lgl, lit);
+      if (!lglbcp (lgl)) {
+       LOG (1, "propagating RDP units produces empty clause");
+       lgl->mt = 1;
+      }
+    }
+  } else if (rsize == 2 && (csize > 2 || dsize > 2)) {
+    int a = lglpeek (&lgl->clause, 0);
+    int b = lglpeek (&lgl->clause, 1);
+    INCSTEPS (rdp.steps);
+    if (!lglhasbin (lgl, a, b)) {
+      LOGCLS (RDPL+1, lgl->clause.start, "exporting binary RDP resolvent");
+      lgladdcls (lgl, REDCS, 0, 1);
+      lgl->stats->rdp.bin++;
+#ifndef NLGLPICOSAT
+      lglpicosatchkcls (lgl);
+#endif
+    }
+  } else if (rsize == 3 && (csize > 3 || dsize > 3)) {
+    int a = lglpeek (&lgl->clause, 0);
+    int b = lglpeek (&lgl->clause, 1);
+    int c = lglpeek (&lgl->clause, 2);
+    INCSTEPS (rdp.steps);
+    if (!lglhastrn (lgl, a, b, c)) {
+      LOGCLS (RDPL+1, lgl->clause.start, "exporting ternary RDP resolvent");
+      lgladdcls (lgl, REDCS, 0, 1);
+      lgl->stats->rdp.trn++;
+#ifndef NLGLPICOSAT
+      lglpicosatchkcls (lgl);
+#endif
+    }
+  }
+  res = 1;
+DONE:
+  while (!lglmtstk (&lgl->clause)) {
+    lit = lglpopstk (&lgl->clause);
+    if (lit) lglunmark (lgl, lit);
+  }
+  return res;
+}
+
+static int lglrdplit (LGL * lgl, int idx) {
+  int64_t npos, nneg, k, i, j, r, p, s, l;
+  Stk * pos = &lgl->rdp->occs[idx];
+  Stk * neg = &lgl->rdp->occs[-idx];
+  lgl->stats->rdp.elim += 1;
+  LOG (RDPL,
+    "RDP pivot %d: pos %d/%d + neg %d/%d",
+    idx,
+    lgl->rdp->count[idx], lglcntstk (pos),
+    lgl->rdp->count[-idx], lglcntstk (neg));
+  lglrdpcollect (lgl, pos), lglrdpcollect (lgl, neg);
+  assert (lgl->rdp->count[idx] >= lglcntstk (pos));
+  assert (lgl->rdp->count[-idx] >= lglcntstk (neg));
+  npos = lglcntstk (pos), nneg = lglcntstk (neg);
+  if (!npos || !nneg) goto DONE;
+  l = ((npos + nneg) * lgl->opts->rdplim.val + 50)/100;
+  r = npos * nneg;
+  p = lglrand (lgl);
+  while (!p || lglgcd64 (p, r) != 1) p++;
+  p = p % r;
+  s = k = lglrand (lgl) % r;
+  LOG (RDPL,
+    "RDP traversal range %lld = %lld * %lld start %lld period %lld limit %lld",
+    (LGLL) r, (LGLL) npos, (LGLL) nneg, (LGLL) s, (LGLL) p, (LGLL) l);
+  do {
+    i = k / nneg, j = k % nneg;
+    LOG (RDPL + 1, "trying index %lld RDP pair %d %d", (LGLL) k, i, j);
+    if (lglrdpresolve (lgl, idx, lglpeek (pos, i), lglpeek (neg, j))) l--;
+    k += p; if (k >= r) k -= r;
+    assert (0 <= k && k < r);
+    if (l < 0) lgl->stats->rdp.limhit.bound++;
+  } while (!lgl->mt && l >= 0 && s != k);
+DONE:
+  lglrdpflush (lgl, pos), lglrdpflush (lgl, neg);
+  lglrelstk (lgl, pos), lglrelstk (lgl, neg);
+  lgl->rdp->eliminated++;
+  lglrdpreport (lgl);
+  return !lgl->mt && lgl->stats->rdp.steps < lgl->limits->rdp.steps;
+}
+
+static void lglsetrdplim (LGL * lgl) {
+  int64_t limit, irrlim;
+  int pen;
+  limit = (lgl->opts->rdpreleff.val*lglvisearch (lgl))/1000;
+  if (limit < lgl->opts->rdpmineff.val) limit = lgl->opts->rdpmineff.val;
+  if (lgl->opts->rdpmaxeff.val >= 0 && limit > lgl->opts->rdpmaxeff.val)
+    limit = lgl->opts->rdpmaxeff.val;
+  limit >>= (pen = lgl->limits->rdp.pen + lglszpen (lgl));
+  irrlim = 3*lgl->stats->irr.clauses.cur;
+  irrlim >>= lgl->limits->simp.pen;
+  if (lgl->opts->irrlim.val && limit < irrlim) {
+    limit = irrlim;
+    lglprt (lgl, 1,
+      "[rdp-%d] limit %lld based on %d irredundant clauses",
+      lgl->stats->rdp.count, (LGLL) limit, lgl->stats->irr.clauses.cur);
+  } else
+    lglprt (lgl, 1, "[rdp-%d] limit %lld with penalty %d = %d + %d",
+      lgl->stats->rdp.count, (LGLL) limit,
+      pen, lgl->limits->rdp.pen, lglszpen (lgl));
+  lgl->limits->rdp.steps = lgl->stats->rdp.steps + limit;
+}
+
+static int lglrdp (LGL * lgl) {
+  int oldunits, newunits, deltaunits, success;
+  int oldtrn, newtrn, deltatrn;
+  int oldbin, newbin, deltabin;
+  if (lgl->nvars <= 2) return 1;
+  if (lgl->mt) return 0;
+  lglstart (lgl, &lgl->times->rdp);
+  lgl->stats->rdp.count++;
+  if (lgl->level) lglbacktrack (lgl, 0);
+  assert (!lgl->simp);
+  lgl->simp = 1;
+  lglsetrdplim (lgl);
+  oldunits = lgl->stats->rdp.units;
+  oldbin = lgl->stats->rdp.bin;
+  oldtrn = lgl->stats->rdp.trn;
+  lglrdpinit (lgl);
+  lglrandidxtrav (lgl, lglrdplit);
+  lglrdpreport (lgl);
+  lglrdpreset (lgl);
+  newunits = lgl->stats->rdp.units; deltaunits = (newunits - oldunits);
+  newbin = lgl->stats->rdp.bin; deltabin = (newbin - oldbin);
+  newtrn = lgl->stats->rdp.trn; deltatrn = (newtrn - oldtrn);
+  lglprt (lgl, 1,
+    "[rdp-%d] found %d units, %d binary and %d ternary clauses",
+    lgl->stats->rdp.count, deltaunits, deltabin, deltatrn);
+  success = deltaunits + deltabin + deltatrn;
+  LGLUPDPEN (rdp, success);
+  assert (lgl->simp);
+  lgl->simp = 0;
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglbcaoccmin (LGL * lgl, int lit) {
+  int * p, * w, * eow;
+  int res, blit, red, tag;
+  HTS * hts;
+  hts = lglhts (lgl, lit);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  res = 0;
+  for (p = w; res <= 3 && p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    red = blit & REDCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag == LRGCS) continue;
+    if (!red) res++;
+  }
+  return res;
+}
+
+static int lglbcaskiplit (LGL * lgl, int lit) {
+  int pocc, nocc;
+  if (lgl->opts->bca.val >= 2) return 0;
+  pocc = lglbcaoccmin (lgl, lit);
+  if (pocc <= 1) return 1;
+  nocc = lglbcaoccmin (lgl, -lit);
+  if (nocc <= 1) return 1;
+  return pocc == 2 && nocc == 2;
+}
+
+static void lglbcalitaux (LGL * lgl, int lit) {
+  int first, blit, tag, red, lidx, other, tmp, found, other2, found2, * r;
+  const int * w, * p, * eow, * c, * q;
+  Stk * covered = &lgl->bca->covered;
+  int round;
+  HTS * hts;
+  assert (lglisfree (lgl, lit));
+  assert (lgl->opts->bca.val);
+  assert (!(lglavar (lgl, lit)->inred & (1 << (lit < 0))));
+  hts = lglhts (lgl, lit);
+  if (!hts->count) return;
+  if (lglbcaskiplit (lgl, lit)) { lgl->stats->bca.skipped++; return; }
+  assert (lglmtstk (covered));
+  first = 1;
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (round = 0; round < 2; round++) {
+    for (p = w; (first || !lglmtstk (covered)) && p < eow; p++) {
+      blit = *p;
+      tag = blit & MASKCS;
+      red = blit & REDCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      assert (!red || tag != LRGCS);
+      if (tag == LRGCS) continue;
+      if (round != (tag == OCCS)) continue;
+      INCSTEPS (bca.steps);
+      if (tag == BINCS) {
+       assert (!round);
+       other = blit >> RMSHFT;
+       if (lglval (lgl, other) > 0) continue;
+       assert (!lglval (lgl, other));
+       found = first;
+       while (!lglmtstk (covered))
+         if (other == lglpopstk (covered)) found = 1;
+       if (found) lglpushstk (lgl, covered, other);
+      } else if (tag == TRNCS) {
+       assert (!round);
+       other = blit >> RMSHFT;
+       if (lglval (lgl, other) > 0) continue;
+       other2 = *p;
+       if (lglval (lgl, other2) > 0) continue;
+       found = found2 = first;
+       while (!lglmtstk (covered))
+         if (other == (tmp = lglpopstk (covered))) found = 1;
+         else if (tmp == other2) found2 = 1;
+       if (found && !lglval (lgl, other)) lglpushstk (lgl, covered, other);
+       if (found2 && !lglval (lgl, other2)) lglpushstk (lgl, covered, other2);
+      } else {
+       assert (!red);
+       assert (round);
+       assert (tag == OCCS);
+       lidx = blit >> RMSHFT;
+       c = lglidx2lits (lgl, red, lidx);
+       INCSTEPS (bca.steps);
+       for (q = c; (other = *q); q++)
+         if (other != lit && lglval (lgl, other) > 0) break;
+       if (other) continue;
+       if (first) {
+         for (q = c; (other = *q); q++)
+           if (other != lit && !lglval (lgl, other))
+             lglpushstk (lgl, covered, other);
+       } else {
+         for (q = covered->start; q < covered->top; q++)
+           assert (!lglsignedmarked (lgl, *q)), lglsignedmark (lgl, *q);
+         for (q = c; (other = *q); q++)
+           if (other != lit && lglsignedmarked (lgl, other))
+             assert (!lglval (lgl, other)), lglsignedunmark (lgl, other);
+         r = covered->start;
+         for (q = r; q < covered->top; q++)
+           if (lglsignedmarked (lgl, (other = *q)))
+             lglsignedunmark (lgl, other);
+           else *r++ = other;
+         covered->top = r;
+       }
+      }
+      first = 0;
+    }
+  }
+}
+
+static int lglbcalit (LGL * lgl, int lit) {
+  unsigned bit;
+  AVar * av;
+  int other;
+  if (lgl->limits->bca.steps < lgl->stats->bca.steps) return 0;
+  if (lglterminate (lgl)) return 0;
+  if (lglifrozen (lgl, lit)) return 1;
+  if (!lglisfree (lgl, lit)) return 1;
+  av = lglavar (lgl, lit);
+  bit = (1 << (lit < 0));
+  if (av->inred & bit) return 1;
+  lglbcalitaux (lgl, lit);
+  while (!lglmtstk (&lgl->bca->covered)) {
+    INCSTEPS (bca.steps);
+    other = lglpopstk (&lgl->bca->covered);
+    if (lglhasbin (lgl, -lit, -other)) continue;
+    LOG (2, "adding binary blocked clause %d %d", -lit, -other);
+    assert (lglmtstk (&lgl->clause));
+    lglpushstk (lgl, &lgl->clause, -lit);
+    lglpushstk (lgl, &lgl->clause, -other);
+    lglpushstk (lgl, &lgl->clause, 0);
+    lgladdcls (lgl, REDCS, 0, 1);
+    lglclnstk (&lgl->clause);
+    lgl->stats->bca.added++;
+  }
+  return 1;
+}
+
+static void lglupdbcadel (LGL * lgl, int success) {
+  if (success && lgl->limits->bca.del.cur)
+    lgl->limits->bca.del.cur /= 2;
+  if (!success && lgl->limits->bca.del.cur < lgl->opts->delmax.val)
+    lgl->limits->bca.del.cur++;
+  lgl->limits->bca.del.rem = lgl->limits->bca.del.cur;
+}
+
+static void lglbca (LGL * lgl) {
+  int oldadded = lgl->stats->bca.added, added;
+  int idx, glue, other, inred, usable;
+  const int * c, * p;
+  int64_t oldsteps;
+  unsigned bit;
+  AVar * av;
+
+  lglstart (lgl, &lgl->times->bca);
+
+  NEW (lgl->bca, 1);
+
+  lgl->stats->bca.count++;
+  oldsteps = lgl->stats->bca.steps;
+  lgl->limits->bca.steps = oldsteps + lgl->opts->bcamaxeff.val;
+  lglprt (lgl, 1, "[bca-%d] limit of %d steps", 
+          lgl->stats->bca.count, lgl->opts->bcamaxeff.val);
+
+  assert (!lgl->bcaing);
+  lgl->bcaing = 1;
+
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lglgc (lgl);
+  assert (lgl->frozen);
+
+  for (idx = 2; idx < lgl->nvars; idx++) lglavar (lgl, idx)->inred = 0;
+  inred = 0;
+  for (glue = 0; glue <= MAXGLUE; glue++) {
+    Stk * s = lgl->red + glue;
+    for (c = s->start; c < s->top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      INCSTEPS (bca.steps);
+      while ((other = *p)) {
+       p++;
+       bit = (1 << (other < 0));
+       av = lglavar (lgl, other);
+       if (av->inred & bit) continue;
+       av->inred |= bit;
+       inred++;
+      }
+    }
+  }
+  lglprt (lgl, 2, 
+    "[bca-%d] %d out of %d literals in large redundant clauses %.0f%%",
+    lgl->stats->bca.count,
+    inred, 2*(lgl->nvars-1), lglpcnt (inred, 2*(lgl->nvars-1)));
+
+  usable = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglifrozen (lgl, idx)) continue;
+    if (!lglisfree (lgl, idx)) continue;
+    av = lglavar (lgl, idx);
+    for (bit = 1; bit <= 2; bit++) if (!(av->inred & bit)) usable++;
+  }
+  lglprt (lgl, 1, 
+    "[bca-%d] %d out of %d literals actually usable %.0f%%",
+    lgl->stats->bca.count,
+    usable, 2*(lgl->nvars-1), lglpcnt (usable, 2*(lgl->nvars-1)));
+
+  if (usable < lgl->opts->bcaminuse.val) {
+    lglprt (lgl, 1, "[bca-%d] not enough literals usable",
+            lgl->stats->bca.count);
+    goto DONE;
+  }
+
+  lgldense (lgl, 1);
+  lglrandlitrav (lgl, lglbcalit);
+  lglsparse (lgl);
+  lglgc (lgl);
+
+DONE:
+  added = lgl->stats->bca.added - oldadded;
+  lglprt (lgl, 1, "[bca-%d] added %d blocked clauses in %lld steps",
+          lgl->stats->bca.count, added, 
+         (LGLL) lgl->stats->bca.steps - oldsteps);
+  assert (lgl->bcaing);
+  lgl->bcaing = 0;
+  lglupdbcadel (lgl, added);
+  lglrelstk (lgl, &lgl->bca->covered);
+  DEL (lgl->bca, 1);
+  lglstop (lgl);
+}
+
+/*------------------------------------------------------------------------*/
+
+#define BVAL 0
+
+static int lglbvamult (LGL * lgl, int mult) {
+  int other, blit, tag, red, res = 0;
+  const int * p, * w, * eow;
+  HTS * hts;
+  hts = lglhts (lgl, mult);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    other = blit >> RMSHFT;
+    if (lglsignedmarked (lgl, other)) res++;
+  }
+  return res;
+}
+
+static void lglbvadef (LGL * lgl, int lit, int mult, Stk * factors) {
+  // TODO what here?
+}
+
+static void lglbvalit (LGL * lgl, int lit, Stk * factors) {
+  int other, blit, tag, red, count, mult, factor;
+  const int * p, * w, * eow;
+  HTS * hts;
+  if (!lglisfree (lgl, lit)) return;
+  hts = lglhts (lgl, lit);
+  if (hts->count < 3) return;
+  LOG (BVAL, "trying to do BVA for literal %d", lit);
+  lglclnstk (factors);
+  w = lglhts2wchs (lgl, hts);
+  eow = w + hts->count;
+  for (p = w; p < eow; p++) {
+    blit = *p;
+    tag = blit & MASKCS;
+    if (tag == TRNCS || tag == LRGCS) p++;
+    if (tag != BINCS) continue;
+    red = blit & REDCS;
+    if (red) continue;
+    other = blit >> RMSHFT;
+    if (!lglisfree (lgl, other)) continue;
+    if (lglsignedmarked (lgl, other)) continue;
+    lglsignedmark (lgl, other);
+    lglpushstk (lgl, factors, other);
+  }
+  count = lglcntstk (factors);
+  LOG (BVAL, "found %d candidates to do BVA for literal %d", count, lit);
+  while (lglcntstk (factors) >= 3) {
+    factor = lgltopstk (factors);
+    LOG (BVAL, "trying factor %d for candidate BVA literal %d", factor, lit);
+    hts = lglhts (lgl, factor);
+    w = lglhts2wchs (lgl, hts);
+    eow = w + hts->count;
+    for (p = w; p < eow; p++) {
+      blit = *p;
+      tag = blit & MASKCS;
+      if (tag == TRNCS || tag == LRGCS) p++;
+      if (tag != BINCS) continue;
+      red = blit & REDCS;
+      if (red) continue;
+      mult = blit >> RMSHFT;
+      if (mult == lit) continue;
+      if (!lglisfree (lgl, mult)) continue;
+      if ((count = lglbvamult (lgl, mult)) < 3) continue;
+      count = lglbvamult (lgl, mult);
+      LOG (BVAL,
+        "multiplier %d with %d common factors for BVA literal %d",
+       mult, count, lit);
+      if (count < 3) continue;
+      lglbvadef (lgl, lit, mult, factors);
+      goto DONE;
+    }
+    (void) lglpopstk (factors);
+    lglsignedunmark (lgl, factor);
+  }
+DONE:
+  while (!lglmtstk (factors)) {
+    other = lglpopstk (factors); 
+    assert (lglsignedmarked (lgl, other));
+    lglsignedunmark (lgl, other);
+  }
+}
+
+static int lglcmpbvacands (int * binoccs, int a, int b) {
+  return binoccs[a] - binoccs[b];
+}
+
+#define LGLCMPBVACANDS(A,B) lglcmpbvacands (binoccs, *(A), *(B))
+
+static void lglbva (LGL * lgl) {
+  int * binoccs, nvars, idx, sgn, lit, blit, red, tag, other, count;
+  int oldirr, removed, added;
+  const int * p, * w, * eow;
+  Stk cands, factors;
+  HTS * hts;
+  nvars = lgl->nvars;
+  if (nvars <= 2) return;
+  lglstart (lgl, &lgl->times->bva);
+  lgl->stats->bva.count++;
+  oldirr = lgl->stats->irr.clauses.cur;
+  lglprt (lgl, 1,
+    "[bva-%d] starting with %d variables and %d clauses",
+    lgl->stats->bva.count, nvars - 2, oldirr);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  NEW (binoccs, 2*nvars);
+  binoccs += nvars;
+  CLR (cands);
+  for (idx = 2; idx < nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    for (sgn = -1; sgn <= 1; sgn += 2) {
+      lit = sgn * idx;
+      hts = lglhts (lgl, lit);
+      if (hts->count < 3) continue;
+      count = 0;
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag != BINCS) continue;
+       red = blit & REDCS;
+       if (red) continue;
+       other = blit >> RMSHFT;
+       if (!lglisfree (lgl, other)) continue;
+       count++;
+      }
+      if (count < 3) continue;
+      binoccs[lit] = count;
+      lglpushstk (lgl, &cands, lit);
+    }
+  }
+  if (lglmtstk (&cands)) {
+    lglprt (lgl, 1,
+      "[bva-%d] no candidates with at least three binary occurrences",
+      lgl->stats->bva.count);
+    goto DONE;
+  }
+  lglprt (lgl, 1,
+    "[bva-%d] %d candidates with at least three binary occurrences",
+    lgl->stats->bva.count, lglcntstk (&cands));
+  SORT (int, cands.start, lglcntstk (&cands), LGLCMPBVACANDS);
+  CLR (factors);
+  while (!lglmtstk (&cands)) {
+    lit = lglpopstk (&cands);
+    lglbvalit (lgl, lit, &factors);
+  }
+  lglrelstk (lgl, &factors);
+DONE:
+  binoccs -= nvars;
+  DEL (binoccs, 2*nvars);
+  lglrelstk (lgl, &cands);
+  added = lgl->nvars - nvars;
+  assert (added >= 0);
+  removed = oldirr - lgl->stats->irr.clauses.cur;
+  assert (removed >= 0);
+  lgl->stats->bva.added += added;
+  lgl->stats->bva.removed += removed;
+  lglprt (lgl, 1,
+    "[bva-%d] removed %d clauses and added %d variables",
+    lgl->stats->bva.count, removed, added);
+  lglstop (lgl);
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lgltreducing (LGL * lgl) {
+  if (lgldelaying (lgl, "transred", &lgl->limits->trd.del.rem)) return 0;
+  if (lglwaiting (lgl, "transred", lgl->opts->transredwait.val)) return 0;
+  return lgl->opts->transred.val;
+}
+
+static int lglunhiding (LGL * lgl) { 
+  if (lgldelaying (lgl, "unhide", &lgl->limits->unhd.del.rem)) return 0;
+  if (lglwaiting (lgl, "unhide", lgl->opts->unhidewait.val)) return 0;
+  return lgl->opts->unhide.val;
+}
+
+static int lgldecomposing (LGL * lgl) { return lgl->opts->decompose.val; }
+
+static int lglcgrclosing (LGL * lgl) {
+  if (lgldelaying (lgl, "cgrclsr", &lgl->limits->cgr.del.rem)) return 0;
+  if (lglwaiting (lgl, "cgrclsr", lgl->opts->cgrclsrwait.val)) return 0;
+  return lgl->opts->cgrclsr.val && lglsmallirr (lgl);
+}
+
+static int lglifting (LGL * lgl) {
+  if (lgldelaying (lgl, "lift", &lgl->limits->lft.del.rem)) return 0;
+  if (lglwaiting (lgl, "lift", lgl->opts->liftwait.val)) return 0;
+  return lgl->opts->lift.val;
+}
+
+static int lglblocking (LGL * lgl) {
+  if (!lgl->opts->block.val) return 0;
+  if (lgl->allfrozen) return 0;
+  if (lgldelaying (lgl, "block", &lgl->limits->blk.del.rem)) return 0;
+  if (lgl->opts->blockwait.val && lgl->wait &&
+      (!lgl->opts->elim.val || !lgl->elmrtc)) {
+    lglprt (lgl, 2, 
+      "[block-waiting] for bounded variable elimination to be completed");
+    return 0;
+  }
+  if (!lglsmallirr (lgl)) return 0;
+  if (lgl->nvars <= 2) return 0;
+  if (lgl->mt) return 0;
+  if (lgl->blkrem) return 1;
+  return lgl->stats->irrprgss > lgl->limits->blk.irrprgss;
+}
+
+static int lgleliminating (LGL * lgl) {
+  if (!lgl->opts->elim.val) return 0;
+  if (lgl->allfrozen) return 0;
+  if (lgldelaying (lgl, "elim", &lgl->limits->elm.del.rem)) return 0;
+  if (!lglsmallirr (lgl)) return 0;
+  if (lgl->nvars <= 2) return 0;
+  if (lgl->mt) return 0;
+  if (lgl->elmrem) return 1;
+  return lgl->stats->irrprgss > lgl->limits->elm.irrprgss;
+}
+
+static int lglrdping (LGL * lgl) {
+  if (lgldelaying (lgl, "rdp", &lgl->limits->rdp.del.rem)) return 0;
+  if (lglwaiting (lgl, "rdp", lgl->opts->rdpwait.val)) return 0;
+  return lgl->opts->rdp.val;
+}
+
+static int lglbcaing (LGL * lgl) {
+  if (!lgl->opts->bca.val) return 0;
+  if (lgl->allfrozen) return 0;
+  if (lgldelaying (lgl, "bca", &lgl->limits->bca.del.rem)) return 0;
+  if (lglwaiting (lgl, "bca", lgl->opts->bcawait.val)) return 0;
+  if (!lglsmallirr (lgl)) return 0;
+  return 1;
+}
+
+static int lglbvaing (LGL * lgl) {
+  if (!lgl->opts->bva.val) return 0;
+  return 1;
+}
+
+static int lglreducing (LGL * lgl) {
+  int reducable;
+  if (!lgl->opts->reduce.val) return 0;
+  reducable = lgl->stats->red.lrg;
+  assert (reducable >= lgl->lrgluereasons);
+  reducable -= lgl->lrgluereasons;
+  assert (reducable >= lgl->stats->lir[0].clauses);
+  reducable -= lgl->stats->lir[0].clauses;
+  return reducable >= lgl->limits->reduce.inner;
+}
+
+static int lgldefragmenting (LGL * lgl) {
+  int relfree;
+  if (lgl->stats->pshwchs < lgl->limits->dfg) return 0;
+  if (!lgl->nvars) return 0;
+  relfree = (100 * lgl->wchs->free + 99) / lgl->nvars;
+  return relfree >= lgl->opts->defragfree.val;
+}
+
+static int lglrestarting (LGL * lgl) {
+  int assumptions;
+  if (!lgl->opts->restart.val) return 0;
+  if (!lgl->level) return 0;
+  if ((assumptions = lglcntstk (&lgl->assume))) {
+    if (lgl->assumed < assumptions) return 0;
+    assert (lgl->alevel <= lgl->level);
+    if (lgl->alevel == lgl->level) return 0;
+  }
+  return lgl->stats->confs >= lgl->limits->restart.confs;
+}
+
+static int lglternresolving (LGL * lgl) { 
+  if (lgldelaying (lgl, "ternres", &lgl->limits->trnr.del.rem)) return 0;
+  if (lglwaiting (lgl, "ternres", lgl->opts->ternreswait.val)) return 0;
+  return lgl->opts->ternres.val;
+}
+
+static int lglgaussing (LGL * lgl) { 
+  if (lgldelaying (lgl, "gauss", &lgl->limits->gauss.del.rem)) return 0;
+  if (lglwaiting (lgl, "gauss", lgl->opts->gausswait.val)) return 0;
+  if (!lglsmallirr (lgl)) return 0;
+  return lgl->opts->gauss.val;
+}
+
+static int lglcliffing (LGL * lgl) {
+  if (lgldelaying (lgl, "cliff", &lgl->limits->cliff.del.rem)) return 0;
+  if (lglwaiting (lgl, "cliff", lgl->opts->cliffwait.val)) return 0;
+  return lgl->opts->cliff.val;
+}
+
+static int lglprobing (LGL * lgl) {
+  if (!lgl->opts->probe.val) return 0;
+  if (lgl->opts->prbasic.val) return 1;
+  if (!lglsmallirr (lgl)) return 0;
+  if (lgl->opts->prbsimple.val) return 1;
+  if (lgl->opts->treelook.val) return 1;
+  return 0;
+}
+
+static int lglcarding (LGL * lgl) {
+  if (!lgl->opts->card.val) return 0;
+  if (lgldelaying (lgl, "card", &lgl->limits->card.del.rem)) return 0;
+  if (lglwaiting (lgl, "card", lgl->opts->cardwait.val)) return 0;
+  return 1;
+}
+
+static int lglcceing (LGL * lgl) {
+  if (!lgl->opts->cce.val) return 0;
+  if (lgl->allfrozen) return 0;
+  if (lgldelaying (lgl, "cce", &lgl->limits->cce.del.rem)) return 0;
+  if (lglwaiting (lgl, "cce", lgl->opts->ccewait.val)) return 0;
+  if (!lglsmallirr (lgl)) return 0;
+  if (lgl->opts->cceonlyifstuck.val &&
+      ((lgl->opts->elim.val && !lgl->elmstuck) || 
+        (lgl->opts->block.val && !lgl->blkstuck))) {
+    lglprt (lgl, 2,
+      "[cce-%d] skipping since elmstuck=%d blkstuck=%d",
+      lgl->stats->cce.count, lgl->elmstuck, lgl->blkstuck);
+    return 0;
+  }
+  return 1;
+}
+
+/*------------------------------------------------------------------------*/
+
+static void lglupdlocslim (LGL * lgl, int updconflimtoo) {
+  int rem = lglrem (lgl), varslimit, vardelta;
+  vardelta = (rem * lgl->opts->locsvared.val + 999)/1000;
+  if (vardelta > rem) vardelta = rem;
+  varslimit = rem - vardelta;
+  lgl->limits->locs.vars = varslimit;
+  lglprt (lgl, 1 + !lgl->opts->locs.val,
+    "[locs-lim] next local search variable limit %d = %d - %d",
+    varslimit, rem, vardelta);
+  if (!updconflimtoo) return;
+  lgl->limits->locs.inc += lgl->opts->locscint.val;
+  assert (lgl->limits->locs.confs <= LLMAX - lgl->limits->locs.inc);
+  lgl->limits->locs.confs = lgl->stats->confs + lgl->limits->locs.inc;
+  lglprt (lgl, 1 + !lgl->opts->locs.val,
+    "[locs-lim] next local search conflict limit increased by %d to %lld",
+    lgl->limits->locs.inc, lgl->limits->locs.confs);
+}
+
+static int lglocsing (LGL * lgl) {
+#ifndef NLGLYALSAT
+  int rem;
+  if (!lgl->opts->locs.val) return 0;
+  if (lgl->limits->locs.confs > lgl->stats->confs) return 0;
+  if (lgl->stats->irr.clauses.cur > lgl->opts->locsclim.val) {
+    lglprt (lgl, 2, "[locs] skipped due to too many clauses");
+    return 0;
+  }
+  rem = lglrem (lgl);
+  if (rem < lgl->limits->locs.vars) {
+    lglprt (lgl, 2,
+      "[locs-limit] local search skipped (remaining %d < limit %d)",
+      rem, lgl->limits->locs.vars);
+    lglupdlocslim (lgl, 1);
+    return 0;
+  }
+  if (lglwaiting (lgl, "locs", lgl->opts->locswait.val)) return 0;
+  if (lgl->opts->locs.val < 0) return 1;
+  return (lgl->stats->locs.count < lgl->opts->locs.val);
+#else
+  (void) lgl;
+  return 0;
+#endif
+}
+
+#ifndef NLGLYALSAT
+
+static void lglocscopy (LGL * lgl, Yals * yals) {
+  int idx, sign, lit, blit, tag, red, other, other2;
+  int count, redcount, units, tmp;
+  const int * p, * w, * eow, * c;
+  HTS * hts;
+  Stk * s;
+  assert (!lgl->level);
+  if (!lgl->mt && !lglbcp (lgl)) lgl->mt = 1;
+  if (!lgl->mt) lglgc (lgl);
+  if (lgl->mt) return;
+  count = redcount = units = 0;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      assert (!lglval (lgl, lit));
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (red && tag == BINCS && lgl->opts->locsred.val < 2) continue;
+       if (red && tag == TRNCS && lgl->opts->locsred.val < 3) continue;
+       if (tag != BINCS && tag != TRNCS) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < idx) continue;
+       assert (!lglval (lgl, other));
+       if (tag == TRNCS) {
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         assert (!lglval (lgl, other2));
+       } else other2 = 0;
+       yals_add (yals, lit);
+       yals_add (yals, other);
+       if (other2) yals_add (yals, other2);
+       yals_add (yals, 0);
+       if (red) redcount++;
+       count++;
+      }
+    }
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    tmp = lglifixed (lgl, idx);
+    if (!tmp) continue;
+    lit = (tmp < 0) ? -idx : idx;
+    yals_add (yals, lit);
+    yals_add (yals, 0);
+    units++;
+  }
+  for (red = -1; red < MAXGLUE; red++) {
+    s = red < 0 ? &lgl->irr : lgl->red + red;
+    if (red >= 0 && lgl->opts->locsred.val < 4) break;
+    for (c = s->start; c < s->top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      while ((other = *p)) {
+       assert (!lglval (lgl, other));
+       yals_add (yals, other);
+       p++;
+      }
+      yals_add (yals, 0);
+      if (red >= 0) redcount++;
+      count++;
+    }
+  }
+
+  lglprt (lgl, 1,
+    "[locs-%d] copied %d irredundant clauses",
+    lgl->stats->locs.count, count - redcount);
+  if (redcount)
+    lglprt (lgl, 1,
+      "[locs-%d] copied %d redundant clauses",
+      lgl->stats->locs.count, redcount);
+  if (units)
+    lglprt (lgl, 1,
+      "[locs-%d] copied %d units",
+      lgl->stats->locs.count, units);
+
+  for (count = 0; count < lglcntstk (&lgl->assume); count++) {
+    lit = lglpeek (&lgl->assume, count);
+    if (abs (lit) <= 0) continue;
+    yals_add (yals, lit);
+    yals_add (yals, 0);
+  }
+  if (count)
+    lglprt (lgl, 1,
+      "[locs-%d] copied %d assumptions as %d unit clauses",
+      lgl->stats->locs.count, count, count);
+  else
+    lglprt (lgl, 2,
+      "[locs-%d] no assumptions copied",
+      lgl->stats->locs.count);
+}
+
+static int64_t lglsetlocslim (LGL * lgl) {
+  int pen, boost;
+  int64_t limit;
+  if (lgl->opts->locsrtc.val) {
+    limit = LLMAX;
+    lglprt (lgl, 1,
+      "[locs-%d] no limit (run to completion)",
+      lgl->stats->locs.count);
+  } else {
+    limit = (lgl->opts->locsreleff.val*lglvisearch (lgl))/100;
+    if (limit < lgl->opts->locsmineff.val) 
+      limit = lgl->opts->locsmineff.val;
+    if (lgl->opts->locsmaxeff.val >= 0 &&
+        limit > lgl->opts->locsmaxeff.val)
+      limit = lgl->opts->locsmaxeff.val;
+    if (lgl->stats->locs.count <= 1 &&
+        lgl->opts->boost.val &&
+        lgl->opts->locsboost.val > 1) {
+      boost = lgl->opts->locsboost.val;
+      lglprt (lgl, 1,
+       "[locs-%d] intially boosting limit by factor of %d",
+       lgl->stats->locs.count, boost);
+    } else boost = 1;
+    limit *= boost;
+    pen = lglitszpen (lgl);
+    limit >>= pen;
+    lglprt (lgl, 1,
+      "[locs-%d] limit %lld literal penalty %d",
+      lgl->stats->locs.count, (LGLL) limit, pen);
+  }
+  return limit;
+}
+
+#endif
+
+static int lglocsaux (LGL * lgl, int hitlim) {
+  int lkhd = 0;
+#ifndef NLGLYALSAT
+  int res, min, pos, neg, idx, lit, old_val, len;
+  const int set = lgl->opts->locset.val;
+  int save = lgl->opts->locsexport.val;
+  unsigned long long seed;
+  char * prefix;
+  int64_t limit;
+  AVar * av;
+  Val val;
+  Yals * yals;
+  lglstart (lgl, &lgl->times->locs);
+  if (lgl->level) lglbacktrack (lgl, 0);
+  if (!lgl->stats->locs.count++) {
+    const char * yals_version ();
+    lglprt (lgl, 1,
+      "[locs-%d] %s",
+      lgl->stats->locs.count, yals_version ());
+  }
+  yals = yals_new_with_mem_mgr ( lgl,
+          (YalsMalloc) lglnew, (YalsRealloc) lglrsz, (YalsFree) lgldel);
+  yals_setout (yals, lgl->out);
+  len = strlen (lgl->prefix) + 80;
+  NEW (prefix, len);
+  if (lgl->tid >= 0)
+    sprintf (prefix, "%s%d [locs-%d] ",
+      lgl->prefix, lgl->tid, lgl->stats->locs.count);
+  else
+    sprintf (prefix, "%s[locs-%d] ", lgl->prefix, lgl->stats->locs.count);
+  yals_setprefix (yals, prefix);
+  DEL (prefix, len);
+  old_val = yals_getopt (yals, "verbose");
+  if (old_val < lgl->opts->verbose.val)
+    yals_setopt (yals, "verbose", lgl->opts->verbose.val);
+  seed = lglrand (lgl);
+  if (lgl->tid >= 0) seed *= lgl->tid + 1;
+  seed += 1237 * (unsigned) lgl->stats->locs.count;
+  yals_srand (yals, seed);
+  if (hitlim > 0) yals_setopt (yals, "hitlim", hitlim);
+  lglocscopy (lgl, yals);
+  if (lgl->mt) { res = 20; goto DONE; }
+  limit = lglsetlocslim (lgl);
+  pos = neg = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    av = lglavar (lgl, idx);
+         if (set == 2 && av->phase > 0) lit = idx;
+    else if (set == 2 && av->phase < 0) lit = -idx;
+    else if (set == 1 && av->locsval > 0) lit = idx;
+    else if (set == 1 && av->locsval < 0) lit = -idx;
+    else continue;
+    assert (lit);
+    if (lit < 0) neg++; else pos++;
+    yals_setphase (yals, lit);
+  }
+  lglprt (lgl, 1,
+    "[locs-%d] importing %d positive %.0f%% and %d negative %.0f%% phases",
+    lgl->stats->locs.count,
+    pos, lglpcnt (pos, pos + neg),
+    neg, lglpcnt (neg, pos + neg));
+  if (limit < LLMAX/1000) limit *= 1000; else limit = LLMAX;
+  yals_setmemslimit (yals, limit);
+  if (lgl->cbs && lgl->cbs->term.fun)
+    yals_seterm (yals, lgl->cbs->term.fun, lgl->cbs->term.state);
+  if (lgl->cbs && lgl->cbs->getime)
+    yals_setime (yals, lgl->cbs->getime);
+  if (lgl->cbs && lgl->cbs->msglock.lock)
+    yals_setmsglock (yals,
+      lgl->cbs->msglock.lock,
+      lgl->cbs->msglock.unlock,
+      lgl->cbs->msglock.state);
+  res = yals_sat (yals);
+  min = yals_minimum (yals);
+  lglprt (lgl, 1,
+    "[locs-%d] local search returns %d with minimum %d",
+    lgl->stats->locs.count, res, min);
+  if (min < lgl->stats->locs.min) lgl->stats->locs.min = min;
+  lgl->stats->locs.flips += yals_flips (yals);
+  lgl->stats->locs.mems += yals_mems (yals);
+  if (res == 10) save = 1;
+  pos = neg = 0;
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    val = yals_deref (yals, idx);
+    assert (abs (val) == 1);
+    av = lglavar (lgl, idx);
+    if (val < 0) neg++, av->locsval = -1;
+    else if (val > 0) pos++, av->locsval = 1;
+    if (save) av->phase = val;
+  }
+  lglprt (lgl, 1,
+    "[locs-%d] %s %d positive %.0f%% and %d negative %.0f%% phases",
+    lgl->stats->locs.count,
+    save ? "exported" : "found",
+    pos, lglpcnt (pos, pos + neg),
+    neg, lglpcnt (neg, pos + neg));
+  if (lgl->opts->locsdec.val == 1) {
+    lkhd = yals_lkhd (yals);
+    if (abs (lkhd) == 1) lkhd = 0;
+    if (lkhd && lglisfree (lgl, lkhd)) {
+      lglprt (lgl, 1,
+       "[locs-%d] using local search look ahead %d",
+       lgl->stats->locs.count, lkhd);
+      lglbumplit (lgl, lkhd);
+    }
+  } else if (lgl->opts->locsdec.val == 2) {
+    const int * p = yals_minlits (yals);
+    int count = 0;
+    while ((lit = *p++))
+      if (abs (lit) > 1 && lglisfree (lgl, lit))
+       lglbumplit (lgl, lit), count++;
+    lglprt (lgl, 1,
+      "[locs-%d] bumped all %d variables in unsatisfied clauses",
+      lgl->stats->locs.count, count);
+  }
+DONE:
+  if (lgl->opts->verbose.val >= 1) yals_stats (yals);
+  yals_del (yals);
+  lglstop (lgl);
+#endif
+  return lkhd;
+}
+
+static void lglocs (LGL * lgl) {
+  (void) lglocsaux (lgl, 0);
+  lglupdlocslim (lgl, 1);
+}
+
+static int lglocslook (LGL * lgl) {
+  int res = lglocsaux (lgl, 100000), elit;
+  Ext * ext;
+  if (res) {
+    elit = lglexport (lgl, res);
+    ext = lglelit2ext (lgl, elit);
+    if (!ext->eliminated && !ext->blocking) {
+      lglprt (lgl, 1, "[locslook] best local search look-ahead %d", res);
+      if (ext->melted) {
+       ext->melted = 0;
+       LOG (2, "look-ahead winner external %d not melted anymore", elit);
+      } else
+       LOG (2, "look-ahead winner external %d was not melted anyhow", elit);
+    } else {
+      lglprt (lgl, 1, "[locslook] no valid local search look-ahead");
+      lglprt (lgl, 1, "[locslook] falling back to JWH");
+      res = lgljwhlook (lgl);
+    }
+  } else LOG (1, "no proper local search look-ahead literal found");
+
+  return res;
+}
+
+/*------------------------------------------------------------------------*/
+#if 0
+
+static void lglanaconnected (LGL * lgl) {
+  if (!lglsmallirr (lgl)) return;
+  if (lgl->level) lglbacktrack (lgl, 0);
+  lgldense (lgl, 1);
+  lglsparse (lgl);
+  lglgc (lgl);
+}
+
+static void lglanabiconnected (LGL * lgl) {
+  if (!lglsmallirr (lgl)) return;
+  if (lgl->level) lglbacktrack (lgl, 0);
+  lgldense (lgl, 1);
+  lglsparse (lgl);
+  lglgc (lgl);
+}
+
+#endif
+/*------------------------------------------------------------------------*/
+
+static int lglforklit (int ilit) {
+  int idx = abs (ilit), res;
+  assert (idx > 1);
+  res = idx - 1;
+  if (ilit < 0) res = -res;
+  return res;
+}
+
+static int lglmegaing (LGL * lgl) {
+  if (!lgl->opts->mega.val) return 0;
+  if (lgl->nvars <= 2) return 0;
+  if (!lglmtstk (&lgl->eassume)) return 0;
+  if (lglwaiting (lgl, "mega", lgl->opts->megawait.val)) return 0;
+  if (lgl->stats->simp.count % lgl->opts->megaint.val) return 0;
+  return 1;
+}
+
+static int lglmega (LGL * lgl) {
+  int remain, idx, start, lit, len, res, nlits, * vals, lifted, eqs;
+  char * prefix;
+  unsigned mod;
+  LGL * forked;
+  AVar * av;
+  assert (lgl->opts->mega.val);
+  assert (lgl->nvars > 2);
+  assert (lglmtstk (&lgl->eassume));
+  lglstart (lgl, &lgl->times->mega);
+  lgl->stats->mega.count++;
+  assert (!lgl->simp), assert (!lgl->probing);
+  lgl->simp = lgl->probing = 1;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  remain = 0;
+  nlits = 2*(lgl->nvars - 2);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (!lglisfree (lgl, idx)) continue;
+    av = lglavar (lgl, idx);
+    if (!(av->mega & 1)) remain++;
+    if (!(av->mega & 2)) remain++;
+  }
+  if (remain)
+    lglprt (lgl, 1,
+       "[mega-%d] found %d remaining literals %.0f%% to try in round %d",
+       lgl->stats->mega.count,
+       remain, lglpcnt (remain, nlits), lgl->stats->mega.rounds);
+  else {
+    lgl->stats->mega.rounds++;
+    remain = 0;
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      if (!lglisfree (lgl, idx)) continue;
+      av = lglavar (lgl, idx);
+      av->mega = 0;
+      remain += 2;
+    }
+    lglprt (lgl, 1,
+      "[mega-%d] scheduled %d literals %.0f%% to try in new round %d",
+      lgl->stats->mega.count,
+      remain, lglpcnt (remain, nlits), lgl->stats->mega.rounds);
+  }
+  if (!remain) goto DONE;
+  mod = lgl->nvars - 2;
+  idx = lglrand (lgl) % mod;
+  idx += 2;
+  start = idx;
+  assert (2 <= idx), assert (idx < lgl->nvars);
+  lit = 0;
+  for (;;) {
+    int posbins, negbins;
+    av = lglavar (lgl, idx);
+    if (av->mega == 3) goto CONTINUE;
+    posbins = lglhasbins (lgl, idx);
+    negbins = lglhasbins (lgl, -idx);
+    if (posbins && negbins) goto CONTINUE;
+    if (av->mega == 1) {
+       if (negbins) goto CONTINUE;
+       lit = -idx; break;
+    }
+    if (av->mega == 2) {
+      if (posbins) goto CONTINUE;
+      lit = idx; break;
+    }
+    assert (!av->mega);
+    if (posbins) { lit = -idx; break; }
+    if (negbins) { lit = idx; break; }
+    lit = (lglrand (lgl) & 1) ? -idx : idx;
+    break;
+CONTINUE:
+    if (++idx == lgl->nvars) idx = 2;
+    if (idx == start) {
+      lglprt (lgl, 1,
+       "[mega-%d] no roots in binary implication graph found",
+       lgl->stats->mega.count);
+      goto DONE;
+    }
+  }
+  assert (lit);
+  forked = lglfork (lgl);
+  lglsetopt (forked, "verbose",
+    lglmax (lgl->opts->verbose.val - 1, 0));
+  lglsetopt (forked, "bca", 0);
+  lglsetopt (forked, "boost", 0);
+  lglsetopt (forked, "mega", 0);
+  lglsetopt (forked, "trep", 0);
+  lglsetopt (forked, "wait", 0);
+  len = strlen (lgl->prefix) + 40;
+  NEW (prefix, len);
+  sprintf (prefix, "%s:mega_%d_0: ", lgl->prefix, lgl->stats->mega.count);
+  lglsetprefix (forked, prefix);
+  DEL (prefix, len);
+  lgladd (forked, lglforklit (lit)); lgladd (forked, 0);
+  res = lglsimp (forked, 1);
+  if (res == 20) {
+    lgl->stats->mega.failed++;
+    lglprt (lgl, 1,
+      "[mega-%d] found failed literal in first branch",
+      lgl->stats->mega.count);
+    lglunit (lgl, -lit);
+    if (!lglbcp (lgl)) { lgl->mt = 1; }
+  } else {
+    lglprt (lgl, 1,
+      "[mega-%d] first branch not failing",
+      lgl->stats->mega.count);
+
+    NEW (vals, lgl->nvars);
+    for (idx = 2; idx < lgl->nvars; idx++) {
+      int val = lglfixed (forked, lglforklit (idx));
+      if (!val) continue;
+      vals[idx] = val;
+      av = lglavar (lgl, idx);
+      if (val > 0) av->mega |= 1;
+      if (val < 0) av->mega |= 2;
+    }
+    lglrelease (forked);
+    lgl->forked--;
+    forked = lglfork (lgl);
+    lglsetopt (forked, "verbose",
+      lglmax (lgl->opts->verbose.val - 1, 0));
+    lglsetopt (forked, "bca", 0);
+    lglsetopt (forked, "boost", 0);
+    lglsetopt (forked, "mega", 0);
+    lglsetopt (forked, "trep", 0);
+    lglsetopt (forked, "wait", 0);
+    len = strlen (lgl->prefix) + 40;
+    NEW (prefix, len);
+    sprintf (prefix, "%s:mega-%d-1: ", lgl->prefix, lgl->stats->mega.count);
+    lglsetprefix (forked, prefix);
+    DEL (prefix, len);
+    lgladd (forked, lglforklit (-lit)); lgladd (forked, 0);
+    res = lglsimp (forked, 1);
+    if (res == 20) {
+      lgl->stats->mega.failed++;
+      lglprt (lgl, 1,
+       "[mega-%d] found failed literal in second branch",
+       lgl->stats->mega.count);
+      lglunit (lgl, lit);
+      if (!lglbcp (lgl)) { lgl->mt = 1; }
+    } else {
+      eqs = lifted = 0;
+      for (idx = 2; idx < lgl->nvars; idx++) {
+       int val = lglfixed (forked, lglforklit (idx));
+       if (!val) continue;
+       if (abs (idx) == abs (lit)) continue;
+       if (vals[idx] == val) {
+         lglunit (lgl, (val < 0) ? -idx : idx);
+         lgl->stats->mega.lifted++;
+         lifted++;
+       } else if (vals[idx] == -val) {
+         eqs++;
+#if 0
+         lgl->stats->mega.eqs++;
+         if (val > 0) {
+           lgladd (lgl, lit), lgladd (lgl, idx); lgladd (lgl, 0);
+           lgladd (lgl, -lit), lgladd (lgl, -idx); lgladd (lgl, 0);
+         } else {
+           lgladd (lgl, -lit), lgladd (lgl, idx); lgladd (lgl, 0);
+           lgladd (lgl, -lit), lgladd (lgl, -idx); lgladd (lgl, 0);
+         }
+#endif
+       }
+      }
+      if (lifted || eqs) {
+       lglprt (lgl, 1,
+         "[mega-%d] lifted %d literals and found %d equivalences",
+         lgl->stats->mega.count, lifted, eqs);
+       if (!lglbcp (lgl)) { lgl->mt = 1; }
+      } else
+       lglprt (lgl, 1,
+         "[mega-%d] unsuccesfull",
+         lgl->stats->mega.count);
+    }
+    DEL (vals, lgl->nvars);
+  }
+  lglrelease (forked);
+  lgl->forked--;
+DONE:
+  assert (lgl->simp), assert (lgl->probing);
+  lgl->simp = lgl->probing = 0;
+  lglstop (lgl);
+  return !lgl->mt;
+}
+
+/*------------------------------------------------------------------------*/
+
+static int lglisimp (LGL * lgl) {
+  if (!lgl->opts->simplify.val) return 1;
+
+  if (lglternresolving (lgl) && !lglternres (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglcarding (lgl) && !lglcard (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglgaussing (lgl) && !lglgauss (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lgldecomposing (lgl) && !lgldecomp (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglprobing (lgl) && !lglprobe (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglcgrclosing (lgl) && !lglcgrclsr (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglifting (lgl) && !lglift (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglcliffing (lgl) && !lglcliff (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglunhiding (lgl) && !lglunhide (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lgltreducing (lgl) && !lgltrd (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglblocking (lgl)) lglblock (lgl);
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglcceing (lgl) && !lglcce (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lgleliminating (lgl) && !lglelim (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglrdping (lgl) && !lglrdp (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (!lgltopgc (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglmegaing (lgl) && !lglmega (lgl)) return 0;
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglbcaing (lgl)) lglbca (lgl);
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglbvaing (lgl)) lglbva (lgl);
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  if (lglrephasing (lgl)) lglrephase (lgl);
+  if (!lgl->allphaseset) lglphase (lgl);
+  if (lglterminate (lgl)) return 1;
+  assert (!lgl->mt);
+
+  lgldefrag (lgl);
+
+#if 0
+  lglanaconnected (lgl);
+  lglanabiconnected (lgl);
+#endif
+
+  return 1;
+}
+
+static int lgltabring (LGL * lgl) {
+  int res, rem, irr;
+  if (!lgl->opts->tabr.val) return 0;
+  res = 0;
+  rem = lglrem (lgl);
+  if (rem < lgl->limits->tabr.vars) {
+    lgl->stats->tabr.count++, res = 1;
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] number variables %d drops below limit %d",
+       lgl->stats->tabr.count, rem, lgl->limits->tabr.vars);
+  }
+  irr = lgl->stats->irr.clauses.cur;
+  if (irr < lgl->limits->tabr.clauses) {
+    if (!res) lgl->stats->tabr.count++, res = 1;
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] number clauses %d drops below limit %d",
+       lgl->stats->tabr.count, irr, lgl->limits->tabr.clauses);
+  }
+  return res;
+}
+
+static void lglupdtabr (LGL * lgl) {
+  lgl->limits->tabr.vars =
+    lglrem (lgl) / lgl->opts->tabrvfactor.val;
+  lgl->limits->tabr.clauses =
+    lgl->stats->irr.clauses.cur / lgl->opts->tabrcfactor.val;
+  lglprt (lgl, 1,
+    "[tabula-rasa-%d] new variable limit %d and clause limit %d",
+      lgl->stats->tabr.count,
+      lgl->limits->tabr.vars, lgl->limits->tabr.clauses);
+}
+
+static void lglincsetupreduce (LGL * lgl) {
+  lgl->limits->reduce.inner = lgl->opts->redlinit.val;
+  lglboundredl (lgl);
+  lgl->limits->reduce.outer = 2*lgl->limits->reduce.inner;
+}
+
+static void lgltabrflushred (LGL * lgl) {
+  assert (lgl->opts->tabr.val >= 1);
+  lgliflushcache (lgl, lgl->opts->tabrkeep.val);
+  lglincsetupreduce (lgl);
+}
+
+static void lgltabrflushphases (LGL * lgl) {
+  if (lgl->opts->tabr.val < 2) return;
+  lglflushphasesaux (lgl, 1);
+  lglphase (lgl);
+  lgl->limits->rephase.confs = lgl->stats->rephase.inc = 10000;
+}
+
+static void lgltabrflushscores (LGL * lgl) {
+  QVar * qv;
+  int idx;
+  if (lgl->opts->tabr.val < 4) return;
+  lglrelstk (lgl, &lgl->dsched);
+  lglcutwidth (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    qv = lgl->qvars + idx;
+    qv->pos = -1;
+    qv->score = 0;
+    lgldsched (lgl, idx);
+  }
+}
+
+static void lgltabrsetup (LGL * lgl) {
+  int64_t newlimit;
+  if (lgl->opts->tabr.val < 3) return;
+  if (lgl->limits->simp.cinc != lgl->opts->cintinc.val) {
+    lgl->limits->simp.cinc = lgl->opts->cintinc.val;
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] new conflict interval %d",
+      lgl->stats->tabr.count, lgl->limits->simp.cinc);
+  } else 
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] conflict interval %d does not change",
+      lgl->stats->tabr.count, lgl->limits->simp.cinc);
+  newlimit = lgl->stats->confs + lgl->limits->simp.cinc;
+  if (newlimit < lgl->limits->simp.confs) {
+    lgl->limits->simp.confs = newlimit;
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] new conflict limit %d",
+      lgl->stats->tabr.count, newlimit);
+  } else
+    lglprt (lgl, 1,
+      "[tabula-rasa-%d] conflict limit %d does not change",
+      lgl->stats->tabr.count, lgl->limits->simp.cinc);
+}
+
+static void lgltabularasa (LGL * lgl) {
+  lglstart (lgl, &lgl->times->tabr);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  lgltabrflushred (lgl);
+  lgltabrflushphases (lgl);
+  lgltabrflushscores (lgl);
+  lgltabrsetup (lgl);
+  lglupdtabr (lgl);
+  lglstop (lgl);
+}
+
+static void lglregularly (LGL * lgl) {
+  if (lglreducing (lgl)) lglreduce (lgl, 0);
+  if (lgltabring (lgl)) lgltabularasa (lgl);
+  if (lgldefragmenting (lgl)) lgldefrag (lgl);
+}
+
+static void lglupdsimpcinc (LGL * lgl, int red, int success) {
+  const char * type = "no";
+  int inc = 0, div = 1, res;
+  assert (red >= 0);
+  if (red <= 100) {
+    if (red > 0) {
+      switch (lgl->opts->cintincdiv.val) {
+       case 3: 
+         if (red >= 50) div = 4;
+         else if (red >= 20) div = 3;
+         else if (red >= 10) div = 2;
+         break;
+       case 2: div = red/2 + 1; break;
+       case 1: div = red/1 + 1; break;
+       case 0:
+       default: 
+          assert (!lgl->opts->cintincdiv.val);
+         break;
+      }
+    }
+    inc = lgl->opts->cintinc.val;
+    if (lgl->opts->simplify.val == 1) {
+      type = "arithmetic";
+    } else if (lgl->opts->simplify.val == 2) {
+      if (inc < lgl->limits->simp.cinc) inc = lgl->limits->simp.cinc;
+      type = "geometric";
+    } else inc = 0;
+  }
+  res = inc / div;
+  if (lgl->limits->simp.cinc - res <= INT_MAX)
+    lgl->limits->simp.cinc += res;
+  lglprt (lgl, 2,
+    "[simplification-%d] new lgl->limits->simp.cinc %d",
+    lgl->stats->simp.count, lgl->limits->simp.cinc);
+  if (div > 1)
+    lglprt (lgl, 1,
+      "[simplification-%d] %s conflict interval increment %d = %d / %d",
+      lgl->stats->simp.count, type, res, inc, div);
+  else
+    lglprt (lgl, 1,
+      "[simplification-%d] full %s conflict interval increment %d",
+      lgl->stats->simp.count, type, res);
+
+  if (success &&
+      lgl->opts->cintmaxsoft.val >= 0 &&
+      lgl->limits->simp.cinc >= lgl->opts->cintmaxsoft.val) {
+    lgl->limits->simp.cinc = lgl->opts->cintmaxsoft.val;
+    lglprt (lgl, 1,
+      "[simplification-%d] "
+      "conflict interval soft limit %d reached",
+      lgl->stats->simp.count, lgl->limits->simp.cinc);
+  } else if (lgl->opts->cintmaxhard.val >= 0 &&
+             lgl->limits->simp.cinc >= lgl->opts->cintmaxhard.val) {
+    lgl->limits->simp.cinc = lgl->opts->cintmaxhard.val;
+    lglprt (lgl, 1,
+      "[simplification-%d] "
+      "conflict interval hard limit %d reached",
+      lgl->stats->simp.count, lgl->limits->simp.cinc);
+  }
+}
+
+static void lglupdsimpint (LGL * lgl, int oldrem, int oldirr, int forced) {
+  int remvar, remirr, pcntred, simpcinc;
+  int64_t pcntremvar64, pcntremirr64;
+  int pcntremvar, pcntremirr;
+
+  remvar = oldrem - lglrem (lgl);
+  if (remvar < 0) remvar = 0;
+  pcntremvar64 = (remvar > 0) ? ((1000ll*remvar)/oldrem + 5)/10 : 0ll;
+  assert (pcntremvar64 <= 100);
+  pcntremvar = pcntremvar64;
+  lglprt (lgl, 1,
+    "[simplification-%d] removed %d variables %.1f%% "
+    "(%d remain %0.f%%)",
+    lgl->stats->simp.count, remvar, lglpcnt (remvar, oldrem),
+    lglrem (lgl), lglpcnt (lglrem (lgl), lgl->limits->inc.vars.start));
+
+  remirr = oldirr - lgl->stats->irr.clauses.cur;
+  if (remirr < 0) remirr = 0;
+  pcntremirr64 = (remirr > 0) ? ((1000ll*remirr)/oldirr + 5)/10 : 0ll;
+  assert (pcntremirr64 <= 100);
+  pcntremirr = pcntremirr64;
+  lglprt (lgl, 1,
+    "[simplification-%d] removed %d irredundant clauses %.1f%% "
+    "(%d remain %.0f%%)",
+    lgl->stats->simp.count, remirr, lglpcnt (remirr, oldirr),
+    lgl->stats->irr.clauses.cur,
+      lglpcnt (lgl->stats->irr.clauses.cur, lgl->limits->inc.clauses.start));
+
+  pcntred = lglmax (pcntremvar, pcntremirr);
+  lglprt (lgl, 1,
+    "[simplification-%d] maximum reduction of %d%% = max (%d%%, %d%%)",
+    lgl->stats->simp.count, pcntred, pcntremvar, pcntremirr);
+
+  if (forced) {
+    simpcinc = 0;
+    lglprt (lgl, 1,
+      "[simplification-%d] forced so keeping old conflict interval %d",
+      lgl->stats->simp.count, lgl->limits->simp.cinc);
+  } else if (lgl->stats->confs < lgl->limits->simp.confs &&
+             (simpcinc = lgl->limits->simp.cinc)) {
+    lglprt (lgl, 1,
+      "[simplification-%d] keeping old conflict interval %d "
+      "(non-conflict triggered simplification)",
+      lgl->stats->simp.count, lgl->limits->simp.cinc);
+  } else if (remvar > 0 && pcntred >= lgl->opts->simprtc.val) {
+    int64_t scaledcinc;
+    int factor;
+    lglprt (lgl, 1,
+      "[simplification-%d] large reduction %d%% >= %d%% limit",
+      lgl->stats->simp.count, pcntred, lgl->opts->simprtc.val);
+    factor = lgl->opts->simpidiv.val - lgl->stats->simp.count;
+    if (factor <= 0) factor = 1;
+    simpcinc = lgl->opts->simpinterdelay.val / factor;
+    scaledcinc = lgl->stats->confs/lgl->opts->simpiscale.val;
+    if (scaledcinc > lgl->limits->simp.cinc)
+      scaledcinc = lgl->limits->simp.cinc;
+    if (scaledcinc < simpcinc) {
+      lglprt (lgl, 1,
+       "[simplification-%d] new conflict interval %d = %d/%d",
+       lgl->stats->simp.count,
+       simpcinc, lgl->opts->simpinterdelay.val, factor);
+    } else {
+      assert (scaledcinc <= INT_MAX);
+      simpcinc = (int) scaledcinc;
+      lglprt (lgl, 1,
+       "[simplification-%d] new conflict interval %d = min (%lld/%d, %d)",
+       lgl->stats->simp.count,
+       simpcinc, (LGLL) lgl->stats->confs, lgl->opts->simpiscale.val,
+       lgl->limits->simp.cinc);
+    }
+  } else {
+    lglupdsimpcinc (lgl, pcntred, remvar || remirr);
+    simpcinc = lgl->limits->simp.cinc;
+    lglprt (lgl, 1, "[simplification-%d] new conflict interval %d",
+            lgl->stats->simp.count, simpcinc);
+  }
+
+  if (forced) {
+    lglprt (lgl, 1,
+      "[simplification-%d] conflict limit remains at %lld",
+      lgl->stats->simp.count, (LGLL) lgl->limits->simp.confs);
+  } else {
+    int penalty, pensimpcinc;
+         if (lgl->stats->irr.clauses.cur <    1000000) penalty = 1;
+    else if (lgl->stats->irr.clauses.cur <   10000000) penalty = 2;
+    else                                               penalty = 4;
+    if (INT_MAX/penalty < simpcinc) pensimpcinc = INT_MAX;
+    else pensimpcinc = penalty * simpcinc;
+    lglprt (lgl, 1,
+      "[simplification-%d] penalized conflict interval %d = %d * %d",
+      lgl->stats->simp.count, pensimpcinc, penalty, simpcinc);
+    assert (pensimpcinc >= 0);
+    lgl->limits->simp.confs = lgl->stats->confs + pensimpcinc;
+    assert (lgl->limits->simp.confs >= 0);
+    lglprt (lgl, 1,
+      "[simplification-%d] new conflict limit %lld",
+      lgl->stats->simp.count, (LGLL) lgl->limits->simp.confs);
+  }
+
+  if (lgl->limits->simp.pen > 0) {
+    lgl->limits->simp.pen--;
+    lglprt (lgl, 1,
+      "[simplification-%d] simplification penalty reduced to %d",
+      lgl->stats->simp.count, lgl->limits->simp.pen);
+  }
+
+  lgl->limits->simp.vars = lglrem (lgl);
+  lgl->forcerephead = 1;
+  if (lgl->wait > 0) lgl->wait--;
+}
+
+static int lglpreprocessing (LGL * lgl, int forced) {
+  int res, oldrem, oldirr;
+  if (lgl->mt) return 0;
+  assert (!lgl->searching);
+  lgl->stats->simp.count++;
+  oldrem = lglrem (lgl);
+  oldirr = lgl->stats->irr.clauses.cur;
+  res = lglisimp (lgl);
+  lglupdsimpint (lgl, oldrem, oldirr, forced);
+  assert (res == !lgl->mt);
+  return res;
+}
+
+static int lglsimplimhit (LGL * lgl) {
+  int64_t n, o, d;
+  int a, r, res = 0;;
+  if (!lgl->opts->inprocessing.val && lgl->stats->simp.count) return 0;
+  if (lgl->stats->confs >= lgl->limits->simp.confs) {
+    lglprt (lgl, 1, "");
+    lglprt (lgl, 1,
+      "[simplification-%d] limit of %lld conflicts hit after %lld conflicts",
+      lgl->stats->simp.count + 1,
+      (LGLL) lgl->limits->simp.confs, (LGLL) lgl->stats->confs);
+    lgl->stats->simp.limhit.confs++;
+    res = 1;
+  }
+  if (!res &&
+      (o = lgl->limits->simp.vars) &&
+      (n = lglrem (lgl)) >= lgl->opts->simpvarlim.val) {
+    d = n - o;
+    r = 100*d;
+    r /= o;
+    if (r <= INT_MIN || r > INT_MAX) a = INT_MAX;
+    else if (r < 0) a = -r;
+    else a = r;
+    if (a >= lgl->opts->simpvarchg.val) {
+      lglprt (lgl, 1, "");
+      lglprt (lgl, 1,
+       "[simplification-%d] limit hit: "
+       "remaining variables changed from %lld to %lld by %d%%",
+       lgl->stats->simp.count + 1, (LGLL) o, (LGLL) n, r);
+      lgl->stats->simp.limhit.vars++;
+      res = 1;
+    }
+  }
+  if (res) {
+    if (lgl->limits->simp.pen)
+      lglprt (lgl, 1,
+       "[simplification-%d] with simplification penalty of %d",
+       lgl->stats->simp.count + 1, lgl->limits->simp.pen);
+    else
+      lglprt (lgl, 2,
+       "[simplification-%d] no simplification penalty",
+       lgl->stats->simp.count + 1);
+  }
+  return res;
+}
+
+static int lglinprocessing (LGL * lgl) {
+  int res, oldrem, oldirr;
+  assert (lgl->searching);
+  if (!lglsimplimhit (lgl)) return !lgl->mt;
+  lgl->stats->simp.count++;
+  lglstart (lgl, &lgl->times->inpr);
+  oldrem = lglrem (lgl);
+  oldirr = lgl->stats->irr.clauses.cur;
+  res = lglisimp (lgl);
+  lglupdsimpint (lgl, oldrem, oldirr, 0);
+  lglstop (lgl);
+  assert (res == !lgl->mt);
+  return res;
+}
+
+static int lglbcptop (LGL * lgl) {
+  int res;
+  if (lglbcp (lgl)) res = 1;
+  else {
+#ifndef NDEBUG
+    int tmp =
+#endif
+    lglana (lgl);
+    assert (!tmp);
+    if (lgl->conf.lit) {
+      LOG (1, "top level propagation produces inconsistency");
+      if (!lgl->mt) lgl->mt = 1;
+    } else assert (lgl->failed);
+    res = 0;
+  }
+  return res;
+}
+
+static int lglimhit (LGL * lgl, Lim * lim) {
+  if (!lim) return 0;
+  if (lim->decs >= 0 && lgl->stats->decisions >= lim->decs) {
+    lglprt (lgl, 1, "[limits] decision limit %lld hit at %lld decisions",
+      (LGLL) lim->decs, (LGLL) lgl->stats->decisions);
+    return 1;
+  }
+  if (lim->confs >= 0 && lgl->stats->confs >= lim->confs) {
+    lglprt (lgl, 1, "[limits] conflict limit %lld hit at %lld conflicts",
+      (LGLL) lim->confs, (LGLL) lgl->stats->confs);
+    return 1;
+  }
+  if (lim->props >= 0 && lgl->stats->props.search >= lim->props) {
+    lglprt (lgl, 1,
+      "[limits] propagation limit %lld hit at %lld propagations",
+      (LGLL) lim->props, (LGLL) lgl->stats->props.search);
+    return 1;
+  }
+  return 0;
+}
+
+static int lgloop (LGL * lgl, Lim * lim) {
+  unsigned confs = 0;
+  for (;;) {
+    if (lglbcpsearch (lgl) && lglinprocessing (lgl)) {
+      if (lglterminate (lgl)) return 0;
+      if (!lglsyncunits (lgl)) return 20;
+      if (!lglsyncls (lgl)) continue;
+      if (lglfailedass (lgl)) return 20;
+      lglregularly (lgl);
+      if (lglimhit (lgl, lim)) return 0;
+      if (lglocsing (lgl)) lglocs (lgl);
+      if (lglrestarting (lgl)) { lglrestart (lgl); continue; }
+      if (!lgldecide (lgl)) return 10;
+    } else if (!lglana (lgl)) return 20;
+    else if (!(++confs & 15) && lglterminate (lgl)) return 0;
+  }
+}
+
+static int lglsearch (LGL * lgl, Lim * lim) {
+  int res;
+  assert (!lgl->searching);
+  lgl->searching = 1;
+  lglstart (lgl, &lgl->times->srch);
+  res = lgloop (lgl, lim);
+  assert (lgl->searching);
+  lgl->searching = 0;
+  lglstop (lgl);
+  return res;
+}
+
+static int lgltopsimp (LGL * lgl, int forcesimp) {
+  assert (lgl->state == READY);
+  if (lgl->mt) return 20;
+  if (lglfailedass (lgl)) return 20;
+  if (!lglbcptop (lgl)) return 20;
+  if (lgl->mt || lglfailedass (lgl)) return 20;
+  if (lglterminate (lgl)) return 0;
+  if ((forcesimp || lglsimplimhit (lgl)) &&
+      !lglpreprocessing (lgl, forcesimp)) return 20;
+  if (lglfailedass (lgl)) return 20;
+  if (!lgl->stats->cutwidths) lglcutwidth (lgl);
+  lglrep (lgl, 2, 's');
+  return 0;
+}
+
+static int lglsolve (LGL * lgl, Lim * lim, int forcesimp) {
+  int res;
+  lgl->limits->simp.pen = lgl->opts->simpen.val;
+  lglstart (lgl, &lgl->times->prep);
+  res = lgltopsimp (lgl, forcesimp);
+  lglstop (lgl);
+  if (res) { assert (res == 20); return res; }
+  return lglsearch (lgl, lim);
+}
+
+static void lglincsetup (LGL * lgl) {
+
+  if (lgl->opts->incsavevisits.val)
+    lgl->limits->inc.visits = lgl->stats->visits.search;
+
+  assert (lgl->limits->inc.clauses.add <= lgl->stats->irr.clauses.add);
+  if (lgl->limits->inc.clauses.add < lgl->stats->irr.clauses.add) {
+    lgl->limits->inc.clauses.add = lgl->stats->irr.clauses.add;
+    lgl->elmrtc = lgl->blkrtc = lgl->ccertc = 0;
+    lgl->elmstuck = lgl->blkstuck = 0;
+    lgl->wait = lgl->opts->waitmax.val;
+  }
+
+  lgl->limits->inc.clauses.start = lgl->stats->irr.clauses.cur;
+  lgl->limits->inc.vars.start = lglrem (lgl);
+
+  lgl->limits->tabr.clauses = lgl->limits->inc.clauses.start;
+  lgl->limits->tabr.vars = lgl->limits->inc.vars.start;
+  lgl->limits->tabr.vars /= lgl->opts->tabrvfactor.val;
+  lgl->limits->tabr.clauses /= lgl->opts->tabrcfactor.val;
+
+  lglincsetupreduce (lgl);
+
+  lgl->limits->flipint = lgl->opts->flipint.val;
+
+  lgl->stats->locs.min = INT_MAX;
+  lglupdlocslim (lgl, 0);
+
+  lgl->limits->rephase.confs = lgl->stats->rephase.inc = 10000;
+
+  CLR (lgl->limits->restart);
+  lgl->limits->restart.confs =
+    lgl->stats->confs + lgl->opts->restartinit.val;
+
+  lgl->limits->simp.pen = 0;
+  if (lgl->opts->incredcint.val > 1) {
+    lgl->limits->simp.cinc /= lgl->opts->incredcint.val;
+    lglprt (lgl, 1,
+       "[incremental-setup] conflict interval increment reduced to %d",
+       lgl->limits->simp.cinc);
+  }
+  if (lgl->opts->incredconfslim.val) {
+    lgl->limits->simp.confs =
+      ((100-lgl->opts->incredconfslim.val)*lgl->limits->simp.confs)/100;
+    lglprt (lgl, 1,
+       "[incremental-setup] conflict limit reduced to %lld",
+       (LGLL) lgl->limits->simp.confs);
+  }
+
+  CLR (lgl->limits->cgr.del);
+
+  CLR (lgl->limits->elm.del);
+  CLR (lgl->limits->blk.del);
+  CLR (lgl->limits->cliff.del);
+
+  CLR (lgl->limits->rdp.del);
+  CLR (lgl->limits->trd.del);
+  CLR (lgl->limits->unhd.del);
+  CLR (lgl->limits->trnr.del);
+  CLR (lgl->limits->lft.del);
+  CLR (lgl->limits->cce.del);
+  CLR (lgl->limits->card.del);
+
+  CLR (lgl->limits->gauss.del);
+
+  CLR (lgl->limits->prb.simple.del);
+  CLR (lgl->limits->prb.basic.del);
+  CLR (lgl->limits->prb.treelook.del);
+
+  CLR (lgl->limits->bca.del);
+}
+
+static void lglsetup (LGL * lgl) {
+  if (lgl->setuponce) goto DONE;
+  lgl->limits->dfg = lgl->stats->pshwchs + lgl->opts->defragint.val;
+
+  lgl->limits->blk.irrprgss = -1;
+  lgl->limits->elm.irrprgss = -1;
+  lgl->limits->term.steps = -1;
+
+  lgl->phaseneg = lgl->opts->phaseneginit.val;
+
+  lgl->rng.w = (unsigned) lgl->opts->seed.val;
+  lgl->rng.z = ~lgl->rng.w;
+  lgl->rng.w <<= 1;
+  lgl->rng.z <<= 1;
+  lgl->rng.w += 1;
+  lgl->rng.z += 1;
+  lgl->rng.w *= 2019164533u, lgl->rng.z *= 1000632769u;
+
+  assert (!lgl->stats->decisions);
+  lgl->limits->randec += lgl->opts->randecint.val/2;
+  lgl->limits->randec += lglrand (lgl) % lgl->opts->randecint.val;
+
+  lgl->limits->simp.vars = lglrem (lgl);
+
+  lgl->setuponce = 1;
+  lglchkenv (lgl);
+DONE:
+  lglinitscores (lgl);
+  lglincsetup (lgl);
+  TRANS (READY);
+}
+
+static void lglinitsolve (LGL * lgl) {
+  if (lgl->state != READY) lglsetup (lgl);
+  lglredvars (lgl);
+  lglfitstk (lgl, &lgl->irr);
+#ifndef NCHKSOL
+  lglfitstk (lgl, &lgl->orig);
+#endif
+  lglrep (lgl, 1, '*');
+}
+
+#ifndef NLGLPICOSAT
+static void lglpicosatchksol (LGL * lgl) {
+#ifndef NDEBUG
+  int idx, lit, res, * p;
+  Val val;
+  if (lgl->picosat.res) assert (lgl->picosat.res == 10);
+  lglpicosatinit (lgl);
+  assert (!picosat_inconsistent (PICOSAT));
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    val = lglval (lgl, idx);
+    assert (val);
+    lit = lglsgn (val) * idx;
+    picosat_assume (PICOSAT, lit);
+  }
+  for (p = lgl->eassume.start; p < lgl->eassume.top; p++)
+    picosat_assume (PICOSAT, lglimport (lgl, *p));
+  res = picosat_sat (PICOSAT, -1);
+  assert (res == 10);
+  LOG (1, "PicoSAT checked solution");
+#endif
+}
+#endif
+
+static void lgleassign (LGL * lgl, int lit) {
+  Ext * ext;
+  ext = lglelit2ext (lgl, lit);
+  LOG (3, "external assign %d ", lit);
+  ext->val = lglsgn (lit);
+}
+
+static void lglcomputechanged (LGL * lgl) {
+  Ext * ext;
+  int eidx;
+  lgl->changed = 0;
+  for (eidx = 1; eidx <= lgl->maxext; eidx++) {
+    ext = lglelit2ext (lgl, eidx);
+    if (ext->oldval && ext->oldval != ext->val) lgl->changed++;
+    ext->oldval = ext->val;
+  }
+  LOG (1, "changed %d assignments in extension", lgl->changed);
+}
+
+static void lglextend (LGL * lgl) {
+  int * p, lit, eidx, ilit, next, satisfied, val, * start, erepr, equiv;
+  Ext * ext, * extrepr;
+  assert (lgl->state & SATISFIED);
+  assert (!(lgl->state & EXTENDED));
+  lgleunassignall (lgl);
+  for (equiv = 0; equiv <= 1; equiv++) {
+    if (equiv)
+      LOG (1, "initializing assignment of non-representative externals");
+    else
+      LOG (1, "initializing assignment of external representatives");
+    for (eidx = 1; eidx <= lgl->maxext; eidx++) {
+      ext = lglelit2ext (lgl, eidx);
+      if (!ext->imported) continue;
+      if (equiv != ext->equiv) continue;
+      assert (!ext->val);
+      if (ext->equiv) {
+       erepr = lglerepr (lgl, eidx);
+LOG (3, "initializing external %d assignment from external representative %d",
+        eidx, erepr);
+       assert (erepr != eidx);
+       extrepr = lglelit2ext (lgl, erepr);
+       if (!(val = extrepr->val)) {
+         ilit = extrepr->repr;
+         if (ilit) {
+           LOG (3, "using external %d to internal %d mapping",
+                abs (erepr), ilit);
+           val = lglcval (lgl, ilit);
+         } else
+LOG (3, "external %d without internal representative", abs (erepr));
+       }
+       if (erepr < 0) val = -val;
+      } else
+      if ((ilit = ext->repr)) {
+       LOG (3, "using external %d to internal %d mapping", eidx, ilit);
+       val = lglcval (lgl, ilit);
+      } else {
+       LOG (3, "external %d without internal representative", eidx);
+       val = 0;
+      }
+      lit = (val > 0) ? eidx : -eidx;
+      lgleassign (lgl, lit);
+    }
+  }
+  start = lgl->extend.start;
+  p = lgl->extend.top;
+  if (p == start) goto SKIP;
+  assert (p > start);
+  p--;
+  assert (!*p);
+  while (p > start) {
+#ifndef NLGLOG
+    if (lgl->opts->log.val >= 4) {
+      int * q;
+      for (q = p; q[-1]; q--)
+       ;
+      LOGCLS (4, q, "next sigma clause to consider");
+    }
+#endif
+    satisfied = 0;
+    next = 0;
+    do {
+      lit = next;
+      if (p == start) next = 0; else next = *--p;
+      if (!lit || satisfied) continue;
+      val = lglederef (lgl, lit);
+      assert (!next || val);
+      if (val > 0) {
+       LOG (4, "sigma clause satisfied by %d", lit);
+       satisfied = 1;
+      }
+    } while (next);
+    assert (lit);
+    if (satisfied) continue;
+    lgleassign (lgl, lit);
+  }
+SKIP:
+  lglcomputechanged (lgl);
+  TRANS (EXTENDED);
+}
+
+void lglsetphases (LGL * lgl) {
+  int elit, phase;
+  REQINITNOTFORKED ();
+  TRAPI ("setphases");
+  REQUIRE (SATISFIED | EXTENDED);
+  if (!(lgl->state & EXTENDED)) lglextend (lgl);
+  for (elit = 1; elit <= lgl->maxext; elit++) {
+    phase = lglederef (lgl, elit);
+    assert (abs (phase) <= 1);
+    lglesetphase (lgl, elit, phase);
+  }
+  if (lgl->clone) lglsetphases (lgl->clone);
+}
+
+#ifndef NCHKSOL
+#include <signal.h>
+#include <unistd.h>
+static void lglchksol (LGL * lgl) {
+  int * p, * c, * eoo = lgl->orig.top, lit, satisfied, sign, idx;
+  unsigned bit;
+  Ext * ext;
+  assert (lglmtstk (&lgl->orig) || !eoo[-1]);
+  assert (lgl->state == EXTENDED);
+  for (c = lgl->orig.start; c < eoo; c = p + 1) {
+    satisfied = 0;
+    for (p = c; (lit = *p); p++)
+      if (!satisfied && lglederef (lgl, lit) > 0)
+       satisfied = 1;
+    if (satisfied) continue;
+    fflush (stderr);
+    lglmsgstart (lgl, 0);
+    fprintf (lgl->out, "unsatisfied original external clause");
+    for (p = c; (lit = *p); p++) fprintf (lgl->out, " %d", lit);
+    lglmsgend (lgl);
+    assert (satisfied);
+    usleep (1000);
+    abort ();  // NOTE: not 'lglabort' on purpose !!
+  }
+  for (idx = 1; idx <= lgl->maxext; idx++) {
+    ext = lglelit2ext (lgl, idx);
+    if (!ext->assumed) continue;
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      bit = 1u << (lit < 0);
+      if (!(ext->assumed & bit)) continue;
+      if (lglederef (lgl, lit) > 0) continue;
+      lglprt (lgl, 0, "unsatisfied assumption %d", lit);
+      assert (lglederef (lgl, lit) > 0);
+      usleep (1000);
+      abort ();        // DITO: not 'lglabort' on purpose !!
+    }
+  }
+}
+#endif
+
+static void lglclass (LGL * lgl, LGL * from) {
+  Ext * extfrom, * extlgl;
+  int eidx, cloned;
+  REQINITNOTFORKED ();
+  ABORTIF (lgl->mt, "can not clone assignment into inconsistent manager");
+  ABORTIF (!from, "uninitialized 'from' solver");
+  ABORTIF (!(from->state & (SATISFIED | EXTENDED)),
+    "require 'from' state to be (SATISFIED | EXTENDED)"); 
+  ABORTIF (from->maxext != lgl->maxext,
+    "can not clone assignments for different sets of variables");
+  if (!(from->state & EXTENDED)) lglextend (from);
+  lglreset (lgl);
+  lgleunassignall (lgl);
+  cloned = lgl->changed = 0;
+  for (eidx = 1; eidx <= lgl->maxext; eidx++) {
+    extlgl = lglelit2ext (lgl, eidx);
+    if (!extlgl->imported) continue;
+    extfrom = lglelit2ext (from, eidx);
+    ABORTIF (!extfrom->imported, 
+      "can not clone assignment of literal imported only by 'to'");
+    assert (extfrom->val == 1 || extfrom->val == -1);
+    lgleassign (lgl, extfrom->val*eidx);
+    cloned++;
+  }
+  lglcomputechanged (lgl);
+  lglprt (lgl, 1, "[class] cloned %d assignments (%d changed)",
+          cloned, lgl->changed);
+  TRANS (EXTENDED);
+#ifndef NCHKSOL
+  lglchksol (lgl);
+#endif
+#ifndef NLGLPICOSAT
+  lglpicosatchksol (lgl);
+#endif
+}
+
+static void lglnegass (LGL * lgl) {
+  const int  * p;
+  Stk eassume;
+  REQINITNOTFORKED ();
+  TRAPI ("negass");
+  if (lgl->mt) return;
+  CLR (eassume);
+  for (p = lgl->eassume.start; p < lgl->eassume.top; p++)
+    lglpushstk (lgl, &eassume, *p);
+  for (p = eassume.start; p < eassume.top; p++)
+    lgleadd (lgl, -*p);
+  lgleadd (lgl, 0);
+  assert (lglmtstk (&lgl->eassume));
+  for (p = eassume.start; p < eassume.top; p++)
+    lglassume (lgl, *p);
+  lglrelstk (lgl, &eassume);
+  lgluse (lgl);
+  if (lgl->clone) lglnegass (lgl->clone);
+}
+
+static int lglcompactify (LGL * lgl, int res) {
+  if (!lgl->opts->compact.val) return 0;
+  if (!res) return 1;
+  if (res == 20) return 1;
+  assert (res == 10);
+  return lgl->opts->compact.val >= 2;
+}
+
+static int lglisat (LGL * lgl, Lim * lim, int simpits) {
+  int res, count, reported = lgl->stats->reported;
+  lglreset (lgl);
+  lglinitsolve (lgl);
+  res = lglsolve (lgl, lim, 0);
+  for (count = 0; !res && count < simpits; count++) {
+    lglprt (lgl, 1,
+      "[simplification-%d] next forced simplification iteration %d",
+      lgl->stats->simp.count + 1, count + 1);
+    res = lglsolve (lgl, lim, 1);
+  }
+  if (lglcompactify (lgl, res)) lglcompact (lgl);
+  if (!res) {
+    TRANS (UNKNOWN);
+    lglrep (lgl, 1, '?');
+  }
+  if (res == 10) {
+    TRANS (SATISFIED);
+    lglrep (lgl, 1, '1');
+  }
+  if (res == 20) {
+    TRANS (UNSATISFIED);
+    if (!lgl->level && !lgl->mt) assert (lgl->failed);
+    lglrep (lgl, 1, '0');
+  }
+  if (reported != lgl->stats->reported) lglflshrep (lgl);
+  if (res == 10) lglextend (lgl);
+#ifndef NCHKSOL
+  if (res == 10) lglchksol (lgl);
+#endif
+#ifndef NLGLPICOSAT
+  if (res == 10) lglpicosatchksol (lgl);
+  if (res == 20) lglpicosatchkunsat (lgl);
+#endif
+  return res;
+}
+
+int lglunclone (LGL * lgl, LGL * from) {
+  int res;
+  REQINITNOTFORKED ();
+  if (lgl->mt) return 20;
+  ABORTIF (!from, "uninitialized 'from' solver");
+  if (from->mt || (from->state & UNSATISFIED)) {
+    lglprt (lgl, 1, "[unclone] unsatisfied state");
+    lglnegass (lgl);
+    res = lglisat (lgl, 0, 0);
+  } else if (from->state & (SATISFIED | EXTENDED)) {
+    lglprt (lgl, 1, "[unclone] satisfied state");
+    lglclass (lgl, from);
+    res = 10;
+  } else {
+    lglprt (lgl, 1, "[unclone] unknown state");
+    lglreset (lgl);
+    TRANS (UNKNOWN);
+    res = 0;
+  }
+  return res;
+}
+
+#define CHKCLONESTATS(STATS) \
+do { \
+  assert (clone->stats->STATS == orig->stats->STATS); \
+} while (0)
+
+static void lglchkclonesamestats (LGL * orig) {
+#ifndef NDEBUG
+  LGL * clone = orig->clone;
+  assert (clone);
+  assert (clone->state == orig->state);
+  CHKCLONESTATS (confs);
+  CHKCLONESTATS (decisions);
+  CHKCLONESTATS (bytes.current);
+  CHKCLONESTATS (bytes.max);
+  CHKCLONESTATS (props.search);
+  CHKCLONESTATS (props.simp);
+  CHKCLONESTATS (props.lkhd);
+  CHKCLONESTATS (visits.search);
+  CHKCLONESTATS (visits.simp);
+  CHKCLONESTATS (visits.lkhd);
+#endif
+}
+
+#define CHKCLONE() \
+do { \
+  if (!lgl->clone) break; \
+  lglchkclonesamestats (lgl); \
+} while (0)
+
+#define CHKCLONENORES(FUN) \
+do { \
+  if (!lgl->clone) break; \
+  FUN (lgl->clone); \
+  CHKCLONE (); \
+} while (0)
+
+#define CHKCLONERES(FUN,RES) \
+do { \
+  int CLONERES; \
+  if (!lgl->clone) break; \
+  CLONERES = FUN (lgl->clone); \
+  ABORTIF (CLONERES != (RES), \
+           "%s (lgl->clone) = %d differs from %s (lgl) = %d", \
+          __FUNCTION__, CLONERES, __FUNCTION__, (RES)); \
+  CHKCLONE (); \
+} while (0)
+
+#define RETURN(FUN,RES) \
+do { \
+  TRAPI ("return %d", (RES)); \
+  CHKCLONERES (FUN, (RES)); \
+} while (0)
+
+#define CHKCLONEARGRES(FUN,ARG,RES) \
+do { \
+  int CLONERES; \
+  if (!lgl->clone) break; \
+  CLONERES = FUN (lgl->clone, (ARG)); \
+  ABORTIF (CLONERES != (RES), \
+           "%s (lgl->clone, %d) = %d differs from %s (lgl, %d) = %d", \
+          __FUNCTION__, (ARG), CLONERES, __FUNCTION__, (ARG), (RES)); \
+  CHKCLONE (); \
+} while (0)
+
+#define RETURNARG(FUN,ARG,RES) \
+do { \
+  TRAPI ("return %d", (RES)); \
+  CHKCLONEARGRES (FUN, (ARG), (RES)); \
+} while (0)
+
+static void lglsetlim (LGL * lgl, Lim * lim) {
+  int64_t clim, dlim, plim, confs, decs, props, delay, delayed;
+  if ((dlim = lgl->opts->dlim.val) < 0) {
+    lim->decs = -1;
+    lglprt (lgl, 1, "[limits] no decision limit");
+  } else {
+    decs = lgl->stats->decisions;
+    lim->decs = (decs >= LLMAX - dlim) ? LLMAX : decs + dlim;
+    lglprt (lgl, 1, "[limits] decision limit %lld after %lld decisions", 
+            (LGLL) lim->decs, (LGLL) decs);
+  }
+  if ((clim = lgl->opts->clim.val) < 0) {
+    lim->confs = -1;
+    lglprt (lgl, 1, "[limits] no conflict limit");
+  } else {
+    confs = lgl->stats->confs;
+    lim->confs = (confs >= LLMAX - clim) ? LLMAX : confs + clim;
+    lglprt (lgl, 1, "[limits] conflict limit %lld after %lld conflicts", 
+            (LGLL) lim->confs, (LGLL) confs);
+  }
+  if ((plim = lgl->opts->plim.val) < 0) {
+    lim->props = -1;
+    lglprt (lgl, 1, "[limits] no propagation limit");
+  } else {
+    plim *= 1000;
+    props = lgl->stats->props.search;
+    lim->props = (props >= LLMAX - plim) ? LLMAX : props + plim;
+    lglprt (lgl, 1,
+      "[limits] propagation limit %lld after %lld propagations", 
+      (LGLL) lim->props, (LGLL) props);
+  }
+  if ((delay = lgl->opts->simpdelay.val) > 0) {
+    delayed = lgl->stats->confs + delay;
+    if (delayed > lgl->limits->simp.confs) {
+      lgl->limits->simp.confs = delayed;
+      lglprt (lgl, 1,
+       "[limits] simplification delayed by %lld to %lld conflicts",
+       (LGLL) delay, (LGLL) lgl->limits->simp.confs);
+    } else lglprt (lgl, 1, 
+             "[limits] simplification conflict limit already exceeds delay");
+  } else lglprt (lgl, 1, 
+           "[limits] simplification not delayed since 'simpdelay' zero");
+}
+
+int lglsat (LGL * lgl) {
+  int res;
+  Lim lim;
+  REQINITNOTFORKED ();
+  TRAPI ("sat");
+  lglstart (lgl, &lgl->times->all);
+  lgl->stats->calls.sat++;
+  ABORTIF (!lglmtstk (&lgl->clause), "clause terminating zero missing");
+  lglfreezer (lgl);
+  lglsetlim (lgl, &lim);
+  res = lglisat (lgl, &lim, 0);
+  lglstop (lgl);
+  RETURN (lglsat, res);
+  return res;
+}
+
+int lglmosat (LGL * lgl, void * state, lglnotify f, int * targets) {
+  int cint, clim, target, ntargets, rtargets, next, round, done;
+  signed char * reported, * r;
+  int64_t confs, totalclim;
+  const int * p;
+  Val val;
+  Lim lim;
+
+  REQINITNOTFORKED ();
+  ABORTIF (!lglmtstk (&lgl->clause), "clause terminating zero missing");
+
+  TRAPI ("mosat");
+  lglstart (lgl, &lgl->times->all);
+  lgl->stats->calls.mosat++;
+
+  ntargets = 0;
+  for (p = targets; *p; p++) ntargets++;
+  NEW (reported, ntargets);
+  rtargets = ntargets;
+
+  cint = lgl->opts->mocint.val;
+  totalclim = (lgl->opts->clim.val < 0) ? 
+                LLMAX : lgl->stats->confs + lgl->opts->clim.val;
+  round = 1;
+  done = next = 0;
+
+  lglprt (lgl, 1,
+    "[mosat-%lld] given %d targets",
+    (LGLL) lgl->stats->calls.mosat, ntargets);
+
+  while (!lgl->mt) {
+
+    for (p = targets, r = reported; !done && (target = *p); p++, r++) {
+      if (*r) continue;
+      val = lglfixed (lgl, target);
+      if (val >= 0) {
+         if (lgl->state == SATISFIED && lglval (lgl, target) > 0) val = 1;
+        else val = 0;
+      }
+      if (!val) continue;
+      LOG (1, "notify %d %d", target, val);
+      done = !f (state, target, val);
+      assert (rtargets > 0), rtargets--;
+      *r = val;
+    }
+
+    round++;
+    lglprt (lgl, 1,
+      "[mosat-%lld-%d] %d targets remain out of %d (%.0f%%)",
+      (LGLL) lgl->stats->calls.mosat, round, rtargets, ntargets,
+      lglpcnt (rtargets, ntargets));
+
+    if (!rtargets) break;
+    if (lgl->stats->confs > totalclim) break;
+
+    for (;;) {
+      assert (next < ntargets);
+      if (!lglfixed (lgl, (target = targets[next]))) break;
+      if (++next == ntargets) next = 0;
+    }
+
+    LOG (1, "focusing on target %d", target);
+    lglassume (lgl, target);
+
+    confs = lgl->stats->confs;
+    clim = lglmin (cint, lgl->opts->clim.val);
+    lim.confs = (confs >= LLMAX - clim) ? LLMAX : confs + clim;
+    lim.decs = -1;
+    lglprt (lgl, 1, "[limits] conflict limit %lld after %lld conflicts", 
+            (LGLL) lim.confs, (LGLL) confs);
+
+    (void) lglisat (lgl, &lim, 0);
+    cint += lgl->opts->mocint.val;
+  }
+
+  DEL (reported, ntargets);
+
+  lglprt (lgl, 1,
+    "[mosat-%lld] solved %d targets out of %d, %d remain",
+    (LGLL) lgl->stats->calls.mosat,
+    ntargets - rtargets, ntargets, rtargets);
+
+  lglstop (lgl);
+
+  return !rtargets;
+}
+
+int lglookahead (LGL * lgl) {
+  int ilit, res;
+  REQINITNOTFORKED ();
+  TRAPI ("lkhd");
+  ABORTIF (!lglmtstk (&lgl->eassume), "imcompatible with 'lglassume'");
+  ABORTIF (!lglmtstk (&lgl->clause), "clause terminating zero missing");
+  lglstart (lgl, &lgl->times->all);
+  lglstart (lgl, &lgl->times->lkhd);
+  lgl->stats->calls.lkhd++;
+  lglreset (lgl);
+  assert (!lgl->lkhd);
+  lgl->lkhd = 1;
+  lglfreezer (lgl);
+  if (lgl->level) lglbacktrack (lgl, 0);
+  if (!lgl->mt && lglbcp (lgl)) {
+    ilit = 0;
+    if (lgl->opts->lkhdmisifelmrtc.val &&
+        lgl->opts->elim.val && lgl->elmrtc)
+      ilit = lglmislook (lgl);
+    else if (lgl->opts->lkhd.val == 2 && !lglsmallirr (lgl))
+      ilit = lgljwhlook (lgl);
+    else switch (lgl->opts->lkhd.val) {
+      case -1: ilit = lglocslook (lgl); break;
+      case 0: ilit = lglislook (lgl); break;
+      case 1: ilit = lgljwhlook (lgl); break;
+      case 2:
+       if (!lgltreelookaux (lgl, &ilit)) assert (lgl->mt);
+       break;
+      case 3:
+      default:
+        assert (lgl->opts->lkhd.val == 3);
+       ilit = lglsumlenlook (lgl);
+       break;
+    }
+    res = (!lgl->mt && ilit) ? lglexport (lgl, ilit) : 0;
+    assert (!res || !lglelit2ext (lgl, res)->melted);
+  } else lgl->mt = 1, res = 0;
+  assert (lgl->lkhd);
+  lgl->lkhd = 0;
+  lglstop (lgl);
+  lglstop (lgl);
+  TRANS (LOOKED);
+  RETURN (lglookahead, res);
+  return res;
+}
+
+int lglchanged (LGL * lgl) {
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("changed");
+  REQUIRE (EXTENDED);
+  res = lgl->changed;
+  RETURN (lglchanged, res);
+  return res;
+}
+
+int lglsimp (LGL * lgl, int iterations) {
+  Lim lim;
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("simp %d", iterations);
+  ABORTIF (iterations < 0, "negative number of simplification iterations");
+  ABORTIF (!lglmtstk (&lgl->clause), "clause terminating zero missing");
+  lglstart (lgl, &lgl->times->all);
+  lgl->stats->calls.simp++;
+  lglfreezer (lgl);
+  CLR (lim);
+  lim.decs = lgl->stats->decisions;
+  res = lglisat (lgl, &lim, iterations);
+  assert (!lgl->level);
+  lglstop (lgl);
+  RETURNARG (lglsimp, iterations, res);
+  return res;
+}
+
+int lglmaxvar (LGL * lgl) {
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("maxvar");
+  res = lgl->maxext;
+  RETURN (lglmaxvar, res);
+  return res;
+}
+
+int lglincvar (LGL  *lgl) {
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("incvar");
+  res = lgl->maxext + 1;
+  (void) lglimport (lgl, res);
+  RETURN (lglincvar, res);
+  return res;
+}
+
+int lglderef (LGL * lgl, int elit) {
+  int res;
+  REQINIT ();
+  TRAPI ("deref %d", elit);
+  lgl->stats->calls.deref++;
+  ABORTIF (!elit, "can not deref zero literal");
+  REQUIRE (SATISFIED | EXTENDED);
+  if (!(lgl->state & EXTENDED)) lglextend (lgl);
+  res = lglederef (lgl, elit);
+  RETURNARG (lglderef, elit, res);
+  return res;
+}
+
+int lglfailed (LGL * lgl, int elit) {
+  unsigned bit;
+  Ext * ext;
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("failed %d", elit);
+  lgl->stats->calls.failed++;
+  ABORTIF (!elit, "can not check zero failed literal");
+  REQUIRE (UNSATISFIED | FAILED);
+  ABORTIF (abs (elit) > lgl->maxext,
+          "can not check unimported failed literal");
+  ext = lglelit2ext (lgl, elit);
+  bit = 1u << (elit < 0);
+  ABORTIF (!(ext->assumed & bit),
+          "can not check unassumed failed literal");
+  if (!(lgl->state & FAILED)) {
+    lglstart (lgl, &lgl->times->all);
+    lglanafailed (lgl);
+    lglstop (lgl);
+  }
+  res = (ext->failed & bit) != 0;
+  RETURNARG (lglfailed, elit, res);
+  return res;
+}
+
+int lglinconsistent (LGL * lgl) {
+  int res;
+  TRAPI ("inconsistent");
+  res = (lgl->mt != 0);
+  RETURN (lglinconsistent, res);
+  return res;
+}
+
+static int lglefixed (LGL * lgl, int elit) {
+  int res, ilit;
+  assert (elit);
+  if (abs (elit) > lgl->maxext) return 0;
+  ilit = lglimport (lgl, elit);
+  if (!ilit) res = 0;
+  else if (abs (ilit) == 1) res = ilit;
+  else res = lglifixed (lgl , ilit);
+  return res;
+}
+
+int lglfixed (LGL * lgl, int elit) {
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("fixed %d", elit);
+  lgl->stats->calls.fixed++;
+  ABORTIF (!elit, "can not deref zero literal");
+  res = lglefixed (lgl, elit);
+  RETURNARG (lglfixed, elit, res);
+  return res;
+}
+
+int lglrepr (LGL * lgl, int elit) {
+  int res, eidx = abs (elit);
+  REQINITNOTFORKED ();
+  TRAPI ("repr %d", elit);
+  lgl->stats->calls.repr++;
+  if (eidx > lgl->maxext) res = elit;
+  else {
+    res = lglerepr (lgl, elit);
+    if (abs (res) <= 1) res = elit;
+  }
+  RETURNARG (lglrepr, elit, res);
+  return res;
+}
+
+void lglfreeze (LGL * lgl, int elit) {
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("freeze %d", elit);
+  lgl->stats->calls.freeze++;
+  ABORTIF (!elit, "can not freeze zero literal");
+  REQUIRE (UNUSED|OPTSET|USED|RESET|SATISFIED|UNSATISFIED|FAILED|LOOKED|
+          UNKNOWN|EXTENDED);
+  LOG (2, "freezing external literal %d", elit);
+  (void) lglimport (lgl, elit);
+  ext = lglelit2ext (lgl, elit);
+  ABORTIF (ext->melted, "freezing melted literal %d", elit);
+  assert (!ext->blocking && !ext->eliminated);
+  ABORTIF (ext->frozen == INT_MAX, "literal %d frozen too often", elit);
+  ext->frozen++;
+  if (!ext->frozen) {
+    lgl->stats->irrprgss++;
+    lglmelter (lgl);
+  }
+  if (lgl->clone) lglfreeze (lgl->clone, elit);
+}
+
+int lglfrozen (LGL * lgl, int elit) {
+  Ext * ext;
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("frozen %d", elit);
+  ABORTIF (!elit, "can not check zero literal for being frozen");
+  if (abs (elit) > lgl->maxext) res = INT_MAX;
+  else if (!(ext = lglelit2ext (lgl, elit))->imported) res = INT_MAX;
+  else res = ext->frozen;
+  RETURNARG (lglfrozen, elit, res);
+  return res;
+}
+
+int lglusable (LGL * lgl, int elit) {
+  Ext * ext;
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("usable %d", elit);
+  ABORTIF (!elit, "can not check zero literal for being usable");
+  if (abs (elit) > lgl->maxext) res = 1;
+  else if (!(ext = lglelit2ext (lgl, elit))->imported) res = 1;
+  else res = !ext->melted;
+  RETURNARG (lglusable, elit, res);
+  return res;
+}
+
+static int lglereusable (LGL * lgl, int elit) {
+  Ext * ext;
+  int res;
+  if (abs (elit) > lgl->maxext) res = 1;
+  else if (!(ext = lglelit2ext (lgl, elit))->imported) res = 1;
+  else if (ext->blocking) res = 0;
+  else if (ext->eliminated) res = 0;
+  else if (ext->equiv) res = 0;
+  else if (abs (ext->repr) == 1) res = 0;
+  else res = 1;
+  return res;
+}
+
+int lglreusable (LGL * lgl, int elit) {
+  int res;
+  REQINITNOTFORKED ();
+  TRAPI ("reusable %d", elit);
+  ABORTIF (!elit, "can not check zero literal for being reusable");
+  res = lglereusable (lgl, elit);
+  RETURNARG (lglreusable, elit, res);
+  return res;
+}
+
+void lglreuse (LGL * lgl, int elit) {
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("reuse %d", elit);
+  ABORTIF (!elit, "can not reuse zero literal");
+  ABORTIF (!lglereusable (lgl, elit), "can not reuse non-reusable literal");
+  if (abs (elit) <= lgl->maxext) {
+    ext = lglelit2ext (lgl, elit);
+    if (ext->imported) {
+      assert (!ext->blocking);
+      assert (!ext->eliminated);
+      if (ext->melted) {
+       LOG (2,
+         "forced permanently melted external %d to be reused",
+         elit);
+       ext->melted = 0;
+       lglmelter (lgl);
+      }
+    }
+  }
+  if (lgl->clone) lglreuse (lgl->clone, elit);
+}
+
+void lglmeltall (LGL * lgl) {
+  int idx, melted;
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("meltall");
+  melted = 0;
+  for (idx = 1; idx <= lgl->maxext; idx++) {
+    ext = lglelit2ext (lgl, idx);
+    ext->melted = 0;
+    if (!ext->frozen) continue;
+    lgl->stats->irrprgss++;
+    ext->frozen = 0;
+    melted++;
+  }
+  lglprt (lgl, 1, "[meltall] melted %d frozen literals", melted);
+  lglmelter (lgl);
+  if (lgl->clone) lglmeltall (lgl->clone);
+}
+
+void lglmelt (LGL * lgl, int elit) {
+  Ext * ext;
+  REQINITNOTFORKED ();
+  TRAPI ("melt %d", elit);
+  lgl->stats->calls.melt++;
+  ABORTIF (!elit, "can not melt zero literal");
+  REQUIRE (UNUSED|OPTSET|USED|RESET|
+          SATISFIED|UNSATISFIED|FAILED|UNKNOWN|LOOKED|
+          EXTENDED);
+  LOG (2, "melting external literal %d", elit);
+  (void) lglimport (lgl, elit);
+  ext = lglelit2ext (lgl, elit);
+  ABORTIF (!ext->frozen, "can not melt fully unfrozen literal %d", elit);
+  assert (!ext->blocking && !ext->eliminated);
+  ext->frozen--;
+  lglmelter (lgl);     // TODO guard  by !ext->frozen?
+  if (lgl->clone) lglmelt (lgl->clone, elit);
+}
+
+void lglreconstk (LGL * lgl, int ** startptr, int ** toptr) {
+  REQINITNOTFORKED ();
+  TRAPI ("reconstk");
+  lglfitstk (lgl, &lgl->extend);       // 'lglcompact' -> 'lglclone'!!
+  if (startptr) *startptr = lgl->extend.start;
+  if (toptr) *toptr = lgl->extend.top;
+  if (lgl->clone) lglreconstk (lgl->clone, 0, 0);
+}
+
+static void lglprstart (LGL * lgl) {
+  assert (lgl->prefix);
+  fputs (lgl->prefix, lgl->out);
+  if (lgl->tid >= 0) fprintf (lgl->out, "%d ", lgl->tid);
+}
+
+static void lglprs (LGL * lgl, const char * fmt, ...) {
+  va_list ap;
+  lglprstart (lgl);
+  va_start (ap, fmt);
+  vfprintf (lgl->out, fmt, ap);
+  va_end (ap);
+  fputc ('\n', lgl->out);
+}
+
+static void lglprsline (LGL * lgl) {
+  lglprstart (lgl);
+  fputc ('\n', lgl->out);
+}
+
+static double lglsqr (double a) { return a*a; }
+
+static void lglgluestats (LGL * lgl) {
+  int64_t added, reduced, forcing, resolved, conflicts;
+  int64_t wadded, wreduced, wforcing, wresolved, wconflicts;
+  int64_t avgadded, avgreduced, avgforcing, avgresolved, avgconflicts;
+  double madded, mreduced, mforcing, mresolved, mconflicts;
+  double vadded, vreduced, vforcing, vresolved, vconflicts;
+  double sadded, sreduced, sforcing, sresolved, sconflicts;
+  Stats * s = lgl->stats;
+  int glue;
+  lglprs (lgl,
+    "scaledglue%7s %3s %9s %3s %9s %3s %9s %3s %9s",
+    "added","", "reduced","", "forcing","", "resolved","", "conflicts");
+  added = reduced = forcing = resolved = conflicts = 0;
+  wadded = wreduced = wforcing = wresolved = wconflicts = 0;
+  for (glue = 0; glue <= MAXGLUE; glue++) {
+    added += s->lir[glue].added;
+    reduced += s->lir[glue].reduced;
+    forcing += s->lir[glue].forcing;
+    resolved += s->lir[glue].resolved;
+    conflicts += s->lir[glue].conflicts;
+    wadded += glue*s->lir[glue].added;
+    wreduced += glue*s->lir[glue].reduced;
+    wforcing += glue*s->lir[glue].forcing;
+    wresolved += glue*s->lir[glue].resolved;
+    wconflicts += glue*s->lir[glue].conflicts;
+  }
+  avgadded = added ? (((10*wadded)/added+5)/10) : 0;
+  avgreduced = reduced ? (((10*wreduced)/reduced+5)/10) : 0;
+  avgforcing = forcing ? (((10*wforcing)/forcing+5)/10) : 0;
+  avgresolved = resolved ? (((10*wresolved)/resolved+5)/10) : 0;
+  avgconflicts = conflicts ? (((10*wconflicts)/conflicts+5)/10) : 0;
+  lglprsline (lgl);
+  lglprs (lgl,
+    "all %9lld %3.0f %9lld %3.0f %9lld %3.0f %9lld %3.0f %9lld %3.0f",
+     (LGLL) added, 100.0,
+     (LGLL) reduced, 100.0,
+     (LGLL) forcing, 100.0,
+     (LGLL) resolved, 100.0,
+     (LGLL) conflicts, 100.0);
+  lglprsline (lgl);
+  for (glue = 0; glue <= MAXGLUE; glue++) {
+    lglprs (lgl,
+      "%2d  %9lld %3.0f%c%9lld %3.0f%c%9lld %3.0f%c%9lld %3.0f%c%9lld %3.0f%c",
+      glue,
+      (LGLL) s->lir[glue].added,
+       lglpcnt (s->lir[glue].added, added),
+       (glue == avgadded) ? '<' : ' ',
+      (LGLL) s->lir[glue].reduced,
+       lglpcnt (s->lir[glue].reduced, reduced),
+       (glue == avgreduced) ? '<' : ' ',
+      (LGLL) s->lir[glue].forcing,
+       lglpcnt (s->lir[glue].forcing, forcing),
+       (glue == avgforcing) ? '<' : ' ',
+      (LGLL) s->lir[glue].resolved,
+       lglpcnt (s->lir[glue].resolved, resolved),
+       (glue == avgresolved) ? '<' : ' ',
+      (LGLL) s->lir[glue].conflicts,
+       lglpcnt (s->lir[glue].conflicts, conflicts),
+       (glue == avgconflicts) ? '<' : ' ');
+  }
+  lglprsline (lgl);
+
+  madded = lglavg (wadded, added),
+  mreduced = lglavg (wreduced, reduced),
+  mforcing = lglavg (wforcing, forcing),
+  mresolved = lglavg (wresolved, resolved),
+  mconflicts = lglavg (wconflicts, conflicts);
+
+  lglprs (lgl,
+    "avg  %14.1f%14.1f%14.1f%14.1f%14.1f",
+     madded, mreduced, mforcing, mresolved, mconflicts);
+
+  vadded = vreduced = vforcing = vresolved = vconflicts = 0;
+  for (glue = 0; glue <= MAXGLUE; glue++) {
+    vadded += s->lir[glue].added * lglsqr (glue - madded);
+    vreduced += s->lir[glue].reduced * lglsqr (glue - mreduced);
+    vforcing += s->lir[glue].forcing * lglsqr (glue - mforcing);
+    vresolved += s->lir[glue].resolved * lglsqr (glue - mresolved);
+    vconflicts += s->lir[glue].conflicts * lglsqr (glue - mconflicts);
+  }
+  sadded = sqrt (lglavg (vadded, added));
+  sreduced = sqrt (lglavg (vreduced, reduced));
+  sforcing = sqrt (lglavg (vforcing, forcing));
+  sresolved = sqrt (lglavg (vresolved, resolved));
+  sconflicts = sqrt (lglavg (vconflicts, conflicts));
+
+  lglprs (lgl,
+    "std  %14.1f%14.1f%14.1f%14.1f%14.1f",
+     sadded, sreduced, sforcing, sresolved, sconflicts);
+}
+
+typedef struct TN { double t; const char * n; } TN;
+
+static int lglcmptn (const TN * a, const TN * b) {
+  if (a->t > b->t) return -1;
+  if (a->t < b->t) return 1;
+  return strcmp (a->n, b->n);
+}
+
+#define INSTN(NAME,FIELD) \
+do { \
+  TN * tn = tns + ntns++; \
+  assert (ntns <= sztns); \
+  tn->t = ts->FIELD; \
+  tn->n = #NAME; \
+} while (0)
+
+static void lglprofsort (LGL * lgl) {
+  Times * ts = lgl->times;
+  const int sztns = 31;
+  int i, ntns = 0;
+  TN tns[sztns];
+
+  INSTN (analysis, ana);
+  INSTN (backward, bkwd);
+  INSTN (bca, bca);
+  INSTN (block, blk);
+  INSTN (bump, bump);
+  INSTN (bva, bva);
+  INSTN (card, card);
+  INSTN (cce, cce);
+  INSTN (cgrclsr, cgr);
+  INSTN (cliff, cliff);
+  INSTN (cutwidth, ctw);
+  INSTN (decide, dec);
+  INSTN (decomp, dcp);
+  INSTN (defrag, dfg );
+  INSTN (elim, elm);
+  INSTN (force, force);
+  INSTN (gauss, gauss);
+  INSTN (gc, gc);
+  INSTN (lift, lft);
+  INSTN (locs, locs);
+  INSTN (mega, mega);
+  INSTN (mincls, mcls);
+  INSTN (phase, phs);
+  INSTN (probe, prb.all);
+  INSTN (rdp, rdp);
+  INSTN (reduce, red );
+  INSTN (restart, rsts);
+  INSTN (tabularasa, tabr);
+  INSTN (ternres, trn);
+  INSTN (transred, trd);
+  INSTN (unhide, unhd);
+
+  assert (ntns == sztns);
+
+  // Force insertion sort to avoid implicit memory allocation!
+  // Otherwise an already existing memory corruption will trigger
+  // another signal and thus might result in non-termination.
+
+  ISORT (TN, lglcmptn, tns, ntns);
+
+  for (i = 0; i < ntns; i++)
+    lglprs (lgl, "%8.3f %3.0f%% %s",
+      tns[i].t, lglpcnt (tns[i].t, ts->all), tns[i].n);
+}
+
+static void lglprof (LGL * lgl) {
+  Times * ts = lgl->times;
+  double t = ts->all, simp, search;
+
+  assert (lgl->opts->verbose.val >= 0);
+  simp = ts->prep + ts->inpr;
+  if (!lgl->opts->verbose.val) goto SHORT;
+
+  lglprofsort (lgl);
+
+  lglprs (lgl, "----------------------------------");
+  lglprs (lgl, "%8.3f %3.0f%% probe simple    %3.0f%%",
+    ts->prb.simple,
+    lglpcnt (ts->prb.simple, t),
+    lglpcnt (ts->prb.simple, ts->prb.all));
+  lglprs (lgl, "%8.3f %3.0f%% probe basic     %3.0f%%",
+    ts->prb.basic,
+    lglpcnt (ts->prb.basic, t),
+    lglpcnt (ts->prb.basic, ts->prb.all));
+  lglprs (lgl, "%8.3f %3.0f%% probe tree-look %3.0f%%",
+    ts->prb.treelook,
+    lglpcnt (ts->prb.treelook, t),
+    lglpcnt (ts->prb.treelook, ts->prb.all));
+  lglprs (lgl, "==================================");
+  lglprs (lgl, "%8.3f %3.0f%% preprocessing   %3.0f%%",
+    ts->prep,
+    lglpcnt (ts->prep, t),
+    lglpcnt (ts->prep, simp));
+  lglprs (lgl, "%8.3f %3.0f%% inprocessing    %3.0f%%",
+    ts->inpr,
+    lglpcnt (ts->inpr, t),
+    lglpcnt (ts->inpr, simp));
+  lglprs (lgl, "==================================");
+SHORT:
+  lglprs (lgl, "%8.3f %3.0f%% simplifying", simp, lglpcnt (simp, t));
+  if (lgl->stats->calls.lkhd)
+    lglprs (lgl, "%8.3f %3.0f%% lookahead", ts->lkhd, lglpcnt (ts->lkhd, t));
+  search = ts->srch - ts->inpr;
+  lglprs (lgl, "%8.3f %3.0f%% search", search, lglpcnt (search, t));
+  lglprs (lgl, "==================================");
+  lglprs (lgl, "%8.3f %3.0f%% all", t, 100.0);
+}
+
+void lglstats (LGL * lgl) {
+  long long visits, travs, min, p, steps;
+  int remaining, removed, sum;
+  Stats * s;
+  double t;
+  REQINITNOTFORKED ();
+  if (lgl->opts->verbose.val < 0) return;
+  s = lgl->stats;
+  t = lgl->times->all;
+  p = s->props.search + s->props.simp + s->props.lkhd;
+  if (!lgl->opts->verbose.val) goto SHORT;
+  sum = s->prb.basic.ate.trnr + s->prb.basic.ate.lrg;
+  lglprs (lgl, 
+    "bate: %d basic ate = %d trn %.0f%% + %d lrg %.0f%% in %d updates",
+    sum, s->prb.basic.ate.trnr, lglpcnt (s->prb.basic.ate.trnr, sum),
+    s->prb.basic.ate.lrg, lglpcnt (s->prb.basic.ate.lrg, sum),
+    s->prb.basic.ate.count);
+
+  lglprs (lgl,
+    "bcas: %d count, %lld added (%lld skipped), %lld steps",
+    s->bca.count, (LGLL) s->bca.added, s->bca.skipped, (LGLL) s->bca.steps);
+
+  lglprs (lgl,
+    "bkwd: tried %lld clauses, %lld lits, %.2f lits/clause",
+    (LGLL) s->bkwd.tried.clauses, (LGLL) s->bkwd.tried.lits,
+    lglavg (s->bkwd.tried.lits, s->bkwd.tried.clauses));
+  lglprs (lgl,
+    "bkwd: checked %lld occs, %.2f occs/clause, %.2f occs/lit",
+    (LGLL) s->bkwd.tried.occs,
+    lglavg (s->bkwd.tried.occs, s->bkwd.tried.clauses),
+    lglavg (s->bkwd.tried.occs, s->bkwd.tried.lits));
+  lglprs (lgl,
+    "bkwd: subsumed %d binary, %d ternary, %d large",
+    s->bkwd.sub2, s->bkwd.sub3, s->bkwd.subl);
+  lglprs (lgl,
+    "bkwd: strengthened %d binary, "
+    "%d ternary (%.0f%% self), %d large (%.0f%% self)",
+    s->bkwd.str2,
+    s->bkwd.str3, lglpcnt (s->bkwd.str3self, s->bkwd.str3),
+    s->bkwd.strl, lglpcnt (s->bkwd.strlself, s->bkwd.strl));
+
+  lglprs (lgl,
+    "blkd: %d bces, %d removed, %lld resolutions, %lld steps",
+    s->blk.count, s->blk.clauses, (LGLL) s->blk.res, (LGLL) s->blk.steps);
+  lglprs (lgl,
+    "blkd: %d blocking literals %.0f%%, %d pure",
+    s->blk.lits, lglpcnt (s->blk.lits, 2*lgl->maxext), s->blk.pure);
+
+  lglprs (lgl,
+    "bvas: %d bvas, %d added, %d removed",
+    s->bva.count, s->bva.added, s->bva.removed);
+
+  lglprs (lgl,
+    "card: %d count, %d units, %d am1, %lld steps",
+    s->card.count, s->card.units, s->card.expam1, (LGLL) s->card.steps);
+  lglprs (lgl,
+    "card: %d rescheduled, %lld eliminated, %lld resolved, %lld subsumed",
+    s->card.resched, (LGLL) s->card.eliminated,
+    (LGLL) s->card.resolved, (LGLL) s->card.subsumed);
+  lglprs (lgl,
+    "card: %d at-most-one constraints found, average size %.2f",
+    s->card.am1.found.cnt,
+    lglavg (s->card.am1.found.sum, s->card.am1.found.cnt));
+  lglprs (lgl,
+    "card: %d at-most-one constraints used %.0f%%, average size %.2f",
+    s->card.am1.used.cnt,
+    lglpcnt (s->card.am1.used.cnt, s->card.am1.found.cnt),
+    lglavg (s->card.am1.used.sum, s->card.am1.used.cnt));
+  lglprs (lgl,
+    "card: %d at-most-two constraints found, average size %.2f",
+    s->card.am2.found.cnt,
+    lglavg (s->card.am2.found.sum, s->card.am2.found.cnt));
+  lglprs (lgl,
+    "card: %d at-most-two constraints used %.0f%%, average size %.2f",
+    s->card.am2.used.cnt,
+    lglpcnt (s->card.am2.used.cnt, s->card.am2.found.cnt),
+    lglavg (s->card.am2.used.sum, s->card.am2.used.cnt));
+
+  lglprs (lgl,
+    "cces: %d cces, %d eliminated, %d ate %.0f%%, %d abce %.0f%%",
+    s->cce.count, s->cce.eliminated,
+    s->cce.ate, lglpcnt (s->cce.ate, s->cce.eliminated),
+    s->cce.abce, lglpcnt (s->cce.abce, s->cce.eliminated));
+  lglprs (lgl,
+    "cces: %lld probed, %d lifted, %d failed",
+    (LGLL) s->cce.probed, s->cce.lifted, s->cce.failed);
+  lglprs (lgl,
+    "cces: %lld cached, %lld rsz, %lld cols %.0f%%, "
+    "%lld srch, %lld hits %.0f%%",
+    (LGLL) s->cce.cache.ins,
+    (LGLL) s->cce.cache.rsz,
+    (LGLL) s->cce.cache.cols,
+      lglpcnt (s->cce.cache.cols, s->cce.cache.ins),
+    (LGLL) s->cce.cache.search,
+    (LGLL) s->cce.cache.hits,
+      lglpcnt (s->cce.cache.hits, s->cce.cache.search));
+
+  lglprs (lgl,
+    "cgrs: %d count, %lld esteps, %lld csteps",
+    s->cgr.count, (LGLL) s->cgr.esteps, (LGLL) s->cgr.csteps);
+  lglprs (lgl,
+    "cgrs: %d eqs, %d units", s->cgr.eq, s->cgr.units);
+  lglprs (lgl,
+    "cgrs: %d matched (%d ands %.0f%%, %d xors %.0f%%, %d ites %.0f%%)",
+    s->cgr.matched.all,
+    s->cgr.matched.and, lglpcnt (s->cgr.matched.and, s->cgr.matched.all),
+    s->cgr.matched.xor, lglpcnt (s->cgr.matched.xor, s->cgr.matched.all),
+    s->cgr.matched.ite, lglpcnt (s->cgr.matched.ite, s->cgr.matched.all));
+  lglprs (lgl,
+    "cgrs: %d simplified (%d ands %.0f%%, %d xors %.0f%%, %d ites %.0f%%)",
+    s->cgr.simplified.all,
+    s->cgr.simplified.and,
+      lglpcnt (s->cgr.simplified.and, s->cgr.simplified.all),
+    s->cgr.simplified.xor,
+     lglpcnt (s->cgr.simplified.xor, s->cgr.simplified.all),
+    s->cgr.simplified.ite,
+     lglpcnt (s->cgr.simplified.ite, s->cgr.simplified.all));
+  lglprs (lgl,
+    "cgrs: %lld extracted "
+    "(%lld ands %.0f%%, %lld xors %.0f%%, %lld ites %.0f%%)",
+    (LGLL)s->cgr.extracted.all,
+    (LGLL)s->cgr.extracted.and,
+      lglpcnt (s->cgr.extracted.and, s->cgr.extracted.all),
+    (LGLL)s->cgr.extracted.xor,
+      lglpcnt (s->cgr.extracted.xor, s->cgr.extracted.all),
+    (LGLL)s->cgr.extracted.ite,
+       lglpcnt (s->cgr.extracted.ite, s->cgr.extracted.all));
+
+  lglprs (lgl,
+    "clff: %d cliffs, %d lifted, %d failed",
+    s->cliff.count, s->cliff.lifted, s->cliff.failed);
+  lglprs (lgl,
+    "clff: %lld decisions, %lld steps",
+    (LGLL) s->cliff.decisions, (LGLL) s->cliff.steps);
+
+  lglprs (lgl,
+    "clls: %lld sat, %lld simp, %lld freeze, %lld melt",
+    (LGLL) s->calls.sat, (LGLL) s->calls.simp,
+    (LGLL) s->calls.freeze, (LGLL) s->calls.melt);
+  lglprs (lgl,
+    "clls: %lld add, %lld assume, %lld deref, %lld failed",
+    (LGLL) s->calls.add, (LGLL) s->calls.assume,
+    (LGLL) s->calls.deref, (LGLL) s->calls.failed);
+  lglprs (lgl,
+    "clls: %lld lkhd, %lld cassume, %lld mosat",
+    (LGLL) s->calls.lkhd, (LGLL) s->calls.cassume, (LGLL) s->calls.mosat);
+
+  lglprs (lgl,
+    "coll: %d gcs, %d rescored clauses, %d rescored vars",
+    s->gcs, s->rescored.clauses, s->rescored.vars);
+
+  lglprs (lgl,
+    "dcps: %d decompositions, %d equivalent %.0f%%",
+         s->decomps, s->equiv.sum, lglpcnt (s->equiv.sum, lgl->maxext));
+
+  lglprs (lgl,
+    "deco: %lld decision-only clauses %.0f%%, %.0f%% reduction",
+    s->mincls.deco, lglpcnt (s->mincls.deco, s->clauses.learned),
+    lglpcnt (s->deco.sum.orig - s->deco.sum.red, s->deco.sum.orig)); 
+
+  lglprs (lgl,
+    "decs: %lld decision, %lld random %.3f%%, %lld flipped %.3f%%",
+    (LGLL) s->decisions,
+    (LGLL) s->randecs, lglpcnt (s->randecs, s->decisions),
+    (LGLL) s->randecsflipped, lglpcnt (s->randecsflipped, s->randecs));
+  lglprs (lgl,
+    "decs: %lld flipped %.3f%% (in %lld phases)",
+    (LGLL) s->flipped, lglpcnt (s->flipped, s->decisions),
+    (LGLL) s->fliphases);
+
+  lglprs (lgl,
+    "elms: %d elims, %d eliminated %.0f%%",
+     s->elm.count, s->elm.elmd, lglpcnt (s->elm.elmd, lgl->maxext));
+  lglprs (lgl,
+    "elms: %d rounds, %.1f rounds/bve",
+    s->elm.rounds, lglavg (s->elm.rounds, s->elm.count));
+  lglprs (lgl,
+    "elms: %d small %.0f%%, %d large %.0f%%",
+    s->elm.small.elm, lglpcnt (s->elm.small.elm, s->elm.elmd),
+    s->elm.large, lglpcnt (s->elm.large, s->elm.elmd));
+  lglprs (lgl,
+    "elms: %d tried small, %d succeeded %.0f%%, %d failed %.0f%%",
+    s->elm.small.tried, s->elm.small.tried - s->elm.small.failed,
+      lglpcnt (s->elm.small.tried - s->elm.small.failed, s->elm.small.tried),
+    s->elm.small.failed,
+      lglpcnt (s->elm.small.failed, s->elm.small.tried));
+  lglprs (lgl,
+    "elms: %d subsumed, %d strengthened, %d blocked",
+    s->elm.sub, s->elm.str, s->elm.blkd);
+  lglprs (lgl,
+    "elms: %lld copies, %lld resolutions, %lld ipos",
+    (LGLL) s->elm.copies, (LGLL) s->elm.resolutions, (LGLL) s->elm.ipos);
+  lglprs (lgl,
+    "elms: %lld subchks, %lld strchks",
+    (LGLL) s->elm.subchks, (LGLL) s->elm.strchks);
+
+  lglprs (lgl,
+    "frcs: %lld computed, %d - %d average min-cut range",
+    (LGLL) s->force.count, s->force.mincut.min, s->force.mincut.max);
+
+  lglprs (lgl,
+    "gaus: %lld extractions, %lld extracted, %.1f size, %d max",
+    s->gauss.count, s->gauss.extracted,
+    lglavg (s->gauss.arity.sum, s->gauss.extracted), s->gauss.arity.max);
+  lglprs (lgl,
+    "gaus: exported %d units, %d binary and %d ternary equations",
+    s->gauss.units, s->gauss.equivs, s->gauss.trneqs);
+  steps = s->gauss.steps.extr + s->gauss.steps.extr;
+  lglprs (lgl,
+    "gaus: %d gc, %lld steps, %lld extr %.0f%%, %lld elim %.0f%%",
+    s->gauss.gcs, (LGLL) steps,
+    s->gauss.steps.extr, lglpcnt (s->gauss.steps.extr, steps),
+    s->gauss.steps.elim, lglpcnt (s->gauss.steps.elim, steps));
+
+  lglprs (lgl,
+    "glue: %.1f orig avg, %.1f real avg, %.1f scaled avg",
+    lglavg (s->clauses.glue, s->clauses.learned),
+    lglavg (s->clauses.realglue, s->clauses.learned),
+    lglavg (s->clauses.scglue, s->clauses.learned));
+  lglprs (lgl,
+    "glue: %lld maxscaledglue=%d (%.0f%%)",
+    (LGLL) s->clauses.maxglue, MAXGLUE,
+    lglpcnt (s->clauses.maxglue, s->clauses.learned));
+
+  lglprs (lgl,
+    "hbrs: %d = %d simple + %d trn %.0f%% + %d lrg %.0f%%, %d sub %.0f%%",
+    s->hbr.cnt,
+    s->hbr.simple, lglpcnt (s->hbr.simple, s->hbr.cnt),
+    s->hbr.trn, lglpcnt (s->hbr.trn, s->hbr.cnt),
+    s->hbr.lrg, lglpcnt (s->hbr.lrg, s->hbr.cnt),
+    s->hbr.sub, lglpcnt (s->hbr.sub, s->hbr.cnt));
+
+  lglprs (lgl,
+    "hght: %.0f average, %.2f height/glue",
+    lglheight (lgl), lglavg (lglheight (lgl), lglglue (lgl)));
+
+  lglprs (lgl,
+    "ints: %lld luby (%lld steps), %lld inout (%lld steps)",
+    (LGLL) s->luby.count, (LGLL) s->luby.steps,
+    (LGLL) s->inout.count, (LGLL) s->inout.steps);
+
+  sum = s->lift.probed0 + s->lift.probed1;
+  lglprs (lgl,
+    "lift: %d phases, %d probed (%lld level1 %.0f%%, %lld level2 %.0f%%)",
+    s->lift.count, sum,
+    (LGLL) s->lift.probed0, lglpcnt (s->lift.probed0, sum),
+    (LGLL) s->lift.probed1, lglpcnt (s->lift.probed1, sum));
+  lglprs (lgl,
+    "lift: %d units, %d equivalences, %d implications",
+    s->lift.units, s->lift.eqs, s->lift.impls);
+
+  lglprs (lgl,
+    "locs: %d count, %lld flips, %lld mems, %d minimun",
+    s->locs.count, (LGLL) s->locs.flips, (LGLL) s->locs.mems, s->locs.min);
+
+  lglprs (lgl,
+    "lrnd: %lld clauses, %.1f length",
+    (LGLL) s->clauses.learned,
+    lglavg (s->lits.learned, s->clauses.learned));
+  lglprs (lgl,
+    "lrnd: %lld uips %.0f%%, %lld flips %.0f%%",
+    (LGLL) s->uips, lglpcnt (s->uips, s->clauses.learned),
+    (LGLL) s->decflipped, lglpcnt (s->decflipped, s->clauses.learned));
+
+  lglprs (lgl,
+    "mega: %d count, %d failed, %d rounds",
+    s->mega.count, s->mega.failed, s->mega.rounds);
+
+  assert (s->lits.nonmin >= s->lits.learned);
+  min = s->lits.nonmin - s->lits.learned;
+  sum = s->moved.bin + s->moved.trn + s->moved.lrg;
+  lglprs (lgl,
+    "mins: %lld learned lits, %.0f%% minimized",
+    (LGLL) s->lits.learned, lglpcnt (min, s->lits.nonmin));
+
+  sum = s->mincls.min + s->mincls.bin + s->mincls.size + s->mincls.deco;
+  lglprs (lgl,
+    "mins: %lld mins %.0f%%, %lld bin %.0f%%, "
+    "%lld size %.0f%%, %lld deco %.0f%%",
+    (LGLL) s->mincls.min, lglpcnt (s->mincls.min, sum),
+    (LGLL) s->mincls.bin, lglpcnt (s->mincls.bin, sum),
+    (LGLL) s->mincls.size, lglpcnt (s->mincls.size, sum),
+    (LGLL) s->mincls.deco, lglpcnt (s->mincls.deco, sum));
+
+  lglprs (lgl,
+    "move: moved %lld, %lld bin %.0f%%, %lld trn %.0f%%, %lld lrg %.0f%%",
+    sum,
+    (LGLL) s->moved.bin, lglpcnt (s->moved.bin, sum),
+    (LGLL) s->moved.trn, lglpcnt (s->moved.trn, sum),
+    (LGLL) s->moved.lrg, lglpcnt (s->moved.lrg, sum));
+
+  sum = s->otfs.str.dyn.red + s->otfs.str.dyn.irr;
+  lglprs (lgl,
+    "otfs: str %d dyn (%d red, %d irr) %lld drv %.0f%%, %lld rst %.0f%%",
+    sum,
+    s->otfs.str.dyn.red, s->otfs.str.dyn.irr,
+    (LGLL) s->otfs.driving, lglpcnt (s->otfs.driving, sum),
+    (LGLL) s->otfs.restarting, lglpcnt (s->otfs.restarting, sum));
+  lglprs (lgl,
+    "otfs: sub %d dyn (%d red, %d irr)",
+    s->otfs.sub.dyn.red + s->otfs.sub.dyn.irr,
+    s->otfs.sub.dyn.red, s->otfs.sub.dyn.irr);
+
+  lglprs (lgl,
+    "phas: %lld computed, %lld set, %lld pos (%.0f%%), %lld neg (%.0f%%)",
+    (LGLL) s->phase.count, (LGLL) s->phase.set,
+    (LGLL) s->phase.pos, lglpcnt (s->phase.pos, s->phase.set),
+    (LGLL) s->phase.neg, lglpcnt (s->phase.neg, s->phase.set));
+
+  lglprs (lgl,
+    "prbs: %d basic, %lld probed, %d failed, %d lifted",
+    s->prb.basic.count, (LGLL) s->prb.basic.probed,
+    s->prb.basic.failed, s->prb.basic.lifted);
+  lglprs (lgl,
+    "prbs: %d simple, %lld probed, %d failed, %d eqs",
+    s->prb.simple.count, (LGLL) s->prb.simple.probed,
+    s->prb.simple.failed, s->prb.simple.eqs);
+  lglprs (lgl,
+    "prbs: %d treelook, %lld probed, %d failed, %d lifted",
+    s->prb.treelook.count, (LGLL) s->prb.treelook.probed,
+    s->prb.treelook.failed, s->prb.treelook.lifted);
+
+  lglprs (lgl,
+    "prps: %lld props, %.0f props/dec",
+    (LGLL) p, lglavg (s->props.search, s->decisions));
+  lglprs (lgl,
+    "prps: %.0f%% srch, %.0f%% simp, %.0f%% lkhd",
+    lglpcnt (s->props.search, p), lglpcnt (s->props.simp, p),
+    lglpcnt (s->props.lkhd, p));
+
+  lglprs (lgl,
+    "psns: %lld searches, %lld hits, %.0f%% hit rate",
+    (LGLL) s->poison.search, (LGLL) s->poison.hits,
+    lglpcnt (s->poison.hits, s->poison.search));
+
+  lglprs (lgl,
+    "rdps: %d count, %d units, %d bin, %d trn, %lld steps",
+    s->rdp.count, s->rdp.units, s->rdp.bin, s->rdp.trn, (LGLL) s->rdp.steps);
+  lglprs (lgl,
+    "rdps: %lld partial eliminations, %lld bounded %.0f%%",
+    (LGLL) s->rdp.elim, (LGLL) s->rdp.limhit.bound, 
+    lglpcnt (s->rdp.limhit.bound, s->rdp.elim));
+  lglprs (lgl,
+    "rdps: %lld resolutions, %lld size %.0f%%, %lld model %.0f%%",
+    (LGLL) s->rdp.res,
+    (LGLL) s->rdp.limhit.len, lglpcnt (s->rdp.limhit.len, s->rdp.res),
+    (LGLL) s->rdp.limhit.model, lglpcnt (s->rdp.limhit.model, s->rdp.res));
+
+  lglprs (lgl,
+    "reds: %d count, %d reset, %d acts %.0f%%",
+    s->reduced.count, s->reduced.reset,
+    s->acts, lglpcnt (s->acts, s->reduced.count));
+  lglprs (lgl,
+    "reds: %d geom %.0f%%, %d glue useless %.0f%%",
+    s->reduced.geom, lglpcnt (s->reduced.geom, s->reduced.count),
+    s->reduced.gul, lglpcnt (s->reduced.gul, s->reduced.count));
+  lglprs (lgl,
+    "reds: %d memlim %.0f%%, %d arith %.0f%%, %d double %.0f%%",
+    s->reduced.memlim, lglpcnt (s->reduced.memlim, s->reduced.count),
+    s->reduced.arith, lglpcnt (s->reduced.arith, s->reduced.count),
+    s->reduced.arith2, lglpcnt (s->reduced.arith2, s->reduced.arith));
+
+  lglprs (lgl,
+    "rmbd: %d removed, %d red %.0f%%",
+    s->bindup.removed, s->bindup.red,
+    lglpcnt (s->bindup.red, s->bindup.removed));
+
+  lglprs (lgl,
+    "rphs: %d recomputed phases",
+    s->rephase.count);
+
+  sum = s->restarts.count + s->restarts.skipped.count;
+  lglprs (lgl,
+    "rsts: %d restarts %.0f%%, %d skipped %.0f%%",
+    s->restarts.count, lglpcnt (s->restarts.count, sum),
+    s->restarts.skipped.count, lglpcnt (s->restarts.skipped.count, sum));
+  lglprs (lgl,
+    "rsts: %d saturating %.0f%%, %d agile %.0f%%, %d reuse %.0f%%",
+    s->restarts.skipped.saturating,
+      lglpcnt (s->restarts.skipped.saturating, s->restarts.skipped.count),
+    s->restarts.skipped.agile,
+      lglpcnt (s->restarts.skipped.agile, s->restarts.skipped.count),
+    s->restarts.skipped.reuse,
+      lglpcnt (s->restarts.skipped.reuse, s->restarts.skipped.count));
+  lglprs (lgl,
+    "rsts: %.1f avg interval, %.1f scaled, %.1f factor",
+    lglavg (s->restarts.intsum.orig, s->restarts.count),
+    lglavg (s->restarts.intsum.scaled, s->restarts.count),
+    lglavg (s->restarts.intsum.orig, s->restarts.intsum.scaled));
+  lglprs (lgl,
+    "rsts: %d kept %.1f%% average %.1f%%",
+    s->restarts.kept.count,
+    lglpcnt (s->restarts.kept.count, s->restarts.count),
+    lglavg (s->restarts.kept.sum, s->restarts.kept.count));
+
+  lglprs (lgl,
+    "simp: %d count (%d confs %0.f%%, %d irr %.0f%%, %d vars %.0f%%)",
+    s->simp.count,
+    s->simp.limhit.confs, lglpcnt (s->simp.limhit.confs, s->simp.count),
+    s->simp.limhit.irr, lglpcnt (s->simp.limhit.irr, s->simp.count),
+    s->simp.limhit.vars, lglpcnt (s->simp.limhit.vars, s->simp.count));
+
+  lglprs (lgl,
+    "subl: %lld count (%lld tried %.1f), %lld sub out of %lld (%.1f%%)",
+    s->subl.count, s->subl.tried, lglavg (s->subl.tried, s->subl.count),
+    s->subl.sub, s->subl.cands, lglpcnt (s->subl.sub, s->subl.cands));
+
+  lglprs (lgl,
+    "sync: %lld produced units, %lld successful consumptions %.0f%%",
+    s->sync.units.produced, s->sync.units.consumed.actual,
+    lglpcnt (s->sync.units.consumed.actual, s->sync.units.produced));
+  lglprs (lgl,
+    "sync: %lld consume units calls, %lld tried %.0f%%, %lld success %.0f%%",
+    s->sync.units.consumed.calls,
+    s->sync.units.consumed.tried,
+    lglpcnt (s->sync.units.consumed.tried, s->sync.units.consumed.calls),
+    s->sync.units.consumed.actual,
+    lglpcnt (s->sync.units.consumed.actual, s->sync.units.consumed.calls));
+  lglprs (lgl,
+    "sync: %lld produced clauses, %lld successful consumptions %.0f%%",
+    s->sync.cls.produced, s->sync.cls.consumed.actual,
+    lglpcnt (s->sync.cls.consumed.actual, s->sync.cls.produced));
+  lglprs (lgl,
+    "sync: %lld consume clause calls, %lld tried %.0f%%, %lld success %.0f%%",
+    s->sync.cls.consumed.calls,
+    s->sync.cls.consumed.tried,
+    lglpcnt (s->sync.cls.consumed.tried, s->sync.cls.consumed.calls),
+    s->sync.cls.consumed.actual,
+    lglpcnt (s->sync.cls.consumed.actual, s->sync.cls.consumed.calls));
+
+  lglprs (lgl, "tabr: %d count", s->tabr.count);
+
+  lglprs (lgl,
+    "tops: %d fixed %.0f%%, %d its, %.2f confs/it",
+    s->fixed.sum, lglpcnt (s->fixed.sum, lgl->maxext), 
+    s->iterations, lglavg (s->confs, s->iterations));
+
+  travs = s->travs.search + s->visits.simp + s->visits.lkhd;
+  lglprs (lgl,
+    "trvs: %lld traversals, %.0f%% srch, %.0f%% simp, %.0f%% lkhd",
+    (LGLL) travs, lglpcnt (s->travs.search, travs),
+    lglpcnt (s->travs.simp, travs), lglpcnt (s->travs.lkhd, travs));
+  lglprs (lgl,
+    "trvs: %.1f search traversals per propagation, %.1f per conflict",
+    lglavg (s->travs.search, s->props.search),
+    lglavg (s->travs.search, s->confs));
+  lglprs (lgl,
+    "trvs: %.1f search traversals per search visit",
+    lglavg (s->travs.search, s->visits.search));
+
+  lglprs (lgl,
+    "trds: %d transitive reductions, %d removed, %d failed",
+    s->trd.count, s->trd.red, s->trd.failed);
+  lglprs (lgl,
+    "trds: %lld nodes, %lld edges, %lld steps",
+    (LGLL) s->trd.lits, (LGLL) s->trd.bins, (LGLL) s->trd.steps);
+
+  lglprs (lgl, "trim: %lld words, %.1f MB",
+    (LGLL) s->trims, (s->trims * sizeof (int)) / (double)(1<<20));
+
+  lglprs (lgl,
+    "trnr: %d count, %d bin, %d trn, %lld steps",
+    s->trnr.count, s->trnr.bin, s->trnr.trn, (LGLL) s->trnr.steps);
+
+  lglprs (lgl,
+    "unhd: %d count, %d rounds, %lld steps",
+    s->unhd.count, s->unhd.rounds, (LGLL) s->unhd.steps);
+  lglprs (lgl,
+    "unhd: %d non-trivial sccs of average size %.1f",
+    s->unhd.stamp.sccs,
+    lglavg (s->unhd.stamp.sumsccsizes, s->unhd.stamp.sccs));
+  sum = lglunhdunits (lgl);
+  lglprs (lgl,
+    "unhd: %d units, %d bin, %d trn, %d lrg",
+    sum, s->unhd.units.bin, s->unhd.units.trn, s->unhd.units.lrg);
+  sum = lglunhdfailed (lgl);
+  lglprs (lgl,
+    "unhd: %d failed, %d stamp, %d lits, %d bin, %d trn, %d lrg",
+    sum, s->unhd.stamp.failed, s->unhd.failed.lits,
+    s->unhd.failed.bin, s->unhd.failed.trn, s->unhd.units.lrg);
+  sum = lglunhdtauts (lgl);
+  lglprs (lgl,
+    "unhd: %d tauts, %d bin %.0f%%, %d trn %.0f%%, %d lrg %.0f%%",
+    sum,
+    s->unhd.tauts.bin, lglpcnt (s->unhd.tauts.bin, sum),
+    s->unhd.tauts.trn, lglpcnt (s->unhd.tauts.trn, sum),
+    s->unhd.tauts.lrg, lglpcnt (s->unhd.tauts.lrg, sum));
+  lglprs (lgl,
+    "unhd: %d tauts, %d stamp %.0f%%, %d red %.0f%%",
+    sum,
+    s->unhd.stamp.trds, lglpcnt (s->unhd.stamp.trds, sum),
+    s->unhd.tauts.red, lglpcnt (s->unhd.tauts.red, sum));
+  sum = lglunhdhbrs (lgl);
+  lglprs (lgl,
+    "unhd: %d hbrs, %d trn %.0f%%, %d lrg %.0f%%, %d red %.0f%%",
+    sum,
+    s->unhd.hbrs.trn, lglpcnt (s->unhd.hbrs.trn, sum),
+    s->unhd.hbrs.lrg, lglpcnt (s->unhd.hbrs.lrg, sum),
+    s->unhd.hbrs.red, lglpcnt (s->unhd.hbrs.red, sum));
+  sum = lglunhdstrd (lgl);
+  lglprs (lgl,
+    "unhd: %d str, %d bin %.0f%%, %d trn %.0f%%, %d lrg %.0f%%, %d red %.0f%%",
+    sum,
+    s->unhd.units.bin, lglpcnt (s->unhd.units.bin, sum),
+    s->unhd.str.trn, lglpcnt (s->unhd.str.trn, sum),
+    s->unhd.str.lrg, lglpcnt (s->unhd.str.lrg, sum),
+    s->unhd.str.red, lglpcnt (s->unhd.str.red, sum));
+
+  removed = s->fixed.sum + s->elm.elmd + s->equiv.sum;
+  remaining = lgl->maxext - removed;
+  assert (remaining >= 0);
+  lglprs (lgl,
+    "vars: %d remaining %.0f%% and %d removed %.0f%% out of %d",
+    remaining, lglpcnt (remaining, lgl->maxext),
+    removed, lglpcnt (removed, lgl->maxext), lgl->maxext);
+  lglprs (lgl,
+    "vars: %d fixed %.0f%%, %d eliminated %.0f%%, %d equivalent %.0f%%",
+    s->fixed.sum, lglpcnt (s->fixed.sum, lgl->maxext),
+    s->elm.elmd, lglpcnt (s->elm.elmd, lgl->maxext),
+    s->equiv.sum, lglpcnt (s->equiv.sum, lgl->maxext));
+
+  visits = s->visits.search + s->visits.simp + s->visits.lkhd;
+  lglprs (lgl,
+    "vsts: %lld visits, %.0f%% srch, %.0f%% simp, %.0f%% lkhd",
+    (LGLL) visits, lglpcnt (s->visits.search, visits),
+    lglpcnt (s->visits.simp, visits), lglpcnt (s->visits.lkhd, visits));
+  lglprs (lgl,
+    "vsts: %.1f search visits per propagation, %.1f per conflict",
+    lglavg (s->visits.search, s->props.search),
+    lglavg (s->visits.search, s->confs));
+
+  lglprs (lgl,
+    "wchs: %lld pushed, %lld enlarged, %d defrags",
+    (LGLL) s->pshwchs, (LGLL) s->enlwchs, s->defrags);
+
+  lglprsline (lgl);
+  lglgluestats (lgl);
+  lglprsline (lgl);
+SHORT:
+  lglprof (lgl);
+  lglprsline (lgl);
+  lglprs (lgl,
+    "%lld decisions, %.1f decisions/sec",
+    (LGLL) s->decisions, lglavg (s->decisions, t));
+  lglprs (lgl,
+    "%lld conflicts, %.1f conflicts/sec",
+    (LGLL) s->confs, lglavg (s->confs, t));
+  lglprs (lgl,
+    "%lld propagations, %.1f megaprops/sec",
+    (LGLL) p, lglavg (p/1e6, t));
+  lglprs (lgl, "%.1f seconds, %.1f MB", t, lglmaxmb (lgl));
+  fflush (lgl->out);
+}
+
+int64_t lglgetprops (LGL * lgl) {
+  REQINITNOTFORKED ();
+  return lgl->stats->props.search + lgl->stats->props.simp;
+}
+
+int64_t lglgetconfs (LGL * lgl) {
+  REQINITNOTFORKED ();
+  return lgl->stats->confs;
+}
+
+int64_t lglgetdecs (LGL * lgl) {
+  REQINITNOTFORKED ();
+  return lgl->stats->decisions;
+}
+
+void lglsizes (LGL * lgl) {
+  lglprt (lgl, 0, "sizeof (int) == %ld", (long) sizeof (int));
+  lglprt (lgl, 0, "sizeof (unsigned) == %ld", (long) sizeof (unsigned));
+  lglprt (lgl, 0, "sizeof (void*) == %ld", (long) sizeof (void*));
+  lglprt (lgl, 0, "sizeof (Stk) == %ld", (long) sizeof (Stk));
+  lglprt (lgl, 0, "sizeof (Fun) == %ld", (long) sizeof (Fun));
+  lglprt (lgl, 0, "sizeof (AVar) == %ld", (long) sizeof (AVar));
+  lglprt (lgl, 0, "sizeof (DVar) == %ld", (long) sizeof (DVar));
+  lglprt (lgl, 0, "sizeof (EVar) == %ld", (long) sizeof (EVar));
+  lglprt (lgl, 0, "sizeof (Gat) == %ld", (long) sizeof (Gat));
+  lglprt (lgl, 0, "sizeof (Stats.lir) == %ld", (long) sizeof ((Stats*)0)->lir);
+  lglprt (lgl, 0, "sizeof (Stats) == %ld", (long) sizeof (Stats));
+  lglprt (lgl, 0, "sizeof (LGL) == %ld", (long) sizeof (LGL));
+  lglprt (lgl, 0, "MAXVAR == %ld", (long) MAXVAR);
+  lglprt (lgl, 0, "MAXREDLIDX == %ld", (long) MAXREDLIDX);
+  lglprt (lgl, 0, "MAXIRRLIDX == %ld", (long) MAXIRRLIDX);
+}
+
+#define LGLRELSTK(MGR,STKPTR) \
+do { \
+  assert (lglmtstk (STKPTR)); \
+  lglrelstk ((MGR), (STKPTR)); \
+} while (0)
+
+void lglrelease (LGL * lgl) {
+  lgldealloc dealloc;
+  int i;
+
+  REQINIT ();
+  if (lgl->clone) lglrelease (lgl->clone), lgl->clone = 0;
+  TRAPI ("release");
+
+#ifndef NLGLDRUPLIG
+  if (lgl->druplig) druplig_reset (lgl->druplig), lgl->druplig = 0;
+#endif
+
+  // Heap state starts here:
+
+  DEL (lgl->avars, lgl->szvars);
+  DEL (lgl->doms, 2*lgl->szvars);
+  DEL (lgl->drail, lgl->szdrail);
+  DEL (lgl->dvars, lgl->szvars);
+  DEL (lgl->ext, lgl->szext);
+  DEL (lgl->i2e, lgl->szvars);
+  DEL (lgl->jwh, 2*lgl->szvars);
+  DEL (lgl->qvars, lgl->szvars);
+  DEL (lgl->vals, lgl->szvars);
+
+  lglrelctk (lgl, &lgl->control);
+
+  lglrelstk (lgl, &lgl->assume);
+  lglrelstk (lgl, &lgl->cassume);
+  lglrelstk (lgl, &lgl->clause);
+  lglrelstk (lgl, &lgl->dsched);
+  lglrelstk (lgl, &lgl->eassume);
+  lglrelstk (lgl, &lgl->eclause);
+  lglrelstk (lgl, &lgl->extend);
+  lglrelstk (lgl, &lgl->fassume);
+  lglrelstk (lgl, &lgl->learned);
+  lglrelstk (lgl, &lgl->frames);
+  lglrelstk (lgl, &lgl->trail);
+  lglrelstk (lgl, &lgl->wchs->stk);
+
+#ifndef NCHKSOL
+  lglrelstk (lgl, &lgl->orig);
+#endif
+
+  lglrelstk (lgl, &lgl->irr);
+  for (i = 0; i <= MAXGLUE; i++) lglrelstk (lgl, &lgl->red[i]);
+
+  // The following heap allocated memory has no state:
+
+  LGLRELSTK (lgl, &lgl->lcaseen);
+  LGLRELSTK (lgl, &lgl->minstk);
+  LGLRELSTK (lgl, &lgl->poisoned);
+  LGLRELSTK (lgl, &lgl->seen);
+
+  DEL (lgl->limits, 1);
+  DEL (lgl->times, 1);
+  DEL (lgl->timers, 1);
+  DEL (lgl->red, MAXGLUE+1);
+  DEL (lgl->wchs, 1);
+
+  if (lgl->fltstr) DEL (lgl->fltstr, 1);
+  if (lgl->cbs) DEL (lgl->cbs, 1);             // next to last
+  lgldelstr (lgl, lgl->prefix);                        // last
+
+  // adjust upfront the mem counters ...
+
+  lgldec (lgl, sizeof *lgl->stats);
+  lgldec (lgl, sizeof *lgl->opts);
+  lgldec (lgl, sizeof *lgl->mem);
+  lgldec (lgl, sizeof *lgl);
+
+  assert (getenv ("LGLEAK") || !lgl->stats->bytes.current);
+
+  if (lgl->closeapitrace == 1) fclose (lgl->apitrace);
+  if (lgl->closeapitrace == 2) pclose (lgl->apitrace);
+
+#ifndef NDEBUG
+#ifndef NLGLPICOSAT
+  if (lgl->picosat.solver) {
+    if (lgl->opts->verbose.val > 0 && lgl->opts->check.val > 0)
+      picosat_stats (PICOSAT);
+    picosat_reset (PICOSAT);
+    lgl->picosat.solver = 0;
+  }
+#endif
+#endif
+
+  if ((dealloc = lgl->mem->dealloc)) {
+     void * memstate = lgl->mem->state;
+     if (lgl->stats) dealloc (memstate, lgl->stats, sizeof *lgl->stats);
+     if (lgl->times) dealloc (memstate, lgl->times, sizeof *lgl->times);
+     if (lgl->opts) dealloc (memstate, lgl->opts, sizeof *lgl->opts);
+     assert (lgl->mem);
+     dealloc (memstate, lgl->mem, sizeof *lgl->mem);
+     dealloc (memstate, lgl, sizeof *lgl);
+  } else {
+    free (lgl->stats);
+    free (lgl->times);
+    free (lgl->opts);
+    free (lgl->mem);
+    free (lgl);
+  }
+}
+
+void lglutrav (LGL * lgl, void * state, void (*trav)(void *, int)) {
+  int elit, val;
+  REQINITNOTFORKED ();
+  if (!lgl->mt && !lglbcp (lgl)) lgl->mt = 1;
+  if (!lgl->mt) lglgc (lgl);
+  if (lgl->mt) return;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  for (elit = 1; elit <= lgl->maxext; elit++) {
+    if (!(val = lglefixed (lgl, elit))) continue;
+    trav (state, (val < 0) ? -elit : elit);
+  }
+}
+
+void lgletrav (LGL * lgl, void * state, void (*trav)(void *, int, int)) {
+  int elit, erepr;
+  REQINITNOTFORKED ();
+  if (!lgl->mt && !lglbcp (lgl)) lgl->mt = 1;
+  if (!lgl->mt) lglgc (lgl);
+  if (lgl->mt) return;
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  for (elit = 1; elit <= lgl->maxext; elit++) {
+    if (lglefixed (lgl, elit)) continue;
+    erepr = lglerepr (lgl, elit);
+    if (erepr == elit) continue;
+    trav (state, elit, erepr);
+  }
+}
+
+static void lglictrav (LGL * lgl, int internal,
+                       void * state, void (*trav)(void *, int)) {
+  int idx, sign, lit, blit, tag, red, other, other2;
+  const int * p, * w, * eow, * c;
+  HTS * hts;
+  REQINITNOTFORKED ();
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  if (!lgl->mt && !lglbcp (lgl)) lgl->mt = 1;
+  if (!lgl->mt) lglgc (lgl);
+  if (lgl->mt) { trav (state, 0); return; }
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      assert (!lglval (lgl, lit));
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (red) continue;
+       if (tag != BINCS && tag != TRNCS) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < idx) continue;
+       assert (!lglval (lgl, other));
+       if (tag == TRNCS) {
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         assert (!lglval (lgl, other2));
+       } else other2 = 0;
+       trav (state, internal ? lit : lglexport (lgl, lit));
+       trav (state, internal ? other : lglexport (lgl, other));
+       if (other2) trav (state, internal ? other2 : lglexport (lgl, other2));
+       trav (state, 0);
+      }
+    }
+  for (c = lgl->irr.start; c < lgl->irr.top; c = p + 1) {
+    p = c;
+    if (*p >= NOTALIT) continue;
+    while ((other = *p)) {
+      assert (!lglval (lgl, other));
+      trav (state, internal ? other : lglexport (lgl, other));
+      p++;
+    }
+    trav (state, 0);
+  }
+}
+
+void lglctrav (LGL * lgl, void * state, void (*trav)(void *, int)) {
+  lglictrav (lgl, 0, state, trav);
+}
+
+static void lgltravcounter (void * voidptr, int lit) {
+  int * cntptr = voidptr;
+  if (!lit) *cntptr += 1;
+}
+
+static void lgltravprinter (void * voidptr, int lit) {
+  FILE * out = voidptr;
+  if (lit) fprintf (out, "%d ", lit);
+  else fprintf (out, "0\n");
+}
+
+void lglprint (LGL * lgl, FILE * file) {
+  int count = 0;
+  lglctrav (lgl, &count, lgltravcounter);
+  fprintf (file, "p cnf %d %d\n", lglmaxvar (lgl), count);
+  lglctrav (lgl, file, lgltravprinter);
+}
+
+void lglprintall (LGL * lgl, FILE * file) {
+  int count = 0;
+  lgltravall (lgl, &count, lgltravcounter);
+  fprintf (file, "p cnf %d %d\n", lglmaxvar (lgl), count);
+  lgltravall (lgl, file, lgltravprinter);
+}
+
+void lglrtrav (LGL * lgl, void * state, void (*trav)(void *, int, int)) {
+  int idx, sign, lit, blit, tag, red, other, other2, glue;
+  const int * p, * c, * w, * eow;
+  Stk * lir;
+  HTS * hts;
+  REQINITNOTFORKED ();
+  if (lgl->mt) return;
+  lglgc (lgl);
+  if (lgl->level > 0) lglbacktrack (lgl, 0);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    if (lglval (lgl, idx)) continue;
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (!red) continue;
+       if (tag != BINCS && tag != TRNCS) continue;
+       other = blit >> RMSHFT;
+       if (abs (other) < idx) continue;
+       assert (!lglval (lgl, other));
+       if (tag == TRNCS) {
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+         assert (!lglval (lgl, other2));
+       } else other2 = 0;
+       trav (state, lglexport (lgl, lit), 0);
+       trav (state, lglexport (lgl, other), 0);
+       if (other2) trav (state, lglexport (lgl, other2), 0);
+       trav (state, 0, 0);
+      }
+    }
+  }
+  for (glue = 0; glue < MAXGLUE; glue++) {
+    lir = lgl->red + glue;
+    for (c = lir->start; c < lir->top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      while ((other = *p)) {
+       assert (!lglval (lgl, other));
+       trav (state, lglexport (lgl, other), 0);
+       p++;
+      }
+      trav (state, 0, 0);
+    }
+  }
+}
+
+static void lgltravallu (void * voidptr, int unit) {
+  Trv * state = voidptr;
+  state->trav (state->state, unit);
+  state->trav (state->state, 0);
+}
+
+static void lgltravalle (void * voidptr, int lit, int repr) {
+  Trv * state = voidptr;
+  state->trav (state->state, -lit);
+  state->trav (state->state, repr);
+  state->trav (state->state, 0);
+  state->trav (state->state, lit);
+  state->trav (state->state, -repr);
+  state->trav (state->state, 0);
+}
+
+void lgltravall (LGL * lgl, void * state, void (*trav)(void *, int)) {
+  Trv travstate;
+  travstate.state = state;
+  travstate.trav = trav;
+  lglutrav (lgl, &travstate, lgltravallu);
+  lgletrav (lgl, &travstate, lgltravalle);
+  lglctrav (lgl, state, trav);
+}
+
+#ifndef NDEBUG
+
+void lgldump (LGL * lgl) {
+  int idx, sign, lit, blit, tag, red, other, other2, glue;
+  const int * p, * w, * eow, * c, * top;
+  Stk * lir;
+  HTS * hts;
+  for (idx = 2; idx < lgl->nvars; idx++)
+    for (sign = -1; sign <= 1; sign += 2) {
+      lit = sign * idx;
+      hts = lglhts (lgl, lit);
+      w = lglhts2wchs (lgl, hts);
+      eow = w + hts->count;
+      for (p = w; p < eow; p++) {
+       blit = *p;
+       tag = blit & MASKCS;
+       red = blit & REDCS;
+       if (tag == TRNCS || tag == LRGCS) p++;
+       if (tag == BINCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = 0;
+       } else if (tag == TRNCS) {
+         other = blit >> RMSHFT;
+         if (abs (other) < idx) continue;
+         other2 = *p;
+         if (abs (other2) < idx) continue;
+       } else continue;
+       fprintf (lgl->out, "%s %d %d", red ? "red" : "irr", lit, other);
+       if (tag == TRNCS) fprintf (lgl->out, " %d", other2);
+       fprintf (lgl->out, "\n");
+      }
+    }
+  top = lgl->irr.top;
+  for (c = lgl->irr.start; c < top; c = p + 1) {
+    p = c;
+    if (*p >= NOTALIT) continue;
+    fprintf (lgl->out, "irr");
+    while (*p) fprintf (lgl->out, " %d", *p++);
+    fprintf (lgl->out, "\n");
+  }
+  for (glue = 0; glue < MAXGLUE; glue++) {
+    lir = lgl->red + glue;
+    top = lir->top;
+    for (c = lir->start; c < top; c = p + 1) {
+      p = c;
+      if (*p >= NOTALIT) continue;
+      fprintf (lgl->out, "glue%d", glue);
+      while (*p) fprintf (lgl->out, " %d", *p++);
+      fprintf (lgl->out, "\n");
+    }
+  }
+}
+
+#endif
+
+static void lglforkadd (void * ptr, int lit) {
+  lgladd (ptr, lit ? lglforklit (lit) : 0);
+}
+
+LGL * lglfork (LGL * parent) {
+  LGL * child;
+  {
+    LGL * lgl = parent;
+    REQINIT ();
+    ABORTIF (!lglmtstk (&parent->eassume), "can not fork under assumptions");
+    ABORTIF (parent->forked == INT_MAX, "parent forked too often");
+  }
+  if (parent->level > 0) lglbacktrack (parent, 0);
+  (void) lglbcp (parent);
+  lglgc (parent);
+  child = lglminit (parent->mem->state,
+                    parent->mem->alloc,
+                    parent->mem->realloc,
+                    parent->mem->dealloc);
+  child->parent = parent;
+  memcpy (child->opts, parent->opts, sizeof *parent->opts);
+  lglcopyclonenfork (child, parent);
+  lglictrav (parent, 1, child, lglforkadd);
+  assert (parent->stats->irr.clauses.cur == child->stats->irr.clauses.cur);
+  parent->forked++;
+  assert (parent->forked > 0);
+  lglprt (parent, 1, "forked-%d", parent->forked);
+  return child;
+}
+
+static void lglflass (LGL * lgl, LGL * from) {
+  int idx, copied = 0;
+  assert (!lgl->level), assert (!lgl->mt);
+  assert ((from->state & (SATISFIED | EXTENDED)));
+  if (lgl->nvars) assert (lgl->nvars == from->maxext + 2);
+  else assert (!from->maxext);
+  lglreset (lgl);
+  for (idx = 2; idx < lgl->nvars; idx++) {
+    int val = lglderef (from, idx-1);
+    int lit = val < 0 ? -idx : idx;
+    lgldassume (lgl, lit);
+    copied++;
+  }
+  lglprt (lgl, 1, "[flass] copied %d internal assignments", copied);
+  TRANS (SATISFIED);
+  lglextend (lgl);
+#ifndef NCHKSOL
+  lglchksol (lgl);
+#endif
+#ifndef NLGLPICOSAT
+  lglpicosatchksol (lgl);
+#endif
+}
+
+int lgljoin (LGL * parent, LGL * child) {
+  int res;
+  {
+    LGL * lgl = parent;
+    ABORTIF (!parent, "uninitialized parent manager");
+    ABORTIF (!child, "uninitialized child manager");
+    ABORTIF (!parent->forked, "parent manager not forked");
+    ABORTIF (!child->parent, "child manager has not parent");
+    ABORTIF (child->parent != parent, "child manager has different parent");
+    ABORTIF (!lglmtstk (&child->eassume),
+      "child manager with assumptions not supported yet");
+  }
+  if (child->mt || (child->state & UNSATISFIED)) {
+#ifndef NLGLOG
+    LGL * lgl = parent;
+#endif
+    assert (child->mt);                                  // no assumptions yet ...
+    lglprt (parent, 1, "[join] unsatisfied state");
+    if (!parent->mt) {
+      LOG (1, "joining empty clause");
+      parent->mt = 1;
+    } else LOG (1, "no need to join empty clause since parent has one");
+    res = 20;
+  } else if (child->state & (SATISFIED | EXTENDED)) {
+    lglprt (parent, 1, "[join] satisfied state");
+    lglflass (parent, child);
+    res = 10;
+  } else {
+    lglprt (parent, 1, "[join] unknown state");
+    lglreset (parent);
+    {
+      LGL * lgl = parent;
+      TRANS (UNKNOWN);
+    }
+    res = 0;
+  }
+  return res;
+}
diff --git a/lingeling/code/lglib.h b/lingeling/code/lglib.h
new file mode 100644 (file)
index 0000000..45a58d4
--- /dev/null
@@ -0,0 +1,350 @@
+/*-------------------------------------------------------------------------*/
+/* Copyright 2010-2014 Armin Biere Johannes Kepler University Linz Austria */
+/*-------------------------------------------------------------------------*/
+
+#ifndef lglib_h_INCLUDED
+#define lglib_h_INCLUDED
+
+#include <stdio.h>                             // for 'FILE'
+#include <stdlib.h>                            // for 'int64_t'
+
+//--------------------------------------------------------------------------
+
+#define LGL_UNKNOWN 0
+#define LGL_SATISFIABLE 10
+#define LGL_UNSATISFIABLE 20
+
+//--------------------------------------------------------------------------
+
+typedef struct LGL LGL;
+
+//--------------------------------------------------------------------------
+
+LGL * lglinit (void);                          // constructor
+void lglrelease (LGL *);                       // destructor
+
+// externally provided memory manager ...
+
+typedef void * (*lglalloc) (void*mem, size_t);
+typedef void (*lgldealloc) (void*mem, void*, size_t);
+typedef void * (*lglrealloc) (void*mem, void *ptr, size_t old, size_t);
+
+LGL * lglminit (void *mem, lglalloc, lglrealloc, lgldealloc);
+
+// 'Cloning' produces identicaly behaving solvers.
+
+LGL * lglclone (LGL *);
+LGL * lglmclone (LGL *, void *mem, lglalloc, lglrealloc, lgldealloc);
+
+int lglunclone (LGL * dst, LGL * src);         // does not release 'src'
+
+// 'Forking' copies only irredundant clauses and also uses internal variable
+// indices of the parent as external variable indices.  Thus 'parent' and
+// the forked off 'child' do neither exactly work the same way, nor do they
+// use from the API point of view the same set of variables.  They are
+// satisfiability equivalent.  If the child becomes unsatisfiable the parent
+// can be assumed to be unsatisfiable too and thus 'lgljoin' would just add
+// the empty clause to the parent.  If the child produces a satisfying
+// assignment, this assignment is turned into an assignment of the parent by
+// 'lgljoin'.  Parents can be forked multiple times.  A child has exactly
+// one parent.  Parents and children can be released independently.  Between
+// 'lglfork' and 'lgljoin' no other operations but further 'lglfork' are
+// allowed.  The effect ot multiple 'lgljoin' with the same parent is
+// unclear at this point.  The same memory manager is use for the child and
+// the parent. Options, prefix, output file and the callbacks for 'getime'
+// and 'onabort' are copied too (if set).
+
+LGL * lglfork (LGL * parent);
+int lgljoin (LGL * parent, LGL * child);       // does not release 'child'
+
+// Both 'Cloning' and 'Forking' can be used to implement 'Push & Pop', but
+// the asymmetric forking is more similar to the classical way of
+// implementing it, needs less resources since for instance eliminated
+// variables do not occupy any memory in the children, but requires lifting
+// back satisfying assignments explicitly (through the whole parent chain).
+// If these full satisfying assignments are really needed actually cloning
+// could be more space efficient too.  Assume you want to split the solver
+// into two instances, one with a literal set to false, the other one to
+// true. Then cloning allows you to produce two independent branches, while
+// for forking you need three, since the root / top solver still has to be
+// kept for lifting back a potential assignment.
+
+//--------------------------------------------------------------------------
+
+const char * lglversion ();
+
+void lglbnr (const char * name,
+             const char * prefix,
+            FILE * file);                      // ... banner
+
+void lglusage (LGL *);                         // print usage "-h"
+void lglopts (LGL *, const char * prefix, int);        // ... defaults "-d" | "-e"
+void lglrgopts (LGL *);                                // ... option ranges "-r"
+void lglpcs (LGL *, int mixed);                        // ... PCS file
+void lglsizes (LGL *);                         // ... data structure sizes
+
+//--------------------------------------------------------------------------
+// setters and getters for options
+
+void lglsetout (LGL *, FILE*);                 // output file for report
+void lglsetprefix (LGL *, const char*);                // prefix for messages
+
+FILE * lglgetout (LGL *);
+const char * lglgetprefix (LGL *);
+
+void lglsetopt (LGL *, const char *, int);     // set option value
+int lglreadopts (LGL *, FILE *);               // read and set options
+int lglgetopt (LGL *, const char *);           // get option value
+int lglhasopt (LGL *, const char *);           // exists option?
+
+int lglgetoptminmax (LGL *, const char *, int * minptr, int * maxptr);
+
+void * lglfirstopt (LGL *);                    // option iterator: first
+
+void * lglnextopt (LGL *,                      // option iterator: next
+                   void * iterator, 
+                   const char ** nameptr,
+                  int *valptr, int *minptr, int *maxptr);
+
+// individual ids for logging and statistics:
+
+void lglsetid (LGL *, int tid, int tids);
+
+// Set default phase of a literal.  Any decision on this literal will always
+// try this phase.  Note, that this function does not have any effect on
+// eliminated variables.  Further equivalent variables share the same forced 
+// phase and thus if they are set to different default phases, only the last
+// set operation will be kept.
+
+void lglsetphase (LGL *, int lit);
+void lglresetphase (LGL *, int lit);   // Stop forcing phase in decisions.
+
+// Assume the solver is in the SATISFIABLE state (after 'lglsat' or
+// 'lglsimp'), then calling 'lglsetphases' will copy the current assignment
+// as default phases.
+
+void lglsetphases (LGL *);
+
+//--------------------------------------------------------------------------
+// call back for abort
+
+void lglonabort (LGL *, void * state, void (*callback)(void* state));
+
+//--------------------------------------------------------------------------
+// write and read API trace
+
+void lglwtrapi (LGL *, FILE *);
+void lglrtrapi (LGL *, FILE *);
+
+//--------------------------------------------------------------------------
+// traverse units, equivalences, remaining clauses, or all clauses:
+
+void lglutrav (LGL *, void * state, void (*trav)(void *, int unit));
+void lgletrav (LGL *, void * state, void (*trav)(void *, int lit, int repr));
+void lglctrav (LGL *, void * state, void (*trav)(void *, int lit));
+void lgltravall (LGL *, void * state, void (*trav)(void *state, int lit));
+
+//--------------------------------------------------------------------------
+
+void lglprint (LGL *, FILE *);                 // remaining in DIMACS format
+void lglprintall (LGL *, FILE *);              // including units & equivs
+
+//--------------------------------------------------------------------------
+// main interface as in PicoSAT (see 'picosat.h' for more information)
+
+int lglmaxvar (LGL *);
+int lglincvar (LGL *);
+
+void lgladd (LGL *, int lit);
+void lglassume (LGL *, int lit);               // assume single units
+
+void lglcassume (LGL *, int lit);              // assume clause
+                                               // (at most one)
+
+void lglfixate (LGL *);                                // add assumptions as units
+
+int lglsat (LGL *);
+int lglsimp (LGL *, int iterations);
+
+int lglderef (LGL *, int lit);                 // neg=false, pos=true
+int lglfixed (LGL *, int lit);                 // ditto but toplevel
+
+int lglfailed (LGL *, int lit);                        // ditto for assumptions
+int lglinconsistent (LGL *);                   // contains empty clause?
+int lglchanged (LGL *);                                // model changed
+
+void lglreducecache (LGL *);                   // reset cache size
+void lglflushcache (LGL *);                    // flush all learned clauses
+
+/*------------------------------------------------------------------------*/
+
+/* Return representative from equivalence class if literal is not top-level
+ * assigned nor eliminated.
+ */
+int lglrepr (LGL *, int lit);
+
+/* Set 'startptr' and 'toptr' to the 'start' and 'top' of the reconstruction
+ * stack, which is used in BCE, BVE and CCE for reconstructing a solution
+ * after eliminating variables or clauses.  These pointers are only valid
+ * until the next 'lglsat/lglsimp' call.
+ */
+void lglreconstk (LGL * lgl, int ** startptr, int ** toptr);
+
+//--------------------------------------------------------------------------
+// Multiple-Objective SAT tries to solve multiple objectives at the same
+// time.  If a target can be satisfied or falsified the user is notified via
+// a callback function of type 'lglnotify'. The argument is an abstract
+// state (of the user), the target literal and as last argument the value
+// (-1 = unsatisfiable, 1 = satisfiable).  If the notification callback
+// returns 1 the 'lglmosat' procedure continues, otherwise it stops.  It
+// returns a non zero value iff only all targets have been either proved to
+// be satisfiable or unsatisfiable.  Even if 'val' given to the notification
+// function is '1', it can not assume that the current assignment is
+// complete, e.g. satisfies the formula.
+//
+typedef int (*lglnotify)(void *state, int target, int val);
+
+int lglmosat (LGL *, void * state, lglnotify, int * targets);
+
+//--------------------------------------------------------------------------
+// Incremental interface provides reference counting for indices, i.e.
+// unfrozen indices become invalid after next 'lglsat' (or 'lglsimp').
+// This is actually a reference counter for variable indices still in use
+// after the next 'lglsat' or 'lglsimp' call.  It is actually variable based
+// and only applies to literals in new clauses or used as assumptions,
+// e.g. in calls to 'lgladd' and 'lglassume'.
+//
+// The following example is actually compilable and used for explaining
+// all the details of this rather complicated incremental API contract:
+
+/***** start of incremental example ***************************************
+
+#include "lglib.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+
+int main () {
+  LGL * lgl = lglinit ();
+  int res;
+  lgladd (lgl, -14); lgladd (lgl, 2); lgladd (lgl, 0);  // binary clause
+  lgladd (lgl, 14); lgladd (lgl, -1); lgladd (lgl, 0);  // binary clause
+  lglassume (lgl, 1);                                   // assume '1'
+  lglfreeze (lgl, 1);                                   // will use '1' below
+  lglfreeze (lgl, 14);                                  // will use '14 too
+  assert (lglfrozen (lgl, 1));
+  assert (lglfrozen (lgl, 14));
+  res = lglsat (lgl);
+  assert (res == 10);
+  (void) lglderef (lgl, 1);                             // fine
+  (void) lglderef (lgl, 2);                             // fine
+  (void) lglderef (lgl, 3);                             // fine !
+  (void) lglderef (lgl, 14);                            // fine
+  assert (!lglusable (lgl, 2));
+  // lgladd (lgl, 2);                                   // ILLEGAL
+  // lglassume (lgl, 2);                                // ILLEGAL
+  assert (lglusable (lgl, 15));                                // '15' not used yet!
+  lgladd (lgl, -14); lgladd (lgl, 1); lgladd (lgl, 0);  // binary clause
+  lgladd (lgl, 15); lgladd (lgl, 0);                    // fine!
+  lglmelt (lgl, 14);                                    // '1' discarded
+  res = lglsat (lgl);
+  assert (res == 10);
+  assert (lglfrozen (lgl, 1));
+  (void) lglderef (lgl, 1);                             // fine
+  (void) lglderef (lgl, 2);                             // fine
+  (void) lglderef (lgl, 3);                             // fine
+  (void) lglderef (lgl, 14);                            // fine
+  (void) lglderef (lgl, 15);                            // fine
+  assert (!lglusable (lgl, 2));
+  assert (!lglusable (lgl, 14));
+  // lglassume (lgl, 2);                                // ILLEGAL
+  // lglassume (lgl, 14);                               // ILLEGAL
+  lgladd (lgl, 1);                                      // still frozen
+  lglmelt (lgl, 1);
+  lgladd (lgl, 0);
+  res = lglsat (lgl);
+  // none frozen
+  assert (!lglusable (lgl, 1));
+  // lgladd(lgl, 1);                                    // ILLEGAL
+  lglsetopt (lgl, "plain", 1);                         // disable BCE ...
+  lgladd (lgl, 8); lgladd (lgl, -9); lgladd (lgl, 0);
+  res = lglsat (lgl);
+  assert (res == 10);
+  assert (!lglusable (lgl, 8));
+  assert (!lglusable (lgl, -9));
+  assert (lglreusable (lgl, 8));
+  assert (lglreusable (lgl, -9));
+  lglreuse (lgl, 8);
+  lgladd (lgl, -8); lgladd (lgl, 0);
+  lglsetopt (lgl, "plain", 0);                         // enable BCE ...
+  res = lglsat (lgl);
+  assert (res);
+  return res;
+}
+
+****** end of incremental example ****************************************/
+
+void lglfreeze (LGL *, int lit);
+int lglfrozen (LGL *, int lit);
+
+void lglmelt (LGL *, int lit);
+void lglmeltall (LGL *);                               // melt all literals
+
+// If a literal was not frozen at the last call to 'lglsat' (or 'lglsimp')
+// it becomes 'unusable' after the next call even though it might not
+// have been used as blocking literal etc.  This
+
+int lglusable (LGL *, int lit);
+int lglreusable (LGL *, int lit);
+void lglreuse (LGL *, int lit);
+
+//--------------------------------------------------------------------------
+// Returns a good look ahead literal or zero if all potential literals have
+// been eliminated or have been used as blocking literals in blocked clause
+// elimination.  Zero is also returned if the formula is already
+// inconsistent.  The lookahead literal is made usable again, for instance
+// if it was not frozen during a previous SAT call and thus implicitly
+// became melted.  Therefore it can be added in a unit clause.
+
+int lglookahead (LGL *);
+
+//--------------------------------------------------------------------------
+// stats:
+
+void lglflushtimers (LGL *lgl);                        // after interrupt etc.
+
+void lglstats (LGL *);
+int64_t lglgetconfs (LGL *);
+int64_t lglgetdecs (LGL *);
+int64_t lglgetprops (LGL *);
+size_t lglbytes (LGL *);
+int lglnvars (LGL *);
+int lglnclauses (LGL *);
+double lglmb (LGL *);
+double lglmaxmb (LGL *);
+double lglsec (LGL *);
+double lglprocesstime (void);
+
+//--------------------------------------------------------------------------
+// low-level parallel support through call backs
+
+void lglseterm (LGL *, int (*term)(void*), void*);
+
+void lglsetproduceunit (LGL *, void (*produce)(void*, int), void*);
+void lglsetconsumeunits (LGL *, void (*consume)(void*,int**,int**), void*);
+void lglsetconsumedunits (LGL *, void (*consumed)(void*,int), void*);
+
+void lglsetproducecls (LGL*, void(*produce)(void*,int*,int glue),void*);
+void lglsetconsumecls (LGL*,void(*consume)(void*,int**,int *glueptr),void*);
+void lglsetconsumedcls (LGL *, void (*consumed)(void*,int), void*);
+
+void lglsetlockeq (LGL *, int * (*lock)(void*), void *);
+void lglsetunlockeq (LGL *, void (*unlock)(void*,int cons,int prod), void *);
+
+void lglsetmsglock (LGL *, void (*lock)(void*), void (*unlock)(void*), void*);
+void lglsetime (LGL *, double (*time)(void));
+
+#endif
diff --git a/lingeling/code/lglmain.c b/lingeling/code/lglmain.c
new file mode 100644 (file)
index 0000000..be6e5ea
--- /dev/null
@@ -0,0 +1,752 @@
+/*-------------------------------------------------------------------------*/
+/* Copyright 2010-2014 Armin Biere Johannes Kepler University Linz Austria */
+/*-------------------------------------------------------------------------*/
+
+#include "lglib.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static LGL * lgl4sigh;
+static int catchedsig, verbose, ignmissingheader, ignaddcls;
+
+static int * targets, sztargets, ntargets, multiple;
+
+static void (*sig_int_handler)(int);
+static void (*sig_segv_handler)(int);
+static void (*sig_abrt_handler)(int);
+static void (*sig_term_handler)(int);
+static void (*sig_bus_handler)(int);
+static void (*sig_alrm_handler)(int);
+
+static void resetsighandlers (void) {
+  (void) signal (SIGINT, sig_int_handler);
+  (void) signal (SIGSEGV, sig_segv_handler);
+  (void) signal (SIGABRT, sig_abrt_handler);
+  (void) signal (SIGTERM, sig_term_handler);
+  (void) signal (SIGBUS, sig_bus_handler);
+}
+
+static void caughtsigmsg (int sig) {
+  if (verbose < 0) return;
+  printf ("c\nc CAUGHT SIGNAL %d", sig);
+  switch (sig) {
+    case SIGINT: printf (" SIGINT"); break;
+    case SIGSEGV: printf (" SIGSEGV"); break;
+    case SIGABRT: printf (" SIGABRT"); break;
+    case SIGTERM: printf (" SIGTERM"); break;
+    case SIGBUS: printf (" SIGBUS"); break;
+    case SIGALRM: printf (" SIGALRM"); break;
+    default: break;
+  }
+  printf ("\nc\n");
+  fflush (stdout);
+}
+
+static void catchsig (int sig) {
+  if (!catchedsig) {
+    catchedsig = 1;
+    caughtsigmsg (sig);
+    fputs ("c s UNKNOWN\n", stdout);
+    fflush (stdout);
+    if (verbose >= 0) {
+      lglflushtimers (lgl4sigh);
+      lglstats (lgl4sigh);
+      caughtsigmsg (sig);
+    }
+  }
+  resetsighandlers ();
+  if (!getenv ("LGLNABORT")) raise (sig); else exit (1);
+}
+
+static void setsighandlers (void) {
+  sig_int_handler = signal (SIGINT, catchsig);
+  sig_segv_handler = signal (SIGSEGV, catchsig);
+  sig_abrt_handler = signal (SIGABRT, catchsig);
+  sig_term_handler = signal (SIGTERM, catchsig);
+  sig_bus_handler = signal (SIGBUS, catchsig);
+}
+
+static int timelimit = -1, caughtalarm = 0;
+
+static void catchalrm (int sig) {
+  assert (sig == SIGALRM);
+  if (!caughtalarm) {
+    caughtalarm = 1;
+    caughtsigmsg (sig);
+    if (timelimit >= 0) {
+      printf ("c time limit of %d reached after %.1f seconds\nc\n",
+              timelimit, lglsec (lgl4sigh));
+      fflush (stdout);
+    }
+  }
+}
+
+static int checkalarm (void * ptr) {
+  assert (ptr == (void*) &caughtalarm);
+  return caughtalarm;
+}
+
+static int next (FILE * in, int *linenoptr) {
+  int res = getc (in);
+  if (res == '\n') *linenoptr += 1;
+  return res;
+}
+
+static char isoptchartab[256];
+static int isoptchartabinitialized;
+
+static int isoptchar (unsigned char uch) { 
+  int i;
+  if (!isoptchartabinitialized) {
+    for (i = 'a'; i <= 'z'; i++) isoptchartab[i] = 1;
+    for (i = 'A'; i <= 'Z'; i++) isoptchartab[i] = 1;
+    for (i = '0'; i <= '9'; i++) isoptchartab[i] = 1;
+    isoptchartab['-'] = isoptchartab['_'] = 1;
+    isoptchartabinitialized = 1;
+  }
+  return isoptchartab[uch];
+}
+
+typedef struct Opt { char * name; int size, count; } Opt;
+
+static void pushoptch (Opt * opt, int ch) {
+  if (opt->count + 1 >= opt->size)
+   opt->name = realloc (opt->name, opt->size = opt->size ? 2*opt->size : 2);
+
+  opt->name[opt->count++] = ch;
+  opt->name[opt->count] = 0;
+}
+
+static const char * parse (LGL * lgl, FILE * in, int * lp) {
+  int ch, prev, m, n, v, c, l, lit, sign, val, embedded = 0, header;
+  Opt opt;
+  memset (&opt, 0, sizeof opt);
+SKIP:
+  ch = next (in, lp);
+  if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') goto SKIP;
+  if (ch == 'c') {
+    ch  = next (in, lp);
+    while (ch != '\n') {
+      if (ch == EOF) return "end of file in comment";
+      prev = ch;
+      ch = next (in, lp);
+      if (prev != '-') continue;
+      if (ch != '-') continue;
+      assert (!opt.count);
+      ch = next (in, lp);
+      while (isoptchar (ch)) {
+       assert (ch != '\n');
+       pushoptch (&opt, ch);
+       ch = next (in, lp);
+      }
+      opt.count = 0;
+      if (ch != '=') continue;
+      ch = next (in, lp);
+      if (ch == '-') sign = -1, ch = next (in, lp); else sign = 1;
+      if (!isdigit (ch)) continue;
+      val = ch - '0';
+      while (isdigit (ch = next (in, lp)))
+       val = 10 * val + (ch - '0');
+
+      if (!lglhasopt (lgl, opt.name)) {
+       fprintf (stderr, 
+                "*** lingeling warning: "
+                "parsed invalid embedded option '--%s'\n", 
+                opt.name);
+       continue;
+      }
+
+      val *= sign;
+
+      if (!embedded++ && verbose >= 0)
+       printf ("c\nc embedded options:\nc\n");
+      if (!strcmp (opt.name, "verbose")) verbose = val;
+      if (verbose >= 0) printf ("c --%s=%d\n", opt.name, val);
+      lglsetopt (lgl, opt.name, val);
+    }
+    goto SKIP;
+  }
+  free (opt.name);
+  if (verbose >= 0) {
+     if (embedded) printf ("c\n"); else printf ("c no embedded options\n");
+     fflush (stdout);
+  }
+  header = m = n = v = l = c = 0;
+  if (ignmissingheader) {
+    if (ch == 'p')  {
+      if (verbose >= 0) printf ("will not read header");
+      while ((ch = next (in, lp)) != '\n' && ch != EOF)
+       ;
+    } else if (verbose >= 0) printf ("c skipping missing header\n");
+    goto BODY2;
+  }
+  if (ch != 'p') return "missing 'p ...' header";
+  if (next (in, lp) != ' ') return "invalid header: expected ' ' after 'p'";
+  while ((ch = next (in, lp)) == ' ')
+    ;
+  if (ch != 'c') return "invalid header: expected 'c' after ' '";
+  if (next (in, lp) != 'n') return "invalid header: expected 'n' after 'c'";
+  if (next (in, lp) != 'f') return "invalid header: expected 'f' after 'n'";
+  if (next (in, lp) != ' ') return "invalid header: expected ' ' after 'f'";
+  while ((ch = next (in, lp)) == ' ')
+    ;
+  if (!isdigit (ch)) return "invalid header: expected digit after 'p cnf '";
+  m = ch - '0';
+  while (isdigit (ch = next (in, lp)))
+    m = 10 * m + (ch - '0');
+  if (ch != ' ') return "invalid header: expected ' ' after 'p cnf <m>'"; 
+  while ((ch = next (in, lp)) == ' ')
+    ;
+  if (!isdigit (ch)) 
+    return "invalid header: expected digit after 'p cnf <m> '";
+  n = ch - '0';
+  while (isdigit (ch = next (in, lp)))
+    n = 10 * n + (ch - '0');
+  while (ch == ' ')
+    ch = next (in, lp);
+  if (ch != '\n') return "invalid header: expected new line after header";
+  if (verbose >= 0)
+    printf ("c found 'p cnf %d %d' header\n", m, n), fflush (stdout);
+  header = 1;
+BODY:
+  ch = next (in, lp);
+BODY2:
+  if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') goto BODY;
+  if (ch == 'c') {
+    while ((ch = next (in, lp)) != '\n')
+      if (ch == EOF) return "end of file in comment";
+    goto BODY;
+  }
+  if (ch == EOF) {
+    if (header && c + 1 == n) return "clause missing";
+    if (header && c < n) return "clauses missing";
+DONE:
+    if (verbose >= 0) {
+      printf ("c read %d variables, %d clauses, %d literals in %.2f seconds\n", 
+             v, c, l, lglsec (lgl));
+      fflush (stdout);
+    }
+    return 0;
+  }
+  if (ch == '-') {
+    ch = next (in, lp);
+    if (ch == '0') return "expected positive digit after '-'";
+    sign = -1;
+  } else sign = 1;
+  if (!isdigit (ch)) return "expected digit";
+  if (header && c == n) return "too many clauses";
+  lit = ch - '0';
+  while (isdigit (ch = next (in, lp)))
+    lit = 10 * lit + (ch - '0');
+  if (header && lit > m) return "maxium variable index exceeded";
+  if (lit > v) v = lit;
+  if (lit) l++;
+  else c++;
+  lit *= sign;
+  lgladd (lgl, lit);
+  if (!lit && ignaddcls && c == n) goto DONE;
+  goto BODY;
+}
+
+typedef struct OBuf { char line[81]; int pos; } OBuf;
+
+static void flushobuf (OBuf * obuf, int simponly, FILE * file) {
+  assert (0 < obuf->pos);
+  assert (obuf->pos < 81);
+  obuf->line[obuf->pos++] = '\n';
+  assert (obuf->pos < 81);
+  obuf->line[obuf->pos++] = 0;
+  if (simponly) fputs ("c ", file);
+  fputc ('v', file);
+  fputs (obuf->line, file);
+  obuf->pos = 0;
+}
+
+static void print2obuf (OBuf * obuf, int i, int simponly, FILE * file) {
+  char str[20];
+  int len;
+  sprintf (str, " %d", i);
+  len = strlen (str);
+  assert (len > 1);
+  if (obuf->pos + len > 79) flushobuf (obuf, simponly, file);
+  strcpy (obuf->line + obuf->pos, str);
+  obuf->pos += len;
+  assert (obuf->pos <= 79);
+}
+
+static FILE * writefile (const char * name, int * clptr) {
+  int len = strlen (name);
+  char * tmp;
+  FILE * res;
+  if (len >= 3 && !strcmp (name + len - 3, ".gz")) {
+    tmp = malloc (len + 20);
+    unlink (name);
+    sprintf (tmp, "gzip -c > %s", name);
+    res = popen (tmp, "w");
+    if (res) *clptr = 2;
+    free (tmp);
+  } else {
+    res = fopen (name, "w");
+    if (res) *clptr = 1;
+  }
+  if (!res) fprintf (stderr, "*** lingeling error: can not write %s\n", name);
+  return res;
+}
+
+static void closefile (FILE * file, int type) {
+  if (type == 1) fclose (file);
+  if (type == 2) pclose (file);
+}
+
+static void lgltravcounter (void * voidptr, int lit) {
+  int * cntptr = voidptr;
+  if (!lit) *cntptr += 1;
+}
+
+static void lglpushtarget (int target) {
+  if (ntargets == sztargets)
+    targets = realloc (targets, sizeof *targets *
+               (sztargets = sztargets ? 2*sztargets : 1));
+  targets[ntargets++] = target;
+}
+
+static int lglmonotifiy (void * lgl, int target, int val) {
+  printf ("t %d %d after %.3f seconds\n", target, val, lglsec (lgl));
+  fflush (stdout);
+  return 1;
+}
+
+static int primes[] = {
+  200000033, 200000039, 200000051, 200000069, 200000081,
+};
+
+static int nprimes = sizeof primes / sizeof *primes;
+
+int main (int argc, char ** argv) {
+  int res, i, j, clin, clout, val, len, lineno, simponly, count, target;
+  const char * iname, * oname, * pname, * match, * p, * err, * thanks;
+  int maxvar, lit, nopts, simplevel;
+  FILE * in, * out, * pfile;
+  char * tmp;
+  LGL * lgl;
+  OBuf obuf;
+  lineno = 1;
+  in = out = 0;
+  res = clin = clout = simponly = simplevel = 0;
+  iname = oname = pname = thanks = 0;
+  lgl4sigh = lgl = lglinit ();
+  setsighandlers ();
+  for (i = 1; i < argc; i++) {
+    if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) {
+      printf ("usage: lingeling [<option> ...][<file>[.gz]]\n");
+      printf ("\n");
+      printf ("where <option> is one of the following:\n");
+      printf ("\n");
+      printf ("-q               be quiet (same as '--verbose=-1')\n");
+      printf ("-s               only simplify and print to output file\n");
+      printf ("-O<L>            set simplification level to <L>\n");
+      printf ("-o <output>      set output file (default 'stdout')\n");
+      printf ("-p <options>     read options from file\n");
+      printf ("\n");
+      printf ("-t <seconds>     set time limit\n");
+      printf ("\n");
+      printf ("-a <assumption>  use multiple assumptions\n");
+      printf ("-m <objective>   use multiple objectives\n");
+      printf ("\n");
+      printf ("-h|--help        print command line option summary\n");
+      printf ("-f|--force       force reading even without header\n");
+      printf ("-i|--ignore      ignore additional clauses\n");
+      printf ("-r|--ranges      print value ranges of options\n");
+      printf ("-d|--defaults    print default values of options\n");
+      printf ("-P|--pcs         print (full) PCS file\n");
+      printf ("--pcs-mixed      print mixed PCS file\n");
+      printf ("--pcs-reduced    print reduced PCS file\n");
+      printf ("-e|--embedded    ditto but in an embedded format print\n");
+      printf ("-n|--no-witness   do not print solution (see '--witness')\n");
+      printf ("\n");
+      printf ("--thanks=<whom>  alternative way of specifying the seed\n");
+      printf ("                 (inspired by Vampire)\n");
+      printf ("\n");
+      printf (
+"The following options can also be used in the form '--<name>=<int>',\n"
+"just '--<name>' for increment and '--no-<name>' for zero.  They\n"
+"can be embedded into the CNF file, set through the API or capitalized\n"
+"with prefix 'LGL' instead of '--' through environment variables.\n"
+"Their default values are displayed in square brackets.\n");
+      printf ("\n");
+      lglusage (lgl);
+      goto DONE;
+    } else if (!strcmp (argv[i], "-s")) simponly = 1;
+    else if (argv[i][0] == '-' && argv[i][1] == 'O') {
+      if (simplevel > 0) {
+       fprintf (stderr, "*** lingeling error: multiple '-O..' options\n");
+       res = 1;
+       goto DONE;
+      }
+      if ((simplevel = atoi (argv[i] + 2)) <= 0) {
+       fprintf (stderr,
+          "*** lingeling error: invalid '%s' option\n", argv[i]);
+       res = 1;
+       goto DONE;
+      }
+    } else if (!strcmp (argv[i], "-q")) lglsetopt (lgl, "verbose", -1);
+    else if (!strcmp (argv[i], "-o")) {
+      if (++i == argc) {
+       fprintf (stderr, "*** lingeling error: argument to '-o' missing\n");
+       res = 1;
+       goto DONE;
+      } 
+      if (oname) {
+       fprintf (stderr, 
+                "*** lingeling error: "
+                "multiple output files '%s' and '%s'\n",
+                oname, argv[i]);
+       res = 1;
+       goto DONE;
+      }
+      oname = argv[i];
+    } else if (!strcmp (argv[i], "-p")) {
+      if (++i == argc) {
+       fprintf (stderr, "*** lingeling error: argument to '-p' missing\n");
+       res = 1;
+       goto DONE;
+      } 
+      if (pname) {
+       fprintf (stderr, 
+                "*** lingeling error: "
+                "multiple option files '%s' and '%s'\n",
+                pname, argv[i]);
+       res = 1;
+       goto DONE;
+      }
+      pname = argv[i];
+    } else if (!strcmp (argv[i], "-t")) {
+      if (++i == argc) {
+       fprintf (stderr, "*** lingeling error: argument to '-t' missing\n");
+       res = 1;
+       goto DONE;
+      }
+      if (timelimit >= 0) {
+       fprintf (stderr, "*** lingeling error: timit limit set twice\n");
+       res = 1;
+       goto DONE;
+      }
+      for (p = argv[i]; *p && isdigit (*p); p++) 
+       ;
+      if (p == argv[i] || *p || (timelimit = atoi (argv[i])) < 0) {
+       fprintf (stderr, 
+         "*** lingeling error: invalid time limit '-t %s'\n", argv[i]);
+       res = 1;
+       goto DONE;
+      }
+    } else if (!strcmp (argv[i], "-a")) {
+      if (++i == argc) {
+       fprintf (stderr, "*** lingeling error: argument to '-a' missing\n");
+       res = 1;
+       goto DONE;
+      }
+      if (multiple) {
+       assert (ntargets > 0);
+       fprintf (stderr, "*** lingeling error: unexpectd '-a' after '-m'\n");
+       res = 1;
+       goto DONE;
+      }
+      target = atoi (argv[i]);
+      if (!target) {
+       fprintf (stderr,
+         "*** lingeling error: invalid literal in '-a %d'\n", target);
+       res = 1;
+       goto DONE;
+      }
+      lglpushtarget (target);
+    } else if (!strcmp (argv[i], "-m")) {
+      if (++i == argc) {
+       fprintf (stderr, "*** lingeling error: argument to '-m' missing\n");
+       res = 1;
+       goto DONE;
+      }
+      if (!multiple && ntargets > 0) {
+       fprintf (stderr, "*** lingeling error: unexpectd '-m' after '-a'\n");
+       res = 1;
+       goto DONE;
+      }
+      target = atoi (argv[i]);
+      if (!target) {
+       fprintf (stderr,
+         "*** lingeling error: invalid literal in '-m %d'\n", target);
+       res = 1;
+       goto DONE;
+      }
+      lglpushtarget (target);
+      multiple = 1;
+    } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--defaults")) {
+      lglopts (lgl, "", 0);
+      goto DONE;
+    } else if (!strcmp (argv[i], "-e") || !strcmp (argv[i], "--embedded")) {
+      lglopts (lgl, "c ", 1);
+      goto DONE;
+    } else if (!strcmp (argv[i], "-r") || !strcmp (argv[i], "--ranges")) {
+      lglrgopts (lgl);
+      goto DONE;
+    } else if (!strcmp (argv[i], "-P") || !strcmp (argv[i], "--pcs")) {
+      printf ("# generated by 'lingeling --pcs'\n");
+      printf ("# version %s\n", lglversion ());
+      lglpcs (lgl, 0);
+      goto DONE;
+    } else if (!strcmp (argv[i], "--pcs-mixed")) {
+      printf ("# generated by 'lingeling --pcs-mixed'\n");
+      printf ("# version %s\n", lglversion ());
+      lglpcs (lgl, 1);
+      goto DONE;
+    } else if (!strcmp (argv[i], "--pcs-reduced")) {
+      printf ("# generated by 'lingeling --pcs-reduced'\n");
+      printf ("# version %s\n", lglversion ());
+      lglpcs (lgl, -1);
+      goto DONE;
+    } else if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--force")) {
+      ignmissingheader = 1;
+    } else if (!strcmp (argv[i], "-i") || !strcmp (argv[i], "--ignore")) {
+      ignaddcls = 1;
+    } else if (!strcmp (argv[i], "-n") || !strcmp (argv[i], "no-witness")) {
+      lglsetopt (lgl, "witness", 0);
+    } else if (argv[i][0] == '-') {
+      if (argv[i][1] == '-') {
+       match = strchr (argv[i] + 2, '=');
+       if (match) {
+         p = match + 1;
+         if (*p == '-') p++;   // TODO for what is this useful again?
+         len = p - argv[i];
+         if (!strncmp (argv[i], "--write-api-trace=", len)) {
+           // TODO not handled yet ...
+           continue;
+         } else if (!strncmp (argv[i], "--thanks=", len)) {
+           thanks = match + 1;
+           continue;
+         } else if (!isdigit (*p)) {
+ERR:
+            fprintf (stderr,
+             "*** lingeling error: invalid command line option '%s'\n",
+             argv[i]);
+           res = 1;
+           goto DONE;
+         }
+         while (*++p) if (!isdigit (*p)) goto ERR;
+         len = match - argv[i] - 2;
+         tmp = malloc (len + 1);
+         j = 0;
+         for (p = argv[i] + 2; *p != '='; p++) tmp[j++] = *p;
+         tmp[j] = 0;
+         val = atoi (match + 1);
+       } else if (!strncmp (argv[i], "--no-", 5)) {
+         tmp = strdup (argv[i] + 5);
+         val = 0;
+       } else {
+         tmp = strdup (argv[i] + 2);
+         val = lglgetopt (lgl, tmp) + 1;
+       }
+       if (!lglhasopt (lgl, tmp)) { free (tmp); goto ERR; }
+       lglsetopt (lgl, tmp, val);
+       free (tmp);
+      } else {
+       if (argv[i][2]) goto ERR;
+       if (!lglhasopt (lgl, argv[i] + 1)) goto ERR;
+       val = lglgetopt (lgl, argv[i] + 1) + 1;
+       lglsetopt (lgl, argv[i] + 1, val);
+      }
+    } else if (iname) {
+      fprintf (stderr, "*** lingeling error: can not read '%s' and '%s'\n",
+               iname, argv[i]);
+      res = 1;
+      goto DONE;
+    } else iname = argv[i];
+  }
+  verbose = lglgetopt (lgl, "verbose");
+  if (verbose >= 0) {
+    lglbnr ("Lingeling SAT Solver", "c ", stdout);
+    if (simponly) printf ("c simplifying only\n");
+    if (oname) printf ("c output file %s\n", oname);
+    if (simponly || oname) fflush (stdout);
+    lglsetopt (lgl, "trep", 1);
+  }
+  if (thanks) {
+    unsigned seed = 0, i = 0, ch;
+    int iseed;
+    for (p = thanks; (ch = *p); p++) {
+      seed += primes[i++] * ch;
+      if (i == nprimes) i = 0;
+    }
+    if (seed >= (unsigned) INT_MAX) seed >>= 1;
+    assert (seed <= (unsigned) INT_MAX);
+    iseed = (int) seed;
+    assert (iseed >= 0);
+    if (verbose)
+      printf ("c will have to thank %s (--seed=%d)\nc\n",
+       thanks, iseed);
+    lglsetopt (lgl, "seed", iseed);
+  }
+  if (verbose >= 2) {
+   printf ("c\nc options after command line parsing:\nc\n");
+   lglopts (lgl, "c ", 0);
+   printf ("c\n");
+   lglsizes (lgl);
+   printf ("c\n");
+  }
+  if (iname) {
+    len = strlen (iname);
+    if (len >= 3 && !strcmp (iname + len - 3, ".gz")) {
+      if (verbose >= 1) printf ("c piping '%s' through 'gunzip'\n", iname);
+      tmp = malloc (len + 20);
+      sprintf (tmp, "gunzip -c %s", iname);
+      in = popen (tmp, "r");
+      if (in) clin = 2;
+      free (tmp);
+    } else if (len >= 5 && !strcmp (iname + len - 5, ".lzma")) {
+      if (verbose >= 1) printf ("c piping '%s' through 'lzcat'\n", iname);
+      tmp = malloc (len + 20);
+      sprintf (tmp, "lzcat %s", iname);
+      in = popen (tmp, "r");
+      if (in) clin = 2;
+      free (tmp);
+    } else if (len >= 4 && !strcmp (iname + len - 4, ".bz2")) {
+      if (verbose >= 1) printf ("c piping '%s' through 'bzcat'\n", iname);
+      tmp = malloc (len + 20);
+      sprintf (tmp, "bzcat %s", iname);
+      in = popen (tmp, "r");
+      if (in) clin = 2;
+      free (tmp);
+    } else if (len >= 3 && !strcmp (iname + len - 3, ".7z")) {
+      if (verbose >= 1) printf ("c piping '%s' through '7z'\n", iname);
+      tmp = malloc (len + 40);
+      sprintf (tmp, "7z x -so %s 2>/dev/null", iname);
+      in = popen (tmp, "r");
+      if (in) clin = 2;
+      free (tmp);
+    } else {
+      in = fopen (iname, "r");
+      if (in) clin = 1;
+    }
+    if (!in) {
+      fprintf (stderr,
+         "*** lingeling error: can not read input file %s\n", iname);
+      res = 1;
+      goto DONE;
+    }
+  } else iname = "<stdin>", in = stdin;
+  if (pname) {
+    pfile = fopen (pname, "r");
+    if (!pfile) {
+      fprintf (stderr,
+        "*** lingeling error: can not read option file %s\n", pname);
+      res = 1;
+      goto DONE;
+    }
+    if (verbose >= 0) {
+      printf ("c reading options file %s\n", pname);
+      fflush (stdout);
+    }
+    nopts = lglreadopts (lgl, pfile);
+    if (verbose >= 0) 
+      printf ("c read and set %d options\nc\n", nopts), fflush (stdout);
+    fclose (pfile);
+  }
+  if (verbose >= 0) printf ("c reading input file %s\n", iname);
+  fflush (stdout);
+  if ((err = parse (lgl, in, &lineno))) {
+    fprintf (stderr, "%s:%d: %s\n", iname, lineno, err);
+    res = 1;
+    goto DONE;
+  }
+  closefile (in, clin);
+  clin = 0;
+  if (verbose >= 1) {
+    printf ("c\n");
+    if (verbose >= 2) printf ("c final options:\nc\n");
+    lglopts (lgl, "c ", 0);
+  }
+  if (timelimit >= 0) {
+    if (verbose >= 0) {
+      printf ("c\nc setting time limit of %d seconds\n", timelimit);
+      fflush (stdout);
+    }
+    lglseterm (lgl, checkalarm, &caughtalarm);
+    sig_alrm_handler = signal (SIGALRM, catchalrm);
+    alarm (timelimit);
+  }
+  if (multiple) lglpushtarget (0), ntargets--;
+  else for (i = 0; i < ntargets; i++) lglassume (lgl, targets[i]);
+  if (multiple) res = lglmosat (lgl, lgl, lglmonotifiy, targets);
+  else {
+    if (simplevel > 0) {
+      if (verbose >= 1) {
+       printf ("c simplifying with simplification level %d\n", simplevel);
+       fflush (stdout);
+      }
+      res = lglsimp (lgl, simplevel);
+      if (verbose >= 1) {
+       printf ("c simplifying result %d after %.2f seconds\n",
+         res, lglsec (lgl));
+       fflush (stdout);
+      }
+    } else res = 0;
+    res = lglsat (lgl);
+  }
+  if (timelimit >= 0) {
+    caughtalarm = 0;
+    (void) signal (SIGALRM, sig_alrm_handler);
+  }
+  if (oname) {
+    double start = lglsec (lgl), delta;
+    if (!strcmp (oname, "-")) out = stdout, oname = "<stdout>", clout = 0;
+    else if (!(out = writefile (oname, &clout))) { res = 1; goto DONE; }
+    if (verbose >= 0) {
+      count = 0;
+      lglctrav (lgl, &count, lgltravcounter);
+      printf ("c\nc writing 'p cnf %d %d' to '%s'\n",
+             lglmaxvar (lgl), count, oname);
+      fflush (stdout);
+    }
+    lglprint (lgl, out);
+    closefile (out, clout);
+    if (verbose >= 0) {
+      delta = lglsec (lgl) - start; if (delta < 0) delta = 0;
+      printf ("c collected garbage and wrote '%s' in %.1f seconds\n", 
+              oname, delta);
+      printf ("c\n"), fflush (stdout);
+    }
+  }
+  if (!simponly || verbose >= 0) {
+    if (simponly) fputs ("c ", stdout);
+    if (res == 10) fputs ("s SATISFIABLE\n", stdout);
+    else if (res == 20) fputs ("s UNSATISFIABLE\n", stdout);
+    else fputs ("c s UNKNOWN\n", stdout);
+    if (thanks) printf ("c\nc Thanks to %s!\nc\n", thanks);
+    fflush (stdout);
+    if (res == 10 && lglgetopt (lgl, "witness")) {
+      obuf.pos = 0;
+      maxvar = lglmaxvar (lgl);
+      for (i = 1; i <= maxvar; i++) {
+       lit = (lglderef (lgl, i) > 0) ? i : -i;
+       print2obuf (&obuf, lit, simponly, stdout);
+      }
+      print2obuf (&obuf, 0, simponly, stdout);
+      if (obuf.pos > 0) flushobuf (&obuf, simponly, stdout);
+      fflush (stdout);
+    }
+  }
+  if (verbose >= 0) fputs ("c\n", stdout), lglstats (lgl);
+DONE:
+  closefile (in, clin);
+  resetsighandlers ();
+  lgl4sigh = 0;
+  lglrelease (lgl);
+  free (targets);
+  return res;
+}
diff --git a/lingeling/code/makefile.in b/lingeling/code/makefile.in
new file mode 100644 (file)
index 0000000..1ff2f0d
--- /dev/null
@@ -0,0 +1,88 @@
+MAKEFLAGS=-j $(if $(CORES),$(CORES),1)
+
+CC=@CC@
+CFLAGS=@CFLAGS@
+
+LIBS=@LIBS@
+LDEPS=@LDEPS@
+HDEPS=@HDEPS@
+AIGER=@AIGER@
+
+all: targets
+
+-include makefile.bcd
+-include makefile.tune
+-include makefile.mus
+-include makefile.other
+
+targets: liblgl.a
+targets: lingeling plingeling ilingeling treengeling
+targets: lglmbt lgluntrace lglddtrace
+targets: @AIGERTARGETS@
+
+analyze:
+       clang --analyze $(CFLAGS) $(shell ls *.c *.h)
+
+liblgl.a: lglib.o lglbnr.o lgldimacs.o makefile
+       ar rc $@ lglib.o lglbnr.o lgldimacs.o
+       ranlib $@
+
+lingeling: lglmain.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -o $@ lglmain.o -L. -llgl $(LIBS)
+plingeling: plingeling.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -pthread -o $@ plingeling.o -L. -llgl $(LIBS)
+treengeling: treengeling.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -pthread -o $@ treengeling.o -L. -llgl $(LIBS)
+blimc: blimc.o liblgl.a makefile $(AIGER)/aiger.o $(LDEPS)
+       $(CC) $(CFLAGS) -o $@ blimc.o -L. $(AIGER)/aiger.o -llgl $(LIBS)
+ilingeling: ilingeling.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -pthread -o $@ ilingeling.o -L. -llgl $(LIBS)
+lglmbt: lglmbt.o liblgl.a $(LDEPS)
+       $(CC) $(CFLAGS) -o $@ lglmbt.o -L. -llgl $(LIBS)
+lgluntrace: lgluntrace.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -o $@ lgluntrace.o -L. -llgl $(LIBS)
+lglddtrace: lglddtrace.o liblgl.a makefile $(LDEPS)
+       $(CC) $(CFLAGS) -o $@ lglddtrace.o -L. -llgl $(LIBS)
+
+lglmain.o: lglmain.c lglib.h makefile
+       $(CC) $(CFLAGS) -c lglmain.c
+plingeling.o: plingeling.c lglib.h makefile
+       $(CC) $(CFLAGS) -c plingeling.c
+treengeling.o: treengeling.c lglib.h makefile
+       $(CC) $(CFLAGS) -c treengeling.c
+ilingeling.o: ilingeling.c lglib.h makefile
+       $(CC) $(CFLAGS) -c ilingeling.c
+blimc.o: blimc.c lglib.h $(AIGER)/aiger.h makefile
+       $(CC) $(CFLAGS) -I$(AIGER) -c -o $@ blimc.c
+lglmbt.o: lglmbt.c lglib.h makefile
+       $(CC) $(CFLAGS) -c lglmbt.c
+lgluntrace.o: lgluntrace.c lglib.h makefile
+       $(CC) $(CFLAGS) -c lgluntrace.c
+lglddtrace.o: lglddtrace.c lglib.h makefile
+       $(CC) $(CFLAGS) -c lglddtrace.c
+
+lglib.o: lglib.c lglib.h makefile $(HDEPS)
+       $(CC) $(CFLAGS) -c lglib.c
+lgldimacs.o: lgldimacs.c lgldimacs.h makefile
+       $(CC) $(CFLAGS) -c lgldimacs.c
+lglbnr.o: lglbnr.c lglcfg.h lglcflags.h makefile
+       $(CC) $(CFLAGS) -c lglbnr.c
+
+lglcfg.h: VERSION mkconfig.sh lglbnr.c lglib.c lglmain.c lglcflags.h makefile
+       rm -f $@
+       ./mkconfig.sh > $@
+lglcflags.h: makefile
+       rm -f $@
+       echo '#define LGL_CC "$(shell $(CC) --version|head -1)"' >> $@
+       echo '#define LGL_CFLAGS "$(CFLAGS)"' >> $@
+
+clean: clean-all clean-config
+clean-config:
+       rm -f makefile lglcfg.h lglcflags.h
+clean-all:
+       rm -f lingeling plingeling ilingeling treengeling blimc
+       rm -f lglmbt lgluntrace lglddtrace
+       rm -f *.gcno *.gcda cscope.out gmon.out *.gcov *.gch *.plist
+       rm -f *.E *.o *.s *.a log/*.log 
+
+.PHONY: all targets clean clean-config clean-all
diff --git a/lingeling/code/mkconfig.sh b/lingeling/code/mkconfig.sh
new file mode 100755 (executable)
index 0000000..6e14bd2
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+die () {
+   echo "*** mkconfig.sh: $*" 1>&2
+   exit 1
+}
+
+[ -f makefile ] || die "can not find 'makefile'"
+
+cat<<EOF
+/*************************************************************/
+/* Automatically generated by './mkconfig.sh': do note edit! */
+/*************************************************************/
+EOF
+
+echo "#define LGL_OS \"`uname -srmn`\""
+echo "#define LGL_COMPILED \"`date`\""
+cat<<EOF
+#define LGL_RELEASED "Tue Apr 29 19:18:48 CEST 2014"
+#define LGL_VERSION "ayv"
+#define LGL_ID "86bf266b9332599f1b876e28a02fe8427aeaa2db"
+EOF
diff --git a/lingeling/license.txt b/lingeling/license.txt
new file mode 100644 (file)
index 0000000..b268295
--- /dev/null
@@ -0,0 +1,39 @@
+Copyright (c) 2010 - 2014, Armin Biere, Johannes Kepler University.
+
+Permission is hereby granted, free of charge, to use this software for
+evaluation and research purposes.
+
+This license does not allow this software to be used in a commercial context.
+
+It is further prohibited to use this software or a substantial portion of it
+in a competition or a similar competitive event, such as the SAT, SMT or QBF
+competitions or evaluations, without explicit written permission by the
+copyright holder.
+
+However, competition organizers are allowed to use this software as part of
+the evaluation process of a particular competition, evaluation or
+competitive event, if the copyright holder of this software submitted this
+software to this particular competition, evaluation or event explicitly.
+
+This permission of using the software as part of a submission by the
+copyright holder to a competition, evaluation or competitive event is only
+granted for one year and only for one particular instance of the competition
+to which this software was submitted by the copyright holder.
+
+If a competition, evaluation or competitive event has multiple tracks,
+categories or sub-competitions, this license is only granted for the tracks
+respectively categories or sub-competitions, to which the software was
+explicitly submitted by the copyright holder.
+
+All other usage is reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/lingeling/readme.txt b/lingeling/readme.txt
new file mode 100644 (file)
index 0000000..92f0a83
--- /dev/null
@@ -0,0 +1,13 @@
+Lingeling SAT Solver Version ayv-86bf266-140429
+
+./configure && make
+
+This software is copyright 2010-2013, Armin Biere, JKU, Linz.  
+
+This is only a restricted release of this software.
+
+See 'COPYING' for more details on the permission to use this software.
+
+All rights are reserved.  No warranty is implied.
+
+Armin Biere
diff --git a/zchaff64/Makefile b/zchaff64/Makefile
new file mode 100644 (file)
index 0000000..44c14f0
--- /dev/null
@@ -0,0 +1,68 @@
+CC = g++ -Wall
+CFLAGS = -O3 
+
+#CFLAGS = -O3 -DNDEBUG
+#MFLAGS = 
+#LINKFLAGS = --static
+
+ifeq (solaris, $(OSTYPE))
+  MFLAGS = -D_NEED_REDEFINE_RAND_MAX_
+endif
+
+RANLIB = ranlib
+AR = ar
+
+.SUFFIXES: .o .cpp 
+
+HEADERS = zchaff_base.h zchaff_clsgen.h zchaff_header.h zchaff_version.h zchaff_dbase.h zchaff_solver.h
+
+SOLVER_SRCS = sat_solver.cpp 
+SOLVER_OBJS = $(SOLVER_SRCS:.cpp=.o)
+                  
+
+LIB_SRCS =  zchaff_utils.cpp \
+           zchaff_solver.cpp\
+           zchaff_base.cpp \
+           zchaff_dbase.cpp \
+           zchaff_c_wrapper.cpp \
+           zchaff_cpp_wrapper.cpp \
+
+LIB_OBJS = $(LIB_SRCS:.cpp=.o)
+
+
+zchaff:   $(SOLVER_OBJS) libsat.a SAT.h
+         $(CC) $(LINKFLAGS) $(CFLAGS) $(MFLAGS) $(SOLVER_OBJS) libsat.a -o zchaff 
+
+zverify_df: zverify_df.cpp
+         $(CC) $(LINKFLAGS) $(CFLAGS) $(MFLAGS) zverify_df.cpp -o zverify_df
+
+zminimal: zminimal.cpp libsat.a
+         $(CC) $(LINKFLAGS) $(CFLAGS) $(MFLAGS) zminimal.cpp libsat.a -o zminimal
+
+cnf_stats: cnf_stats.cpp
+         $(CC) $(LINKFLAGS) $(CFLAGS) $(MFLAGS) cnf_stats.cpp -o cnf_stats
+
+$(LIB_OBJS): $(HEADERS) Makefile
+
+$(SOLVER_OBJS): $(SOLVER_SRCS) SAT.h Makefile
+
+zchaff_c_wrapper.cpp:  zchaff_wrapper.wrp
+               sed 's/EXTERN/extern \"C\"/' zchaff_wrapper.wrp > zchaff_c_wrapper.cpp
+
+zchaff_cpp_wrapper.cpp:        zchaff_wrapper.wrp
+               sed 's/EXTERN//' zchaff_wrapper.wrp > zchaff_cpp_wrapper.cpp
+SAT_C.h:
+       sed 's/gid = 0/gid/' SAT.h > SAT_C.h
+
+libsat.a:   $(LIB_OBJS)
+       @rm -f libsat.a
+       $(AR) cr libsat.a $(LIB_OBJS)
+       $(RANLIB) libsat.a
+
+.cpp.o:
+       $(CC) $(CFLAGS) $(MFLAGS) -c $< 
+
+clean: 
+       rm -f *.o libsat.a zchaff *wrapper.cpp zminimal zverify_df cnf_stats SAT_C.h
+
+all: zchaff zverify_df zminimal cnf_stats
diff --git a/zchaff64/README b/zchaff64/README
new file mode 100644 (file)
index 0000000..ec90311
--- /dev/null
@@ -0,0 +1,124 @@
+This is the 64 bit version of zchaff.
+
+[2007.3.12]
+Fixed the inefficiency bug in zverify_df. Thanks to Allen Van Gelder and 
+Tjark Weber.
+
+[2004.11.15 Simplified]
+This is just a simplified version of 2004.5.13. Many portions of dead 
+codes are removed. Some of codes are re-written and re-formatted for 
+easy reading. You might experience a little speedup. Please switch back
+to 2004.5.13 if the functionalities you need are removed in the simplified 
+version.
+
+[2004.5.13]
+Some performace update. This is the version we used for SAT04 competition. 
+Please consult our website for the detailed description.
+
+[2003.12.04]
+Fixed:
+1. Various bugs in add_clause_incr(). We would like to thank Alexander 
+   Smith from University of Toronto for his suggestion and experiments on 
+   this issue.
+2. SAT_HOOK added.
+3. unset_force_terminate added.
+
+[2003.11.04]
+Fixed:
+1. Compile under g++ 3.3 and above
+2. Assertion error for certain instances in core extraction
+3. A typo in run_till_fix. Now it takes the second argument as the max 
+number of iterations to run as intended.
+
+[2003.10.09]
+Fixes in this release:
+1. Bug fixed for time overflow after 2147 seconds.
+2. The Perl script run_till_fix is updated such that it works for cnf 
+files located in other directory.
+3. zverify_df.cpp now also verifies the conflict clause given in 
+resolve_trace with the one constructed by zverify itself using the 
+information given in resolve_trace.
+[2003.7.22]
+NOTE: If your code is in C instead of C++, please use SAT_C.h instead of 
+SAT.h as the header file. 
+
+This is a new (as of June, 2003)  release of zchaff, a SAT solver from
+Princeton University. The main difference between this one and the 
+previous (2001.2.17) version are listed in the following:
+1. This version of zchaff has incremental SAT solving capability
+   In practice, many SAT instances are related in the sense that they only
+   differ in a small number of clauses. Zchaff can solve a set of
+   such instances incrementally, leveraging the knowledge (clauses) learned
+   from previous runs to help current runs. This feature can only be invoked
+   through the functional call interface. Please read SAT.h for more
+   information about assigning clauses with Group IDs and how to delete
+   clause or add clauses by groups.
+                                                                                
+                                    
+2. This version of zchaff is certifiable
+   Now zchaff can produce a verifiable trace that can be checked by a third
+   party checker. To invoke this, modify zchaff_solver.cpp and uncomment
+   #define VERIFY_ON and compile again. Now zchaff will produce a trace
+   called resolution_trace after each run and this can be checked by
+   zverify_bf or zverify_df, which are two checkers based on breadth-first 
+   and depth-first search.
+                                                                                
+                                    
+3. This version of zchaff can produce an unsatisfiable core from an 
+   unsatisifable formula Unsatisfiable core extraction can be useful for 
+   some applications. This version of zchaff implement the idea presented 
+   in our SAT 2003 paper about extracting unsat cores.
+                                                                                
+4. This version can compile under gcc 3.x.
+                                    
+5. This version fixed a couple of serious bugs in the previous version. 
+   (But may have introduced other bugs :().
+                                                                                
+                                    
+How to Install:
+  Use "make" to compile, or "make all" to compile zchaff with extra utilities
+  (e.g. core extractor, verifier). It should work without any problem 
+  under Linux, Cygwin or Solaris.
+
+  To compile a native Windows executable, Open Visual Studio .Net, create
+  a project, and add these files into the project:
+  zchaff_base.cpp, 
+  zchaff_cpp_wrapper.cpp (this can be obtained by rename 
+  zchaff_wrapper.wrp to zchaff_cpp_wrapper.cpp and delete all occurance of 
+  "EXTERN" in the file.)
+  zchaff_dbase.cpp
+  zchaff_solver.cpp
+  zchaff_utils.cpp
+  sat_solver.cpp
+
+  Also, modify files that contain headers "sys/*.h". Delete those troublesome 
+  headers, replace them with "#include <time.h>", and replace the code for 
+  function get_cpu_time() with:
+
+        double get_cpu_time(void) {
+                return  (double)clock()/(double)(CLOCKS_PER_SEC);
+        } 
+  This function will overflow after 2147 seconds. So the reported time 
+  may not be correct. This is a temporary solution and hopefully we will fix it in 
+  the future.
+  MSVC will report a lot of warnings. Hopefully none is serious. :(. As 
+  you suspected, zchaff is not tested under native Windows enviroment. 
+  But anyway, this is the hack. 
+
+How to use: 
+  the main executable is zchaff. The command line is 
+                zchaff CNF_FILE [TimeLimit]
+  Other executables will print out a help info when executed with no 
+  argument.
+
+  run_till_fix can obtain a small core by iteratively run core extraction. 
+  Do turn
+  VERIFY_ON in zchaff_solver.cpp when compile. 
+
+For any questions or bug reports, please send email to 
+Yogesh Mahajan at yogism@Princeton.EDU
+
+Thanks.
+
+The SAT Group at Princeton University
diff --git a/zchaff64/SAT.h b/zchaff64/SAT.h
new file mode 100644 (file)
index 0000000..b501aca
--- /dev/null
@@ -0,0 +1,446 @@
+// /*********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************/
+
+#ifndef __SAT_HEADER__
+#define __SAT_HEADER__
+
+#define SAT_Manager void *
+
+typedef long long long64;  // this is for 32 bit unix machines
+// typedef long long64;     // this is for Windows or 64 bit unix machines
+
+
+#ifndef _SAT_STATUS_
+#define _SAT_STATUS_
+enum SAT_StatusT {
+    UNDETERMINED,
+    UNSATISFIABLE,
+    SATISFIABLE,
+    TIME_OUT,
+    MEM_OUT,
+    ABORTED
+};
+#endif
+
+#ifndef _CLS_STATUS_
+#define _CLS_STATUS_
+enum CLAUSE_STATUS {
+    ORIGINAL_CL,
+    CONFLICT_CL,
+    DELETED_CL,
+};
+#endif
+
+#ifndef UNKNOWN
+#define UNKNOWN         2
+#endif
+
+// /*============================================================
+//
+// This is the header for using the sat solver. A typical flow is
+//
+// 1. calling SAT_InitManager to get a new manager. You can pre-set
+//    the number of variables upfront, or you can add it later by
+//    SAT_AddVariable.
+//    Variables are indexed from 1, NOT 0.
+//
+// 2. add clauses by calling SAT_AddClause. Clause is represented by
+//    an array of integers. Each literal is represented by
+//    2 * VarIndex + Sign. The Sign is 0 for positive phased literals,
+//    and 1 for negative phased literals.
+//    For example, a clause (3 -5 11 -4 ) should be represented by
+//    { 6, 11, 22, 9 }
+//    Note: Each variable can occure no more than once in a clause.
+//    if a variable occures in both phase, the clause is automatically
+//    satisfied. If more than one occurance with same phase, they
+//    should be combined. IT IS YOUR RESPONSIBILITY TO KEEP EACH
+//    CLAUSE NON-REDUNDENT, or the solver will not function correctly.
+//
+// 3. zchaff support incremental SAT solving. Clauses can be added
+//    or deleted from the database after each run. To accomplish
+//    this, a clause is associated with a "Group ID". Each clause
+//    has one Group ID. The group of clauses with the same GID can
+//    be deleted from the database by calling SAT_DeleteClauseGroup
+//    after each run. You need to call SAT_Reset to reset the state
+//    of the solver before begining a new run.
+//    As an example, the first 10 clauses are associated with GID 1,
+//    We add another 2 clauses with GID 2. After solving this instance
+//    with 12 clauses, we may want to delete the last 2 clauses and
+//    add another 3 clauses. We call SAT_DeleteClauseGroup with GID
+//    2 and add the three clauses (these three clauses can have any
+//    GID: either 1 if you don't want to delete them in the future,
+//    2 if you want to distinguish them from Group 1). Then you should
+//    call SAT_Reset() to reset the state of the solver, and call
+//    SAT_Solve() again to solve the new instance (a instance with
+//    13 clauses).
+//    You should obtain free GID using SAT_AllocClauseGroupID. When
+//    you call SAT_DeleteClauseGroup, the gid will be freed and can
+//    be re-used when you call SAT_AllocClauseGroupID() again.
+//    You can also merge two group of clauses into 1 by calling
+//    corresponding functions.
+//
+// 4. Optionally, you may set the time limit and memory limit for
+//    the solver, note: time and memory limits are not exact.
+//    Also, you can set other paramenters like clause deletion
+//    etc.
+//
+// 5. You can add hook function to do some extra work after
+//    a certain number of decisions (branchings). A hook function
+//    should accept input of a manager, and has no return value.
+//
+// 6. Calling SAT_Solve to solve the problem. it will return the
+//    status of the solver.
+//
+// 7. If the problem is satisfiable, you can call SAT_GetVarAsgnment
+//    to get a variable assignment which satisfy the problem.
+//
+// 8. You can also get some statistics from the solver, such as
+//    run time, mem usage, etc.
+//
+// 9. Release the manager by calling SAT_ReleaseManager.
+//
+// You need to link the library libsat.a, also, though you can compile
+// your C program with c compiler when using this sat solver, you
+// still need c++ linker to link the library.
+//
+// Have fun.
+//                         The Chaff Team
+//                         (contact zfu@EE.Princeton.EDU
+//                         for any questions or suggestions)
+//                         2004. 3. 10
+// =============================================================*/
+
+
+// Following are the main functions for the flow.
+
+// init a manager
+SAT_Manager SAT_InitManager(void);
+
+// get the version of the solver
+char * SAT_Version(SAT_Manager mng);
+
+// release a manager
+void SAT_ReleaseManager(SAT_Manager mng);
+
+// set the number of variables.
+void SAT_SetNumVariables(SAT_Manager mng,
+                         int num_vars);
+
+// add a variable. it will return the new var's index
+int SAT_AddVariable(SAT_Manager mng);
+
+// the following functions will allow/disallow the variable to be branched
+// user may want to branch only on certain variables (for example, primary
+// inputs of a circuit, if the CNF is generated from circuit).
+// By default, all variables are branchable, usually, if a variable is
+// unbranchable, it's value should be determined by all the branchable variables.
+// if that's not the case, then these variables may not get an assigned
+// value even if the solver says that the problem is satisfiable.
+// Notice, the solver determines if a problem is satisfiable by trying to assign
+// all the branchable variables. If all such variables can be assigned values
+// without causing conflict, then the instance is reported as satisfiable, even
+// if the instance is actually unsatisfiable because of unbranchable
+// variables being not dependent on branchable variables.
+void SAT_EnableVarBranch(SAT_Manager mng, int vid);
+
+void SAT_DisableVarBranch(SAT_Manager mng, int vid);
+// add a clause. a literal is a integer with value 2*V_idx + sign
+// gid is the group ID. by default, gid equals 0 . Note: group 0
+// clauses can't be deleted.
+void SAT_AddClause(SAT_Manager          mng,
+                   int *                clause_lits,
+                   int                  num_lits,
+                   int                  gid = 0);
+
+// delete a clause group and learned clauses depending on them.
+void SAT_DeleteClauseGroup(SAT_Manager          mng,
+                           int                  gid);
+
+// This will reset the solver so it will not keep the implications made before
+void SAT_Reset(SAT_Manager mng);
+
+// merge the clause group gid1 with gid2, return a new group which
+// contain both groups.
+int SAT_MergeClauseGroup(SAT_Manager    mng,
+                         int            gid1,
+                         int            gid2);
+
+// Allocate a free clause group id. will be -1 if no more available.
+// current implementation allow 32 deletable group IDs ranging from
+// 1-32. Group 0 is the permanent group (i.e. can't delete).
+int SAT_AllocClauseGroupID(SAT_Manager mng);
+
+// followings are for clause gid manipulation
+int SAT_IsSetClauseGroupID(SAT_Manager mng, int cl_idx, int id);
+int SAT_SetClauseGroupID(SAT_Manager mng, int cl_idx, int id);
+int SAT_ClearClauseGroupID(SAT_Manager mng, int cl_idx, int id);
+// clauses belong to volatile group will always be deleted when
+// SAT_DeleteClauseGroup is called
+int SAT_GetVolatileGroupID(SAT_Manager mng);
+// clauses belong to global group will never be deleted
+int SAT_GetGlobalGroupID(SAT_Manager mng);
+
+
+void SAT_SetTimeLimit(SAT_Manager       mng,
+                      float             runtime);
+
+// note: memory estimation is very rough, so allow 30% of error
+// in both SetMemLimit and EstimateMemUsage. Also, in the run
+// time, the memory usage could be temporarily 50% larger than
+// the limit (this occours when program reallocate memory because
+// of insufficiency in the initial allocation).
+void SAT_SetMemLimit(SAT_Manager        mng,
+                     int                num_bytes);
+
+
+int SAT_Solve(SAT_Manager mng);
+// enum SAT_StatusT
+// Get a variable's assignment. -1 means UNKNOWN or undicided
+int SAT_GetVarAsgnment(SAT_Manager      mng,
+                       int              v_idx);
+
+// this is used for randomness in decision making
+void SAT_SetRandomness(SAT_Manager      mng,
+                       int              n);
+// if the seed < 0, solver will use the day timer to
+// get a "psuedo real random" seed.
+void SAT_SetRandSeed(SAT_Manager        mng,
+                     int                seed);
+
+// add a hookfunction. This function will be called
+// every "interval" of decisions. You can add more than
+// one such hook functions. i.e. call SAT_AddHookFun more
+// than once.
+void SAT_AddHookFun(SAT_Manager         mng,
+                    void (*fun)(void *),
+                    int                 interval);
+
+// /* =======================================================
+// This function is for users who want to customize their own
+// decision making strategy.
+//
+// What you can do is add a hook function with interval of 1,
+// that function will be called before every decision. Inside
+// this hook function, use SAT_MakeDecision to make decision
+// with variable "vid" and "sign". sign = 1 means value of
+// the variable be 0.
+//
+// If there are no free variable left, problem is satisfied,
+// call SAT_MakeDecision with vid = 0 && sign = 0 will cause
+// solver exit with status "SATISFIABLE".
+//
+// Here is an example:
+//
+// void my_own_decision (SAT_Manager mng)
+// {
+// int n_var = SAT_NumVariables(mng);
+// int i;
+// for (i=1; i<n_var; ++i) {
+//   if (SAT_GetVarAsgnment(mng, i)==UNKNOWN){
+//     SAT_MakeDecision(mng, i, 1); //make decision with value 0;
+//     break;
+//   }
+// }
+// if (i >= n_var) //every var got an assignment, no free var left
+//   SAT_MakeDecision (mng, 0, 0);
+// }
+// ======================================================== */
+void SAT_MakeDecision(SAT_Manager        mng,
+                      int                vid,
+                      int                sign);
+
+// Following are statistics collecting functions
+int SAT_EstimateMemUsage(SAT_Manager mng);
+// time elapsed from last call of GetElapsedCPUTime
+float SAT_GetElapsedCPUTime(SAT_Manager mng);
+// current cpu time
+float SAT_GetCurrentCPUTime(SAT_Manager mng);
+// time spent on the whole solving process
+float SAT_GetCPUTime(SAT_Manager mng);
+
+int SAT_NumLiterals(SAT_Manager mng);
+
+int SAT_NumClauses(SAT_Manager mng);
+
+int SAT_NumVariables(SAT_Manager mng);
+
+int SAT_InitNumLiterals(SAT_Manager mng);
+
+int SAT_InitNumClauses(SAT_Manager mng);
+
+long64 SAT_NumAddedLiterals(SAT_Manager mng);
+
+int SAT_NumAddedClauses(SAT_Manager mng);
+
+int SAT_NumShrinkings(SAT_Manager mng);
+
+int SAT_NumDeletedClauses(SAT_Manager mng);
+
+int SAT_NumDelOrigCls(SAT_Manager mng);
+
+long64 SAT_NumDeletedLiterals(SAT_Manager mng);
+
+int SAT_NumDecisions(SAT_Manager mng);
+int SAT_NumDecisionsStackConf(SAT_Manager mng);
+int SAT_NumDecisionsVsids(SAT_Manager mng);
+int SAT_NumDecisionsShrinking(SAT_Manager mng);
+
+
+int SAT_Random_Seed(SAT_Manager mng);
+
+long64 SAT_NumImplications(SAT_Manager mng);
+
+int SAT_MaxDLevel(SAT_Manager mng);
+
+float SAT_AverageBubbleMove(SAT_Manager mng);
+// Following function will allow you to traverse all the
+// clauses and literals. Clause is represented by a index.
+// The original clauses' indice are not changed during the
+// whole process, while added clauses may get deleted, so
+// a certain index may not always represent the same
+// clause, also, a index may not always be valid.
+int SAT_GetFirstClause(SAT_Manager mng);
+
+// GetClauseType will get the clause's type. it can be
+// ORIGINAL_CL, CONFLICT_CL, PROBE_CL
+int SAT_GetClauseType(SAT_Manager mng, int cl_idx);
+
+// if there are no more clauses left, return value is -1.
+// the organization is like :
+// index 0 ... InitNumClauses - 1 are the original clauses
+// after that, they are added clauses.
+int SAT_GetNextClause(SAT_Manager mng, int cl_idx);
+
+int SAT_GetClauseNumLits(SAT_Manager mng, int cl_idx);
+
+// the lits array should have been pre-allocated enough memory
+// to store all the lits of a clause. Use SAT_GetClauseNumLits to find
+// out before-hand how much memory is required.
+void SAT_GetClauseLits(SAT_Manager mng, int cl_idx,  int * lits);
+
+// Following functions dictate the run time behavior
+// Don't mess with them unless you know what you are doing
+void SAT_EnableConfClsDeletion(SAT_Manager mng);
+void SAT_DisableConfClsDeletion(SAT_Manager mng);
+void SAT_SetClsDeletionInterval(SAT_Manager mng, int freq);
+
+void SAT_SetMaxUnrelevance(SAT_Manager mng, int n);
+void SAT_SetMinClsLenForDelete(SAT_Manager mng, int n);
+void SAT_SetMaxConfClsLenAllowed(SAT_Manager mng, int n);
+
+//  void SAT_AllowMultipleConflicts(SAT_Manager mng);
+//  void SAT_AllowMultipleConfCls(SAT_Manager mng);
+//  void SAT_SetLitPoolCompactRatio(SAT_Manager mng, float ratio);
+//  void SAT_SetLitPoolExpantionRatio(SAT_Manager mng, float ration);
+
+// this function cleans all learned clauses in the database.
+// it can be called if you incrementally solving many instances and
+// the learned clauses occupy too much memory. By calling
+// this function, it essentially equal to a fresh restart, i.e. throw
+// away the learned clauses obtained so far.
+void SAT_CleanUpDatabase(SAT_Manager mng);
+
+// Followings are functions to facilitate the translation from
+// Circuit to a CNF representation. It will automatically generate
+// the necessary clauses to represent the gates.
+// Note: The input convension are the same as in AddClause,
+//      e.g. 2 * Vid + Sign
+// NOTE: You need to make sure that the signals (a, b, c, o etc) are
+// distinctive. I.e. the two inputs to a AND2 gate are different
+// signals. Otherwise, the solver may behave incorrectly. Don't
+// add a gate that has signal a and a' as inputs. You should do
+// these kinds of special case simplifications by yourself.
+
+
+void SAT_GenClsAnd2(SAT_Manager         mng,
+                    int                 a,
+                    int                 b,
+                    int                 o,
+                    int                 gid = 0);
+
+void SAT_GenClsAndN(SAT_Manager         mng,
+                    int *               inputs,
+                    int                 num_inputs,
+                    int                 o,
+                    int                 gid = 0);
+
+void SAT_GenClsOr2(SAT_Manager          mng,
+                   int                  a,
+                   int                  b,
+                   int                  o,
+                   int                  gid = 0);
+
+void SAT_GenClsOrN(SAT_Manager          mng,
+                   int *                inputs,
+                   int                  num_inputs,
+                   int                  o,
+                   int                  gid = 0);
+
+void SAT_GenClsNand2(SAT_Manager        mng,
+                     int                a,
+                     int                b,
+                     int                o,
+                     int                gid = 0);
+
+void SAT_GenClsNandN(SAT_Manager        mng,
+                     int *              inputs,
+                     int                num_inputs,
+                     int                o,
+                     int                gid = 0);
+
+void SAT_GenClsNor2(SAT_Manager         mng,
+                    int                 a,
+                    int                 b,
+                    int                 o,
+                    int                 gid = 0);
+
+void SAT_GenClsNorN(SAT_Manager         mng,
+                   int *                inputs,
+                   int                  num_inputs,
+                   int                  o,
+                   int                  gid = 0);
+
+void SAT_GenClsXor(SAT_Manager          mng,
+                   int                  a,
+                   int                  b,
+                   int                  o,
+                   int                  gid = 0);
+
+void SAT_GenClsNot(SAT_Manager          mng,
+                   int                  a,
+                   int                  o,
+                   int                  gid = 0);
+
+#endif
diff --git a/zchaff64/cnf_stats.cpp b/zchaff64/cnf_stats.cpp
new file mode 100644 (file)
index 0000000..7e928de
--- /dev/null
@@ -0,0 +1,110 @@
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstdio>
+
+#include <set>
+#include <vector>
+#include <assert.h>
+
+using namespace std;
+
+const int MAX_WORD_LENGTH       = 64;
+const int MAX_LINE_LENGTH       = 256000;
+
+int main(int argc, char** argv) {
+  assert(argc == 2);
+  char * filename = argv[1];
+  int line_num = 0;
+  char line_buffer[MAX_LINE_LENGTH];
+  char word_buffer[MAX_WORD_LENGTH];
+  set<int> clause_vars;
+  set<int> clause_lits;
+  int num_cls = 0;
+  vector<bool> variables;
+  int var_num;
+  int cl_num;
+  ifstream inp(filename, ios::in);
+  if (!inp) {
+    cerr << "Can't open input file" << endl;
+    exit(1);
+  }
+  while (inp.getline(line_buffer, MAX_LINE_LENGTH)) {
+    ++line_num;
+    if (line_buffer[0] == 'c') {
+      continue;
+    }
+    else if (line_buffer[0] == 'p') {
+      int arg = sscanf(line_buffer, "p cnf %d %d", &var_num, &cl_num);
+      if (arg < 2) {
+        cerr << "Unable to read number of variables and clauses"
+             << "at line " << line_num << endl;
+        exit(3);
+      }
+      variables.resize(var_num + 1);
+      for (int i = 0; i < var_num + 1; ++i)
+        variables[i] = false;
+    } else {                             // Clause definition or continuation
+      char *lp = line_buffer;
+      do {
+        char *wp = word_buffer;
+        while (*lp && ((*lp == ' ') || (*lp == '\t'))) {
+          lp++;
+        }
+        while (*lp && (*lp != ' ') && (*lp != '\t') && (*lp != '\n')) {
+          *(wp++) = *(lp++);
+        }
+        *wp = '\0';                                 // terminate string
+
+        if (strlen(word_buffer) != 0) {     // check if number is there
+          int var_idx = atoi(word_buffer);
+          int sign = 0;
+
+          if (var_idx != 0) {
+            if (var_idx < 0) {
+              var_idx = -var_idx;
+              sign = 1;
+            }
+            clause_vars.insert(var_idx);
+            clause_lits.insert((var_idx << 1) + sign);
+          } else {
+            // add this clause
+            if (clause_vars.size() != 0 &&
+                clause_vars.size() == clause_lits.size()) {
+              vector <int> temp;
+              for (set<int>::iterator itr = clause_lits.begin();
+                itr != clause_lits.end(); ++itr)
+                temp.push_back(*itr);
+              for (unsigned i = 0; i < temp.size(); ++i)
+                variables[temp[i]>>1] = true;
+              ++num_cls;
+            } else {
+              cout << "Literals of both polarity at line "
+                   << line_num << ", clause skipped " << endl;
+            }
+            // it contain var of both polarity, so is automatically
+            // satisfied, just skip it
+            clause_lits.clear();
+            clause_vars.clear();
+          }
+        }
+      }
+      while (*lp);
+    }
+  }
+  if (!inp.eof()) {
+    cerr << "Input line " << line_num <<  " too long. Unable to continue..."
+         << endl;
+    exit(2);
+  }
+  assert(clause_vars.size() == 0);
+  int num_vars  = 0;
+  for (unsigned i = 0; i < variables.size(); ++i) {
+    if (variables[i])
+      ++num_vars;
+  }
+  cout <<"Statistics of CNF file:\t\t" <<  filename << "\n"
+     <<" Claim:\t\t Cl: " << cl_num << "\t Var: " << var_num << "\n"
+     <<" Actual:\t Cl: " << num_cls << "\t Var: " << num_vars << endl;
+  return 0;
+}
diff --git a/zchaff64/run_till_fix.pl b/zchaff64/run_till_fix.pl
new file mode 100755 (executable)
index 0000000..2601569
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+die "Usage:\nrun_till_fix CNF_Filename [Num_Max_Iterations]" if (@ARGV < 1);
+    
+my $file = $ARGV[0];
+my $max_iteration = @ARGV > 1 ? $ARGV[1] : 1000;
+my $last_cls_count = 0; 
+my $filename = $file."_itr_0";
+$filename =~ s/.*\///;
+
+system("cp $file $filename");
+
+$file =~ s/.*\///;
+
+for (my $i = 0; $i < $max_iteration; ++$i) {
+  
+  open INPUT, "<$filename" or die "$!\n";
+  
+  my @tokens;
+  
+  while (<INPUT>) {
+    @tokens = split / /;
+    last if ($tokens[0] eq "p");
+  }
+  
+  last if $tokens[3] == $last_cls_count;
+  
+  $last_cls_count = $tokens[3];
+  
+  system("zchaff $filename");
+  system("zverify_df $filename resolve_trace -core");
+  my $j = $i + 1;
+  $filename = $file."_itr_".$j;
+  system("mv unsat_core.cnf $filename");
+}
diff --git a/zchaff64/sat_solver.cpp b/zchaff64/sat_solver.cpp
new file mode 100644 (file)
index 0000000..618bca8
--- /dev/null
@@ -0,0 +1,281 @@
+/* =========FOR INTERNAL USE ONLY. NO DISTRIBUTION PLEASE ========== */
+
+/*********************************************************************
+ Copyright 2000-2004, Princeton University.  All rights reserved. 
+ By using this software the USER indicates that he or she has read, 
+ understood and will comply with the following:
+
+ --- Princeton University hereby grants USER nonexclusive permission 
+ to use, copy and/or modify this software for internal, noncommercial,
+ research purposes only. Any distribution, including commercial sale 
+ or license, of this software, copies of the software, its associated 
+ documentation and/or modifications of either is strictly prohibited 
+ without the prior consent of Princeton University.  Title to copyright
+ to this software and its associated documentation shall at all times 
+ remain with Princeton University.  Appropriate copyright notice shall 
+ be placed on all software copies, and a complete copy of this notice 
+ shall be included in all copies of the associated documentation.  
+ No right is  granted to use in advertising, publicity or otherwise 
+ any trademark,  service mark, or the name of Princeton University. 
+
+
+ --- This software and any associated documentation is provided "as is" 
+
+ PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS 
+ OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A 
+ PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR 
+ ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, 
+ TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.  
+
+ Princeton University shall not be liable under any circumstances for 
+ any direct, indirect, special, incidental, or consequential damages 
+ with respect to any claim by USER or any third party on account of 
+ or arising from the use, or inability to use, this software or its 
+ associated documentation, even if Princeton University has been advised
+ of the possibility of those damages.
+*********************************************************************/
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstdio>
+
+#include <set>
+#include <vector>
+#include <dirent.h>
+#include "SAT.h"
+
+using namespace std;
+
+const int MAX_LINE_LENGTH       = 65536;
+const int MAX_WORD_LENGTH       = 64;
+
+//This cnf parser function is based on the GRASP code by Joao Marques Silva
+void read_cnf(SAT_Manager mng, char * filename )
+{
+//    cout <<"read cnf "<<endl;
+    char line_buffer[MAX_LINE_LENGTH];
+    char word_buffer[MAX_WORD_LENGTH];
+    set<int> clause_vars;
+    set<int> clause_lits;
+    int line_num = 0;
+    
+    if(opendir(filename)){
+        cerr << "Can't open input file, it's a directory" << endl;
+        exit(1);
+    }
+    
+    ifstream inp (filename, ios::in);
+    if (!inp) {
+        cerr << "Can't open input file" << endl;
+        exit(1);
+    }
+    while (inp.getline(line_buffer, MAX_LINE_LENGTH)) {
+        ++ line_num;
+        if (line_buffer[0] == 'c') { 
+            continue; 
+        }
+        else if (line_buffer[0] == 'p') {
+            int var_num;
+            int cl_num;
+
+            int arg = sscanf (line_buffer, "p cnf %d %d", &var_num, &cl_num);
+            if( arg < 2 ) {
+                cerr << "Unable to read number of variables and clauses"
+                     << "at line " << line_num << endl;
+                exit(3);
+            }
+            SAT_SetNumVariables(mng, var_num); //first element not used.
+        }
+        else {                             // Clause definition or continuation
+            char *lp = line_buffer;
+            do {
+                char *wp = word_buffer;
+                while (*lp && ((*lp == ' ') || (*lp == '\t'))) {
+                    lp++;
+                }
+                while (*lp && (*lp != ' ') && (*lp != '\t') && (*lp != '\n')) {
+                    *(wp++) = *(lp++);
+                }
+                *wp = '\0';                                 // terminate string
+
+                if (strlen(word_buffer) != 0) {     // check if number is there
+                    int var_idx = atoi (word_buffer);
+                    int sign = 0;
+
+                    if( var_idx != 0) {
+                        if( var_idx < 0)  { var_idx = -var_idx; sign = 1; }
+                        clause_vars.insert(var_idx);
+                        clause_lits.insert( (var_idx << 1) + sign);
+                    }         
+                    else {
+                        //add this clause
+                        if (clause_vars.size() != 0 && (clause_vars.size() == clause_lits.size())) { //yeah, can add this clause
+                            vector <int> temp;
+                            for (set<int>::iterator itr = clause_lits.begin();
+                                 itr != clause_lits.end(); ++itr)
+                                temp.push_back (*itr);
+                            SAT_AddClause(mng, & temp.begin()[0], temp.size() );
+                        }
+                        else {} //it contain var of both polarity, so is automatically satisfied, just skip it
+                        clause_lits.clear();
+                        clause_vars.clear();
+                    }
+                }
+            }
+            while (*lp);
+        }
+    }
+    if (!inp.eof()) {
+        cerr << "Input line " << line_num <<  " too long. Unable to continue..." << endl;
+        exit(2);
+    }
+//    assert (clause_vars.size() == 0);         //some benchmark has no 0 in the last clause
+    if (clause_lits.size() && clause_vars.size()==clause_lits.size() ) {
+        vector <int> temp;
+        for (set<int>::iterator itr = clause_lits.begin();
+             itr != clause_lits.end(); ++itr)
+            temp.push_back (*itr);
+        SAT_AddClause(mng, & temp.begin()[0], temp.size() );
+    }
+    clause_lits.clear();
+    clause_vars.clear();
+//    cout <<"done read cnf"<<endl;
+}
+
+
+void handle_result(SAT_Manager mng, int outcome, char * filename )
+{
+    char * result = "UNKNOWN";
+    switch (outcome) {
+    case SATISFIABLE:
+        cout << "Instance Satisfiable" << endl;
+//following lines will print out a solution if a solution exist
+        for (int i=1, sz = SAT_NumVariables(mng); i<= sz; ++i) {
+            switch(SAT_GetVarAsgnment(mng, i)) {
+            case -1:        
+                cout <<"("<< i<<")"; break;
+            case 0:
+                cout << "-" << i; break;
+            case 1:
+                cout << i ; break;
+            default:
+                cerr << "Unknown variable value state"<< endl;
+                exit(4);
+            }
+            cout << " ";
+        }
+        result  = "SAT";
+        break;
+    case UNSATISFIABLE:
+        result  = "UNSAT";
+        cout << "Instance Unsatisfiable" << endl;
+        break; 
+    case TIME_OUT:
+        result  = "ABORT : TIME OUT"; 
+        cout << "Time out, unable to determine the satisfiability of the instance"<<endl;
+        break;
+    case MEM_OUT:
+        result  = "ABORT : MEM OUT"; 
+        cout << "Memory out, unable to determine the satisfiability of the instance"<<endl;
+        break;
+    default:
+        cerr << "Unknown outcome" << endl;
+    }
+    cout << "Random Seed Used\t\t\t\t" << SAT_Random_Seed(mng) << endl;
+    cout << "Max Decision Level\t\t\t\t" << SAT_MaxDLevel(mng) << endl;
+    cout << "Num. of Decisions\t\t\t\t" << SAT_NumDecisions(mng)<< endl;
+    cout << "( Stack + Vsids + Shrinking Decisions )\t\t" <<SAT_NumDecisionsStackConf(mng);
+    cout << " + " <<SAT_NumDecisionsVsids(mng)<<" + "<<SAT_NumDecisionsShrinking(mng)<<endl;
+    cout << "Original Num Variables\t\t\t\t" << SAT_NumVariables(mng) << endl;
+    cout << "Original Num Clauses\t\t\t\t" << SAT_InitNumClauses(mng) << endl;
+    cout << "Original Num Literals\t\t\t\t" << SAT_InitNumLiterals(mng) << endl;
+    cout << "Added Conflict Clauses\t\t\t\t" << SAT_NumAddedClauses(mng)- SAT_InitNumClauses(mng)<< endl;
+    cout << "Num of Shrinkings\t\t\t\t" << SAT_NumShrinkings(mng)<< endl;
+    cout << "Deleted Conflict Clauses\t\t\t" << SAT_NumDeletedClauses(mng)-SAT_NumDelOrigCls(mng) <<endl;
+    cout << "Deleted Clauses\t\t\t\t\t" << SAT_NumDeletedClauses(mng) <<endl;
+    cout << "Added Conflict Literals\t\t\t\t" << SAT_NumAddedLiterals(mng) - SAT_InitNumLiterals(mng) << endl;
+    cout << "Deleted (Total) Literals\t\t\t" << SAT_NumDeletedLiterals(mng) <<endl;
+    cout << "Number of Implication\t\t\t\t" << SAT_NumImplications(mng)<< endl;
+    //other statistics comes here
+    cout << "Total Run Time\t\t\t\t\t" << SAT_GetCPUTime(mng) << endl;
+//    cout << "RESULT:\t" << filename << " " << result << " RunTime: " << SAT_GetCPUTime(mng)<< endl;
+    cout  << "RESULT:\t"<<result << endl;
+
+
+}
+
+void output_status(SAT_Manager mng)
+{
+    cout << "Dec: " << SAT_NumDecisions(mng)<< "\t ";
+    cout << "AddCl: " << SAT_NumAddedClauses(mng) <<"\t";
+    cout << "AddLit: " << SAT_NumAddedLiterals(mng)<<"\t";
+    cout << "DelCl: " << SAT_NumDeletedClauses(mng) <<"\t";
+    cout << "DelLit: " << SAT_NumDeletedLiterals(mng)<<"\t";
+    cout << "NumImp: " << SAT_NumImplications(mng) <<"\t";
+    cout << "AveBubbleMove: " << SAT_AverageBubbleMove(mng) <<"\t";
+    //other statistics comes here
+    cout << "RunTime:" << SAT_GetElapsedCPUTime(mng) << endl;
+}
+
+void verify_solution(SAT_Manager mng)
+{
+    int num_verified = 0;
+    for ( int cl_idx = SAT_GetFirstClause (mng); cl_idx >= 0; 
+          cl_idx = SAT_GetNextClause(mng, cl_idx)) {
+        int len = SAT_GetClauseNumLits(mng, cl_idx);
+        int * lits = new int[len+1];
+        SAT_GetClauseLits( mng, cl_idx, lits);
+        int i;
+        for (i=0; i< len; ++i) {
+            int v_idx = lits[i] >> 1;
+            int sign = lits[i] & 0x1;
+            int var_value = SAT_GetVarAsgnment( mng, v_idx);
+            if( (var_value == 1 && sign == 0) ||
+                (var_value == 0 && sign == 1) ) break;
+        }
+        if (i >= len) {
+            cerr << "Verify Satisfiable solution failed, please file a bug report, thanks. " << endl;
+            exit(6);
+        }
+        delete [] lits;
+        ++ num_verified;
+    }
+    cout <<"c "<< num_verified << " Clauses are true, Verify Solution successful."<<endl;;
+}
+
+int main(int argc, char ** argv)
+{
+    SAT_Manager mng = SAT_InitManager();
+    if (argc < 2) {
+        cerr << "Z-Chaff: Accelerated SAT Solver from Princeton. " << endl;
+        cerr << "Copyright 2000-2004, Princeton University." << endl << endl;;
+        cerr << "Usage: "<< argv[0] << " cnf_file [time_limit]" << endl;
+        return 2;
+    }
+    cout << "Z-Chaff Version: " << SAT_Version(mng) << endl;
+    cout << "Solving " << argv[1] << " ......" << endl;
+    if (argc == 2) {
+        read_cnf (mng, argv[1] );
+    }
+    else {
+        read_cnf (mng, argv[1] );
+        SAT_SetTimeLimit(mng, atoi(argv[2]));
+    }
+
+/* if you want some statistics during the solving, uncomment following line */
+//    SAT_AddHookFun(mng,output_status, 5000);
+
+/* you can set all your parameters here, following values are the defaults*/ 
+//    SAT_SetMaxUnrelevance(mng, 20);
+//    SAT_SetMinClsLenForDelete(mng, 100);
+//    SAT_SetMaxConfClsLenAllowed(mng, 5000);
+
+/* randomness may help sometimes, by default, there is no randomness */
+//    SAT_SetRandomness (mng, 10);
+//    SAT_SetRandSeed (mng, -1);
+    int result = SAT_Solve(mng);
+    if (result == SATISFIABLE) 
+        verify_solution(mng);
+    handle_result (mng, result,  argv[1]);
+    return 0;
+}
diff --git a/zchaff64/zchaff_base.cpp b/zchaff64/zchaff_base.cpp
new file mode 100644 (file)
index 0000000..642df75
--- /dev/null
@@ -0,0 +1,101 @@
+// /*********************************************************************
+//  Copyright 2000-2004, Princeton University.  All rights reserved.
+//  By using this software the USER indicates that he or she has read,
+//  understood and will comply with the following:
+//
+//  --- Princeton University hereby grants USER nonexclusive permission
+//  to use, copy and/or modify this software for internal, noncommercial,
+//  research purposes only. Any distribution, including commercial sale
+//  or license, of this software, copies of the software, its associated
+//  documentation and/or modifications of either is strictly prohibited
+//  without the prior consent of Princeton University.  Title to copyright
+//  to this software and its associated documentation shall at all times
+//  remain with Princeton University.  Appropriate copyright notice shall
+//  be placed on all software copies, and a complete copy of this notice
+//  shall be included in all copies of the associated documentation.
+//  No right is  granted to use in advertising, publicity or otherwise
+//  any trademark,  service mark, or the name of Princeton University.
+//
+//
+//  --- This software and any associated documentation is provided "as is"
+//
+//  PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+//  OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+//  PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+//  ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+//  TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+//  Princeton University shall not be liable under any circumstances for
+//  any direct, indirect, special, incidental, or consequential damages
+//  with respect to any claim by USER or any third party on account of
+//  or arising from the use, or inability to use, this software or its
+//  associated documentation, even if Princeton University has been advised
+//  of the possibility of those damages.
+// *********************************************************************/
+
+#include <iostream>
+#include <vector>
+
+using namespace std;
+
+#include "zchaff_base.h"
+
+void CLitPoolElement::dump(ostream & os) {
+  os << (var_sign() ? " -" : " +") << var_index();
+  if (is_watched())
+    os << "*";
+}
+
+void CClause::dump(ostream & os) {
+  if (status() == DELETED_CL)
+    os << "\t\t\t======removed=====";
+  for (int i = 0, sz = num_lits(); i < sz; ++i)
+    os << literal(i);
+  os << endl;
+}
+
+bool CClause::self_check(void) {
+  assert(num_lits() > 0);
+  int watched = 0;
+  for (unsigned i = 0; i < num_lits(); ++i) {
+    assert(literal(i).is_literal());
+    if (literal(i).is_watched())
+      ++watched;
+  }
+  assert(num_lits() ==1 || watched == 2);  // either unit, or have two watched
+  assert(!literal(num_lits() + 1).is_literal());
+  return true;
+}
+
+bool CVariable::self_check(void) {
+  for (unsigned i = 0; i < 2; ++i) {
+    vector<CLitPoolElement*>& w = watched(i);
+    for (unsigned j = 0; j < w.size(); ++j) {
+      assert(w[j]->is_watched());
+      assert((unsigned)w[j]->var_sign() == i);
+    }
+  }
+  return true;
+}
+
+void CVariable::dump(ostream & os) {
+  if (is_marked())
+    os << "*" ;
+  os << "V: " << _value << "  DL: " << _dlevel  << "  POS: "<< _assgn_stack_pos
+     << "  Ante: " << _antecedent << endl;
+  for (unsigned j = 0; j < 2; ++j) {
+    os << (j == 0 ? "WPos " : "WNeg ") <<  "(" ;
+    for (unsigned i = 0; i < watched(j).size(); ++i)
+      os << watched(j)[i]->find_clause_index() << "  " ;
+    os << ")" << endl;
+  }
+#ifdef KEEP_LIT_CLAUSES
+  for (unsigned j = 0; j < 2; ++j) {
+    os << (j == 0 ? "Pos " : "Neg ") <<  "(" ;
+    for (unsigned i = 0; i < lit_clause(j).size(); ++i)
+      os << lit_clause(j)[i] << "  " ;
+    os << ")" << endl;
+  }
+#endif
+  os << endl;
+}
diff --git a/zchaff64/zchaff_base.h b/zchaff64/zchaff_base.h
new file mode 100644 (file)
index 0000000..a44b8e3
--- /dev/null
@@ -0,0 +1,506 @@
+// /*********************************************************************
+//  Copyright 2000-2004, Princeton University.  All rights reserved.
+//  By using this software the USER indicates that he or she has read,
+//  understood and will comply with the following:
+//
+//  --- Princeton University hereby grants USER nonexclusive permission
+//  to use, copy and/or modify this software for internal, noncommercial,
+//  research purposes only. Any distribution, including commercial sale
+//  or license, of this software, copies of the software, its associated
+//  documentation and/or modifications of either is strictly prohibited
+//  without the prior consent of Princeton University.  Title to copyright
+//  to this software and its associated documentation shall at all times
+//  remain with Princeton University.  Appropriate copyright notice shall
+//  be placed on all software copies, and a complete copy of this notice
+//  shall be included in all copies of the associated documentation.
+//  No right is  granted to use in advertising, publicity or otherwise
+//  any trademark, service mark, or the name of Princeton University.
+//
+//
+//  --- This software and any associated documentation is provided "as is"
+//
+//  PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+//  OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+//  PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+//  ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+//  TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+//  Princeton University shall not be liable under any circumstances for
+//  any direct, indirect, special, incidental, or consequential damages
+//  with respect to any claim by USER or any third party on account of
+//  or arising from the use, or inability to use, this software or its
+//  associated documentation, even if Princeton University has been advised
+//  of the possibility of those damages.
+// *********************************************************************/
+
+
+#ifndef __BASIC_CLASSES__
+#define __BASIC_CLASSES__
+
+#include <assert.h>
+
+#include "zchaff_header.h"
+
+#define UNKNOWN           2
+#define NULL_CLAUSE          -1
+
+#define VOLATILE_GID   -1
+#define        PERMANENT_GID         0
+// #define KEEP_LIT_CLAUSES
+typedef int ClauseIdx;  // Used to refer a clause. Because of dynamic
+                        // allocation of vector storage, no pointer is allowered
+
+#ifndef _CLS_STATUS_
+#define _CLS_STATUS_
+enum CLAUSE_STATUS {
+  ORIGINAL_CL,
+  CONFLICT_CL,
+  DELETED_CL,
+};
+#endif
+
+// /**Class********************************************************************
+//
+//   Synopsis    [Definition of a literal]
+//
+//   Description [A literal is a variable with phase. Two things specify a
+//                literal: its "sign", and its variable index.
+//
+//                Each clause that has more than 1 literal contains two special
+//                literals. They are being "watched". A literal is marked with
+//                2 bits: 00->not watched; 11->watched, direction = 1;
+//                01->watched, dir = -1; 10 is not valid. These two bits occupy
+//                the least significant bits of the literal.
+//
+//                Each literal is represented by a 32 bit signed integer. The
+//                higher 29 bits represent the variable index. At most 2**28
+//                varialbes are allowed. If the sign of this integer is
+//                negative, it means that it is not a valid literal. It could
+//                be a clause index or a deleted literal pool element. The 3rd
+//                least significant bit is used to mark its sign.
+//                0->positive, 1->negative.
+//
+//                The literals are collected in a storage space called literal
+//                pool. An element in a literal pool can be a literal or a
+//                special spacing element to indicate the termination of a
+//                clause. The spacing elements has negative value of the clause
+//                index.]
+//
+//                Right Hand spacing element has the clause id, so why is it
+//                not less than 0?
+//
+//   SeeAlso     [CDatabase, CClause]
+//
+// ****************************************************************************
+
+class CLitPoolElement {
+  protected:
+    int32 _val;
+
+  public:
+    // constructors & destructors
+    CLitPoolElement(void):_val(0)        {}
+
+    ~CLitPoolElement()                         {}
+
+    // member access function
+    int & val(void) {
+      return _val;
+    }
+
+    // stands for signed variable, i.e. 2*var_idx + sign
+    int s_var(void) {
+      return _val >> 2;
+    }
+
+    unsigned var_index(void) {
+      return _val >> 3;
+    }
+
+    unsigned var_sign(void) {
+      return ((_val >> 2) & 0x1);
+    }
+
+    void set(int s_var) {
+      _val = (s_var << 2);
+    }
+
+    void set(int vid, int sign) {
+      _val = (((vid << 1) + sign) << 2);
+    }
+
+    // followings are for manipulate watched literals
+    int direction(void) {
+      return ((_val & 0x3) - 2);
+    }
+
+    bool is_watched(void) {
+      return ((_val & 0x3) != 0);
+    }
+
+    void unwatch(void) {
+      _val = _val & (~0x3);
+    }
+
+    void set_watch(int dir) {
+      _val = _val + dir + 2;
+    }
+
+    // following are used for spacing (e.g. indicate clause's end)
+    bool is_literal(void) {
+      return _val > 0;
+    }
+
+    void set_clause_index(int cl_idx) {
+      _val = - cl_idx;
+    }
+
+    ClauseIdx get_clause_index(void) {
+      assert(_val <= 0);
+      return -_val;
+    }
+
+    // misc functions
+    unsigned find_clause_index(void) {
+      CLitPoolElement * ptr;
+      for (ptr = this; ptr->is_literal(); ++ptr);
+      return ptr->get_clause_index();
+    }
+
+    // every class should have a dump function and a self check function
+    void dump(ostream & os= cout);
+
+    friend ostream & operator << (ostream & os, CLitPoolElement & l) {
+      l.dump(os);
+      return os;
+    }
+};
+
+// /**Class********************************************************************
+//
+//   Synopsis    [Definition of a clause]
+//
+//   Description [A clause is consisted of a certain number of literals.
+//                All literals are collected in a single large vector, called
+//                literal pool. Each clause has a pointer to the beginning
+//                position of it's literals in the pool.
+//
+//                Zchaff support incremental SAT. Clauses can be added or
+//                deleted from the database during search. To accomodate this
+//                feature, some modifications are needed.
+//
+//                Clauses can be generated during search by conflict driven
+//                analysis. Conflict clauses are generated by a resolution
+//                process. Therefore, if after one search, some clauses got
+//                deleted, then some of the learned conflict clause may be
+//                invalidated. To maintain the integrity of the clause
+//                database, it is necessary to keep track of the clauses that
+//                are involved in the resolution process for a certain conflict
+//                clause so that when those clauses are deleted, the conflict
+//                clause should also be deleted.
+//
+//                The scheme we implement is similar to the scheme described in
+//                : Ofer Strichman, Pruning techniques for the SAT-based
+//                Bounded Model Checking Problems, in Proc. 11th Advanced
+//                Research Working Conference on Correct Hardware Design and
+//                Verification Methods (CHARME'01)
+//                ]
+//
+//   SeeAlso     [CDatabase]
+//
+// ****************************************************************************
+class CClause {
+  protected:
+    CLitPoolElement *   _first_lit;     // pointer to the first literal
+    unsigned            _num_lits ;
+    CLAUSE_STATUS       _status : 3;
+    unsigned            _id     : 29;   // the unique ID of a clause
+    unsigned            _gflag;         // the clause group id flag,
+                                        // maximum allow WORD_WIDTH groups
+    int                 _activity;
+    int                 _sat_lit_idx;
+
+  public:
+
+    // constructors & destructors
+    CClause(void) {
+      _sat_lit_idx = 0;
+    }
+
+    ~CClause() {}
+
+    // initialization & clear up
+    void init(CLitPoolElement * head, unsigned num_lits, unsigned gflag) {
+      _first_lit = head;
+      _num_lits = num_lits;
+      _gflag = gflag;
+    }
+
+    // member access function
+    inline int & activity(void) {
+      return _activity;
+    }
+
+    inline int & sat_lit_idx(void) {
+      return _sat_lit_idx;
+    }
+
+    inline CLitPoolElement * literals(void) {
+      // literals()[i] is it's the i-th literal
+      return _first_lit;
+    }
+
+    // return the idx-th literal
+    inline CLitPoolElement & literal(int idx) {
+     return *(_first_lit + idx);
+    }
+
+    // use it only if you want to modify _first_lit
+    inline CLitPoolElement * & first_lit(void) {
+      return _first_lit;
+    }
+
+    inline unsigned & num_lits(void) {
+      return _num_lits;
+    }
+
+    inline unsigned id(void) {
+      return _id;
+    }
+
+    inline void set_id(int id) {
+      _id = id;
+    }
+
+    inline CLAUSE_STATUS status(void) {
+      return _status;
+    }
+
+    inline void set_status(CLAUSE_STATUS st) {
+      _status = st;
+    }
+
+    // manipulate the group flag
+    inline unsigned & gflag(void) {
+      return _gflag;
+    }
+
+    inline bool gid(int i) {
+      assert(i >= 1 && i <= WORD_WIDTH);
+      return ((_gflag & (1 << (i - 1))) != 0);
+    }
+
+    inline void set_gid(int i) {
+      assert(i >= 1 && i <= WORD_WIDTH);
+      _gflag |= (1 << (i - 1));
+    }
+
+    inline void clear_gid(int i) {
+      assert(i >= 1 && i <= WORD_WIDTH);
+      _gflag &= ~(1 << (i - 1));
+    }
+
+    // misc function
+    bool self_check(void);
+
+    void dump(ostream & os = cout);
+
+    friend ostream & operator << (ostream & os, CClause & cl) {
+        cl.dump(os);
+        return os;
+    }
+};
+
+
+// /**Class********************************************************************
+//
+// Synopsis    [Definition of a variable]
+//
+// Description [CVariable contains the necessary information for a variable.]
+//
+// SeeAlso     [CDatabase]
+//
+// ****************************************************************************
+class CVariable {
+  protected:
+    unsigned _value             : 2;  // it can take 3 values, 0, 1 and UNKNOWN
+    bool _marked                : 1;  // used in conflict analysis.
+    unsigned _new_cl_phase      : 2;  // it can take 3 value
+    // 0: pos phase, 1: neg phase, UNKNOWN : not in new clause;
+    // It is used to keep track of literals appearing
+    // in newly added clause so that
+    // a. each variable can only appearing in one phase
+    // b. same literal won't appear more than once.
+    bool _enable_branch         : 1;  // if this variable is enabled in branch
+                                      // selection
+    int _implied_sign           : 1;  // when a var is implied, here is the
+                                      // sign (1->negative, 0->positive)
+    ClauseIdx _antecedent;    // used in conflict analysis.
+    int _dlevel;              // decision level this variable being assigned
+    int _assgn_stack_pos;     // the position where it is in the assignment
+                              // stack
+    int _lits_count[2];       // how many literals are there with this
+                              // variable. (two phases)
+    int _2_lits_count[2];     // how many literals in 2 literal clauses are
+                              // there with this variable. (two phases)
+    vector<CLitPoolElement *> _watched[2];  // watched literals of this
+                                            // var. 0: pos phase, 1: neg phase
+
+#ifdef KEEP_LIT_CLAUSES
+    vector<ClauseIdx> _lit_clauses[2];  // this will keep track of ALL the
+                                        // appearance of the variable in
+                                        // clauses
+                                        // note this will increase the database
+                                        // size by upto a factor of 2
+#endif
+    int _scores[2];                     // the score used for decision making
+    int _var_score_pos;                 // keep track of this variable's
+                                        // position in the sorted score array
+
+  public:
+    // constructors & destructors
+    CVariable(void) {
+        init();
+        _lits_count[0] = _lits_count[1] = 0;
+        _2_lits_count[0] = _2_lits_count[1] = 0;
+    }
+
+    ~CVariable() {}
+
+    void init(void) {
+      _value = UNKNOWN;
+      _antecedent = NULL_CLAUSE;
+      _marked = false;
+      _dlevel = -1;
+      _assgn_stack_pos = -1;
+      _new_cl_phase = UNKNOWN;
+      _scores[0] = _scores[1] = 0;
+      _enable_branch = true;
+    }
+
+    // member access function
+    inline int & score(int i) {
+      return _scores[i];
+    }
+
+    inline int & two_lits_count(int i) {
+      return _2_lits_count[i];
+    }
+
+    inline int score(void) {
+      // return 1; this will make a fixed order branch heuristic
+      int result = score(0) > score(1) ? score(0) : score(1);
+      if (_dlevel == 0)
+        result =-1;
+      return result;
+    }
+
+    inline int & var_score_pos(void) {
+      return _var_score_pos;
+    }
+
+    inline void set_var_score_pos(int pos) {
+      _var_score_pos = pos;
+    }
+
+    inline unsigned value(void) {
+      return _value;
+    }
+
+    inline void set_value(unsigned v) {
+      _value = v;
+    }
+
+    inline int & dlevel(void) {
+      return _dlevel;
+    }
+
+    inline int get_dlevel(void) {
+      return _dlevel;
+    }
+
+    inline void set_dlevel(int dl) {
+      _dlevel = dl;
+    }
+
+    inline int & assgn_stack_pos(void) {
+      return _assgn_stack_pos;
+    }
+
+    inline int & lits_count(int i) {
+      return _lits_count[i];
+    }
+
+    inline bool is_marked(void) {
+      return _marked;
+    }
+
+    inline int get_implied_sign(void) {
+      return _implied_sign;
+    }
+
+    inline void set_implied_sign(int sign) {
+      _implied_sign = sign;
+    }
+
+    inline unsigned new_cl_phase(void) {
+      return _new_cl_phase;
+    }
+
+    inline void set_new_cl_phase(unsigned phase) {
+      _new_cl_phase = phase;
+    }
+
+    inline void set_marked(void) {
+      _marked = true;
+    }
+
+    inline void clear_marked(void) {
+      _marked = false;
+    }
+
+    inline ClauseIdx & antecedent(void) {
+      return _antecedent;
+    }
+
+    inline ClauseIdx get_antecedent(void) {
+      return _antecedent;
+    }
+
+    inline void set_antecedent(ClauseIdx cl) {
+      _antecedent = cl;
+    }
+
+    inline vector<CLitPoolElement *> & watched(int i) {
+      return _watched[i];
+    }
+
+    inline void enable_branch(void) {
+      _enable_branch = true;
+    }
+
+    inline void disable_branch(void) {
+      _enable_branch = false;
+    }
+
+    inline bool is_branchable(void) {
+      return _enable_branch;
+    }
+
+#ifdef KEEP_LIT_CLAUSES
+    inline vector<ClauseIdx> & lit_clause(int i) {
+      return _lit_clauses[i];
+    }
+#endif
+
+    // misc function
+    bool self_check(void);
+
+    void dump(ostream & os = cout);
+
+    friend ostream & operator << (ostream & os, CVariable & v) {
+      v.dump(os);
+      return os;
+    }
+};
+#endif
diff --git a/zchaff64/zchaff_clsgen.h b/zchaff64/zchaff_clsgen.h
new file mode 100644 (file)
index 0000000..31e2f03
--- /dev/null
@@ -0,0 +1,234 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#ifndef __CLAUSE_GENERATOR__
+#define __CLAUSE_GENERATOR__
+#include "zchaff_solver.h"
+
+class CClause_Gen {
+  private:
+    inline static int * ptr(vector<int>::iterator itr) {
+      return &(*itr);
+    }
+    inline static int pos(int i) {
+      return i;
+    }
+    inline static int neg(int i) {
+      return i^0x1;
+    }
+
+  public:
+    static void and2(CSolver & solver, int a, int b, int o, int gid = 0) {
+      // a*b=c <==> (a + o')( b + o')(a'+b'+o)
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(neg(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void and_n(CSolver & solver, int * inputs, int num_input, int o,
+                      int gid = 0) {
+      vector <int> lits;
+      int i;
+      for (i = 0; i < num_input; ++i) {
+        lits.clear();
+        lits.push_back(pos(inputs[i]));
+        lits.push_back(neg(o));
+        solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      }
+      lits.clear();
+      for (i = 0; i < num_input; ++i)
+        lits.push_back(neg(inputs[i]));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void or2(CSolver & solver, int a, int b, int o, int gid = 0) {
+      // a+b=c <==> (a' + c)( b' + c)(a + b + c')
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(neg(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(pos(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void or_n(CSolver & solver, int * inputs, int num_input, int o,
+                     int gid = 0) {
+      vector <int> lits;
+      int i;
+      for (i = 0; i < num_input; ++i) {
+        lits.clear();
+        lits.push_back(neg(inputs[i]));
+        lits.push_back(pos(o));
+        solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      }
+      lits.clear();
+      for (i = 0; i < num_input; ++i)
+        lits.push_back(pos(inputs[i]));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void nand2(CSolver & solver, int a, int b, int o, int gid = 0) {
+      // a Nand b = o <==> (a + o)( b + o)(a' + b' + o')
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(neg(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void nand_n(CSolver & solver, int * inputs, int num_input, int o,
+                       int gid = 0) {
+      vector <int> lits;
+      int i;
+      for (i = 0; i < num_input; ++i) {
+        lits.clear();
+        lits.push_back(pos(inputs[i]));
+        lits.push_back(pos(o));
+        solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      }
+      lits.clear();
+      for (i = 0; i < num_input; ++i)
+        lits.push_back(neg(inputs[i]));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void nor2(CSolver & solver, int a, int b, int o, int gid = 0) {
+      // a Nor b = o <==> (a' + o')( b' + o')(a + b + o)
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(neg(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(pos(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void nor_n(CSolver & solver, int * inputs, int num_input, int o,
+               int gid = 0) {
+      vector <int> lits;
+      int i;
+      for (i = 0; i < num_input; ++i) {
+        lits.clear();
+        lits.push_back(neg(inputs[i]));
+        lits.push_back(neg(o));
+        solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      }
+      lits.clear();
+      for (i = 0; i < num_input; ++i)
+        lits.push_back(pos(inputs[i]));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void xor2(CSolver & solver, int a, int b, int o, int gid = 0) {
+      // a xor b = o <==> (a' + b' + o')
+      //                  (a + b + o' )
+      //                  (a' + b + o)
+      //                         (a + b' + o)
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(neg(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(pos(b));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(pos(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(neg(b));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+
+    static void not1(CSolver & solver, int a, int o, int gid = 0) {
+      // a' = o <==> (a' + o')( a + o)
+      vector <int> lits;
+      lits.clear();
+      lits.push_back(neg(a));
+      lits.push_back(neg(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+      lits.clear();
+      lits.push_back(pos(a));
+      lits.push_back(pos(o));
+      solver.add_orig_clause(ptr(lits.begin()), lits.size(), gid);
+    }
+};
+#endif
diff --git a/zchaff64/zchaff_dbase.cpp b/zchaff64/zchaff_dbase.cpp
new file mode 100644 (file)
index 0000000..3e78c7f
--- /dev/null
@@ -0,0 +1,476 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// ********************************************************************/
+
+#include <iostream>
+#include <vector>
+#include <set>
+
+using namespace std;
+
+#include "zchaff_dbase.h"
+
+CDatabase::CDatabase(void) {
+  _stats.mem_used_up                 = false;
+  _stats.init_num_clauses            = 0;
+  _stats.init_num_literals           = 0;
+  _stats.num_added_clauses           = 0;
+  _stats.num_added_literals          = 0;
+  _stats.num_deleted_clauses         = 0;
+  _stats.num_del_orig_cls            = 0;
+  _stats.num_deleted_literals        = 0;
+  _stats.num_enlarge                 = 0;
+  _stats.num_compact                 = 0;
+  _lit_pool_start = (CLitPoolElement *) malloc(sizeof(CLitPoolElement) *
+                                               STARTUP_LIT_POOL_SIZE);
+  _lit_pool_finish = _lit_pool_start;
+  _lit_pool_end_storage = _lit_pool_start + STARTUP_LIT_POOL_SIZE;
+  lit_pool_push_back(0);  // set the first element as a dummy element
+  _params.mem_limit = 1024 * 1024 * 1024;  // that's 1 G
+  variables()->resize(1);                  // var_id == 0 is never used.
+  _allocated_gid                    = 0;
+}
+
+CDatabase::~CDatabase(void) {
+  free(_lit_pool_start);
+}
+
+unsigned CDatabase::estimate_mem_usage(void) {
+  unsigned mem_lit_pool = sizeof(CLitPoolElement) * (lit_pool_size() +
+                                                     lit_pool_free_space());
+  unsigned mem_vars = sizeof(CVariable) * variables()->capacity();
+  unsigned mem_cls = sizeof(CClause) * clauses()->capacity();
+  unsigned mem_cls_queue = sizeof(int) * _unused_clause_idx.size();
+  unsigned mem_watched = 2 * num_clauses() * sizeof(CLitPoolElement *);
+  unsigned mem_lit_clauses = 0;
+#ifdef KEEP_LIT_CLAUSES
+  mem_lit_clauses = num_literals() * sizeof(ClauseIdx);
+#endif
+  return (mem_lit_pool + mem_vars + mem_cls +
+          mem_cls_queue + mem_watched + mem_lit_clauses);
+}
+
+unsigned CDatabase::mem_usage(void) {
+  int mem_lit_pool = (lit_pool_size() + lit_pool_free_space()) *
+                     sizeof(CLitPoolElement);
+  int mem_vars = sizeof(CVariable) * variables()->capacity();
+  int mem_cls = sizeof(CClause) * clauses()->capacity();
+  int mem_cls_queue = sizeof(int) * _unused_clause_idx.size();
+  int mem_watched = 0, mem_lit_clauses = 0;
+  for (unsigned i = 0, sz = variables()->size(); i < sz ;  ++i) {
+    CVariable & v = variable(i);
+    mem_watched        += v.watched(0).capacity() + v.watched(1).capacity();
+#ifdef KEEP_LIT_CLAUSES
+    mem_lit_clauses += v.lit_clause(0).capacity() + v.lit_clause(1).capacity();
+#endif
+  }
+  mem_watched *= sizeof(CLitPoolElement*);
+  mem_lit_clauses *= sizeof(ClauseIdx);
+  return (mem_lit_pool + mem_vars + mem_cls +
+          mem_cls_queue + mem_watched + mem_lit_clauses);
+}
+
+int CDatabase::alloc_gid(void) {
+  for (unsigned i = 1; i <= WORD_WIDTH; ++i) {
+    if (is_gid_allocated(i) == false) {
+      _allocated_gid |= (1 << (i-1));
+      return i;
+    }
+  }
+  warning(_POSITION_, "Not enough GID");
+  return VOLATILE_GID;
+}
+
+void CDatabase::free_gid(int gid) {
+  assert(gid > 0 && "Can't free volatile or permanent group");
+  assert(gid <= WORD_WIDTH && "gid > WORD_WIDTH?");
+  if (!is_gid_allocated(gid)) {
+    fatal(_POSITION_, "Can't free unallocated GID");
+  }
+  _allocated_gid &= (~(1<< (gid-1)));
+}
+
+bool CDatabase::is_gid_allocated(int gid) {
+  if (gid == VOLATILE_GID || gid == PERMANENT_GID)
+    return true;
+  assert(gid <= WORD_WIDTH && gid > 0);
+  if (_allocated_gid & (1 << (gid -1)))
+    return true;
+  return false;
+}
+
+int CDatabase::merge_clause_group(int g2, int g1) {
+  assert(g1 >0 && g2> 0 && "Can't merge with permanent or volatile group");
+  assert(g1 != g2);
+  assert(is_gid_allocated(g1) && is_gid_allocated(g2));
+  for (unsigned i = 0, sz = clauses()->size(); i < sz; ++i) {
+    if (clause(i).status() != DELETED_CL) {
+      if (clause(i).gid(g1) == true) {
+        clause(i).clear_gid(g1);
+        clause(i).set_gid(g2);
+      }
+    }
+  }
+  free_gid(g1);
+  return g2;
+}
+
+void CDatabase::mark_clause_deleted(CClause & cl) {
+  ++_stats.num_deleted_clauses;
+  _stats.num_deleted_literals += cl.num_lits();
+  CLAUSE_STATUS status = cl.status();
+  if (status == ORIGINAL_CL)
+     _stats.num_del_orig_cls++;
+  cl.set_status(DELETED_CL);
+  for (unsigned i = 0; i < cl.num_lits(); ++i) {
+    CLitPoolElement & l = cl.literal(i);
+    --variable(l.var_index()).lits_count(l.var_sign());
+    l.val() = 0;
+  }
+  _unused_clause_idx.insert(&cl - &(*clauses()->begin()));
+}
+
+bool CDatabase::is_conflicting(ClauseIdx cl) {
+  CLitPoolElement * lits = clause(cl).literals();
+  for (int i = 0, sz= clause(cl).num_lits(); i < sz;  ++i) {
+    if (literal_value(lits[i]) != 0)
+      return false;
+  }
+  return true;
+}
+
+bool CDatabase::is_satisfied(ClauseIdx cl) {
+  CLitPoolElement * lits = clause(cl).literals();
+  for (int i = 0, sz = clause(cl).num_lits(); i < sz; ++i) {
+    if (literal_value(lits[i]) == 1)
+      return true;
+  }
+  return false;
+}
+
+bool CDatabase::is_unit(ClauseIdx cl) {
+  int num_unassigned = 0;
+  CLitPoolElement * lits = clause(cl).literals();
+  for (unsigned i = 0, sz= clause(cl).num_lits(); i < sz;  ++i) {
+    int value = literal_value(lits[i]);
+    if (value == 1)
+      return false;
+    else if (value != 0)
+      ++num_unassigned;
+  }
+  return num_unassigned == 1;
+}
+
+int CDatabase::find_unit_literal(ClauseIdx cl) {
+  // will return 0 if not unit
+  int unit_lit = 0;
+  for (int i = 0, sz = clause(cl).num_lits(); i < sz;  ++i) {
+    int value = literal_value(clause(cl).literal(i));
+    if (value == 1)
+      return 0;
+    else if (value != 0) {
+      if (unit_lit == 0)
+        unit_lit = clause(cl).literals()[i].s_var();
+      else
+        return 0;
+    }
+  }
+  return unit_lit;
+}
+
+inline CLitPoolElement * CDatabase::lit_pool_begin(void) {
+  return _lit_pool_start;
+}
+
+inline CLitPoolElement * CDatabase::lit_pool_end(void) {
+  return _lit_pool_finish;
+}
+
+inline void CDatabase::lit_pool_incr_size(int size) {
+  _lit_pool_finish += size;
+  assert(_lit_pool_finish <= _lit_pool_end_storage);
+}
+
+inline void CDatabase::lit_pool_push_back(int value) {
+  assert(_lit_pool_finish <= _lit_pool_end_storage);
+  _lit_pool_finish->val() = value;
+  ++_lit_pool_finish;
+}
+
+inline int CDatabase::lit_pool_size(void) {
+  return _lit_pool_finish - _lit_pool_start;
+}
+
+inline int CDatabase::lit_pool_free_space(void) {
+  return _lit_pool_end_storage - _lit_pool_finish;
+}
+
+inline double CDatabase::lit_pool_utilization(void) {
+    // minus num_clauses() is because of spacing (i.e. clause indices)
+  return (double)num_literals() / ((double) (lit_pool_size() - num_clauses())) ;
+}
+
+inline CLitPoolElement & CDatabase::lit_pool(int i) {
+  return _lit_pool_start[i];
+}
+
+void CDatabase::compact_lit_pool(void) {
+  unsigned i, sz;
+  int new_index = 1;
+  // first do the compaction for the lit pool
+  for (i = 1, sz = lit_pool_size(); i < sz;  ++i) {
+    // begin with 1 because 0 position is always 0
+    if (!lit_pool(i).is_literal() && !lit_pool(i-1).is_literal()) {
+      continue;
+    } else {
+      lit_pool(new_index) = lit_pool(i);
+      ++new_index;
+    }
+  }
+  _lit_pool_finish = lit_pool_begin() + new_index;
+  // update all the pointers to the literals;
+  // 1. clean up the watched pointers from variables
+  for (i = 1, sz = variables()->size(); i < sz;  ++i) {
+    variable(i).watched(0).clear();
+    variable(i).watched(1).clear();
+  }
+  for (i = 1, sz = lit_pool_size(); i < sz;  ++i) {
+    CLitPoolElement & lit = lit_pool(i);
+    // 2. reinsert the watched pointers
+    if (lit.is_literal()) {
+      if (lit.is_watched()) {
+         int var_idx = lit.var_index();
+         int sign = lit.var_sign();
+         variable(var_idx).watched(sign).push_back(& lit_pool(i));
+       }
+    } else {  // lit is not literal
+    // 3. update the clauses' first literal pointer
+      int cls_idx = lit.get_clause_index();
+      clause(cls_idx).first_lit() = &lit_pool(i) - clause(cls_idx).num_lits();
+    }
+  }
+  ++_stats.num_compact;
+}
+
+bool CDatabase::enlarge_lit_pool(void) {
+  // will return true if successful, otherwise false.
+  unsigned i, sz;
+  // if memory efficiency < 2/3, we do a compaction
+  if (lit_pool_utilization() < 0.67) {
+    compact_lit_pool();
+    return true;
+  }
+  // otherwise we have to enlarge it.
+  // first, check if memory is running out
+  int current_mem = estimate_mem_usage();
+  float grow_ratio = 1;
+  if (current_mem < _params.mem_limit / 4)
+    grow_ratio = 2;
+  else if (current_mem < _params.mem_limit /2 )
+    grow_ratio = 1.5;
+  else if (current_mem < _params.mem_limit * 0.8)
+    grow_ratio = 1.2;
+  if (grow_ratio < 1.2) {
+    if (lit_pool_utilization() < 0.9) {  // still has some garbage
+      compact_lit_pool();
+      return true;
+    }
+    else
+      return false;
+  }
+  // second, make room for new lit pool.
+  CLitPoolElement * old_start = _lit_pool_start;
+  CLitPoolElement * old_finish = _lit_pool_finish;
+  int old_size = _lit_pool_end_storage - _lit_pool_start;
+  int new_size = (int)(old_size * grow_ratio);
+  _lit_pool_start = (CLitPoolElement *) realloc(_lit_pool_start,
+                                                sizeof(CLitPoolElement) *
+                                                new_size);
+  _lit_pool_finish = _lit_pool_start + (old_finish - old_start);
+  _lit_pool_end_storage = _lit_pool_start + new_size;
+
+  // update all the pointers
+  long long displacement = _lit_pool_start - old_start;
+  for (i = 0; i < clauses()->size(); ++i) {
+    if (clause(i).status() != DELETED_CL)
+      clause(i).first_lit() += displacement;
+  }
+  for (i = 0, sz = variables()->size(); i < sz ;  ++i) {
+    CVariable & v = variable(i);
+    for (int j = 0; j < 2 ; ++j) {
+      int k, sz1;
+      vector<CLitPoolElement *> & watched = v.watched(j);
+      for (k = 0, sz1 = watched.size(); k < sz1 ; ++k) {
+        watched[k] += displacement;
+      }
+    }
+  }
+  ++_stats.num_enlarge;
+  return true;
+}
+
+ClauseIdx CDatabase::get_free_clause_idx(void) {
+  ClauseIdx new_cl;
+  new_cl = _clauses.size();
+  _clauses.resize(new_cl + 1);
+  clause(new_cl).set_id(_stats.num_added_clauses);
+  return new_cl;
+}
+
+ClauseIdx CDatabase::add_clause(int * lits, int n_lits, int gflag) {
+  int new_cl;
+  // a. do we need to enlarge lits pool?
+  while (lit_pool_free_space() <= n_lits + 1) {
+    if (enlarge_lit_pool() == false)
+      return -1;  // mem out, can't enlarge lit pool, because
+      // ClauseIdx can't be -1, so it shows error.
+  }
+  // b. get a free cl index;
+  new_cl = get_free_clause_idx();
+  // c. add the clause lits to lits pool
+  CClause & cl = clause(new_cl);
+  cl.init(lit_pool_end(), n_lits, gflag);
+  lit_pool_incr_size(n_lits + 1);
+  if (n_lits == 2) {
+    ++variable(lits[0]>>1).two_lits_count(lits[0] & 0x1);
+    ++variable(lits[1]>>1).two_lits_count(lits[1] & 0x1);
+  }
+  for (int i = 0; i < n_lits; ++i) {
+    int var_idx = lits[i] >> 1;
+    assert((unsigned)var_idx < variables()->size());
+    int var_sign = lits[i] & 0x1;
+    cl.literal(i).set(var_idx, var_sign);
+    ++variable(var_idx).lits_count(var_sign);
+#ifdef KEEP_LIT_CLAUSES
+    variable(var_idx).lit_clause(var_sign).push_back(new_cl);
+#endif
+  }
+  // the element after the last one is the spacing element
+  cl.literal(n_lits).set_clause_index(new_cl);
+  // d. set the watched pointers
+  if (cl.num_lits() > 1) {
+    // add the watched literal. note: watched literal must be the last free var
+    int max_idx = -1, max_dl = -1;
+    int i, sz = cl.num_lits();
+    // set the first watched literal
+    for (i = 0; i < sz; ++i) {
+      int v_idx = cl.literal(i).var_index();
+      int v_sign = cl.literal(i).var_sign();
+      CVariable & v = variable(v_idx);
+      if (literal_value(cl.literal(i)) != 0) {
+        v.watched(v_sign).push_back(&cl.literal(i));
+        cl.literal(i).set_watch(1);
+        break;
+      } else {
+        if (v.dlevel() > max_dl) {
+          max_dl = v.dlevel();
+          max_idx = i;
+        }
+      }
+    }
+    if (i >= sz) {  // no unassigned literal. so watch literal with max dlevel
+      int v_idx = cl.literal(max_idx).var_index();
+      int v_sign = cl.literal(max_idx).var_sign();
+      variable(v_idx).watched(v_sign).push_back(&cl.literal(max_idx));
+      cl.literal(max_idx).set_watch(1);
+    }
+
+    // set the second watched literal
+    max_idx = -1;
+    max_dl = -1;
+    for (i = sz-1; i >= 0; --i) {
+      if (cl.literal(i).is_watched())
+        continue;  // need to watch two different literals
+      int v_idx = cl.literal(i).var_index();
+      int v_sign = cl.literal(i).var_sign();
+      CVariable & v = variable(v_idx);
+      if (literal_value(cl.literal(i)) != 0) {
+        v.watched(v_sign).push_back(&cl.literal(i));
+        cl.literal(i).set_watch(-1);
+        break;
+      } else {
+        if (v.dlevel() > max_dl) {
+          max_dl = v.dlevel();
+          max_idx = i;
+        }
+      }
+    }
+    if (i < 0) {
+      int v_idx = cl.literal(max_idx).var_index();
+      int v_sign = cl.literal(max_idx).var_sign();
+      variable(v_idx).watched(v_sign).push_back(&cl.literal(max_idx));
+      cl.literal(max_idx).set_watch(-1);
+    }
+  }
+  // update some statistics
+  ++_stats.num_added_clauses;
+  _stats.num_added_literals += n_lits;
+  return new_cl;
+}
+
+void CDatabase::output_lit_pool_stats(void) {
+  cout << "Lit_Pool Used " << lit_pool_size() << " Free "
+       << lit_pool_free_space()
+       << " Total " << lit_pool_size() + lit_pool_free_space()
+       << " Num. Cl " << num_clauses() << " Num. Lit " << num_literals()
+       << " Efficiency " <<  lit_pool_utilization() << endl;
+}
+
+void CDatabase::detail_dump_cl(ClauseIdx cl_idx, ostream & os) {
+  os << "CL : " << cl_idx;
+  CClause & cl = clause(cl_idx);
+  if (cl.status() == DELETED_CL)
+    os << "\t\t\t======removed=====";
+  char value;
+  for (unsigned i = 0; i < cl.num_lits(); ++i) {
+    if (literal_value(cl.literal(i)) == 0)
+      value = '0';
+    else if (literal_value(cl.literal(i)) == 1)
+      value = '1';
+    else
+      value = 'X';
+    os << cl.literal(i) << "(" << value << "@"
+       << variable(cl.literal(i).var_index()).dlevel()<< ")  ";
+  }
+  os << endl;
+}
+
+void CDatabase::dump(ostream & os) {
+  unsigned i;
+  os << "Dump Database: " << endl;
+  for (i = 0; i < _clauses.size(); ++i)
+    detail_dump_cl(i);
+  for (i = 1; i < _variables.size(); ++i)
+    os << "VID " << i << ":\t" << variable(i);
+}
diff --git a/zchaff64/zchaff_dbase.h b/zchaff64/zchaff_dbase.h
new file mode 100644 (file)
index 0000000..729bc2e
--- /dev/null
@@ -0,0 +1,298 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************/
+#ifndef __ZCHAFF_DATABASE__
+#define __ZCHAFF_DATABASE__
+
+#include "zchaff_base.h"
+
+#define STARTUP_LIT_POOL_SIZE 0x8000
+
+// **Struct********************************************************************
+//
+// Synopsis    [Definition of the statistics of clause database]
+//
+//  Description []
+//
+//  SeeAlso     [CDatabase]
+//
+// ****************************************************************************
+
+struct CDatabaseStats {
+  bool             mem_used_up;
+  unsigned         init_num_clauses;
+  unsigned         init_num_literals;
+  unsigned         num_added_clauses;
+  long64           num_added_literals;
+  unsigned         num_deleted_clauses;
+  unsigned         num_del_orig_cls;
+  long64           num_deleted_literals;
+  unsigned         num_compact;
+  unsigned         num_enlarge;
+};
+
+// **Struct********************************************************************
+//
+//  Synopsis    [Definition of the parameters of clause database]
+//
+//  Description []
+//
+//  SeeAlso     [CDatabase]
+//
+// ****************************************************************************
+
+struct CDatabaseParams {
+  int         mem_limit;
+};
+
+// **Class*********************************************************************
+//
+//  Synopsis    [Definition of clause database ]
+//
+//  Description [Clause Database is the place where the information of the
+//               SAT problem are stored. it is a parent class of CSolver ]
+//
+//  SeeAlso     [CSolver]
+//
+// ****************************************************************************
+
+class CDatabase {
+  protected:
+    CDatabaseStats      _stats;
+
+    CDatabaseParams     _params;
+
+    unsigned            _allocated_gid;    // the gids that have already been
+                                           // allocated
+
+    // for efficiency, the memeory management of lit pool is done by the solver
+    CLitPoolElement * _lit_pool_start;     // the begin of the lit vector
+    CLitPoolElement * _lit_pool_finish;    // the tail of the used lit vector
+    CLitPoolElement * _lit_pool_end_storage;  // the storage end of lit vector
+
+
+    vector<CVariable>   _variables;     // note: first element is not used
+
+    vector<CClause>     _clauses;
+
+    set<ClauseIdx>      _unused_clause_idx;
+
+    ClauseIdx           top_unsat_cls;
+
+  protected:
+    // constructors & destructors
+    CDatabase() ;
+
+    ~CDatabase();
+
+    void init_stats(void) {
+      _stats.mem_used_up              = false;
+      _stats.init_num_clauses         = num_clauses();
+      _stats.init_num_literals        = num_literals();
+      _stats.num_deleted_clauses      = 0;
+      _stats.num_del_orig_cls         = 0;
+      _stats.num_deleted_literals     = 0;
+      _stats.num_enlarge              = 0;
+      _stats.num_compact              = 0;
+    }
+
+    // lit pool naming convention follows STL Vector
+    CLitPoolElement * lit_pool_begin(void);
+
+    CLitPoolElement * lit_pool_end(void);
+
+    void lit_pool_incr_size(int size);
+
+    void lit_pool_push_back(int value);
+
+    int lit_pool_size(void);
+
+    int lit_pool_free_space(void);
+
+    double lit_pool_utilization(void);
+
+    CLitPoolElement & lit_pool(int i);
+
+    // functions on lit_pool
+    void output_lit_pool_stats(void);
+
+    // when allocated memeory runs out, do a reallocation
+    bool enlarge_lit_pool(void);
+
+    void compact_lit_pool(void);        // garbage collection
+
+    unsigned literal_value(CLitPoolElement l) {
+    // note: it will return 0 or 1 or other, here "other" may not equal UNKNOWN
+      return (variable(l.var_index()).value() ^ l.var_sign());
+    }
+
+    unsigned svar_value(int svar) {
+    // note: it will return 0 or 1 or other, here "other" may not equal UNKNOWN
+      return (variable(svar >> 1).value() ^ (svar & 0x1));
+    }
+
+    // clause properties
+    void mark_clause_deleted(CClause & cl);
+
+    int find_unit_literal(ClauseIdx cl);  // if not unit clause, return 0.
+
+    bool is_conflicting(ClauseIdx cl);    // e.g. all literals assigned value 0
+
+    bool is_unit(ClauseIdx cl);
+
+    bool is_satisfied(ClauseIdx cl);   // e.g. at least one literal has value 1
+
+    // others
+    ClauseIdx get_free_clause_idx(void);
+
+    ClauseIdx add_clause(int * lits, int n_lits, int gflag = 0);
+
+  public:
+
+    // member access function
+    inline vector<CVariable>* variables(void) {
+      return &_variables;
+    }
+
+    inline CVariable & variable(int idx) {
+      return _variables[idx];
+    }
+
+    inline vector<CClause>* clauses(void) {
+      return &_clauses;
+    }
+
+    inline CClause & clause(ClauseIdx idx) {
+      return _clauses[idx];
+    }
+
+    inline CDatabaseStats & stats(void) {
+      return _stats;
+    }
+
+    inline void set_mem_limit(int n) {
+      _params.mem_limit = n;
+    }
+
+    // clause group management
+    int alloc_gid(void);
+
+    void free_gid(int gid);
+
+    inline int get_volatile_gid(void) {
+      return -1;
+    }
+
+    inline int get_permanent_gid(void) {
+      return 0;
+    }
+
+    bool is_gid_allocated(int gid);
+
+    int merge_clause_group(int g1, int g2);
+
+    // some stats
+    inline unsigned & init_num_clauses(void) {
+      return _stats.init_num_clauses;
+    }
+
+    inline unsigned & init_num_literals(void) {
+      return _stats.init_num_literals;
+    }
+
+    inline unsigned & num_added_clauses(void) {
+      return _stats.num_added_clauses;
+    }
+
+    inline long64  & num_added_literals(void) {
+      return _stats.num_added_literals;
+    }
+
+    inline unsigned & num_deleted_clauses(void) {
+      return _stats.num_deleted_clauses;
+    }
+
+    inline unsigned & num_del_orig_cls(void) {
+      return _stats.num_del_orig_cls;
+    }
+
+    inline long64 & num_deleted_literals(void) {
+      return _stats.num_deleted_literals;
+    }
+
+    inline unsigned num_variables(void) {
+      return variables()->size() - 1;
+    }
+
+    inline unsigned num_clauses(void) {
+      return _clauses.size() - _unused_clause_idx.size();
+    }
+
+    inline unsigned num_literals(void) {
+      return _stats.num_added_literals - _stats.num_deleted_literals;
+    }
+
+    inline unsigned num_mem_compacts(void) {
+      return _stats.num_compact;
+    }
+
+    inline unsigned num_mem_enlarges(void) { return
+      _stats.num_enlarge;
+    }
+
+    // functions
+    unsigned estimate_mem_usage(void);
+
+    unsigned mem_usage(void);
+
+    inline void set_variable_number(int n) {
+      variables()->resize(n + 1);
+    }
+
+    inline int add_variable(void) {
+      variables()->resize(variables()->size() + 1);
+      return variables()->size() - 1;
+    }
+
+    // dump functions
+    void detail_dump_cl(ClauseIdx cl_idx, ostream & os = cout);
+
+    void dump(ostream & os = cout);
+
+    friend ostream & operator << (ostream & os, CDatabase & db) {
+      db.dump(os);
+      return os;
+    }
+};
+#endif
diff --git a/zchaff64/zchaff_header.h b/zchaff64/zchaff_header.h
new file mode 100644 (file)
index 0000000..b5442a8
--- /dev/null
@@ -0,0 +1,75 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#ifndef __ZCHAFF_INCLUDE__
+#define __ZCHAFF_INCLUDE__
+
+#define WORD_SIZE 4
+// #define WORD_SIZE 8
+
+extern int _global_debug_level;
+extern int _global_check_level;
+
+#ifndef __FUNCTION__
+# define __FUNCTION__ ((char*)0)
+#endif
+
+#ifndef __FILE__
+# define __FILE__ 0
+#endif
+
+#ifndef __LINE__
+# define __LINE__ 0
+#endif
+
+#define _POSITION_  __FUNCTION__, __FILE__, __LINE__
+
+#if WORD_SIZE == 4
+#define WORD_WIDTH         32
+typedef unsigned        uint32;
+typedef int             int32;
+typedef long long       long64;
+#elif WORD_SIZE == 8
+#define WORD_WIDTH         64
+typedef unsigned int    uint32;
+typedef int             int32;
+typedef long            long64;
+#endif
+
+void fatal(char * fun, char * file, int lineno, char * fmt, ...);
+void warning(char * fun, char * file, int lineno, char * fmt, ...);
+double get_cpu_time(void);
+
+#endif
diff --git a/zchaff64/zchaff_solver.cpp b/zchaff64/zchaff_solver.cpp
new file mode 100644 (file)
index 0000000..0c9b99b
--- /dev/null
@@ -0,0 +1,1528 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark, service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// ********************************************************************
+
+#include <iostream>
+#include <algorithm>
+#include <fstream>
+#include <vector>
+#include <map>
+#include <set>
+#include <queue>
+
+using namespace std;
+
+#include "zchaff_solver.h"
+
+// #define VERIFY_ON
+
+#ifdef VERIFY_ON
+ofstream verify_out("resolve_trace");
+#endif
+
+void CSolver::re_init_stats(void) {
+  _stats.is_mem_out           = false;
+  _stats.outcome              = UNDETERMINED;
+  _stats.next_restart         = _params.restart.first_restart;
+  _stats.restart_incr         = _params.restart.backtrack_incr;
+  _stats.next_cls_deletion    = _params.cls_deletion.interval;
+  _stats.next_var_score_decay = _params.decision.decay_period;
+  _stats.current_randomness   = _params.decision.base_randomness;
+
+  _stats.total_bubble_move            = 0;
+  _stats.num_decisions                = 0;
+  _stats.num_decisions_stack_conf     = 0;
+  _stats.num_decisions_vsids          = 0;
+  _stats.num_decisions_shrinking      = 0;
+  _stats.num_backtracks               = 0;
+  _stats.max_dlevel                   = 0;
+  _stats.num_implications             = 0;
+  _stats.num_restarts                 = 0;
+  _stats.num_del_orig_cls             = 0;
+  _stats.num_shrinkings               = 0;
+  _stats.start_cpu_time               = get_cpu_time();
+  _stats.finish_cpu_time              = 0;
+  _stats.random_seed                  = 0;
+}
+
+void CSolver::init_stats(void) {
+  re_init_stats();
+
+  _stats.been_reset                   = true;
+  _stats.num_free_variables           = 0;
+  _stats.num_free_branch_vars         = 0;
+}
+
+void CSolver::init_parameters(void) {
+  _params.verbosity                           = 0;
+  _params.time_limit                          = 3600 * 24;  // a day
+  _params.shrinking.size                      = 95;
+  _params.shrinking.enable                    = true;
+  _params.shrinking.upper_bound               = 800;
+  _params.shrinking.lower_bound               = 600;
+  _params.shrinking.upper_delta               = -5;
+  _params.shrinking.lower_delta               = 10;
+  _params.shrinking.window_width              = 20;
+  _params.shrinking.bound_update_frequency    = 20;
+
+  _params.decision.base_randomness            = 0;
+  _params.decision.decay_period               = 40;
+  _params.decision.bubble_init_step           = 0x400;
+
+  _params.cls_deletion.enable                 = true ;
+  _params.cls_deletion.head_activity          = 500;
+  _params.cls_deletion.tail_activity          = 10;
+  _params.cls_deletion.head_num_lits          = 6;
+  _params.cls_deletion.tail_num_lits          = 45;
+  _params.cls_deletion.tail_vs_head           = 16;
+  _params.cls_deletion.interval               = 600;
+
+  _params.restart.enable                      = true;
+  _params.restart.interval                    = 700;
+  _params.restart.first_restart               = 7000;
+  _params.restart.backtrack_incr              = 700;
+}
+
+CSolver::CSolver(void) {
+  init_parameters();
+  init_stats();
+  _dlevel                       = 0;
+  _force_terminate              = false;
+  _implication_id               = 0;
+  _num_marked                   = 0;
+  _num_in_new_cl                = 0;
+  _outside_constraint_hook      = NULL;
+  _sat_hook                     = NULL;
+}
+
+CSolver::~CSolver(void) {
+  while (!_assignment_stack.empty()) {
+    delete _assignment_stack.back();
+    _assignment_stack.pop_back();
+  }
+}
+
+void CSolver::set_time_limit(float t) {
+  _params.time_limit = t;
+}
+
+float CSolver::elapsed_cpu_time(void) {
+  return get_cpu_time() - _stats.start_cpu_time;
+}
+
+float CSolver::cpu_run_time(void) {
+  return (_stats.finish_cpu_time - _stats.start_cpu_time);
+}
+
+void CSolver::set_variable_number(int n) {
+  assert(num_variables() == 0);
+  CDatabase::set_variable_number(n);
+  _stats.num_free_variables = num_variables();
+  while (_assignment_stack.size() <= num_variables())
+    _assignment_stack.push_back(new vector<int>);
+  assert(_assignment_stack.size() == num_variables() + 1);
+}
+
+int CSolver::add_variable(void) {
+  int num = CDatabase::add_variable();
+  ++_stats.num_free_variables;
+  while (_assignment_stack.size() <= num_variables())
+    _assignment_stack.push_back(new vector<int>);
+  assert(_assignment_stack.size() == num_variables() + 1);
+  return num;
+}
+
+void CSolver::set_mem_limit(int s) {
+  CDatabase::set_mem_limit(s);
+}
+
+void CSolver::set_randomness(int n) {
+  _params.decision.base_randomness = n;
+}
+
+void CSolver::set_random_seed(int seed) {
+  srand(seed);
+}
+
+void CSolver::enable_cls_deletion(bool allow) {
+  _params.cls_deletion.enable = allow;
+}
+
+void CSolver::add_hook(HookFunPtrT fun, int interval) {
+  pair<HookFunPtrT, int> a(fun, interval);
+  _hooks.push_back(pair<int, pair<HookFunPtrT, int> > (0, a));
+}
+
+void CSolver::run_periodic_functions(void) {
+  // a. restart
+  if (_params.restart.enable && _stats.num_backtracks > _stats.next_restart &&
+      _shrinking_cls.empty()) {
+    _stats.next_restart = _stats.num_backtracks + _stats.restart_incr;
+    delete_unrelevant_clauses();
+    restart();
+    if (_stats.num_restarts % 5 == 1)
+      compact_lit_pool();
+    cout << "\rDecision: " << _assignment_stack[0]->size() << "/"
+         <<num_variables() << "\tTime: " << get_cpu_time() -
+           _stats.start_cpu_time << "/" << _params.time_limit << flush;
+  }
+
+  // b. decay variable score
+  if (_stats.num_backtracks > _stats.next_var_score_decay) {
+    _stats.next_var_score_decay = _stats.num_backtracks +
+                                  _params.decision.decay_period;
+    decay_variable_score();
+  }
+
+  // c. run hook functions
+  for (unsigned i = 0; i< _hooks.size(); ++i) {
+    pair<int, pair<HookFunPtrT, int> > & hook = _hooks[i];
+    if (_stats.num_decisions >= hook.first) {
+      hook.first += hook.second.second;
+      hook.second.first((void *) this);
+    }
+  }
+}
+
+void CSolver::init_solve(void) {
+  CDatabase::init_stats();
+  re_init_stats();
+  _stats.been_reset = false;
+
+  assert(_conflicts.empty());
+  assert(_conflict_lits.empty());
+  assert(_num_marked == 0);
+  assert(_num_in_new_cl == 0);
+  assert(_dlevel == 0);
+
+  for (unsigned i = 0, sz = variables()->size(); i < sz; ++i) {
+    variable(i).score(0) = variable(i).lits_count(0);
+    variable(i).score(1) = variable(i).lits_count(1);
+  }
+
+  _ordered_vars.resize(num_variables());
+  update_var_score();
+
+  set_random_seed(_stats.random_seed);
+
+  top_unsat_cls = clauses()->size() - 1;
+
+  _stats.shrinking_benefit = 0;
+  _shrinking_cls.clear();
+  _stats.shrinking_cls_length = 0;
+}
+
+void CSolver::set_var_value(int v, int value, ClauseIdx ante, int dl) {
+    assert(value == 0 || value == 1);
+    CVariable & var = variable(v);
+    assert(var.value() == UNKNOWN);
+    assert(dl == dlevel());
+
+    var.set_dlevel(dl);
+    var.set_value(value);
+    var.antecedent() = ante;
+    var.assgn_stack_pos() = _assignment_stack[dl]->size();
+    _assignment_stack[dl]->push_back(v * 2 + !value);
+    set_var_value_BCP(v, value);
+
+    ++_stats.num_implications ;
+    if (var.is_branchable())
+        --num_free_variables();
+}
+
+void CSolver::set_var_value_BCP(int v, int value) {
+  vector<CLitPoolElement *> & watchs = variable(v).watched(value);
+  for (vector <CLitPoolElement *>::iterator itr = watchs.begin();
+       itr != watchs.end(); ++itr) {
+    ClauseIdx cl_idx;
+    CLitPoolElement * other_watched = *itr;
+    CLitPoolElement * watched = *itr;
+    int dir = watched->direction();
+    CLitPoolElement * ptr = watched;
+    while (true) {
+      ptr += dir;
+      if (ptr->val() <= 0) {  // reached one end of the clause
+        if (dir == 1)  // reached the right end, i.e. spacing element is cl_id
+          cl_idx = ptr->get_clause_index();
+        if (dir == watched->direction()) {  // we haven't go both directions.
+          ptr = watched;
+          dir = -dir;                     // change direction, go the other way
+          continue;
+        }
+        // otherwise, we have already go through the whole clause
+        int the_value = literal_value(*other_watched);
+        if (the_value == 0)  // a conflict
+          _conflicts.push_back(cl_idx);
+        else if (the_value != 1)  // i.e. unknown
+          queue_implication(other_watched->s_var(), cl_idx);
+        break;
+      }
+      if (ptr->is_watched()) {  // literal is the other watched lit, skip it.
+        other_watched = ptr;
+        continue;
+      }
+      if (literal_value(*ptr) == 0)  // literal value is 0, keep going
+        continue;
+      // now the literal's value is either 1 or unknown, watch it instead
+      int v1 = ptr->var_index();
+      int sign = ptr->var_sign();
+      variable(v1).watched(sign).push_back(ptr);
+      ptr->set_watch(dir);
+      // remove the original watched literal from watched list
+      watched->unwatch();
+      *itr = watchs.back();  // copy the last element in it's place
+      watchs.pop_back();     // remove the last element
+      --itr;                 // do this so with don't skip one during traversal
+      break;
+    }
+  }
+}
+
+void CSolver::unset_var_value(int v) {
+  if (v == 0)
+    return;
+  CVariable & var = variable(v);
+  var.set_value(UNKNOWN);
+  var.set_antecedent(NULL_CLAUSE);
+  var.set_dlevel(-1);
+  var.assgn_stack_pos() = -1;
+
+  if (var.is_branchable()) {
+    ++num_free_variables();
+    if (var.var_score_pos() < _max_score_pos)
+      _max_score_pos = var.var_score_pos();
+  }
+}
+
+void CSolver::dump_assignment_stack(ostream & os ) {
+  os << "Assignment Stack:  ";
+  for (int i = 0; i <= dlevel(); ++i) {
+    os << "(" <<i << ":";
+    for (unsigned j = 0; j < (*_assignment_stack[i]).size(); ++j) {
+      os << ((*_assignment_stack[i])[j]&0x1?"-":"+")
+         << ((*_assignment_stack[i])[j] >> 1) << " ";
+    }
+    os << ") " << endl;
+  }
+  os << endl;
+}
+
+void CSolver::dump_implication_queue(ostream & os) {
+  _implication_queue.dump(os);
+}
+
+void CSolver::delete_clause_group(int gid) {
+  assert(is_gid_allocated(gid));
+
+  if (_stats.been_reset == false)
+    reset();  // if delete some clause, then implication queue are invalidated
+
+  for (vector<CClause>::iterator itr = clauses()->begin();
+       itr != clauses()->end(); ++itr) {
+    CClause & cl = *itr;
+    if (cl.status() != DELETED_CL) {
+      if (cl.gid(gid) == true) {
+        mark_clause_deleted(cl);
+      }
+    }
+  }
+
+  // delete the index from variables
+  for (vector<CVariable>::iterator itr = variables()->begin();
+         itr != variables()->end(); ++itr) {
+    for (unsigned i = 0; i < 2; ++i) {  // for each phase
+      // delete the lit index from the vars
+#ifdef KEEP_LIT_CLAUSES
+      vector<ClauseIdx> & lit_clauses = (*itr).lit_clause(i);
+      for (vector<ClauseIdx>::iterator itr1 = lit_clauses.begin();
+           itr1 != lit_clauses.end(); ++itr1) {
+        if (clause(*itr1).status() == DELETED_CL) {
+          *itr1 = lit_clauses.back();
+          lit_clauses.pop_back();
+          --itr1;
+        }
+      }
+#endif
+      // delete the watched index from the vars
+      vector<CLitPoolElement *> & watched = (*itr).watched(i);
+      for (vector<CLitPoolElement *>::iterator itr1 = watched.begin();
+           itr1 != watched.end(); ++itr1) {
+        if ((*itr1)->val() <= 0) {
+          *itr1 = watched.back();
+          watched.pop_back();
+          --itr1;
+        }
+      }
+    }
+  }
+  free_gid(gid);
+}
+
+void CSolver::reset(void) {
+  if (_stats.been_reset)
+    return;
+  if (num_variables() == 0)
+    return;
+  back_track(0);
+  _conflicts.clear();
+  while (!_implication_queue.empty())
+    _implication_queue.pop();
+
+  _stats.outcome = UNDETERMINED;
+  _stats.been_reset = true;
+}
+
+void CSolver::delete_unrelevant_clauses(void) {
+  unsigned original_del_cls = num_deleted_clauses();
+  int num_conf_cls = num_clauses() - init_num_clauses() + num_del_orig_cls();
+  int head_count = num_conf_cls / _params.cls_deletion.tail_vs_head;
+  int count = 0;
+  for (vector<CClause>::iterator itr = clauses()->begin();
+                                 itr != clauses()->end() - 1; ++itr) {
+    CClause & cl = *itr;
+    if (cl.status() != CONFLICT_CL) {
+      continue;
+    }
+    bool cls_sat_at_dl_0 = false;
+    for (int i = 0, sz = cl.num_lits(); i < sz; ++i) {
+      if (literal_value(cl.literal(i)) == 1 &&
+          variable(cl.literal(i).var_index()).dlevel() == 0) {
+        cls_sat_at_dl_0 = true;
+        break;
+      }
+    }
+    if (cls_sat_at_dl_0) {
+      int val_0_lits = 0, val_1_lits = 0, unknown_lits = 0;
+      for (unsigned i = 0; i < cl.num_lits(); ++i) {
+        int lit_value = literal_value(cl.literal(i));
+        if (lit_value == 0)
+          ++val_0_lits;
+        if (lit_value == 1)
+          ++val_1_lits;
+        if (lit_value == UNKNOWN)
+          ++unknown_lits;
+        if (unknown_lits + val_1_lits > 1) {
+          mark_clause_deleted(cl);
+          break;
+        }
+      }
+      continue;
+    }
+
+    count++;
+    int max_activity = _params.cls_deletion.head_activity -
+                       (_params.cls_deletion.head_activity -
+                        _params.cls_deletion.tail_activity) *
+                       count/num_conf_cls;
+    int max_conf_cls_size;
+
+    if (head_count > 0) {
+      max_conf_cls_size = _params.cls_deletion.head_num_lits;
+      --head_count;
+    } else {
+      max_conf_cls_size = _params.cls_deletion.tail_num_lits;
+    }
+
+    if (cl.activity() > max_activity)
+      continue;
+
+    int val_0_lits = 0, val_1_lits = 0, unknown_lits = 0, lit_value;
+    for (unsigned i = 0; i < cl.num_lits(); ++i) {
+      lit_value = literal_value(cl.literal(i));
+      if (lit_value == 0)
+        ++val_0_lits;
+      else if (lit_value == 1)
+        ++val_1_lits;
+      else
+        ++unknown_lits;
+      if ((unknown_lits > max_conf_cls_size)) {
+        mark_clause_deleted(cl);
+        break;
+      }
+    }
+  }
+
+  // if none were recently marked for deletion...
+  if (original_del_cls == num_deleted_clauses())
+    return;
+
+  // delete the index from variables
+  for (vector<CVariable>::iterator itr = variables()->begin();
+       itr != variables()->end(); ++itr) {
+    for (unsigned i = 0; i < 2; ++i) {  // for each phase
+      // delete the lit index from the vars
+#ifdef KEEP_LIT_CLAUSES
+      vector<ClauseIdx> & lit_clauses = (*itr).lit_clause(i);
+      for (vector<ClauseIdx>::iterator itr1 = lit_clauses.begin();
+           itr1 != lit_clauses.end(); ++itr1) {
+        if (clause(*itr1).status() == DELETED_CL) {
+          *itr1 = lit_clauses.back();
+          lit_clauses.pop_back();
+          --itr1;
+        }
+      }
+#endif
+      // delete the watched index from the vars
+      vector<CLitPoolElement *> & watched = (*itr).watched(i);
+      for (vector<CLitPoolElement *>::iterator itr1 = watched.begin();
+           itr1 != watched.end(); ++itr1) {
+        if ((*itr1)->val() <= 0) {
+          *itr1 = watched.back();
+          watched.pop_back();
+          --itr1;
+        }
+      }
+    }
+  }
+
+  for (unsigned i = 1, sz = variables()->size(); i < sz; ++i) {
+    if (variable(i).dlevel() != 0) {
+      variable(i).score(0) = variable(i).lits_count(0);
+      variable(i).score(1) = variable(i).lits_count(1);
+      if (variable(i).lits_count(0) == 0 && variable(i).value() == UNKNOWN) {
+        queue_implication(i * 2 + 1, NULL_CLAUSE);
+      }
+      else if (variable(i).lits_count(1) == 0 &&
+               variable(i).value() == UNKNOWN) {
+        queue_implication(i * 2, NULL_CLAUSE);
+      }
+    } else {
+      variable(i).score(0) = 0;
+      variable(i).score(1) = 0;
+    }
+  }
+  update_var_score();
+}
+
+bool CSolver::time_out(void) {
+  return (get_cpu_time() - _stats.start_cpu_time> _params.time_limit);
+}
+
+void CSolver::adjust_variable_order(int * lits, int n_lits) {
+  // note lits are signed vars, not CLitPoolElements
+  for (int i = 0; i < n_lits; ++i) {
+    int var_idx = lits[i] >> 1;
+    CVariable & var = variable(var_idx);
+    assert(var.value() != UNKNOWN);
+    int orig_score = var.score();
+    ++variable(var_idx).score(lits[i] & 0x1);
+    int new_score = var.score();
+    if (orig_score == new_score)
+      continue;
+    int pos = var.var_score_pos();
+    int orig_pos = pos;
+    assert(_ordered_vars[pos].first == & var);
+    assert(_ordered_vars[pos].second == orig_score);
+    int bubble_step = _params.decision.bubble_init_step;
+    for (pos = orig_pos ; pos >= 0; pos -= bubble_step) {
+      if (_ordered_vars[pos].second >= new_score)
+        break;
+    }
+    pos += bubble_step;
+    for (bubble_step = bubble_step >> 1; bubble_step > 0;
+         bubble_step = bubble_step >> 1) {
+      if (pos - bubble_step >= 0 &&
+          _ordered_vars[pos - bubble_step].second < new_score)
+        pos -= bubble_step;
+    }
+    // now found the position, do a swap
+    _ordered_vars[orig_pos] = _ordered_vars[pos];
+    _ordered_vars[orig_pos].first->set_var_score_pos(orig_pos);
+    _ordered_vars[pos].first = & var;
+    _ordered_vars[pos].second = new_score;
+    _ordered_vars[pos].first->set_var_score_pos(pos);
+    _stats.total_bubble_move += orig_pos - pos;
+  }
+}
+
+void CSolver::decay_variable_score(void) {
+  unsigned i, sz;
+  for (i = 1, sz = variables()->size(); i < sz; ++i) {
+    CVariable & var = variable(i);
+    var.score(0) /= 2;
+    var.score(1) /= 2;
+  }
+  for (i = 0, sz = _ordered_vars.size(); i < sz; ++i) {
+    _ordered_vars[i].second = _ordered_vars[i].first->score();
+  }
+}
+
+bool CSolver::decide_next_branch(void) {
+  if (dlevel() > 0)
+    assert(_assignment_stack[dlevel()]->size() > 0);
+  if (!_implication_queue.empty()) {
+    // some hook function did a decision, so skip my own decision making.
+    // if the front of implication queue is 0, that means it's finished
+    // because var index start from 1, so 2 *vid + sign won't be 0.
+    // else it's a valid decision.
+    return (_implication_queue.front().lit != 0);
+  }
+  int s_var = 0;
+  if (_params.shrinking.enable) {
+    while (!_shrinking_cls.empty()) {
+      s_var = _shrinking_cls.begin()->second;
+      _shrinking_cls.erase(_shrinking_cls.begin());
+      if (variable(s_var >> 1).value() == UNKNOWN) {
+        _stats.num_decisions++;
+        _stats.num_decisions_shrinking++;
+        ++dlevel();
+        queue_implication(s_var ^ 0x1, NULL_CLAUSE);
+        return true;
+      }
+    }
+  }
+
+  if (_outside_constraint_hook != NULL)
+     _outside_constraint_hook(this);
+
+  if (!_implication_queue.empty())
+     return (_implication_queue.front().lit != 0);
+
+  ++_stats.num_decisions;
+  if (num_free_variables() == 0)  // no more free vars
+     return false;
+
+  bool cls_sat = true;
+  int i, sz, var_idx, score, max_score = -1;
+
+  for (; clause(top_unsat_cls).status() != ORIGINAL_CL; --top_unsat_cls) {
+    CClause &cl=clause(top_unsat_cls);
+    if (cl.status() != CONFLICT_CL)
+      continue;
+    cls_sat = false;
+    if (cl.sat_lit_idx() < (int)cl.num_lits() &&
+        literal_value(cl.literal(cl.sat_lit_idx())) == 1)
+      cls_sat = true;
+    if (!cls_sat) {
+      max_score = -1;
+      for (i = 0, sz = cl.num_lits(); i < sz; ++i) {
+        var_idx = cl.literal(i).var_index();
+        if (literal_value(cl.literal(i)) == 1) {
+          cls_sat = true;
+          cl.sat_lit_idx() = i;
+          break;
+        }
+        else if (variable(var_idx).value() == UNKNOWN) {
+          score = variable(var_idx).score();
+          if (score > max_score) {
+            max_score = score;
+            s_var = var_idx * 2;
+          }
+        }
+      }
+    }
+    if (!cls_sat)
+      break;
+  }
+  if (!cls_sat && max_score != -1) {
+    ++dlevel();
+    if (dlevel() > _stats.max_dlevel)
+      _stats.max_dlevel = dlevel();
+    CVariable& v = variable(s_var >> 1);
+    if (v.score(0) < v.score(1))
+      s_var += 1;
+    else if (v.score(0) == v.score(1)) {
+      if (v.two_lits_count(0) > v.two_lits_count(1))
+        s_var+=1;
+      else if (v.two_lits_count(0) == v.two_lits_count(1))
+        s_var+=rand()%2;
+    }
+    assert(s_var >= 2);
+    queue_implication(s_var, NULL_CLAUSE);
+    ++_stats.num_decisions_stack_conf;
+    return true;
+  }
+
+  for (unsigned i = _max_score_pos; i < _ordered_vars.size(); ++i) {
+    CVariable & var = *_ordered_vars[i].first;
+    if (var.value() == UNKNOWN && var.is_branchable()) {
+      // move th max score position pointer
+      _max_score_pos = i;
+      // make some randomness happen
+      if (--_stats.current_randomness < _params.decision.base_randomness)
+        _stats.current_randomness = _params.decision.base_randomness;
+      int randomness = _stats.current_randomness;
+      if (randomness >= num_free_variables())
+        randomness = num_free_variables() - 1;
+      int skip = rand() % (1 + randomness);
+      int index = i;
+      while (skip > 0) {
+        ++index;
+      if (_ordered_vars[index].first->value() == UNKNOWN &&
+          _ordered_vars[index].first->is_branchable())
+        --skip;
+      }
+      CVariable * ptr = _ordered_vars[index].first;
+      assert(ptr->value() == UNKNOWN && ptr->is_branchable());
+      int sign = 0;
+      if (ptr->score(0) < ptr->score(1))
+        sign += 1;
+      else if (ptr->score(0) == ptr->score(1)) {
+        if (ptr->two_lits_count(0) > ptr->two_lits_count(1))
+          sign += 1;
+        else if (ptr->two_lits_count(0) == ptr->two_lits_count(1))
+          sign += rand() % 2;
+      }
+      int var_idx = ptr - &(*variables()->begin());
+      s_var = var_idx + var_idx + sign;
+      break;
+    }
+  }
+  assert(s_var >= 2);  // there must be a free var somewhere
+  ++dlevel();
+  if (dlevel() > _stats.max_dlevel)
+    _stats.max_dlevel = dlevel();
+  ++_stats.num_decisions_vsids;
+  _implication_id = 0;
+  queue_implication(s_var, NULL_CLAUSE);
+  return true;
+}
+
+int CSolver::preprocess(void) {
+  assert(dlevel() == 0);
+
+  // 1. detect all the unused variables
+  vector<int> un_used;
+  for (unsigned i = 1, sz = variables()->size(); i < sz; ++i) {
+    CVariable & v = variable(i);
+    if (v.lits_count(0) == 0 && v.lits_count(1) == 0) {
+      un_used.push_back(i);
+      queue_implication(i+i, NULL_CLAUSE);
+      int r = deduce();
+      assert(r == NO_CONFLICT);
+    }
+  }
+  if (_params.verbosity > 1 && un_used.size() > 0) {
+    cout << un_used.size() << " Variables are defined but not used " << endl;
+    if (_params.verbosity > 2) {
+      for (unsigned i = 0; i< un_used.size(); ++i)
+         cout << un_used[i] << " ";
+      cout << endl;
+    }
+  }
+
+  // 2. detect all variables with only one phase occuring (i.e. pure literals)
+  vector<int> uni_phased;
+  for (unsigned i = 1, sz = variables()->size(); i < sz; ++i) {
+    CVariable & v = variable(i);
+    if (v.value() != UNKNOWN)
+      continue;
+    if (v.lits_count(0) == 0) {  // no positive phased lits.
+      queue_implication(i+i+1, NULL_CLAUSE);
+      uni_phased.push_back(-i);
+    }
+    else if (v.lits_count(1) == 0) {  // no negative phased lits.
+      queue_implication(i+i, NULL_CLAUSE);
+      uni_phased.push_back(i);
+    }
+  }
+  if (_params.verbosity > 1 && uni_phased.size() > 0) {
+    cout << uni_phased.size() << " Variables only appear in one phase." <<endl;
+    if (_params.verbosity > 2) {
+      for (unsigned i = 0; i< uni_phased.size(); ++i)
+        cout << uni_phased[i] << " ";
+      cout <<endl;
+    }
+  }
+
+  // 3. Unit clauses
+  for (unsigned i = 0, sz = clauses()->size(); i < sz; ++i) {
+    if (clause(i).status() != DELETED_CL &&
+        clause(i).num_lits() == 1 &&
+        variable(clause(i).literal(0).var_index()).value() == UNKNOWN)
+      queue_implication(clause(i).literal(0).s_var(), i);
+  }
+
+  if (deduce() == CONFLICT) {
+    cout << " CONFLICT during preprocess " <<endl;
+#ifdef VERIFY_ON
+    for (unsigned i = 1; i < variables()->size(); ++i) {
+      if (variable(i).value() != UNKNOWN) {
+        assert(variable(i).dlevel() <= 0);
+        int ante = variable(i).antecedent();
+        int ante_id = 0;
+        if (ante >= 0) {
+          ante_id = clause(ante).id();
+          verify_out << "VAR: " << i
+                     << " L: " << variable(i).assgn_stack_pos()
+                     << " V: " << variable(i).value()
+                     << " A: " << ante_id
+                     << " Lits:";
+          for (unsigned j = 0; j < clause(ante).num_lits(); ++j)
+            verify_out <<" " <<  clause(ante).literal(j).s_var();
+          verify_out << endl;
+         }
+       }
+    }
+    verify_out << "CONF: " << clause(_conflicts[0]).id() << " ==";
+    for (unsigned i = 0; i < clause(_conflicts[0]).num_lits(); ++i) {
+      int svar = clause(_conflicts[0]).literal(i).s_var();
+      verify_out << " " << svar;
+    }
+    verify_out << endl;
+#endif
+    return CONFLICT;
+  }
+  if (_params.verbosity > 1) {
+    cout << _assignment_stack[0]->size() << " vars set during preprocess; "
+         << endl;
+  }
+  return NO_CONFLICT;
+}
+
+void CSolver::mark_var_unbranchable(int vid) {
+  if (variable(vid).is_branchable()) {
+    variable(vid).disable_branch();
+    if (variable(vid).value() == UNKNOWN)
+      --num_free_variables();
+  }
+}
+
+void CSolver::mark_var_branchable(int vid) {
+  CVariable & var = variable(vid);
+  if (!var.is_branchable()) {
+    var.enable_branch();
+    if (var.value() == UNKNOWN) {
+      ++num_free_variables();
+      if (var.var_score_pos() < _max_score_pos)
+        _max_score_pos = var.var_score_pos();
+    }
+  }
+}
+
+ClauseIdx CSolver::add_orig_clause(int * lits, int n_lits, int gid) {
+  int cid = add_clause_with_gid(lits, n_lits, gid);
+  if (cid >= 0) {
+    clause(cid).set_status(ORIGINAL_CL);
+    clause(cid).activity() = 0;
+  }
+  return cid;
+}
+
+ClauseIdx CSolver::add_clause_with_gid(int * lits, int n_lits, int gid) {
+  unsigned gflag;
+  if (gid == PERMANENT_GID )
+    gflag = 0;
+  else if (gid == VOLATILE_GID) {
+    gflag = (~0x0);
+  } else {
+    assert(gid <= WORD_WIDTH && gid > 0);
+    gflag = (1 << (gid- 1));
+  }
+  ClauseIdx cid = add_clause(lits, n_lits, gflag);
+  if (cid < 0) {
+    _stats.is_mem_out = true;
+    _stats.outcome = MEM_OUT;
+  }
+  return cid;
+}
+
+ClauseIdx CSolver::add_conflict_clause(int * lits, int n_lits, int gflag) {
+  ClauseIdx cid = add_clause(lits, n_lits, gflag);
+  if (cid >= 0) {
+    clause(cid).set_status(CONFLICT_CL);
+    clause(cid).activity() = 0;
+  } else {
+    _stats.is_mem_out = true;
+    _stats.outcome = MEM_OUT;
+  }
+  return cid;
+}
+
+void CSolver::real_solve(void) {
+  while (_stats.outcome == UNDETERMINED) {
+    run_periodic_functions();
+    if (decide_next_branch()) {
+      while (deduce() == CONFLICT) {
+        int blevel;
+        blevel = analyze_conflicts();
+        if (blevel < 0) {
+          _stats.outcome = UNSATISFIABLE;
+          return;
+        }
+      }
+    } else {
+      if (_sat_hook != NULL && _sat_hook(this))
+        continue;
+      _stats.outcome = SATISFIABLE;
+      return;
+    }
+    if (time_out()) {
+      _stats.outcome = TIME_OUT;
+      return;
+    }
+    if (_force_terminate) {
+      _stats.outcome = ABORTED;
+      return;
+    }
+    if (_stats.is_mem_out) {
+      _stats.outcome = MEM_OUT;
+       return;
+    }
+  }
+}
+
+int CSolver::solve(void) {
+  if (_stats.outcome == UNDETERMINED) {
+    init_solve();
+
+    if (preprocess() == CONFLICT)
+      _stats.outcome = UNSATISFIABLE;
+    else  // the real search
+      real_solve();
+    cout << endl;
+    _stats.finish_cpu_time = get_cpu_time();
+  }
+  return _stats.outcome;
+}
+
+void CSolver::back_track(int blevel) {
+  assert(blevel <= dlevel());
+  for (int i = dlevel(); i >= blevel; --i) {
+    vector<int> & assignments = *_assignment_stack[i];
+    for (int j = assignments.size() - 1 ; j >= 0; --j)
+      unset_var_value(assignments[j]>>1);
+    assignments.clear();
+  }
+  dlevel() = blevel - 1;
+  if (dlevel() < 0 )
+    dlevel() = 0;
+  ++_stats.num_backtracks;
+}
+
+int CSolver::deduce(void) {
+  while (!_implication_queue.empty()) {
+    const CImplication & imp = _implication_queue.front();
+    int lit = imp.lit;
+    int vid = lit>>1;
+    ClauseIdx cl = imp.antecedent;
+    _implication_queue.pop();
+    CVariable & var = variable(vid);
+    if (var.value() == UNKNOWN) {  // an implication
+      set_var_value(vid, !(lit & 0x1), cl, dlevel());
+    }
+    else if (var.value() == (unsigned)(lit & 0x1)) {
+      // a conflict
+      // note: literal & 0x1 == 1 means the literal is in negative phase
+      // when a conflict occure at not current dlevel, we need to backtrack
+      // to resolve the problem.
+      // conflict analysis will only work if the conflict occure at
+      // the top level (current dlevel)
+      _conflicts.push_back(cl);
+      break;
+    } else {
+      // so the variable have been assigned before
+      // update its antecedent with a shorter one
+      if (var.antecedent() != NULL_CLAUSE &&
+          clause(cl).num_lits() < clause(var.antecedent()).num_lits())
+        var.antecedent() = cl;
+      assert(var.dlevel() <= dlevel());
+    }
+  }
+  // if loop exited because of a conflict, we need to clean implication queue
+  while (!_implication_queue.empty())
+    _implication_queue.pop();
+  return (_conflicts.size() ? CONFLICT : NO_CONFLICT);
+}
+
+void CSolver::verify_integrity(void) {
+  for (unsigned i = 1; i < variables()->size(); ++i) {
+    if (variable(i).value() != UNKNOWN) {
+      int pos = variable(i).assgn_stack_pos();
+      int value = variable(i).value();
+      int dlevel = variable(i).dlevel();
+      assert((*_assignment_stack[dlevel])[pos] == (int) (i+i+1-value));
+    }
+  }
+  for (unsigned i = 0; i < clauses()->size(); ++i) {
+    if (clause(i).status() == DELETED_CL)
+      continue;
+    CClause & cl = clause(i);
+    int num_0 = 0;
+    int num_1 = 0;
+    int num_unknown = 0;
+    int watched[2];
+    int watch_index = 0;
+    watched[1] = watched[0] = 0;
+    for (unsigned j = 0; j < cl.num_lits(); ++j) {
+      CLitPoolElement lit = cl.literal(j);
+      int vid = lit.var_index();
+      if (variable(vid).value() == UNKNOWN) {
+        ++num_unknown;
+      } else {
+        if (literal_value(lit) == 0)
+          ++num_0;
+        else
+          ++num_1;
+      }
+      if (lit.is_watched()) {
+        watched[watch_index] = lit.s_var();
+        ++watch_index;
+      }
+    }
+    if (watch_index == 0) {
+      assert(cl.num_lits() == 1);
+      continue;
+    }
+    assert(watch_index == 2);
+    for (unsigned j = 0; j < cl.num_lits(); ++j) {
+      CLitPoolElement lit = cl.literal(j);
+      int vid1 = (watched[0]>>1);
+      if (variable(vid1).value() == (unsigned)(watched[0] & 0x1)) {
+        if (!lit.is_watched()) {
+          assert(literal_value(lit) == 0);
+          assert(variable(lit.var_index()).dlevel() <=
+                  variable(vid1).dlevel());
+        }
+      }
+      int vid2 = (watched[1]>>1);
+      if (variable(vid2).value() == (unsigned)(watched[1] & 0x1)) {
+        if (!lit.is_watched()) {
+          assert(literal_value(lit) == 0);
+          assert(variable(lit.var_index()).dlevel() <=
+                  variable(vid1).dlevel());
+        }
+      }
+    }
+  }
+}
+
+void CSolver::mark_vars(ClauseIdx cl, int var_idx) {
+  assert(_resolvents.empty() || var_idx != -1);
+#ifdef VERIFY_ON
+  _resolvents.push_back(clause(cl).id());
+#endif
+  for (CLitPoolElement* itr = clause(cl).literals(); (*itr).val() > 0; ++itr) {
+    int v = (*itr).var_index();
+    if (v == var_idx)
+      continue;
+    else if (variable(v).dlevel() == dlevel()) {
+      if (!variable(v).is_marked()) {
+        variable(v).set_marked();
+        ++_num_marked;
+        if (_mark_increase_score) {
+          int tmp = itr->s_var();
+          adjust_variable_order(&tmp, 1);
+        }
+      }
+    } else {
+      assert(variable(v).dlevel() < dlevel());
+      if (variable(v).new_cl_phase() == UNKNOWN) {  // it's not in the new cl
+        // We can remove the variable assigned at dlevel 0 if
+        // we are nog going to use incremental SAT.
+        // if(variable(v).dlevel()){
+          ++_num_in_new_cl;
+          variable(v).set_new_cl_phase((*itr).var_sign());
+          _conflict_lits.push_back((*itr).s_var());
+        // }
+       } else {
+         // if this variable is already in the new clause, it must
+         // have the same phase
+         assert(variable(v).new_cl_phase() == (*itr).var_sign());
+       }
+    }
+  }
+}
+
+int CSolver::analyze_conflicts(void) {
+  assert(!_conflicts.empty());
+  assert(_conflict_lits.size() == 0);
+  assert(_implication_queue.empty());
+  assert(_num_marked == 0);
+  if (dlevel() == 0) {  // already at level 0. Conflict means unsat.
+#ifdef VERIFY_ON
+    for (unsigned i = 1; i < variables()->size(); ++i) {
+      if (variable(i).value() != UNKNOWN) {
+        assert(variable(i).dlevel() <= 0);
+        int ante = variable(i).antecedent();
+        int ante_id = 0;
+        if (ante >= 0) {
+          ante_id = clause(ante).id();
+          assert(clause(ante).status() != DELETED_CL);
+          verify_out << "VAR: " << i
+                     << " L: " << variable(i).assgn_stack_pos()
+                     << " V: " << variable(i).value()
+                     << " A: " << ante_id
+                     << " Lits:";
+          for (unsigned j = 0; j < clause(ante).num_lits(); ++j)
+            verify_out << " " << clause(ante).literal(j).s_var();
+          verify_out << endl;
+        }
+      }
+    }
+    ClauseIdx shortest;
+    shortest = _conflicts.back();
+    unsigned len = clause(_conflicts.back()).num_lits();
+    while (!_conflicts.empty()) {
+      if (clause(_conflicts.back()).num_lits() < len) {
+        shortest = _conflicts.back();
+        len = clause(_conflicts.back()).num_lits();
+      }
+      _conflicts.pop_back();
+    }
+    verify_out << "CONF: " << clause(shortest).id() << " ==";
+    for (unsigned i = 0; i < clause(shortest).num_lits(); ++i) {
+      int svar = clause(shortest).literal(i).s_var();
+      verify_out << " " << svar;
+    }
+    verify_out << endl;
+#endif
+    _conflicts.clear();
+    back_track(0);
+    return -1;
+  }
+  return  conflict_analysis_firstUIP();
+}
+
+// when all the literals involved are in _conflict_lits
+// call this function to finish the adding clause and backtrack
+
+int CSolver::finish_add_conf_clause(int gflag) {
+  ClauseIdx added_cl = add_conflict_clause(&(*_conflict_lits.begin()),
+                                           _conflict_lits.size(), gflag);
+  if (added_cl < 0) {  // memory out.
+    _stats.is_mem_out = true;
+    _conflicts.clear();
+    assert(_implication_queue.empty());
+    return 1;
+  }
+
+  top_unsat_cls = clauses()->size() - 1;
+
+#ifdef VERIFY_ON
+  verify_out << "CL: " <<  clause(added_cl).id() << " <=";
+  for (unsigned i = 0; i< _resolvents.size(); ++i)
+        verify_out << " " <<  _resolvents[i];
+    verify_out << endl;
+    _resolvents.clear();
+#endif
+
+  adjust_variable_order(&(*_conflict_lits.begin()), _conflict_lits.size());
+
+  if (_params.shrinking.enable) {
+    _shrinking_cls.clear();
+    if (_stats.shrinking_cls_length != 0) {
+      int benefit = _stats.shrinking_cls_length - _conflict_lits.size();
+      _stats.shrinking_benefit += benefit;
+      _stats.shrinking_cls_length = 0;
+      _recent_shrinkings.push(benefit);
+      if (_recent_shrinkings.size() > _params.shrinking.window_width) {
+        _stats.shrinking_benefit -= _recent_shrinkings.front();
+        _recent_shrinkings.pop();
+      }
+    }
+    if (_conflict_lits.size() > _params.shrinking.size) {
+      _shrinking_cls.clear();
+      for (unsigned i = 0, sz = _conflict_lits.size(); i < sz; ++i) {
+        _shrinking_cls.insert(pair<int, int>
+                 (variable(_conflict_lits[i]>>1).dlevel(), _conflict_lits[i]));
+      }
+      int prev_dl = _shrinking_cls.begin()->first;
+      multimap<int, int>::iterator itr, itr_del;
+      int last_dl = _shrinking_cls.rbegin()->first;
+
+      bool found_gap = false;
+      for (itr = _shrinking_cls.begin(); itr->first != last_dl;) {
+        if (itr->first - prev_dl > 2) {
+          found_gap = true;
+          break;
+        }
+        prev_dl = itr->first;
+        itr_del = itr;
+        ++itr;
+        _shrinking_cls.erase(itr_del);
+      }
+      if (found_gap && _shrinking_cls.size() > 0 && prev_dl < dlevel() - 1) {
+        _stats.shrinking_cls_length = _conflict_lits.size();
+        ++_stats.num_shrinkings;
+        back_track(prev_dl + 1);
+        _conflicts.clear();
+#ifdef VERIFY_ON
+        _resolvents.clear();
+#endif
+        _num_in_new_cl = 0;
+        for (unsigned i = 0, sz = _conflict_lits.size(); i < sz; ++i)
+          variable(_conflict_lits[i]>>1).set_new_cl_phase(UNKNOWN);
+        _conflict_lits.clear();
+        if (_stats.num_shrinkings %
+            _params.shrinking.bound_update_frequency == 0 &&
+            _recent_shrinkings.size() == _params.shrinking.window_width) {
+          if (_stats.shrinking_benefit > _params.shrinking.upper_bound)
+            _params.shrinking.size += _params.shrinking.upper_delta;
+          else if (_stats.shrinking_benefit < _params.shrinking.lower_bound)
+            _params.shrinking.size += _params.shrinking.lower_delta;
+        }
+        return prev_dl;
+      }
+    }
+  }
+  int back_dl = 0;
+  int unit_lit = -1;
+
+  for (unsigned i = 0; i < clause(added_cl).num_lits(); ++i) {
+    int vid = clause(added_cl).literal(i).var_index();
+    int sign =clause(added_cl).literal(i).var_sign();
+    assert(variable(vid).value() != UNKNOWN);
+    assert(literal_value(clause(added_cl).literal(i)) == 0);
+    int dl = variable(vid).dlevel();
+    if (dl < dlevel()) {
+      if (dl > back_dl)
+        back_dl = dl;
+    } else {
+      assert(unit_lit == -1);
+      unit_lit = vid + vid + sign;
+    }
+  }
+  if (back_dl == 0) {
+    _stats.next_restart = _stats.num_backtracks + _stats.restart_incr;
+    _stats.next_cls_deletion = _stats.num_backtracks +
+                               _params.cls_deletion.interval;
+  }
+
+  back_track(back_dl + 1);
+  queue_implication(unit_lit, added_cl);
+
+  // after resolve the first conflict, others must also be resolved
+  // for (unsigned i = 1; i < _conflicts.size(); ++i)
+  //   assert(!is_conflicting(_conflicts[i]));
+
+  _conflicts.clear();
+
+  while (!_conflict_lits.empty()) {
+    int svar = _conflict_lits.back();
+    _conflict_lits.pop_back();
+    CVariable & var = variable(svar >> 1);
+    assert(var.new_cl_phase() == (unsigned)(svar & 0x1));
+    --_num_in_new_cl;
+    var.set_new_cl_phase(UNKNOWN);
+  }
+  assert(_num_in_new_cl == 0);
+  return back_dl;
+}
+
+int CSolver::conflict_analysis_firstUIP(void) {
+  int min_conf_id = _conflicts[0];
+  int min_conf_length = -1;
+  ClauseIdx cl;
+  unsigned gflag;
+  _mark_increase_score = false;
+  if (_conflicts.size() > 1) {
+    for (vector<ClauseIdx>::iterator ci = _conflicts.begin();
+         ci != _conflicts.end(); ci++) {
+      assert(_num_in_new_cl == 0);
+      assert(dlevel() > 0);
+      cl = *ci;
+      mark_vars(cl, -1);
+      // current dl must be the conflict cl.
+      vector <int> & assignments = *_assignment_stack[dlevel()];
+      // now add conflict lits, and unassign vars
+      for (int i = assignments.size() - 1; i >= 0; --i) {
+        int assigned = assignments[i];
+        if (variable(assigned >> 1).is_marked()) {
+          // this variable is involved in the conflict clause or its antecedent
+          variable(assigned>>1).clear_marked();
+          --_num_marked;
+          ClauseIdx ante_cl = variable(assigned>>1).get_antecedent();
+          if ( _num_marked == 0 ) {
+            // the first UIP encountered, conclude add clause
+            assert(variable(assigned>>1).new_cl_phase() == UNKNOWN);
+            // add this assignment's reverse, e.g. UIP
+            _conflict_lits.push_back(assigned ^ 0x1);
+            ++_num_in_new_cl;
+            variable(assigned>>1).set_new_cl_phase((assigned^0x1)&0x1);
+            break;
+          } else {
+            assert(ante_cl != NULL_CLAUSE);
+            mark_vars(ante_cl, assigned >> 1);
+          }
+        }
+      }
+      if (min_conf_length == -1 ||
+          (int)_conflict_lits.size() < min_conf_length) {
+        min_conf_length = _conflict_lits.size();
+        min_conf_id = cl;
+      }
+
+      for (vector<int>::iterator vi = _conflict_lits.begin(); vi !=
+           _conflict_lits.end(); ++vi) {
+        int s_var = *vi;
+        CVariable & var = variable(s_var >> 1);
+        assert(var.new_cl_phase() == (unsigned)(s_var & 0x1));
+        var.set_new_cl_phase(UNKNOWN);
+      }
+      _num_in_new_cl = 0;
+      _conflict_lits.clear();
+#ifdef VERIFY_ON
+      _resolvents.clear();
+#endif
+    }
+  }
+
+  assert(_num_marked == 0);
+  cl = min_conf_id;
+  clause(cl).activity() += 5;
+  _mark_increase_score = true;
+  mark_vars(cl, -1);
+  gflag = clause(cl).gflag();
+  vector <int> & assignments = *_assignment_stack[dlevel()];
+  for (int i = assignments.size() - 1; i >= 0; --i) {
+    int assigned = assignments[i];
+    if (variable(assigned >> 1).is_marked()) {
+      variable(assigned>>1).clear_marked();
+      --_num_marked;
+      ClauseIdx ante_cl = variable(assigned>>1).get_antecedent();
+      if ( _num_marked == 0 ) {
+        _conflict_lits.push_back(assigned ^ 0x1);
+        ++_num_in_new_cl;
+        variable(assigned >> 1).set_new_cl_phase((assigned ^ 0x1) & 0x1);
+        break;
+      } else {
+        gflag |= clause(ante_cl).gflag();
+        mark_vars(ante_cl, assigned >> 1);
+        clause(ante_cl).activity() += 5;
+      }
+    }
+  }
+  return finish_add_conf_clause(gflag);
+}
+
+void CSolver::print_cls(ostream & os) {
+  for (unsigned i = 0; i < clauses()->size(); ++i) {
+    CClause & cl = clause(i);
+    if (cl.status() == DELETED_CL)
+      continue;
+    if (cl.status() == ORIGINAL_CL) {
+      os <<"0 ";
+    } else {
+      assert(cl.status() == CONFLICT_CL);
+      os << "A ";
+    }
+    for (unsigned j = 1; j < 33; ++j)
+      os << (cl.gid(j) ? 1 : 0);
+    os << "\t";
+    for (unsigned j = 0; j < cl.num_lits(); ++j) {
+      os << (cl.literal(j).var_sign() ? "-":"")
+         << cl.literal(j).var_index() << " ";
+    }
+    os <<"0" <<  endl;
+  }
+}
+
+int CSolver::mem_usage(void) {
+  int mem_dbase = CDatabase::mem_usage();
+  int mem_assignment = 0;
+  for (int i = 0; i < _stats.max_dlevel; ++i)
+    mem_assignment += _assignment_stack[i]->capacity() * sizeof(int);
+  mem_assignment += sizeof(vector<int>)* _assignment_stack.size();
+  return mem_dbase + mem_assignment;
+}
+
+void CSolver::clean_up_dbase(void) {
+  assert(dlevel() == 0);
+
+  int mem_before = mem_usage();
+  // 1. remove all the learned clauses
+  for (vector<CClause>::iterator itr = clauses()->begin();
+       itr != clauses()->end() - 1; ++itr) {
+    CClause & cl = * itr;
+    if (cl.status() != ORIGINAL_CL)
+      mark_clause_deleted(cl);
+  }
+  // delete_unrelevant_clauses() is specialized using berkmin deletion strategy
+
+  // 2. free up the mem for the vectors if possible
+  for (unsigned i = 0; i < variables()->size(); ++i) {
+    for (unsigned j = 0; j < 2; ++j) {  // both phase
+      vector<CLitPoolElement *> watched;
+      vector<CLitPoolElement *> & old_watched = variable(i).watched(j);
+      watched.reserve(old_watched.size());
+      for (vector<CLitPoolElement *>::iterator itr = old_watched.begin();
+           itr != old_watched.end(); ++itr)
+        watched.push_back(*itr);
+        // because watched is a temp mem allocation, it will get deleted
+        // out of the scope, but by swap it with the old_watched, the
+        // contents are reserved.
+        old_watched.swap(watched);
+#ifdef KEEP_LIT_CLAUSES
+        vector<int> lits_cls;
+        vector<int> & old_lits_cls = variable(i).lit_clause(j);
+        lits_cls.reserve(old_lits_cls.size());
+        for (vector<int>::iterator itr1 = old_lits_cls.begin(); itr1 !=
+            old_lits_cls.end(); ++itr1)
+          lits_cls.push_back(*itr1);
+        old_lits_cls.swap(lits_cls);
+#endif
+    }
+  }
+
+  int mem_after = mem_usage();
+  if (_params.verbosity > 0) {
+    cout << "Database Cleaned, releasing (approximately) "
+         << mem_before - mem_after << " Bytes" << endl;
+  }
+}
+
+void CSolver::update_var_score(void) {
+  for (unsigned i = 1, sz = variables()->size(); i < sz; ++i) {
+    _ordered_vars[i-1].first = & variable(i);
+    _ordered_vars[i-1].second = variable(i).score();
+  }
+  ::stable_sort(_ordered_vars.begin(), _ordered_vars.end(), cmp_var_stat);
+  for (unsigned i = 0, sz =  _ordered_vars.size(); i < sz; ++i)
+    _ordered_vars[i].first->set_var_score_pos(i);
+  _max_score_pos = 0;
+}
+
+void CSolver::restart(void) {
+  _stats.num_restarts += 1;
+  if (_params.verbosity > 1 )
+    cout << "Restarting ... " << endl;
+  if (dlevel() > 0)
+    back_track(1);
+  assert(dlevel() == 0);
+}
+
+// this function can be called within a solving process. i.e. not after
+// solve() terminate
+int CSolver::add_clause_incr(int * lits, int num_lits, int gid) {
+  // Do not mess up with shrinking.
+  assert(!_params.shrinking.enable || _shrinking_cls.empty());
+  unsigned gflag;
+  _stats.outcome = UNDETERMINED;
+
+  if (gid == PERMANENT_GID)
+    gflag = 0;
+  else if (gid == VOLATILE_GID) {
+    gflag = ~0x0;
+  } else {
+    assert(gid <= WORD_WIDTH && gid > 0);
+    gflag = (1 << (gid - 1));
+  }
+
+  int cl = add_clause(lits, num_lits, gflag);
+  if (cl < 0)
+    return -1;
+  clause(cl).set_status(ORIGINAL_CL);
+
+  if (clause(cl).num_lits() == 1) {
+    int var_idx = clause(cl).literal(0).var_index();
+    if (literal_value(clause(cl).literal(0)) == 0 &&
+        variable(var_idx).dlevel() == 0) {
+      back_track(0);
+      if (preprocess() == CONFLICT)
+        _stats.outcome = UNSATISFIABLE;
+    } else {
+      if (dlevel() > 0)
+        back_track(1);
+      queue_implication(clause(cl).literal(0).s_var(), cl);
+    }
+    return cl;
+  }
+
+  for (unsigned i = 0, sz = clause(cl).num_lits(); i < sz; ++i) {
+    int var_idx = lits[i] >> 1;
+    int value = variable(var_idx).value();
+    if (value == UNKNOWN)
+      continue;
+    if (variable(var_idx).dlevel() == 0 &&
+        variable(var_idx).antecedent() == -1 &&
+        literal_value(clause(cl).literal(i)) == 0) {
+      back_track(0);
+      if (preprocess() == CONFLICT)
+        _stats.outcome = UNSATISFIABLE;
+      return cl;
+    }
+  }
+
+  int max_level = 0;
+  int max_level2 = 0;
+  int unit_lit = 0;
+  int unknown_count = 0;
+  int num_sat = 0;
+  int sat_dlevel = -1, max_lit = 0;
+  bool already_sat = false;
+
+  for (unsigned i = 0, sz = clause(cl).num_lits();
+       unknown_count < 2 && i < sz; ++i) {
+    int var_idx = lits[i] / 2;
+    int value = variable(var_idx).value();
+    if (value == UNKNOWN) {
+      unit_lit = clause(cl).literal(i).s_var();
+      ++unknown_count;
+    } else {
+      int dl = variable(var_idx).dlevel();
+      if (dl >= max_level) {
+        max_level2 = max_level;
+        max_level = dl;
+        max_lit = clause(cl).literal(i).s_var();
+      }
+      else if (dl > max_level2)
+        max_level2 = dl;
+      if (literal_value(clause(cl).literal(i)) == 1) {
+        already_sat = true;
+        ++num_sat;
+        sat_dlevel = dl;
+      }
+    }
+  }
+  if (unknown_count == 0) {
+    if (already_sat) {
+      assert(sat_dlevel > -1);
+      if (num_sat == 1 && sat_dlevel == max_level && max_level > max_level2) {
+        back_track(max_level2 + 1);
+        assert(max_lit > 1);
+        queue_implication(max_lit, cl);
+      }
+    } else {
+      assert(is_conflicting(cl));
+      if (max_level > max_level2) {
+        back_track(max_level2 + 1);
+        assert(max_lit > 1);
+        queue_implication(max_lit, cl);
+      } else {
+        back_track(max_level);
+        if (max_level == 0 && preprocess() == CONFLICT)
+          _stats.outcome = UNSATISFIABLE;
+      }
+    }
+  }
+  else if (unknown_count == 1) {
+    if (!already_sat) {
+      if (max_level < dlevel())
+        back_track(max_level + 1);
+      queue_implication(unit_lit, cl);
+    }
+  }
+  return cl;
+}
diff --git a/zchaff64/zchaff_solver.h b/zchaff64/zchaff_solver.h
new file mode 100644 (file)
index 0000000..54336ec
--- /dev/null
@@ -0,0 +1,408 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#ifndef __SAT_SOLVER__
+#define __SAT_SOLVER__
+
+#include "zchaff_version.h"
+#include "zchaff_dbase.h"
+
+#ifndef _SAT_STATUS_
+#define _SAT_STATUS_
+
+enum SAT_StatusT {
+  UNDETERMINED,
+  UNSATISFIABLE,
+  SATISFIABLE,
+  TIME_OUT,
+  MEM_OUT,
+  ABORTED
+};
+#endif
+
+enum SAT_DeductionT {
+  CONFLICT,
+  NO_CONFLICT
+};
+
+class CSolver;
+
+typedef void(*HookFunPtrT)(void *) ;
+typedef void(*OutsideConstraintHookPtrT)(CSolver * solver);
+typedef bool(*SatHookPtrT)(CSolver * solver);
+
+// **Struct********************************************************************
+//
+//  Synopsis    [Sat solver parameters ]
+//
+//  Description []
+//
+//  SeeAlso     []
+//
+// ****************************************************************************
+
+struct CSolverParameters {
+  float         time_limit;
+  int           verbosity;
+
+  struct {
+    unsigned    size;
+    int         enable;
+    int         upper_bound;
+    int         lower_bound;
+    int         upper_delta;
+    int         lower_delta;
+    int         bound_update_frequency;
+    unsigned    window_width;
+  } shrinking;
+
+  struct {
+    int         base_randomness;
+    int         bubble_init_step;
+    int         decay_period;
+  } decision;
+
+  struct {
+    bool        enable;
+    unsigned    interval;
+    unsigned    head_activity;
+    unsigned    tail_activity;
+    unsigned    head_num_lits;
+    unsigned    tail_num_lits;
+    int         tail_vs_head;
+  } cls_deletion;
+
+  struct {
+    bool        enable;
+    int         interval;
+    int         first_restart;
+    int         backtrack_incr;
+  } restart;
+};
+
+// **Struct********************************************************************
+//
+//  Synopsis    [Sat solver statistics ]
+//
+// Description []
+//
+//  SeeAlso     []
+//
+// ****************************************************************************
+
+struct CSolverStats {
+  bool          been_reset;  // when delete clause in incremental solving,
+                             // must reset.
+  SAT_StatusT   outcome;
+  bool          is_mem_out;  // this flag will be set if memory out
+  double        start_cpu_time;
+  double        finish_cpu_time;
+  int           current_randomness;
+  int           next_restart;
+  int           restart_incr;
+  int           next_cls_deletion;
+  int           next_var_score_decay;
+  int           num_free_variables;
+  int           num_free_branch_vars;
+  long64        total_bubble_move;
+  int           num_decisions;
+  int           num_decisions_stack_conf;
+  int           num_decisions_vsids;
+  int           num_decisions_shrinking;
+  int           num_shrinkings;
+  int           shrinking_benefit;
+  int           shrinking_cls_length;
+  int           num_backtracks;
+  int           max_dlevel;
+  int           random_seed;
+  long64        num_implications;
+  int           num_restarts;
+  int           num_del_orig_cls;
+};
+
+// **Class*********************************************************************
+//
+//  Synopsis    [Sat Solver]
+//
+//  Description [This class contains the process and datastructrues to solve
+//               the Sat problem.]
+//
+//  SeeAlso     []
+//
+// ****************************************************************************
+
+inline bool cmp_var_stat(const pair<CVariable *, int> & v1,
+                         const pair<CVariable *, int> & v2) {
+  return v1.second >= v2.second;
+}
+
+struct cmp_var_assgn_pos {
+  bool operator() (CVariable * v1, CVariable * v2) {
+    if (v1->dlevel() > v2->dlevel())
+      return true;
+    else if (v1->dlevel() < v2->dlevel())
+      return false;
+    else if (v1->assgn_stack_pos() > v2->assgn_stack_pos())
+      return true;
+    return false;
+  }
+};
+
+struct CImplication {
+  int lit;
+  int antecedent;
+};
+
+struct ImplicationQueue:queue<CImplication> {
+  void dump(ostream & os) {
+    queue<CImplication> temp(*this);
+    os << "Implication Queue Previous: " ;
+    while (!temp.empty()) {
+      CImplication a = temp.front();
+      os << "(" << ((a.lit & 0x1) ? "-" : "+") << (a.lit >> 1)
+         << ":" << a.antecedent << ")  ";
+      temp.pop();
+    }
+  }
+};
+
+class CSolver:public CDatabase {
+  protected:
+    int                 _id;                  // the id of the solver, in case
+                                              // we need to distinguish
+    bool                _force_terminate;
+    CSolverParameters   _params;              // parameters for the solver
+    CSolverStats        _stats;               // statistics and states
+
+    int                 _dlevel;              // current decision elvel
+    vector<vector<int>*>_assignment_stack;
+    queue<int>          _recent_shrinkings;
+    bool                _mark_increase_score;  // used in mark_vars during
+                                              // multiple conflict analysis
+    long64              _implication_id;
+    ImplicationQueue    _implication_queue;
+
+    // hook function run after certain number of decisions
+    vector<pair<int, pair<HookFunPtrT, int> > > _hooks;
+    OutsideConstraintHookPtrT                   _outside_constraint_hook;
+    SatHookPtrT         _sat_hook;  // hook function run after a satisfiable
+                                    // solution found, return true to continue
+                              // solving and false to terminate as satisfiable
+
+    // these are for decision making
+    int                 _max_score_pos;   // index the unassigned var with
+                                          // max score
+    vector<pair<CVariable*, int> > _ordered_vars;  // pair's first pointing to
+                                              // the var, second is the score.
+
+    // these are for conflict analysis
+    int               _num_marked;     // used when constructing learned clause
+    int               _num_in_new_cl;  // used when constructing learned clause
+    vector<ClauseIdx> _conflicts;      // the conflicting clauses
+    vector<int>       _conflict_lits;  // used when constructing learned clause
+    vector<int>       _resolvents;
+    multimap<int, int> _shrinking_cls;
+
+  protected:
+    void re_init_stats(void);
+    void init_stats(void);
+    void init_parameters(void);
+    void init_solve(void);
+    void real_solve(void);
+    void restart(void);
+    int preprocess(void);
+    int deduce(void);
+    void run_periodic_functions(void);
+
+    // for decision making
+    bool decide_next_branch(void);
+    void decay_variable_score(void) ;
+    void adjust_variable_order(int * lits, int n_lits);
+    void update_var_score(void);
+
+    // for conflict analysis
+    ClauseIdx add_conflict_clause(int * lits, int n_lits, int gflag);
+    int analyze_conflicts(void);
+    ClauseIdx finish_add_conf_clause(int gflag);
+    int conflict_analysis_firstUIP(void);
+    void mark_vars(ClauseIdx cl, int var_idx);
+    void back_track(int level);
+
+    // for bcp
+    void set_var_value(int var, int value, ClauseIdx ante, int dl);
+    void set_var_value_BCP(int v, int value);
+    void unset_var_value(int var);
+
+    // misc functions
+    bool time_out(void);
+    void delete_unrelevant_clauses(void);
+    ClauseIdx add_clause_with_gid(int * lits, int n_lits, int gid = 0);
+
+  public:
+    // constructors and destructors
+    CSolver(void);
+    ~CSolver(void);
+
+    // member access function
+    void set_time_limit(float t);
+    void set_mem_limit(int s);
+    void enable_cls_deletion(bool allow);
+    void set_randomness(int n) ;
+    void set_random_seed(int seed);
+
+    void set_variable_number(int n);
+    int add_variable(void) ;
+    void mark_var_branchable(int vid);
+    void mark_var_unbranchable(int vid);
+
+    inline int & dlevel(void) {
+      return _dlevel;
+    }
+
+    inline int outcome(void) {
+      return _stats.outcome;
+    }
+
+    inline int num_decisions(void) {
+      return _stats.num_decisions;
+    }
+
+    inline int num_decisions_stack_conf(void) {
+      return _stats.num_decisions_stack_conf;
+    }
+
+    inline int num_decisions_vsids(void) {
+      return _stats.num_decisions_vsids;
+    }
+
+    inline int num_decisions_shrinking(void) {
+      return _stats.num_decisions_shrinking;
+    }
+
+    inline int num_shrinkings(void) {
+      return _stats.num_shrinkings;
+    }
+
+    inline int & num_free_variables(void) {
+      return _stats.num_free_variables;
+    }
+
+    inline int max_dlevel(void) {
+      return _stats.max_dlevel;
+    }
+
+    inline int random_seed(void) {
+      return _stats.random_seed;
+    }
+
+    inline long64 num_implications(void) {
+      return _stats.num_implications;
+    }
+
+    inline long64 total_bubble_move(void) {
+      return _stats.total_bubble_move;
+    }
+
+    inline char * version(void) {
+      return __ZCHAFF_VERSION__;
+    }
+
+    float elapsed_cpu_time(void);
+    float cpu_run_time(void) ;
+    int estimate_mem_usage(void) {
+      return CDatabase::estimate_mem_usage();
+    }
+
+    int mem_usage(void);
+
+    void queue_implication(int lit, ClauseIdx ante_clause) {
+      CImplication i;
+      i.lit = lit;
+      i.antecedent = ante_clause;
+      _implication_queue.push(i);
+    }
+
+    // top level function
+    inline int id(void) {
+      return _id;
+    }
+
+    inline void set_id(int i) {
+      _id = i;
+    }
+
+    inline void force_terminate(void) {
+      _force_terminate = true;
+    }
+
+    inline void unset_force_terminate(void) {
+      _force_terminate = false;
+    }
+
+    // for incremental SAT
+    int add_clause_incr(int * lits, int n_lits, int gid = 0);
+
+    void make_decision(int lit) {
+        ++dlevel();
+        queue_implication(lit, NULL_CLAUSE);
+    }
+
+    void add_hook(HookFunPtrT fun, int interval);
+
+    inline void add_outside_constraint_hook(OutsideConstraintHookPtrT fun) {
+      _outside_constraint_hook = fun;
+    }
+
+    inline void add_sat_hook(SatHookPtrT fun) {
+      _sat_hook = fun;
+    }
+
+    void verify_integrity(void);
+    void delete_clause_group(int gid);
+    void reset(void);
+    int solve(void);
+    ClauseIdx add_orig_clause(int * lits, int n_lits, int gid = 0);
+    void clean_up_dbase(void);
+    void dump_assignment_stack(ostream & os = cout);
+    void dump_implication_queue(ostream & os = cout);
+
+    void print_cls(ostream & os = cout);
+    void dump(ostream & os = cout ) {
+        CDatabase::dump(os);
+        dump_assignment_stack(os);
+    }
+    void add_outside_clauses(void);
+};
+#endif
diff --git a/zchaff64/zchaff_utils.cpp b/zchaff64/zchaff_utils.cpp
new file mode 100644 (file)
index 0000000..632f2d1
--- /dev/null
@@ -0,0 +1,89 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int _global_debug_leveli = 0;
+
+int _global_check_level = 0;
+
+void fatal(char * fun, char * file, int lineno, char * fmt, ...) {
+  va_list ap;
+  fprintf(stderr, "***");
+  if (fun)
+    fprintf(stderr, " in %s", fun);
+  if (file)
+    fprintf(stderr, " at %s", file);
+  if (lineno)
+    fprintf(stderr, ":%d", lineno);
+  fprintf(stderr, " ");
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+  exit(1);
+}
+
+void warning(char * fun, char * file, int lineno, char * fmt, ...) {
+  va_list ap;
+  fprintf(stderr, "***");
+  if (fun)
+    fprintf(stderr, " in %s", fun);
+  if (file)
+    fprintf(stderr, " at %s", file);
+  if (lineno)
+    fprintf(stderr, ":%d", lineno);
+  fprintf(stderr, " ");
+
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+double get_cpu_time(void) {
+  double res;
+  struct rusage usage;
+  getrusage(RUSAGE_SELF, &usage);
+  res = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
+  res *= 1e-6;
+  res += usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
+  return res;
+}
diff --git a/zchaff64/zchaff_version.h b/zchaff64/zchaff_version.h
new file mode 100644 (file)
index 0000000..43555be
--- /dev/null
@@ -0,0 +1,38 @@
+// *********************************************************************
+// Copyright 2000-2003, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark, service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#ifndef __ZCHAFF_VERSION__
+#define __ZCHAFF_VERSION__ "zChaff 2007.3.12"
+#endif
diff --git a/zchaff64/zchaff_wrapper.wrp b/zchaff64/zchaff_wrapper.wrp
new file mode 100644 (file)
index 0000000..48cbc0a
--- /dev/null
@@ -0,0 +1,489 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// ********************************************************************
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <queue>
+#include <set>
+#include <map>
+using namespace std;
+
+#include "zchaff_solver.h"
+#include "zchaff_clsgen.h"
+
+#ifndef SAT_Manager
+#define SAT_Manager void *
+#endif
+
+// =====================================================================
+// Following are wrapper functions for C/C++ callers.
+//
+// =====================================================================
+
+EXTERN SAT_Manager SAT_InitManager(void) {
+  CSolver * solver = new CSolver;
+  return (SAT_Manager)solver;
+}
+
+EXTERN char * SAT_Version(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  return solver->version();
+}
+
+EXTERN void SAT_SetNumVariables(SAT_Manager mng, int n_var) {
+  CSolver * solver = (CSolver*) mng;
+  solver->set_variable_number(n_var);
+}
+
+EXTERN void SAT_ReleaseManager(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  delete solver;
+}
+
+EXTERN int SAT_AddVariable(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int vid = solver->add_variable();
+  return vid;
+}
+
+EXTERN void  SAT_EnableVarBranch(SAT_Manager mng, int vid) {
+  CSolver * solver = (CSolver*) mng;
+  solver->mark_var_branchable(vid);
+}
+
+EXTERN void SAT_DisableVarBranch(SAT_Manager mng, int vid) {
+  CSolver * solver = (CSolver*) mng;
+  solver->mark_var_unbranchable(vid);
+}
+
+EXTERN void SAT_SetTimeLimit(SAT_Manager mng, float runtime) {
+  CSolver * solver = (CSolver*) mng;
+  solver->set_time_limit(runtime);
+}
+
+EXTERN void SAT_SetMemLimit(SAT_Manager mng, int mem_limit) {
+  CSolver * solver = (CSolver*) mng;
+  solver->set_mem_limit(mem_limit);
+}
+
+EXTERN void SAT_AddClause(SAT_Manager           mng,
+                          int *                 clause_lits,
+                          int                   num_lits,
+                          int                   gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  solver->add_orig_clause(clause_lits, num_lits, gid);
+}
+
+EXTERN void SAT_DeleteClauseGroup(SAT_Manager   mng,
+                                  int           gid) {
+  CSolver * solver = (CSolver*) mng;
+  solver->delete_clause_group(gid);
+}
+
+EXTERN void SAT_Reset(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  solver->reset();
+}
+
+EXTERN int SAT_MergeClauseGroup(SAT_Manager     mng,
+                                int             gid1,
+                                int             gid2) {
+  CSolver * solver = (CSolver*) mng;
+  int g = solver->merge_clause_group(gid1, gid2);
+  return g;
+}
+
+EXTERN int SAT_AllocClauseGroupID(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int gid = solver->alloc_gid();
+  return gid;
+}
+
+EXTERN int SAT_GetGlobalGroupID(SAT_Manager mng) {
+  return 0;
+}
+
+EXTERN int SAT_GetVolatileGroupID(SAT_Manager mng) {
+  return -1;
+}
+
+EXTERN int SAT_Solve(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int result = solver->solve();
+  return result;
+}
+
+EXTERN void SAT_AddHookFun(SAT_Manager          mng,
+                           void(*fun)(void *),
+                           int                  interval) {
+  CSolver * solver = (CSolver*) mng;
+  solver->add_hook(fun, interval);
+}
+
+EXTERN void SAT_MakeDecision(SAT_Manager        mng,
+                             int                vid,
+                             int                sign) {
+  CSolver * solver = (CSolver*) mng;
+  solver->make_decision(vid+vid+sign);
+}
+
+EXTERN void SAT_SetRandomness(SAT_Manager        mng,
+                              int                n) {
+  CSolver * solver = (CSolver*) mng;
+  solver->set_randomness(n);
+}
+
+EXTERN void SAT_SetRandSeed(SAT_Manager         mng,
+                            int                 seed) {
+  CSolver * solver = (CSolver*) mng;
+  solver->set_random_seed(seed);
+}
+
+EXTERN int SAT_GetVarAsgnment(SAT_Manager       mng,
+                              int               v_idx) {
+  CSolver * solver = (CSolver*) mng;
+  assert(v_idx > 0 && v_idx < (int) solver->variables()->size());
+  int v = solver->variable(v_idx).value();
+  return v;
+}
+
+EXTERN int SAT_EstimateMemUsage(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int usage = solver->estimate_mem_usage();
+  return usage;
+}
+
+EXTERN float SAT_GetElapsedCPUTime(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  float time = solver->elapsed_cpu_time();
+  return time;
+}
+
+EXTERN float SAT_GetCurrentCPUTime(SAT_Manager mng) {
+  float time = get_cpu_time() / 1000.0;
+  return time;
+}
+
+EXTERN float SAT_GetCPUTime(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  float time = solver->cpu_run_time();
+  return time;
+}
+
+EXTERN int SAT_NumLiterals(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_literals();
+  return n;
+}
+
+EXTERN int SAT_NumClauses(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_clauses();
+  return n;
+}
+
+EXTERN int SAT_NumVariables(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_variables();
+  return n;
+}
+
+EXTERN int SAT_InitNumLiterals(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->init_num_literals();
+  return n;
+}
+
+EXTERN int SAT_InitNumClauses(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->init_num_clauses();
+  return n;
+}
+
+EXTERN long64 SAT_NumAddedLiterals(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  long64 n = solver->num_added_literals();
+  return n;
+}
+
+EXTERN int SAT_NumAddedClauses(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int  n =  solver->num_added_clauses();
+  return n;
+}
+
+EXTERN int SAT_NumDeletedClauses(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_deleted_clauses();
+  return n;
+}
+
+EXTERN int SAT_NumDelOrigCls(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_del_orig_cls();
+  return n;
+}
+
+EXTERN long64 SAT_NumDeletedLiterals(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  long64 n = solver->num_deleted_literals();
+  return n;
+}
+
+EXTERN int SAT_NumDecisions(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_decisions();
+  return n;
+}
+
+EXTERN int SAT_NumDecisionsStackConf(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_decisions_stack_conf();
+  return n;
+}
+
+EXTERN int SAT_NumDecisionsVsids(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_decisions_vsids();
+  return n;
+}
+
+EXTERN int SAT_NumDecisionsShrinking(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_decisions_shrinking();
+  return n;
+}
+
+EXTERN int SAT_NumShrinkings(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->num_shrinkings();
+  return n;
+}
+
+EXTERN int SAT_Random_Seed(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->random_seed();
+  return n;
+}
+
+EXTERN long64 SAT_NumImplications(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  long64 n = solver->num_implications();
+  return n;
+}
+
+EXTERN int SAT_MaxDLevel(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->max_dlevel();
+  return n;
+}
+
+EXTERN float SAT_AverageBubbleMove(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  float n = ((float) solver->total_bubble_move()) /
+    (solver->num_added_literals() - solver->init_num_literals());
+  return n;
+}
+
+EXTERN int SAT_GetFirstClause(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  for (unsigned i = 0; i < solver->clauses()->size(); ++i)
+    if (solver->clause(i).status() != DELETED_CL) {
+      return i;
+    }
+  return -1;
+}
+
+EXTERN int SAT_GetClauseType(SAT_Manager mng, int cl_idx) {
+  CSolver * solver = (CSolver*) mng;
+  int type = solver->clause(cl_idx).status();
+  return type;
+}
+
+EXTERN int SAT_IsSetClauseGroupID(SAT_Manager mng, int cl_idx, int id) {
+  CSolver * solver = (CSolver*) mng;
+  int r = solver->clause(cl_idx).gid(id);
+  return r;
+}
+
+EXTERN void SAT_ClearClauseGroupID(SAT_Manager mng, int cl_idx, int id) {
+  CSolver * solver = (CSolver*) mng;
+  solver->clause(cl_idx).clear_gid(id);
+}
+
+EXTERN void SAT_SetClauseGroupID(SAT_Manager mng, int cl_idx, int id) {
+  CSolver * solver = (CSolver*) mng;
+  solver->clause(cl_idx).set_gid(id);
+}
+
+EXTERN int SAT_GetNextClause(SAT_Manager mng, int cl_idx) {
+  CSolver * solver = (CSolver*) mng;
+  for (unsigned i = cl_idx + 1; i < solver->clauses()->size(); ++i)
+    if (solver->clause(i).status() != DELETED_CL) {
+      return i;
+    }
+  return -1;
+}
+
+EXTERN int SAT_GetClauseNumLits(SAT_Manager mng, int cl_idx) {
+  CSolver * solver = (CSolver*) mng;
+  int n = solver->clause(cl_idx).num_lits();
+  return n;
+}
+
+EXTERN void SAT_GetClauseLits(SAT_Manager mng, int cl_idx, int * lits) {
+  CSolver * solver = (CSolver*) mng;
+  for (unsigned i = 0; i < solver->clause(cl_idx).num_lits(); ++i) {
+    lits[i] = solver->clause(cl_idx).literal(i).s_var();
+  }
+}
+
+EXTERN void SAT_EnableConfClsDeletion(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  solver->enable_cls_deletion(true);
+}
+
+EXTERN void SAT_DisableConfClsDeletion(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  solver->enable_cls_deletion(false);
+}
+
+EXTERN void SAT_CleanUpDatabase(SAT_Manager mng) {
+  CSolver * solver = (CSolver*) mng;
+  solver->clean_up_dbase();
+}
+
+EXTERN void SAT_GenClsAnd2(SAT_Manager          mng,
+                           int                  a,
+                           int                  b,
+                           int                  o,
+                           int                  gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.and2(*solver, a, b, o, gid);
+}
+
+EXTERN void SAT_GenClsAndN(SAT_Manager          mng,
+                           int *                inputs,
+                           int                  num_inputs,
+                           int                  o,
+                           int                  gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.and_n(*solver, inputs, num_inputs, o, gid);
+}
+
+EXTERN void SAT_GenClsOr2(SAT_Manager           mng,
+                          int                   a,
+                          int                   b,
+                          int                   o,
+                          int                   gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.or2(*solver, a, b, o, gid);
+}
+
+EXTERN void SAT_GenClsOrN(SAT_Manager           mng,
+                          int *                 inputs,
+                          int                   num_inputs,
+                          int                   o,
+                          int                   gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.or_n(*solver, inputs, num_inputs, o, gid);
+}
+
+EXTERN void SAT_GenClsNand2(SAT_Manager         mng,
+                            int                 a,
+                            int                 b,
+                            int                 o,
+                            int                 gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.nand2(*solver, a, b, o, gid);
+}
+
+
+EXTERN void SAT_GenClsNandN(SAT_Manager         mng,
+                            int *               inputs,
+                            int                 num_inputs,
+                            int                 o,
+                            int                 gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.nand_n(*solver, inputs, num_inputs, o, gid);
+}
+
+
+EXTERN void SAT_GenClsNor2(SAT_Manager          mng,
+                           int                  a,
+                           int                  b,
+                           int                  o,
+                           int                  gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.nor2(*solver, a, b, o, gid);
+}
+
+
+EXTERN void SAT_GenClsNorN(SAT_Manager          mng,
+                           int *                inputs,
+                           int                  num_inputs,
+                           int                  o,
+                           int                  gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.nor_n(*solver, inputs, num_inputs, o, gid);
+}
+
+EXTERN void SAT_GenClsXor(SAT_Manager           mng,
+                          int                   a,
+                          int                   b,
+                          int                   o,
+                          int                   gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.xor2(*solver, a, b, o, gid);
+}
+
+EXTERN void SAT_GenClsNot(SAT_Manager           mng,
+                          int                   a,
+                          int                   o,
+                          int                   gid = 0) {
+  CSolver * solver = (CSolver*) mng;
+  CClause_Gen cls_gen;
+  cls_gen.not1(*solver, a, o, gid);
+}
diff --git a/zchaff64/zminimal.cpp b/zchaff64/zminimal.cpp
new file mode 100644 (file)
index 0000000..036dd68
--- /dev/null
@@ -0,0 +1,316 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark,  service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstdio>
+#include <set>
+#include <vector>
+
+using namespace std;
+
+#include "SAT.h"
+
+const int MAX_LINE_LENGTH       = 65536;
+const int MAX_WORD_LENGTH       = 64;
+
+void read_cnf_omit(SAT_Manager mng, char * filename, vector<int> & omit) {
+  char line_buffer[MAX_LINE_LENGTH];
+  char word_buffer[MAX_WORD_LENGTH];
+  set<int> clause_vars;
+  set<int> clause_lits;
+  unsigned omit_idx = 0;
+  int line_num = 0;
+  ifstream inp(filename, ios::in);
+  if (!inp) {
+    cerr << "Can't open input file" << endl;
+    exit(1);
+  }
+  int cl_id = -1;
+  while (inp.getline(line_buffer, MAX_LINE_LENGTH)) {
+    ++line_num;
+    if (line_buffer[0] == 'c') {
+      continue;
+    }
+    else if (line_buffer[0] == 'p') {
+      int var_num;
+      int cl_num;
+      int arg = sscanf(line_buffer, "p cnf %d %d", &var_num, &cl_num);
+      if (arg < 2) {
+        cerr << "Unable to read number of variables and clauses"
+             << "at line " << line_num << endl;
+        exit(3);
+      }
+      SAT_SetNumVariables(mng, var_num);  // first element not used.
+    } else {                             // Clause definition or continuation
+      char *lp = line_buffer;
+      do {
+        char *wp = word_buffer;
+        while (*lp && ((*lp == ' ') || (*lp == '\t'))) {
+          lp++;
+        }
+        while (*lp && (*lp != ' ') && (*lp != '\t') && (*lp != '\n')) {
+          *(wp++) = *(lp++);
+        }
+        *wp = '\0';                                 // terminate string
+
+        if (strlen(word_buffer) != 0) {     // check if number is there
+          int var_idx = atoi(word_buffer);
+          int sign = 0;
+
+          if (var_idx != 0) {
+            if (var_idx < 0) {
+              var_idx = -var_idx;
+              sign = 1;
+            }
+            clause_vars.insert(var_idx);
+            clause_lits.insert((var_idx << 1) + sign);
+          } else {
+            // add this clause
+            ++cl_id;
+            if (omit_idx < omit.size()-1 && omit[omit_idx] < cl_id )
+              ++omit_idx;
+            if (omit_idx < omit.size()) {
+              if (omit[omit_idx] == cl_id) {
+                clause_lits.clear();
+                clause_vars.clear();
+              }
+            }
+            if (clause_vars.size() != 0 &&
+                clause_vars.size() == clause_lits.size()) {
+              vector <int> temp;
+              for (set<int>::iterator itr = clause_lits.begin();
+                   itr != clause_lits.end(); ++itr) {
+                temp.push_back(*itr);
+              }
+              SAT_AddClause(mng, & temp.begin()[0], temp.size() );
+            }
+            clause_lits.clear();
+            clause_vars.clear();
+          }
+        }
+      }
+      while (*lp);
+    }
+  }
+  if (!inp.eof()) {
+    cerr << "Input line " << line_num << " too long. Unable to continue..."
+         << endl;
+    exit(2);
+  }
+
+  if (clause_lits.size() && clause_vars.size() == clause_lits.size()) {
+    vector <int> temp;
+    for (set<int>::iterator itr = clause_lits.begin();
+         itr != clause_lits.end(); ++itr) {
+      temp.push_back(*itr);
+    }
+    SAT_AddClause(mng, & temp.begin()[0], temp.size() );
+  }
+  clause_lits.clear();
+  clause_vars.clear();
+}
+
+int get_num_clause(char * filename) {
+  char line_buffer[MAX_LINE_LENGTH];
+  ifstream inp(filename, ios::in);
+  if (!inp) {
+    cerr << "Can't open input file" << endl;
+    exit(1);
+  }
+  while (inp.getline(line_buffer, MAX_LINE_LENGTH)) {
+    if (inp.fail()) {
+      cerr << "Too large an input line. Unable to continue..." << endl;
+      exit(2);
+    }
+    if (line_buffer[0] == 'p') {
+      int var_num;
+      int cl_num;
+      int arg = sscanf(line_buffer, "p cnf %d %d", &var_num, &cl_num);
+      if (arg < 2) {
+        cerr << "Unable to read number of variables and clauses" << endl;
+        exit(3);
+      }
+      return cl_num;
+    }
+  }
+  cerr << "Can't find the header in CNF:  p cnf NumVar NumCls " << endl;
+  exit(1);
+  return 0;
+}
+
+void handle_result(SAT_Manager mng, int outcome, char * filename) {
+  char * result = "UNKNOWN";
+  switch (outcome) {
+    case SATISFIABLE:
+      cout << "Instance satisfiable" << endl;
+      // following lines will print out a solution if a solution exist
+      for (unsigned i = 1, sz = SAT_NumVariables(mng); i <= sz; ++i) {
+        switch (SAT_GetVarAsgnment(mng, i)) {
+          case -1:
+            cout << "(" << i<< ")";
+            break;
+          case 0:
+            cout << "-" << i;
+            break;
+          case 1:
+            cout << i;
+            break;
+          default:
+            cerr << "Unknown variable value state"<< endl;
+            exit(4);
+        }
+        cout << " ";
+      }
+      result  = "SAT";
+      cout << endl;
+      break;
+    case UNSATISFIABLE:
+      result  = "UNSAT";
+      cout << "Instance unsatisfiable" << endl;
+      break;
+    case TIME_OUT:
+      result  = "ABORT : TIME OUT";
+      cout << "Time out, unable to determine the outcome of the instance";
+      cout << endl;
+      break;
+    case MEM_OUT:
+      result  = "ABORT : MEM OUT";
+      cout << "Memory out, unable to determine the outcome of the instance";
+      cout << endl;
+      break;
+    default:
+      cerr << "Unknown outcome" << endl;
+      exit(5);
+  }
+  cout << "Max Decision Level\t\t\t" << SAT_MaxDLevel(mng) << endl;
+  cout << "Num. of Decisions\t\t\t" << SAT_NumDecisions(mng) << endl;
+  cout << "Num. of Variables\t\t\t" << SAT_NumVariables(mng) << endl;
+  cout << "Original Num Clauses\t\t\t" << SAT_InitNumClauses(mng) << endl;
+  cout << "Original Num Literals\t\t\t" << SAT_InitNumLiterals(mng) << endl;
+  cout << "Added Conflict Clauses\t\t\t" << SAT_NumAddedClauses(mng) -
+                                            SAT_InitNumClauses(mng)<< endl;
+  cout << "Added Conflict Literals\t\t\t" << SAT_NumAddedLiterals(mng) -
+                                             SAT_InitNumLiterals(mng) << endl;
+  cout << "Deleted Unrelevant clause\t\t" << SAT_NumDeletedClauses(mng) <<endl;
+  cout << "Deleted Unrelevant literals\t\t" <<SAT_NumDeletedLiterals(mng) <<endl;
+  cout << "Number of Implication\t\t\t" << SAT_NumImplications(mng)<< endl;
+
+  // other statistics comes here
+  cout << "Total Run Time\t\t\t\t" << SAT_GetCPUTime(mng) << endl << endl;
+  cout  << result << endl;
+}
+
+void output_status(SAT_Manager mng) {
+  cout << "Dec: " << SAT_NumDecisions(mng) << "\t ";
+  cout << "AddCl: " << SAT_NumAddedClauses(mng) << "\t";
+  cout << "AddLit: " << SAT_NumAddedLiterals(mng) << "\t";
+  cout << "DelCl: " << SAT_NumDeletedClauses(mng) << "\t";
+  cout << "DelLit: " << SAT_NumDeletedLiterals(mng) << "\t";
+  cout << "NumImp: " << SAT_NumImplications(mng) << "\t";
+  cout << "AveBubbleMove: " << SAT_AverageBubbleMove(mng) << "\t";
+  // other statistics comes here
+  cout << "RunTime:" << SAT_GetElapsedCPUTime(mng) << endl;
+}
+
+void verify_solution(SAT_Manager mng) {
+  int num_verified = 0;
+  for (int cl_idx = SAT_GetFirstClause (mng); cl_idx >= 0;
+       cl_idx = SAT_GetNextClause(mng, cl_idx)) {
+    int len = SAT_GetClauseNumLits(mng, cl_idx);
+    int * lits = new int[len+1];
+    SAT_GetClauseLits(mng, cl_idx, lits);
+    int i;
+    for (i = 0; i < len; ++i) {
+      int v_idx = lits[i] >> 1;
+      int sign = lits[i] & 0x1;
+      int var_value = SAT_GetVarAsgnment(mng, v_idx);
+      if ((var_value == 1 && sign == 0) ||
+          (var_value == 0 && sign == 1))
+        break;
+    }
+    if (i >= len) {
+      cerr << "Verify Satisfiable solution failed, please "
+           << "file a bug report, thanks. " << endl;
+      exit(6);
+    }
+    delete [] lits;
+      ++num_verified;
+  }
+  cout << num_verified << " Clauses are true, Verify Solution successful. ";
+}
+
+int main(int argc, char ** argv) {
+  if (argc != 2) {
+    cerr << "ZMinimal: Find Minimal Core. " << endl;
+    cerr << "Copyright 2003-2004, Princeton University" << endl << endl;
+    cerr << "Usage: "<< argv[0] << " cnf_file " << endl;
+    return 2;
+  }
+  vector<int> omit;
+  int num_cls = get_num_clause(argv[1]);
+  cout << "Total : " << num_cls << " passes";
+  for (int i = 0; i < num_cls; ++i) {
+    if (i % 50 == 0)
+      cout << endl << i << ":\t";
+    if (i % 10 == 0)
+      cout << " ";
+    cout.flush();
+    SAT_Manager mng = SAT_InitManager();
+    omit.push_back(i);
+    read_cnf_omit(mng, argv[1], omit);
+    int result = SAT_Solve(mng);
+    if (result != SATISFIABLE) {
+      cout << "*" ;
+    } else {
+      cout << "-";
+      omit.pop_back();
+    }
+    cout.flush();
+    SAT_ReleaseManager(mng);
+  }
+  cout << endl;
+  cout << "Instance Cls: " << num_cls << "  MinCore Cls: "
+       << num_cls - omit.size() << " Diff: " << omit.size() << endl;
+  cout << "Unneeded clauses are: ";
+  for (unsigned i = 0; i < omit.size(); ++i) {
+    if (i % 20 == 0)
+      cout << endl;
+    cout << omit[i] << " ";
+  }
+  cout << endl;
+  return 0;
+}
diff --git a/zchaff64/zverify_df.cpp b/zchaff64/zverify_df.cpp
new file mode 100644 (file)
index 0000000..9c8f061
--- /dev/null
@@ -0,0 +1,798 @@
+// *********************************************************************
+// Copyright 2000-2004, Princeton University.  All rights reserved.
+// By using this software the USER indicates that he or she has read,
+// understood and will comply with the following:
+//
+// --- Princeton University hereby grants USER nonexclusive permission
+// to use, copy and/or modify this software for internal, noncommercial,
+// research purposes only. Any distribution, including commercial sale
+// or license, of this software, copies of the software, its associated
+// documentation and/or modifications of either is strictly prohibited
+// without the prior consent of Princeton University.  Title to copyright
+// to this software and its associated documentation shall at all times
+// remain with Princeton University.  Appropriate copyright notice shall
+// be placed on all software copies, and a complete copy of this notice
+// shall be included in all copies of the associated documentation.
+// No right is  granted to use in advertising, publicity or otherwise
+// any trademark, service mark, or the name of Princeton University.
+//
+//
+// --- This software and any associated documentation is provided "as is"
+//
+// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
+// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
+// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
+// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
+//
+// Princeton University shall not be liable under any circumstances for
+// any direct, indirect, special, incidental, or consequential damages
+// with respect to any claim by USER or any third party on account of
+// or arising from the use, or inability to use, this software or its
+// associated documentation, even if Princeton University has been advised
+// of the possibility of those damages.
+// *********************************************************************
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <vector>
+#include <set>
+#include <iostream>
+#include <fstream>
+#include <assert.h>
+
+using namespace std;
+
+const int WORD_LEN      = 64000;
+
+const int MEM_LIMIT     = 800000;
+
+const int UNKNOWN       = 2;
+
+int _peak_mem;
+bool _dump_core;
+
+double get_cpu_time(void) {
+  double res;
+  struct rusage usage;
+  getrusage(RUSAGE_SELF, &usage);
+  res = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
+  res *= 1e-6;
+  res += usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
+  return res;
+}
+
+void get_line(ifstream* fs, vector<char>* buf) {
+  buf->clear();
+  buf->reserve(4096);
+  while (!fs->eof()) {
+    char ch = fs->get();
+    if (ch == '\n' || ch == '\377')
+      break;
+    if (ch == '\r')
+      continue;
+    buf->push_back(ch);
+  }
+  buf->push_back('\0');
+  return;
+}
+
+int get_token(char * & lp, char * token) {
+  char * wp = token;
+  while (*lp && ((*lp == ' ') || (*lp == '\t'))) {
+    lp++;
+  }
+  while (*lp && (*lp != ' ') && (*lp != '\t') && (*lp != '\n')) {
+    *(wp++) = *(lp++);
+  }
+  *wp = '\0';                                 // terminate string
+  return wp - token;
+}
+
+int get_mem_usage(void) {
+  FILE * fp;
+  char buffer[128];
+  char token[128];
+  char filename[128];
+
+  int pid = getpid();
+  snprintf(filename, sizeof(filename), "/proc/%i/status", pid);
+  if ((fp = fopen(filename, "r")) == NULL) {
+    cerr << "Can't open Proc file, are you sure you are using Linux?" << endl;
+    exit(1);
+  }
+  while (!feof(fp)) {
+    fgets(buffer, 128, fp);
+    char * ptr = buffer;
+    get_token(ptr, token);
+    if (strcmp(token, "VmSize:") == 0) {
+      get_token(ptr, token);
+      fclose(fp);
+      return atoi(token);
+    }
+  }
+  cerr << "Error in get memeory usage" << endl;
+  exit(1);
+  return 0;
+}
+
+int my_a2i(char * str) {
+  int result = 0;
+  bool neg = false;
+  if (str[0] == '-') {
+    neg = true;
+    ++str;
+  }
+  else if (str[0] == '+')
+    ++str;
+  for (unsigned i = 0; i < strlen(str); ++i) {
+    int d = str[i] - '0';
+    if (d < 0 || d > 9) {
+      cerr << "Abort: Unable to change " << str << " into a number " << endl;
+      exit(1);
+    }
+    result = result * 10 + d;
+  }
+  if (neg)
+    result = -result;
+  return result;
+}
+
+class CClause {
+  public:
+    vector<int> literals;
+    vector<int> resolvents;
+    bool is_involved    : 1;
+    bool is_built       : 1;
+    bool is_needed      : 1;
+
+    CClause(void) {
+      is_involved = false;
+      is_built = false;
+      is_needed = false;
+    }
+    ~CClause(void) {}
+};
+
+class CVariable {
+  public:
+    short       value;
+    short       in_clause_phase         :4;
+    bool        is_needed               :1;
+    int         antecedent;
+    int         num_lits[2];
+    int         level;
+    CVariable(void) {
+      value = UNKNOWN;
+      antecedent = -1;
+      in_clause_phase = UNKNOWN;
+      num_lits[0] = num_lits[1] = 0;
+      level = -1;
+      is_needed = false;
+    }
+};
+
+struct cmp_var_level {
+  bool operator() (CVariable * v1, CVariable * v2) {
+    if (v1->level > v2->level)
+      return true;
+    else if (v1->level < v2->level)
+      return false;
+    else if (v1 > v2)
+      return true;
+    return false;
+  }
+};
+
+class CDatabase {
+  private:
+    int                 _current_num_clauses;
+    int                 _num_init_clauses;
+    vector<CVariable>   _variables;
+    vector<CClause>     _clauses;
+    int                 _conf_id;
+    vector<int>         _conf_clause;
+
+  public:
+    CDatabase(void) {
+      _num_init_clauses = 0;
+      _current_num_clauses = 0;
+      _conf_id = -1;
+    }
+
+    int & num_init_clauses(void) {
+      return _num_init_clauses;
+    }
+
+    vector<CVariable> & variables(void) {
+      return _variables;
+    }
+
+    vector<CClause> & clauses(void) {
+      return  _clauses;
+    }
+
+    void read_cnf(char * filename);
+    bool verify(char * filename);
+    bool real_verify(void);
+    int lit_value(int svar) {
+      assert(_variables[svar>>1].value != UNKNOWN);
+      return _variables[svar>>1].value ^ (svar & 0x1);
+    }
+    int add_orig_clause_by_lits(vector<int> lits);
+    int add_learned_clause_by_resolvents(vector<int> & resolvents);
+    void set_var_number(int nvar);
+    void set_init_cls_number(int n) {
+      _num_init_clauses = n;
+    }
+    void construct_learned_clauses(void);
+    void recursive_construct_clause(int cl_id);
+    void recursive_find_involved(int cl_id);
+    int recursive_find_level(int vid);
+    void dump(void);
+};
+
+void CDatabase::dump(void) {
+  cout << "p cnf " << _variables.size() - 1 << " " << _num_init_clauses << endl;
+  for (unsigned i = 0; i < _clauses.size(); ++i) {
+    for (unsigned j = 0; j < _clauses[i].literals.size(); ++j) {
+      int lit = _clauses[i].literals[j];
+      cout << ((lit & 0x1) ? "-" : "") << (lit >> 1) << " ";
+    }
+    cout << "0" << endl;
+  }
+}
+
+void CDatabase::set_var_number(int nvar) {
+  _variables.resize(nvar + 1);
+  for (unsigned i = 0; i < _variables.size(); ++i) {
+    _variables[i].value = UNKNOWN;
+    _variables[i].in_clause_phase = UNKNOWN;
+  }
+}
+
+void check_mem_out(void) {
+  int mem = get_mem_usage();
+  if (mem > MEM_LIMIT) {
+    cerr << "Mem out" << endl;
+    exit(1);
+  }
+  if (mem > _peak_mem)
+    _peak_mem = mem;
+}
+
+int CDatabase::add_orig_clause_by_lits(vector<int> lits) {
+  static int line_n = 0;
+  ++line_n;
+  if (lits.size() == 0) {
+    cerr << "Empty Clause Encountered " << endl;
+    exit(1);
+  }
+  int cls_id = _clauses.size();
+  _clauses.resize(_clauses.size() + 1);
+  vector<int> temp_cls;
+  for (unsigned i = 0; i < lits.size(); ++i) {
+    int vid = lits[i];
+    int phase = 0;
+    if (vid < 0) {
+      vid = - vid;
+      phase = 1;
+    }
+    if (vid == 0 || vid > (int) _variables.size() - 1) {
+      cerr << "Variable index out of range " << endl;
+      exit(1);
+    }
+    if (_variables[vid].in_clause_phase == UNKNOWN) {
+      _variables[vid].in_clause_phase = phase;
+      temp_cls.push_back(vid + vid + phase);
+//    _clauses[cls_id].my_literals.push_back(vid + vid + phase);
+      ++_variables[vid].num_lits[phase];
+    }
+    else if (_variables[vid].in_clause_phase != phase) {
+      cerr << "clause " << line_n << endl;
+      cerr << "A clause contain both literal and its negate " << endl;
+      exit(1);
+    }
+  }
+  _clauses[cls_id].literals.resize(temp_cls.size());
+  for (unsigned i = 0; i< temp_cls.size(); ++i) {
+    _clauses[cls_id].literals[i]= temp_cls[i];
+  }
+  _clauses[cls_id].is_built = true;
+//      _clauses[cls_id].my_is_built = true;
+  for (unsigned i = 0; i< lits.size(); ++i) {
+    int vid = lits[i];
+    if (vid < 0) vid = -vid;
+    _variables[vid].in_clause_phase = UNKNOWN;
+  }
+  ++_current_num_clauses;
+  if (_current_num_clauses%10 == 0)
+    check_mem_out();
+  return cls_id;
+}
+
+int CDatabase::add_learned_clause_by_resolvents(vector<int> & resolvents) {
+  int cls_id = _clauses.size();
+  _clauses.resize(_clauses.size() + 1);
+  _clauses[cls_id].resolvents.resize(resolvents.size());
+  for (unsigned i = 0; i< resolvents.size(); ++i)
+    _clauses[cls_id].resolvents[i] = resolvents[i];
+  _clauses[cls_id].is_built = false;
+  return cls_id;
+}
+
+void CDatabase::read_cnf(char * filename) {
+  cout << "Read in original clauses ... ";
+  ifstream in_file(filename);
+  if (!in_file) {
+    cerr << "Can't open input CNF file " << filename << endl;
+    exit(1);
+  }
+  vector<char> buffer;
+  vector<int> literals;
+  bool header_encountered = false;
+  char token[WORD_LEN];
+  while (!in_file.eof()) {
+    get_line(&in_file, &buffer);
+    char * ptr = &(*buffer.begin());
+    if (get_token(ptr, token)) {
+      if (strcmp(token, "c") == 0)
+        continue;
+      else if (strcmp(token, "p") == 0) {
+        get_token(ptr, token);
+        if (strcmp(token, "cnf") != 0) {
+          cerr << "Format Error, p cnf NumVar NumCls " << endl;
+          exit(1);
+        }
+        get_token(ptr, token);
+        int nvar = my_a2i(token);
+        set_var_number(nvar);
+        get_token(ptr, token);
+        int ncls = my_a2i(token);
+        set_init_cls_number(ncls);
+        header_encountered = true;
+        continue;
+      } else {
+        int lit = my_a2i(token);
+        if (lit != 0) {
+          literals.push_back(lit);
+        } else {
+          add_orig_clause_by_lits(literals);
+          literals.clear();
+        }
+      }
+    }
+    while (get_token(ptr, token)) {
+      int lit = my_a2i(token);
+      if (lit != 0) {
+        literals.push_back(lit);
+      } else {
+        add_orig_clause_by_lits(literals);
+        literals.clear();
+      }
+    }
+  }
+  if (!literals.empty()) {
+    cerr << "Trailing numbers without termination " << endl;
+    exit(1);
+  }
+  if (clauses().size() != (unsigned)num_init_clauses())
+    cerr << "WARNING : Clause count inconsistant with the header " << endl;
+  cout << num_init_clauses() << " Clauses " << endl;
+}
+
+void CDatabase::recursive_find_involved(int cl_id) {
+  if (_clauses[cl_id].is_involved == true)
+    return;
+  _clauses[cl_id].is_involved = true;
+
+  recursive_construct_clause(cl_id);
+
+  int num_1 = 0;
+  for (unsigned i = 0; i < _clauses[cl_id].literals.size(); ++i) {
+    int lit = _clauses[cl_id].literals[i];
+    int vid = (lit>>1);
+    int sign = (lit & 0x1);
+    assert(_variables[vid].value != UNKNOWN);
+    if ((_variables[vid].value == 1 && sign == 0) ||
+      (_variables[vid].value == 0 && sign == 1)) {
+      if (num_1 == 0) {
+        ++num_1;
+      } else {
+        cerr << "Clause " << cl_id << " has more than one value 1 literals "
+             << endl;
+        exit(1);
+      }
+    } else {  // literal value 0, so seek its antecedent
+      int ante = _variables[vid].antecedent;
+      recursive_find_involved(ante);
+    }
+  }
+}
+
+void CDatabase::recursive_construct_clause(int cl_id) {
+  CClause & cl = _clauses[cl_id];
+  if (cl.is_built == true)
+    return;
+
+  assert(cl.resolvents.size() > 1);
+
+  // I have to construct them first because of recursion may
+  // mess up with the in_clause_signs.
+  for (unsigned i = 0; i < cl.resolvents.size(); ++i) {
+    _clauses[cl.resolvents[i]].is_needed = true;
+    recursive_construct_clause(cl.resolvents[i]);
+  }
+
+//      cout << "Constructing clause " << cl_id << endl;
+  vector<int> literals;
+
+  // initialize
+  int cl1 = cl.resolvents[0];
+  assert(_clauses[cl1].is_built);
+  for (unsigned i = 0; i < _clauses[cl1].literals.size(); ++i) {
+    int lit = _clauses[cl1].literals[i];
+    int vid = (lit >> 0x1);
+    int sign = (lit & 0x1);
+    assert(_variables[vid].in_clause_phase == UNKNOWN);
+    _variables[vid].in_clause_phase = sign;
+    literals.push_back(lit);
+  }
+
+  for (unsigned i = 1; i < cl.resolvents.size(); ++i) {
+    int distance = 0;
+    int cl1 = cl.resolvents[i];
+    assert(_clauses[cl1].is_built);
+    for (unsigned j = 0; j < _clauses[cl1].literals.size(); ++j) {
+      int lit = _clauses[cl1].literals[j];
+      int vid = (lit >> 0x1);
+      int sign = (lit & 0x1);
+      if (_variables[vid].in_clause_phase == UNKNOWN) {
+        _variables[vid].in_clause_phase = sign;
+        literals.push_back(lit);
+      }
+      else if (_variables[vid].in_clause_phase != sign) {
+        // distance 1 literal
+        ++distance;
+        _variables[vid].in_clause_phase = UNKNOWN;
+      }
+    }
+    if (distance != 1) {
+      cerr << "Resolve between two clauses with distance larger than 1" << endl;
+      cerr << "The resulting clause is " << cl_id << endl;
+      cerr << "Starting clause is " << cl.resolvents[0] << endl;
+      cerr << "One of the clause involved is " << cl1 << endl;
+      exit(1);
+    }
+  }
+  vector<int> temp_cls;
+  for (unsigned i = 0; i < literals.size(); ++i) {
+    int lit = literals[i];
+    int vid = (lit >> 0x1);
+    int sign = (lit & 0x1);
+    if (_variables[vid].in_clause_phase == UNKNOWN)
+      continue;
+    assert(_variables[vid].in_clause_phase == sign);
+    _variables[vid].in_clause_phase = UNKNOWN;
+    temp_cls.push_back(lit);
+  }
+  cl.literals.resize(temp_cls.size());
+  for (unsigned i = 0; i < temp_cls.size(); ++i)
+    cl.literals[i] = temp_cls[i];
+
+//      ::sort(cl.literals.begin(), cl.literals.end());
+//      assert(cl.literals.size()== cl.my_literals.size());
+//      for (unsigned i=0; i< cl.literals.size(); ++i)
+//        assert(cl.literals[i] == cl.my_literals[i]);
+  cl.is_built = true;
+  ++_current_num_clauses;
+  if (_current_num_clauses%10 == 0)
+    check_mem_out();
+}
+
+int CDatabase::recursive_find_level(int vid) {
+  int ante = _variables[vid].antecedent;
+  assert(_variables[vid].value != UNKNOWN);
+  assert(_variables[vid].antecedent != -1);
+  assert(_clauses[ante].is_involved);
+  if (_variables[vid].level != -1)
+    return _variables[vid].level;
+  int level = -1;
+  for (unsigned i = 0; i <_clauses[ante].literals.size(); ++i) {
+    int v = (_clauses[ante].literals[i] >> 1);
+    int s = (_clauses[ante].literals[i] & 0x1);
+    if (v == vid) {
+      assert(_variables[v].value != s);
+      continue;
+    } else {
+      assert(_variables[v].value == s);
+      int l = recursive_find_level(v);
+      if (level < l )
+        level = l;
+    }
+  }
+  _variables[vid].level = level + 1;
+  return level + 1;
+}
+
+bool CDatabase::real_verify(void) {
+  // 1. If a variable is assigned value at dlevel 0,
+  // either it's pure or it has an antecedent
+  for (unsigned i = 1; i < _variables.size(); ++i) {
+    if (_variables[i].value != UNKNOWN && _variables[i].antecedent == -1) {
+      if ((_variables[i].num_lits[0] == 0 && _variables[i].value == 0) ||
+        (_variables[i].num_lits[1] == 0 && _variables[i].value == 1)) {
+//      cout << "Variable " << i << " is assigned " << _variables[i].value
+//      << " because it is pure literal. " << endl;
+      } else {
+        cerr << "Don't know why variable " << i << " is assigned "
+             << _variables[i].value << " for no reasons" << endl;
+        exit(1);
+      }
+    }
+  }
+  // 2. Construct the final conflicting clause if needed and find all
+  // the clauses that are involved in making it conflicting
+  cout << "Begin constructing all involved clauses " << endl;
+  _clauses[_conf_id].is_needed = true;
+  recursive_find_involved(_conf_id);
+  int count = 0;
+  for (unsigned i = num_init_clauses(); i< _clauses.size(); ++i)
+    if (_clauses[i].is_built)
+      ++count;
+  cout << "Num. Learned Clause:\t\t\t" << _clauses.size() - num_init_clauses()
+       << endl
+       << "Num. Clause Built:\t\t\t" << count << endl
+       << "Constructed all involved clauses " << endl;
+
+  // 2.5. Verify the literals in the CONF clause
+  // comments this out if it gives error because you give the wrong
+  // CONF clause literals.
+  assert(_clauses[_conf_id].is_built);
+  assert(_clauses[_conf_id].is_involved);
+  bool _found;
+  for (unsigned i = 0; i <_conf_clause.size(); ++i) {
+    _found = false;
+    for (unsigned j = 0; j <_clauses[_conf_id].literals.size(); ++j) {
+      if (_conf_clause[i] == _clauses[_conf_id].literals[j]) {
+        _found = true;
+        break;
+      }
+    }
+    if (!_found) {
+      cerr << "The conflict clause in trace can't be verified! " << endl;
+      cerr << "Literal " << _conf_clause[i] << " is not found." << endl;
+    }
+  }
+  cout << "Conflict clause verification finished." << endl;
+
+  // 3. Levelize the variables that are decided at dlevel 0
+  cout << "Levelize variables...";
+  for (unsigned i = 1; i < _variables.size(); ++i) {
+    int cl_id = _variables[i].antecedent;
+    if (_variables[i].value != UNKNOWN &&  cl_id != -1) {
+      if (_clauses[cl_id].is_involved) {
+        int level = recursive_find_level(i);
+        // cout << "Var: " << i << " level " << level << endl;
+      }
+    }
+  }
+  cout << "finished"<< endl;
+  // 4. Can we construct an empty clause?
+  cout << "Begin Resolution..." ;
+  set<CVariable *, cmp_var_level> clause_lits;
+  for (unsigned i = 0; i< _clauses[_conf_id].literals.size(); ++i) {
+    assert(lit_value(_clauses[_conf_id].literals[i]) == 0);
+    int vid = (_clauses[_conf_id].literals[i] >> 1);
+    clause_lits.insert(&_variables[vid]);
+  }
+  assert(clause_lits.size() == _clauses[_conf_id].literals.size());
+
+  while (!clause_lits.empty()) {
+//    for (set<CVariable *, cmp_var_level>::iterator itr = clause_lits.begin();
+//         itr != clause_lits.end(); ++itr) {
+//      int vid = (*itr) - &_variables[0];
+//      cout << vid << "(" << (*itr)->level << ") ";
+//    }
+//    cout << endl;
+
+    int vid = (*clause_lits.begin() - &_variables[0]);
+    int ante = _variables[vid].antecedent;
+    if (ante == -1) {
+      cerr << "Variable " << vid << " has an NULL antecedent ";
+      exit(1);
+    }
+    _clauses[ante].is_needed = true;
+    clause_lits.erase(clause_lits.begin());
+    _variables[vid].in_clause_phase = 1;
+    CClause & cl = _clauses[ante];
+    int distance = 0;
+    for (unsigned i = 0; i< cl.literals.size(); ++i) {
+      int l = cl.literals[i];
+      int v = (l>>1);
+      assert(_variables[v].value != UNKNOWN);
+      if (lit_value(l) == 1) {
+        if (vid != v) {
+          cerr << "The antecedent of the variable is not really an antecedent "
+               << endl;
+          exit(1);
+        }
+        else
+          ++distance;
+      }
+      else
+        clause_lits.insert(&_variables[v]);
+    }
+    assert(distance == 1);
+  }
+  cout << " Empty clause generated." << endl;
+  cout << "Mem Usage :\t\t\t\t" << get_mem_usage()<< endl;
+  int needed_cls_count = 0;
+  int needed_var_count = 0;
+  for (int i = 0; i < num_init_clauses(); ++i) {
+    if (_clauses[i].is_needed == true) {
+      ++needed_cls_count;
+      for (unsigned j = 0; j < _clauses[i].literals.size(); ++j) {
+        int vid = (_clauses[i].literals[j] >> 1);
+        if (_variables[vid].is_needed == false) {
+          ++needed_var_count;
+          _variables[vid].is_needed = true;
+        }
+      }
+    }
+  }
+  cout << "Original Num. Clauses:\t\t\t" << num_init_clauses() << endl;
+  cout << "Needed Clauses to Construct Empty:\t"<< needed_cls_count << endl;
+  cout << "Total Variable count:\t\t\t" << _variables.size()-1 << endl;
+  cout << "Variables involved in Empty:\t\t" << needed_var_count << endl;
+
+  for (unsigned i = 0; i< _clauses.size(); ++i) {
+    if (_clauses[i].is_built)
+      assert(_clauses[i].is_needed || i < (unsigned)num_init_clauses());
+  }
+  if (_dump_core == true) {
+    cout << "Unsat Core dumped:\t\t\tunsat_core.cnf" << endl;
+    ofstream dump("unsat_core.cnf");
+    dump << "c Variables Not Involved: ";
+    unsigned int k = 0;
+    for (unsigned i = 1; i < _variables.size(); ++i) {
+      if (_variables[i].is_needed == false) {
+        if (k%20 == 0)
+          dump << endl << "c ";
+        ++k;
+        dump << i << " ";
+      }
+    }
+    dump << endl;
+    dump << "p cnf " << _variables.size()-1 << " " << needed_cls_count << endl;
+    for (int i = 0; i < num_init_clauses(); ++i) {
+      if (_clauses[i].is_needed) {
+        dump << "c Original Cls ID: " << i << endl;
+        for (unsigned j = 0; j < _clauses[i].literals.size(); ++j) {
+          dump << ((_clauses[i].literals[j] & 0x1)?" -":" ")
+               << (_clauses[i].literals[j] >> 1);
+        }
+        dump << " 0" << endl;
+      }
+    }
+  }
+  return true;
+}
+
+bool CDatabase::verify(char * filename) {
+  vector<char> buffer;
+  char token[WORD_LEN];
+
+  ifstream in_file(filename);
+  if (!in_file) {
+    cerr << "Can't open input CNF file " << filename << endl;
+    exit(1);
+  }
+
+  while (!in_file.eof()) {
+    get_line(&in_file, &buffer);
+    char * ptr = &(*buffer.begin());
+    get_token(ptr, token);
+    if (strcmp(token, "CL:") == 0) {
+      vector<int> resolvents;
+
+      get_token(ptr, token);
+      int cl_id = my_a2i(token);
+
+      get_token(ptr, token);
+      assert(strcmp(token, "<=") == 0);
+
+      while (get_token(ptr, token)) {
+        int r = my_a2i(token);
+        resolvents.push_back(r);
+      }
+      int c = add_learned_clause_by_resolvents(resolvents);
+      assert(c == cl_id);
+    }
+    else if (strcmp(token, "VAR:") == 0) {
+      get_token(ptr, token);
+      int vid = my_a2i(token);
+
+      get_token(ptr, token);
+      assert(strcmp(token, "L:") == 0);
+      get_token(ptr, token);  // skip the level
+
+      get_token(ptr, token);
+      assert(strcmp(token, "V:") == 0);
+      get_token(ptr, token);
+      int value = my_a2i(token);
+      assert(value == 1 || value == 0);
+
+      get_token(ptr, token);
+      assert(strcmp(token, "A:") == 0);
+      get_token(ptr, token);
+      int ante = my_a2i(token);
+
+      get_token(ptr, token);
+      assert(strcmp(token, "Lits:") == 0);
+
+      _variables[vid].value = value;
+      _variables[vid].antecedent = ante;
+    }
+    else if (strcmp(token, "CONF:") == 0) {
+      get_token(ptr, token);
+      _conf_id = my_a2i(token);
+
+      get_token(ptr, token);
+      assert(strcmp(token, "==") == 0);
+
+      while (get_token(ptr, token)) {
+        int lit = my_a2i(token);
+        assert(lit > 0);
+        assert((lit>>1) < (int)_variables.size());
+        _conf_clause.push_back(lit);
+      }
+    }
+  }
+  if (_conf_id == -1) {
+    cerr << "No final conflicting clause defined " << endl;
+    exit(1);
+  }
+  cout << "Mem Usage After Readin file:\t\t" << get_mem_usage() << endl;
+  return real_verify();
+}
+
+int main(int argc, char** argv) {
+  cout << "ZVerify SAT Solver Verifier" << endl;
+  cout << "Copyright Princeton University, 2003-2004. All Right Reseverd."
+       << endl;
+  if (argc != 3 && argc !=4) {
+    cerr << "Usage: " << argv[0] << " CNF_File Dump_File [-core]" << endl
+       << "-core: dump the unsat core " << endl;
+    cerr << endl;
+    exit(1);
+  }
+  if (argc == 3) {
+    _dump_core = false;
+  } else {
+    assert(argc == 4);
+    if (strcmp(argv[3], "-core") != 0) {
+      cerr << "Must use -core as the third parameter" << endl;
+      exit(1);
+    }
+    _dump_core = true;
+  }
+  cout << "COMMAND LINE: ";
+  for (int i = 0; i < argc; ++i)
+    cout << argv[i] << " ";
+  cout << endl;
+
+  _peak_mem = get_mem_usage();
+  CDatabase dbase;
+  double begin_time = get_cpu_time();
+  dbase.read_cnf(argv[1]);
+  if (dbase.verify(argv[2]) == true) {
+    double end_time = get_cpu_time();
+    cout << "CPU Time:\t\t\t\t" << end_time - begin_time << endl;
+    cout << "Peak Mem Usage:\t\t\t\t" << _peak_mem << endl;
+    cout << "Verification Successful " << endl;
+  } else {
+    cout << "Failed to verify the result " << endl;
+  }
+  return 0;
+}