Merging a squash of the branch timothy-king/CVC4/glpknecfix c95bf7d4f1 into master...
authorTim King <taking@cs.nyu.edu>
Fri, 7 Mar 2014 23:00:37 +0000 (18:00 -0500)
committerTim King <taking@cs.nyu.edu>
Fri, 7 Mar 2014 23:00:52 +0000 (18:00 -0500)
48 files changed:
config/glpk.m4
src/Makefile.am
src/theory/arith/approx_simplex.cpp
src/theory/arith/approx_simplex.h
src/theory/arith/arith_ite_utils.cpp [new file with mode: 0644]
src/theory/arith/arith_ite_utils.h [new file with mode: 0644]
src/theory/arith/arith_rewriter.cpp
src/theory/arith/arith_static_learner.cpp
src/theory/arith/arith_static_learner.h
src/theory/arith/arith_utilities.h
src/theory/arith/callbacks.cpp
src/theory/arith/callbacks.h
src/theory/arith/congruence_manager.cpp
src/theory/arith/congruence_manager.h
src/theory/arith/constraint.cpp
src/theory/arith/constraint.h
src/theory/arith/constraint_forward.h
src/theory/arith/cut_log.cpp [new file with mode: 0644]
src/theory/arith/cut_log.h [new file with mode: 0644]
src/theory/arith/dio_solver.cpp
src/theory/arith/dio_solver.h
src/theory/arith/error_set.cpp
src/theory/arith/error_set.h
src/theory/arith/fc_simplex.cpp
src/theory/arith/linear_equality.cpp
src/theory/arith/linear_equality.h
src/theory/arith/matrix.h
src/theory/arith/normal_form.cpp
src/theory/arith/normal_form.h
src/theory/arith/options
src/theory/arith/partial_model.cpp
src/theory/arith/partial_model.h
src/theory/arith/simplex.cpp
src/theory/arith/simplex.h
src/theory/arith/simplex_update.cpp
src/theory/arith/simplex_update.h
src/theory/arith/soi_simplex.cpp
src/theory/arith/soi_simplex.h
src/theory/arith/tableau.h
src/theory/arith/theory_arith_private.cpp
src/theory/arith/theory_arith_private.h
src/theory/theory_engine.cpp
src/theory/theory_engine.h
src/util/rational_cln_imp.cpp
src/util/rational_cln_imp.h
src/util/rational_gmp_imp.cpp
src/util/rational_gmp_imp.h
test/regress/regress0/Makefile.am

index 6c59a3094861ca66b9fef8887aa55b14e6cd82e7..932b053e0f40e7d9c0a55547538c29cbc202a688 100644 (file)
@@ -95,7 +95,7 @@ if test -z "$GLPK_LIBS"; then
                                   [#else]
                                   [#include <glpk.h>]
                                   [#endif],
-                                  [int i = lpx_get_int_parm(NULL, LPX_K_ITCNT)])],
+                                  [int i = glp_get_it_cnt(NULL)])],
     [GLPK_LIBS="-lglpk $1"],
     [])
   LIBS="$cvc4_save_LIBS"
@@ -118,7 +118,7 @@ if test -z "$GLPK_LIBS"; then
                                   [#else]
                                   [#include <glpk.h>]
                                   [#endif],
-                                  [int i = lpx_get_int_parm(NULL, LPX_K_ITCNT)])],
+                                  [int i = glp_get_it_cnt(NULL)])],
     [GLPK_LIBS="-lglpk $1"],
     [])
   LIBS="$cvc4_save_LIBS"
index 279e52e09e63d00c7cc2d1e9887c1fc067c1054e..64e3eb93286dcda90c560a12fc6c6ebeeb90a38c 100644 (file)
@@ -329,6 +329,8 @@ libcvc4_la_SOURCES = \
        theory/arith/arithvar.h \
        theory/arith/arithvar.cpp \
        theory/arith/bound_counts.h \
+       theory/arith/arith_ite_utils.h \
+       theory/arith/arith_ite_utils.cpp \
        theory/arith/arith_rewriter.h \
        theory/arith/arith_rewriter.cpp \
        theory/arith/arith_static_learner.h \
@@ -384,6 +386,8 @@ libcvc4_la_SOURCES = \
        theory/arith/arith_unate_lemma_mode.cpp \
        theory/arith/arith_propagation_mode.h \
        theory/arith/arith_propagation_mode.cpp \
+       theory/arith/cut_log.h \
+       theory/arith/cut_log.cpp \
        theory/arith/options_handlers.h \
        theory/booleans/type_enumerator.h \
        theory/booleans/theory_bool.h \
index 1b3099842803738ed2fa59cd098e0862b8c30734..9f6b1796ed5b05cc18091fe81f2414aeeb9fdba4 100644 (file)
 #include "theory/arith/approx_simplex.h"
 #include "theory/arith/normal_form.h"
 #include "theory/arith/constraint.h"
+#include "theory/arith/cut_log.h"
+#include "theory/arith/matrix.h"
 #include <math.h>
 #include <cmath>
+#include <cfloat>
+#include <map>
 
 using namespace std;
 
@@ -29,13 +33,229 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
-ApproximateSimplex::ApproximateSimplex() :
-  d_pivotLimit(std::numeric_limits<int>::max())
+struct AuxInfo {
+  TreeLog* tl;
+  int pivotLimit;
+  int branchLimit;
+  int branchDepth;
+  MipResult term; /* terminatation */
+};
+
+enum SlackReplace { SlackUndef=0, SlackLB, SlackUB, SlackVLB, SlackVUB };
+
+std::ostream& operator<<(std::ostream& out, MipResult res){
+  switch(res){
+  case MipUnknown:
+    out << "MipUnknown"; break;
+  case MipBingo:
+    out << "MipBingo"; break;
+  case MipClosed:
+    out << "MipClosed"; break;
+  case BranchesExhausted:
+    out << "BranchesExhausted"; break;
+  case PivotsExhauasted:
+    out << "PivotsExhauasted"; break;
+  case ExecExhausted:
+    out << "ExecExhausted"; break;
+  default:
+    out << "Unexpected Mip Value!"; break;
+  }
+  return out;
+}
+struct VirtualBound {
+  // Either x <= d * y or x >= d * y
+  ArithVar x; // variable being bounded
+  Kind k; // either LEQ or GEQ
+  Rational d; // the multiple on y
+  ArithVar y; // the variable that is the upper bound
+  ConstraintP c; // the original constraint relating x and y
+
+  VirtualBound()
+    : x(ARITHVAR_SENTINEL)
+    , k(kind::UNDEFINED_KIND)
+    , d()
+    , y(ARITHVAR_SENTINEL)
+    , c(NullConstraint)
+  {}
+  VirtualBound(ArithVar toBound, Kind rel, const Rational& coeff, ArithVar bounding, ConstraintP orig)
+    : x(toBound)
+    , k(rel)
+    , d(coeff)
+    , y(bounding)
+    , c(orig)
+  { Assert(k == kind::LEQ || k == kind::GEQ); }
+};
+
+struct CutScratchPad {
+  bool d_failure; // if the construction was unsuccessful
+
+  /* GOMORY CUTS Datastructures */
+  ArithVar d_basic; // a variable that is basic in the approximate solver
+  DenseVector d_tabRow;           // a row in the tableau not including d_basic, equal to 0
+  DenseMap<ConstraintP> d_toBound; // each variable in toBound maps each variable in tabRow to either an upper/lower bound
+
+  /* MIR CUTS Datastructures */
+  DenseMap<SlackReplace> d_slacks;// The x'[i] selected for x[i]
+  DenseMap<VirtualBound> d_vub;   // Virtual upper bounds.
+  DenseMap<VirtualBound> d_vlb;   // Virtual lower bounds.
+  DenseMap<Rational> d_compRanges;
+
+  // a sum of rows in the tableau, with possible replacements for fixed
+  // sum aggLhs[i] x[i] = aggRhs;
+  DenseVector d_agg;
+  // Takes agg and replaces x[i] with a slack variable x'[i]
+  // Takes agg and replaces x[i] with a slack variable x'[i]
+  // sum modLhs[i] x'[i] = modRhs;
+  DenseVector d_mod;
+
+  // Takes mod, and performs c-Mir on it
+  // sum alpha[i] x'[i] <= beta
+  DenseVector d_alpha;
+
+  /* The constructed cut */
+  // sum cut[i] x[i] <= cutRhs
+  DenseVector d_cut;
+  Kind d_cutKind;
+
+  /* The constraints used throughout construction. */
+  std::set<ConstraintP> d_explanation; // use pointer equality
+  CutScratchPad(){
+    clear();
+  }
+  void clear(){
+    d_failure = false;
+    d_basic = ARITHVAR_SENTINEL;
+    d_tabRow.purge();
+    d_toBound.purge();
+
+    d_slacks.purge();
+    d_vub.purge();
+    d_vlb.purge();
+    d_compRanges.purge();
+
+    d_agg.purge();
+    d_mod.purge();
+    d_alpha.purge();
+
+    d_cut.purge();
+    d_cutKind = kind::UNDEFINED_KIND;
+    d_explanation.clear();
+  }
+};
+ApproximateStatistics::ApproximateStatistics()
+  // : d_relaxCalls("z::approx::relaxCalls",0)
+  // ,  d_relaxUnknowns("z::approx::relaxUnknowns",0)
+  // ,  d_relaxFeasible("z::approx::relaxFeasible",0)
+  // ,  d_relaxInfeasible("z::approx::relaxInfeasible",0)
+  // ,  d_relaxPivotsExhausted("z::approx::relaxPivotsExhausted",0)
+  // ,  d_mipCalls("z::approx::mipCalls",0)
+  // ,  d_mipUnknowns("z::approx::mipUnknowns",0)
+  // ,  d_mipBingo("z::approx::mipBingo",0)
+  // ,  d_mipClosed("z::approx::mipClosed",0)
+  // ,  d_mipBranchesExhausted("z::approx::mipBranchesExhausted",0)
+  // ,  d_mipPivotsExhausted("z::approx::mipPivotsExhausted",0)
+  // ,  d_mipExecExhausted("z::approx::mipExecExhausted",0)
+  // ,  d_gmiGen("z::approx::gmiGen",0)
+  // ,  d_gmiReplay("z::approx::gmiReplay",0)
+  // ,  d_mipGen("z::approx::mipGen",0)
+  // ,  d_mipReplay("z::approx::mipReplay",0)
+  :  d_branchMaxDepth("z::approx::branchMaxDepth",0)
+  ,  d_branchesMaxOnAVar("z::approx::branchesMaxOnAVar",0)
+  //,  d_branchTotal("z::approx::branchTotal",0)
+  //,  d_branchCuts("z::approx::branchCuts",0)
+
+  ,  d_gaussianElimConstructTime("z::approx::gaussianElimConstruct::time")
+  ,  d_gaussianElimConstruct("z::approx::gaussianElimConstruct::calls",0)
+  ,  d_averageGuesses("z::approx::averageGuesses")
+{
+  // StatisticsRegistry::registerStat(&d_relaxCalls);
+  // StatisticsRegistry::registerStat(&d_relaxUnknowns);
+  // StatisticsRegistry::registerStat(&d_relaxFeasible);
+  // StatisticsRegistry::registerStat(&d_relaxInfeasible);
+  // StatisticsRegistry::registerStat(&d_relaxPivotsExhausted);
+
+  // StatisticsRegistry::registerStat(&d_mipCalls);
+  // StatisticsRegistry::registerStat(&d_mipUnknowns);
+  // StatisticsRegistry::registerStat(&d_mipBingo);
+  // StatisticsRegistry::registerStat(&d_mipClosed);
+  // StatisticsRegistry::registerStat(&d_mipBranchesExhausted);
+  // StatisticsRegistry::registerStat(&d_mipPivotsExhausted);
+  // StatisticsRegistry::registerStat(&d_mipExecExhausted);
+
+
+  // StatisticsRegistry::registerStat(&d_gmiGen);
+  // StatisticsRegistry::registerStat(&d_gmiReplay);
+  // StatisticsRegistry::registerStat(&d_mipGen);
+  // StatisticsRegistry::registerStat(&d_mipReplay);
+
+  StatisticsRegistry::registerStat(&d_branchMaxDepth);
+  //StatisticsRegistry::registerStat(&d_branchTotal);
+  //StatisticsRegistry::registerStat(&d_branchCuts);
+  StatisticsRegistry::registerStat(&d_branchesMaxOnAVar);
+
+  StatisticsRegistry::registerStat(&d_gaussianElimConstructTime);
+  StatisticsRegistry::registerStat(&d_gaussianElimConstruct);
+
+  StatisticsRegistry::registerStat(&d_averageGuesses);
+}
+
+ApproximateStatistics::~ApproximateStatistics(){
+  // StatisticsRegistry::unregisterStat(&d_relaxCalls);
+  // StatisticsRegistry::unregisterStat(&d_relaxUnknowns);
+  // StatisticsRegistry::unregisterStat(&d_relaxFeasible);
+  // StatisticsRegistry::unregisterStat(&d_relaxInfeasible);
+  // StatisticsRegistry::unregisterStat(&d_relaxPivotsExhausted);
+
+  // StatisticsRegistry::unregisterStat(&d_mipCalls);
+  // StatisticsRegistry::unregisterStat(&d_mipUnknowns);
+  // StatisticsRegistry::unregisterStat(&d_mipBingo);
+  // StatisticsRegistry::unregisterStat(&d_mipClosed);
+  // StatisticsRegistry::unregisterStat(&d_mipBranchesExhausted);
+  // StatisticsRegistry::unregisterStat(&d_mipPivotsExhausted);
+  // StatisticsRegistry::unregisterStat(&d_mipExecExhausted);
+
+
+  // StatisticsRegistry::unregisterStat(&d_gmiGen);
+  // StatisticsRegistry::unregisterStat(&d_gmiReplay);
+  // StatisticsRegistry::unregisterStat(&d_mipGen);
+  // StatisticsRegistry::unregisterStat(&d_mipReplay);
+
+  StatisticsRegistry::unregisterStat(&d_branchMaxDepth);
+  //StatisticsRegistry::unregisterStat(&d_branchTotal);
+  //StatisticsRegistry::unregisterStat(&d_branchCuts);
+  StatisticsRegistry::unregisterStat(&d_branchesMaxOnAVar);
+
+  StatisticsRegistry::unregisterStat(&d_gaussianElimConstructTime);
+  StatisticsRegistry::unregisterStat(&d_gaussianElimConstruct);
+
+  StatisticsRegistry::unregisterStat(&d_averageGuesses);
+}
+
+Integer ApproximateSimplex::s_defaultMaxDenom(1<<26);
+
+ApproximateSimplex::ApproximateSimplex(const ArithVariables& v, TreeLog& l,
+                                       ApproximateStatistics& s)
+  : d_vars(v)
+  , d_log(l)
+  , d_stats(s)
+  , d_pivotLimit(std::numeric_limits<int>::max())
+  , d_branchLimit(std::numeric_limits<int>::max())
+  , d_maxDepth(std::numeric_limits<int>::max())
 {}
 
-void ApproximateSimplex::setPivotLimit(int pivotLimit){
-  Assert(pivotLimit >= 0);
-  d_pivotLimit = pivotLimit;
+void ApproximateSimplex::setPivotLimit(int pl){
+  Assert(pl >= 0);
+  d_pivotLimit = pl;
+}
+
+void ApproximateSimplex::setBranchingDepth(int bd){
+  Assert(bd >= 0);
+  d_maxDepth = bd;
+}
+
+void ApproximateSimplex::setBranchOnVariableLimit(int bl){
+  Assert(bl >= 0);
+  d_branchLimit = bl;
 }
 
 const double ApproximateSimplex::SMALL_FIXED_DELTA = .000000001;
@@ -77,7 +297,7 @@ std::vector<Integer> ApproximateSimplex::rationalToCfe(const Rational& q, int de
       mods.push_back(Integer());
       Integer& back = mods.back();
       back = carry.floor();
-      //cout << "  cfe["<<i<<"]: " << back << endl;
+      Debug("rationalToCfe") << "  cfe["<<i<<"]: " << back << endl;
       carry -= back;
       if(carry.isZero()){
         break;
@@ -91,24 +311,85 @@ std::vector<Integer> ApproximateSimplex::rationalToCfe(const Rational& q, int de
   return mods;
 }
 
-Rational ApproximateSimplex::estimateWithCFE(const Rational& q, int depth){
-  std::vector<Integer> cfe = rationalToCfe(q,depth);
-  return cfeToRational(cfe);
+
+Rational ApproximateSimplex::estimateWithCFE(const Rational& r, const Integer& K){
+  Debug("estimateWithCFE") << "estimateWithCFE(" << r << ", " << K << ")" <<endl;
+  // references
+  // page 4: http://carlossicoli.free.fr/C/Cassels_J.W.S.-An_introduction_to_diophantine_approximation-University_Press(1965).pdf
+  // http://en.wikipedia.org/wiki/Continued_fraction
+  Assert(K >= Integer(1));
+  if( r.getDenominator() <= K ){
+    return r;
+  }
+
+  // current numerator and denominator that has not been resolved in the cfe
+  Integer num = r.getNumerator(), den = r.getDenominator();
+  Integer quot,rem;
+
+  unsigned t = 0;
+  // For a sequence of candidate solutions q_t/p_t
+  // we keep only 3 time steps: 0[prev], 1[current], 2[next]
+  // timesteps with a fake timestep 0 (p is 0 and q is 1)
+  // at timestep 1
+  Integer p[3]; // h
+  Integer q[3]; // k
+  // load the first 3 time steps manually
+  p[0] =    0; q[0] = 1; // timestep -2
+  p[1] =    1; q[1] = 0; // timestep -1
+
+  Integer::floorQR(quot, rem, num, den);
+  num = den; den = rem;
+
+  q[2] = q[0] + quot*q[1];
+  p[2] = p[0] + quot*p[1];
+  Debug("estimateWithCFE") <<  "  cfe["<<t<<"]: " << p[2] <<"/"<< q[2] << endl;
+  while( q[2] <= K ){
+    p[0] = p[1]; p[1] = p[2];
+    q[0] = q[1]; q[1] = q[2];
+
+
+    Integer::floorQR(quot, rem, num, den);
+    num = den; den = rem;
+
+    p[2] = p[0]+quot*p[1];
+    q[2] = q[0]+quot*q[1];
+    ++t;
+    Debug("estimateWithCFE") << "  cfe["<<t<<"]: " << p[2] <<"/"<< q[2] << endl;
+  }
+
+  Integer k = (K-q[0]).floorDivideQuotient(q[1]);
+  Rational cand_prev(p[0]+k*p[1], q[0]+k*q[1]);
+  Rational cand_curr(p[1], q[1]);
+  Rational dist_prev = (cand_prev - r).abs();
+  Rational dist_curr = (cand_curr - r).abs();
+  if(dist_prev <= dist_curr){
+    Debug("estimateWithCFE") << cand_prev << " is closer than " << cand_curr << endl;
+    return cand_prev;
+  }else{
+    Debug("estimateWithCFE") << cand_curr << " is closer than " << cand_prev << endl;
+    return cand_curr;
+  }
+}
+
+Rational ApproximateSimplex::estimateWithCFE(double d, const Integer& D) throw (RationalFromDoubleException){
+  return estimateWithCFE(Rational::fromDouble(d), D);
 }
 
-Rational ApproximateSimplex::estimateWithCFE(double d){
-  return estimateWithCFE(Rational::fromDouble(d), 10);
+Rational ApproximateSimplex::estimateWithCFE(double d) throw (RationalFromDoubleException){
+  return estimateWithCFE(d, s_defaultMaxDenom);
 }
 
 class ApproxNoOp : public ApproximateSimplex {
 public:
-  ApproxNoOp(const ArithVariables& vars){}
+  ApproxNoOp(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s)
+  : ApproximateSimplex(v,l,s)
+  {}
   ~ApproxNoOp(){}
 
-  virtual ApproxResult solveRelaxation(){
-    return ApproxError;
+  virtual LinResult solveRelaxation(){
+    return LinUnknown;
   }
-  virtual Solution extractRelaxation() const{
+  virtual Solution extractRelaxation() const throw (RationalFromDoubleException){
     return Solution();
   }
 
@@ -116,14 +397,31 @@ public:
     return ArithRatPairVec();
   }
 
-  virtual ApproxResult solveMIP(){
-    return ApproxError;
+  virtual MipResult solveMIP(bool al){
+    return MipUnknown;
   }
-  virtual Solution extractMIP() const{
+  virtual Solution extractMIP() const throw (RationalFromDoubleException){
     return Solution();
   }
 
   virtual void setOptCoeffs(const ArithRatPairVec& ref){}
+  virtual std::vector<const CutInfo*> getValidCuts(const std::set<const NodeLog*>& nodes){
+    return std::vector<const CutInfo*>();
+  }
+
+  virtual void tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException){}
+
+  virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& node) throw(RationalFromDoubleException){
+    return std::vector<const CutInfo*>();
+  }
+
+  virtual ArithVar getBranchVar(const NodeLog& nl) const{
+    return ARITHVAR_SENTINEL;
+  }
+
+  virtual double sumInfeasibilities(bool mip) const{
+    return 0.0;
+  }
 };
 
 }/* CVC4::theory::arith namespace */
@@ -146,14 +444,33 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
+Kind glpk_type_to_kind(int glpk_cut_type){
+  switch(glpk_cut_type){
+  case GLP_LO: return kind::GEQ;
+  case GLP_UP: return kind::LEQ;
+  case GLP_FX: return kind::EQUAL;
+  case GLP_DB:
+  case GLP_FR:
+  default:     return kind::UNDEFINED_KIND;
+  }
+}
+
+class GmiInfo;
+class MirInfo;
+class BranchCutInfo;
+
 class ApproxGLPK : public ApproximateSimplex {
 private:
-  glp_prob* d_prob;
-  const ArithVariables& d_vars;
+  glp_prob* d_inputProb; /* a copy of the input prob */
+  glp_prob* d_realProb;  /* a copy of the real relaxation output */
+  glp_prob* d_mipProb;   /* a copy of the integer prob */
 
   DenseMap<int> d_colIndices;
   DenseMap<int> d_rowIndices;
 
+  NodeLog::RowIdMap d_rootRowIds;
+  //DenseMap<ArithVar> d_rowToArithVar;
+  DenseMap<ArithVar> d_colToArithVar;
 
   int d_instanceID;
 
@@ -162,27 +479,127 @@ private:
 
   static int s_verbosity;
 
+  CutScratchPad d_pad;
+
+  std::vector<Integer> d_denomGuesses;
+
 public:
-  ApproxGLPK(const ArithVariables& vars);
+  ApproxGLPK(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s);
   ~ApproxGLPK();
 
-  virtual ApproxResult solveRelaxation();
-  virtual Solution extractRelaxation() const{
+  virtual LinResult solveRelaxation();
+  virtual Solution extractRelaxation() const throw (RationalFromDoubleException){
     return extractSolution(false);
   }
 
   virtual ArithRatPairVec heuristicOptCoeffs() const;
 
-  virtual ApproxResult solveMIP();
-  virtual Solution extractMIP() const{
+  virtual MipResult solveMIP(bool al);
+  virtual Solution extractMIP() const throw (RationalFromDoubleException){
     return extractSolution(true);
   }
   virtual void setOptCoeffs(const ArithRatPairVec& ref);
+  //void getValidCuts(const NodeLog& con, std::vector<const CutInfo*>& out);
+  virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& nodes) throw (RationalFromDoubleException);
+  //virtual std::vector<const NodeLog*> getBranches();
+
+  //Node downBranchLiteral(const NodeLog& con) const;
+  ArithVar getBranchVar(const NodeLog& con) const;
 
   static void printGLPKStatus(int status, std::ostream& out);
+
+
 private:
-  Solution extractSolution(bool mip) const;
+  Solution extractSolution(bool mip) const throw (RationalFromDoubleException);
   int guessDir(ArithVar v) const;
+
+  // get this stuff out of here
+  void tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException);
+
+  ArithVar _getArithVar(int nid, int M, int ind) const;
+  ArithVar getArithVarFromRow(int nid, int ind) const {
+    if(ind >= 0){
+      const NodeLog& nl = d_log.getNode(nid);
+      return nl.lookupRowId(ind);
+    }
+    return ARITHVAR_SENTINEL;
+  }
+
+  // virtual void mapRowId(int nid, int ind, ArithVar v){
+  //   NodeLog& nl = d_log.getNode(nid);
+  //   nl.mapRowId(ind, v);
+  // }
+  // virtual void applyRowsDeleted(int nid, const RowsDeleted& rd){
+  //   NodeLog& nl = d_log.getNode(nid);
+  //   nl.applyRowsDeleted(rd);
+  // }
+
+  ArithVar getArithVarFromStructural(int ind) const{
+    if(ind >= 0){
+      unsigned u = (unsigned) ind;
+      if(d_colToArithVar.isKey(u)){
+        return d_colToArithVar[u];
+      }
+    }
+    return ARITHVAR_SENTINEL;
+  }
+
+  /**
+   * Attempts to make the row vector vec on the pad.
+   * If this is not in the row span of the original tableau this
+   * raises the failure flag.
+   */
+  bool attemptConstructTableRow(int node, int M, const PrimitiveVec& vec);
+  bool guessCoefficientsConstructTableRow(int node, int M, const PrimitiveVec& vec);
+  bool guessCoefficientsConstructTableRow(int node, int M, const PrimitiveVec& vec, const Integer& D);
+  bool gaussianElimConstructTableRow(int node, int M, const PrimitiveVec& vec);
+
+  /* This is a guess of a vector in the row span of the tableau.
+   * Attempt to cancel out all of the variables.
+   * returns true if this is constructable.
+   */
+  bool guessIsConstructable(const DenseMap<Rational>& guess) const;
+
+  /**
+   * Loads a vector of statuses into a dense map over bounds.
+   * returns true on failure.
+   */
+  bool loadToBound(int node, int M, int len, int* inds, int* statuses,
+                   DenseMap<ConstraintP>& toBound) const;
+
+  /** checks the cut on the pad for whether it is sufficiently similar to cut. */
+  bool checkCutOnPad(int nid, const CutInfo& cut) const;
+
+
+  /** turns the pad into a node and creates an explanation. */
+  //std::pair<Node, Node> makeCutNodes(int nid, const CutInfo& cut) const;
+
+  // true means failure!
+  // BRANCH CUTS
+  bool attemptBranchCut(int nid, const BranchCutInfo& br);
+
+  // GOMORY CUTS
+  bool attemptGmi(int nid, const GmiInfo& gmi);
+  /** tries to turn the information on the pad into a cut. */
+  bool constructGmiCut();
+
+  // MIR CUTS
+  bool attemptMir(int nid, const MirInfo& mir);
+  bool applyCMIRRule(int nid, const MirInfo& mir);
+  bool makeRangeForComplemented(int nid, const MirInfo& mir);
+  bool loadSlacksIntoPad(int nid, const MirInfo& mir);
+  bool loadVirtualBoundsIntoPad(int nid, const MirInfo& mir);
+  bool loadRowSumIntoAgg(int nid, int M, const PrimitiveVec& mir);
+  bool buildModifiedRow(int nid, const MirInfo& mir);
+  bool constructMixedKnapsack();
+  bool replaceSlacksOnCuts();
+  bool loadVB(int nid, int M, int j, int ri, bool wantUb, VirtualBound& tmp);
+
+
+  double sumInfeasibilities(bool mip) const{
+    return sumInfeasibilities(mip? d_mipProb : d_realProb);
+  }
+  double sumInfeasibilities(glp_prob* prob, bool mip) const;
 };
 
 int ApproxGLPK::s_verbosity = 0;
@@ -197,11 +614,11 @@ int ApproxGLPK::s_verbosity = 0;
 namespace CVC4 {
 namespace theory {
 namespace arith {
-ApproximateSimplex* ApproximateSimplex::mkApproximateSimplexSolver(const ArithVariables& vars){
+ApproximateSimplex* ApproximateSimplex::mkApproximateSimplexSolver(const ArithVariables& vars, TreeLog& l, ApproximateStatistics& s){
 #ifdef CVC4_USE_GLPK
-  return new ApproxGLPK(vars);
+  return new ApproxGLPK(vars, l, s);
 #else
-  return new ApproxNoOp(vars);
+  return new ApproxNoOp(vars, l, s);
 #endif
 }
 bool ApproximateSimplex::enabled() {
@@ -223,16 +640,38 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
-ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
-  d_vars(avars), d_solvedRelaxation(false), d_solvedMIP(false)
+static CutInfoKlass fromGlpkClass(int klass){
+  switch(klass){
+  case GLP_RF_GMI: return GmiCutKlass;
+  case GLP_RF_MIR: return MirCutKlass;
+  case GLP_RF_COV:
+  case GLP_RF_CLQ:
+  default:         return UnknownKlass;
+  }
+}
+
+ApproxGLPK::ApproxGLPK(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s)
+  : ApproximateSimplex(v, l, s)
+  , d_inputProb(NULL)
+  , d_realProb(NULL)
+  , d_mipProb(NULL)
+  , d_solvedRelaxation(false)
+  , d_solvedMIP(false)
 {
   static int instance = 0;
   ++instance;
   d_instanceID = instance;
 
-  d_prob = glp_create_prob();
-  glp_set_obj_dir(d_prob, GLP_MAX);
-  glp_set_prob_name(d_prob, "ApproximateSimplex::approximateFindModel");
+  d_denomGuesses.push_back(Integer(1<<22));
+  d_denomGuesses.push_back(ApproximateSimplex::s_defaultMaxDenom);
+  d_denomGuesses.push_back(Integer(1ul<<29));
+  d_denomGuesses.push_back(Integer(1ul<<31));
+
+  d_inputProb = glp_create_prob();
+  d_realProb = glp_create_prob();
+  d_mipProb = glp_create_prob();
+  glp_set_obj_dir(d_inputProb, GLP_MAX);
+  glp_set_prob_name(d_inputProb, "ApproximateSimplex::approximateFindModel");
 
   int numRows = 0;
   int numCols = 0;
@@ -241,24 +680,35 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
   for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
     ArithVar v = *vi;
 
-    if(d_vars.isSlack(v)){
+    if(d_vars.isAuxiliary(v)){
       ++numRows;
       d_rowIndices.set(v, numRows);
+      //mapRowId(d_log.getRootId(), numRows, v);
+      d_rootRowIds.insert(make_pair(numRows, v));
+      //d_rowToArithVar.set(numRows, v);
+      Debug("approx") << "Row vars: " << v << "<->" << numRows << endl;
     }else{
       ++numCols;
       d_colIndices.set(v, numCols);
+      d_colToArithVar.set(numCols, v);
+      Debug("approx") << "Col vars: " << v << "<->" << numCols << endl;
     }
   }
-  glp_add_rows(d_prob, numRows);
-  glp_add_cols(d_prob, numCols);
+  Assert(numRows > 0);
+  Assert(numCols > 0);
+
+
+
+  glp_add_rows(d_inputProb, numRows);
+  glp_add_cols(d_inputProb, numCols);
 
   // Assign the upper/lower bounds and types to each variable
   for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
     ArithVar v = *vi;
 
     if(s_verbosity >= 2){
-      Message() << v  << " ";
-      d_vars.printModel(v, Message());
+      //Message() << v  << " ";
+      //d_vars.printModel(v, Message());
     }
 
     int type;
@@ -282,14 +732,15 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
       type = GLP_FR;
     }
 
-    if(d_vars.isSlack(v)){
+    if(d_vars.isAuxiliary(v)){
       int rowIndex = d_rowIndices[v];
-      glp_set_row_bnds(d_prob, rowIndex, type, lb, ub);
+      glp_set_row_bnds(d_inputProb, rowIndex, type, lb, ub);
     }else{
       int colIndex = d_colIndices[v];
+      // is input is correct here
       int kind = d_vars.isInteger(v) ? GLP_IV : GLP_CV;
-      glp_set_col_kind(d_prob, colIndex, kind);
-      glp_set_col_bnds(d_prob, colIndex, type, lb, ub);
+      glp_set_col_kind(d_inputProb, colIndex, kind);
+      glp_set_col_bnds(d_inputProb, colIndex, type, lb, ub);
     }
   }
 
@@ -333,7 +784,7 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
       ar[entryCounter] = coeff;
     }
   }
-  glp_load_matrix(d_prob, numEntries, ia, ja, ar);
+  glp_load_matrix(d_inputProb, numEntries, ia, ja, ar);
 
   delete[] ia;
   delete[] ja;
@@ -410,12 +861,12 @@ ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
 
     if(type != GLP_FX && type != GLP_FR){
 
-      if(d_vars.isSlack(v)){
+      if(d_vars.isAuxiliary(v)){
         Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
         uint32_t len = p.size();
         d_rowCandidates.set(v, len);
         sumRowLength += len;
-        maxRowLength =std::max(maxRowLength, len);
+        maxRowLength = std::max(maxRowLength, len);
       }else if(!d_vars.isInteger(v)){
         d_colCandidates.set(v, BoundCounts());
       }
@@ -430,7 +881,7 @@ ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
     bool ubCap = !d_vars.hasLowerBound(v) && d_vars.hasUpperBound(v);
 
     if(lbCap || ubCap){
-      Constraint b = lbCap ? d_vars.getLowerBoundConstraint(v)
+      ConstraintP b = lbCap ? d_vars.getLowerBoundConstraint(v)
         : d_vars.getUpperBoundConstraint(v);
 
       if(!(b->getValue()).noninfinitesimalIsZero()){ continue; }
@@ -530,7 +981,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
     ArithVar v = (*i).first;
     const Rational& q = (*i).second;
 
-    if(d_vars.isSlack(v)){
+    if(d_vars.isAuxiliary(v)){
       // replace the variable by its definition and multiply by q
       Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
       Polynomial pq = p * q;
@@ -563,7 +1014,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
   for(DenseMap<double>::const_iterator ci =nbCoeffs.begin(), ciend = nbCoeffs.end(); ci != ciend; ++ci){
     Index colIndex = *ci;
     double coeff = nbCoeffs[colIndex];
-    glp_set_obj_coef(d_prob, colIndex, coeff);
+    glp_set_obj_coef(d_inputProb, colIndex, coeff);
   }
 }
 
@@ -610,11 +1061,14 @@ void ApproxGLPK::printGLPKStatus(int status, std::ostream& out){
 }
 
 ApproxGLPK::~ApproxGLPK(){
-  glp_delete_prob(d_prob);
+  glp_delete_prob(d_inputProb);
+  glp_delete_prob(d_realProb);
+  glp_delete_prob(d_mipProb);
+
 }
 
 
-ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
+ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const throw (RationalFromDoubleException){
   Assert(d_solvedRelaxation);
   Assert(!mip  || d_solvedMIP);
 
@@ -622,12 +1076,15 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
   DenseSet& newBasis = sol.newBasis;
   DenseMap<DeltaRational>& newValues = sol.newValues;
 
+  glp_prob* prob = mip ? d_mipProb : d_realProb;
+
   for(ArithVariables::var_iterator i = d_vars.var_begin(), i_end = d_vars.var_end(); i != i_end; ++i){
     ArithVar vi = *i;
-    bool isSlack = d_vars.isSlack(vi);
-    int glpk_index = isSlack ? d_rowIndices[vi] : d_colIndices[vi];
+    bool isAux = d_vars.isAuxiliary(vi);
+    int glpk_index = isAux ? d_rowIndices[vi] : d_colIndices[vi];
 
-    int status = isSlack ? glp_get_row_stat(d_prob, glpk_index) : glp_get_col_stat(d_prob, glpk_index);
+    int status = isAux ? glp_get_row_stat(prob, glpk_index)
+      : glp_get_col_stat(prob, glpk_index);
     if(s_verbosity >= 2){
       Message() << "assignment " << vi << endl;
     }
@@ -667,10 +1124,14 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
     if(useDefaultAssignment){
       if(s_verbosity >= 2){ Message() << "non-basic other" << endl; }
 
-      double newAssign =
-        mip ?
-        (isSlack ? glp_mip_row_val(d_prob, glpk_index) :  glp_mip_col_val(d_prob, glpk_index))
-        : (isSlack ? glp_get_row_prim(d_prob, glpk_index) :  glp_get_col_prim(d_prob, glpk_index));
+      double newAssign;
+      if(mip){
+        newAssign = (isAux ? glp_mip_row_val(prob, glpk_index)
+                     :  glp_mip_col_val(prob, glpk_index));
+      }else{
+        newAssign = (isAux ? glp_get_row_prim(prob, glpk_index)
+                     :  glp_get_col_prim(prob, glpk_index));
+      }
       const DeltaRational& oldAssign = d_vars.getAssignment(vi);
 
 
@@ -718,7 +1179,51 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
   return sol;
 }
 
-ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
+double ApproxGLPK::sumInfeasibilities(glp_prob* prob, bool mip) const{
+  /* compute the sum of dual infeasibilities */
+  double infeas = 0.0;
+
+  for(ArithVariables::var_iterator i = d_vars.var_begin(), i_end = d_vars.var_end(); i != i_end; ++i){
+    ArithVar vi = *i;
+    bool isAux = d_vars.isAuxiliary(vi);
+    int glpk_index = isAux ? d_rowIndices[vi] : d_colIndices[vi];
+
+    double newAssign;
+    if(mip){
+      newAssign = (isAux ? glp_mip_row_val(prob, glpk_index)
+                   :  glp_mip_col_val(prob, glpk_index));
+    }else{
+      newAssign = (isAux ? glp_get_row_prim(prob, glpk_index)
+                   :  glp_get_col_prim(prob, glpk_index));
+    }
+
+
+    double ub = isAux ?
+      glp_get_row_ub(prob, glpk_index) : glp_get_col_ub(prob, glpk_index);
+
+    double lb = isAux ?
+      glp_get_row_lb(prob, glpk_index) : glp_get_col_lb(prob, glpk_index);
+
+    if(ub != +DBL_MAX){
+      if(newAssign > ub){
+        double ubinf = newAssign - ub;
+        infeas += ubinf;
+        Debug("approx::soi") << "ub inf" << vi << " " << ubinf << " " << infeas << endl;
+      }
+    }
+    if(lb != -DBL_MAX){
+      if(newAssign < lb){
+        double lbinf = lb - newAssign;
+        infeas  += lbinf;
+
+        Debug("approx::soi") << "lb inf" << vi << " " << lbinf << " " << infeas << endl;
+      }
+    }
+  }
+  return infeas;
+}
+
+LinResult ApproxGLPK::solveRelaxation(){
   Assert(!d_solvedRelaxation);
 
   glp_smcp parm;
@@ -732,51 +1237,563 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
     parm.msg_lev = GLP_MSG_ALL;
   }
 
-  int res = glp_simplex(d_prob, &parm);
+  glp_erase_prob(d_realProb);
+  glp_copy_prob(d_realProb, d_inputProb, GLP_OFF);
+
+  int res = glp_simplex(d_realProb, &parm);
   switch(res){
   case 0:
     {
-      int status = glp_get_status(d_prob);
+      int status = glp_get_status(d_realProb);
+      int iterationcount = glp_get_it_cnt(d_realProb);
       switch(status){
       case GLP_OPT:
       case GLP_FEAS:
       case GLP_UNBND:
         d_solvedRelaxation = true;
-        return ApproxSat;
+        return LinFeasible;
       case GLP_INFEAS:
       case GLP_NOFEAS:
         d_solvedRelaxation = true;
-        return ApproxUnsat;
+        return LinInfeasible;
       default:
-        return ApproxError;
+        {
+          if(iterationcount >= d_pivotLimit){
+            return LinExhausted;
+          }
+          return LinUnknown;
+        }
       }
     }
   default:
-    return ApproxError;
+    return LinUnknown;
+  }
+}
+
+
+struct MirInfo : public CutInfo {
+
+  /** a sum of input rows. */
+  PrimitiveVec row_sum;
+
+  /* the delta used */
+  double delta;
+
+  /* all of these are length vars == N+M*/
+  int nvars;
+  char* cset;
+  char* subst;
+  int*  vlbRows;
+  int*  vubRows;
+  MirInfo(int execOrd, int ord)
+    : CutInfo(MirCutKlass, execOrd, ord)
+    , nvars(0)
+    , cset(NULL)
+    , subst(NULL)
+    , vlbRows(NULL)
+    , vubRows(NULL)
+  {}
+
+  ~MirInfo(){
+    clearSets();
+  }
+  void clearSets(){
+    if(cset != NULL){
+      delete[] cset;
+      delete[] subst;
+      delete[] vlbRows;
+      delete[] vubRows;
+      cset = NULL;
+      nvars = 0;
+    }
+  }
+  void initSet(){
+    Assert(d_N >= 0);
+    Assert(d_mAtCreation >= 0);
+    clearSets();
+
+    int vars = 1 + d_N + d_mAtCreation;
+
+    cset = new char[1+vars];
+    subst = new char[1+vars];
+    vlbRows = new int[1+vars];
+    vubRows = new int[1+vars];
+  }
+};
+
+struct GmiInfo : public CutInfo {
+  int basic;
+  PrimitiveVec tab_row;
+  int* tab_statuses;
+  /* has the length tab_row.length */
+
+  GmiInfo(int execOrd, int ord)
+    : CutInfo(GmiCutKlass, execOrd, ord)
+    , basic(-1)
+    , tab_row()
+    , tab_statuses(NULL)
+  {
+    Assert(!initialized_tab());
+  }
+
+  ~GmiInfo(){
+    if(initialized_tab()){
+      clear_tab();
+    }
+  }
+
+  bool initialized_tab() const {
+    return tab_statuses != NULL;
+  }
+
+  void init_tab(int N){
+    if(initialized_tab()){
+      clear_tab();
+    }
+    tab_row.setup(N);
+    tab_statuses = new int[1+N];
+  }
+
+  void clear_tab() {
+    delete[] tab_statuses;
+    tab_statuses = NULL;
+    tab_row.clear();
+    basic = -1;
+  }
+};
+
+
+
+static void loadCut(glp_tree *tree, CutInfo* cut){
+  int ord, cut_len, cut_klass;
+  int N, M;
+  int* cut_inds;
+  double* cut_coeffs;
+  int glpk_cut_type;
+  double cut_rhs;
+  glp_prob* lp;
+
+  lp = glp_ios_get_prob(tree);
+  ord = cut->poolOrdinal();
+
+  N = glp_get_num_cols(lp);
+  M = glp_get_num_rows(lp);
+
+  cut->setDimensions(N, M);
+
+
+
+  // Get the cut
+  cut_len = glp_ios_get_cut(tree, ord, NULL, NULL, &cut_klass, NULL, NULL);
+  Assert(fromGlpkClass(cut_klass) == cut->getKlass());
+
+  PrimitiveVec& cut_vec = cut->getCutVector();
+  cut_vec.setup(cut_len);
+  cut_inds = cut_vec.inds;
+  cut_coeffs = cut_vec.coeffs;
+
+  cut_vec.len = glp_ios_get_cut(tree, ord, cut_inds, cut_coeffs, &cut_klass, &glpk_cut_type, &cut_rhs);
+  Assert(fromGlpkClass(cut_klass) == cut->getKlass());
+  Assert(cut_vec.len == cut_len);
+
+  cut->setRhs(cut_rhs);
+
+  cut->setKind( glpk_type_to_kind(glpk_cut_type) );
+}
+
+
+static MirInfo* mirCut(glp_tree *tree, int exec_ord, int cut_ord){
+  Debug("approx::mirCut") << "mirCut()" << exec_ord << endl;
+
+  MirInfo* mir;
+  mir = new MirInfo(exec_ord, cut_ord);
+  loadCut(tree, mir);
+  mir->initSet();
+
+
+  int nrows = glp_ios_cut_get_aux_nrows(tree, cut_ord);
+
+  PrimitiveVec& row_sum = mir->row_sum;
+  row_sum.setup(nrows);
+  glp_ios_cut_get_aux_rows(tree, cut_ord, row_sum.inds, row_sum.coeffs);
+
+  glp_ios_cut_get_mir_cset(tree, cut_ord, mir->cset);
+  mir->delta = glp_ios_cut_get_mir_delta(tree, cut_ord);
+  glp_ios_cut_get_mir_subst(tree, cut_ord, mir->subst);
+  glp_ios_cut_get_mir_virtual_rows(tree, cut_ord, mir->vlbRows, mir->vubRows);
+
+  if(Debug.isOn("approx::mirCut")){
+    Debug("approx::mirCut") << "mir_id: " << exec_ord << endl;
+    row_sum.print(Debug("approx::mirCut"));
+  }
+
+  return mir;
+}
+
+static GmiInfo* gmiCut(glp_tree *tree, int exec_ord, int cut_ord){
+  Debug("approx::gmiCut") << "gmiCut()" << exec_ord << endl;
+
+  int gmi_var;
+  int write_pos;
+  int read_pos;
+  int stat;
+  int ind;
+  int i;
+
+  GmiInfo* gmi;
+  glp_prob* lp;
+
+  gmi = new GmiInfo(exec_ord, cut_ord);
+  loadCut(tree, gmi);
+
+  lp = glp_ios_get_prob(tree);
+
+  int N = gmi->getN();
+  int M = gmi->getMAtCreation();
+
+  // Get the tableau row
+  int nrows CVC4_UNUSED = glp_ios_cut_get_aux_nrows(tree, gmi->poolOrdinal());
+  Assert(nrows == 1);
+  int rows[1+1];
+  glp_ios_cut_get_aux_rows(tree, gmi->poolOrdinal(), rows, NULL);
+  gmi_var = rows[1];
+
+  gmi->init_tab(N);
+  gmi->basic = M+gmi_var;
+
+  Debug("approx::gmiCut")
+    << gmi <<" " << gmi->basic << " "
+    << cut_ord<<" "  << M <<" " << gmi_var << endl;
+
+  PrimitiveVec& tab_row = gmi->tab_row;
+  Debug("approx::gmiCut") << "Is N sufficient here?" << endl;
+  tab_row.len = glp_eval_tab_row(lp, gmi->basic, tab_row.inds, tab_row.coeffs);
+
+  Debug("approx::gmiCut") << "gmi_var " << gmi_var << endl;
+
+  Debug("approx::gmiCut") << "tab_pos " << tab_row.len << endl;
+  write_pos = 1;
+  for(read_pos = 1; read_pos <= tab_row.len; ++read_pos){
+    if (fabs(tab_row.coeffs[read_pos]) < 1e-10){
+    }else{
+      tab_row.coeffs[write_pos] = tab_row.coeffs[read_pos];
+      tab_row.inds[write_pos] = tab_row.inds[read_pos];
+      ++write_pos;
+    }
+  }
+  tab_row.len = write_pos-1;
+  Debug("approx::gmiCut") << "write_pos " << write_pos << endl;
+  Assert(tab_row.len > 0);
+
+  for(i = 1; i <= tab_row.len; ++i){
+    ind = tab_row.inds[i];
+    Debug("approx::gmiCut") << "ind " << i << " " << ind << endl;
+    stat = (ind <= M) ?
+      glp_get_row_stat(lp, ind) : glp_get_col_stat(lp, ind - M);
+
+    Debug("approx::gmiCut") << "ind " << i << " " << ind << " stat " << stat << endl;
+    switch (stat){
+    case GLP_NL:
+    case GLP_NU:
+    case GLP_NS:
+      gmi->tab_statuses[i] = stat;
+      break;
+    case GLP_NF:
+    default:
+      Unreachable();
+    }
+  }
+
+  if(Debug.isOn("approx::gmiCut")){
+    gmi->print(Debug("approx::gmiCut"));
+  }
+  return gmi;
+}
+
+static BranchCutInfo* branchCut(glp_tree *tree, int exec_ord, int br_var, double br_val, bool down_bad){
+  //(tree, br_var, br_val, dn < 0);
+  double rhs;
+  Kind k;
+  if(down_bad){
+    // down branch is infeasible
+    // x <= floor(v) is infeasible
+    // - so x >= ceiling(v) is implied
+    k = kind::GEQ;
+    rhs = std::ceil(br_val);
+  }else{
+    // up branch is infeasible
+    // x >= ceiling(v) is infeasible
+    // - so x <= floor(v) is implied
+    k = kind::LEQ;
+    rhs = std::floor(br_val);
   }
+  BranchCutInfo* br_cut = new BranchCutInfo(exec_ord, br_var, k, rhs);
+  return br_cut;
 }
 
-void stopAtBingoOrPivotLimit(glp_tree *tree, void *info){
-  int pivotLimit = *((int*)info);
+static void glpkCallback(glp_tree *tree, void *info){
+  AuxInfo* aux = (AuxInfo*)(info);
+  TreeLog& tl = *(aux->tl);
+
+  int exec = tl.getExecutionOrd();
+  int glpk_node_p = -1;
+  int node_ord = -1;
+
+  if(tl.isActivelyLogging()){
+    switch(glp_ios_reason(tree)){
+    case GLP_LI_DELROW:
+      {
+        glpk_node_p = glp_ios_curr_node(tree);
+        node_ord = glp_ios_node_ord(tree, glpk_node_p);
+
+        int nrows = glp_ios_rows_deleted(tree, NULL);
+        int* num = new int[1+nrows];
+        glp_ios_rows_deleted(tree, num);
+
+        NodeLog& node = tl.getNode(node_ord);
+
+        RowsDeleted* rd = new RowsDeleted(exec, nrows, num);
+
+        node.addCut(rd);
+        delete num;
+      }
+      break;
+    case GLP_ICUTADDED:
+      {
+        int cut_ord = glp_ios_pool_size(tree);
+        glpk_node_p = glp_ios_curr_node(tree);
+        node_ord = glp_ios_node_ord(tree, glpk_node_p);
+        Assert(cut_ord > 0);
+        Debug("approx") << "curr node " << glpk_node_p
+                        << " cut ordinal " << cut_ord
+                        << " node depth " << glp_ios_node_level(tree, glpk_node_p)
+                        << endl;
+        int klass;
+        glp_ios_get_cut(tree, cut_ord, NULL, NULL, &klass, NULL, NULL);
+
+        NodeLog& node = tl.getNode(node_ord);
+        switch(klass){
+        case GLP_RF_GMI:
+          {
+            GmiInfo* gmi = gmiCut(tree, exec, cut_ord);
+            node.addCut(gmi);
+          }
+          break;
+        case GLP_RF_MIR:
+          {
+            MirInfo* mir = mirCut(tree, exec, cut_ord);
+            node.addCut(mir);
+          }
+          break;
+        case GLP_RF_COV:
+          Debug("approx") << "GLP_RF_COV" << endl;
+          break;
+        case GLP_RF_CLQ:
+          Debug("approx") << "GLP_RF_CLQ" << endl;
+          break;
+        default:
+          break;
+        }
+      }
+      break;
+    case GLP_ICUTSELECT:
+      {
+        glpk_node_p = glp_ios_curr_node(tree);
+        node_ord = glp_ios_node_ord(tree, glpk_node_p);
+        int cuts = glp_ios_pool_size(tree);
+        int* ords = new int[1+cuts];
+        int* rows = new int[1+cuts];
+        int N = glp_ios_selected_cuts(tree, ords, rows);
+
+        NodeLog& nl = tl.getNode(node_ord);
+        Debug("approx") << glpk_node_p << " " << node_ord << " " << cuts << " " << N << std::endl;
+        for(int i = 1; i <= N; ++i){
+          Debug("approx") << "adding to " << node_ord <<" @ i= " << i
+                          << " ords[i] = " << ords[i]
+                          << " rows[i] = " << rows[i] << endl;
+          nl.addSelected(ords[i], rows[i]);
+        }
+        delete[] ords;
+        delete[] rows;
+        nl.applySelected();
+      }
+    break;
+  case GLP_LI_BRANCH:
+    {
+      // a branch was just made
+      int br_var;
+      int p, dn, up;
+      int p_ord, dn_ord, up_ord;
+      double br_val;
+      br_var = glp_ios_branch_log(tree, &br_val, &p, &dn, &up);
+      p_ord = glp_ios_node_ord(tree, p);
+
+      dn_ord = (dn >= 0) ? glp_ios_node_ord(tree, dn) : -1;
+      up_ord = (up >= 0) ? glp_ios_node_ord(tree, up) : -1;
+
+      Debug("approx::") << "branch: "<< br_var << " "  << br_val << " tree " << p << " " << dn << " " << up << endl;
+      Debug("approx::") << "\t " << p_ord << " " << dn_ord << " " << up_ord << endl;
+      if(dn < 0 && up < 0){
+        Debug("approx::") << "branch close " << exec << endl;
+        NodeLog& node = tl.getNode(p_ord);
+        BranchCutInfo* cut_br = branchCut(tree, exec, br_var, br_val, dn < 0);
+        node.addCut(cut_br);
+        tl.close(p_ord);
+      }else if(dn < 0 || up < 0){
+        Debug("approx::") << "branch cut" << exec << endl;
+        NodeLog& node = tl.getNode(p_ord);
+        BranchCutInfo* cut_br = branchCut(tree, exec, br_var, br_val, dn < 0);
+        node.addCut(cut_br);
+      }else{
+        Debug("approx::") << "normal branch" << endl;
+        tl.branch(p_ord, br_var, br_val, dn_ord, up_ord);
+      }
+    }
+    break;
+    case GLP_LI_CLOSE:
+      {
+        glpk_node_p = glp_ios_curr_node(tree);
+        node_ord = glp_ios_node_ord(tree, glpk_node_p);
+        Debug("approx::") << "close " << glpk_node_p << endl;
+        tl.close(node_ord);
+      }
+      break;
+    default:
+      break;
+    }
+  }
+
   switch(glp_ios_reason(tree)){
   case GLP_IBINGO:
+    Debug("approx::") << "bingo" << endl;
+    aux->term = MipBingo;
     glp_ios_terminate(tree);
     break;
+  case GLP_ICUTADDED:
+    {
+      tl.addCut();
+    }
+    break;
+  case GLP_LI_BRANCH:
+    {
+      int p, dn, up;
+      int br_var = glp_ios_branch_log(tree, NULL, &p, &dn, &up);
+
+      if(br_var >= 0){
+        unsigned v = br_var;
+        tl.logBranch(v);
+        int depth = glp_ios_node_level(tree, p);
+        unsigned ubl =  (aux->branchLimit) >= 0 ? ((unsigned)(aux->branchLimit)) : 0u;
+        if(tl.numBranches(v) >= ubl || depth >= (aux->branchDepth)){
+          aux->term = BranchesExhausted;
+          glp_ios_terminate(tree);
+        }
+      }
+    }
+    break;
+  case GLP_LI_CLOSE:
+    break;
   default:
-    glp_prob* prob = glp_ios_get_prob(tree);
-    int iterationcount = lpx_get_int_parm(prob, LPX_K_ITCNT);
-    if(iterationcount > pivotLimit){
-      glp_ios_terminate(tree);
+    {
+      glp_prob* prob = glp_ios_get_prob(tree);
+      int iterationcount = glp_get_it_cnt(prob);
+      if(exec > (aux->pivotLimit)){
+        aux->term = ExecExhausted;
+        glp_ios_terminate(tree);
+      }else if(iterationcount > (aux->pivotLimit)){
+        aux->term = PivotsExhauasted;
+        glp_ios_terminate(tree);
+      }
     }
     break;
   }
 }
 
-ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
+std::vector<const CutInfo*> ApproxGLPK::getValidCuts(const NodeLog& con) throw (RationalFromDoubleException){
+  std::vector<const CutInfo*> proven;
+  int nid = con.getNodeId();
+  for(NodeLog::const_iterator j = con.begin(), jend=con.end(); j!=jend; ++j){
+    CutInfo* cut = *j;
+
+    if(cut->getKlass() != RowsDeletedKlass){
+      if(!cut->reconstructed()){
+        Assert(!cut->reconstructed());
+        tryCut(nid, *cut);
+      }
+    }
+
+    if(cut->proven()){
+      proven.push_back(cut);
+    }
+  }
+  return proven;
+}
+
+// std::vector<const CutInfo*> ApproxGLPK::getValidCuts(const std::set<const NodeLog*>& nodes){
+//   // assume selected has been applied
+//   std::vector<const CutInfo*> proven;
+//   std::set<const NodeLog*>::const_iterator i, iend;
+//   for(i = nodes.begin(), iend=nodes.end(); i!=iend; ++i){
+//     const NodeLog* nl = *i;
+//     getValidCuts(*nl, proven);
+//   }
+
+//   return proven;
+// }
+
+ArithVar ApproxGLPK::getBranchVar(const NodeLog& con) const{
+  int br_var = con.branchVariable();
+  return getArithVarFromStructural(br_var);
+}
+
+// Node ApproxGLPK::downBranchLiteral(const NodeLog& con) const{
+//   int br_var = con.branchVariable();
+//   ArithVar v = getArithVarFromStructural(br_var);
+//   if(v != ARITHVAR_SENTINEL){
+//     if(d_vars.isIntegerInput(v) && d_vars.hasNode(v)){
+//       Node var = d_vars.asNode(v);
+//       double br_val = con.branchValue();
+//       Rational val = estimateWithCFE(br_val);
+//       if(!val.isIntegral()){
+//         NodeManager* nm = NodeManager::currentNM();
+//         Node ineq = nm->mkNode(kind::LEQ, var, mkRationalNode(val));
+//         return Rewriter::rewrite(ineq);
+//       }
+//     }
+//   }
+//   return Node::null();
+// }
+
+// std::vector<const NodeLog*> ApproxGLPK::getBranches(){
+//   std::vector<const NodeLog*> branches;
+//   for(TreeLog::const_iterator i = d_log.begin(), iend=d_log.end(); i!=iend;++i){
+//     const NodeLog& con = (*i).second;
+//     if(con.isBranch()){
+//       branches.push_back(&con);
+//     }
+//   }
+//   return branches;
+// }
+
+MipResult ApproxGLPK::solveMIP(bool activelyLog){
   Assert(d_solvedRelaxation);
   // Explicitly disable presolving
   // We need the basis thus the presolver must be off!
   // This is default, but this is just being cautious.
+  AuxInfo aux;
+  aux.pivotLimit = d_pivotLimit;
+  aux.branchLimit = d_branchLimit;
+  aux.branchDepth = d_maxDepth;
+  aux.tl = &d_log;
+  aux.term = MipUnknown;
+
+  d_log.reset(d_rootRowIds);
+  if(activelyLog){
+    d_log.makeActive();
+  }else{
+    d_log.makeInactive();
+  }
+
   glp_iocp parm;
   glp_init_iocp(&parm);
   parm.presolve = GLP_OFF;
@@ -785,36 +1802,1361 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
   parm.gmi_cuts = GLP_ON;
   parm.mir_cuts = GLP_ON;
   parm.cov_cuts = GLP_ON;
-  parm.cb_func = stopAtBingoOrPivotLimit;
-  parm.cb_info = &d_pivotLimit;
+  parm.cb_func = glpkCallback;
+  parm.cb_info = &aux;
   parm.msg_lev = GLP_MSG_OFF;
   if(s_verbosity >= 1){
     parm.msg_lev = GLP_MSG_ALL;
   }
-  int res = glp_intopt(d_prob, &parm);
+
+  glp_erase_prob(d_mipProb);
+  glp_copy_prob(d_mipProb, d_realProb, GLP_OFF);
+
+  int res = glp_intopt(d_mipProb, &parm);
+
+  Debug("approx::solveMIP") << "res "<<res<<" aux.term "<< aux.term << endl;
 
   switch(res){
   case 0:
   case GLP_ESTOP:
     {
-      int status = glp_mip_status(d_prob);
+      int status = glp_mip_status(d_mipProb);
+      Debug("approx::") << "status " << status << endl;
       switch(status){
       case GLP_OPT:
       case GLP_FEAS:
         d_solvedMIP = true;
-        return ApproxSat;
+        Debug("approx::") << "bingo here!" << endl;
+        return MipBingo;
       case GLP_NOFEAS:
         d_solvedMIP = true;
-        return ApproxUnsat;
+        return MipClosed;
       default:
-        return ApproxError;
+        if(aux.term == MipBingo){
+          d_solvedMIP = true;
+          Debug("approx::") << "bingo here?" << endl;
+        }
+        return aux.term;
       }
     }
   default:
-    return ApproxError;
+    return MipUnknown;
+  }
+}
+
+
+
+// Node explainSet(const set<ConstraintP>& inp){
+//   Assert(!inp.empty());
+//   NodeBuilder<> nb(kind::AND);
+//   set<ConstraintP>::const_iterator iter, end;
+//   for(iter = inp.begin(), end = inp.end(); iter != end; ++iter){
+//     const ConstraintP c = *iter;
+//     Assert(c != NullConstraint);
+//     c->explainForConflict(nb);
+//   }
+//   Node ret = safeConstructNary(nb);
+//   Node rew = Rewriter::rewrite(ret);
+//   if(rew.getNumChildren() < ret.getNumChildren()){
+//     //Debug("approx::") << "explainSet " << ret << " " << rew << endl;
+//   }
+//   return rew;
+// }
+
+DeltaRational sumConstraints(const DenseMap<Rational>& xs, const DenseMap<ConstraintP>& cs, bool* anyinf){
+  if(anyinf != NULL){
+    *anyinf = false;
   }
+
+  DeltaRational beta(0);
+  DenseMap<Rational>::const_iterator iter, end;
+  iter = xs.begin();
+  end = xs.end();
+
+  Debug("approx::sumConstraints") << "sumConstraints";
+  for(; iter != end; ++iter){
+    ArithVar x = *iter;
+    const Rational& psi = xs[x];
+    ConstraintP c = cs[x];
+    Assert(c != NullConstraint);
+
+    const DeltaRational& bound = c->getValue();
+    beta += bound * psi;
+    Debug("approx::sumConstraints") << " +("<<bound << "*" << psi <<")";
+    if(anyinf != NULL ){
+      *anyinf = *anyinf || !bound.infinitesimalIsZero();
+    }
+  }
+  Debug("approx::sumConstraints") << "= " << beta << endl;
+
+  return beta;
+}
+
+// remove fixed variables from the vector
+void removeFixed(const ArithVariables& vars, DenseVector& dv, set<ConstraintP>& exp){
+  DenseMap<Rational>& vec = dv.lhs;
+  Rational& removed = dv.rhs;
+  vector<ArithVar> equal;
+  DenseMap<Rational>::const_iterator vec_iter, vec_end;
+  vec_iter = vec.begin(), vec_end = vec.end();
+  for(; vec_iter != vec_end; ++vec_iter){
+    ArithVar x = *vec_iter;
+    if(vars.boundsAreEqual(x)){
+      equal.push_back(x);
+    }
+  }
+  vector<ArithVar>::const_iterator equal_iter, equal_end;
+  equal_iter = equal.begin(), equal_end = equal.end();
+  for(; equal_iter != equal_end; ++equal_iter){
+    ArithVar x = *equal_iter;
+    Assert(vars.boundsAreEqual(x));
+    const DeltaRational& lb = vars.getLowerBound(x);
+    Assert(lb.infinitesimalIsZero());
+    removed -= (vec[x]) * lb.getNoninfinitesimalPart();
+
+    vec.remove(x);
+
+    std::pair<ConstraintP, ConstraintP> p = vars.explainEqualBounds(x);
+    exp.insert(p.first);
+    Debug("removeFixed") << "remove fixed " << p.first << endl;
+    if(p.second != NullConstraint){
+      exp.insert(p.second);
+      Debug("removeFixed") << "remove fixed " << p.second << endl;
+    }
+  }
+}
+void removeZeroes(DenseMap<Rational>& v){
+  // Remove Slack variables
+  vector<ArithVar> zeroes;
+  DenseMap<Rational>::const_iterator i, iend;
+  for(i = v.begin(), iend = v.end(); i != iend; ++i){
+    ArithVar x = *i;
+    if(v[x].isZero()){
+      zeroes.push_back(x);
+    }
+  }
+
+  vector<ArithVar>::const_iterator j, jend;
+  for(j = zeroes.begin(), jend = zeroes.end(); j != jend; ++j){
+    ArithVar x = *j;
+    v.remove(x);
+  }
+}
+void removeZeroes(DenseVector& v){
+  removeZeroes(v.lhs);
 }
 
+void removeAuxillaryVariables(const ArithVariables& vars, DenseMap<Rational>& vec){
+  // Remove auxillary variables
+  vector<ArithVar> aux;
+  DenseMap<Rational>::const_iterator vec_iter, vec_end;
+  vec_iter = vec.begin(), vec_end = vec.end();
+  for(; vec_iter != vec_end; ++vec_iter){
+    ArithVar x = *vec_iter;
+    if(vars.isAuxiliary(x)){
+      aux.push_back(x);
+    }
+  }
+
+  vector<ArithVar>::const_iterator aux_iter, aux_end;
+  aux_iter = aux.begin(), aux_end = aux.end();
+  for(; aux_iter != aux_end; ++aux_iter){
+    ArithVar s = *aux_iter;
+    Rational& s_coeff = vec.get(s);
+    Assert(vars.isAuxiliary(s));
+    Assert(vars.hasNode(s));
+    Node sAsNode = vars.asNode(s);
+    Polynomial p = Polynomial::parsePolynomial(sAsNode);
+    for(Polynomial::iterator j = p.begin(), p_end=p.end(); j != p_end; ++j){
+      Monomial m = *j;
+      const Rational& ns_coeff = m.getConstant().getValue();
+      Node vl = m.getVarList().getNode();
+      ArithVar ns = vars.asArithVar(vl);
+      Rational prod = s_coeff * ns_coeff;
+      if(vec.isKey(ns)){
+        vec.get(ns) += prod;
+      }else{
+        vec.set(ns, prod);
+      }
+    }
+    s_coeff = Rational(0); // subtract s_coeff * s from vec
+  }
+  removeZeroes(vec);
+}
+
+ArithVar ApproxGLPK::_getArithVar(int nid, int M, int ind) const{
+  if(ind <= 0){
+    return ARITHVAR_SENTINEL;
+  }else if(ind <= M){
+    return getArithVarFromRow(nid, ind);
+  }else{
+    return getArithVarFromStructural(ind - M);
+  }
+}
+
+
+bool ApproxGLPK::guessIsConstructable(const DenseMap<Rational>& guess) const {
+  // basic variable
+  // sum g[i] * x_i
+  DenseMap<Rational> g = guess;
+  removeAuxillaryVariables(d_vars, g);
+
+  if(Debug.isOn("guessIsConstructable")){
+    if(!g.empty()){
+      Debug("approx::guessIsConstructable") << "guessIsConstructable failed " << g.size() << endl;
+      DenseVector::print(Debug("approx::guessIsConstructable"), g);
+      Debug("approx::guessIsConstructable") << endl;
+    }
+  }
+  return g.empty();
+}
+
+bool ApproxGLPK::loadToBound(int nid, int M, int len, int* inds, int* statuses, DenseMap<ConstraintP>& toBound) const{
+  for(int i = 1; i <= len; ++i){
+    int status = statuses[i];
+    int ind = inds[i];
+    ArithVar v = _getArithVar(nid, M, ind);
+    ConstraintP c = NullConstraint;
+    if(v == ARITHVAR_SENTINEL){ return true; }
+
+    switch(status){
+    case GLP_NL:
+      c = d_vars.getLowerBoundConstraint(v);
+      break;
+    case GLP_NU:
+    case GLP_NS: // upper bound sufficies for fixed variables
+      c = d_vars.getUpperBoundConstraint(v);
+      break;
+    case GLP_NF:
+    default:
+      return true;
+    }
+    if(c == NullConstraint){
+      Debug("approx::") << "couldn't find " << v << " @ " << nid << endl;
+      return true;
+    }
+    Assert(c != NullConstraint);
+    toBound.set(v, c);
+  }
+  return false;
+}
+
+bool ApproxGLPK::checkCutOnPad(int nid, const CutInfo& cut) const{
+
+  Debug("approx::checkCutOnPad") << "checkCutOnPad(" << nid <<", " << cut.getId() <<")"<<endl;
+
+  const DenseMap<Rational>& constructedLhs = d_pad.d_cut.lhs;
+  const Rational& constructedRhs = d_pad.d_cut.rhs;
+  hash_set<ArithVar> visited;
+
+  if(constructedLhs.empty()){
+    Debug("approx::checkCutOnPad") << "its empty?" <<endl;
+    return true;
+  }
+  if(cut.getKind() != d_pad.d_cutKind) {
+    Debug("approx::checkCutOnPad") << "rel doesn't match" << endl;
+    return true;
+  }
+
+  const PrimitiveVec& cv = cut.getCutVector();
+  for(int i = 1; i <= cv.len; ++i){
+    int ind = cv.inds[i]; // this is always a structural variable
+    double coeff = cv.coeffs[i];
+
+
+
+    if(!d_colToArithVar.isKey(ind)){ return true; }
+    ArithVar x = d_colToArithVar[ind];
+    //if(x == ARITHVAR_SENTINEL){ return true; }
+    visited.insert(x);
+
+
+    if(!constructedLhs.isKey(x)){
+      if(Debug.isOn("approx::checkCutOnPad")){
+        Debug("approx::checkCutOnPad") << " didn't find key for " << x << std::endl;
+        cut.print(Debug("approx::checkCutOnPad"));
+        Debug("approx::checkCutOnPad") << endl;
+        d_pad.d_cut.print(Debug("approx::checkCutOnPad"));
+        Debug("approx::checkCutOnPad") << endl;
+      }
+      return true;
+    }
+
+    const Rational& onConstructed = constructedLhs[x];
+
+    Debug("approx::checkCutOnPad") << ind << " " << coeff  << " " << endl;
+    Debug("approx::checkCutOnPad") << " " << x << " " << onConstructed << endl;
+
+    if(!roughlyEqual(coeff, onConstructed.getDouble())){
+      Debug("approx::checkCutOnPad") << "coeff failure" << endl;
+      return true;
+    }
+  }
+  if(visited.size() != constructedLhs.size()){
+    Debug("approx::checkCutOnPad") << "size mismatch" << endl;
+    return true;
+  }
+
+
+  if(!roughlyEqual(cut.getRhs(), constructedRhs.getDouble())){
+    Debug("approx::checkCutOnPad")
+      << "norm rhs is off " << cut.getRhs() << " " << constructedRhs << endl;
+    return true;
+  }
+  return false;
+}
+
+
+
+bool ApproxGLPK::attemptBranchCut(int nid, const BranchCutInfo& br_cut){
+  d_pad.clear();
+
+  const PrimitiveVec& cut_vec = br_cut.getCutVector();
+  int structural = cut_vec.inds[1];
+  Assert(roughlyEqual(cut_vec.coeffs[1], +1.0));
+
+  ArithVar x = getArithVarFromStructural(structural);
+  d_pad.d_failure = (x == ARITHVAR_SENTINEL);
+  if(d_pad.d_failure){ return true; }
+
+  Kind brKind = br_cut.getKind();
+
+  d_pad.d_failure = (brKind != kind::LEQ && brKind != kind::GEQ);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_cutKind = brKind;
+  d_pad.d_cut.lhs.set(x, Rational(1));
+
+  Rational& rhs = d_pad.d_cut.rhs;
+  rhs = estimateWithCFE(Rational::fromDouble(br_cut.getRhs()), Integer(1));
+  d_pad.d_failure = !rhs.isIntegral();
+  if(d_pad.d_failure) { return true; }
+
+  d_pad.d_failure = checkCutOnPad(nid, br_cut);
+  if(d_pad.d_failure){ return true; }
+
+  return false;
+}
+
+bool ApproxGLPK::attemptGmi(int nid, const GmiInfo& gmi){
+  d_pad.clear();
+
+  d_pad.d_cutKind = kind::GEQ;
+
+  int M = gmi.getMAtCreation();
+  ArithVar b = _getArithVar(nid, M, gmi.basic);
+  d_pad.d_failure = (b == ARITHVAR_SENTINEL);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = !d_vars.isIntegerInput(b);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_basic = b;
+
+
+  const PrimitiveVec& tab = gmi.tab_row;
+  d_pad.d_failure = attemptConstructTableRow(nid, M, tab);
+  if(d_pad.d_failure){ return true; }
+
+  int* statuses = gmi.tab_statuses;
+  DenseMap<ConstraintP>& toBound = d_pad.d_toBound;
+  d_pad.d_failure = loadToBound(nid, M, tab.len, tab.inds, statuses, toBound);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = constructGmiCut();
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = checkCutOnPad(nid, gmi);
+  if(d_pad.d_failure){ return true; }
+
+  return false;
+}
+
+bool ApproxGLPK::applyCMIRRule(int nid, const MirInfo& mir){
+
+  const DenseMap<Rational>& compRanges = d_pad.d_compRanges;
+
+  DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+  Rational& b = d_pad.d_alpha.rhs;
+
+  Rational delta = estimateWithCFE(mir.delta);
+  d_pad.d_failure = (delta.sgn() <= 0);
+  if(d_pad.d_failure){ return true; }
+
+  Debug("approx::mir") << "applyCMIRRule() " << delta << " " << mir.delta << endl;
+
+  DenseMap<Rational>::const_iterator iter, iend;
+  iter = alpha.begin(), iend = alpha.end();
+  for(; iter != iend; ++iter){
+    ArithVar v = *iter;
+    const Rational& curr = alpha[v];
+    Rational next = curr / delta;
+    if(compRanges.isKey(v)){
+      b -= curr * compRanges[v];
+      alpha.set(v, - next);
+    }else{
+      alpha.set(v, next);
+    }
+  }
+  b = b / delta;
+
+  Rational roundB = (b + Rational(1,2)).floor();
+  d_pad.d_failure = (b - roundB).abs() < Rational(1,90);
+  // intensionally more generous than glpk here
+  if(d_pad.d_failure){ return true; }
+
+  Rational one(1);
+  Rational fb = b.floor_frac();
+  Rational one_sub_fb = one - fb;
+  Rational gamma = (one / one_sub_fb);
+
+  DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+  Rational& beta = d_pad.d_cut.rhs;
+
+  iter = alpha.begin(), iend = alpha.end();
+  for(; iter != iend; ++iter){
+    ArithVar v = *iter;
+    const Rational& a_j = alpha[v];
+    if(d_vars.isIntegerInput(v)){
+      Rational floor_aj = a_j.floor();
+      Rational frac_aj = a_j.floor_frac();
+      if(frac_aj <= fb){
+        cut.set(v, floor_aj);
+      }else{
+        Rational tmp =  ((frac_aj - fb) / one_sub_fb);
+        cut.set(v, floor_aj + tmp);
+      }
+    }else{
+      cut.set(v, a_j * gamma);
+    }
+  }
+  beta = b.floor();
+
+  iter = cut.begin(), iend = cut.end();
+  for(; iter != iend; ++iter){
+    ArithVar v = *iter;
+    if(compRanges.isKey(v)){
+      Rational neg = - cut[v];
+      beta += neg * compRanges[v];
+      cut.set(v, neg);
+    }
+  }
+
+  return false;
+}
+
+bool ApproxGLPK::attemptMir(int nid, const MirInfo& mir){
+  d_pad.clear();
+
+  d_pad.d_cutKind = kind::LEQ;
+
+  // virtual bounds must be done before slacks
+  d_pad.d_failure = loadVirtualBoundsIntoPad(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = loadSlacksIntoPad(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+
+  d_pad.d_failure = loadRowSumIntoAgg(nid, mir.getMAtCreation(), mir.row_sum);
+  if(d_pad.d_failure){ return true; }
+
+  removeFixed(d_vars, d_pad.d_agg, d_pad.d_explanation);
+
+  d_pad.d_failure = buildModifiedRow(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure =  constructMixedKnapsack();
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = makeRangeForComplemented(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = applyCMIRRule(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+  d_pad.d_failure = replaceSlacksOnCuts();
+  if(d_pad.d_failure){ return true; }
+
+  removeAuxillaryVariables(d_vars, d_pad.d_cut.lhs);
+
+  d_pad.d_failure = checkCutOnPad(nid, mir);
+  if(d_pad.d_failure){ return true; }
+
+  return false;
+  //return makeCutNodes(nid, mir);
+}
+
+bool ApproxGLPK::loadVB(int nid, int M, int j, int ri, bool wantUb, VirtualBound& tmp){
+  if(ri <= 0) { return true; }
+
+  static int instance = 0;
+  ++instance;
+  Debug("glpk::loadVB") << "loadVB() " << instance << endl;
+
+  ArithVar rowVar = _getArithVar(nid, M, ri);
+  ArithVar contVar = _getArithVar(nid, M, j);
+  if(rowVar == ARITHVAR_SENTINEL){ return true; }
+  if(contVar == ARITHVAR_SENTINEL){ return true; }
+
+  if(!d_vars.isAuxiliary(rowVar)){ return true; }
+  // is integer is correct here
+  if(d_vars.isInteger(contVar)){ return true; }
+
+  ConstraintP lb = d_vars.getLowerBoundConstraint(rowVar);
+  ConstraintP ub = d_vars.getUpperBoundConstraint(rowVar);
+
+  if(lb != NullConstraint && ub != NullConstraint){ return true; }
+
+  ConstraintP rcon = lb == NullConstraint ? ub : lb;
+  if(rcon == NullConstraint) { return true; }
+
+  if(!rcon->getValue().isZero()){ return true; }
+
+  if(!d_vars.hasNode(rowVar)){ return true; }
+  Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(rowVar));
+  if(p.size() != 2) { return false; }
+
+  Monomial first = p.getHead(), second = p.getTail().getHead();
+  Rational c1 = first.getConstant().getValue();
+  Rational c2 = second.getConstant().getValue();
+  Node nx1 = first.getVarList().getNode();
+  Node nx2 = second.getVarList().getNode();
+
+  if(!d_vars.hasArithVar(nx1)) { return true; }
+  if(!d_vars.hasArithVar(nx2)) { return true; }
+  ArithVar x1 = d_vars.asArithVar(nx1), x2 = d_vars.asArithVar(nx2);
+
+  Assert(x1 != x2);
+  Assert(!c1.isZero());
+  Assert(!c2.isZero());
+
+  Debug("glpk::loadVB")
+    << " lb " << lb
+    << " ub " << ub
+    << " rcon " << rcon
+    << " x1 " << x1
+    << " x2 " << x2
+    << " c1 " << c1
+    << " c2 " << c2 << endl;
+
+  ArithVar iv = (x1 == contVar) ? x2 : x1;
+  Rational& cc = (x1 == contVar) ? c1 : c2;
+  Rational& ic = (x1 == contVar) ? c2 : c1;
+
+  Debug("glpk::loadVB")
+    << " cv " << contVar
+    << " cc " << cc
+    << " iv " << iv
+    << " c2 " << ic << endl;
+
+  if(!d_vars.isIntegerInput(iv)){ return true; }
+  // cc * cv + ic * iv <= 0 or
+  // cc * cv + ic * iv <= 0
+
+  if(rcon == ub){ // multiply by -1
+    cc = -cc; ic = - ic;
+  }
+  Debug("glpk::loadVB") << " cv " << contVar
+                        << " cc " << cc
+                        << " iv " << iv
+                        << " c2 " << ic << endl;
+
+  // cc * cv + ic * iv >= 0
+  // cc * cv >= -ic * iv
+  // if cc < 0:
+  //   cv <= -ic/cc * iv
+  // elif cc > 0:
+  //   cv >= -ic/cc * iv
+  Assert(!cc.isZero());
+  Rational d = -ic/cc;
+  Debug("glpk::loadVB") << d << " " << cc.sgn() << endl;
+  bool nowUb = cc.sgn() < 0;
+  if(wantUb != nowUb) { return true; }
+
+  Kind rel = wantUb ? kind::LEQ : kind::GEQ;
+
+  tmp = VirtualBound(contVar, rel, d, iv, rcon);
+  return false;
+}
+
+bool ApproxGLPK::loadVirtualBoundsIntoPad(int nid, const MirInfo& mir){
+  Assert(mir.vlbRows != NULL);
+  Assert(mir.vubRows != NULL);
+
+  int N = mir.getN();
+  int M = mir.getMAtCreation();
+
+  // Load the virtual bounds first
+  VirtualBound tmp;
+  for(int j=1; j <= N+M; ++j){
+    if(!loadVB(nid, M, j, mir.vlbRows[j], false, tmp)){
+      if(d_pad.d_vlb.isKey(tmp.x)){ return true; }
+      d_pad.d_vlb.set(tmp.x, tmp);
+    }else if(mir.vlbRows[j] > 0){
+      Debug("approx::mir") << "expected vlb to work" << endl;
+    }
+    if(!loadVB(nid, M, j, mir.vubRows[j], true, tmp)){
+      if(d_pad.d_vub.isKey(tmp.x)){ return true; }
+      d_pad.d_vub.set(tmp.x, tmp);
+    }else if(mir.vubRows[j] > 0){
+      Debug("approx::mir") << "expected vub to work" << endl;
+    }
+  }
+  return false;
+}
+
+bool ApproxGLPK::loadSlacksIntoPad(int nid, const MirInfo& mir){
+  Assert(mir.vlbRows != NULL);
+  Assert(mir.vubRows != NULL);
+
+  int N = mir.getN();
+  int M = mir.getMAtCreation();
+
+  bool useVB;
+  // Load the virtual bounds first
+  SlackReplace rep;
+  bool lb;
+  ConstraintP b;
+  Debug("approx::mir") << "loadSlacksIntoPad(): N="<<N<<", M=" << M << std::endl;
+  for(int j=1; j <= N+M; ++j){
+    ArithVar v = _getArithVar(nid, M, j);
+    if(v == ARITHVAR_SENTINEL){
+      Debug("approx::mir") << " for: " << j << " no variable" << endl;
+      continue;
+    }
+    rep = SlackUndef;
+    char sub = mir.subst[j];
+    switch(sub){
+    case 'L':
+    case 'U':
+      lb = (sub == 'L');
+      useVB = lb ? (mir.vlbRows[j] > 0) : (mir.vubRows[j] > 0);
+      if(useVB){
+        if(lb ? d_pad.d_vlb.isKey(v) : d_pad.d_vub.isKey(v)){
+          rep = lb ? SlackVLB : SlackVUB;
+        }
+      }else{
+        b = lb ? d_vars.getLowerBoundConstraint(v)
+          : d_vars.getUpperBoundConstraint(v);
+        if(b != NullConstraint){
+          if(b->getValue().infinitesimalIsZero()){
+            rep = lb ? SlackLB : SlackUB;
+          }
+        }
+      }
+
+      Debug("approx::mir") << " for: " << j << ", " << v;
+      Debug("approx::mir") << " " << ((rep != SlackUndef) ? "succ" : "fail") << " ";
+      Debug("approx::mir") << sub << " " << rep << " " << mir.vlbRows[j] << " " << mir.vubRows[j]
+                           << endl;
+      if(rep != SlackUndef){
+        d_pad.d_slacks.set(v,rep);
+      }
+      break;
+    case '?':
+      continue;
+    default:
+      Debug("approx::mir") << " for: " << j << " got subst " << (int)sub << endl;
+      continue;
+    }
+  }
+  return false;
+}
+
+bool ApproxGLPK::replaceSlacksOnCuts(){
+  vector<ArithVar> virtualVars;
+
+  DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+  Rational& cutRhs = d_pad.d_cut.rhs;
+
+  DenseMap<Rational>::const_iterator iter, iend;
+  iter = cut.begin(), iend = cut.end();
+  for(; iter != iend; ++iter){
+    ArithVar x = *iter;
+    SlackReplace rep = d_pad.d_slacks[x];
+    if(d_vars.isIntegerInput(x)){
+      Assert(rep == SlackLB  || rep == SlackUB);
+      Rational& a = cut.get(x);
+
+      const DeltaRational& bound = (rep == SlackLB) ?
+        d_vars.getLowerBound(x) : d_vars.getUpperBound(x);
+      Assert(bound.infinitesimalIsZero());
+      Rational prod = a * bound.getNoninfinitesimalPart();
+      if(rep == SlackLB){
+        cutRhs += prod;
+      }else{
+        cutRhs -= prod;
+        a = -a;
+      }
+    }else if(rep == SlackVLB){
+      virtualVars.push_back(d_pad.d_vlb[x].y);
+    }else if(rep == SlackVUB){
+      virtualVars.push_back(d_pad.d_vub[x].y);
+    }
+  }
+
+  for(size_t i = 0; i < virtualVars.size(); ++i){
+    ArithVar x = virtualVars[i];
+    if(!cut.isKey(x)){
+      cut.set(x, Rational(0));
+    }
+  }
+
+  iter = cut.begin(), iend = cut.end();
+  for(; iter != iend; ++iter){
+    ArithVar x = *iter;
+    if(!d_vars.isIntegerInput(x)){
+      SlackReplace rep = d_pad.d_slacks[x];
+      Rational& a = cut.get(x);
+      switch(rep){
+      case SlackLB:
+        {
+          const DeltaRational& bound = d_vars.getLowerBound(x);
+          Assert(bound.infinitesimalIsZero());
+          cutRhs += a * bound.getNoninfinitesimalPart();
+        }
+        break;
+      case SlackUB:
+        {
+          const DeltaRational& bound = d_vars.getUpperBound(x);
+          Assert(bound.infinitesimalIsZero());
+          cutRhs -= a * bound.getNoninfinitesimalPart();
+          a = -a;
+        }
+        break;
+      case SlackVLB:
+      case SlackVUB:
+        {
+          bool lb = (rep == SlackVLB);
+          const VirtualBound& vb = lb ?
+            d_pad.d_vlb[x] : d_pad.d_vub[x];
+          ArithVar y = vb.y;
+          Assert(vb.x == x);
+          Assert(cut.isKey(y));
+          Rational& ycoeff = cut.get(y);
+          if(lb){
+            ycoeff -= a * vb.d;
+          }else{
+            ycoeff += a * vb.d;
+            a = -a;
+          }
+        }
+        break;
+      default:
+        return true;
+      }
+    }
+  }
+  removeZeroes(cut);
+  return false;
+}
+
+bool ApproxGLPK::loadRowSumIntoAgg(int nid, int M, const PrimitiveVec& row_sum){
+  DenseMap<Rational>& lhs = d_pad.d_agg.lhs;
+  d_pad.d_agg.rhs = Rational(0);
+
+  int len = row_sum.len;
+  for(int i = 1; i <= len; ++i){
+    int aux_ind = row_sum.inds[i]; // auxillary index
+    double coeff = row_sum.coeffs[i];
+    ArithVar x = _getArithVar(nid, M, aux_ind);
+    if(x == ARITHVAR_SENTINEL){ return true; }
+    Rational c = estimateWithCFE(coeff);
+    if(lhs.isKey(x)){
+      lhs.get(x) -= c;
+    }else{
+      lhs.set(x, -c);
+    }
+  }
+
+  Debug("approx::mir") << "beg loadRowSumIntoAgg() 1" << endl;
+  if(Debug.isOn("approx::mir")) { DenseVector::print(Debug("approx::mir"), lhs); }
+  removeAuxillaryVariables(d_vars, lhs);
+  Debug("approx::mir") << "end loadRowSumIntoAgg() 1" << endl;
+
+  if(Debug.isOn("approx::mir")){
+    Debug("approx::mir") << "loadRowSumIntoAgg() 2" << endl;
+    DenseVector::print(Debug("approx::mir"), lhs);
+    Debug("approx::mir") << "end loadRowSumIntoAgg() 2" << endl;
+  }
+
+  for(int i = 1; i <= len; ++i){
+    int aux_ind = row_sum.inds[i]; // auxillary index
+    double coeff = row_sum.coeffs[i];
+    ArithVar x = _getArithVar(nid, M, aux_ind);
+    Assert(x != ARITHVAR_SENTINEL);
+    Rational c = estimateWithCFE(coeff);
+    Assert(!lhs.isKey(x));
+    lhs.set(x, c);
+  }
+
+  if(Debug.isOn("approx::mir")){
+    Debug("approx::mir") << "loadRowSumIntoAgg() 2" << endl;
+    DenseVector::print(Debug("approx::mir"), lhs);
+    Debug("approx::mir") << "end loadRowSumIntoAgg() 3" << endl;
+  }
+  return false;
+}
+
+bool ApproxGLPK::buildModifiedRow(int nid, const MirInfo& mir){
+  const DenseMap<Rational>& agg = d_pad.d_agg.lhs;
+  const Rational& aggRhs = d_pad.d_agg.rhs;
+  DenseMap<Rational>& mod = d_pad.d_mod.lhs;
+  Rational& modRhs = d_pad.d_mod.rhs;
+
+  Debug("approx::mir")
+    << "buildModifiedRow()"
+    << " |agg|=" << d_pad.d_agg.lhs.size()
+    << " |mod|=" << d_pad.d_mod.lhs.size()
+    << " |slacks|=" << d_pad.d_slacks.size()
+    << " |vlb|=" << d_pad.d_vub.size()
+    << " |vub|=" << d_pad.d_vlb.size() << endl;
+
+  mod.addAll(agg);
+  modRhs = aggRhs;
+  DenseMap<Rational>::const_iterator iter, iend;
+  for(iter = agg.begin(), iend = agg.end(); iter != iend; ++iter){
+    ArithVar x = *iter;
+    const Rational& c = mod[x];
+    if(!d_pad.d_slacks.isKey(x)){
+      Debug("approx::mir") << "missed x: " << x << endl;
+      return true;
+    }
+    SlackReplace rep = d_pad.d_slacks[x];
+    switch(rep){
+    case SlackLB: // skip for now
+    case SlackUB:
+      break;
+    case SlackVLB: /* x[k] = lb[k] * x[kk] + x'[k] */
+    case SlackVUB: /* x[k] = ub[k] * x[kk] - x'[k] */
+      {
+        Assert(!d_vars.isIntegerInput(x));
+        bool ub = (rep == SlackVUB);
+        const VirtualBound& vb =
+          ub ? d_pad.d_vub[x] : d_pad.d_vlb[x];
+        Assert(vb.x == x);
+        ArithVar y = vb.y;
+        Rational prod = c * vb.d;
+        if(mod.isKey(y)){
+          mod.get(x) += prod;
+        }else{
+          mod.set(y, prod);
+        }
+        if(ub){
+          mod.set(x, -c);
+        }
+        Assert(vb.c != NullConstraint);
+        d_pad.d_explanation.insert(vb.c);
+      }
+      break;
+    default:
+      return true;
+    }
+  }
+  removeZeroes(mod); /* if something cancelled we don't want it in the explanation */
+  for(iter = mod.begin(), iend = mod.end(); iter != iend; ++iter){
+    ArithVar x = *iter;
+    if(!d_pad.d_slacks.isKey(x)){  return true; }
+
+    SlackReplace rep = d_pad.d_slacks[x];
+    switch(rep){
+    case SlackLB: /* x = lb + x' */
+    case SlackUB: /* x = ub - x' */
+      {
+        bool ub = (rep == SlackUB);
+        ConstraintP b = ub ?  d_vars.getUpperBoundConstraint(x):
+          d_vars.getLowerBoundConstraint(x);
+
+        Assert(b != NullConstraint);
+        Assert(b->getValue().infinitesimalIsZero());
+        const Rational& c = mod.get(x);
+        modRhs -= c * b->getValue().getNoninfinitesimalPart();
+        if(ub){
+          mod.set(x, -c);
+        }
+        d_pad.d_explanation.insert(b);
+      }
+      break;
+    case SlackVLB: /* handled earlier */
+    case SlackVUB:
+      break;
+    default:
+      return true;
+    }
+  }
+  removeZeroes(mod);
+  return false;
+}
+
+bool ApproxGLPK::makeRangeForComplemented(int nid, const MirInfo& mir){
+  DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+  int M = mir.getMAtCreation();
+  int N = mir.getN();
+  DenseMap<Rational>& compRanges = d_pad.d_compRanges;
+
+  int complemented = 0;
+
+  for(int j = 1; j <= M + N; ++j){
+    if(mir.cset[j] != 0){
+      complemented++;
+      ArithVar x = _getArithVar(nid, M, j);
+      if(!alpha.isKey(x)){ return true; }
+      if(!d_vars.isIntegerInput(x)){ return true; }
+      Assert(d_pad.d_slacks.isKey(x));
+      Assert(d_pad.d_slacks[x] == SlackLB || d_pad.d_slacks[x] == SlackUB);
+
+      ConstraintP lb = d_vars.getLowerBoundConstraint(x);
+      ConstraintP ub = d_vars.getUpperBoundConstraint(x);
+
+      if(lb == NullConstraint) { return true; }
+      if(ub == NullConstraint) { return true; }
+
+      if(!lb->getValue().infinitesimalIsZero()){
+        return true;
+      }
+      if(!ub->getValue().infinitesimalIsZero()){
+        return true;
+      }
+
+      const Rational& uval = ub->getValue().getNoninfinitesimalPart();
+      const Rational& lval = lb->getValue().getNoninfinitesimalPart();
+
+      d_pad.d_explanation.insert(lb);
+      d_pad.d_explanation.insert(ub);
+
+      Rational u = uval - lval;
+      // u is the same for both rep == LP and rep == UB
+      if(compRanges.isKey(x)) { return true; }
+      compRanges.set(x,u);
+    }
+  }
+
+  Debug("approx::mir") <<  "makeRangeForComplemented()" << complemented << endl;
+  return false;
+}
+
+
+bool ApproxGLPK::constructMixedKnapsack(){
+  const DenseMap<Rational>& mod = d_pad.d_mod.lhs;
+  const Rational& modRhs = d_pad.d_mod.rhs;
+  DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+  Rational& beta = d_pad.d_alpha.rhs;
+
+  Assert(alpha.empty());
+  beta = modRhs;
+
+  unsigned intVars = 0;
+  unsigned remain = 0;
+  unsigned dropped = 0;
+  DenseMap<Rational>::const_iterator iter, iend;
+  for(iter = mod.begin(), iend = mod.end(); iter != iend; ++iter){
+    ArithVar v = *iter;
+    const Rational& c = mod[v];
+    Assert(!c.isZero());
+    if(d_vars.isIntegerInput(v)){
+      intVars++;
+      alpha.set(v, c);
+    }else if(c.sgn() < 0){
+      remain++;
+      alpha.set(v, c);
+    }else{
+      dropped++;
+    }
+  }
+
+  Debug("approx::mir")
+    << "constructMixedKnapsack() "
+    <<" dropped " << dropped
+    <<" remain " << remain
+    <<" intVars " << intVars
+    << endl;
+  return intVars == 0; // if this is 0 we have failed
+}
+
+bool ApproxGLPK::attemptConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+  bool failed = guessCoefficientsConstructTableRow(nid, M, vec);
+  if(failed){
+    failed = gaussianElimConstructTableRow(nid, M, vec);
+  }
+
+  return failed;
+}
+
+bool ApproxGLPK::gaussianElimConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+  TimerStat::CodeTimer codeTimer(d_stats.d_gaussianElimConstructTime);
+  ++d_stats.d_gaussianElimConstruct;
+
+  ArithVar basic = d_pad.d_basic;
+  DenseMap<Rational>& tab = d_pad.d_tabRow.lhs;
+  tab.purge();
+  d_pad.d_tabRow.rhs = Rational(0);
+  Assert(basic != ARITHVAR_SENTINEL);
+  Assert(tab.empty());
+  Assert(d_pad.d_tabRow.rhs.isZero());
+
+  if(d_vars.isAuxiliary(basic)) { return true; }
+
+  if(Debug.isOn("gaussianElimConstructTableRow")){
+    Debug("gaussianElimConstructTableRow") << "1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    vec.print(Debug("gaussianElimConstructTableRow"));
+    Debug("gaussianElimConstructTableRow") << "match " << basic << "("<<d_vars.asNode(basic)<<")"<<endl;
+  }
+
+  set<ArithVar> onrow;
+  for(int i = 1; i <= vec.len; ++i){
+    int ind = vec.inds[i];
+    ArithVar var = _getArithVar(nid, M, ind);
+    if(var == ARITHVAR_SENTINEL){
+      Debug("gaussianElimConstructTableRow") << "couldn't find" << ind << " " << M << " " << nid << endl;
+      return true;
+    }
+    onrow.insert(var);
+  }
+
+
+  Debug("gaussianElimConstructTableRow") << "2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+  Matrix<Rational> A;
+  A.increaseSizeTo(d_vars.getNumberOfVariables());
+  std::vector< std::pair<RowIndex, ArithVar> > rows;
+  set<ArithVar>::const_iterator i, iend;
+  // load the rows for auxiliary variables into A
+  for(i=onrow.begin(), iend=onrow.end(); i!=iend; ++i){
+    ArithVar v = *i;
+    if(d_vars.isAuxiliary(v)){
+      Assert(d_vars.hasNode(v));
+
+      vector<Rational> coeffs;
+      vector<ArithVar> vars;
+
+      coeffs.push_back(Rational(-1));
+      vars.push_back(v);
+
+      Node n = d_vars.asNode(v);
+      Polynomial p = Polynomial::parsePolynomial(n);
+      Polynomial::iterator j = p.begin(), jend=p.end();
+      for(j=p.begin(), jend=p.end(); j!=jend; ++j){
+        Monomial m = *j;
+        if(m.isConstant()) { return true; }
+        VarList vl = m.getVarList();
+        if(!d_vars.hasArithVar(vl.getNode())){ return true; }
+        ArithVar x = d_vars.asArithVar(vl.getNode());
+        const Rational& q = m.getConstant().getValue();
+        coeffs.push_back(q); vars.push_back(x);
+      }
+      RowIndex rid = A.addRow(coeffs, vars);
+      rows.push_back(make_pair(rid, ARITHVAR_SENTINEL));
+    }
+  }
+  Debug("gaussianElimConstructTableRow") << "3 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+  for(size_t i=0; i < rows.size(); ++i){
+    RowIndex rid = rows[i].first;
+    Assert(rows[i].second == ARITHVAR_SENTINEL);
+
+    // substitute previous rows
+    for(size_t j=0; j < i; j++){
+      RowIndex prevRow = rows[j].first;
+      ArithVar other = rows[j].second;
+      Assert(other != ARITHVAR_SENTINEL);
+      const Matrix<Rational>::Entry& e = A.findEntry(rid, other);
+      if(!e.blank()){
+        // r_p : 0 = -1 * other + sum a_i x_i
+        // rid : 0 =  e * other + sum b_i x_i
+        // rid += e * r_p
+        //     : 0 = 0 * other + ... 
+        Assert(!e.getCoefficient().isZero());
+
+        Rational cp = e.getCoefficient();
+        Debug("gaussianElimConstructTableRow")
+          << "on " << rid << " subst " << cp << "*" << prevRow << " " << other << endl;
+        A.rowPlusRowTimesConstant(rid, prevRow, cp);
+      }
+    }
+    if(Debug.isOn("gaussianElimConstructTableRow")){
+      A.printMatrix(Debug("gaussianElimConstructTableRow"));
+    }
+
+    // solve the row for anything other than non-basics
+    bool solveForBasic = (i + 1 == rows.size());
+    Rational q;
+    ArithVar s = ARITHVAR_SENTINEL;
+    Matrix<Rational>::RowIterator k = A.getRow(rid).begin();
+    Matrix<Rational>::RowIterator k_end = A.getRow(rid).end();
+    for(; k != k_end; ++k){
+      const Matrix<Rational>::Entry& e = *k;
+      ArithVar colVar = e.getColVar();
+      bool selectColVar = false;
+      if(colVar == basic){
+        selectColVar = solveForBasic;
+      }else if(onrow.find(colVar) == onrow.end()) {
+        selectColVar = true;
+      }
+      if(selectColVar){
+        s = colVar;
+        q = e.getCoefficient();
+      }
+    }
+    if(s == ARITHVAR_SENTINEL || q.isZero()){
+      Debug("gaussianElimConstructTableRow") << "3 fail gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+      return true;
+    }else{
+      // 0 = q * s + sum c_i * x_i
+      Rational mult = -(q.inverse());
+      Debug("gaussianElimConstructTableRow") << "selecting " << s << " : " << mult << endl;
+      Debug("gaussianElimConstructTableRow") << "selecting " << rid << " " << s << endl;
+      //cout << "selecting " << s << " : complexity " << mult.complexity() << " " << mult << endl;
+      //cout << "selecting " << rid << " " << s << endl;
+      A.multiplyRowByConstant(rid, mult);
+      rows[i].second = s;
+    }
+  }
+  Debug("gaussianElimConstructTableRow") << "4 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+  if(rows.empty()) {
+    Debug("gaussianElimConstructTableRow") << "4 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    return true;
+  }
+  RowIndex rid_last = rows.back().first;
+  ArithVar rid_var = rows.back().second;
+  if(rid_var != basic){
+    Debug("gaussianElimConstructTableRow") << "4 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    return true;
+  }
+
+  Assert(tab.empty());
+
+  Matrix<Rational>::RowIterator k = A.getRow(rid_last).begin();
+  Matrix<Rational>::RowIterator k_end = A.getRow(rid_last).end();
+  for(; k != k_end; ++k){
+    const Matrix<Rational>::Entry& e = *k;
+    tab.set(e.getColVar(), e.getCoefficient());
+  }
+  Debug("gaussianElimConstructTableRow") << "5 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+  if(!tab.isKey(basic)){
+    Debug("gaussianElimConstructTableRow") << "5 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    return true;
+  }
+  if(tab[basic] != Rational(-1)){
+    Debug("gaussianElimConstructTableRow") << "5 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    return true;
+  }
+
+  tab.remove(basic);
+  Debug("gaussianElimConstructTableRow") << "6 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+  if(vec.len < 0 ){
+    Debug("gaussianElimConstructTableRow") << "6 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+    return true;
+  }
+  if(tab.size() != ((unsigned)vec.len) ) {
+    Debug("gaussianElimConstructTableRow") << "6 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<< tab.size() <<  " " << vec.len << endl;
+    return true;
+  }
+
+  Debug("gaussianElimConstructTableRow") << "7 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+  for(int i = 1; i <= vec.len; ++i){
+    int ind = vec.inds[i];
+    double coeff = vec.coeffs[i];
+    ArithVar var = _getArithVar(nid, M, ind);
+    Assert(var != ARITHVAR_SENTINEL);
+    if(!tab.isKey(var)){
+      Debug("gaussianElimConstructTableRow") << "7 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+      return true;
+    }
+
+    double est = tab[var].getDouble();
+
+    if(!ApproximateSimplex::roughlyEqual(coeff, est)){
+      Debug("gaussianElimConstructTableRow") << "7 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"
+           << " boink on " << ind << " " << var << " " << est <<endl;
+      return true;
+    }
+    Debug("gaussianElimConstructTableRow") << var << " cfe " << coeff << endl;
+  }
+
+  Debug("gaussianElimConstructTableRow")
+    << "gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"
+    << " superduper" << endl;
+
+  return false;
+}
+bool ApproxGLPK::guessCoefficientsConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+  for(size_t i=0; i < d_denomGuesses.size(); ++i){
+    const Integer& D = d_denomGuesses[i];
+    if(!guessCoefficientsConstructTableRow(nid, M, vec, D)){
+      d_stats.d_averageGuesses.addEntry(i+1);
+      Debug("approx::gmi") << "guesseditat " << i << " D=" << D << endl;
+      return false;
+    }
+  }
+  return true;
+}
+bool ApproxGLPK::guessCoefficientsConstructTableRow(int nid, int M, const PrimitiveVec& vec, const Integer& D){
+  ArithVar basic = d_pad.d_basic;
+  DenseMap<Rational>& tab = d_pad.d_tabRow.lhs;
+  tab.purge();
+  d_pad.d_tabRow.rhs = Rational(0);
+  Assert(basic != ARITHVAR_SENTINEL);
+  Assert(tab.empty());
+  Assert(d_pad.d_tabRow.rhs.isZero());
+
+  if(Debug.isOn("guessCoefficientsConstructTableRow")){
+    Debug("guessCoefficientsConstructTableRow")  << "attemptConstructTableRow("<<nid <<", "<< basic<<",...," << D<< ")"<<endl;
+    vec.print(Debug("guessCoefficientsConstructTableRow"));
+    Debug("guessCoefficientsConstructTableRow") << "match " << basic << "("<<d_vars.asNode(basic)<<")"<<endl;
+  }
+
+  tab.set(basic, Rational(-1));
+  for(int i = 1; i <= vec.len; ++i){
+    int ind = vec.inds[i];
+    double coeff = vec.coeffs[i];
+    ArithVar var = _getArithVar(nid, M, ind);
+    if(var == ARITHVAR_SENTINEL){
+      Debug("guessCoefficientsConstructTableRow") << "couldn't find" << ind << " " << M << " " << nid << endl;
+      return true;
+    }
+    Debug("guessCoefficientsConstructTableRow") << "match " << ind << "," << var << "("<<d_vars.asNode(var)<<")"<<endl;
+
+    Rational cfe = estimateWithCFE(coeff, D);
+    tab.set(var, cfe);
+    Debug("guessCoefficientsConstructTableRow") << var << " cfe " << cfe << endl;
+  }
+  if(!guessIsConstructable(tab)){
+    Debug("guessCoefficientsConstructTableRow") << "failed to construct with " << D  << endl;
+    return true;
+  }
+  tab.remove(basic);
+  return false;
+}
+
+/* Maps an ArithVar to either an upper/lower bound */
+bool ApproxGLPK::constructGmiCut(){
+  const DenseMap<Rational>& tabRow = d_pad.d_tabRow.lhs;
+  const DenseMap<ConstraintP>& toBound = d_pad.d_toBound;
+  DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+  std::set<ConstraintP>& explanation = d_pad.d_explanation;
+  Rational& rhs = d_pad.d_cut.rhs;
+
+  DenseMap<Rational>::const_iterator iter, end;
+  Assert(cut.empty());
+
+  // compute beta for a "fake" assignment
+  bool anyInf;
+  DeltaRational dbeta = sumConstraints(tabRow, toBound, &anyInf);
+  const Rational& beta = dbeta.getNoninfinitesimalPart();
+  Debug("approx::gmi") << dbeta << endl;
+  if(anyInf || beta.isIntegral()){ return true; }
+
+  Rational one = Rational(1);
+  Rational fbeta = beta.floor_frac();
+  rhs = fbeta;
+  Assert(fbeta.sgn() > 0);
+  Assert(fbeta < one);
+  Rational one_sub_fbeta = one - fbeta;
+  for(iter = tabRow.begin(), end = tabRow.end(); iter != end; ++iter){
+    ArithVar x = *iter;
+    const Rational& psi = tabRow[x];
+    ConstraintP c = toBound[x];
+    const Rational& bound = c->getValue().getNoninfinitesimalPart();
+    if(d_vars.boundsAreEqual(x)){
+      // do not add a coefficient
+      // implictly substitute the variable w/ its constraint
+      std::pair<ConstraintP, ConstraintP> exp = d_vars.explainEqualBounds(x);
+      explanation.insert(exp.first);
+      if(exp.second != NullConstraint){
+        explanation.insert(exp.second);
+      }
+    }else if(d_vars.isIntegerInput(x) && psi.isIntegral()){
+      // do not add a coefficient
+      // nothing to explain
+      Debug("approx::gmi") << "skipping " << x << endl;
+    }else{
+      explanation.insert(c);
+      Rational phi;
+      Rational alpha = (c->isUpperBound() ? psi : -psi);
+
+      // x - ub <= 0 and lb - x <= 0
+      if(d_vars.isIntegerInput(x)){
+        Assert(!psi.isIntegral());
+        // alpha = slack_sgn * psi
+        Rational falpha = alpha.floor_frac();
+        Assert(falpha.sgn() > 0);
+        Assert(falpha < one);
+        phi = (falpha <= fbeta) ?
+          falpha : ((fbeta / one_sub_fbeta) * (one - falpha));
+      }else{
+        phi = (alpha >= 0) ?
+          alpha : ((fbeta / one_sub_fbeta) * (- alpha));
+      }
+      Assert(phi.sgn() != 0);
+      if(c->isUpperBound()){
+        cut.set(x, -phi);
+        rhs -= phi * bound;
+      }else{
+        cut.set(x, phi);
+        rhs += phi * bound;
+      }
+    }
+  }
+  if(Debug.isOn("approx::gmi")){
+    Debug("approx::gmi") << "pre removeSlackVariables";
+    d_pad.d_cut.print(Debug("approx::gmi"));
+    Debug("approx::gmi") << endl;
+  }
+  removeAuxillaryVariables(d_vars, cut);
+
+  if(Debug.isOn("approx::gmi")){
+    Debug("approx::gmi") << "post removeAuxillaryVariables";
+    d_pad.d_cut.print(Debug("approx::gmi"));
+    Debug("approx::gmi") << endl;
+  }
+  removeFixed(d_vars, d_pad.d_cut, explanation);
+
+  if(Debug.isOn("approx::gmi")){
+    Debug("approx::gmi") << "post removeFixed";
+    d_pad.d_cut.print(Debug("approx::gmi"));
+    Debug("approx::gmi") << endl;
+  }
+  return false;
+}
+
+void ApproxGLPK::tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException){
+  Assert(!cut.reconstructed());
+  Assert(cut.getKlass() != RowsDeletedKlass);
+  bool failure = false;
+  switch(cut.getKlass()){
+  case GmiCutKlass:
+    failure = attemptGmi(nid, static_cast<const GmiInfo&>(cut));
+    break;
+  case MirCutKlass:
+    failure = attemptMir(nid, static_cast<const MirInfo&>(cut));
+    break;
+  case BranchCutKlass:
+    failure = attemptBranchCut(nid, dynamic_cast<const BranchCutInfo&>(cut));
+    break;
+  default:
+    break;
+  }
+  Assert(failure == d_pad.d_failure);
+
+  if(!failure){
+    // move the pad to the cut
+    cut.setReconstruction(d_pad.d_cut);
+
+    if(cut.getKlass() != BranchCutKlass){
+      std::set<ConstraintP>& exp = d_pad.d_explanation;
+      ConstraintCPVec asvec(exp.begin(), exp.end());
+      cut.swapExplanation(asvec);
+    }
+  }else{
+    Debug("approx") << "failure " << cut.getKlass() << endl;
+  }
+}
+
+
 }/* CVC4::theory::arith namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index b32fdef2d95434cae50075d3a4a9ed4a1c3c9291..15996fef8ba6c090bff1c204796eb168c6552854 100644 (file)
@@ -22,7 +22,9 @@
 
 #include "util/statistics_registry.h"
 #include "theory/arith/arithvar.h"
-#include "theory/arith/linear_equality.h"
+#include "util/rational.h"
+#include "theory/arith/delta_rational.h"
+//#include "theory/arith/linear_equality.h"
 #include "util/dense_map.h"
 #include <vector>
 
@@ -30,10 +32,81 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
+enum LinResult {
+  LinUnknown,  /* Unknown error */
+  LinFeasible, /* Relaxation is feasible */
+  LinInfeasible,   /* Relaxation is infeasible/all integer branches closed */
+  LinExhausted
+};
+
+enum MipResult {
+  MipUnknown,  /* Unknown error */
+  MipBingo,    /* Integer feasible */
+  MipClosed,   /* All integer branches closed */
+  BranchesExhausted, /* Exhausted number of branches */
+  PivotsExhauasted,  /* Exhausted number of pivots */
+  ExecExhausted      /* Exhausted total operations */
+};
+std::ostream& operator<<(std::ostream& out, MipResult res);
+
+class ApproximateStatistics {
+public:
+  // IntStat d_relaxCalls;
+  // IntStat d_relaxUnknowns;
+  // IntStat d_relaxFeasible;
+  // IntStat d_relaxInfeasible;
+  // IntStat d_relaxPivotsExhausted;
+
+  // IntStat d_mipCalls;
+  // IntStat d_mipUnknowns;
+  // IntStat d_mipBingo;
+  // IntStat d_mipClosed;
+  // IntStat d_mipBranchesExhausted;
+  // IntStat d_mipPivotsExhausted;
+  // IntStat d_mipExecExhausted;
+
+
+  // IntStat d_gmiGen;
+  // IntStat d_gmiReplay;
+  // IntStat d_mipGen;
+  // IntStat d_mipReplay;
+
+  IntStat d_branchMaxDepth;
+  IntStat d_branchesMaxOnAVar;
+
+  TimerStat d_gaussianElimConstructTime;
+  IntStat d_gaussianElimConstruct;
+  AverageStat d_averageGuesses;
+
+  ApproximateStatistics();
+  ~ApproximateStatistics();
+};
+
+
+class NodeLog;
+class TreeLog;
+class ArithVariables;
+class CutInfo;
+class RowsDeleted;
 
 class ApproximateSimplex{
 protected:
+  const ArithVariables& d_vars;
+  TreeLog& d_log;
+  ApproximateStatistics& d_stats;
+
   int d_pivotLimit;
+  /* the maximum pivots allowed in a query. */
+
+  int d_branchLimit;
+  /* maximum branches allowed on a variable */
+
+  int d_maxDepth;
+  /* maxmimum branching depth allowed.*/
+
+  static Integer s_defaultMaxDenom;
+  /* Default denominator for diophatine approximation.
+  * 2^{26}*/
 
 public:
 
@@ -43,31 +116,48 @@ public:
    * If glpk is enabled, return a subclass that can do something.
    * If glpk is disabled, return a subclass that does nothing.
    */
-  static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars);
-  ApproximateSimplex();
+  static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars, TreeLog& l, ApproximateStatistics& s);
+  ApproximateSimplex(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s);
   virtual ~ApproximateSimplex(){}
 
+  /* the maximum pivots allowed in a query. */
+  void setPivotLimit(int pl);
+
+  /* maximum branches allowed on a variable */
+  void setBranchOnVariableLimit(int bl);
+
+  /* maximum branches allowed on a variable */
+  void setBranchingDepth(int bd);
+
   /** A result is either sat, unsat or unknown.*/
-  enum ApproxResult {ApproxError, ApproxSat, ApproxUnsat};
+  //enum ApproxResult {ApproxError, ApproxSat, ApproxUnsat};
   struct Solution {
     DenseSet newBasis;
     DenseMap<DeltaRational> newValues;
     Solution() : newBasis(), newValues(){}
   };
 
-  /** Sets a deterministic effort limit. */
-  void setPivotLimit(int pivotLimit);
+  virtual ArithVar getBranchVar(const NodeLog& nl) const = 0;
+  //virtual void mapRowId(int nid, int ind, ArithVar v) = 0;
+  //virtual void applyRowsDeleted(int nid, const RowsDeleted& rd) = 0;
 
   /** Sets a maximization criteria for the approximate solver.*/
   virtual void setOptCoeffs(const ArithRatPairVec& ref) = 0;
 
   virtual ArithRatPairVec heuristicOptCoeffs() const = 0;
 
-  virtual ApproxResult solveRelaxation() = 0;
-  virtual Solution extractRelaxation() const = 0;
+  virtual LinResult solveRelaxation() = 0;
+  virtual Solution extractRelaxation() const throw(RationalFromDoubleException) = 0;
+
+  virtual MipResult solveMIP(bool activelyLog) = 0;
+  virtual Solution extractMIP() const throw(RationalFromDoubleException) = 0;
+
+  virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& node) throw(RationalFromDoubleException) = 0;
+  //virtual std::vector<const NodeLog*> getBranches() = 0;
 
-  virtual ApproxResult solveMIP() = 0;
-  virtual Solution extractMIP() const = 0;
+  //virtual Node downBranchLiteral(const NodeLog& con) const = 0;
+
+  virtual void tryCut(int nid, CutInfo& cut) throw(RationalFromDoubleException) = 0;
 
   /** UTILITIES FOR DEALING WITH ESTIMATES */
 
@@ -82,7 +172,8 @@ public:
    * cuts off the estimate once the value is approximately zero.
    * This is designed for removing rounding artifacts.
    */
-  static Rational estimateWithCFE(double d);
+  static Rational estimateWithCFE(double d) throw(RationalFromDoubleException);
+  static Rational estimateWithCFE(double d, const Integer& D) throw(RationalFromDoubleException);
 
   /**
    * Converts a rational to a continued fraction expansion representation
@@ -95,7 +186,10 @@ public:
   static Rational cfeToRational(const std::vector<Integer>& exp);
 
   /** Estimates a rational as a continued fraction expansion.*/
-  static Rational estimateWithCFE(const Rational& q, int depth);
+  //static Rational estimateWithCFE(const Rational& q, int depth);
+  static Rational estimateWithCFE(const Rational& q, const Integer& K);
+
+  virtual double sumInfeasibilities(bool mip) const = 0;
 };/* class ApproximateSimplex */
 
 
diff --git a/src/theory/arith/arith_ite_utils.cpp b/src/theory/arith/arith_ite_utils.cpp
new file mode 100644 (file)
index 0000000..61bf5c7
--- /dev/null
@@ -0,0 +1,436 @@
+#include "theory/arith/arith_ite_utils.h"
+#include "theory/arith/normal_form.h"
+#include "theory/arith/arith_utilities.h"
+#include "theory/ite_utilities.h"
+#include "theory/theory_model.h"
+#include "theory/rewriter.h"
+#include "theory/substitutions.h"
+#include <ostream>
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+Node ArithIteUtils::applyReduceVariablesInItes(Node n){
+  NodeBuilder<> nb(n.getKind());
+  if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+    nb << (n.getOperator());
+  }
+  for(Node::iterator it = n.begin(), end = n.end(); it != end; ++it){
+    nb << reduceVariablesInItes(*it);
+  }
+  Node res = nb;
+  return res;
+}
+
+Node ArithIteUtils::reduceVariablesInItes(Node n){
+  using namespace CVC4::kind;
+  if(d_reduceVar.find(n) != d_reduceVar.end()){
+    Node res = d_reduceVar[n];
+    return res.isNull() ? n : res;
+  }
+
+  switch(n.getKind()){
+  case ITE:{
+    Node c = n[0], t = n[1], e = n[2];
+    if(n.getType().isReal()){
+      Node rc = reduceVariablesInItes(c);
+      Node rt = reduceVariablesInItes(t);
+      Node re = reduceVariablesInItes(e);
+
+      Node vt = d_varParts[t];
+      Node ve = d_varParts[e];
+      Node vpite = (vt == ve) ? vt : Node::null();
+
+      if(vpite.isNull()){
+        Node rite = rc.iteNode(rt, re);
+        // do not apply
+        d_reduceVar[n] = rite;
+        d_constants[n] = mkRationalNode(Rational(0));
+        d_varParts[n] = rite; // treat the ite as a variable
+        return rite;
+      }else{
+        NodeManager* nm = NodeManager::currentNM();
+        Node constantite = rc.iteNode(d_constants[t], d_constants[e]);
+        Node sum = nm->mkNode(kind::PLUS, vpite, constantite);
+        d_reduceVar[n] = sum;
+        d_constants[n] = constantite;
+        d_varParts[n] = vpite;
+        return sum;
+      }
+    }else{ // non-arith ite
+      if(!d_contains.containsTermITE(n)){
+        // don't bother adding to d_reduceVar
+        return n;
+      }else{
+        Node newIte = applyReduceVariablesInItes(n);
+        d_reduceVar[n] = (n == newIte) ? Node::null(): newIte;
+        return newIte;
+      }
+    }
+  }break;
+  default:
+    if(n.getType().isReal() && Polynomial::isMember(n)){
+      Node newn = Node::null();
+      if(!d_contains.containsTermITE(n)){
+        newn = n;
+      }else if(n.getNumChildren() > 0){
+        newn = applyReduceVariablesInItes(n);
+        newn = Rewriter::rewrite(newn);
+        Assert(Polynomial::isMember(newn));
+      }else{
+        newn = n;
+      }
+
+      Polynomial p = Polynomial::parsePolynomial(newn);
+      if(p.isConstant()){
+        d_constants[n] = newn;
+        d_varParts[n] = mkRationalNode(Rational(0));
+        // don't bother adding to d_reduceVar
+        return newn;
+      }else if(!p.containsConstant()){
+        d_constants[n] = mkRationalNode(Rational(0));
+        d_varParts[n] = newn;
+        d_reduceVar[n] = p.getNode();
+        return p.getNode();
+      }else{
+        Monomial mc = p.getHead();
+        d_constants[n] = mc.getConstant().getNode();
+        d_varParts[n] = p.getTail().getNode();
+        d_reduceVar[n] = newn;
+        return newn;
+      }
+    }else{
+      if(!d_contains.containsTermITE(n)){
+        return n;
+      }
+      if(n.getNumChildren() > 0){
+        Node res = applyReduceVariablesInItes(n);
+        d_reduceVar[n] = res;
+        return res;
+      }else{
+        return n;
+      }
+    }
+    break;
+  }
+  Unreachable();
+  return Node::null();
+}
+
+ArithIteUtils::ArithIteUtils(ContainsTermITEVistor& contains,
+                             context::Context* uc,
+                             TheoryModel* model)
+  : d_contains(contains)
+  , d_subs(NULL)
+  , d_model(model)
+  , d_one(1)
+  , d_subcount(uc, 0)
+  , d_skolems(uc)
+  , d_implies()
+  , d_skolemsAdded()
+  , d_orBinEqs()
+{
+  d_subs = new SubstitutionMap(uc);
+}
+
+ArithIteUtils::~ArithIteUtils(){
+  delete d_subs;
+  d_subs = NULL;
+}
+
+void ArithIteUtils::clear(){
+  d_reduceVar.clear();
+  d_constants.clear();
+  d_varParts.clear();
+}
+
+const Integer& ArithIteUtils::gcdIte(Node n){
+  if(d_gcds.find(n) != d_gcds.end()){
+    return d_gcds[n];
+  }
+  if(n.getKind() == kind::CONST_RATIONAL){
+    const Rational& q = n.getConst<Rational>();
+    if(q.isIntegral()){
+      d_gcds[n] = q.getNumerator();
+      return d_gcds[n];
+    }else{
+      return d_one;
+    }
+  }else if(n.getKind() == kind::ITE && n.getType().isReal()){
+    const Integer& tgcd = gcdIte(n[1]);
+    if(tgcd.isOne()){
+      d_gcds[n] = d_one;
+      return d_one;
+    }else{
+      const Integer& egcd = gcdIte(n[2]);
+      Integer ite_gcd = tgcd.gcd(egcd);
+      d_gcds[n] = ite_gcd;
+      return d_gcds[n];
+    }
+  }
+  return d_one;
+}
+
+Node ArithIteUtils::reduceIteConstantIteByGCD_rec(Node n, const Rational& q){
+  if(n.isConst()){
+    Assert(n.getKind() == kind::CONST_RATIONAL);
+    return mkRationalNode(n.getConst<Rational>() * q);
+  }else{
+    Assert(n.getKind() == kind::ITE);
+    Assert(n.getType().isInteger());
+    Node rc = reduceConstantIteByGCD(n[0]);
+    Node rt = reduceIteConstantIteByGCD_rec(n[1], q);
+    Node re = reduceIteConstantIteByGCD_rec(n[2], q);
+    return rc.iteNode(rt, re);
+  }
+}
+
+Node ArithIteUtils::reduceIteConstantIteByGCD(Node n){
+  Assert(n.getKind() == kind::ITE);
+  Assert(n.getType().isReal());
+  const Integer& gcd = gcdIte(n);
+  if(gcd.isOne()){
+    Node newIte = reduceConstantIteByGCD(n[0]).iteNode(n[1],n[2]);
+    d_reduceGcd[n] = newIte;
+    return newIte;
+  }else if(gcd.isZero()){
+    Node zeroNode = mkRationalNode(Rational(0));
+    d_reduceGcd[n] = zeroNode;
+    return zeroNode;
+  }else{
+    Rational divBy(Integer(1), gcd);
+    Node redite = reduceIteConstantIteByGCD_rec(n, divBy);
+    Node gcdNode = mkRationalNode(Rational(gcd));
+    Node multIte = NodeManager::currentNM()->mkNode(kind::MULT, gcdNode, redite);
+    d_reduceGcd[n] = multIte;
+    return multIte;
+  }
+}
+
+Node ArithIteUtils::reduceConstantIteByGCD(Node n){
+  if(d_reduceGcd.find(n) != d_reduceGcd.end()){
+    return d_reduceGcd[n];
+  }
+  if(n.getKind() == kind::ITE && n.getType().isReal()){
+    return reduceIteConstantIteByGCD(n);
+  }
+
+  if(n.getNumChildren() > 0){
+    NodeBuilder<> nb(n.getKind());
+    if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+      nb << (n.getOperator());
+    }
+    bool anychange = false;
+    for(Node::iterator it = n.begin(), end = n.end(); it != end; ++it){
+      Node child = *it;
+      Node redchild = reduceConstantIteByGCD(child);
+      anychange = anychange || (child != redchild);
+      nb << redchild;
+    }
+    if(anychange){
+      Node res = nb;
+      d_reduceGcd[n] = res;
+      return res;
+    }else{
+      d_reduceGcd[n] = n;
+      return n;
+    }
+  }else{
+    return n;
+  }
+}
+
+unsigned ArithIteUtils::getSubCount() const{
+  return d_subcount;
+}
+
+void ArithIteUtils::addSubstitution(TNode f, TNode t){
+  Debug("arith::ite") << "adding " << f << " -> " << t << endl;
+  d_subcount = d_subcount + 1;
+  d_subs->addSubstitution(f, t);
+  d_model->addSubstitution(f, t);
+}
+
+Node ArithIteUtils::applySubstitutions(TNode f){
+  return d_subs->apply(f);
+}
+
+Node ArithIteUtils::selectForCmp(Node n) const{
+  if(n.getKind() == kind::ITE){
+    if(d_skolems.find(n[0]) != d_skolems.end()){
+      return selectForCmp(n[1]);
+    }
+  }
+  return n;
+}
+
+void ArithIteUtils::learnSubstitutions(const std::vector<Node>& assertions){
+  for(size_t i=0, N=assertions.size(); i < N; ++i){
+    collectAssertions(assertions[i]);
+  }
+  bool solvedSomething;
+  do{
+    solvedSomething = false;
+    size_t readPos = 0, writePos = 0, N = d_orBinEqs.size();
+    for(; readPos < N; readPos++){
+      Node curr = d_orBinEqs[readPos];
+      bool solved = solveBinOr(curr);
+      if(solved){
+        solvedSomething = true;
+      }else{
+        // didn't solve, push back
+        d_orBinEqs[writePos] = curr;
+        writePos++;
+      }
+    }
+    Assert(writePos <= N);
+    d_orBinEqs.resize(writePos);
+  }while(solvedSomething);
+
+  for(size_t i = 0, N=d_skolemsAdded.size(); i<N; ++i){
+    Node sk = d_skolemsAdded[i];
+    Node to = d_skolems[sk];
+    if(!to.isNull()){
+      Node fp = applySubstitutions(to);
+      addSubstitution(sk, fp);
+    }
+  }
+  d_implies.clear();
+  d_skolemsAdded.clear();
+  d_orBinEqs.clear();
+}
+
+void ArithIteUtils::addImplications(Node x, Node y){
+  // (or x y)
+  // (=> (not x) y)
+  // (=> (not y) x)
+
+  Node xneg = x.negate();
+  Node yneg = y.negate();
+  d_implies[xneg].insert(y);
+  d_implies[yneg].insert(x);
+}
+
+void ArithIteUtils::collectAssertions(TNode assertion){
+  if(assertion.getKind() == kind::OR){
+    if(assertion.getNumChildren() == 2){
+      TNode left = assertion[0], right = assertion[1];
+      addImplications(left, right);
+      if(left.getKind() == kind::EQUAL && right.getKind() == kind::EQUAL){
+        if(left[0].getType().isInteger() && right[0].getType().isInteger()){
+          d_orBinEqs.push_back(assertion);
+        }
+      }
+    }
+  }else if(assertion.getKind() == kind::AND){
+    for(unsigned i=0, N=assertion.getNumChildren(); i < N; ++i){
+      collectAssertions(assertion[i]);
+    }
+  }
+}
+
+Node ArithIteUtils::findIteCnd(TNode tb, TNode fb) const{
+  Node negtb = tb.negate();
+  Node negfb = fb.negate();
+  ImpMap::const_iterator ti = d_implies.find(negtb);
+  ImpMap::const_iterator fi = d_implies.find(negfb);
+
+  if(ti != d_implies.end() && fi != d_implies.end()){
+    const std::set<Node>& negtimp = ti->second;
+    const std::set<Node>& negfimp = fi->second;
+
+    // (or (not x) y)
+    // (or x z)
+    // (or y z)
+    // ---
+    // (ite x y z) return x
+    // ---
+    // (not y) => (not x)
+    // (not z) => x
+    std::set<Node>::const_iterator ci = negtimp.begin(), cend = negtimp.end();
+    for(; ci != cend; ci++){
+      Node impliedByNotTB = *ci;
+      Node impliedByNotTBNeg = impliedByNotTB.negate();
+      if(negfimp.find(impliedByNotTBNeg) != negfimp.end()){
+        return impliedByNotTBNeg; // implies tb
+      }
+    }
+  }
+
+  return Node::null();
+}
+
+bool ArithIteUtils::solveBinOr(TNode binor){
+  Assert(binor.getKind() == kind::OR);
+  Assert(binor.getNumChildren() == 2);
+  Assert(binor[0].getKind() ==  kind::EQUAL);
+  Assert(binor[1].getKind() ==  kind::EQUAL);
+
+  Node n = applySubstitutions(binor);
+  Assert(n.getKind() == kind::OR);
+  Assert(binor.getNumChildren() == 2);
+  TNode l = n[0];
+  TNode r = n[1];
+
+  Assert(l.getKind() ==  kind::EQUAL);
+  Assert(r.getKind() ==  kind::EQUAL);
+
+  Debug("arith::ite") << "bin or " << n << endl;
+
+  bool lArithEq = l.getKind() == kind::EQUAL && l[0].getType().isInteger();
+  bool rArithEq = r.getKind() == kind::EQUAL && r[0].getType().isInteger();
+
+  if(lArithEq && rArithEq){
+    TNode sel = Node::null();
+    TNode otherL = Node::null();
+    TNode otherR = Node::null();
+    if(l[0] == r[0]) {
+      sel = l[0]; otherL = l[1]; otherR = r[1];
+    }else if(l[0] == r[1]){
+      sel = l[0]; otherL = l[1]; otherR = r[0];
+    }else if(l[1] == r[0]){
+      sel = l[1]; otherL = l[0]; otherR = r[1];
+    }else if(l[1] == r[1]){
+      sel = l[1]; otherL = l[0]; otherR = r[0];
+    }
+    Debug("arith::ite") << "selected " << sel << endl;
+    if(sel.isVar() && sel.getKind() != kind::SKOLEM){
+
+      Debug("arith::ite") << "others l:" << otherL << " r " << otherR << endl;
+      Node useForCmpL = selectForCmp(otherL);
+      Node useForCmpR = selectForCmp(otherR);
+
+      Assert(Polynomial::isMember(sel));
+      Assert(Polynomial::isMember(useForCmpL));
+      Assert(Polynomial::isMember(useForCmpR));
+      Polynomial lside = Polynomial::parsePolynomial( useForCmpL );
+      Polynomial rside = Polynomial::parsePolynomial( useForCmpR );
+      Polynomial diff = lside-rside;
+
+      Debug("arith::ite") << "diff: " << diff.getNode() << endl;
+      if(diff.isConstant()){
+        // a: (sel = otherL) or (sel = otherR), otherL-otherR = c
+
+        NodeManager* nm = NodeManager::currentNM();
+
+        Node cnd = findIteCnd(binor[0], binor[1]);
+
+        Node sk = nm->mkSkolem("deor$$", nm->booleanType());
+        Node ite = sk.iteNode(otherL, otherR);
+        d_skolems.insert(sk, cnd);
+        d_skolemsAdded.push_back(sk);
+        addSubstitution(sel, ite);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/arith_ite_utils.h b/src/theory/arith/arith_ite_utils.h
new file mode 100644 (file)
index 0000000..fab0f32
--- /dev/null
@@ -0,0 +1,100 @@
+
+
+
+
+
+// Pass 1: label the ite as (constant) or (+ constant variable)
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H
+#define __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H
+
+#include "expr/node.h"
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include "context/cdo.h"
+#include "context/cdtrail_hashmap.h"
+
+namespace CVC4 {
+namespace theory {
+class ContainsTermITEVistor;
+class SubstitutionMap;
+class TheoryModel;
+
+namespace arith {
+
+class ArithIteUtils {
+  ContainsTermITEVistor& d_contains;
+  SubstitutionMap* d_subs;
+  TheoryModel* d_model;
+
+  typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
+  // cache for reduce vars
+  NodeMap d_reduceVar; // if reduceVars[n].isNull(), treat reduceVars[n] == n
+
+  // reduceVars[n] = d_constants[n] + d_varParts[n]
+  NodeMap d_constants; // d_constants[n] is a constant ite tree
+  NodeMap d_varParts; // d_varParts[n] is a polynomial
+
+
+  NodeMap d_reduceGcd;
+  typedef std::hash_map<Node, Integer, NodeHashFunction> NodeIntegerMap;
+  NodeIntegerMap d_gcds;
+
+  Integer d_one;
+
+  context::CDO<unsigned> d_subcount;
+  typedef context::CDTrailHashMap<Node, Node, NodeHashFunction> CDNodeMap;
+  CDNodeMap d_skolems;
+
+  typedef std::map<Node, std::set<Node> > ImpMap;
+  ImpMap d_implies;
+
+  std::vector<Node> d_skolemsAdded;
+
+  std::vector<Node> d_orBinEqs;
+
+public:
+  ArithIteUtils(ContainsTermITEVistor& contains,
+                context::Context* userContext,
+                TheoryModel* model);
+  ~ArithIteUtils();
+
+  //(ite ?v_2 ?v_1 (ite ?v_3 (- ?v_1 128) (- ?v_1 256)))
+
+  /** removes common sums variables sums from term ites. */
+  Node reduceVariablesInItes(Node n);
+
+  Node reduceConstantIteByGCD(Node n);
+
+  void clear();
+
+  Node applySubstitutions(TNode f);
+  unsigned getSubCount() const;
+
+  void learnSubstitutions(const std::vector<Node>& assertions);
+
+private:
+  /* applies this to all children of n and constructs the result */
+  Node applyReduceVariablesInItes(Node n);
+
+  const Integer& gcdIte(Node n);
+  Node reduceIteConstantIteByGCD_rec(Node n, const Rational& q);
+  Node reduceIteConstantIteByGCD(Node n);
+
+  void addSubstitution(TNode f, TNode t);
+  Node selectForCmp(Node n) const;
+
+  void collectAssertions(TNode assertion);
+  void addImplications(Node x, Node y);
+  Node findIteCnd(TNode tb, TNode fb) const;
+  bool solveBinOr(TNode binor);
+
+}; /* class ArithIteUtils */
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H */
index e1cab03568df672cf9248823c512a9b7a5b57ca7..5aa904aed204579bcf1d725f1e6c55ea91e227c3 100644 (file)
@@ -222,36 +222,94 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
 RewriteResponse ArithRewriter::preRewriteMult(TNode t){
   Assert(t.getKind()== kind::MULT);
 
-  // Rewrite multiplications with a 0 argument and to 0
-  Rational qZero(0);
+  if(t.getNumChildren() == 2){
+    if(t[0].getKind() == kind::CONST_RATIONAL
+       && t[0].getConst<Rational>().isOne()){
+      return RewriteResponse(REWRITE_DONE, t[1]);
+    }
+    if(t[1].getKind() == kind::CONST_RATIONAL
+       && t[1].getConst<Rational>().isOne()){
+      return RewriteResponse(REWRITE_DONE, t[0]);
+    }
+  }
 
+  // Rewrite multiplications with a 0 argument and to 0
   for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
     if((*i).getKind() == kind::CONST_RATIONAL) {
-      if((*i).getConst<Rational>() == qZero) {
-        return RewriteResponse(REWRITE_DONE, mkRationalNode(qZero));
+      if((*i).getConst<Rational>().isZero()) {
+        TNode zero = (*i);
+        return RewriteResponse(REWRITE_DONE, zero);
       }
     }
   }
   return RewriteResponse(REWRITE_DONE, t);
 }
+
+static bool canFlatten(Kind k, TNode t){
+  for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
+    TNode child = *i;
+    if(child.getKind() == k){
+      return true;
+    }
+  }
+  return false;
+}
+
+static void flatten(std::vector<TNode>& pb, Kind k, TNode t){
+  if(t.getKind() == k){
+    for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
+      TNode child = *i;
+      if(child.getKind() == k){
+        flatten(pb, k, child);
+      }else{
+        pb.push_back(child);
+      }
+    }
+  }else{
+    pb.push_back(t);
+  }
+}
+
+static Node flatten(Kind k, TNode t){
+  std::vector<TNode> pb;
+  flatten(pb, k, t);
+  Assert(pb.size() >= 2);
+  return NodeManager::currentNM()->mkNode(k, pb);
+}
+
 RewriteResponse ArithRewriter::preRewritePlus(TNode t){
   Assert(t.getKind()== kind::PLUS);
 
-  return RewriteResponse(REWRITE_DONE, t);
+  if(canFlatten(kind::PLUS, t)){
+    return RewriteResponse(REWRITE_DONE, flatten(kind::PLUS, t));
+  }else{
+    return RewriteResponse(REWRITE_DONE, t);
+  }
 }
 
 RewriteResponse ArithRewriter::postRewritePlus(TNode t){
   Assert(t.getKind()== kind::PLUS);
 
-  Polynomial res = Polynomial::mkZero();
+  std::vector<Monomial> monomials;
+  std::vector<Polynomial> polynomials;
 
   for(TNode::iterator i = t.begin(), end = t.end(); i != end; ++i){
-    Node curr = *i;
-    Polynomial currPoly = Polynomial::parsePolynomial(curr);
+    TNode curr = *i;
+    if(Monomial::isMember(curr)){
+      monomials.push_back(Monomial::parseMonomial(curr));
+    }else{
+      polynomials.push_back(Polynomial::parsePolynomial(curr));
+    }
+  }
 
-    res = res + currPoly;
+  if(!monomials.empty()){
+    Monomial::sort(monomials);
+    Monomial::combineAdjacentMonomials(monomials);
+    polynomials.push_back(Polynomial::mkPolynomial(monomials));
   }
 
+  Polynomial res = Polynomial::sumPolynomials(polynomials);
+
   return RewriteResponse(REWRITE_DONE, res.getNode());
 }
 
index 8f6f75295611910d3ed3f3217d400439955a2cf9..3854188e00ee3a8a202b5849a7310e66e0375ac5 100644 (file)
@@ -21,6 +21,8 @@
 #include "theory/arith/arith_static_learner.h"
 #include "theory/arith/options.h"
 
+#include "theory/arith/normal_form.h"
+
 #include "expr/expr.h"
 #include "expr/convenience_node_builders.h"
 
@@ -38,7 +40,11 @@ ArithStaticLearner::ArithStaticLearner(context::Context* userContext) :
   d_minMap(userContext),
   d_maxMap(userContext),
   d_statistics()
-{}
+{
+}
+
+ArithStaticLearner::~ArithStaticLearner(){
+}
 
 ArithStaticLearner::Statistics::Statistics():
   d_iteMinMaxApplications("theory::arith::iteMinMaxApplications", 0),
@@ -98,9 +104,6 @@ void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){
 }
 
 
-
-
-
 void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet& defTrue){
   Debug("arith::static") << "===================== looking at " << n << endl;
 
@@ -116,49 +119,12 @@ void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet
       iteConstant(n, learned);
     }
     break;
+
   case CONST_RATIONAL:
     // Mark constants as minmax
     d_minMap.insert(n, n.getConst<Rational>());
     d_maxMap.insert(n, n.getConst<Rational>());
     break;
-  case OR: {
-    // Look for things like "x = 0 OR x = 1" (that are defTrue) and
-    // turn them into a pseudoboolean.  We catch "x >= 0
-    if(defTrue.find(n) == defTrue.end() ||
-       n.getNumChildren() != 2 ||
-       n[0].getKind() != EQUAL ||
-       n[1].getKind() != EQUAL) {
-      break;
-    }
-    Node var, c1, c2;
-    if(n[0][0].isVar() &&
-       n[0][1].isConst()) {
-      var = n[0][0];
-      c1 = n[0][1];
-    } else if(n[0][1].isVar() &&
-              n[0][0].isConst()) {
-      var = n[0][1];
-      c1 = n[0][0];
-    } else {
-      break;
-    }
-    if(!var.getType().isInteger() ||
-       !c1.getType().isReal()) {
-      break;
-    }
-    if(var == n[1][0]) {
-      c2 = n[1][1];
-    } else if(var == n[1][1]) {
-      c2 = n[1][0];
-    } else {
-      break;
-    }
-    if(!c2.getType().isReal()) {
-      break;
-    }
-
-    break;
-  }
   default: // Do nothing
     break;
   }
index d8407eeba3fb7279a58f25d067b3c62da807009f..2615cdcd6b4d5f539689511c3eccf49ee86fc409 100644 (file)
@@ -25,7 +25,6 @@
 #include "theory/arith/arith_utilities.h"
 
 #include "context/context.h"
-#include "context/cdlist.h"
 #include "context/cdtrail_hashmap.h"
 #include <set>
 
@@ -45,6 +44,7 @@ private:
 
 public:
   ArithStaticLearner(context::Context* userContext);
+  ~ArithStaticLearner();
   void staticLearning(TNode n, NodeBuilder<>& learned);
 
   void addBound(TNode n);
index 11626c1de54738884309f0aab902367528db417f..98aa43e713901389f645ad274879da8747a67454 100644 (file)
@@ -238,6 +238,25 @@ inline Node flattenAnd(Node n){
   return NodeManager::currentNM()->mkNode(kind::AND, out);
 }
 
+inline Node getIdentity(Kind k){
+  switch(k){
+  case kind::AND:
+    return NodeManager::currentNM()->mkConst<bool>(true);
+  case kind::PLUS:
+    return NodeManager::currentNM()->mkConst(Rational(1));
+  default:
+    Unreachable();
+  }
+}
+
+inline Node safeConstructNary(NodeBuilder<>& nb){
+  switch(nb.getNumChildren()){
+  case 0:  return getIdentity(nb.getKind());
+  case 1:  return nb[0];
+  default: return (Node)nb;
+  }
+}
+
 }/* CVC4::theory::arith namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index d4a445b70c46303839ce5db6ef2bf4a5ecf34849..c4b64682f7591515bb8a888bf53a3780ecb24ab8 100644 (file)
@@ -22,6 +22,9 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
+SetupLiteralCallBack::SetupLiteralCallBack(TheoryArithPrivate& ta)
+  : d_arith(ta)
+{}
 void SetupLiteralCallBack::operator()(TNode lit){
   TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit;
   if(!d_arith.isSetup(atom)){
@@ -29,30 +32,72 @@ void SetupLiteralCallBack::operator()(TNode lit){
   }
 }
 
+DeltaComputeCallback::DeltaComputeCallback(const TheoryArithPrivate& ta)
+  : d_ta(ta)
+{}
 Rational DeltaComputeCallback::operator()() const{
   return d_ta.deltaValueForTotalOrder();
 }
 
+TempVarMalloc::TempVarMalloc(TheoryArithPrivate& ta)
+: d_ta(ta)
+{}
 ArithVar TempVarMalloc::request(){
   Node skolem = mkRealSkolem("tmpVar");
-  return d_ta.requestArithVar(skolem, false);
+  return d_ta.requestArithVar(skolem, false, true);
 }
 void TempVarMalloc::release(ArithVar v){
   d_ta.releaseArithVar(v);
 }
 
+BasicVarModelUpdateCallBack::BasicVarModelUpdateCallBack(TheoryArithPrivate& ta)
+  : d_ta(ta)
+{}
 void BasicVarModelUpdateCallBack::operator()(ArithVar x){
   d_ta.signal(x);
 }
 
-void RaiseConflict::operator()(Node n){
-  d_ta.raiseConflict(n);
+RaiseConflict::RaiseConflict(TheoryArithPrivate& ta, ConstraintCPVec& buf )
+  : d_ta(ta)
+  , d_construction(buf)
+{}
+
+/* Adds a constraint to the constraint under construction. */
+void RaiseConflict::addConstraint(ConstraintCP c){
+  d_construction.push_back(c);
+}
+/* Turns the vector under construction into a conflict */
+void RaiseConflict::commitConflict(){
+  Assert(!d_construction.empty());
+  sendConflict(d_construction);
+  d_construction.clear();
+}
+
+void RaiseConflict::sendConflict(const ConstraintCPVec& vec){
+  d_ta.raiseConflict(vec);
+}
+
+/* If you are not an equality engine, don't use this! */
+void RaiseConflict::blackBoxConflict(Node n){
+  d_ta.blackBoxConflict(n);
 }
 
+
+BoundCountingLookup::BoundCountingLookup(TheoryArithPrivate& ta)
+: d_ta(ta)
+{}
+
 const BoundsInfo& BoundCountingLookup::boundsInfo(ArithVar basic) const{
   return d_ta.boundsInfo(basic);
 }
 
+BoundCounts BoundCountingLookup::atBounds(ArithVar basic) const{
+  return boundsInfo(basic).atBounds();
+}
+BoundCounts BoundCountingLookup::hasBounds(ArithVar basic) const {
+  return boundsInfo(basic).hasBounds();
+}
+
 }/* CVC4::theory::arith namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index fd9369bf11103dc8eabe46211a801815e4510ec6..c4c79ad75b190184bd0278284ef485835ff3de30 100644 (file)
@@ -24,6 +24,7 @@
 #include "theory/arith/theory_arith_private_forward.h"
 #include "theory/arith/arithvar.h"
 #include "theory/arith/bound_counts.h"
+#include "theory/arith/constraint_forward.h"
 
 namespace CVC4 {
 namespace theory {
@@ -67,7 +68,7 @@ class SetupLiteralCallBack : public TNodeCallBack {
 private:
   TheoryArithPrivate& d_arith;
 public:
-  SetupLiteralCallBack(TheoryArithPrivate& ta) : d_arith(ta){}
+  SetupLiteralCallBack(TheoryArithPrivate& ta);
   void operator()(TNode lit);
 };
 
@@ -75,7 +76,7 @@ class DeltaComputeCallback : public RationalCallBack {
 private:
   const TheoryArithPrivate& d_ta;
 public:
-  DeltaComputeCallback(const TheoryArithPrivate& ta) : d_ta(ta){}
+  DeltaComputeCallback(const TheoryArithPrivate& ta);
   Rational operator()() const;
 };
 
@@ -83,7 +84,7 @@ class BasicVarModelUpdateCallBack : public ArithVarCallBack{
 private:
   TheoryArithPrivate& d_ta;
 public:
-  BasicVarModelUpdateCallBack(TheoryArithPrivate& ta) : d_ta(ta) {}
+  BasicVarModelUpdateCallBack(TheoryArithPrivate& ta);
   void operator()(ArithVar x);
 };
 
@@ -91,31 +92,37 @@ class TempVarMalloc : public ArithVarMalloc {
 private:
   TheoryArithPrivate& d_ta;
 public:
-  TempVarMalloc(TheoryArithPrivate& ta) : d_ta(ta) {}
+  TempVarMalloc(TheoryArithPrivate& ta);
   ArithVar request();
   void release(ArithVar v);
 };
 
-class RaiseConflict : public NodeCallBack {
+class RaiseConflict {
 private:
   TheoryArithPrivate& d_ta;
+  ConstraintCPVec& d_construction;
 public:
-  RaiseConflict(TheoryArithPrivate& ta) : d_ta(ta) {}
-  void operator()(Node n);
+  RaiseConflict(TheoryArithPrivate& ta, ConstraintCPVec& d_construction);
+
+  /* Adds a constraint to the constraint under construction. */
+  void addConstraint(ConstraintCP c);
+  /* Turns the vector under construction into a conflict */
+  void commitConflict();
+
+  void sendConflict(const ConstraintCPVec& vec);
+
+  /* If you are not an equality engine, don't use this! */
+  void blackBoxConflict(Node n);
 };
 
 class BoundCountingLookup {
 private:
   TheoryArithPrivate& d_ta;
 public:
-  BoundCountingLookup(TheoryArithPrivate& ta) : d_ta(ta) {}
+  BoundCountingLookup(TheoryArithPrivate& ta);
   const BoundsInfo& boundsInfo(ArithVar basic) const;
-  BoundCounts atBounds(ArithVar basic) const{
-    return boundsInfo(basic).atBounds();
-  }
-  BoundCounts hasBounds(ArithVar basic) const {
-    return boundsInfo(basic).hasBounds();
-  }
+  BoundCounts atBounds(ArithVar basic) const;
+  BoundCounts hasBounds(ArithVar basic) const;
 };
 
 }/* CVC4::theory::arith namespace */
index a828b9e7f8c08eec30403145d3b6e66cfce73521..d1d11c86efa3b642a9b4842ca03b733c9108fe56 100644 (file)
@@ -65,11 +65,105 @@ ArithCongruenceManager::Statistics::~Statistics(){
   StatisticsRegistry::unregisterStat(&d_conflicts);
 }
 
+ArithCongruenceManager::ArithCongruenceNotify::ArithCongruenceNotify(ArithCongruenceManager& acm)
+  : d_acm(acm)
+{}
+
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerEquality(TNode equality, bool value) {
+  Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
+  if (value) {
+    return d_acm.propagate(equality);
+  } else {
+    return d_acm.propagate(equality.notNode());
+  }
+}
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerPredicate(TNode predicate, bool value) {
+  Unreachable();
+}
+
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+  Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
+  if (value) {
+    return d_acm.propagate(t1.eqNode(t2));
+  } else {
+    return d_acm.propagate(t1.eqNode(t2).notNode());
+  }
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+  Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << std::endl;
+  if (t1.getKind() == kind::CONST_BOOLEAN) {
+    d_acm.propagate(t1.iffNode(t2));
+  } else {
+    d_acm.propagate(t1.eqNode(t2));
+  }
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyNewClass(TNode t) {
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyPreMerge(TNode t1, TNode t2) {
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyPostMerge(TNode t1, TNode t2) {
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+}
+
+void ArithCongruenceManager::raiseConflict(Node conflict){
+  Assert(!inConflict());
+  Debug("arith::conflict") << "difference manager conflict   " << conflict << std::endl;
+  d_inConflict.raise();
+  d_raiseConflict.blackBoxConflict(conflict);
+}
+bool ArithCongruenceManager::inConflict() const{
+  return d_inConflict.isRaised();
+}
+
+bool ArithCongruenceManager::hasMorePropagations() const {
+  return !d_propagatations.empty();
+}
+const Node ArithCongruenceManager::getNextPropagation() {
+  Assert(hasMorePropagations());
+  Node prop = d_propagatations.front();
+  d_propagatations.dequeue();
+  return prop;
+}
+
+bool ArithCongruenceManager::canExplain(TNode n) const {
+  return d_explanationMap.find(n) != d_explanationMap.end();
+}
+
 void ArithCongruenceManager::setMasterEqualityEngine(eq::EqualityEngine* eq) {
   d_ee.setMasterEqualityEngine(eq);
 }
 
-void ArithCongruenceManager::watchedVariableIsZero(Constraint lb, Constraint ub){
+Node ArithCongruenceManager::externalToInternal(TNode n) const{
+  Assert(canExplain(n));
+  ExplainMap::const_iterator iter = d_explanationMap.find(n);
+  size_t pos = (*iter).second;
+  return d_propagatations[pos];
+}
+
+void ArithCongruenceManager::pushBack(TNode n){
+  d_explanationMap.insert(n, d_propagatations.size());
+  d_propagatations.enqueue(n);
+
+  ++(d_statistics.d_propagations);
+}
+void ArithCongruenceManager::pushBack(TNode n, TNode r){
+  d_explanationMap.insert(r, d_propagatations.size());
+  d_explanationMap.insert(n, d_propagatations.size());
+  d_propagatations.enqueue(n);
+
+  ++(d_statistics.d_propagations);
+}
+void ArithCongruenceManager::pushBack(TNode n, TNode r, TNode w){
+  d_explanationMap.insert(w, d_propagatations.size());
+  d_explanationMap.insert(r, d_propagatations.size());
+  d_explanationMap.insert(n, d_propagatations.size());
+  d_propagatations.enqueue(n);
+
+  ++(d_statistics.d_propagations);
+}
+
+void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub){
   Assert(lb->isLowerBound());
   Assert(ub->isUpperBound());
   Assert(lb->getVariable() == ub->getVariable());
@@ -79,13 +173,13 @@ void ArithCongruenceManager::watchedVariableIsZero(Constraint lb, Constraint ub)
   ++(d_statistics.d_watchedVariableIsZero);
 
   ArithVar s = lb->getVariable();
-  Node reason = ConstraintValue::explainConflict(lb,ub);
+  Node reason = Constraint_::externalExplainByAssertions(lb,ub);
 
   d_keepAlive.push_back(reason);
   assertionToEqualityEngine(true, s, reason);
 }
 
-void ArithCongruenceManager::watchedVariableIsZero(Constraint eq){
+void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
   Assert(eq->isEquality());
   Assert(eq->getValue().sgn() == 0);
 
@@ -96,20 +190,20 @@ void ArithCongruenceManager::watchedVariableIsZero(Constraint eq){
   //Explain for conflict is correct as these proofs are generated
   //and stored eagerly
   //These will be safe for propagation later as well
-  Node reason = eq->explainForConflict();
+  Node reason = eq->externalExplainByAssertions();
 
   d_keepAlive.push_back(reason);
   assertionToEqualityEngine(true, s, reason);
 }
 
-void ArithCongruenceManager::watchedVariableCannotBeZero(Constraint c){
+void ArithCongruenceManager::watchedVariableCannotBeZero(ConstraintCP c){
   ++(d_statistics.d_watchedVariableIsNotZero);
 
   ArithVar s = c->getVariable();
 
   //Explain for conflict is correct as these proofs are generated and stored eagerly
   //These will be safe for propagation later as well
-  Node reason = c->explainForConflict();
+  Node reason = c->externalExplainByAssertions();
 
   d_keepAlive.push_back(reason);
   assertionToEqualityEngine(false, s, reason);
@@ -142,7 +236,7 @@ bool ArithCongruenceManager::propagate(TNode x){
 
   Assert(rewritten.getKind() != kind::CONST_BOOLEAN);
 
-  Constraint c = d_constraintDatabase.lookup(rewritten);
+  ConstraintP c = d_constraintDatabase.lookup(rewritten);
   if(c == NullConstraint){
     //using setup as there may not be a corresponding congruence literal yet
     d_setupLiteral(rewritten);
@@ -158,7 +252,8 @@ bool ArithCongruenceManager::propagate(TNode x){
 
   if(c->negationHasProof()){
     Node expC = explainInternal(x);
-    Node neg = c->getNegation()->explainForConflict();
+    ConstraintCP negC = c->getNegation();
+    Node neg = negC->externalExplainByAssertions();
     Node conf = expC.andNode(neg);
     Node final = flattenAnd(conf);
 
@@ -288,7 +383,7 @@ void ArithCongruenceManager::assertionToEqualityEngine(bool isEquality, ArithVar
   }
 }
 
-void ArithCongruenceManager::equalsConstant(Constraint c){
+void ArithCongruenceManager::equalsConstant(ConstraintCP c){
   Assert(c->isEquality());
 
   ++(d_statistics.d_equalsConstantCalls);
@@ -303,13 +398,13 @@ void ArithCongruenceManager::equalsConstant(Constraint c){
   Node eq = xAsNode.eqNode(asRational);
   d_keepAlive.push_back(eq);
 
-  Node reason = c->explainForConflict();
+  Node reason = c->externalExplainByAssertions();
   d_keepAlive.push_back(reason);
 
   d_ee.assertEquality(eq, true, reason);
 }
 
-void ArithCongruenceManager::equalsConstant(Constraint lb, Constraint ub){
+void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
   Assert(lb->isLowerBound());
   Assert(ub->isUpperBound());
   Assert(lb->getVariable() == ub->getVariable());
@@ -319,7 +414,7 @@ void ArithCongruenceManager::equalsConstant(Constraint lb, Constraint ub){
                           << ub << std::endl;
 
   ArithVar x = lb->getVariable();
-  Node reason = ConstraintValue::explainConflict(lb,ub);
+  Node reason = Constraint_::externalExplainByAssertions(lb,ub);
 
   Node xAsNode = d_avariables.asNode(x);
   Node asRational = mkRationalNode(lb->getValue().getNoninfinitesimalPart());
index b4e0091699a61389e5c9ead9e0983d36261ac79f..8e369ff9a4b617053c1e823e8bece91ecda8ff6b 100644 (file)
@@ -57,43 +57,19 @@ private:
   private:
     ArithCongruenceManager& d_acm;
   public:
-    ArithCongruenceNotify(ArithCongruenceManager& acm): d_acm(acm) {}
-
-    bool eqNotifyTriggerEquality(TNode equality, bool value) {
-      Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
-      if (value) {
-        return d_acm.propagate(equality);
-      } else {
-        return d_acm.propagate(equality.notNode());
-      }
-    }
-
-    bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
-      Unreachable();
-    }
-
-    bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
-      Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
-      if (value) {
-        return d_acm.propagate(t1.eqNode(t2));
-      } else {
-        return d_acm.propagate(t1.eqNode(t2).notNode());
-      }
-    }
-
-    void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
-      Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << std::endl;
-      if (t1.getKind() == kind::CONST_BOOLEAN) {
-        d_acm.propagate(t1.iffNode(t2));
-      } else {
-        d_acm.propagate(t1.eqNode(t2));
-      }
-    }
-
-    void eqNotifyNewClass(TNode t) { }
-    void eqNotifyPreMerge(TNode t1, TNode t2) { }
-    void eqNotifyPostMerge(TNode t1, TNode t2) { }
-    void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+    ArithCongruenceNotify(ArithCongruenceManager& acm);
+
+    bool eqNotifyTriggerEquality(TNode equality, bool value);
+
+    bool eqNotifyTriggerPredicate(TNode predicate, bool value);
+
+    bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value);
+
+    void eqNotifyConstantTermMerge(TNode t1, TNode t2);
+    void eqNotifyNewClass(TNode t);
+    void eqNotifyPreMerge(TNode t1, TNode t2);
+    void eqNotifyPostMerge(TNode t1, TNode t2);
+    void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
   };
   ArithCongruenceNotify d_notify;
 
@@ -117,66 +93,27 @@ private:
 
   eq::EqualityEngine d_ee;
 
-  void raiseConflict(Node conflict){
-    Assert(!inConflict());
-    Debug("arith::conflict") << "difference manager conflict   " << conflict << std::endl;
-    d_inConflict.raise();
-    d_raiseConflict(conflict);
-  }
+  void raiseConflict(Node conflict);
 public:
 
-  bool inConflict() const{
-    return d_inConflict.isRaised();
-  };
+  bool inConflict() const;
 
-  bool hasMorePropagations() const {
-    return !d_propagatations.empty();
-  }
+  bool hasMorePropagations() const;
 
-  const Node getNextPropagation() {
-    Assert(hasMorePropagations());
-    Node prop = d_propagatations.front();
-    d_propagatations.dequeue();
-    return prop;
-  }
+  const Node getNextPropagation();
 
-  bool canExplain(TNode n) const {
-    return d_explanationMap.find(n) != d_explanationMap.end();
-  }
+  bool canExplain(TNode n) const;
 
   void setMasterEqualityEngine(eq::EqualityEngine* eq);
 
 private:
-  Node externalToInternal(TNode n) const{
-    Assert(canExplain(n));
-    ExplainMap::const_iterator iter = d_explanationMap.find(n);
-    size_t pos = (*iter).second;
-    return d_propagatations[pos];
-  }
-
-  void pushBack(TNode n){
-    d_explanationMap.insert(n, d_propagatations.size());
-    d_propagatations.enqueue(n);
-
-    ++(d_statistics.d_propagations);
-  }
-
-  void pushBack(TNode n, TNode r){
-    d_explanationMap.insert(r, d_propagatations.size());
-    d_explanationMap.insert(n, d_propagatations.size());
-    d_propagatations.enqueue(n);
+  Node externalToInternal(TNode n) const;
 
-    ++(d_statistics.d_propagations);
-  }
+  void pushBack(TNode n);
 
-  void pushBack(TNode n, TNode r, TNode w){
-    d_explanationMap.insert(w, d_propagatations.size());
-    d_explanationMap.insert(r, d_propagatations.size());
-    d_explanationMap.insert(n, d_propagatations.size());
-    d_propagatations.enqueue(n);
+  void pushBack(TNode n, TNode r);
 
-    ++(d_statistics.d_propagations);
-  }
+  void pushBack(TNode n, TNode r, TNode w);
 
   bool propagate(TNode x);
   void explain(TNode literal, std::vector<TNode>& assumptions);
@@ -207,21 +144,21 @@ public:
   }
 
   /** Assert an equality. */
-  void watchedVariableIsZero(Constraint eq);
+  void watchedVariableIsZero(ConstraintCP eq);
 
   /** Assert a conjunction from lb and ub. */
-  void watchedVariableIsZero(Constraint lb, Constraint ub);
+  void watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub);
 
   /** Assert that the value cannot be zero. */
-  void watchedVariableCannotBeZero(Constraint c);
+  void watchedVariableCannotBeZero(ConstraintCP c);
 
   /** Assert that the value cannot be zero. */
-  void watchedVariableCannotBeZero(Constraint c, Constraint d);
+  void watchedVariableCannotBeZero(ConstraintCP c, ConstraintCP d);
 
 
   /** Assert that the value is congruent to a constant. */
-  void equalsConstant(Constraint eq);
-  void equalsConstant(Constraint lb, Constraint ub);
+  void equalsConstant(ConstraintCP eq);
+  void equalsConstant(ConstraintCP lb, ConstraintCP ub);
 
 
   void addSharedTerm(Node x);
index 78b9d3494e7da08ad4a1cb9475f01b2aac490a3c..acbd4a04b68d0cded8a6182a83dfa02f35ddca0a 100644 (file)
@@ -64,7 +64,7 @@ ConstraintType constraintTypeOfComparison(const Comparison& cmp){
   }
 }
 
-ConstraintValue::ConstraintValue(ArithVar x,  ConstraintType t, const DeltaRational& v)
+Constraint_::Constraint_(ArithVar x,  ConstraintType t, const DeltaRational& v)
   : d_variable(x),
     d_type(t),
     d_value(v),
@@ -72,7 +72,7 @@ ConstraintValue::ConstraintValue(ArithVar x,  ConstraintType t, const DeltaRatio
     d_literal(Node::null()),
     d_negation(NullConstraint),
     d_canBePropagated(false),
-    _d_assertionOrder(AssertionOrderSentinel),
+    d_assertionOrder(AssertionOrderSentinel),
     d_witness(TNode::null()),
     d_proof(ProofIdSentinel),
     d_split(false),
@@ -82,7 +82,7 @@ ConstraintValue::ConstraintValue(ArithVar x,  ConstraintType t, const DeltaRatio
 }
 
 
-std::ostream& operator<<(std::ostream& o, const Constraint c){
+std::ostream& operator<<(std::ostream& o, const ConstraintP c){
   if(c == NullConstraint){
     return o << "NullConstraint";
   }else{
@@ -105,7 +105,7 @@ std::ostream& operator<<(std::ostream& o, const ConstraintType t){
   }
 }
 
-std::ostream& operator<<(std::ostream& o, const ConstraintValue& c){
+std::ostream& operator<<(std::ostream& o, const Constraint_& c){
   o << c.getVariable() << ' ' << c.getType() << ' ' << c.getValue();
   if(c.hasLiteral()){
     o << "(node " << c.getLiteral() << ')';
@@ -143,11 +143,67 @@ std::ostream& operator<<(std::ostream& o, const ValueCollection& vc){
   return o << "}";
 }
 
-void ConstraintValue::debugPrint() const {
+std::ostream& operator<<(std::ostream& o, const ConstraintCPVec& v){
+  o << "[" << v.size() << "x";
+  ConstraintCPVec::const_iterator i, end;
+  for(i=v.begin(), end=v.end(); i != end; ++i){
+    ConstraintCP c = *i;
+    o << ", " << (*c);
+  }
+  o << "]";
+  return o;
+}
+
+void Constraint_::debugPrint() const {
   Message() << *this << endl;
 }
 
-void ValueCollection::push_into(std::vector<Constraint>& vec) const {
+
+ValueCollection::ValueCollection()
+  : d_lowerBound(NullConstraint),
+    d_upperBound(NullConstraint),
+    d_equality(NullConstraint),
+    d_disequality(NullConstraint)
+{}
+
+bool ValueCollection::hasLowerBound() const{
+  return d_lowerBound != NullConstraint;
+}
+
+bool ValueCollection::hasUpperBound() const{
+  return d_upperBound != NullConstraint;
+}
+
+bool ValueCollection::hasEquality() const{
+  return d_equality != NullConstraint;
+}
+
+bool ValueCollection::hasDisequality() const {
+  return d_disequality != NullConstraint;
+}
+
+ConstraintP ValueCollection::getLowerBound() const {
+  Assert(hasLowerBound());
+  return d_lowerBound;
+}
+
+ConstraintP ValueCollection::getUpperBound() const {
+  Assert(hasUpperBound());
+  return d_upperBound;
+}
+
+ConstraintP ValueCollection::getEquality() const {
+  Assert(hasEquality());
+  return d_equality;
+}
+
+ConstraintP ValueCollection::getDisequality() const {
+  Assert(hasDisequality());
+  return d_disequality;
+}
+
+
+void ValueCollection::push_into(std::vector<ConstraintP>& vec) const {
   Debug("arith::constraint") << "push_into " << *this << endl;
   if(hasEquality()){
     vec.push_back(d_equality);
@@ -163,7 +219,7 @@ void ValueCollection::push_into(std::vector<Constraint>& vec) const {
   }
 }
 
-ValueCollection ValueCollection::mkFromConstraint(Constraint c){
+ValueCollection ValueCollection::mkFromConstraint(ConstraintP c){
   ValueCollection ret;
   Assert(ret.empty());
   switch(c->getType()){
@@ -210,7 +266,7 @@ const DeltaRational& ValueCollection::getValue() const{
   return nonNull()->getValue();
 }
 
-void ValueCollection::add(Constraint c){
+void ValueCollection::add(ConstraintP c){
   Assert(c != NullConstraint);
 
   Assert(empty() || getVariable() == c->getVariable());
@@ -238,7 +294,7 @@ void ValueCollection::add(Constraint c){
   }
 }
 
-Constraint ValueCollection::getConstraintOfType(ConstraintType t) const{
+ConstraintP ValueCollection::getConstraintOfType(ConstraintType t) const{
   switch(t){
   case LowerBound:
     Assert(hasLowerBound());
@@ -288,7 +344,7 @@ bool ValueCollection::empty() const{
       hasDisequality());
 }
 
-Constraint ValueCollection::nonNull() const{
+ConstraintP ValueCollection::nonNull() const{
   //This can be optimized by caching, but this is not necessary yet!
   /* "Premature optimization is the root of all evil." */
   if(hasLowerBound()){
@@ -304,18 +360,18 @@ Constraint ValueCollection::nonNull() const{
   }
 }
 
-bool ConstraintValue::initialized() const {
+bool Constraint_::initialized() const {
   return d_database != NULL;
 }
 
-void ConstraintValue::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, Constraint negation){
+void Constraint_::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation){
   Assert(!initialized());
   d_database = db;
   d_variablePosition = v;
   d_negation = negation;
 }
 
-ConstraintValue::~ConstraintValue() {
+Constraint_::~Constraint_() {
   Assert(safeToGarbageCollect());
 
   if(initialized()){
@@ -336,12 +392,12 @@ ConstraintValue::~ConstraintValue() {
   }
 }
 
-const ValueCollection& ConstraintValue::getValueCollection() const{
+const ValueCollection& Constraint_::getValueCollection() const{
   return d_variablePosition->second;
 }
 
-Constraint ConstraintValue::getCeiling() {
-  Debug("getCeiling") << "ConstraintValue::getCeiling on " << *this << endl;
+ConstraintP Constraint_::getCeiling() {
+  Debug("getCeiling") << "Constraint_::getCeiling on " << *this << endl;
   Assert(getValue().getInfinitesimalPart().sgn() > 0);
 
   DeltaRational ceiling(getValue().ceiling());
@@ -350,7 +406,7 @@ Constraint ConstraintValue::getCeiling() {
   return d_database->getConstraint(getVariable(), getType(), ceiling);
 }
 
-Constraint ConstraintValue::getFloor() {
+ConstraintP Constraint_::getFloor() {
   Assert(getValue().getInfinitesimalPart().sgn() < 0);
 
   DeltaRational floor(Rational(getValue().floor()));
@@ -359,19 +415,26 @@ Constraint ConstraintValue::getFloor() {
   return d_database->getConstraint(getVariable(), getType(), floor);
 }
 
-void ConstraintValue::setCanBePropagated() {
+void Constraint_::setCanBePropagated() {
   Assert(!canBePropagated());
   d_database->pushCanBePropagatedWatch(this);
 }
 
-void ConstraintValue::setAssertedToTheTheory(TNode witness) {
+void Constraint_::setAssertedToTheTheoryWithNegationTrue(TNode witness) {
+  Assert(hasLiteral());
+  Assert(!assertedToTheTheory());
+  Assert(d_negation->hasProof());
+  d_database->pushAssertionOrderWatch(this, witness);
+}
+
+void Constraint_::setAssertedToTheTheory(TNode witness) {
   Assert(hasLiteral());
   Assert(!assertedToTheTheory());
   Assert(!d_negation->assertedToTheTheory());
   d_database->pushAssertionOrderWatch(this, witness);
 }
 
-bool ConstraintValue::satisfiedBy(const DeltaRational& dr) const {
+bool Constraint_::satisfiedBy(const DeltaRational& dr) const {
   switch(getType()){
   case LowerBound:
     return getValue() <= dr;
@@ -385,19 +448,19 @@ bool ConstraintValue::satisfiedBy(const DeltaRational& dr) const {
   Unreachable();
 }
 
-// bool ConstraintValue::isPsuedoConstraint() const {
-//   return d_proof == d_database->d_psuedoConstraintProof;
-// }
+bool Constraint_::isInternalDecision() const {
+  return d_proof == d_database->d_internalDecisionProof;
+}
 
-bool ConstraintValue::isSelfExplaining() const {
+bool Constraint_::isSelfExplaining() const {
   return d_proof == d_database->d_selfExplainingProof;
 }
 
-bool ConstraintValue::hasEqualityEngineProof() const {
+bool Constraint_::hasEqualityEngineProof() const {
   return d_proof == d_database->d_equalityEngineProof;
 }
 
-bool ConstraintValue::sanityChecking(Node n) const {
+bool Constraint_::sanityChecking(Node n) const {
   Comparison cmp = Comparison::parseNormalForm(n);
   Kind k = cmp.comparisonKind();
   Polynomial pleft = cmp.normalizedVariablePart();
@@ -441,7 +504,7 @@ bool ConstraintValue::sanityChecking(Node n) const {
   }
 }
 
-Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
+ConstraintP Constraint_::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
   switch(t){
   case LowerBound:
     {
@@ -450,12 +513,12 @@ Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const Del
         Assert(r.getInfinitesimalPart() == 1);
         // make (not (v > r)), which is (v <= r)
         DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
-        return new ConstraintValue(v, UpperBound, dropInf);
+        return new Constraint_(v, UpperBound, dropInf);
       }else{
         Assert(r.infinitesimalSgn() == 0);
         // make (not (v >= r)), which is (v < r)
         DeltaRational addInf(r.getNoninfinitesimalPart(), -1);
-        return new ConstraintValue(v, UpperBound, addInf);
+        return new Constraint_(v, UpperBound, addInf);
       }
     }
   case UpperBound:
@@ -465,18 +528,18 @@ Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const Del
         Assert(r.getInfinitesimalPart() == -1);
         // make (not (v < r)), which is (v >= r)
         DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
-        return new ConstraintValue(v, LowerBound, dropInf);
+        return new Constraint_(v, LowerBound, dropInf);
       }else{
         Assert(r.infinitesimalSgn() == 0);
         // make (not (v <= r)), which is (v > r)
         DeltaRational addInf(r.getNoninfinitesimalPart(), 1);
-        return new ConstraintValue(v, LowerBound, addInf);
+        return new Constraint_(v, LowerBound, addInf);
       }
     }
   case Equality:
-    return new ConstraintValue(v, Disequality, r);
+    return new Constraint_(v, Disequality, r);
   case Disequality:
-    return new ConstraintValue(v, Equality, r);
+    return new Constraint_(v, Equality, r);
   default:
     Unreachable();
     return NullConstraint;
@@ -500,11 +563,42 @@ ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Co
   d_equalityEngineProof = d_proofs.size();
   d_proofs.push_back(NullConstraint);
 
-  // d_pseudoConstraintProof = d_proofs.size();
-  // d_proofs.push_back(NullConstraint);
+  d_internalDecisionProof = d_proofs.size();
+  d_proofs.push_back(NullConstraint);
+}
+
+SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{
+  Assert(variableDatabaseIsSetup(v));
+  return d_varDatabases[v]->d_constraints;
+}
+
+void ConstraintDatabase::pushSplitWatch(ConstraintP c){
+  Assert(!c->d_split);
+  c->d_split = true;
+  d_watches->d_splitWatches.push_back(c);
+}
+
+
+void ConstraintDatabase::pushCanBePropagatedWatch(ConstraintP c){
+  Assert(!c->d_canBePropagated);
+  c->d_canBePropagated = true;
+  d_watches->d_canBePropagatedWatches.push_back(c);
+}
+
+void ConstraintDatabase::pushAssertionOrderWatch(ConstraintP c, TNode witness){
+  Assert(!c->assertedToTheTheory());
+  c->d_assertionOrder = d_watches->d_assertionOrderWatches.size();
+  c->d_witness = witness;
+  d_watches->d_assertionOrderWatches.push_back(c);
 }
 
-Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
+void ConstraintDatabase::pushProofWatch(ConstraintP c, ProofId pid){
+  Assert(c->d_proof == ProofIdSentinel);
+  c->d_proof = pid;
+  d_watches->d_proofWatches.push_back(c);
+}
+
+ConstraintP ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
   //This must always return a constraint.
 
   SortedConstraintMap& scm = getVariableSCM(v);
@@ -516,8 +610,8 @@ Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const
   if(vc.hasConstraintOfType(t)){
     return vc.getConstraintOfType(t);
   }else{
-    Constraint c = new ConstraintValue(v, t, r);
-    Constraint negC = ConstraintValue::makeNegation(v, t, r);
+    ConstraintP c = new Constraint_(v, t, r);
+    ConstraintP negC = Constraint_::makeNegation(v, t, r);
 
     SortedConstraintMapIterator negPos;
     if(t == Equality || t == Disequality){
@@ -539,6 +633,15 @@ Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const
     return c;
   }
 }
+
+ConstraintP ConstraintDatabase::ensureConstraint(ValueCollection& vc, ConstraintType t){
+  if(vc.hasConstraintOfType(t)){
+    return vc.getConstraintOfType(t);
+  }else{
+    return getConstraint(vc.getVariable(), t, vc.getValue());
+  }
+}
+
 bool ConstraintDatabase::emptyDatabase(const std::vector<PerVariableDatabase>& vec){
   std::vector<PerVariableDatabase>::const_iterator first = vec.begin();
   std::vector<PerVariableDatabase>::const_iterator last = vec.end();
@@ -550,7 +653,7 @@ ConstraintDatabase::~ConstraintDatabase(){
 
   delete d_watches;
 
-  std::vector<Constraint> constraintList;
+  std::vector<ConstraintP> constraintList;
 
   while(!d_varDatabases.empty()){
     PerVariableDatabase* back = d_varDatabases.back();
@@ -561,7 +664,7 @@ ConstraintDatabase::~ConstraintDatabase(){
       (i->second).push_into(constraintList);
     }
     while(!constraintList.empty()){
-      Constraint c = constraintList.back();
+      ConstraintP c = constraintList.back();
       constraintList.pop_back();
       delete c;
     }
@@ -586,17 +689,25 @@ ConstraintDatabase::Statistics::~Statistics(){
   StatisticsRegistry::unregisterStat(&d_unatePropagateImplications);
 }
 
+void ConstraintDatabase::deleteConstraintAndNegation(ConstraintP c){
+  Assert(c->safeToGarbageCollect());
+  ConstraintP neg = c->getNegation();
+  Assert(neg->safeToGarbageCollect());
+  delete c;
+  delete neg;
+}
+
 void ConstraintDatabase::addVariable(ArithVar v){
   if(d_reclaimable.isMember(v)){
     SortedConstraintMap& scm = getVariableSCM(v);
 
-    std::vector<Constraint> constraintList;
+    std::vector<ConstraintP> constraintList;
 
     for(SortedConstraintMapIterator i = scm.begin(), end = scm.end(); i != end; ++i){
       (i->second).push_into(constraintList);
     }
     while(!constraintList.empty()){
-      Constraint c = constraintList.back();
+      ConstraintP c = constraintList.back();
       constraintList.pop_back();
       Assert(c->safeToGarbageCollect());
       delete c;
@@ -605,6 +716,7 @@ void ConstraintDatabase::addVariable(ArithVar v){
 
     d_reclaimable.remove(v);
   }else{
+    Debug("arith::constraint") << "about to fail" << v << " " << d_varDatabases.size() << endl;
     Assert(v == d_varDatabases.size());
     d_varDatabases.push_back(new PerVariableDatabase(v));
   }
@@ -615,20 +727,20 @@ void ConstraintDatabase::removeVariable(ArithVar v){
   d_reclaimable.add(v);
 }
 
-bool ConstraintValue::safeToGarbageCollect() const{
+bool Constraint_::safeToGarbageCollect() const{
   return !isSplit()
     && !canBePropagated()
     && !hasProof()
     && !assertedToTheTheory();
 }
 
-Node ConstraintValue::split(){
+Node Constraint_::split(){
   Assert(isEquality() || isDisequality());
 
   bool isEq = isEquality();
 
-  Constraint eq = isEq ? this : d_negation;
-  Constraint diseq = isEq ? d_negation : this;
+  ConstraintP eq = isEq ? this : d_negation;
+  ConstraintP diseq = isEq ? d_negation : this;
 
   TNode eqNode = eq->getLiteral();
   Assert(eqNode.getKind() == kind::EQUAL);
@@ -651,26 +763,26 @@ bool ConstraintDatabase::hasLiteral(TNode literal) const {
   return lookup(literal) != NullConstraint;
 }
 
-// Constraint ConstraintDatabase::addLiteral(TNode literal){
+// ConstraintP ConstraintDatabase::addLiteral(TNode literal){
 //   Assert(!hasLiteral(literal));
 //   bool isNot = (literal.getKind() == NOT);
 //   TNode atom = isNot ? literal[0] : literal;
 
-//   Constraint atomC = addAtom(atom);
+//   ConstraintP atomC = addAtom(atom);
 
 //   return isNot ? atomC->d_negation : atomC;
 // }
 
-// Constraint ConstraintDatabase::allocateConstraintForComparison(ArithVar v, const Comparison cmp){
+// ConstraintP ConstraintDatabase::allocateConstraintForComparison(ArithVar v, const Comparison cmp){
 //   Debug("arith::constraint") << "allocateConstraintForLiteral(" << v << ", "<< cmp <<")" << endl;
 //   Kind kind = cmp.comparisonKind();
 //   ConstraintType type = constraintTypeOfLiteral(kind);
   
 //   DeltaRational dr = cmp.getDeltaRational();
-//   return new ConstraintValue(v, type, dr);
+//   return new Constraint_(v, type, dr);
 // }
 
-Constraint ConstraintDatabase::addLiteral(TNode literal){
+ConstraintP ConstraintDatabase::addLiteral(TNode literal){
   Assert(!hasLiteral(literal));
   bool isNot = (literal.getKind() == NOT);
   Node atomNode = (isNot ? literal[0] : literal);
@@ -688,7 +800,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
 
   DeltaRational posDR = posCmp.normalizedDeltaRational();
 
-  Constraint posC = new ConstraintValue(v, posType, posDR);
+  ConstraintP posC = new Constraint_(v, posType, posDR);
 
   Debug("arith::constraint") << "addliteral( literal ->" << literal << ")" << endl;
   Debug("arith::constraint") << "addliteral( posC ->" << posC << ")" << endl;
@@ -702,9 +814,9 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
   // If the attempt fails, i points to a pre-existing ValueCollection
 
   if(posI->second.hasConstraintOfType(posC->getType())){
-    //This is the situation where the Constraint exists, but
+    //This is the situation where the ConstraintP exists, but
     //the literal has not been  associated with it.
-    Constraint hit = posI->second.getConstraintOfType(posC->getType());
+    ConstraintP hit = posI->second.getConstraintOfType(posC->getType());
     Debug("arith::constraint") << "hit " << hit << endl;
     Debug("arith::constraint") << "posC " << posC << endl;
 
@@ -719,7 +831,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
     ConstraintType negType = constraintTypeOfComparison(negCmp);
     DeltaRational negDR = negCmp.normalizedDeltaRational();
 
-    Constraint negC = new ConstraintValue(v, negType, negDR);
+    ConstraintP negC = new Constraint_(v, negType, negDR);
 
     SortedConstraintMapIterator negI;
 
@@ -771,7 +883,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
 //   }
 // }
 
-Constraint ConstraintDatabase::lookup(TNode literal) const{
+ConstraintP ConstraintDatabase::lookup(TNode literal) const{
   NodetoConstraintMap::const_iterator iter = d_nodetoConstraintMap.find(literal);
   if(iter == d_nodetoConstraintMap.end()){
     return NullConstraint;
@@ -780,11 +892,19 @@ Constraint ConstraintDatabase::lookup(TNode literal) const{
   }
 }
 
-void ConstraintValue::selfExplaining(){
+void Constraint_::selfExplainingWithNegationTrue(){
+  Assert(!hasProof());
+  Assert(getNegation()->hasProof());
+  Assert(hasLiteral());
+  Assert(assertedToTheTheory());
+  d_database->pushProofWatch(this, d_database->d_selfExplainingProof);
+}
+
+void Constraint_::selfExplaining(){
   markAsTrue();
 }
 
-void ConstraintValue::propagate(){
+void Constraint_::propagate(){
   Assert(hasProof());
   Assert(canBePropagated());
   Assert(!assertedToTheTheory());
@@ -793,7 +913,7 @@ void ConstraintValue::propagate(){
   d_database->d_toPropagate.push(this);
 }
 
-void ConstraintValue::propagate(Constraint a){
+void Constraint_::propagate(ConstraintCP a){
   Assert(!hasProof());
   Assert(canBePropagated());
 
@@ -801,7 +921,7 @@ void ConstraintValue::propagate(Constraint a){
   propagate();
 }
 
-void ConstraintValue::propagate(Constraint a, Constraint b){
+void Constraint_::propagate(ConstraintCP a, ConstraintCP b){
   Assert(!hasProof());
   Assert(canBePropagated());
 
@@ -809,7 +929,7 @@ void ConstraintValue::propagate(Constraint a, Constraint b){
   propagate();
 }
 
-void ConstraintValue::propagate(const std::vector<Constraint>& b){
+void Constraint_::propagate(const ConstraintCPVec& b){
   Assert(!hasProof());
   Assert(canBePropagated());
 
@@ -817,9 +937,8 @@ void ConstraintValue::propagate(const std::vector<Constraint>& b){
   propagate();
 }
 
-void ConstraintValue::impliedBy(Constraint a){
-  Assert(!isTrue());
-  Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(ConstraintCP a){
+  Assert(truthIsUnknown());
 
   markAsTrue(a);
   if(canBePropagated()){
@@ -827,9 +946,8 @@ void ConstraintValue::impliedBy(Constraint a){
   }
 }
 
-void ConstraintValue::impliedBy(Constraint a, Constraint b){
-  Assert(!isTrue());
-  Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(ConstraintCP a, ConstraintCP b){
+  Assert(truthIsUnknown());
 
   markAsTrue(a, b);
   if(canBePropagated()){
@@ -837,9 +955,8 @@ void ConstraintValue::impliedBy(Constraint a, Constraint b){
   }
 }
 
-void ConstraintValue::impliedBy(const std::vector<Constraint>& b){
-  Assert(!isTrue());
-  Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(const ConstraintCPVec& b){
+  Assert(truthIsUnknown());
 
   markAsTrue(b);
   if(canBePropagated()){
@@ -847,30 +964,29 @@ void ConstraintValue::impliedBy(const std::vector<Constraint>& b){
   }
 }
 
-// void ConstraintValue::setPseudoConstraint(){
-//   Assert(truthIsUnknown());
-//   Assert(!hasLiteral());
+void Constraint_::setInternalDecision(){
+  Assert(truthIsUnknown());
+  Assert(!assertedToTheTheory());
 
-//   d_database->pushProofWatch(this, d_database->d_pseudoConstraintProof);
-// }
+  d_database->pushProofWatch(this, d_database->d_internalDecisionProof);
+}
 
-void ConstraintValue::setEqualityEngineProof(){
+void Constraint_::setEqualityEngineProof(){
   Assert(truthIsUnknown());
   Assert(hasLiteral());
   d_database->pushProofWatch(this, d_database->d_equalityEngineProof);
 }
 
-void ConstraintValue::markAsTrue(){
+void Constraint_::markAsTrue(){
   Assert(truthIsUnknown());
   Assert(hasLiteral());
   Assert(assertedToTheTheory());
   d_database->pushProofWatch(this, d_database->d_selfExplainingProof);
 }
 
-void ConstraintValue::markAsTrue(Constraint imp){
+void Constraint_::markAsTrue(ConstraintCP imp){
   Assert(truthIsUnknown());
   Assert(imp->hasProof());
-  //Assert(!imp->isPseudoConstraint());
 
   d_database->d_proofs.push_back(NullConstraint);
   d_database->d_proofs.push_back(imp);
@@ -878,12 +994,10 @@ void ConstraintValue::markAsTrue(Constraint imp){
   d_database->pushProofWatch(this, proof);
 }
 
-void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){
+void Constraint_::markAsTrue(ConstraintCP impA, ConstraintCP impB){
   Assert(truthIsUnknown());
   Assert(impA->hasProof());
   Assert(impB->hasProof());
-  //Assert(!impA->isPseudoConstraint());
-  //Assert(!impB->isPseudoConstraint());
 
   d_database->d_proofs.push_back(NullConstraint);
   d_database->d_proofs.push_back(impA);
@@ -893,12 +1007,12 @@ void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){
   d_database->pushProofWatch(this, proof);
 }
 
-void ConstraintValue::markAsTrue(const vector<Constraint>& a){
+void Constraint_::markAsTrue(const ConstraintCPVec& a){
   Assert(truthIsUnknown());
   Assert(a.size() >= 1);
   d_database->d_proofs.push_back(NullConstraint);
-  for(vector<Constraint>::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
-    Constraint c_i = *i;
+  for(ConstraintCPVec::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
+    ConstraintCP c_i = *i;
     Assert(c_i->hasProof());
     //Assert(!c_i->isPseudoConstraint());
     d_database->d_proofs.push_back(c_i);
@@ -909,12 +1023,12 @@ void ConstraintValue::markAsTrue(const vector<Constraint>& a){
   d_database->pushProofWatch(this, proof);
 }
 
-SortedConstraintMap& ConstraintValue::constraintSet() const{
+SortedConstraintMap& Constraint_::constraintSet() const{
   Assert(d_database->variableDatabaseIsSetup(d_variable));
   return (d_database->d_varDatabases[d_variable])->d_constraints;
 }
 
-bool ConstraintValue::proofIsEmpty() const{
+bool Constraint_::proofIsEmpty() const{
   Assert(hasProof());
   bool result = d_database->d_proofs[d_proof] == NullConstraint;
   //Assert((!result) || isSelfExplaining() || hasEqualityEngineProof() || isPseudoConstraint());
@@ -922,32 +1036,76 @@ bool ConstraintValue::proofIsEmpty() const{
   return result;
 }
 
-Node ConstraintValue::makeImplication(const std::vector<Constraint>& b) const{
-  Node antecedent = makeConjunction(b);
+Node Constraint_::externalImplication(const ConstraintCPVec& b) const{
+  Assert(hasLiteral());
+  Node antecedent = externalExplainByAssertions(b);
   Node implied = getLiteral();
   return antecedent.impNode(implied);
 }
 
 
-Node ConstraintValue::makeConjunction(const std::vector<Constraint>& b){
-  NodeBuilder<> nb(kind::AND);
-  for(vector<Constraint>::const_iterator i = b.begin(), end = b.end(); i != end; ++i){
-    Constraint b_i = *i;
-    b_i->explainBefore(nb, AssertionOrderSentinel);
+Node Constraint_::externalExplainByAssertions(const ConstraintCPVec& b){
+  return externalExplain(b, AssertionOrderSentinel);
+}
+
+struct ConstraintCPHash {
+  /* Todo replace with an id */
+  size_t operator()(ConstraintCP c) const{
+    Assert(sizeof(ConstraintCP) > 0);
+    return ((size_t)c)/sizeof(ConstraintCP);
   }
-  if(nb.getNumChildren() >= 2){
-    return nb;
-  }else if(nb.getNumChildren() == 1){
-    return nb[0];
-  }else{
-    return mkBoolNode(true);
+};
+
+void Constraint_::assertionFringe(ConstraintCPVec& v){
+  hash_set<ConstraintCP, ConstraintCPHash> visited;
+  size_t writePos = 0;
+
+  if(!v.empty()){
+    const ConstraintDatabase* db = v.back()->d_database;
+    const CDConstraintList& proofs = db->d_proofs;
+    for(size_t i = 0; i < v.size(); ++i){
+      ConstraintCP vi = v[i];
+      if(visited.find(vi) == visited.end()){
+        Assert(vi->hasProof());
+        visited.insert(vi);
+        if(vi->onFringe()){
+          v[writePos] = vi;
+          writePos++;
+        }else{
+          Assert(!vi->isSelfExplaining());
+          ProofId p = vi->d_proof;
+          ConstraintCP antecedent = proofs[p];
+          while(antecedent != NullConstraint){
+            v.push_back(antecedent);
+            --p;
+            antecedent = proofs[p];
+          }
+        }
+      }
+    }
+    v.resize(writePos);
+  }
+}
+
+void Constraint_::assertionFringe(ConstraintCPVec& o, const ConstraintCPVec& i){
+  o.insert(o.end(), i.begin(), i.end());
+  assertionFringe(o);
+}
+
+Node Constraint_::externalExplain(const ConstraintCPVec& v, AssertionOrder order){
+  NodeBuilder<> nb(kind::AND);
+  ConstraintCPVec::const_iterator i, end;
+  for(i = v.begin(), end = v.end(); i != end; ++i){
+    ConstraintCP v_i = *i;
+    v_i->externalExplain(nb, order);
   }
+  return safeConstructNary(nb);
 }
 
-void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) const{
+void Constraint_::externalExplain(NodeBuilder<>& nb, AssertionOrder order) const{
   Assert(hasProof());
   Assert(!isSelfExplaining() || assertedToTheTheory());
-
+  Assert(!isInternalDecision());
 
   if(assertedBefore(order)){
     nb << getWitness();
@@ -956,56 +1114,61 @@ void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) con
   }else{
     Assert(!isSelfExplaining());
     ProofId p = d_proof;
-    Constraint antecedent = d_database->d_proofs[p];
+    ConstraintCP antecedent = d_database->d_proofs[p];
 
     for(; antecedent != NullConstraint; antecedent = d_database->d_proofs[--p] ){
-      antecedent->explainBefore(nb, order);
+      antecedent->externalExplain(nb, order);
     }
   }
 }
-Node ConstraintValue::explainBefore(AssertionOrder order) const{
+
+Node Constraint_::externalExplain(AssertionOrder order) const{
   Assert(hasProof());
   Assert(!isSelfExplaining() || assertedBefore(order));
+  Assert(!isInternalDecision());
   if(assertedBefore(order)){
     return getWitness();
   }else if(hasEqualityEngineProof()){
     return d_database->eeExplain(this);
   }else{
     Assert(!proofIsEmpty());
-    //Force the selection of the layer above if the node is assertedToTheTheory()!
+    //Force the selection of the layer above if the node is
+    // assertedToTheTheory()!
     if(d_database->d_proofs[d_proof-1] == NullConstraint){
-      Constraint antecedent = d_database->d_proofs[d_proof];
-      return antecedent->explainBefore(order);
+      ConstraintCP antecedent = d_database->d_proofs[d_proof];
+      return antecedent->externalExplain(order);
     }else{
       NodeBuilder<> nb(kind::AND);
       Assert(!isSelfExplaining());
 
       ProofId p = d_proof;
-      Constraint antecedent = d_database->d_proofs[p];
-      for(; antecedent != NullConstraint; antecedent = d_database->d_proofs[--p] ){
-        antecedent->explainBefore(nb, order);
+      ConstraintCP antecedent = d_database->d_proofs[p];
+      while(antecedent != NullConstraint){
+        antecedent->externalExplain(nb, order);
+        --p;
+        antecedent = d_database->d_proofs[p];
       }
       return nb;
     }
   }
 }
 
-Node ConstraintValue::explainConflict(Constraint a, Constraint b){
+Node Constraint_::externalExplainByAssertions(ConstraintCP a, ConstraintCP b){
   NodeBuilder<> nb(kind::AND);
-  a->explainForConflict(nb);
-  b->explainForConflict(nb);
+  a->externalExplainByAssertions(nb);
+  b->externalExplainByAssertions(nb);
   return nb;
 }
 
-Node ConstraintValue::explainConflict(Constraint a, Constraint b, Constraint c){
+Node Constraint_::externalExplainByAssertions(ConstraintCP a, ConstraintCP b, ConstraintCP c){
   NodeBuilder<> nb(kind::AND);
-  a->explainForConflict(nb);
-  b->explainForConflict(nb);
-  c->explainForConflict(nb);
+  a->externalExplainByAssertions(nb);
+  b->externalExplainByAssertions(nb);
+  c->externalExplainByAssertions(nb);
   return nb;
 }
 
-Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
+ConstraintP Constraint_::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
   Assert(initialized());
   Assert(!asserted || hasLiteral);
 
@@ -1016,7 +1179,7 @@ Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool as
     --i;
     const ValueCollection& vc = i->second;
     if(vc.hasLowerBound()){
-      Constraint weaker = vc.getLowerBound();
+      ConstraintP weaker = vc.getLowerBound();
 
       // asserted -> hasLiteral
       // hasLiteral -> weaker->hasLiteral()
@@ -1030,7 +1193,7 @@ Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool as
   return NullConstraint;
 }
 
-Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
+ConstraintP Constraint_::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
   SortedConstraintMapConstIterator i = d_variablePosition;
   const SortedConstraintMap& scm = constraintSet();
   SortedConstraintMapConstIterator i_end = scm.end();
@@ -1039,7 +1202,7 @@ Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool as
   for(; i != i_end; ++i){
     const ValueCollection& vc = i->second;
     if(vc.hasUpperBound()){
-      Constraint weaker = vc.getUpperBound();
+      ConstraintP weaker = vc.getUpperBound();
       if((!hasLiteral || (weaker->hasLiteral())) &&
          (!asserted || ( weaker->assertedToTheTheory()))){
         return weaker;
@@ -1050,7 +1213,7 @@ Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool as
   return NullConstraint;
 }
 
-Constraint ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
+ConstraintP ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
   Assert(variableDatabaseIsSetup(v));
   Assert(t == UpperBound ||  t == LowerBound);
 
@@ -1110,12 +1273,12 @@ Constraint ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t,
     }
   }
 }
-Node ConstraintDatabase::eeExplain(const ConstraintValue* const c) const{
+Node ConstraintDatabase::eeExplain(const Constraint_* const c) const{
   Assert(c->hasLiteral());
   return d_congruenceManager.explain(c->getLiteral());
 }
 
-void ConstraintDatabase::eeExplain(const ConstraintValue* const c, NodeBuilder<>& nb) const{
+void ConstraintDatabase::eeExplain(const Constraint_* const c, NodeBuilder<>& nb) const{
   Assert(c->hasLiteral());
   d_congruenceManager.explain(c->getLiteral(), nb);
 }
@@ -1133,7 +1296,7 @@ ConstraintDatabase::Watches::Watches(context::Context* satContext, context::Cont
 {}
 
 
-void ConstraintValue::setLiteral(Node n) {
+void Constraint_::setLiteral(Node n) {
   Assert(!hasLiteral());
   Assert(sanityChecking(n));
   d_literal = n;
@@ -1142,7 +1305,7 @@ void ConstraintValue::setLiteral(Node n) {
   map.insert(make_pair(d_literal, this));
 }
 
-void implies(std::vector<Node>& out, Constraint a, Constraint b){
+void implies(std::vector<Node>& out, ConstraintP a, ConstraintP b){
   Node la = a->getLiteral();
   Node lb = b->getLiteral();
 
@@ -1153,7 +1316,7 @@ void implies(std::vector<Node>& out, Constraint a, Constraint b){
   out.push_back(orderOr);
 }
 
-void mutuallyExclusive(std::vector<Node>& out, Constraint a, Constraint b){
+void mutuallyExclusive(std::vector<Node>& out, ConstraintP a, ConstraintP b){
   Node la = a->getLiteral();
   Node lb = b->getLiteral();
 
@@ -1169,13 +1332,13 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, Ari
   SortedConstraintMap& scm = getVariableSCM(v);
   SortedConstraintMapConstIterator scm_iter = scm.begin();
   SortedConstraintMapConstIterator scm_end = scm.end();
-  Constraint prev = NullConstraint;
+  ConstraintP prev = NullConstraint;
   //get transitive unates
   //Only lower bounds or upperbounds should be done.
   for(; scm_iter != scm_end; ++scm_iter){
     const ValueCollection& vc = scm_iter->second;
     if(vc.hasUpperBound()){
-      Constraint ub = vc.getUpperBound();
+      ConstraintP ub = vc.getUpperBound();
       if(ub->hasLiteral()){
         if(prev != NullConstraint){
           implies(out, prev, ub);
@@ -1188,7 +1351,7 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, Ari
 
 void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, ArithVar v) const{
 
-  vector<Constraint> equalities;
+  vector<ConstraintP> equalities;
 
   SortedConstraintMap& scm = getVariableSCM(v);
   SortedConstraintMapConstIterator scm_iter = scm.begin();
@@ -1197,34 +1360,34 @@ void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, Arith
   for(; scm_iter != scm_end; ++scm_iter){
     const ValueCollection& vc = scm_iter->second;
     if(vc.hasEquality()){
-      Constraint eq = vc.getEquality();
+      ConstraintP eq = vc.getEquality();
       if(eq->hasLiteral()){
         equalities.push_back(eq);
       }
     }
   }
 
-  vector<Constraint>::const_iterator i, j, eq_end = equalities.end();
+  vector<ConstraintP>::const_iterator i, j, eq_end = equalities.end();
   for(i = equalities.begin(); i != eq_end; ++i){
-    Constraint at_i = *i;
+    ConstraintP at_i = *i;
     for(j= i + 1; j != eq_end; ++j){
-      Constraint at_j = *j;
+      ConstraintP at_j = *j;
 
       mutuallyExclusive(out, at_i, at_j);
     }
   }
 
   for(i = equalities.begin(); i != eq_end; ++i){
-    Constraint eq = *i;
+    ConstraintP eq = *i;
     const ValueCollection& vc = eq->getValueCollection();
     Assert(vc.hasEquality() && vc.getEquality()->hasLiteral());
 
     bool hasLB = vc.hasLowerBound() && vc.getLowerBound()->hasLiteral();
     bool hasUB = vc.hasUpperBound() && vc.getUpperBound()->hasLiteral();
 
-    Constraint lb = hasLB ?
+    ConstraintP lb = hasLB ?
       vc.getLowerBound() : eq->getStrictlyWeakerLowerBound(true, false);
-    Constraint ub = hasUB ?
+    ConstraintP ub = hasUB ?
       vc.getUpperBound() : eq->getStrictlyWeakerUpperBound(true, false);
 
     if(hasUB && hasLB && !eq->isSplit()){
@@ -1251,21 +1414,20 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& lemmas)
   }
 }
 
-void ConstraintDatabase::raiseUnateConflict(Constraint ant, Constraint cons){
+void ConstraintDatabase::raiseUnateConflict(ConstraintP ant, ConstraintP cons){
   Assert(ant->hasProof());
-  Constraint negCons = cons->getNegation();
+  ConstraintP negCons = cons->getNegation();
   Assert(negCons->hasProof());
 
   Debug("arith::unate::conf") << ant << "implies " << cons << endl;
   Debug("arith::unate::conf") << negCons << " is true." << endl;
 
-
-  Node conf = ConstraintValue::explainConflict(ant, negCons);
-  Debug("arith::unate::conf") << conf << std::endl;
-  d_raiseConflict(conf);
+  d_raiseConflict.addConstraint(ant);
+  d_raiseConflict.addConstraint(negCons);
+  d_raiseConflict.commitConflict();
 }
 
-void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
+void ConstraintDatabase::unatePropLowerBound(ConstraintP curr, ConstraintP prev){
   Debug("arith::unate") << "unatePropLowerBound " << curr << " " << prev << endl;
   Assert(curr != prev);
   Assert(curr != NullConstraint);
@@ -1297,7 +1459,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
     //Don't worry about implying the negation of upperbound.
     //These should all be handled by propagating the LowerBounds!
     if(vc.hasLowerBound()){
-      Constraint lb = vc.getLowerBound();
+      ConstraintP lb = vc.getLowerBound();
       if(lb->negationHasProof()){
         raiseUnateConflict(curr, lb);
         return;
@@ -1309,7 +1471,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
       }
     }
     if(vc.hasDisequality()){
-      Constraint dis = vc.getDisequality();
+      ConstraintP dis = vc.getDisequality();
       if(dis->negationHasProof()){
         raiseUnateConflict(curr, dis);
         return;
@@ -1323,7 +1485,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
   }
 }
 
-void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
+void ConstraintDatabase::unatePropUpperBound(ConstraintP curr, ConstraintP prev){
   Debug("arith::unate") << "unatePropUpperBound " << curr << " " << prev << endl;
   Assert(curr != prev);
   Assert(curr != NullConstraint);
@@ -1348,7 +1510,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
     //Don't worry about implying the negation of upperbound.
     //These should all be handled by propagating the UpperBounds!
     if(vc.hasUpperBound()){
-      Constraint ub = vc.getUpperBound();
+      ConstraintP ub = vc.getUpperBound();
       if(ub->negationHasProof()){
         raiseUnateConflict(curr, ub);
         return;
@@ -1359,7 +1521,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
       }
     }
     if(vc.hasDisequality()){
-      Constraint dis = vc.getDisequality();
+      ConstraintP dis = vc.getDisequality();
       if(dis->negationHasProof()){
         raiseUnateConflict(curr, dis);
         return;
@@ -1373,7 +1535,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
   }
 }
 
-void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, Constraint prevUB){
+void ConstraintDatabase::unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB){
   Debug("arith::unate") << "unatePropEquality " << curr << " " << prevLB << " " << prevUB << endl;
   Assert(curr != prevLB);
   Assert(curr != prevUB);
@@ -1405,7 +1567,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
     //Don't worry about implying the negation of upperbound.
     //These should all be handled by propagating the LowerBounds!
     if(vc.hasLowerBound()){
-      Constraint lb = vc.getLowerBound();
+      ConstraintP lb = vc.getLowerBound();
       if(lb->negationHasProof()){
         raiseUnateConflict(curr, lb);
         return;
@@ -1416,7 +1578,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
       }
     }
     if(vc.hasDisequality()){
-      Constraint dis = vc.getDisequality();
+      ConstraintP dis = vc.getDisequality();
       if(dis->negationHasProof()){
         raiseUnateConflict(curr, dis);
         return;
@@ -1440,7 +1602,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
     //Don't worry about implying the negation of upperbound.
     //These should all be handled by propagating the UpperBounds!
     if(vc.hasUpperBound()){
-      Constraint ub = vc.getUpperBound();
+      ConstraintP ub = vc.getUpperBound();
       if(ub->negationHasProof()){
         raiseUnateConflict(curr, ub);
         return;
@@ -1452,7 +1614,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
       }
     }
     if(vc.hasDisequality()){
-      Constraint dis = vc.getDisequality();
+      ConstraintP dis = vc.getDisequality();
       if(dis->negationHasProof()){
         raiseUnateConflict(curr, dis);
         return;
index 4966115d2f9bd13a82b64ba74b07ba34e16ae64b..18e53660f757abb640c4701044d5f22ca99612c3 100644 (file)
@@ -94,9 +94,9 @@ namespace arith {
 enum ConstraintType {LowerBound, Equality, UpperBound, Disequality};
 
 
-typedef context::CDList<Constraint> CDConstraintList;
+typedef context::CDList<ConstraintCP> CDConstraintList;
 
-typedef __gnu_cxx::hash_map<Node, Constraint, NodeHashFunction> NodetoConstraintMap;
+typedef __gnu_cxx::hash_map<Node, ConstraintP, NodeHashFunction> NodetoConstraintMap;
 
 typedef size_t ProofId;
 static ProofId ProofIdSentinel = std::numeric_limits<ProofId>::max();
@@ -111,54 +111,29 @@ static AssertionOrder AssertionOrderSentinel = std::numeric_limits<AssertionOrde
 class ValueCollection {
 private:
 
-  Constraint d_lowerBound;
-  Constraint d_upperBound;
-  Constraint d_equality;
-  Constraint d_disequality;
+  ConstraintP d_lowerBound;
+  ConstraintP d_upperBound;
+  ConstraintP d_equality;
+  ConstraintP d_disequality;
 
 public:
-  ValueCollection()
-    : d_lowerBound(NullConstraint),
-      d_upperBound(NullConstraint),
-      d_equality(NullConstraint),
-      d_disequality(NullConstraint)
-  {}
+  ValueCollection();
 
-  static ValueCollection mkFromConstraint(Constraint c);
+  static ValueCollection mkFromConstraint(ConstraintP c);
 
-  bool hasLowerBound() const{
-    return d_lowerBound != NullConstraint;
-  }
-  bool hasUpperBound() const{
-    return d_upperBound != NullConstraint;
-  }
-  bool hasEquality() const{
-    return d_equality != NullConstraint;
-  }
-  bool hasDisequality() const {
-    return d_disequality != NullConstraint;
-  }
+  bool hasLowerBound() const;
+  bool hasUpperBound() const;
+  bool hasEquality() const;
+  bool hasDisequality() const;
 
   bool hasConstraintOfType(ConstraintType t) const;
 
-  Constraint getLowerBound() const {
-    Assert(hasLowerBound());
-    return d_lowerBound;
-  }
-  Constraint getUpperBound() const {
-    Assert(hasUpperBound());
-    return d_upperBound;
-  }
-  Constraint getEquality() const {
-    Assert(hasEquality());
-    return d_equality;
-  }
-  Constraint getDisequality() const {
-    Assert(hasDisequality());
-    return d_disequality;
-  }
+  ConstraintP getLowerBound() const;
+  ConstraintP getUpperBound() const;
+  ConstraintP getEquality() const;
+  ConstraintP getDisequality() const;
 
-  Constraint getConstraintOfType(ConstraintType t) const;
+  ConstraintP getConstraintOfType(ConstraintType t) const;
 
   /** Returns true if any of the constraints are non-null. */
   bool empty() const;
@@ -174,11 +149,11 @@ public:
    * Adds a constraint to the set.
    * The collection must not have a constraint of that type already.
    */
-  void add(Constraint c);
+  void add(ConstraintP c);
 
-  void push_into(std::vector<Constraint>& vec) const;
+  void push_into(std::vector<ConstraintP>& vec) const;
 
-  Constraint nonNull() const;
+  ConstraintP nonNull() const;
 
   ArithVar getVariable() const;
   const DeltaRational& getValue() const;
@@ -220,7 +195,7 @@ struct PerVariableDatabase{
   }
 };
 
-class ConstraintValue {
+class Constraint_ {
 private:
   /** The ArithVar associated with the constraint. */
   const ArithVar d_variable;
@@ -246,7 +221,7 @@ private:
   Node d_literal;
 
   /** Pointer to the negation of the Constraint. */
-  Constraint d_negation;
+  ConstraintP d_negation;
 
   /**
    * This is true if the associated node can be propagated.
@@ -269,10 +244,11 @@ private:
    * Sat Context Dependent.
    * This is initially AssertionOrderSentinel.
    */
-  AssertionOrder _d_assertionOrder;
+  AssertionOrder d_assertionOrder;
+
   /**
    * This is guaranteed to be on the fact queue.
-   * For example if x + y = x + 1 is on the fact queue, then use this 
+   * For example if x + y = x + 1 is on the fact queue, then use this
    */
   TNode d_witness;
 
@@ -309,13 +285,13 @@ private:
    * Because of circular dependencies a Constraint is not fully valid until
    * initialize has been called on it.
    */
-  ConstraintValue(ArithVar x,  ConstraintType t, const DeltaRational& v);
+  Constraint_(ArithVar x,  ConstraintType t, const DeltaRational& v);
 
   /**
    * Destructor for a constraint.
    * This should only be called if safeToGarbageCollect() is true.
    */
-  ~ConstraintValue();
+  ~Constraint_();
 
   bool initialized() const;
 
@@ -323,12 +299,12 @@ private:
    * This initializes the fields that cannot be set in the constructor due to
    * circular dependencies.
    */
-  void initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, Constraint negation);
+  void initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation);
 
   class ProofCleanup {
   public:
-    inline void operator()(Constraint* p){
-      Constraint constraint = *p;
+    inline void operator()(ConstraintP* p){
+      ConstraintP constraint = *p;
       Assert(constraint->d_proof != ProofIdSentinel);
       constraint->d_proof = ProofIdSentinel;
     }
@@ -336,8 +312,8 @@ private:
 
   class CanBePropagatedCleanup {
   public:
-    inline void operator()(Constraint* p){
-      Constraint constraint = *p;
+    inline void operator()(ConstraintP* p){
+      ConstraintP constraint = *p;
       Assert(constraint->d_canBePropagated);
       constraint->d_canBePropagated = false;
     }
@@ -345,10 +321,10 @@ private:
 
   class AssertionOrderCleanup {
   public:
-    inline void operator()(Constraint* p){
-      Constraint constraint = *p;
+    inline void operator()(ConstraintP* p){
+      ConstraintP constraint = *p;
       Assert(constraint->assertedToTheTheory());
-      constraint->_d_assertionOrder = AssertionOrderSentinel;
+      constraint->d_assertionOrder = AssertionOrderSentinel;
       constraint->d_witness = TNode::null();
       Assert(!constraint->assertedToTheTheory());
     }
@@ -356,8 +332,8 @@ private:
 
   class SplitCleanup {
   public:
-    inline void operator()(Constraint* p){
-      Constraint constraint = *p;
+    inline void operator()(ConstraintP* p){
+      ConstraintP constraint = *p;
       Assert(constraint->d_split);
       constraint->d_split = false;
     }
@@ -389,7 +365,7 @@ public:
     return d_value;
   }
 
-  Constraint getNegation() const {
+  ConstraintP getNegation() const {
     return d_negation;
   }
 
@@ -421,7 +397,7 @@ public:
 
   /**
    * Splits the node in the user context.
-   * Returns a lemma that is assumed to be true fro the rest of the user context.
+   * Returns a lemma that is assumed to be true for the rest of the user context.
    * Constraint must be an equality or disequality.
    */
   Node split();
@@ -441,8 +417,8 @@ public:
   }
 
   bool assertedToTheTheory() const {
-    Assert((_d_assertionOrder < AssertionOrderSentinel) != d_witness.isNull());
-    return _d_assertionOrder < AssertionOrderSentinel;
+    Assert((d_assertionOrder < AssertionOrderSentinel) != d_witness.isNull());
+    return d_assertionOrder < AssertionOrderSentinel;
   }
   TNode getWitness() const {
     Assert(assertedToTheTheory());
@@ -450,12 +426,17 @@ public:
   }
 
   bool assertedBefore(AssertionOrder time) const {
-    return _d_assertionOrder < time;
+    return d_assertionOrder < time;
   }
 
-
+  /** Sets the witness literal for a node being on the assertion stack.
+   * The negation of the node cannot be true. */
   void setAssertedToTheTheory(TNode witness);
 
+  /** Sets the witness literal for a node being on the assertion stack.
+   * The negation of the node must be true!
+   * This is for conflict generation specificially! */
+  void setAssertedToTheTheoryWithNegationTrue(TNode witness);
 
   bool hasLiteral() const {
     return !d_literal.isNull();
@@ -474,6 +455,8 @@ public:
    */
   void selfExplaining();
 
+  void selfExplainingWithNegationTrue();
+
   /** Returns true if the node is selfExplaining.*/
   bool isSelfExplaining() const;
 
@@ -485,12 +468,17 @@ public:
 
 
   /**
-   * There cannot be a literal associated with this constraint.
-   * The explanation is the constant true.
-   * explainInto() does nothing.
+   * A sets the constraint to be an internal decision.
+   *
+   * This does not need to have a witness or an associated literal.
+   * This is always itself in the explanation fringe for both conflicts
+   * and propagation.
+   * This cannot be converted back into a Node conflict or explanation.
+   *
+   * This cannot have a proof or be asserted to the theory!
    */
-  //void setPseudoConstraint();
-  //bool isPseudoConstraint() const;
+  void setInternalDecision();
+  bool isInternalDecision() const;
 
   /**
    * Returns a explanation of the constraint that is appropriate for conflicts.
@@ -500,8 +488,8 @@ public:
    * This is the minimum fringe of the implication tree s.t.
    * every constraint is assertedToTheTheory() or hasEqualityEngineProof().
    */
-  Node explainForConflict() const{
-    return explainBefore(AssertionOrderSentinel);
+  Node externalExplainByAssertions() const {
+    return externalExplain(AssertionOrderSentinel);
   }
 
   /**
@@ -515,13 +503,38 @@ public:
    * This is not appropriate for propagation!
    * Use explainForPropagation() instead.
    */
-  void explainForConflict(NodeBuilder<>& nb) const{
-    explainBefore(nb, AssertionOrderSentinel);
+  void externalExplainByAssertions(NodeBuilder<>& nb) const{
+    externalExplain(nb, AssertionOrderSentinel);
   }
 
+  /* Equivalent to calling externalExplainByAssertions on all constraints in b */
+  static Node externalExplainByAssertions(const ConstraintCPVec& b);
+  /* utilities for calling externalExplainByAssertions on 2 constraints */
+  static Node externalExplainByAssertions(ConstraintCP a, ConstraintCP b);
+  static Node externalExplainByAssertions(ConstraintCP a, ConstraintCP b, ConstraintCP c);
+  //static Node externalExplainByAssertions(ConstraintCP a);
+
+  /**
+   * This is the minimum fringe of the implication tree s.t. every constraint is
+   * - assertedToTheTheory(),
+   * - isInternalDecision() or
+   * - hasEqualityEngineProof().
+   */
+  static void assertionFringe(ConstraintCPVec& v);
+  static void assertionFringe(ConstraintCPVec& out, const ConstraintCPVec& in);
+
   /** Utility function built from explainForConflict. */
-  static Node explainConflict(Constraint a, Constraint b);
-  static Node explainConflict(Constraint a, Constraint b, Constraint c);
+  //static Node explainConflict(ConstraintP a, ConstraintP b);
+  //static Node explainConflict(ConstraintP a, ConstraintP b, Constraint c);
+
+  //static Node explainConflictForEE(ConstraintCP a, ConstraintCP b);
+  //static Node explainConflictForEE(ConstraintCP a);
+  //static Node explainConflictForDio(ConstraintCP a);
+  //static Node explainConflictForDio(ConstraintCP a, ConstraintCP b);
+
+  bool onFringe() const {
+    return assertedToTheTheory() || isInternalDecision() || hasEqualityEngineProof();
+  }
 
   /**
    * Returns an explanation of a propagation by the ConstraintDatabase.
@@ -531,14 +544,20 @@ public:
    * This is the minimum fringe of the implication tree (excluding the constraint itself)
    * s.t. every constraint is assertedToTheTheory() or hasEqualityEngineProof().
    */
-  Node explainForPropagation() const {
+  Node externalExplainForPropagation() const {
     Assert(hasProof());
     Assert(!isSelfExplaining());
-    return explainBefore(_d_assertionOrder);
+    return externalExplain(d_assertionOrder);
   }
 
+  // void externalExplainForPropagation(NodeBuilder<>& nb) const{
+  //   Assert(hasProof());
+  //   Assert(!isSelfExplaining());
+  //   externalExplain(nb, d_assertionOrder);
+  // }
+
 private:
-  Node explainBefore(AssertionOrder order) const;
+  Node externalExplain(AssertionOrder order) const;
 
   /**
    * Returns an explanation of that was assertedBefore(order).
@@ -548,7 +567,9 @@ private:
    * This is the minimum fringe of the implication tree
    * s.t. every constraint is assertedBefore(order) or hasEqualityEngineProof().
    */
-  void explainBefore(NodeBuilder<>& nb, AssertionOrder order) const;
+  void externalExplain(NodeBuilder<>& nb, AssertionOrder order) const;
+
+  static Node externalExplain(const ConstraintCPVec& b, AssertionOrder order);
 
 public:
   bool hasProof() const {
@@ -558,26 +579,38 @@ public:
     return d_negation->hasProof();
   }
 
+  /* Neither the contraint has a proof nor the negation has a proof.*/
   bool truthIsUnknown() const {
     return !hasProof() && !negationHasProof();
   }
 
+  /* This is a synonym for hasProof(). */
   bool isTrue() const {
     return hasProof();
   }
 
-  Constraint getCeiling();
+  /**
+   * Returns the constraint that corresponds to taking
+   *    x r ceiling(getValue()) where r is the node's getType().
+   * Esstentially this is an up branch.
+   */
+  ConstraintP getCeiling();
 
-  Constraint getFloor();
+  /**
+   * Returns the constraint that corresponds to taking
+   *    x r floor(getValue()) where r is the node's getType().
+   * Esstentially this is a down branch.
+   */
+  ConstraintP getFloor();
 
 
-  static Constraint makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r);
+  static ConstraintP makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r);
 
   const ValueCollection& getValueCollection() const;
 
 
-  Constraint getStrictlyWeakerUpperBound(bool hasLiteral, bool mustBeAsserted) const;
-  Constraint getStrictlyWeakerLowerBound(bool hasLiteral, bool mustBeAsserted) const;
+  ConstraintP getStrictlyWeakerUpperBound(bool hasLiteral, bool mustBeAsserted) const;
+  ConstraintP getStrictlyWeakerLowerBound(bool hasLiteral, bool mustBeAsserted) const;
 
   /**
    * Marks the node as having a proof a.
@@ -587,19 +620,23 @@ public:
    * canBePropagated()
    * !assertedToTheTheory()
    */
-  void propagate(Constraint a);
-  void propagate(Constraint a, Constraint b);
-  void propagate(const std::vector<Constraint>& b);
+  void propagate(ConstraintCP a);
+  void propagate(ConstraintCP a, ConstraintCP b);
+  //void propagate(const std::vector<Constraint>& b);
+  void propagate(const ConstraintCPVec& b);
+
   /**
    * The only restriction is that this is not known be true.
    * This propagates if there is a node.
    */
-  void impliedBy(Constraint a);
-  void impliedBy(Constraint a, Constraint b);
-  void impliedBy(const std::vector<Constraint>& b);
+  void impliedBy(ConstraintCP a);
+  void impliedBy(ConstraintCP a, ConstraintCP b);
+  //void impliedBy(const std::vector<Constraint>& b);
+  void impliedBy(const ConstraintCPVec& b);
 
-  Node makeImplication(const std::vector<Constraint>& b) const;
-  static Node makeConjunction(const std::vector<Constraint>& b);
+  Node externalImplication(const ConstraintCPVec& b) const;
+  static Node externalConjunction(const ConstraintCPVec& b);
+  //static Node makeConflictNode(const ConstraintCPVec& b);
 
   /** The node must have a proof already and be eligible for propagation! */
   void propagate();
@@ -617,10 +654,11 @@ private:
    * Marks the node as having a proof a.
    * This is safe if the node does not have
    */
-  void markAsTrue(Constraint a);
+  void markAsTrue(ConstraintCP a);
 
-  void markAsTrue(Constraint a, Constraint b);
-  void markAsTrue(const std::vector<Constraint>& b);
+  void markAsTrue(ConstraintCP a, ConstraintCP b);
+  //void markAsTrue(const std::vector<Constraint>& b);
+  void markAsTrue(const ConstraintCPVec& b);
 
   void debugPrint() const;
 
@@ -634,11 +672,11 @@ private:
 
 }; /* class ConstraintValue */
 
-std::ostream& operator<<(std::ostream& o, const ConstraintValue& c);
-std::ostream& operator<<(std::ostream& o, const Constraint c);
+std::ostream& operator<<(std::ostream& o, const Constraint_& c);
+std::ostream& operator<<(std::ostream& o, const ConstraintP c);
 std::ostream& operator<<(std::ostream& o, const ConstraintType t);
 std::ostream& operator<<(std::ostream& o, const ValueCollection& c);
-
+std::ostream& operator<<(std::ostream& o, const ConstraintCPVec& v);
 
 
 class ConstraintDatabase {
@@ -650,20 +688,17 @@ private:
    */
   std::vector<PerVariableDatabase*> d_varDatabases;
 
-  SortedConstraintMap& getVariableSCM(ArithVar v) const{
-    Assert(variableDatabaseIsSetup(v));
-    return d_varDatabases[v]->d_constraints;
-  }
+  SortedConstraintMap& getVariableSCM(ArithVar v) const;
 
   /** Maps literals to constraints.*/
   NodetoConstraintMap d_nodetoConstraintMap;
 
   /**
    * A queue of propagated constraints.
-   *
-   * As Constraint are pointers, the elements of the queue do not require destruction.
+   * ConstraintCP are pointers.
+   * The elements of the queue do not require destruction.
    */
-  context::CDQueue<Constraint> d_toPropagate;
+  context::CDQueue<ConstraintCP> d_toPropagate;
 
   /**
    * Proof Lists.
@@ -701,17 +736,16 @@ private:
   ProofId d_equalityEngineProof;
 
   /**
-   * Marks a node as being true always.
-   * This is only okay for purely internal things.
-   *
-   * This is a special proof that is always a member of the list.
+   * Marks a constraint as being proved by making an internal
+   * decision. Such nodes cannot be used in external explanations
+   * but can be used internally.
    */
-  //ProofId d_pseudoConstraintProof;
+  ProofId d_internalDecisionProof;
 
-  typedef context::CDList<Constraint, ConstraintValue::ProofCleanup> ProofCleanupList;
-  typedef context::CDList<Constraint, ConstraintValue::CanBePropagatedCleanup> CBPList;
-  typedef context::CDList<Constraint, ConstraintValue::AssertionOrderCleanup> AOList;
-  typedef context::CDList<Constraint, ConstraintValue::SplitCleanup> SplitList;
+  typedef context::CDList<ConstraintP, Constraint_::ProofCleanup> ProofCleanupList;
+  typedef context::CDList<ConstraintP, Constraint_::CanBePropagatedCleanup> CBPList;
+  typedef context::CDList<ConstraintP, Constraint_::AssertionOrderCleanup> AOList;
+  typedef context::CDList<ConstraintP, Constraint_::SplitCleanup> SplitList;
 
   /**
    * The watch lists are collected together as they need to be garbage collected
@@ -744,30 +778,10 @@ private:
   };
   Watches* d_watches;
 
-  void pushSplitWatch(Constraint c){
-    Assert(!c->d_split);
-    c->d_split = true;
-    d_watches->d_splitWatches.push_back(c);
-  }
-
-  void pushCanBePropagatedWatch(Constraint c){
-    Assert(!c->d_canBePropagated);
-    c->d_canBePropagated = true;
-    d_watches->d_canBePropagatedWatches.push_back(c);
-  }
-
-  void pushAssertionOrderWatch(Constraint c, TNode witness){
-    Assert(!c->assertedToTheTheory());
-    c->_d_assertionOrder = d_watches->d_assertionOrderWatches.size();
-    c->d_witness = witness;
-    d_watches->d_assertionOrderWatches.push_back(c);
-  }
-
-  void pushProofWatch(Constraint c, ProofId pid){
-    Assert(c->d_proof == ProofIdSentinel);
-    c->d_proof = pid;
-    d_watches->d_proofWatches.push_back(c);
-  }
+  void pushSplitWatch(ConstraintP c);
+  void pushCanBePropagatedWatch(ConstraintP c);
+  void pushAssertionOrderWatch(ConstraintP c, TNode witness);
+  void pushProofWatch(ConstraintP c, ProofId pid);
 
   /** Returns true if all of the entries of the vector are empty. */
   static bool emptyDatabase(const std::vector<PerVariableDatabase>& vec);
@@ -786,7 +800,7 @@ private:
 
   RaiseConflict d_raiseConflict;
 
-  friend class ConstraintValue;
+  friend class Constraint_;
 
 public:
 
@@ -799,13 +813,13 @@ public:
   ~ConstraintDatabase();
 
   /** Adds a literal to the database. */
-  Constraint addLiteral(TNode lit);
+  ConstraintP addLiteral(TNode lit);
 
   /**
    * If hasLiteral() is true, returns the constraint.
    * Otherwise, returns NullConstraint.
    */
-  Constraint lookup(TNode literal) const;
+  ConstraintP lookup(TNode literal) const;
 
   /**
    * Returns true if the literal has been added to the database.
@@ -818,10 +832,10 @@ public:
     return !d_toPropagate.empty();
   }
 
-  Constraint nextPropagation(){
+  ConstraintCP nextPropagation(){
     Assert(hasMorePropagations());
 
-    Constraint p = d_toPropagate.front();
+    ConstraintCP p = d_toPropagate.front();
     d_toPropagate.pop();
 
     return p;
@@ -831,8 +845,8 @@ public:
   bool variableDatabaseIsSetup(ArithVar v) const;
   void removeVariable(ArithVar v);
 
-  Node eeExplain(ConstConstraint c) const;
-  void eeExplain(ConstConstraint c, NodeBuilder<>& nb) const;
+  Node eeExplain(ConstraintCP c) const;
+  void eeExplain(ConstraintCP c, NodeBuilder<>& nb) const;
 
   /**
    * Returns a constraint with the variable v, the constraint type t, and a value
@@ -843,8 +857,13 @@ public:
    * The returned value v is dominated:
    *  If t is UpperBound, r <= v
    *  If t is LowerBound, r >= v
+   *
+   * variableDatabaseIsSetup(v) must be true.
    */
-  Constraint getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const;
+  ConstraintP getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const;
+
+  /** Returns the constraint, if it exists */
+  ConstraintP lookupConstraint(ArithVar v, ConstraintType t, const DeltaRational& r) const;
 
   /**
    * Returns a constraint with the variable v, the constraint type t and the value r.
@@ -852,22 +871,18 @@ public:
    * If there is no such constraint, this constraint is added to the database.
    *
    */
-  Constraint getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r);
+  ConstraintP getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r);
 
   /**
    * Returns a constraint of the given type for the value and variable
    * for the given ValueCollection, vc.
    * This is made if there is no such constraint.
    */
-  Constraint ensureConstraint(ValueCollection& vc, ConstraintType t){
-    if(vc.hasConstraintOfType(t)){
-      return vc.getConstraintOfType(t);
-    }else{
-      return getConstraint(vc.getVariable(), t, vc.getValue());
-    }
-  }
+  ConstraintP ensureConstraint(ValueCollection& vc, ConstraintType t);
 
 
+  void deleteConstraintAndNegation(ConstraintP c);
+
   /**
    * Outputs a minimal set of unate implications onto the vector for the variable.
    * This outputs lemmas of the general forms
@@ -887,12 +902,12 @@ public:
   void outputUnateInequalityLemmas(std::vector<Node>& lemmas, ArithVar v) const;
 
 
-  void unatePropLowerBound(Constraint curr, Constraint prev);
-  void unatePropUpperBound(Constraint curr, Constraint prev);
-  void unatePropEquality(Constraint curr, Constraint prevLB, Constraint prevUB);
+  void unatePropLowerBound(ConstraintP curr, ConstraintP prev);
+  void unatePropUpperBound(ConstraintP curr, ConstraintP prev);
+  void unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB);
 
 private:
-  void raiseUnateConflict(Constraint ant, Constraint cons);
+  void raiseUnateConflict(ConstraintP ant, ConstraintP cons);
 
   DenseSet d_reclaimable;
 
@@ -907,6 +922,7 @@ private:
 
 }; /* ConstraintDatabase */
 
+
 }/* CVC4::theory::arith namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index f01c64b60280a9dbb2104051f267a67001b7b7f4..19326c0b32b8ab8b7e224af57f8604fab9581f9d 100644 (file)
  ** minimize interaction between header files.
  **/
 
-#include "cvc4_private.h"
-
 #ifndef __CVC4__THEORY__ARITH__CONSTRAINT_FORWARD_H
 #define __CVC4__THEORY__ARITH__CONSTRAINT_FORWARD_H
 
+#include "cvc4_private.h"
+#include <vector>
+
 namespace CVC4 {
 namespace theory {
 namespace arith {
 
-class ConstraintValue;
-typedef ConstraintValue* Constraint;
-typedef const ConstraintValue* const ConstConstraint;
+class Constraint_;
+typedef Constraint_* ConstraintP;
+typedef const Constraint_* ConstraintCP;
 
-static const Constraint NullConstraint = NULL;
+const ConstraintP NullConstraint = NULL;
 
 class ConstraintDatabase;
 
+typedef std::vector<ConstraintCP> ConstraintCPVec;
+
 }/* CVC4::theory::arith namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
diff --git a/src/theory/arith/cut_log.cpp b/src/theory/arith/cut_log.cpp
new file mode 100644 (file)
index 0000000..f933516
--- /dev/null
@@ -0,0 +1,691 @@
+#include "cvc4autoconfig.h"
+
+
+#include "theory/arith/cut_log.h"
+#include "theory/arith/approx_simplex.h"
+#include "theory/arith/normal_form.h"
+#include "theory/arith/constraint.h"
+#include <math.h>
+#include <cmath>
+#include <map>
+#include <limits.h>
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+NodeLog::const_iterator NodeLog::begin() const { return d_cuts.begin(); }
+NodeLog::const_iterator NodeLog::end() const { return d_cuts.end(); }
+
+NodeLog& TreeLog::getNode(int nid) {
+  ToNodeMap::iterator i = d_toNode.find(nid);
+  Assert(i != d_toNode.end());
+  return (*i).second;
+}
+
+TreeLog::const_iterator TreeLog::begin() const { return d_toNode.begin(); }
+TreeLog::const_iterator TreeLog::end() const { return d_toNode.end(); }
+
+int TreeLog::getExecutionOrd(){
+  int res = next_exec_ord;
+  ++next_exec_ord;
+  return res;
+}
+void TreeLog::makeInactive(){  d_active = false; }
+void TreeLog::makeActive(){  d_active = true; }
+bool TreeLog::isActivelyLogging() const { return d_active; }
+
+
+PrimitiveVec::PrimitiveVec()
+  : len(0)
+  , inds(NULL)
+  , coeffs(NULL)
+{}
+
+PrimitiveVec::~PrimitiveVec(){
+  clear();
+}
+bool PrimitiveVec::initialized() const {
+  return inds != NULL;
+}
+void PrimitiveVec::clear() {
+  if(initialized()){
+    delete[] inds;
+    delete[] coeffs;
+    len = 0;
+    inds = NULL;
+    coeffs = NULL;
+  }
+}
+void PrimitiveVec::setup(int l){
+  Assert(!initialized());
+  len = l;
+  inds = new int[1+len];
+  coeffs = new double[1+len];
+}
+void PrimitiveVec::print(std::ostream& out) const{
+  Assert(initialized());
+  out << len << " ";
+  out.precision(15);
+  for(int i = 1; i <= len; ++i){
+    out << "["<< inds[i] <<", " << coeffs[i]<<"]";
+  }
+}
+std::ostream& operator<<(std::ostream& os, const PrimitiveVec& pv){
+  pv.print(os);
+  return os;
+}
+
+CutInfo::CutInfo(CutInfoKlass kl, int eid, int o)
+  : d_klass(kl)
+  , d_execOrd(eid)
+  , d_poolOrd(o)
+  , d_cutType(kind::UNDEFINED_KIND)
+  , d_cutRhs()
+  , d_cutVec()
+  , d_mAtCreation(-1)
+  , d_rowId(-1)
+  , d_exactPrecision(NULL)
+  , d_explanation(NULL)
+{}
+
+CutInfo::~CutInfo(){
+  if(d_exactPrecision == NULL){ delete d_exactPrecision; }
+  if(d_explanation == NULL){ delete d_explanation; }
+}
+
+int CutInfo::getId() const {
+  return d_execOrd;
+}
+
+int CutInfo::getRowId() const{
+  return d_rowId;
+}
+
+void CutInfo::setRowId(int rid){
+  d_rowId = rid;
+}
+
+void CutInfo::print(ostream& out) const{
+  out << "[CutInfo " << d_execOrd << " " << d_poolOrd
+      << " " << d_klass << " " << d_cutType << " " << d_cutRhs
+      << " ";
+  d_cutVec.print(out);
+  out << "]" << endl;
+}
+
+PrimitiveVec& CutInfo::getCutVector(){
+  return d_cutVec;
+}
+
+const PrimitiveVec& CutInfo::getCutVector() const{
+  return d_cutVec;
+}
+
+// void CutInfo::init_cut(int l){
+//   cut_vec.setup(l);
+// }
+
+Kind CutInfo::getKind() const{
+  return d_cutType;
+}
+
+void CutInfo::setKind(Kind k){
+  Assert(k == kind::LEQ || k == kind::GEQ);
+  d_cutType = k;
+}
+
+double CutInfo::getRhs() const{
+  return d_cutRhs;
+}
+
+void CutInfo::setRhs(double r){
+  d_cutRhs = r;
+}
+
+bool CutInfo::reconstructed() const{
+  return d_exactPrecision != NULL;
+}
+
+CutInfoKlass CutInfo::getKlass() const{
+  return d_klass;
+}
+
+int CutInfo::poolOrdinal() const{
+  return d_poolOrd;
+}
+
+void CutInfo::setDimensions(int N, int M){
+  d_mAtCreation = M;
+  d_N = N;
+}
+
+int CutInfo::getN() const{
+  return d_N;
+}
+
+int CutInfo::getMAtCreation() const{
+  return d_mAtCreation;
+}
+
+/* Returns true if the cut has an explanation. */
+bool CutInfo::proven() const{
+  return d_explanation != NULL;
+}
+
+bool CutInfo::operator<(const CutInfo& o) const{
+  return d_execOrd < o.d_execOrd;
+}
+
+
+void CutInfo::setReconstruction(const DenseVector& ep){
+  Assert(!reconstructed());
+  d_exactPrecision = new DenseVector(ep);
+}
+
+void CutInfo::setExplanation(const ConstraintCPVec& ex){
+  Assert(reconstructed());
+  if(d_explanation == NULL){
+    d_explanation = new ConstraintCPVec(ex);
+  }else{
+    *d_explanation = ex;
+  }
+}
+
+void CutInfo::swapExplanation(ConstraintCPVec& ex){
+  Assert(reconstructed());
+  Assert(!proven());
+  if(d_explanation == NULL){
+    d_explanation = new ConstraintCPVec();
+  }
+  d_explanation->swap(ex);
+}
+
+const DenseVector& CutInfo::getReconstruction() const {
+  Assert(reconstructed());
+  return *d_exactPrecision;
+}
+
+void CutInfo::clearReconstruction(){
+  if(proven()){
+    delete d_explanation;
+    d_explanation = NULL;
+  }
+
+  if(reconstructed()){
+    delete d_exactPrecision;
+    d_exactPrecision = NULL;
+  }
+
+  Assert(!reconstructed());
+  Assert(!proven());
+}
+
+const ConstraintCPVec& CutInfo::getExplanation() const {
+  Assert(proven());
+  return *d_explanation;
+}
+
+std::ostream& operator<<(std::ostream& os, const CutInfo& ci){
+  ci.print(os);
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& out, CutInfoKlass kl){
+  switch(kl){
+  case MirCutKlass:
+    out << "MirCutKlass"; break;
+  case GmiCutKlass:
+    out << "GmiCutKlass"; break;
+  case BranchCutKlass:
+    out << "BranchCutKlass"; break;
+  case RowsDeletedKlass:
+    out << "RowDeletedKlass"; break;
+  case UnknownKlass:
+    out << "UnknownKlass"; break;
+  default:
+    out << "unexpected CutInfoKlass"; break;
+  }
+  return out;
+}
+bool NodeLog::isBranch() const{
+  return d_brVar >= 0;
+}
+
+NodeLog::NodeLog()
+  : d_nid(-1)
+  , d_parent(NULL)
+  , d_tl(NULL)
+  , d_cuts()
+  , d_rowIdsSelected()
+  , d_stat(Open)
+  , d_brVar(-1)
+  , d_brVal(0.0)
+  , d_downId(-1)
+  , d_upId(-1)
+  , d_rowId2ArithVar()
+{}
+
+NodeLog::NodeLog(TreeLog* tl, int node, const RowIdMap& m)
+  : d_nid(node)
+  , d_parent(NULL)
+  , d_tl(tl)
+  , d_cuts()
+  , d_rowIdsSelected()
+  , d_stat(Open)
+  , d_brVar(-1)
+  , d_brVal(0.0)
+  , d_downId(-1)
+  , d_upId(-1)
+  , d_rowId2ArithVar(m)
+{}
+
+NodeLog::NodeLog(TreeLog* tl, NodeLog* parent, int node)
+  : d_nid(node)
+  , d_parent(parent)
+  , d_tl(tl)
+  , d_cuts()
+  , d_rowIdsSelected()
+  , d_stat(Open)
+  , d_brVar(-1)
+  , d_brVal(0.0)
+  , d_downId(-1)
+  , d_upId(-1)
+  , d_rowId2ArithVar()
+{}
+
+NodeLog::~NodeLog(){
+  CutSet::iterator i = d_cuts.begin(), iend = d_cuts.end();
+  for(; i != iend; ++i){
+    CutInfo* c = *i;
+    delete c;
+  }
+  d_cuts.clear();
+  Assert(d_cuts.empty());
+}
+
+std::ostream& operator<<(std::ostream& os, const NodeLog& nl){
+  nl.print(os);
+  return os;
+}
+
+void NodeLog::copyParentRowIds() {
+  Assert(d_parent != NULL);
+  d_rowId2ArithVar = d_parent->d_rowId2ArithVar;
+}
+
+int NodeLog::branchVariable() const {
+  return d_brVar;
+}
+double NodeLog::branchValue() const{
+  return d_brVal;
+}
+int NodeLog::getNodeId() const {
+  return d_nid;
+}
+int NodeLog::getDownId() const{
+  return d_downId;
+}
+int NodeLog::getUpId() const{
+  return d_upId;
+}
+void NodeLog::addSelected(int ord, int sel){
+  Assert(d_rowIdsSelected.find(ord) == d_rowIdsSelected.end());
+  d_rowIdsSelected[ord] = sel;
+  Debug("approx::nodelog") << "addSelected("<< ord << ", "<< sel << ")" << endl;
+}
+void NodeLog::applySelected() {
+  CutSet::iterator iter = d_cuts.begin(), iend = d_cuts.end(), todelete;
+  while(iter != iend){
+    CutInfo* curr = *iter;
+    int poolOrd = curr->poolOrdinal();
+    if(curr->getRowId() >= 0 ){
+      // selected previously, kip
+      ++iter;
+    }else if(curr->getKlass() == RowsDeletedKlass){
+      // skip
+      ++iter;
+    }else if(curr->getKlass() == BranchCutKlass){
+      // skip
+      ++iter;
+    }else if(d_rowIdsSelected.find(poolOrd) == d_rowIdsSelected.end()){
+      todelete = iter;
+      ++iter;
+      d_cuts.erase(todelete);
+      delete curr;
+    }else{
+      Debug("approx::nodelog") << "applySelected " << curr->getId() << " " << poolOrd << "->" << d_rowIdsSelected[poolOrd] << endl;
+      curr->setRowId( d_rowIdsSelected[poolOrd] );
+      ++iter;
+    }
+  }
+  d_rowIdsSelected.clear();
+}
+
+void NodeLog::applyRowsDeleted(const RowsDeleted& rd) {
+  std::map<int, CutInfo*> currInOrd; //sorted
+
+  const PrimitiveVec& cv = rd.getCutVector();
+  std::vector<int> sortedRemoved (cv.inds+1, cv.inds+cv.len+1);
+  sortedRemoved.push_back(INT_MAX);
+  std::sort(sortedRemoved.begin(), sortedRemoved.end());
+
+  if(Debug.isOn("approx::nodelog")){
+    Debug("approx::nodelog") << "Removing #" << sortedRemoved.size()<< "...";
+    for(unsigned k = 0; k<sortedRemoved.size(); k++){
+      Debug("approx::nodelog") << ", " << sortedRemoved[k];
+    }
+    Debug("approx::nodelog") << endl;
+    Debug("approx::nodelog") << "cv.len" << cv.len  << endl;
+  }
+
+  int min = sortedRemoved.front();
+
+  CutSet::iterator iter = d_cuts.begin(), iend = d_cuts.end();
+  while(iter != iend){
+    CutInfo* curr= *iter;
+    if(curr->getId() < rd.getId()){
+      if(d_rowId2ArithVar.find(curr->getRowId()) != d_rowId2ArithVar.end()){
+        if(curr->getRowId() >= min){
+          currInOrd.insert(make_pair(curr->getRowId(), curr));
+        }
+      }
+    }
+    ++iter;
+  }
+
+  RowIdMap::const_iterator i, end;
+  i=d_rowId2ArithVar.begin(), end = d_rowId2ArithVar.end();
+  for(; i != end; ++i){
+    int key = (*i).first;
+    if(key >= min){
+      if(currInOrd.find(key) == currInOrd.end()){
+        CutInfo* null = NULL;
+        currInOrd.insert(make_pair(key, null));
+      }
+    }
+  }
+
+
+
+  std::map<int, CutInfo*>::iterator j, jend;
+
+  int posInSorted = 0;
+  for(j = currInOrd.begin(), jend=currInOrd.end(); j!=jend; ++j){
+    int origOrd = (*j).first;
+    ArithVar v = d_rowId2ArithVar[origOrd];
+    int headRemovedOrd = sortedRemoved[posInSorted];
+    while(headRemovedOrd < origOrd){
+      ++posInSorted;
+      headRemovedOrd  = sortedRemoved[posInSorted];
+    }
+    // headRemoveOrd >= origOrd
+    Assert(headRemovedOrd >= origOrd);
+
+    CutInfo* ci = (*j).second;
+    if(headRemovedOrd == origOrd){
+
+      if(ci == NULL){
+        Debug("approx::nodelog") << "deleting from above because of " << rd << endl;
+        Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+        d_rowId2ArithVar.erase(origOrd);
+      }else{
+        Debug("approx::nodelog") << "deleting " << ci << " because of " << rd << endl;
+        Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+        d_rowId2ArithVar.erase(origOrd);
+        ci->setRowId(-1);
+      }
+    }else{
+      Assert(headRemovedOrd > origOrd);
+      // headRemoveOrd > origOrd
+      int newOrd = origOrd - posInSorted;
+      Assert(newOrd > 0);
+      if(ci == NULL){
+        Debug("approx::nodelog") << "shifting above down due to " << rd << endl;
+        Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+        Debug("approx::nodelog") << "now have " << newOrd << " <-> " << v << endl;
+        d_rowId2ArithVar.erase(origOrd);
+        mapRowId(newOrd, v);
+      }else{
+        Debug("approx::nodelog") << "shifting " << ci << " down due to " << rd << endl;
+        Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+        Debug("approx::nodelog") << "now have " << newOrd << " <-> " << v << endl;
+        ci->setRowId(newOrd);
+        d_rowId2ArithVar.erase(origOrd);
+        mapRowId(newOrd, v);
+      }
+    }
+  }
+
+}
+
+// void NodeLog::adjustRowId(CutInfo& ci, const RowsDeleted& rd) {
+//   int origRowId = ci.getRowId();
+//   int newRowId = ci.getRowId();
+//   ArithVar v = d_rowId2ArithVar[origRowId];
+
+//   const PrimitiveVec& cv = rd.getCutVector();
+
+//   for(int j = 1, N = cv.len; j <= N; j++){
+//     int ind = cv.inds[j];
+//     if(ind == origRowId){
+//       newRowId = -1;
+//       break;
+//     }else if(ind < origRowId){
+//       newRowId--;
+//     }
+//   }
+
+//   if(newRowId < 0){
+//     cout << "deleting " << ci << " because of " << rd << endl;
+//     cout << "had " << origRowId << " <-> " << v << endl;
+//     d_rowId2ArithVar.erase(origRowId);
+//     ci.setRowId(-1);
+//   }else if(newRowId != origRowId){
+//     cout << "adjusting " << ci << " because of " << rd << endl;
+//     cout << "had " << origRowId << " <-> " << v << endl;
+//     cout << "now have " << newRowId << " <-> " << v << endl;
+//     d_rowId2ArithVar.erase(origRowId);
+//     ci.setRowId(newRowId);
+//     mapRowId(newRowId, v);
+//   }else{
+//     cout << "row id unchanged " << ci << " because of " << rd << endl;
+//   }
+// }
+
+
+ArithVar NodeLog::lookupRowId(int rowId) const{
+  RowIdMap::const_iterator i = d_rowId2ArithVar.find(rowId);
+  if(i == d_rowId2ArithVar.end()){
+    return ARITHVAR_SENTINEL;
+  }else{
+    return (*i).second;
+  }
+}
+
+void NodeLog::mapRowId(int rowId, ArithVar v){
+  Assert(lookupRowId(rowId) == ARITHVAR_SENTINEL);
+  Debug("approx::nodelog")
+    << "On " << getNodeId()
+    << " adding row id " << rowId << " <-> " << v << endl;
+  d_rowId2ArithVar[rowId] = v;
+}
+
+
+
+void NodeLog::addCut(CutInfo* ci){
+  Assert(ci != NULL);
+  d_cuts.insert(ci);
+}
+
+void NodeLog::print(ostream& o) const{
+  o << "[n" << getNodeId();
+  for(const_iterator iter = begin(), iend = end(); iter != iend; ++iter ){
+    CutInfo* cut = *iter;
+    o << ", " << cut->poolOrdinal();
+    if(cut->getRowId() >= 0){
+      o << " " << cut->getRowId();
+    }
+  }
+  o << "]" << std::endl;
+}
+
+void NodeLog::closeNode(){
+  Assert(d_stat == Open);
+  d_stat = Closed;
+}
+
+void NodeLog::setBranch(int br, double val, int d, int u){
+  Assert(d_stat == Open);
+  d_brVar = br;
+  d_brVal = val;
+  d_downId = d;
+  d_upId = u;
+  d_stat = Branched;
+}
+
+TreeLog::TreeLog()
+  : next_exec_ord(0)
+  , d_toNode()
+  , d_branches()
+  , d_numCuts(0)
+  , d_active(false)
+{
+  NodeLog::RowIdMap empty;
+  reset(empty);
+}
+
+int TreeLog::getRootId() const{
+  return 1;
+}
+
+NodeLog& TreeLog::getRootNode(){
+  return getNode(getRootId());
+}
+
+void TreeLog::clear(){
+  next_exec_ord = 0;
+  d_toNode.clear();
+  d_branches.purge();
+
+  d_numCuts = 0;
+
+  // add root
+}
+
+void TreeLog::reset(const NodeLog::RowIdMap& m){
+  clear();
+  d_toNode.insert(make_pair(getRootId(), NodeLog(this, getRootId(), m)));
+}
+
+void TreeLog::addCut(){ d_numCuts++; }
+uint32_t TreeLog::cutCount() const { return d_numCuts; }
+void TreeLog::logBranch(uint32_t x){
+  d_branches.add(x);
+}
+uint32_t TreeLog::numBranches(uint32_t x){
+  return d_branches.count(x);
+}
+
+void TreeLog::branch(int nid, int br, double val, int dn, int up){
+  NodeLog& nl = getNode(nid);
+  nl.setBranch(br, val, dn, up);
+
+  d_toNode.insert(make_pair(dn, NodeLog(this, &nl, dn)));
+  d_toNode.insert(make_pair(up, NodeLog(this, &nl, up)));
+}
+
+void TreeLog::close(int nid){
+  NodeLog& nl = getNode(nid);
+  nl.closeNode();
+}
+
+
+
+// void TreeLog::applySelected() {
+//   std::map<int, NodeLog>::iterator iter, end;
+//   for(iter = d_toNode.begin(), end = d_toNode.end(); iter != end; ++iter){
+//     NodeLog& onNode = (*iter).second;
+//     //onNode.applySelected();
+//   }
+// }
+
+void TreeLog::print(ostream& o) const{
+  o << "TreeLog: " << d_toNode.size() << std::endl;
+  for(const_iterator iter = begin(), iend = end(); iter != iend; ++iter){
+    const NodeLog& onNode = (*iter).second;
+    onNode.print(o);
+  }
+}
+
+void TreeLog::applyRowsDeleted(int nid, const RowsDeleted& rd){
+  NodeLog& nl = getNode(nid);
+  nl.applyRowsDeleted(rd);
+}
+
+void TreeLog::mapRowId(int nid, int ind, ArithVar v){
+  NodeLog& nl = getNode(nid);
+  nl.mapRowId(ind, v);
+}
+
+void DenseVector::purge() {
+  lhs.purge();
+  rhs = Rational(0);
+}
+
+RowsDeleted::RowsDeleted(int execOrd, int nrows, const int num[])
+  : CutInfo(RowsDeletedKlass, execOrd, 0)
+{
+  d_cutVec.setup(nrows);
+  for(int j=1; j <= nrows; j++){
+    d_cutVec.coeffs[j] = 0;
+    d_cutVec.inds[j] = num[j];
+  }
+}
+
+BranchCutInfo::BranchCutInfo(int execOrd, int br, Kind dir, double val)
+  : CutInfo(BranchCutKlass, execOrd, 0)
+{
+  d_cutVec.setup(1);
+  d_cutVec.inds[1] = br;
+  d_cutVec.coeffs[1] = +1.0;
+  d_cutRhs = val;
+  d_cutType = dir;
+}
+
+void TreeLog::printBranchInfo(ostream& os) const{
+  uint32_t total = 0;
+  DenseMultiset::const_iterator iter = d_branches.begin(),  iend = d_branches.end();
+  for(; iter != iend; ++iter){
+    uint32_t el = *iter;
+    total += el;
+  }
+  os << "printBranchInfo() : " << total << endl;
+  iter = d_branches.begin(),  iend = d_branches.end();
+  for(; iter != iend; ++iter){
+    uint32_t el = *iter;
+    os << "["<<el <<", " << d_branches.count(el) << "]";
+  }
+  os << endl;
+}
+
+
+void DenseVector::print(std::ostream& os) const {
+  os << rhs << " + ";
+  print(os, lhs);
+}
+void DenseVector::print(ostream& out, const DenseMap<Rational>& v){
+  out << "[DenseVec len " <<  v.size();
+  DenseMap<Rational>::const_iterator iter, end;
+  for(iter = v.begin(), end = v.end(); iter != end; ++iter){
+    ArithVar x = *iter;
+    out << ", "<< x << " " << v[x];
+  }
+  out << "]";
+}
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h
new file mode 100644 (file)
index 0000000..1233136
--- /dev/null
@@ -0,0 +1,281 @@
+
+#include "cvc4_private.h"
+
+#pragma once
+
+#include "expr/kind.h"
+#include "util/statistics_registry.h"
+#include "theory/arith/arithvar.h"
+#include "theory/arith/constraint_forward.h"
+#include "util/dense_map.h"
+#include <vector>
+#include <map>
+#include <set>
+#include <ext/hash_map>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/** A low level vector of indexed doubles. */
+struct PrimitiveVec {
+  int len;
+  int* inds;
+  double* coeffs;
+  PrimitiveVec();
+  ~PrimitiveVec();
+  bool initialized() const;
+  void clear();
+  void setup(int l);
+  void print(std::ostream& out) const;
+};
+std::ostream& operator<<(std::ostream& os, const PrimitiveVec& pv);
+
+struct DenseVector {
+  DenseMap<Rational> lhs;
+  Rational rhs;
+  void purge();
+  void print(std::ostream& os) const;
+
+  static void print(std::ostream& os, const DenseMap<Rational>& lhs);
+};
+
+/** The different kinds of cuts. */
+enum CutInfoKlass{ MirCutKlass, GmiCutKlass, BranchCutKlass,
+                   RowsDeletedKlass,
+                   UnknownKlass};
+std::ostream& operator<<(std::ostream& os, CutInfoKlass kl);
+
+/** A general class for describing a cut. */
+class CutInfo {
+protected:
+  CutInfoKlass d_klass;
+  int d_execOrd;
+
+  int d_poolOrd;    /* cut's ordinal in the current node pool */
+  Kind d_cutType;   /* Lowerbound, upperbound or undefined. */
+  double d_cutRhs; /* right hand side of the cut */
+  PrimitiveVec d_cutVec; /* vector of the cut */
+
+  /**
+   * The number of rows at the time the cut was made.
+   * This is required to descramble indices after the fact!
+   */
+  int d_mAtCreation;
+
+  /** This is the number of structural variables. */
+  int d_N;
+
+  /** if selected, make this non-zero */
+  int d_rowId;
+
+  /* If the cut has been successfully created,
+   * the cut is stored in exact precision in d_exactPrecision.
+   * If the cut has not yet been proven, this is null.
+   */
+  DenseVector* d_exactPrecision;
+
+  ConstraintCPVec* d_explanation;
+
+public:
+  CutInfo(CutInfoKlass kl, int cutid, int ordinal);
+
+  virtual ~CutInfo();
+
+  int getId() const;
+
+  int getRowId() const;
+  void setRowId(int rid);
+
+  void print(std::ostream& out) const;
+  //void init_cut(int l);
+  PrimitiveVec& getCutVector();
+  const PrimitiveVec& getCutVector() const;
+
+  Kind getKind() const;
+  void setKind(Kind k);
+
+
+  void setRhs(double r);
+  double getRhs() const;
+
+  CutInfoKlass getKlass() const;
+  int poolOrdinal() const;
+
+  void setDimensions(int N, int M);
+  int getN() const;
+  int getMAtCreation() const;
+
+  bool operator<(const CutInfo& o) const;
+
+  /* Returns true if the cut was successfully made in exact precision.*/
+  bool reconstructed() const;
+
+  /* Returns true if the cut has an explanation. */
+  bool proven() const;
+
+  void setReconstruction(const DenseVector& ep);
+  void setExplanation(const ConstraintCPVec& ex);
+  void swapExplanation(ConstraintCPVec& ex);
+
+  const DenseVector& getReconstruction() const;
+  const ConstraintCPVec& getExplanation() const;
+
+  void clearReconstruction();
+};
+std::ostream& operator<<(std::ostream& os, const CutInfo& ci);
+
+struct BranchCutInfo : public CutInfo {
+  BranchCutInfo(int execOrd, int br,  Kind dir, double val);
+};
+
+struct RowsDeleted : public CutInfo {
+  RowsDeleted(int execOrd, int nrows, const int num[]);
+};
+
+class TreeLog;
+
+class NodeLog {
+private:
+  int d_nid;
+  NodeLog* d_parent; /* If null this is the root */
+  TreeLog* d_tl;     /* TreeLog containing the node. */
+
+  struct CmpCutPointer{
+    int operator()(const CutInfo* a, const CutInfo* b) const{
+      return *a < *b;
+    }
+  };
+  typedef std::set<CutInfo*, CmpCutPointer> CutSet;
+  CutSet d_cuts;
+  std::map<int, int> d_rowIdsSelected;
+
+  enum Status {Open, Closed, Branched};
+  Status d_stat;
+
+  int d_brVar; // branching variable
+  double d_brVal;
+  int d_downId;
+  int d_upId;
+
+public:
+  typedef __gnu_cxx::hash_map<int, ArithVar> RowIdMap;
+private:
+  RowIdMap d_rowId2ArithVar;
+
+public:
+  NodeLog(); /* default constructor. */
+  NodeLog(TreeLog* tl, int node, const RowIdMap& m); /* makes a root node. */
+  NodeLog(TreeLog* tl, NodeLog* parent, int node);/* makes a non-root node. */
+
+  ~NodeLog();
+
+  int getNodeId() const;
+  void addSelected(int ord, int sel);
+  void applySelected();
+  void addCut(CutInfo* ci);
+  void print(std::ostream& o) const;
+
+  bool isRoot() const;
+  const NodeLog& getParent() const;
+
+  void copyParentRowIds();
+
+  bool isBranch() const;
+  int branchVariable() const;
+  double branchValue() const;
+
+  typedef CutSet::const_iterator const_iterator;
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  void setBranch(int br, double val, int dn, int up);
+  void closeNode();
+
+  int getDownId() const;
+  int getUpId() const;
+
+  /**
+   * Looks up a row id to the appropraite arith variable.
+   * Be careful these are deleted in context during replay!
+   * failure returns ARITHVAR_SENTINEL */
+  ArithVar lookupRowId(int rowId) const;
+
+  /**
+   * Maps a row id to an arithvar.
+   * Be careful these are deleted in context during replay!
+   */
+  void mapRowId(int rowid, ArithVar v);
+  void applyRowsDeleted(const RowsDeleted& rd);
+
+};
+std::ostream& operator<<(std::ostream& os, const NodeLog& nl);
+
+class ApproximateSimplex;
+class TreeLog {
+private:
+  ApproximateSimplex* d_generator;
+
+  int next_exec_ord;
+  typedef std::map<int, NodeLog> ToNodeMap;
+  ToNodeMap d_toNode;
+  DenseMultiset d_branches;
+
+  uint32_t d_numCuts;
+
+  bool d_active;
+
+public:
+  TreeLog();
+
+  NodeLog& getNode(int nid);
+  void branch(int nid, int br, double val, int dn, int up);
+  void close(int nid);
+
+  //void applySelected();
+  void print(std::ostream& o) const;
+
+  typedef ToNodeMap::const_iterator const_iterator;
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  int getExecutionOrd();
+
+  void reset(const NodeLog::RowIdMap& m);
+
+  // Applies rd tp to the node with id nid
+  void applyRowsDeleted(int nid, const RowsDeleted& rd);
+
+  // Synonym for getNode(nid).mapRowId(ind, v)
+  void mapRowId(int nid, int ind, ArithVar v);
+
+private:
+  void clear();
+
+public:
+  void makeInactive();
+  void makeActive();
+
+  bool isActivelyLogging() const;
+
+  void addCut();
+  uint32_t cutCount() const;
+
+  void logBranch(uint32_t x);
+  uint32_t numBranches(uint32_t x);
+
+  int getRootId() const;
+
+  uint32_t numNodes() const{
+    return d_toNode.size();
+  }
+
+  NodeLog& getRootNode();
+  void printBranchInfo(std::ostream& os) const;
+};
+
+
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
index 39c2d859b28bda2c3629ef65e1a2c2136895dcac..c9f9df7271d303a6d59537f70b10da7e20ff8e61 100644 (file)
@@ -281,7 +281,7 @@ void DioSolver::moveMinimumByAbsToQueueFront(){
   size_t N = d_currentF.size();
   for(size_t i=1; i < N; ++i){
     Monomial curr = d_trail[d_currentF[i]].d_minimalMonomial;
-    if(curr.absLessThan(minMonomial)){
+    if(curr.absCmp(minMonomial) < 0){
       indexInQueue = i;
       minMonomial = curr;
     }
index 5039f826c27287873c633e36349df8783e7a734f..32b8382fa3133a86d2f1765c66c9ea5fe1a42537 100644 (file)
@@ -102,17 +102,17 @@ private:
   };
   context::CDList<Constraint> d_trail;
 
-  /** Compare by d_minimal. */
-  struct TrailMinimalCoefficientOrder {
-    const context::CDList<Constraint>& d_trail;
-    TrailMinimalCoefficientOrder(const context::CDList<Constraint>& trail):
-      d_trail(trail)
-    {}
-
-    bool operator()(TrailIndex i, TrailIndex j){
-      return d_trail[i].d_minimalMonomial.absLessThan(d_trail[j].d_minimalMonomial);
-    }
-  };
+  // /** Compare by d_minimal. */
+  // struct TrailMinimalCoefficientOrder {
+  //   const context::CDList<Constraint>& d_trail;
+  //   TrailMinimalCoefficientOrder(const context::CDList<Constraint>& trail):
+  //     d_trail(trail)
+  //   {}
+
+  //   bool operator()(TrailIndex i, TrailIndex j){
+  //     return d_trail[i].d_minimalMonomial.absLessThan(d_trail[j].d_minimalMonomial);
+  //   }
+  // };
 
   /**
    * A substitution is stored as a constraint in the trail together with
index dea78acf798919852561cd7cd4285b94ad7fd303..6d341ed12ede2e4944b610f2cf7c46abd4d52caf 100644 (file)
@@ -39,7 +39,7 @@ ErrorInformation::ErrorInformation()
   Debug("arith::error::mem") << "def constructor " << d_variable << " "  << d_amount << endl;
 }
 
-ErrorInformation::ErrorInformation(ArithVar var, Constraint vio, int sgn)
+ErrorInformation::ErrorInformation(ArithVar var, ConstraintP vio, int sgn)
   : d_variable(var)
   , d_violated(vio)
   , d_sgn(sgn)
@@ -105,7 +105,7 @@ ErrorInformation& ErrorInformation::operator=(const ErrorInformation& ei){
   return *this;
 }
 
-void ErrorInformation::reset(Constraint c, int sgn){
+void ErrorInformation::reset(ConstraintP c, int sgn){
   Assert(!isRelaxed());
   Assert(c != NullConstraint);
   d_violated = c;
@@ -272,7 +272,7 @@ void ErrorSet::transitionVariableOutOfError(ArithVar v) {
   ErrorInformation& ei = d_errInfo.get(v);
   Assert(ei.debugInitialized());
   if(ei.isRelaxed()){
-    Constraint viol = ei.getViolated();
+    ConstraintP viol = ei.getViolated();
     if(ei.sgn() > 0){
       d_variables.setLowerBoundConstraint(viol);
     }else{
@@ -293,7 +293,7 @@ void ErrorSet::transitionVariableIntoError(ArithVar v) {
   Assert(inconsistent(v));
   bool vilb = d_variables.cmpAssignmentLowerBound(v) < 0;
   int sgn = vilb ? 1 : -1;
-  Constraint c = vilb ?
+  ConstraintP c = vilb ?
     d_variables.getLowerBoundConstraint(v) : d_variables.getUpperBoundConstraint(v);
   d_errInfo.set(v, ErrorInformation(v, c, sgn));
   ErrorInformation& ei = d_errInfo.get(v);
@@ -373,7 +373,7 @@ int ErrorSet::popSignal() {
       Assert(!vilb || !viub);
       int currSgn = vilb ? 1 : -1;
       if(currSgn != prevSgn){
-        Constraint curr = vilb ?  d_variables.getLowerBoundConstraint(back)
+        ConstraintP curr = vilb ?  d_variables.getLowerBoundConstraint(back)
           : d_variables.getUpperBoundConstraint(back);
         ei.reset(curr, currSgn);
       }
index d1b692cb4edad2e55fb4c5f1508c6cb884e60e10..b87282ba0326c1386bf3563715eaa9d3bc2856f3 100644 (file)
@@ -120,7 +120,7 @@ private:
    * This needs to be saved in case that the
    * violated constraint
    */
-  Constraint d_violated;
+  ConstraintP d_violated;
 
   /**
    * This is the sgn of the first derivate the variable must move to satisfy
@@ -155,12 +155,12 @@ private:
 
 public:
   ErrorInformation();
-  ErrorInformation(ArithVar var, Constraint vio, int sgn);
+  ErrorInformation(ArithVar var, ConstraintP vio, int sgn);
   ~ErrorInformation();
   ErrorInformation(const ErrorInformation& ei);
   ErrorInformation& operator=(const ErrorInformation& ei);
 
-  void reset(Constraint c, int sgn);
+  void reset(ConstraintP c, int sgn);
 
   inline ArithVar getVariable() const { return d_variable; }
 
@@ -192,7 +192,7 @@ public:
   }
   inline const FocusSetHandle& getHandle() const{ return d_handle; }
 
-  inline Constraint getViolated() const { return d_violated; }
+  inline ConstraintP getViolated() const { return d_violated; }
 
   bool debugInitialized() const {
     return
@@ -389,7 +389,7 @@ public:
     return d_errInfo[a].getMetric();
   }
 
-  Constraint getViolated(ArithVar a) const {
+  ConstraintP getViolated(ArithVar a) const {
     return d_errInfo[a].getViolated();
   }
 
index c0bffdf077ccfe93b11d207d30b6da7205cc0cf4..70a3229594bdefda9357d7fa87be9ed85b526c84 100644 (file)
@@ -536,7 +536,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
   }
 
   if(selected.describesPivot()){
-    Constraint limiting = selected.limiting();
+    ConstraintP limiting = selected.limiting();
     ArithVar basic = limiting->getVariable();
     Assert(d_linEq.basicIsTracked(basic));
     d_linEq.pivotAndUpdate(basic, nonbasic, limiting->getValue());
index 5817a3629c1e71fbadba9d865c2df414800f52e6..f4c1ae10c3bc33b2855d1b0ee78abd7c1de18f09 100644 (file)
@@ -494,7 +494,7 @@ const Tableau::Entry* LinearEqualityModule::rowLacksBound(RowIndex ridx, bool ro
   return NULL;
 }
 
-void LinearEqualityModule::propagateBasicFromRow(Constraint c){
+void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){
   Assert(c != NullConstraint);
   Assert(c->isUpperBound() || c->isLowerBound());
   Assert(!c->assertedToTheTheory());
@@ -504,12 +504,12 @@ void LinearEqualityModule::propagateBasicFromRow(Constraint c){
   ArithVar basic = c->getVariable();
   RowIndex ridx = d_tableau.basicToRowIndex(basic);
 
-  vector<Constraint> bounds;
+  ConstraintCPVec bounds;
   propagateRow(bounds, ridx, upperBound, c);
   c->impliedBy(bounds);
 }
 
-void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c){
+void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bool rowUp, ConstraintP c){
   Assert(!c->assertedToTheTheory());
   Assert(c->canBePropagated());
   Assert(!c->hasProof());
@@ -529,7 +529,7 @@ void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx,
     int sgn = a_ij.sgn();
     Assert(sgn != 0);
     bool selectUb = rowUp ? (sgn > 0) : (sgn < 0);
-    Constraint bound = selectUb
+    ConstraintCP bound = selectUb
       ? d_variables.getUpperBoundConstraint(nonbasic)
       : d_variables.getLowerBoundConstraint(nonbasic);
 
@@ -541,12 +541,12 @@ void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx,
                                    << v << ") done" << endl;
 }
 
-Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
+ConstraintP LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
 
   int sgn = coeff.sgn();
   bool ub = aboveUpper?(sgn < 0) : (sgn > 0);
 
-  Constraint c = ub ?
+  ConstraintP c = ub ?
     d_variables.getUpperBoundConstraint(v) :
     d_variables.getLowerBoundConstraint(v);
 
@@ -556,7 +556,7 @@ Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRation
 
     weakened = false;
 
-    Constraint weaker = ub?
+    ConstraintP weaker = ub?
       c->getStrictlyWeakerUpperBound(true, true):
       c->getStrictlyWeakerLowerBound(true, true);
 
@@ -591,7 +591,7 @@ Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRation
   return c;
 }
 
-Node LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basicVar) const {
+void LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, RaiseConflict& rc) const {
   TimerStat::CodeTimer codeTimer(d_statistics.d_weakenTime);
 
   const DeltaRational& assignment = d_variables.getAssignment(basicVar);
@@ -606,29 +606,25 @@ Node LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basic
     surplus = d_variables.getLowerBound(basicVar) - assignment;
   }
 
-  NodeBuilder<> conflict(kind::AND);
   bool anyWeakenings = false;
   for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){
     const Tableau::Entry& entry = *i;
     ArithVar v = entry.getColVar();
     const Rational& coeff = entry.getCoefficient();
     bool weakening = false;
-    Constraint c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
+    ConstraintP c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
     Debug("weak") << "weak : " << weakening << " "
                   << c->assertedToTheTheory() << " "
                   << d_variables.getAssignment(v) << " "
-                  << c << endl
-                  << c->explainForConflict() << endl;
+                  << c << endl;
     anyWeakenings = anyWeakenings || weakening;
 
-    Debug("weak") << "weak : " << c->explainForConflict() << endl;
-    c->explainForConflict(conflict);
+    rc.addConstraint(c);
   }
   ++d_statistics.d_weakeningAttempts;
   if(anyWeakenings){
     ++d_statistics.d_weakeningSuccesses;
   }
-  return conflict;
 }
 
 ArithVar LinearEqualityModule::minVarOrder(ArithVar x, ArithVar y) const {
@@ -787,7 +783,7 @@ bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
   int coeffSgn = u.getCoefficient().sgn();
   int nbdir = u.nonbasicDirection();
 
-  Constraint c = u.limiting();
+  ConstraintP c = u.limiting();
   int toUB = (c->getType() == UpperBound ||
               c->getType() == Equality) ? 1 : 0;
   int toLB = (c->getType() == LowerBound ||
@@ -886,7 +882,7 @@ bool LinearEqualityModule::accumulateBorder(const Tableau::Entry& entry, bool ub
 
   Assert(basicIsTracked(currBasic));
 
-  Constraint bound = ub ?
+  ConstraintP bound = ub ?
     d_variables.getUpperBoundConstraint(currBasic):
     d_variables.getLowerBoundConstraint(currBasic);
 
@@ -1003,7 +999,7 @@ UpdateInfo LinearEqualityModule::mkConflictUpdate(const Tableau::Entry& entry, b
   ArithVar currBasic = d_tableau.rowIndexToBasic(entry.getRowIndex());
   ArithVar nb = entry.getColVar();
 
-  Constraint bound = ub ?
+  ConstraintP bound = ub ?
     d_variables.getUpperBoundConstraint(currBasic):
     d_variables.getLowerBoundConstraint(currBasic);
 
@@ -1031,14 +1027,14 @@ UpdateInfo LinearEqualityModule::speculativeUpdate(ArithVar nb, const Rational&
   Debug("speculativeUpdate") << "focusCoeff " << focusCoeff << endl;
 
   if(d_variables.hasUpperBound(nb)){
-    Constraint ub = d_variables.getUpperBoundConstraint(nb);
+    ConstraintP ub = d_variables.getUpperBoundConstraint(nb);
     d_upperBoundDifference = ub->getValue() - d_variables.getAssignment(nb);
     Border border(ub, d_upperBoundDifference, false, NULL, true);
     Debug("handleBorders") << "push back increasing " << border << endl;
     d_increasing.push_back(border);
   }
   if(d_variables.hasLowerBound(nb)){
-    Constraint lb = d_variables.getLowerBoundConstraint(nb);
+    ConstraintP lb = d_variables.getLowerBoundConstraint(nb);
     d_lowerBoundDifference = lb->getValue() - d_variables.getAssignment(nb);
     Border border(lb, d_lowerBoundDifference, false, NULL, false);
     Debug("handleBorders") << "push back decreasing " << border << endl;
index 293a0ddad2fea3ab0ae55c60feaf9ae7ed34472d..804ad29acc0fc723a1827362832bc92dce7cfd84 100644 (file)
@@ -46,7 +46,7 @@ namespace arith {
 
 struct Border{
   // The constraint for the border
-  Constraint d_bound;
+  ConstraintP d_bound;
 
   // The change to the nonbasic to reach the border
   DeltaRational d_diff;
@@ -65,11 +65,11 @@ struct Border{
     d_bound(NullConstraint) // ignore the other values
   {}
 
-  Border(Constraint l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub):
+  Border(ConstraintP l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub):
     d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(en),  d_upperbound(ub)
   {}
 
-  Border(Constraint l, const DeltaRational& diff, bool areFixing, bool ub):
+  Border(ConstraintP l, const DeltaRational& diff, bool areFixing, bool ub):
     d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(NULL),  d_upperbound(ub)
   {}
   bool operator<(const Border& other) const{
@@ -414,13 +414,13 @@ public:
    * The constraint on a basic variable b is implied by the constraints
    * on its row.  This is a wrapper for propagateRow().
    */
-  void propagateBasicFromRow(Constraint c);
+  void propagateBasicFromRow(ConstraintP c);
 
   /**
    * Exports either the explanation of an upperbound or a lower bound
    * of the basic variable basic, using the non-basic variables in the row.
    */
-  void propagateRow(std::vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c);
+  void propagateRow(ConstraintCPVec& into, RowIndex ridx, bool rowUp, ConstraintP c);
 
   /**
    * Computes the value of a basic variable using the assignments
@@ -592,26 +592,26 @@ private:
    * with the weakest possible constraint that is consistent with the surplus
    * surplus.
    */
-  Constraint weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
+  ConstraintP weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
                                 const Rational& coeff, bool& anyWeakening, ArithVar basic) const;
 
 public:
   /**
    * Constructs a minimally weak conflict for the basic variable basicVar.
    */
-  Node minimallyWeakConflict(bool aboveUpper, ArithVar basicVar) const;
+  void minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, RaiseConflict& rc) const;
 
   /**
    * Given a non-basic variable that is know to have a conflict on it,
    * construct and return a conflict.
    * Follows section 4.2 in the CAV06 paper.
    */
-  inline Node generateConflictAboveUpperBound(ArithVar conflictVar) const {
-    return minimallyWeakConflict(true, conflictVar);
+  inline void generateConflictAboveUpperBound(ArithVar conflictVar, RaiseConflict& rc) const {
+    minimallyWeakConflict(true, conflictVar, rc);
   }
 
-  inline Node generateConflictBelowLowerBound(ArithVar conflictVar) const {
-    return minimallyWeakConflict(false, conflictVar);
+  inline void generateConflictBelowLowerBound(ArithVar conflictVar, RaiseConflict& rc) const {
+    minimallyWeakConflict(false, conflictVar, rc);
   }
 
   /**
index d93b6986e8f769609a2b954bc459340256fa993d..084281c0421b72099d9da04fec5b1892d794b67a 100644 (file)
@@ -362,16 +362,18 @@ public:
 
 template <class T>
 class Matrix {
-protected:
-
+public:
   typedef MatrixEntry<T> Entry;
 
+protected:
   typedef CVC4::theory::arith::RowVector<T> RowVectorT;
-  typedef typename RowVectorT::const_iterator RowIterator;
-
   typedef CVC4::theory::arith::ColumnVector<T> ColumnVectorT;
+
+public:
+  typedef typename RowVectorT::const_iterator RowIterator;
   typedef typename ColumnVectorT::const_iterator ColIterator;
 
+protected:
   // RowTable : RowID |-> RowVector
   typedef std::vector< RowVectorT > RowTable;
   RowTable d_rows;
@@ -532,6 +534,12 @@ public:
     d_columns.push_back(ColumnVector<T>(&d_entries));
   }
 
+  void increaseSizeTo(size_t s){
+    while(getNumColumns() < s){
+      increaseSize();
+    }
+  }
+
   const RowVector<T>& getRow(RowIndex r) const {
     Assert(r < d_rows.size());
     return d_rows[r];
@@ -600,7 +608,33 @@ public:
     d_mergeBuffer.purge();
   }
 
-  /**  to += mult * buffer. */
+  /* to *= mult */
+  void multiplyRowByConstant(RowIndex to, const T& mult){
+    RowIterator i = getRow(to).begin();
+    RowIterator i_end = getRow(to).end();
+    for( ; i != i_end; ++i){
+      EntryID id = i.getID();
+      Entry& entry = d_entries.get(id);
+      T& coeff = entry.getCoefficient();
+      coeff *= mult;
+    }
+  }
+
+  /**  to += mult * from.
+   * Use the more efficient rowPlusBufferTimesConstant() for
+   * repeated use.
+   */
+  void rowPlusRowTimesConstant(RowIndex to, RowIndex from, const T& mult){
+    Assert(to != from);
+    loadRowIntoBuffer(from);
+    rowPlusBufferTimesConstant(to, mult);
+    clearBuffer();
+  }
+
+  /**  to += mult * buffer.
+   * Invalidates coefficients on the row.
+   * (mult should never be a direct copy of a coefficient!)
+   */
   void rowPlusBufferTimesConstant(RowIndex to, const T& mult){
     Assert(d_rowInMergeBuffer != ROW_INDEX_SENTINEL);
     Assert(to != ROW_INDEX_SENTINEL);
index 4edc55cca9013bc69d6a25708418e6f79aa6a7b2..3adb72f3778669104ef023e44e4637e2fea70f9c 100644 (file)
@@ -18,6 +18,7 @@
 #include "theory/arith/normal_form.h"
 #include "theory/arith/arith_utilities.h"
 #include <list>
+#include "theory/theory.h"
 
 using namespace std;
 
@@ -25,6 +26,47 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
+Constant Constant::mkConstant(const Rational& rat) {
+  return Constant(mkRationalNode(rat));
+}
+
+size_t Variable::getComplexity() const{
+  return 1u;
+}
+
+size_t VarList::getComplexity() const{
+  if(empty()){
+    return 1;
+  }else if(singleton()){
+    return 1;
+  }else{
+    return size() + 1;
+  }
+}
+
+size_t Monomial::getComplexity() const{
+  return getConstant().getComplexity() + getVarList().getComplexity();
+}
+
+size_t Polynomial::getComplexity() const{
+  size_t cmp = 0;
+  iterator i = begin(), e = end();
+  for(; i != e; ++i){
+    Monomial m = *i;
+    cmp += m.getComplexity();
+  }
+  return cmp;
+}
+
+size_t Constant::getComplexity() const{
+  return getValue().complexity();
+}
+
+bool Variable::isLeafMember(Node n){
+  return (!isRelationOperator(n.getKind())) &&
+    (Theory::isLeafOf(n, theory::THEORY_ARITH));
+}
+
 bool Variable::isDivMember(Node n){
   switch(n.getKind()){
   case kind::DIVISION:
@@ -39,6 +81,8 @@ bool Variable::isDivMember(Node n){
   }
 }
 
+
+
 bool VarList::isSorted(iterator start, iterator end) {
   return __gnu_cxx::is_sorted(start, end);
 }
@@ -161,27 +205,76 @@ Monomial Monomial::operator*(const Monomial& mono) const {
   return Monomial::mkMonomial(newConstant, newVL);
 }
 
-vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) {
+// vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) {
+//   Assert(isSorted(monos));
+//   vector<Monomial> outMonomials;
+//   typedef vector<Monomial>::const_iterator iterator;
+//   for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) {
+//     Rational constant = (*rangeIter).getConstant().getValue();
+//     VarList varList  = (*rangeIter).getVarList();
+//     ++rangeIter;
+//     while(rangeIter != end && varList == (*rangeIter).getVarList()) {
+//       constant += (*rangeIter).getConstant().getValue();
+//       ++rangeIter;
+//     }
+//     if(constant != 0) {
+//       Constant asConstant = Constant::mkConstant(constant);
+//       Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
+//       outMonomials.push_back(nonZero);
+//     }
+//   }
+
+//   Assert(isStrictlySorted(outMonomials));
+//   return outMonomials;
+// }
+
+void Monomial::sort(std::vector<Monomial>& m){
+  if(!isSorted(m)){
+    std::sort(m.begin(), m.end());
+  }
+}
+
+void Monomial::combineAdjacentMonomials(std::vector<Monomial>& monos) {
   Assert(isSorted(monos));
-  vector<Monomial> outMonomials;
-  typedef vector<Monomial>::const_iterator iterator;
-  for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) {
-    Rational constant = (*rangeIter).getConstant().getValue();
-    VarList varList  = (*rangeIter).getVarList();
-    ++rangeIter;
-    while(rangeIter != end && varList == (*rangeIter).getVarList()) {
-      constant += (*rangeIter).getConstant().getValue();
-      ++rangeIter;
+  size_t writePos, readPos, N;
+  for(writePos = 0, readPos = 0, N = monos.size(); readPos < N;){
+    Monomial& atRead = monos[readPos];
+    const VarList& varList  = atRead.getVarList();
+
+    size_t rangeEnd = readPos+1;
+    for(; rangeEnd < N; rangeEnd++){
+      if(!(varList == monos[rangeEnd].getVarList())){ break; }
     }
-    if(constant != 0) {
-      Constant asConstant = Constant::mkConstant(constant);
-      Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
-      outMonomials.push_back(nonZero);
+    // monos[i] for i in [readPos, rangeEnd) has the same var list
+    if(readPos+1 == rangeEnd){ // no addition needed
+      if(!atRead.getConstant().isZero()){
+        Monomial cpy = atRead; // being paranoid here
+        monos[writePos] = cpy;
+        writePos++;
+      }
+    }else{
+      Rational constant(monos[readPos].getConstant().getValue());
+      for(size_t i=readPos+1; i < rangeEnd; ++i){
+        constant += monos[i].getConstant().getValue();
+      }
+      if(!constant.isZero()){
+        Constant asConstant = Constant::mkConstant(constant);
+        Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
+        monos[writePos] = nonZero;
+        writePos++;
+      }
     }
+    Assert(rangeEnd>readPos);
+    readPos = rangeEnd;
   }
-
-  Assert(isStrictlySorted(outMonomials));
-  return outMonomials;
+  if(writePos > 0 ){
+    Monomial cp = monos[0];
+    Assert(writePos <= N);
+    monos.resize(writePos, cp);
+  }else{
+    monos.clear();
+  }
+  Assert(isStrictlySorted(monos));
 }
 
 void Monomial::print() const {
@@ -199,12 +292,56 @@ Polynomial Polynomial::operator+(const Polynomial& vl) const {
   std::vector<Monomial> sortedMonos;
   merge_ranges(begin(), end(), vl.begin(), vl.end(), sortedMonos);
 
-  std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos);
+  Monomial::combineAdjacentMonomials(sortedMonos);
+  //std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos);
 
-  Polynomial result = mkPolynomial(combined);
+  Polynomial result = mkPolynomial(sortedMonos);
   return result;
 }
 
+
+Polynomial Polynomial::sumPolynomials(const std::vector<Polynomial>& ps){
+  if(ps.empty()){
+    return mkZero();
+  }else if(ps.size() <= 4){
+    // if there are few enough polynomials just add them
+    Polynomial p = ps[0];
+    for(size_t i = 1; i < ps.size(); ++i){
+      p = p + ps[i];
+    }
+    return p;
+  }else{
+    // general case
+    std::map<Node, Rational> coeffs;
+    for(size_t i = 0, N = ps.size(); i<N; ++i){
+      const Polynomial& p = ps[i];
+      for(iterator pi = p.begin(), pend = p.end(); pi != pend; ++pi) {
+        Monomial m = *pi;
+        coeffs[m.getVarList().getNode()] += m.getConstant().getValue();
+      }
+    }
+    std::vector<Monomial> monos;
+    std::map<Node, Rational>::const_iterator ci = coeffs.begin(), cend = coeffs.end();
+    for(; ci != cend; ++ci){
+      if(!(*ci).second.isZero()){
+        Constant c = Constant::mkConstant((*ci).second);
+        Node n = (*ci).first;
+        VarList vl = VarList::parseVarList(n);
+        if(vl.empty()){
+          monos.push_back(Monomial(c));
+        }else{
+          monos.push_back(Monomial(c, vl));
+        }
+      }
+    }
+    Monomial::sort(monos);
+    Monomial::combineAdjacentMonomials(monos);
+
+    Polynomial result = mkPolynomial(monos);
+    return result;
+  }
+}
+
 Polynomial Polynomial::operator-(const Polynomial& vl) const {
   Constant negOne = Constant::mkConstant(Rational(-1));
 
@@ -257,7 +394,7 @@ Polynomial Polynomial::operator*(const Monomial& mono) const {
     // Suppose this = (+ x y), mono = x, (* x y).getId() < (* x x).getId()
     // newMonos = <(* x x), (* x y)> after this loop.
     // This is not sorted according to the current VarList order.
-    std::sort(newMonos.begin(), newMonos.end());
+    Monomial::sort(newMonos);
     return Polynomial::mkPolynomial(newMonos);
   }
 }
@@ -281,7 +418,7 @@ Monomial Polynomial::selectAbsMinimum() const {
   ++iter;
   for(; iter != end(); ++iter){
     Monomial curr = *iter;
-    if(curr.absLessThan(min)){
+    if(curr.absCmp(min) < 0){
       min = curr;
     }
   }
@@ -315,10 +452,16 @@ Integer Polynomial::numeratorGCD() const {
   Assert(i!=e);
 
   Integer d = (*i).getConstant().getValue().getNumerator().abs();
+  if(d.isOne()){
+    return d;
+  }
   ++i;
   for(; i!=e; ++i){
     Integer c = (*i).getConstant().getValue().getNumerator();
     d = d.gcd(c);
+    if(d.isOne()){
+      return d;
+    }
   }
   return d;
 }
@@ -615,6 +758,22 @@ bool Comparison::rightIsConstant() const {
   }
 }
 
+size_t Comparison::getComplexity() const{
+  switch(comparisonKind()){
+  case kind::CONST_BOOLEAN: return 1;
+  case kind::LT:
+  case kind::LEQ:
+  case kind::DISTINCT:
+  case kind::EQUAL:
+  case kind::GT:
+  case kind::GEQ:
+    return getLeft().getComplexity() +  getRight().getComplexity();
+  default:
+    Unhandled(comparisonKind());
+    return -1;
+  }
+}
+
 Polynomial Comparison::getLeft() const {
   TNode left;
   Kind k = comparisonKind();
@@ -804,10 +963,10 @@ bool Comparison::isNormalEqualityOrDisequality() const {
           }else{
             Monomial absMinRight = varRight.selectAbsMinimum();
             Debug("nf::tmp") << mleft.getNode() << " " << absMinRight.getNode() << endl;
-            if( mleft.absLessThan(absMinRight) ){
+            if( mleft.absCmp(absMinRight) < 0){
               return true;
             }else{
-              return (!absMinRight.absLessThan(mleft)) && mleft < absMinRight;
+              return (!(absMinRight.absCmp(mleft)< 0)) && mleft < absMinRight;
             }
           }
         }
index cd5f047b5965ee523a8cf34a952e499ebbf7b5c8..f098d8b54fe40bc1c79c2ae7dabf52ae4951b83b 100644 (file)
@@ -23,8 +23,8 @@
 #include "expr/node.h"
 #include "expr/node_self_iterator.h"
 #include "util/rational.h"
-#include "theory/theory.h"
-#include "theory/arith/arith_utilities.h"
+#include "theory/arith/delta_rational.h"
+//#include "theory/arith/arith_utilities.h"
 
 #include <list>
 #include <algorithm>
@@ -247,11 +247,11 @@ public:
       // by a variable.
       return true;
     default:
-      return (!isRelationOperator(k)) &&
-        (Theory::isLeafOf(n, theory::THEORY_ARITH));
+      return isLeafMember(n);
     }
   }
 
+  static bool isLeafMember(Node n);
   static bool isDivMember(Node n);
   bool isDivLike() const{
     return isDivMember(getNode());
@@ -286,6 +286,7 @@ public:
 
   bool operator==(const Variable& v) const { return getNode() == v.getNode();}
 
+  size_t getComplexity() const;
 };/* class Variable */
 
 
@@ -306,9 +307,7 @@ public:
     return Constant(n);
   }
 
-  static Constant mkConstant(const Rational& rat) {
-    return Constant(mkRationalNode(rat));
-  }
+  static Constant mkConstant(const Rational& rat);
 
   static Constant mkZero() {
     return mkConstant(Rational(0));
@@ -322,6 +321,7 @@ public:
     return getNode().getConst<Rational>();
   }
 
+  static int absCmp(const Constant& a, const Constant& b);
   bool isIntegral() const { return getValue().isIntegral(); }
 
   int sgn() const { return getValue().sgn(); }
@@ -373,6 +373,8 @@ public:
     return getValue().getNumerator().length();
   }
 
+  size_t getComplexity() const;
+
 };/* class Constant */
 
 
@@ -563,6 +565,7 @@ public:
     }
     return true;
   }
+  size_t getComplexity() const;
 
 private:
   bool isSorted(iterator start, iterator end);
@@ -687,6 +690,9 @@ public:
     return isSorted(m) && std::adjacent_find(m.begin(),m.end()) == m.end();
   }
 
+  static void sort(std::vector<Monomial>& m);
+  static void combineAdjacentMonomials(std::vector<Monomial>& m);
+
   /**
    * The variable product
    */
@@ -717,11 +723,14 @@ public:
    * Given a sorted list of monomials, this function transforms this
    * into a strictly sorted list of monomials that does not contain zero.
    */
-  static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
+  //static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
 
-  bool absLessThan(const Monomial& other) const{
-    return getConstant().abs() < other.getConstant().abs();
+  int absCmp(const Monomial& other) const{
+    return getConstant().getValue().absCmp(other.getConstant().getValue());
   }
+  // bool absLessThan(const Monomial& other) const{
+  //   return getConstant().abs() < other.getConstant().abs();
+  // }
 
   uint32_t coefficientLength() const{
     return getConstant().length();
@@ -730,6 +739,7 @@ public:
   void print() const;
   static void printList(const std::vector<Monomial>& list);
 
+  size_t getComplexity() const;
 };/* class Monomial */
 
 class SumPair;
@@ -938,9 +948,12 @@ public:
     return true;
   }
 
+  static Polynomial sumPolynomials(const std::vector<Polynomial>& polynomials);
+
   /** Returns true if the polynomial contains a non-linear monomial.*/
   bool isNonlinear() const;
 
+
   /**
    * Selects a minimal monomial in the polynomial by the absolute value of
    * the coefficient.
@@ -1058,6 +1071,8 @@ public:
     return getHead().getVarList();
   }
 
+  size_t getComplexity() const;
+
   friend class SumPair;
   friend class Comparison;
 
@@ -1173,6 +1188,10 @@ public:
     return getConstant().isZero() && isConstant();
   }
 
+  uint32_t size() const{
+    return getPolynomial().size();
+  }
+
   bool isNonlinear() const{
     return getPolynomial().isNonlinear();
   }
@@ -1368,6 +1387,8 @@ public:
     return parse.isNormalForm();
   }
 
+  size_t getComplexity() const;
+
   SumPair toSumPair() const;
 
   Polynomial normalizedVariablePart() const;
index 3fc08e18e18fd41b535667a3b32ae1669f9559a9..cf35265d6d07034fd569329a53197761921ee2df 100644 (file)
@@ -85,8 +85,11 @@ option restrictedPivots --restrict-pivots bool :default true :read-write
 option collectPivots --collect-pivot-stats bool :default false :read-write
  collect the pivot history
 
-option fancyFinal --fancy-final bool :default false :read-write
- tuning how final check works for really hard problems
+option useApprox --use-approx bool :default false :read-write
+ attempt to use an approximate solver
+
+option maxApproxDepth --approx-branch-depth int16_t :default 200 :read-write
+ maximum branch depth the approximate solver is allowed to take
 
 option exportDioDecompositions --dio-decomps bool :default false :read-write
  let skolem variables for integer divisibility constraints leak from the dio solver
@@ -103,4 +106,46 @@ option soiQuickExplain --soi-qe bool :default false :read-write
 option rewriteDivk rewrite-divk --rewrite-divk bool :default false :read-write
  rewrite division and mod when by a constant into linear terms
 
+option trySolveIntStandardEffort --se-solve-int bool :default false
+ attempt to use the approximate solve integer method on standard effort
+
+option replayFailureLemma --lemmas-on-replay-failure bool :default false
+ attempt to use external lemmas if approximate solve integer failed
+
+option dioSolverTurns --dio-turns int :default 10
+ turns in a row dio solver cutting gets
+
+option rrTurns --rr-turns int :default 3
+ round robin turn
+
+option dioRepeat --dio-repeat bool :default false
+ handle dio solver constraints in mass or one at a time
+
+option replayEarlyCloseDepths --replay-early-close-depth int :default 1
+ multiples of the depths to try to close the approx log eagerly
+
+option replayFailurePenalty --replay-failure-penalty int :default 100
+ number of solve integer attempts to skips after a numeric failure
+
+option replayNumericFailurePenalty --replay-num-err-penalty int :default 4194304
+ number of solve integer attempts to skips after a numeric failure
+
+option replayRejectCutSize --replay-reject-cut unsigned :default 25500
+ maximum complexity of any coefficient while replaying cuts
+
+option lemmaRejectCutSize --replay-lemma-reject-cut unsigned :default 25500
+ maximum complexity of any coefficient while outputing replaying cut lemmas
+
+option soiApproxMajorFailure --replay-soi-major-threshold double :default .01
+ threshold for a major tolerance failure by the approximate solver
+
+option soiApproxMajorFailurePen --replay-soi-major-threshold-pen int :default 50
+ threshold for a major tolerance failure by the approximate solver
+
+option soiApproxMinorFailure --replay-soi-minor-threshold double :default .0001
+ threshold for a minor tolerance failure by the approximate solver
+
+option soiApproxMinorFailurePen --replay-soi-minor-threshold-pen int :default 10
+ threshold for a minor tolerance failure by the approximate solver
+
 endmodule
index 3fae3751c49f8e4cdb748709846095ba00b5a5ce..8f08de36ca9554cecf671e678fc04d08188c51ff 100644 (file)
@@ -33,7 +33,6 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
    d_numberOfVariables(0),
    d_pool(),
    d_released(),
-   d_releasedIterator(d_released.begin()),
    d_nodeToArithVarMap(),
    d_boundsQueue(),
    d_enqueueingBoundCounts(true),
@@ -44,6 +43,87 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
    d_deltaComputingFunc(deltaComputingFunc)
 { }
 
+ArithVar ArithVariables::getNumberOfVariables() const {
+  return d_numberOfVariables;
+}
+
+
+bool ArithVariables::hasArithVar(TNode x) const {
+  return d_nodeToArithVarMap.find(x) != d_nodeToArithVarMap.end();
+}
+
+bool ArithVariables::hasNode(ArithVar a) const {
+  return d_vars.isKey(a);
+}
+
+ArithVar ArithVariables::asArithVar(TNode x) const{
+  Assert(hasArithVar(x));
+  Assert((d_nodeToArithVarMap.find(x))->second <= ARITHVAR_SENTINEL);
+  return (d_nodeToArithVarMap.find(x))->second;
+}
+
+Node ArithVariables::asNode(ArithVar a) const{
+  Assert(hasNode(a));
+  return d_vars[a].d_node;
+}
+
+ArithVariables::var_iterator::var_iterator()
+  : d_vars(NULL)
+  , d_wrapped()
+{}
+
+ArithVariables::var_iterator::var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci)
+  : d_vars(vars), d_wrapped(ci)
+{
+  nextInitialized();
+}
+
+ArithVariables::var_iterator& ArithVariables::var_iterator::operator++(){
+  ++d_wrapped;
+  nextInitialized();
+  return *this;
+}
+bool ArithVariables::var_iterator::operator==(const ArithVariables::var_iterator& other) const{
+  return d_wrapped == other.d_wrapped;
+}
+bool ArithVariables::var_iterator::operator!=(const ArithVariables::var_iterator& other) const{
+  return d_wrapped != other.d_wrapped;
+}
+ArithVar ArithVariables::var_iterator::operator*() const{
+  return *d_wrapped;
+}
+
+void ArithVariables::var_iterator::nextInitialized(){
+  VarInfoVec::const_iterator end = d_vars->end();
+  while(d_wrapped != end &&
+        !((*d_vars)[*d_wrapped].initialized())){
+    ++d_wrapped;
+  }
+}
+
+ArithVariables::var_iterator ArithVariables::var_begin() const {
+  return var_iterator(&d_vars, d_vars.begin());
+}
+
+ArithVariables::var_iterator ArithVariables::var_end() const {
+  return var_iterator(&d_vars, d_vars.end());
+}
+bool ArithVariables::isInteger(ArithVar x) const {
+  return d_vars[x].d_type >= ATInteger;
+}
+
+/** Is the assignment to x integral? */
+bool ArithVariables::integralAssignment(ArithVar x) const {
+  return getAssignment(x).isIntegral();
+}
+bool ArithVariables::isAuxiliary(ArithVar x) const {
+  return d_vars[x].d_auxiliary;
+}
+
+bool ArithVariables::isIntegerInput(ArithVar x) const {
+  return isInteger(x) && !isAuxiliary(x);
+}
+
 ArithVariables::VarInfo::VarInfo()
   : d_var(ARITHVAR_SENTINEL),
     d_assignment(0),
@@ -53,14 +133,14 @@ ArithVariables::VarInfo::VarInfo()
     d_cmpAssignmentUB(-1),
     d_pushCount(0),
     d_node(Node::null()),
-    d_slack(false)
+    d_auxiliary(false)
 { }
 
 bool ArithVariables::VarInfo::initialized() const {
   return d_var != ARITHVAR_SENTINEL;
 }
 
-void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
+void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool aux){
   Assert(!initialized());
   Assert(d_lb == NullConstraint);
   Assert(d_ub == NullConstraint);
@@ -68,9 +148,9 @@ void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
   Assert(d_cmpAssignmentUB < 0);
   d_var = v;
   d_node = n;
-  d_slack = slack;
+  d_auxiliary = aux;
 
-  if(d_slack){
+  if(d_auxiliary){
     //The type computation is not quite accurate for Rationals that are
     //integral.
     //We'll use the isIntegral check from the polynomial package instead.
@@ -112,6 +192,10 @@ bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundsInfo&
 
 void ArithVariables::releaseArithVar(ArithVar v){
   VarInfo& vi = d_vars.get(v);
+
+  size_t removed CVC4_UNUSED = d_nodeToArithVarMap.erase(vi.d_node);
+  Assert(removed == 1);
+
   vi.uninitialize();
 
   if(d_safeAssignment.isKey(v)){
@@ -124,7 +208,7 @@ void ArithVariables::releaseArithVar(ArithVar v){
   }
 }
 
-bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
+bool ArithVariables::VarInfo::setUpperBound(ConstraintP ub, BoundsInfo& prev){
   Assert(initialized());
   bool wasNull = d_ub == NullConstraint;
   bool isNull = ub == NullConstraint;
@@ -140,7 +224,7 @@ bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
   return ubChanged;
 }
 
-bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundsInfo& prev){
+bool ArithVariables::VarInfo::setLowerBound(ConstraintP lb, BoundsInfo& prev){
   Assert(initialized());
   bool wasNull = d_lb == NullConstraint;
   bool isNull = lb == NullConstraint;
@@ -177,23 +261,22 @@ bool ArithVariables::VarInfo::canBeReclaimed() const{
   return d_pushCount == 0;
 }
 
+bool ArithVariables::canBeReleased(ArithVar v) const{
+  return d_vars[v].canBeReclaimed();
+}
+
 void ArithVariables::attemptToReclaimReleased(){
-  std::list<ArithVar>::iterator i_end = d_released.end();
-  for(int iter = 0; iter < 20 && d_releasedIterator != i_end; ++d_releasedIterator){
-    ArithVar v = *d_releasedIterator;
-    VarInfo& vi = d_vars.get(v);
-    if(vi.canBeReclaimed()){
+  size_t readPos = 0, writePos = 0, N = d_released.size();
+  for(; readPos < N; ++readPos){
+    ArithVar v = d_released[readPos];
+    if(canBeReleased(v)){
       d_pool.push_back(v);
-      std::list<ArithVar>::iterator curr = d_releasedIterator;
-      ++d_releasedIterator;
-      d_released.erase(curr);
     }else{
-      ++d_releasedIterator;
+      d_released[writePos] = v;
+      writePos++;
     }
   }
-  if(d_releasedIterator == i_end){
-    d_releasedIterator = d_released.begin();
-  }
+  d_released.resize(writePos);
 }
 
 ArithVar ArithVariables::allocateVariable(){
@@ -232,6 +315,21 @@ bool ArithVariables::boundsAreEqual(ArithVar x) const{
   }
 }
 
+
+std::pair<ConstraintP, ConstraintP> ArithVariables::explainEqualBounds(ArithVar x) const{
+  Assert(boundsAreEqual(x));
+
+  ConstraintP lb = getLowerBoundConstraint(x);
+  ConstraintP ub = getUpperBoundConstraint(x);
+  if(lb->isEquality()){
+    return make_pair(lb, NullConstraint);
+  }else if(ub->isEquality()){
+    return make_pair(ub, NullConstraint);
+  }else{
+    return make_pair(lb, ub);
+  }
+}
+
 void ArithVariables::setAssignment(ArithVar x, const DeltaRational& r){
   Debug("partial_model") << "pm: updating the assignment to" << x
                          << " now " << r <<endl;
@@ -266,15 +364,15 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& safe, const
   }
 }
 
-void ArithVariables::initialize(ArithVar x, Node n, bool slack){
+void ArithVariables::initialize(ArithVar x, Node n, bool aux){
   VarInfo& vi = d_vars.get(x);
-  vi.initialize(x, n, slack);
+  vi.initialize(x, n, aux);
   d_nodeToArithVarMap[n] = x;
 }
 
-ArithVar ArithVariables::allocate(Node n, bool slack){
+ArithVar ArithVariables::allocate(Node n, bool aux){
   ArithVar v = allocateVariable();
-  initialize(v, n, slack);
+  initialize(v, n, aux);
   return v;
 }
 
@@ -333,7 +431,7 @@ const DeltaRational& ArithVariables::getAssignment(ArithVar x) const{
 }
 
 
-void ArithVariables::setLowerBoundConstraint(Constraint c){
+void ArithVariables::setLowerBoundConstraint(ConstraintP c){
   AssertArgument(c != NullConstraint, "Cannot set a lower bound to NullConstraint.");
   AssertArgument(c->isEquality() || c->isLowerBound(),
                  "Constraint type must be set to an equality or UpperBound.");
@@ -351,7 +449,7 @@ void ArithVariables::setLowerBoundConstraint(Constraint c){
   }
 }
 
-void ArithVariables::setUpperBoundConstraint(Constraint c){
+void ArithVariables::setUpperBoundConstraint(ConstraintP c){
   AssertArgument(c != NullConstraint, "Cannot set a upper bound to NullConstraint.");
   AssertArgument(c->isEquality() || c->isUpperBound(),
                  "Constraint type must be set to an equality or UpperBound.");
@@ -450,6 +548,14 @@ void ArithVariables::commitAssignmentChanges(){
   clearSafeAssignments(false);
 }
 
+bool ArithVariables::lowerBoundIsZero(ArithVar x){
+  return hasLowerBound(x) && getLowerBound(x).sgn() == 0;
+}
+
+bool ArithVariables::upperBoundIsZero(ArithVar x){
+  return hasUpperBound(x) && getUpperBound(x).sgn() == 0;
+}
+
 void ArithVariables::printEntireModel(std::ostream& out) const{
   out << "---Printing Model ---" << std::endl;
   for(var_iterator i = var_begin(), iend = var_end(); i != iend; ++i){
@@ -474,6 +580,10 @@ void ArithVariables::printModel(ArithVar x, std::ostream& out) const{
     out << getUpperBound(x) << " ";
     out << getUpperBoundConstraint(x) << " ";
   }
+
+  if(isInteger(x) && !integralAssignment(x)){
+    out << "(not an integer)" << endl;
+  }
   out << endl;
 }
 
@@ -540,10 +650,36 @@ void ArithVariables::processBoundsQueue(BoundUpdateCallback& changed){
   }
 }
 
+void ArithVariables::invalidateDelta() {
+  d_deltaIsSafe = false;
+}
+
+void ArithVariables::setDelta(const Rational& d){
+  d_delta = d;
+  d_deltaIsSafe = true;
+}
+
+void ArithVariables::startQueueingBoundCounts(){
+  d_enqueueingBoundCounts = true;
+}
+void ArithVariables::stopQueueingBoundCounts(){
+  d_enqueueingBoundCounts = false;
+}
+
+bool ArithVariables::inMaps(ArithVar x) const{
+  return x < getNumberOfVariables();
+}
+
+ArithVariables::LowerBoundCleanUp::LowerBoundCleanUp(ArithVariables* pm)
+  : d_pm(pm)
+{}
 void ArithVariables::LowerBoundCleanUp::operator()(AVCPair* p){
   d_pm->popLowerBound(p);
 }
 
+ArithVariables::UpperBoundCleanUp::UpperBoundCleanUp(ArithVariables* pm)
+  : d_pm(pm)
+{}
 void ArithVariables::UpperBoundCleanUp::operator()(AVCPair* p){
   d_pm->popUpperBound(p);
 }
index c497adb75fbd03cbbc15a5b496dbd9ea9cc8ac22..33af3d4efb35c5d93782e905b1ae546ad5ec25ea 100644 (file)
@@ -9,10 +9,11 @@
  ** See the file COPYING in the top-level source directory for licensing
  ** information.\endverbatim
  **
- ** \brief [[ Add one-line brief description here ]]
+ ** \brief Datastructures that track variable by variable information.
  **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** This is a datastructure that tracks variable specific information.
+ ** This is partially context dependent to back track upper/lower bounds
+ ** and information derived from these.
  **/
 
 #include "cvc4_private.h"
@@ -50,40 +51,44 @@ private:
     ArithVar d_var;
 
     DeltaRational d_assignment;
-    Constraint d_lb;
-    Constraint d_ub;
+    ConstraintP d_lb;
+    ConstraintP d_ub;
     int d_cmpAssignmentLB;
     int d_cmpAssignmentUB;
 
     unsigned d_pushCount;
     ArithType d_type;
     Node d_node;
-    bool d_slack;
+    bool d_auxiliary;
 
   public:
     VarInfo();
 
     bool setAssignment(const DeltaRational& r, BoundsInfo& prev);
-    bool setLowerBound(Constraint c, BoundsInfo& prev);
-    bool setUpperBound(Constraint c, BoundsInfo& prev);
+    bool setLowerBound(ConstraintP c, BoundsInfo& prev);
+    bool setUpperBound(ConstraintP c, BoundsInfo& prev);
 
     /** Returns true if this VarInfo has been initialized. */
     bool initialized() const;
 
     /**
      * Initializes the VarInfo with the ArithVar index it is associated with,
-     * the node that the variable represents, and whether it is a slack variable.
+     * the node that the variable represents, and whether it is an auxillary
+     * variable.
      */
-    void initialize(ArithVar v, Node n, bool slack);
+    void initialize(ArithVar v, Node n, bool aux);
+
     /** Uninitializes the VarInfo. */
     void uninitialize();
 
     bool canBeReclaimed() const;
 
-    /** Indicator variables for if the assignment is equal to the upper and lower bounds. */
+    /** Indicator variables for if the assignment is equal to the upper
+     * and lower bounds. */
     BoundCounts atBoundCounts() const;
 
-    /** Combination of indicator variables for whether it has upper and lower bounds.  */
+    /** Combination of indicator variables for whether it has upper and
+     * lower bounds.  */
     BoundCounts hasBoundCounts() const;
 
     /** Stores both atBoundCounts() and hasBoundCounts().  */
@@ -92,21 +97,22 @@ private:
 
   /**Maps from ArithVar -> VarInfo */
   typedef DenseMap<VarInfo> VarInfoVec;
+
   /** This maps an ArithVar to its Variable information.*/
   VarInfoVec d_vars;
 
-  // Partial Map from Arithvar -> PreviousAssignment
+  /** Partial Map from Arithvar -> PreviousAssignment */
   DenseMap<DeltaRational> d_safeAssignment;
 
-  // if d_vars.isKey(x), then x < d_numberOfVariables
+  /** if d_vars.isKey(x), then x < d_numberOfVariables */
   ArithVar d_numberOfVariables;
 
   /** [0, d_numberOfVariables) \intersect d_vars.keys == d_pool */
   // Everything in the pool is fair game.
   // There must be NO outstanding assertions
   std::vector<ArithVar> d_pool;
-  std::list<ArithVar> d_released;
-  std::list<ArithVar>::iterator d_releasedIterator;
+  std::vector<ArithVar> d_released;
+  //std::list<ArithVar>::iterator d_releasedIterator;
 
   // Reverse Map from Node to ArithVar
   // Inverse of d_vars[x].d_node
@@ -118,36 +124,29 @@ private:
 
   /**
    * If this is true, record the incoming changes to the bound information.
-   * If this is false, the responsibility of recording the changes is LinearEqualities's.
+   * If this is false, the responsibility of recording the changes is
+   * LinearEqualities's.
    */
   bool d_enqueueingBoundCounts;
 
  public:
 
-  inline ArithVar getNumberOfVariables() const {
-    return d_numberOfVariables;
-  }
+  /** Returns the number of variables. */
+  ArithVar getNumberOfVariables() const;
 
-  inline bool hasArithVar(TNode x) const {
-    return d_nodeToArithVarMap.find(x) != d_nodeToArithVarMap.end();
-  }
+  /** Returns true if the node has an associated variables. */
+  bool hasArithVar(TNode x) const;
 
-  inline bool hasNode(ArithVar a) const {
-    return d_vars.isKey(a);
-  }
-
-  inline ArithVar asArithVar(TNode x) const{
-    Assert(hasArithVar(x));
-    Assert((d_nodeToArithVarMap.find(x))->second <= ARITHVAR_SENTINEL);
-    return (d_nodeToArithVarMap.find(x))->second;
-  }
+  /** Returns true if the variable has a defining node. */
+  bool hasNode(ArithVar a) const;
 
+  /** Returns the ArithVar associated with a node. */
+  ArithVar asArithVar(TNode x) const;
 
-  inline Node asNode(ArithVar a) const{
-    Assert(hasNode(a));
-    return d_vars[a].d_node;
-  }
+  /** Returns the node associated with an ArithVar. */
+  Node asNode(ArithVar a) const;
 
+  /** Allocates a freshly allocated variables. */
   ArithVar allocateVariable();
 
   class var_iterator {
@@ -155,68 +154,47 @@ private:
     const VarInfoVec* d_vars;
     VarInfoVec::const_iterator d_wrapped;
   public:
-    var_iterator(){}
-    var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci)
-      : d_vars(vars), d_wrapped(ci)
-    {
-      nextInitialized();
-    }
-
-    var_iterator& operator++(){
-      ++d_wrapped;
-      nextInitialized();
-      return *this;
-    }
-    bool operator==(const var_iterator& other) const{
-      return d_wrapped == other.d_wrapped;
-    }
-    bool operator!=(const var_iterator& other) const{
-      return d_wrapped != other.d_wrapped;
-    }
-    ArithVar operator*() const{
-      return *d_wrapped;
-    }
+    var_iterator();
+    var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci);
+    var_iterator& operator++();
+
+    bool operator==(const var_iterator& other) const;
+    bool operator!=(const var_iterator& other) const;
+    ArithVar operator*() const;
+
   private:
-    void nextInitialized(){
-      VarInfoVec::const_iterator end = d_vars->end();
-      while(d_wrapped != end &&
-            !((*d_vars)[*d_wrapped].initialized())){
-        ++d_wrapped;
-      }
-    }
+    void nextInitialized();
   };
-  var_iterator var_begin() const {
-    return var_iterator(&d_vars, d_vars.begin());
-  }
 
-  var_iterator var_end() const {
-    return var_iterator(&d_vars, d_vars.end());
-  }
+  var_iterator var_begin() const;
+  var_iterator var_end() const;
 
 
   bool canBeReleased(ArithVar v) const;
   void releaseArithVar(ArithVar v);
   void attemptToReclaimReleased();
 
-  bool isInteger(ArithVar x) const {
-    return d_vars[x].d_type >= ATInteger;
-  }
-  bool isSlack(ArithVar x) const {
-    return d_vars[x].d_slack;
-  }
+  /** Is this variable guaranteed to have an integer assignment?
+   * (Should agree with the type system.) */
+  bool isInteger(ArithVar x) const;
 
-  bool integralAssignment(ArithVar x) const {
-    return getAssignment(x).isIntegral();
-  }
+  /** Is the assignment to x integral? */
+  bool integralAssignment(ArithVar x) const;
+
+  /* Is this variable defined as a linear sum of other variables? */
+  bool isAuxiliary(ArithVar x) const;
+
+  /* Is the variable both input and not auxiliary? */
+  bool isIntegerInput(ArithVar x) const;
 
  private:
 
-  typedef std::pair<ArithVar, Constraint> AVCPair;
+  typedef std::pair<ArithVar, ConstraintP> AVCPair;
   class LowerBoundCleanUp {
   private:
     ArithVariables* d_pm;
   public:
-    LowerBoundCleanUp(ArithVariables* pm) : d_pm(pm) {}
+    LowerBoundCleanUp(ArithVariables* pm);
     void operator()(AVCPair* restore);
   };
 
@@ -224,7 +202,7 @@ private:
   private:
     ArithVariables* d_pm;
   public:
-    UpperBoundCleanUp(ArithVariables* pm) : d_pm(pm) {}
+    UpperBoundCleanUp(ArithVariables* pm);
     void operator()(AVCPair* restore);
   };
 
@@ -255,27 +233,27 @@ public:
    * This sets the lower bound for a variable in the current context.
    * This must be stronger the previous constraint.
    */
-  void setLowerBoundConstraint(Constraint lb);
+  void setLowerBoundConstraint(ConstraintP lb);
 
   /**
    * This sets the upper bound for a variable in the current context.
    * This must be stronger the previous constraint.
    */
-  void setUpperBoundConstraint(Constraint ub);
+  void setUpperBoundConstraint(ConstraintP ub);
 
   /** Returns the constraint for the upper bound of a variable. */
-  inline Constraint getUpperBoundConstraint(ArithVar x) const{
+  inline ConstraintP getUpperBoundConstraint(ArithVar x) const{
     return d_vars[x].d_ub;
   }
   /** Returns the constraint for the lower bound of a variable. */
-  inline Constraint getLowerBoundConstraint(ArithVar x) const{
+  inline ConstraintP getLowerBoundConstraint(ArithVar x) const{
     return d_vars[x].d_lb;
   }
 
   /* Initializes a variable to a safe value.*/
-  void initialize(ArithVar x, Node n, bool slack);
+  void initialize(ArithVar x, Node n, bool aux);
 
-  ArithVar allocate(Node n, bool slack = false);
+  ArithVar allocate(Node n, bool aux = false);
 
   /* Gets the last assignment to a variable that is known to be consistent. */
   const DeltaRational& getSafeAssignment(ArithVar x) const;
@@ -288,13 +266,8 @@ public:
   void commitAssignmentChanges();
 
 
-  inline bool lowerBoundIsZero(ArithVar x){
-    return hasLowerBound(x) && getLowerBound(x).sgn() == 0;
-  }
-
-  inline bool upperBoundIsZero(ArithVar x){
-    return hasUpperBound(x) && getUpperBound(x).sgn() == 0;
-  }
+  bool lowerBoundIsZero(ArithVar x);
+  bool upperBoundIsZero(ArithVar x);
 
   bool boundsAreEqual(ArithVar x) const;
 
@@ -393,17 +366,12 @@ public:
 
   const Rational& getDelta();
 
-  inline void invalidateDelta() {
-    d_deltaIsSafe = false;
-  }
+  void invalidateDelta();
 
-  void setDelta(const Rational& d){
-    d_delta = d;
-    d_deltaIsSafe = true;
-  }
+  void setDelta(const Rational& d);
 
-  void startQueueingBoundCounts(){ d_enqueueingBoundCounts = true; }
-  void stopQueueingBoundCounts(){ d_enqueueingBoundCounts = false; }
+  void startQueueingBoundCounts();
+  void stopQueueingBoundCounts();
   void addToBoundQueue(ArithVar v, const BoundsInfo& prev);
 
   BoundsInfo selectBoundsInfo(ArithVar v, bool old) const;
@@ -413,6 +381,15 @@ public:
 
   void printEntireModel(std::ostream& out) const;
 
+
+  /**
+   * Precondition: assumes boundsAreEqual(x).
+   * If the either the lower/ upper bound is an equality, eq,
+   * this returns make_pair(eq, NullConstraint).
+   * Otherwise, this returns make_pair(lb, ub).
+   */
+  std::pair<ConstraintP, ConstraintP> explainEqualBounds(ArithVar x) const;
+
 private:
 
   /**
@@ -423,9 +400,7 @@ private:
 
   bool debugEqualSizes();
 
-  bool inMaps(ArithVar x) const{
-    return x < getNumberOfVariables();
-  }
+  bool inMaps(ArithVar x) const;
 
 };/* class ArithVariables */
 
index a160f4fe262ed59d094023dac69b8617a0aaf3cb..e67f4b9fcf3d8aaed94c3fcbfe61bda2d6757889 100644 (file)
@@ -77,35 +77,40 @@ bool SimplexDecisionProcedure::standardProcessSignals(TimerStat &timer, IntStat&
 void SimplexDecisionProcedure::reportConflict(ArithVar basic){
   Assert(!d_conflictVariables.isMember(basic));
   Assert(checkBasicForConflict(basic));
-  Node conflict = generateConflictForBasic(basic);
+  RaiseConflict rc( d_conflictChannel);
 
-  static bool verbose = false;
-  if(verbose) { Message() << "conflict " << basic << " " << conflict << endl; }
-  Assert(!conflict.isNull());
-  d_conflictChannel(conflict);
+  generateConflictForBasic(basic, rc);
+
+  // static bool verbose = false;
+  // if(verbose) { Message() << "conflict " << basic << " " << conflict << endl; }
+  // Assert(!conflict.isNull());
+  //d_conflictChannel(conflict);
+  rc.commitConflict();
   d_conflictVariables.add(basic);
 }
 
-Node SimplexDecisionProcedure::generateConflictForBasic(ArithVar basic) const {
+void SimplexDecisionProcedure::generateConflictForBasic(ArithVar basic, RaiseConflict& rc) const {
 
   Assert(d_tableau.isBasic(basic));
   Assert(checkBasicForConflict(basic));
 
   if(d_variables.cmpAssignmentLowerBound(basic) < 0){
     Assert(d_linEq.nonbasicsAtUpperBounds(basic));
-    return d_linEq.generateConflictBelowLowerBound(basic);
+    return d_linEq.generateConflictBelowLowerBound(basic, rc);
   }else if(d_variables.cmpAssignmentUpperBound(basic) > 0){
     Assert(d_linEq.nonbasicsAtLowerBounds(basic));
-    return d_linEq.generateConflictAboveUpperBound(basic);
+    return d_linEq.generateConflictAboveUpperBound(basic, rc);
   }else{
     Unreachable();
   }
 }
-Node SimplexDecisionProcedure::maybeGenerateConflictForBasic(ArithVar basic) const {
+bool SimplexDecisionProcedure::maybeGenerateConflictForBasic(ArithVar basic) const {
   if(checkBasicForConflict(basic)){
-    return generateConflictForBasic(basic);
+    RaiseConflict rc(d_conflictChannel);
+    generateConflictForBasic(basic, rc);
+    return true;
   }else{
-    return Node::null();
+    return false;
   }
 }
 
index b61cadaf87c0b73c596b682883fd41d34f3d5aad..f545da51ea35e9f484a6ce34c74cf11d58a5748b 100644 (file)
@@ -157,16 +157,16 @@ protected:
    * If a conflict is discovered a node summarizing the conflict is returned.
    * Otherwise, Node::null() is returned.
    */
-  Node maybeGenerateConflictForBasic(ArithVar basic) const;
+  bool maybeGenerateConflictForBasic(ArithVar basic) const;
 
   /** Returns true if a tracked basic variable has a conflict on it. */
   bool checkBasicForConflict(ArithVar b) const;
 
   /**
    * If a basic variable has a conflict on its row,
-   * this produces a minimized row.
+   * this produces a minimized row on the conflict channel.
    */
-  Node generateConflictForBasic(ArithVar basic) const;
+  void generateConflictForBasic(ArithVar basic, RaiseConflict& rc) const;
 
 
   /** Gets a fresh variable from TheoryArith. */
index ba19d01b11af7c7d485df97781ae9de61a619832..416fbe745872fb2951954e9272c6c515f986efb1 100644 (file)
@@ -51,7 +51,7 @@ UpdateInfo::UpdateInfo(ArithVar nb, int dir):
   Assert(dir == 1 || dir == -1);
 }
 
-UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint c):
+UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP c):
   d_nonbasic(nb),
   d_nonbasicDirection(delta.sgn()),
   d_nonbasicDelta(delta),
@@ -65,7 +65,7 @@ UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, c
   Assert(conflict);
 }
 
-UpdateInfo UpdateInfo::conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim){
+UpdateInfo UpdateInfo::conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim){
   return UpdateInfo(true, nb, delta, r, lim);
 }
 
@@ -81,7 +81,7 @@ void UpdateInfo::updateUnbounded(const DeltaRational& delta, int ec, int f){
   Assert(!describesPivot());
   Assert(debugSgnAgreement());
 }
-void UpdateInfo::updatePureFocus(const DeltaRational& delta, Constraint c){
+void UpdateInfo::updatePureFocus(const DeltaRational& delta, ConstraintP c){
   d_limiting = c;
   d_nonbasicDelta = delta;
   d_errorsChange.clear();
@@ -93,7 +93,7 @@ void UpdateInfo::updatePureFocus(const DeltaRational& delta, Constraint c){
   Assert(debugSgnAgreement());
 }
 
-void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Constraint c){
+void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, ConstraintP c){
   d_limiting = c;
   d_nonbasicDelta = delta;
   d_errorsChange.clear();
@@ -103,7 +103,7 @@ void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Cons
   Assert(debugSgnAgreement());
 }
 
-void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Constraint c, int ec){
+void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, ConstraintP c, int ec){
   d_limiting = c;
   d_nonbasicDelta = delta;
   d_errorsChange = ec;
@@ -114,7 +114,7 @@ void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Cons
   Assert(debugSgnAgreement());
 }
 
-void UpdateInfo::witnessedUpdate(const DeltaRational& delta, Constraint c, int ec, int fd){
+void UpdateInfo::witnessedUpdate(const DeltaRational& delta, ConstraintP c, int ec, int fd){
   d_limiting = c;
   d_nonbasicDelta = delta;
   d_errorsChange = ec;
@@ -125,7 +125,7 @@ void UpdateInfo::witnessedUpdate(const DeltaRational& delta, Constraint c, int e
   Assert(debugSgnAgreement());
 }
 
-void UpdateInfo::update(const DeltaRational& delta, const Rational& r, Constraint c, int ec, int fd){
+void UpdateInfo::update(const DeltaRational& delta, const Rational& r, ConstraintP c, int ec, int fd){
   d_limiting = c;
   d_nonbasicDelta = delta;
   d_errorsChange = ec;
index 5a313e305130e0ad981bb3cc4d6ed0866b6e3462..e223bba7f496c294cafcccf70dcd0d3579414c67 100644 (file)
@@ -136,7 +136,7 @@ private:
    * - Pivot-And-Update: then this is not NullConstraint and the variable is not d_nonbasic.
    * - Update: then this is not NullConstraint and the variable is d_nonbasic.
    */
-  Constraint d_limiting;
+  ConstraintP d_limiting;
 
   WitnessImprovement d_witness;
 
@@ -150,7 +150,7 @@ private:
   }
 
   /** This private constructor allows for setting conflict to true. */
-  UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim);
+  UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim);
 
 public:
 
@@ -170,7 +170,7 @@ public:
   void updateUnbounded(const DeltaRational& d, int ec, int f);
 
 
-  void updatePureFocus(const DeltaRational& d, Constraint c);
+  void updatePureFocus(const DeltaRational& d, ConstraintP c);
   //void updatePureError(const DeltaRational& d, Constraint c, int e);
   //void updatePure(const DeltaRational& d, Constraint c, int e, int f);
 
@@ -178,23 +178,23 @@ public:
    * This updates the nonBasicDelta to d and limiting to c.
    * This clears errorChange() and focusDir().
    */
-  void updatePivot(const DeltaRational& d, const Rational& r,  Constraint c);
+  void updatePivot(const DeltaRational& d, const Rational& r,  ConstraintP c);
 
   /**
    * This updates the nonBasicDelta to d, limiting to c, and errorChange to e.
    * This clears focusDir().
    */
-  void updatePivot(const DeltaRational& d, const Rational& r, Constraint c, int e);
+  void updatePivot(const DeltaRational& d, const Rational& r, ConstraintP c, int e);
 
   /**
    * This updates the nonBasicDelta to d, limiting to c, errorChange to e and
    * focusDir to f.
    */
-  void witnessedUpdate(const DeltaRational& d, Constraint c, int e, int f);
-  void update(const DeltaRational& d, const Rational& r, Constraint c, int e, int f);
+  void witnessedUpdate(const DeltaRational& d, ConstraintP c, int e, int f);
+  void update(const DeltaRational& d, const Rational& r, ConstraintP c, int e, int f);
 
 
-  static UpdateInfo conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim);
+  static UpdateInfo conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim);
 
   inline ArithVar nonbasic() const { return d_nonbasic; }
   inline bool uninitialized() const {
@@ -283,7 +283,7 @@ public:
   }
 
   /** Returns the limiting constraint. */
-  inline Constraint limiting() const {
+  inline ConstraintP limiting() const {
     return d_limiting;
   }
 
index 2eb258d3b5c391a9ce99c199a9ba7190f1872379..ded322f1835747b1beb86471f43fee5f331f0010 100644 (file)
@@ -383,7 +383,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
   }
 
   if(selected.describesPivot()){
-    Constraint limiting = selected.limiting();
+    ConstraintP limiting = selected.limiting();
     ArithVar basic = limiting->getVariable();
     Assert(d_linEq.basicIsTracked(basic));
     d_linEq.pivotAndUpdate(basic, nonbasic, limiting->getValue());
@@ -765,16 +765,17 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
   return subsets;
 }
 
-Node SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
+void SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
   Assert(d_soiVar == ARITHVAR_SENTINEL);
   d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, subset);
 
-  NodeBuilder<> conflict(kind::AND);
+  //NodeBuilder<> conflict(kind::AND);
   for(ArithVarVec::const_iterator iter = subset.begin(), end = subset.end(); iter != end; ++iter){
     ArithVar e = *iter;
-    Constraint violated = d_errorSet.getViolated(e);
+    ConstraintP violated = d_errorSet.getViolated(e);
     //cout << "basic error var: " << violated << endl;
-    violated->explainForConflict(conflict);
+    d_conflictChannel.addConstraint(violated);
+    //violated->explainForConflict(conflict);
 
     //d_tableau.debugPrintIsBasic(e);
     //d_tableau.printBasicRow(e, cout);
@@ -785,18 +786,19 @@ Node SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
     if(v == d_soiVar){ continue; }
     const Rational& coeff = entry.getCoefficient();
 
-    Constraint c = (coeff.sgn() > 0) ?
+    ConstraintP c = (coeff.sgn() > 0) ?
       d_variables.getUpperBoundConstraint(v) :
       d_variables.getLowerBoundConstraint(v);
 
     //cout << "nb : " << c << endl;
-    c->explainForConflict(conflict);
+    d_conflictChannel.addConstraint(c);
   }
 
-  Node conf = conflict;
+  //Node conf = conflict;
   tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
   d_soiVar = ARITHVAR_SENTINEL;
-  return conf;
+  d_conflictChannel.commitConflict();
+  //return conf;
 }
 
 
@@ -812,9 +814,10 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
 
   if(options::soiQuickExplain()){
     quickExplain();
-    Node conflict = generateSOIConflict(d_qeConflict);
+    generateSOIConflict(d_qeConflict);
+    //Node conflict = generateSOIConflict(d_qeConflict);
     //cout << conflict << endl;
-    d_conflictChannel(conflict);
+    //d_conflictChannel(conflict);
   }else{
 
     vector<ArithVarVec> subsets = greedyConflictSubsets();
@@ -823,11 +826,12 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
     Assert(!subsets.empty());
     for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
       const ArithVarVec& subset = *i;
-      Node conflict = generateSOIConflict(subset);
+      generateSOIConflict(subset);
+      //Node conflict = generateSOIConflict(subset);
       //cout << conflict << endl;
 
       //reportConflict(conf); do not do this. We need a custom explanations!
-      d_conflictChannel(conflict);
+      //d_conflictChannel(conflict);
     }
   }
   Assert(  d_soiVar == ARITHVAR_SENTINEL);
index cee6cf81d745a4d229104db3e9bb62e940cb9ad4..89df69390492ddc5e8cbce1e44e33d6db48a5e44 100644 (file)
@@ -171,7 +171,7 @@ private:
   WitnessImprovement soiRound();
   WitnessImprovement SOIConflict();
   std::vector< ArithVarVec > greedyConflictSubsets();
-  Node generateSOIConflict(const ArithVarVec& subset);
+  void generateSOIConflict(const ArithVarVec& subset);
 
   // WitnessImprovement focusUsingSignDisagreements(ArithVar basic);
   // WitnessImprovement focusDownToLastHalf();
index 3e4cb819ba91a3897c269c1851330a291f031c95..8cf92d0750213f10f44acde5e87da8105bf41e5e 100644 (file)
@@ -81,7 +81,7 @@ public:
   }
 
   ArithVar rowIndexToBasic(RowIndex rid) const {
-    Assert(rid < d_rowIndex2basic.size());
+    Assert(d_rowIndex2basic.isKey(rid));
     return d_rowIndex2basic[rid];
   }
 
index 40a336a4ae86818835b7cfc75a5f1fde6fbd7b6e..d920fc8cad517047b8cdc66ca674b371d6da26e7 100644 (file)
@@ -41,6 +41,7 @@
 #include "smt/logic_exception.h"
 
 #include "theory/arith/arithvar.h"
+#include "theory/arith/cut_log.h"
 #include "theory/arith/delta_rational.h"
 #include "theory/arith/matrix.h"
 #include "theory/arith/arith_rewriter.h"
@@ -54,6 +55,9 @@
 #include "theory/arith/approx_simplex.h"
 #include "theory/arith/constraint.h"
 
+#include "theory/ite_utilities.h"
+#include "theory/arith/arith_ite_utils.h"
+
 #include "theory/arith/arith_utilities.h"
 #include "theory/arith/delta_rational.h"
 #include "theory/arith/partial_model.h"
@@ -82,11 +86,17 @@ namespace CVC4 {
 namespace theory {
 namespace arith {
 
+static Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum);
+static double fRand(double fMin, double fMax);
+static bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap);
+
+
 TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
   d_containing(containing),
   d_nlIncomplete( false),
   d_rowTracking(),
-  d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
+  d_conflictBuffer(),
+  d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this, d_conflictBuffer)),
   d_qflraStatus(Result::SAT_UNKNOWN),
   d_unknownsInARow(0),
   d_hasDoneWorkSinceCut(false),
@@ -108,26 +118,97 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
   d_tableauResetDensity(1.6),
   d_tableauResetPeriod(10),
   d_conflicts(c),
-  d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this)),
-  d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
-  d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
-  d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
-  d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
+  d_blackBoxConflict(c, Node::null()),
+  d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this, d_conflictBuffer)),
+  d_cmEnabled(c, true),
+  d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+  d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+  d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+  d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+  d_pass1SDP(NULL),
+  d_otherSDP(NULL),
+  d_lastContextIntegerAttempted(c,-1),
   d_DELTA_ZERO(0),
+  d_approxCuts(c),
   d_fullCheckCounter(0),
   d_cutCount(c, 0),
   d_cutInContext(c),
   d_likelyIntegerInfeasible(c, false),
   d_guessedCoeffSet(c, false),
   d_guessedCoeffs(),
+  d_treeLog(NULL),
+  d_replayVariables(),
+  d_replayConstraints(),
+  d_lhsTmp(),
+  d_approxStats(NULL),
+  d_attemptSolveIntTurnedOff(u, 0),
+  d_dioSolveResources(0),
+  d_solveIntMaybeHelp(0u),
+  d_solveIntAttempts(0u),
   d_statistics()
 {
   srand(79);
 }
 
-TheoryArithPrivate::~TheoryArithPrivate(){ }
+TheoryArithPrivate::~TheoryArithPrivate(){
+  if(d_treeLog != NULL){ delete d_treeLog; }
+  if(d_approxStats != NULL) { delete d_approxStats; }
+}
+
+static bool contains(const ConstraintCPVec& v, ConstraintP con){
+  for(unsigned i = 0, N = v.size(); i < N; ++i){
+    if(v[i] == con){
+      return true;
+    }
+  }
+  return false;
+}
+static void drop( ConstraintCPVec& v, ConstraintP con){
+  size_t readPos, writePos, N;
+  for(readPos = 0, writePos = 0, N = v.size(); readPos < N; ++readPos){
+    ConstraintCP curr = v[readPos];
+    if(curr != con){
+      v[writePos] = curr;
+      writePos++;
+    }
+  }
+  v.resize(writePos);
+}
 
 
+static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec& pos, const ConstraintCPVec& neg){
+  unsigned posPos CVC4_UNUSED = pos.size();
+  for(unsigned i = 0, N = pos.size(); i < N; ++i){
+    if(pos[i] == c){
+      posPos = i;
+    }else{
+      buf.push_back(pos[i]);
+    }
+  }
+  Assert(posPos < pos.size());
+  ConstraintP negc = c->getNegation();
+  unsigned negPos CVC4_UNUSED = neg.size();
+  for(unsigned i = 0, N = neg.size(); i < N; ++i){
+    if(neg[i] == negc){
+      negPos = i;
+    }else{
+      buf.push_back(neg[i]);
+    }
+  }
+  Assert(negPos < neg.size());
+
+  // Assert(dnconf.getKind() == kind::AND);
+  // Assert(upconf.getKind() == kind::AND);
+  // Assert(dnpos < dnconf.getNumChildren());
+  // Assert(uppos < upconf.getNumChildren());
+  // Assert(equalUpToNegation(dnconf[dnpos], upconf[uppos]));
+
+  // NodeBuilder<> nb(kind::AND);
+  // dropPosition(nb, dnconf, dnpos);
+  // dropPosition(nb, upconf, uppos);
+  // return safeConstructNary(nb);
+}
+
 void TheoryArithPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) {
   d_congruenceManager.setMasterEqualityEngine(eq);
 }
@@ -177,40 +258,79 @@ TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg) thr
 TheoryArithPrivate::ModelException::~ModelException() throw (){ }
 
 
-TheoryArithPrivate::Statistics::Statistics():
-  d_statAssertUpperConflicts("theory::arith::AssertUpperConflicts", 0),
-  d_statAssertLowerConflicts("theory::arith::AssertLowerConflicts", 0),
-  d_statUserVariables("theory::arith::UserVariables", 0),
-  d_statSlackVariables("theory::arith::SlackVariables", 0),
-  d_statDisequalitySplits("theory::arith::DisequalitySplits", 0),
-  d_statDisequalityConflicts("theory::arith::DisequalityConflicts", 0),
-  d_simplifyTimer("theory::arith::simplifyTimer"),
-  d_staticLearningTimer("theory::arith::staticLearningTimer"),
-  d_presolveTime("theory::arith::presolveTime"),
-  d_newPropTime("theory::arith::newPropTimer"),
-  d_externalBranchAndBounds("theory::arith::externalBranchAndBounds",0),
-  d_initialTableauSize("theory::arith::initialTableauSize", 0),
-  d_currSetToSmaller("theory::arith::currSetToSmaller", 0),
-  d_smallerSetToCurr("theory::arith::smallerSetToCurr", 0),
-  d_restartTimer("theory::arith::restartTimer"),
-  d_boundComputationTime("theory::arith::bound::time"),
-  d_boundComputations("theory::arith::bound::boundComputations",0),
-  d_boundPropagations("theory::arith::bound::boundPropagations",0),
-  d_unknownChecks("theory::arith::status::unknowns", 0),
-  d_maxUnknownsInARow("theory::arith::status::maxUnknownsInARow", 0),
-  d_avgUnknownsInARow("theory::arith::status::avgUnknownsInARow"),
-  d_revertsOnConflicts("theory::arith::status::revertsOnConflicts",0),
-  d_commitsOnConflicts("theory::arith::status::commitsOnConflicts",0),
-  d_nontrivialSatChecks("theory::arith::status::nontrivialSatChecks",0),
-  d_satPivots("pivots::sat"),
-  d_unsatPivots("pivots::unsat"),
-  d_unknownPivots("pivots::unkown")
+TheoryArithPrivate::Statistics::Statistics()
+  : d_statAssertUpperConflicts("theory::arith::AssertUpperConflicts", 0)
+  , d_statAssertLowerConflicts("theory::arith::AssertLowerConflicts", 0)
+  , d_statUserVariables("theory::arith::UserVariables", 0)
+  , d_statAuxiliaryVariables("theory::arith::AuxiliaryVariables", 0)
+  , d_statDisequalitySplits("theory::arith::DisequalitySplits", 0)
+  , d_statDisequalityConflicts("theory::arith::DisequalityConflicts", 0)
+  , d_simplifyTimer("theory::arith::simplifyTimer")
+  , d_staticLearningTimer("theory::arith::staticLearningTimer")
+  , d_presolveTime("theory::arith::presolveTime")
+  , d_newPropTime("theory::arith::newPropTimer")
+  , d_externalBranchAndBounds("theory::arith::externalBranchAndBounds",0)
+  , d_initialTableauSize("theory::arith::initialTableauSize", 0)
+  , d_currSetToSmaller("theory::arith::currSetToSmaller", 0)
+  , d_smallerSetToCurr("theory::arith::smallerSetToCurr", 0)
+  , d_restartTimer("theory::arith::restartTimer")
+  , d_boundComputationTime("theory::arith::bound::time")
+  , d_boundComputations("theory::arith::bound::boundComputations",0)
+  , d_boundPropagations("theory::arith::bound::boundPropagations",0)
+  , d_unknownChecks("theory::arith::status::unknowns", 0)
+  , d_maxUnknownsInARow("theory::arith::status::maxUnknownsInARow", 0)
+  , d_avgUnknownsInARow("theory::arith::status::avgUnknownsInARow")
+  , d_revertsOnConflicts("theory::arith::status::revertsOnConflicts",0)
+  , d_commitsOnConflicts("theory::arith::status::commitsOnConflicts",0)
+  , d_nontrivialSatChecks("theory::arith::status::nontrivialSatChecks",0)
+  , d_replayLogRecCount("z::approx::replay::rec",0)
+  , d_replayLogRecConflictEscalation("z::approx::replay::rec::escalation",0)
+  , d_replayLogRecEarlyExit("z::approx::replay::rec::earlyexit",0)
+  , d_replayBranchCloseFailures("z::approx::replay::rec::branch::closefailures",0)
+  , d_replayLeafCloseFailures("z::approx::replay::rec::leaf::closefailures",0)
+  , d_replayBranchSkips("z::approx::replay::rec::branch::skips",0)
+  , d_mirCutsAttempted("z::approx::cuts::mir::attempted",0)
+  , d_gmiCutsAttempted("z::approx::cuts::gmi::attempted",0)
+  , d_branchCutsAttempted("z::approx::cuts::branch::attempted",0)
+  , d_cutsReconstructed("z::approx::cuts::reconstructed",0)
+  , d_cutsReconstructionFailed("z::approx::cuts::reconstructed::failed",0)
+  , d_cutsProven("z::approx::cuts::proofs",0)
+  , d_cutsProofFailed("z::approx::cuts::proofs::failed",0)
+  , d_mipReplayLemmaCalls("z::approx::external::calls",0)
+  , d_mipExternalCuts("z::approx::external::cuts",0)
+  , d_mipExternalBranch("z::approx::external::branches",0)
+  , d_inSolveInteger("z::approx::inSolverInteger",0)
+  , d_branchesExhausted("z::approx::exhausted::branches",0)
+  , d_execExhausted("z::approx::exhausted::exec",0)
+  , d_pivotsExhausted("z::approx::exhausted::pivots",0)
+  , d_panicBranches("z::arith::paniclemmas",0)
+  , d_relaxCalls("z::arith::relax::calls",0)
+  , d_relaxLinFeas("z::arith::relax::feasible::res",0)
+  , d_relaxLinFeasFailures("z::arith::relax::feasible::failures",0)
+  , d_relaxLinInfeas("z::arith::relax::infeasible",0)
+  , d_relaxLinInfeasFailures("z::arith::relax::infeasible::failures",0)
+  , d_relaxLinExhausted("z::arith::relax::exhausted",0)
+  , d_relaxOthers("z::arith::relax::other",0)
+  , d_applyRowsDeleted("z::arith::cuts::applyRowsDeleted",0)
+  , d_replaySimplexTimer("z::approx::replay::simplex::timer")
+  , d_replayLogTimer("z::approx::replay::log::timer")
+  , d_solveIntTimer("z::solveInt::timer")
+  , d_solveRealRelaxTimer("z::solveRealRelax::timer")
+  , d_solveIntCalls("z::solveInt::calls", 0)
+  , d_solveStandardEffort("z::solveInt::calls::standardEffort", 0)
+  , d_approxDisabled("z::approxDisabled", 0)
+  , d_replayAttemptFailed("z::replayAttemptFailed",0)
+  , d_cutsRejectedDuringReplay("z::approx::replay::cuts::rejected", 0)
+  , d_cutsRejectedDuringLemmas("z::approx::external::cuts::rejected", 0)
+  , d_satPivots("pivots::sat")
+  , d_unsatPivots("pivots::unsat")
+  , d_unknownPivots("pivots::unkown")
 {
   StatisticsRegistry::registerStat(&d_statAssertUpperConflicts);
   StatisticsRegistry::registerStat(&d_statAssertLowerConflicts);
 
   StatisticsRegistry::registerStat(&d_statUserVariables);
-  StatisticsRegistry::registerStat(&d_statSlackVariables);
+  StatisticsRegistry::registerStat(&d_statAuxiliaryVariables);
   StatisticsRegistry::registerStat(&d_statDisequalitySplits);
   StatisticsRegistry::registerStat(&d_statDisequalityConflicts);
   StatisticsRegistry::registerStat(&d_simplifyTimer);
@@ -241,6 +361,54 @@ TheoryArithPrivate::Statistics::Statistics():
   StatisticsRegistry::registerStat(&d_satPivots);
   StatisticsRegistry::registerStat(&d_unsatPivots);
   StatisticsRegistry::registerStat(&d_unknownPivots);
+
+  StatisticsRegistry::registerStat(&d_replayLogRecCount);
+  StatisticsRegistry::registerStat(&d_replayLogRecConflictEscalation);
+  StatisticsRegistry::registerStat(&d_replayLogRecEarlyExit);
+  StatisticsRegistry::registerStat(&d_replayBranchCloseFailures);
+  StatisticsRegistry::registerStat(&d_replayLeafCloseFailures);
+  StatisticsRegistry::registerStat(&d_replayBranchSkips);
+  StatisticsRegistry::registerStat(&d_mirCutsAttempted);
+  StatisticsRegistry::registerStat(&d_gmiCutsAttempted);
+  StatisticsRegistry::registerStat(&d_branchCutsAttempted);
+  StatisticsRegistry::registerStat(&d_cutsReconstructed);
+  StatisticsRegistry::registerStat(&d_cutsProven);
+  StatisticsRegistry::registerStat(&d_cutsProofFailed);
+  StatisticsRegistry::registerStat(&d_cutsReconstructionFailed);
+  StatisticsRegistry::registerStat(&d_mipReplayLemmaCalls);
+  StatisticsRegistry::registerStat(&d_mipExternalCuts);
+  StatisticsRegistry::registerStat(&d_mipExternalBranch);
+
+  StatisticsRegistry::registerStat(&d_inSolveInteger);
+  StatisticsRegistry::registerStat(&d_branchesExhausted);
+  StatisticsRegistry::registerStat(&d_execExhausted);
+  StatisticsRegistry::registerStat(&d_pivotsExhausted);
+  StatisticsRegistry::registerStat(&d_panicBranches);
+  StatisticsRegistry::registerStat(&d_relaxCalls);
+  StatisticsRegistry::registerStat(&d_relaxLinFeas);
+  StatisticsRegistry::registerStat(&d_relaxLinFeasFailures);
+  StatisticsRegistry::registerStat(&d_relaxLinInfeas);
+  StatisticsRegistry::registerStat(&d_relaxLinInfeasFailures);
+  StatisticsRegistry::registerStat(&d_relaxLinExhausted);
+  StatisticsRegistry::registerStat(&d_relaxOthers);
+
+  StatisticsRegistry::registerStat(&d_applyRowsDeleted);
+
+  StatisticsRegistry::registerStat(&d_replaySimplexTimer);
+  StatisticsRegistry::registerStat(&d_replayLogTimer);
+  StatisticsRegistry::registerStat(&d_solveIntTimer);
+  StatisticsRegistry::registerStat(&d_solveRealRelaxTimer);
+
+  StatisticsRegistry::registerStat(&d_solveIntCalls);
+  StatisticsRegistry::registerStat(&d_solveStandardEffort);
+
+  StatisticsRegistry::registerStat(&d_approxDisabled);
+
+  StatisticsRegistry::registerStat(&d_replayAttemptFailed);
+
+  StatisticsRegistry::registerStat(&d_cutsRejectedDuringReplay);
+  StatisticsRegistry::registerStat(&d_cutsRejectedDuringLemmas);
+
 }
 
 TheoryArithPrivate::Statistics::~Statistics(){
@@ -248,7 +416,7 @@ TheoryArithPrivate::Statistics::~Statistics(){
   StatisticsRegistry::unregisterStat(&d_statAssertLowerConflicts);
 
   StatisticsRegistry::unregisterStat(&d_statUserVariables);
-  StatisticsRegistry::unregisterStat(&d_statSlackVariables);
+  StatisticsRegistry::unregisterStat(&d_statAuxiliaryVariables);
   StatisticsRegistry::unregisterStat(&d_statDisequalitySplits);
   StatisticsRegistry::unregisterStat(&d_statDisequalityConflicts);
   StatisticsRegistry::unregisterStat(&d_simplifyTimer);
@@ -278,6 +446,66 @@ TheoryArithPrivate::Statistics::~Statistics(){
   StatisticsRegistry::unregisterStat(&d_satPivots);
   StatisticsRegistry::unregisterStat(&d_unsatPivots);
   StatisticsRegistry::unregisterStat(&d_unknownPivots);
+
+  StatisticsRegistry::unregisterStat(&d_replayLogRecCount);
+  StatisticsRegistry::unregisterStat(&d_replayLogRecConflictEscalation);
+  StatisticsRegistry::unregisterStat(&d_replayLogRecEarlyExit);
+  StatisticsRegistry::unregisterStat(&d_replayBranchCloseFailures);
+  StatisticsRegistry::unregisterStat(&d_replayLeafCloseFailures);
+  StatisticsRegistry::unregisterStat(&d_replayBranchSkips);
+  StatisticsRegistry::unregisterStat(&d_mirCutsAttempted);
+  StatisticsRegistry::unregisterStat(&d_gmiCutsAttempted);
+  StatisticsRegistry::unregisterStat(&d_branchCutsAttempted);
+  StatisticsRegistry::unregisterStat(&d_cutsReconstructed);
+  StatisticsRegistry::unregisterStat(&d_cutsProven);
+  StatisticsRegistry::unregisterStat(&d_cutsProofFailed);
+  StatisticsRegistry::unregisterStat(&d_cutsReconstructionFailed);
+  StatisticsRegistry::unregisterStat(&d_mipReplayLemmaCalls);
+  StatisticsRegistry::unregisterStat(&d_mipExternalCuts);
+  StatisticsRegistry::unregisterStat(&d_mipExternalBranch);
+
+
+  StatisticsRegistry::unregisterStat(&d_inSolveInteger);
+  StatisticsRegistry::unregisterStat(&d_branchesExhausted);
+  StatisticsRegistry::unregisterStat(&d_execExhausted);
+  StatisticsRegistry::unregisterStat(&d_pivotsExhausted);
+  StatisticsRegistry::unregisterStat(&d_panicBranches);
+  StatisticsRegistry::unregisterStat(&d_relaxCalls);
+  StatisticsRegistry::unregisterStat(&d_relaxLinFeas);
+  StatisticsRegistry::unregisterStat(&d_relaxLinFeasFailures);
+  StatisticsRegistry::unregisterStat(&d_relaxLinInfeas);
+  StatisticsRegistry::unregisterStat(&d_relaxLinInfeasFailures);
+  StatisticsRegistry::unregisterStat(&d_relaxLinExhausted);
+  StatisticsRegistry::unregisterStat(&d_relaxOthers);
+
+  StatisticsRegistry::unregisterStat(&d_applyRowsDeleted);
+
+  StatisticsRegistry::unregisterStat(&d_replaySimplexTimer);
+  StatisticsRegistry::unregisterStat(&d_replayLogTimer);
+  StatisticsRegistry::unregisterStat(&d_solveIntTimer);
+  StatisticsRegistry::unregisterStat(&d_solveRealRelaxTimer);
+
+  StatisticsRegistry::unregisterStat(&d_solveIntCalls);
+  StatisticsRegistry::unregisterStat(&d_solveStandardEffort);
+
+  StatisticsRegistry::unregisterStat(&d_approxDisabled);
+
+  StatisticsRegistry::unregisterStat(&d_replayAttemptFailed);
+
+  StatisticsRegistry::unregisterStat(&d_cutsRejectedDuringReplay);
+  StatisticsRegistry::unregisterStat(&d_cutsRejectedDuringLemmas);
+}
+
+bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){
+  DenseMap<Rational>::const_iterator riter, rend;
+  for(riter=row.begin(), rend=row.end(); riter != rend; ++riter){
+    ArithVar v = *riter;
+    const Rational& q = row[v];
+    if(q.complexity() > cap){
+      return false;
+    }
+  }
+  return true;
 }
 
 void TheoryArithPrivate::revertOutOfConflict(){
@@ -290,25 +518,67 @@ void TheoryArithPrivate::clearUpdates(){
   d_updatedBounds.purge();
 }
 
+void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b){
+  ConstraintCPVec v;
+  v.push_back(a);
+  v.push_back(b);
+  d_conflicts.push_back(v);
+}
+
+void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c){
+  ConstraintCPVec v;
+  v.push_back(a);
+  v.push_back(b);
+  v.push_back(c);
+  d_conflicts.push_back(v);
+}
+
 void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){
-  Assert(d_congruenceManager.isWatchedVariable(x));
-  Assert(d_partialModel.upperBoundIsZero(x));
-  Assert(d_partialModel.lowerBoundIsZero(x));
+  if(d_cmEnabled){
+    Assert(d_congruenceManager.isWatchedVariable(x));
+    Assert(d_partialModel.upperBoundIsZero(x));
+    Assert(d_partialModel.lowerBoundIsZero(x));
 
-  Constraint lb = d_partialModel.getLowerBoundConstraint(x);
-  Constraint ub = d_partialModel.getUpperBoundConstraint(x);
+    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x);
+    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x);
 
-  if(lb->isEquality()){
-    d_congruenceManager.watchedVariableIsZero(lb);
-  }else if(ub->isEquality()){
-    d_congruenceManager.watchedVariableIsZero(ub);
+    if(lb->isEquality()){
+      d_congruenceManager.watchedVariableIsZero(lb);
+    }else if(ub->isEquality()){
+      d_congruenceManager.watchedVariableIsZero(ub);
+    }else{
+      d_congruenceManager.watchedVariableIsZero(lb, ub);
+    }
+  }
+}
+
+bool TheoryArithPrivate::getSolveIntegerResource(){
+  if(d_attemptSolveIntTurnedOff > 0){
+    d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff - 1;
+    return false;
   }else{
-    d_congruenceManager.watchedVariableIsZero(lb, ub);
+    return true;
+  }
+}
+
+bool TheoryArithPrivate::getDioCuttingResource(){
+  if(d_dioSolveResources > 0){
+    d_dioSolveResources--;
+    if(d_dioSolveResources == 0){
+      d_dioSolveResources = -options::rrTurns();
+    }
+    return true;
+  }else{
+    d_dioSolveResources++;
+    if(d_dioSolveResources >= 0){
+      d_dioSolveResources = options::dioSolverTurns();
+    }
+    return false;
   }
 }
 
 /* procedure AssertLower( x_i >= c_i ) */
-bool TheoryArithPrivate::AssertLower(Constraint constraint){
+bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
   Assert(constraint != NullConstraint);
   Assert(constraint->isLowerBound());
 
@@ -326,38 +596,43 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
 
   int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
   if(cmpToUB > 0){ //  c_i < \lowerbound(x_i)
-    Constraint ubc = d_partialModel.getUpperBoundConstraint(x_i);
-    Node conflict = ConstraintValue::explainConflict(ubc, constraint);
-    Debug("arith") << "AssertLower conflict " << conflict << endl;
+    ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
+    raiseConflict(ubc, constraint);
+
+    // Node conflict = ConstraintValue::explainConflict(ubc, constraint);
+    // Debug("arith") << "AssertLower conflict " << conflict << endl;
+    // raiseConflict(conflict);
     ++(d_statistics.d_statAssertLowerConflicts);
-    raiseConflict(conflict);
     return true;
   }else if(cmpToUB == 0){
     if(isInteger(x_i)){
       d_constantIntegerVariables.push_back(x_i);
       Debug("dio::push") << x_i << endl;
     }
-    Constraint ub = d_partialModel.getUpperBoundConstraint(x_i);
-
-    if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
-      // if it is not a watched variable report it
-      // if it is is a watched variable and c_i == 0,
-      // let zeroDifferenceDetected(x_i) catch this
-      d_congruenceManager.equalsConstant(constraint, ub);
+    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i);
+
+    if(d_cmEnabled){
+      if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
+        // if it is not a watched variable report it
+        // if it is is a watched variable and c_i == 0,
+        // let zeroDifferenceDetected(x_i) catch this
+        d_congruenceManager.equalsConstant(constraint, ub);
+      }
     }
 
     const ValueCollection& vc = constraint->getValueCollection();
     if(vc.hasDisequality()){
       Assert(vc.hasEquality());
-      const Constraint eq = vc.getEquality();
-      const Constraint diseq = vc.getDisequality();
+      ConstraintP eq = vc.getEquality();
+      ConstraintP diseq = vc.getDisequality();
       if(diseq->isTrue()){
-        //const Constraint ub = vc.getUpperBound();
-        Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
+        //const ConstraintP ub = vc.getUpperBound();
+        raiseConflict(diseq, ub, constraint);
+        //Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
 
         ++(d_statistics.d_statDisequalityConflicts);
-        Debug("eq") << " assert lower conflict " << conflict << endl;
-        raiseConflict(conflict);
+        //Debug("eq") << " assert lower conflict " << conflict << endl;
+        //raiseConflict(conflict);
         return true;
       }else if(!eq->isTrue()){
         Debug("eq") << "lb == ub, propagate eq" << eq << endl;
@@ -370,17 +645,19 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
     const ValueCollection& vc = constraint->getValueCollection();
 
     if(vc.hasDisequality()){
-      const Constraint diseq = vc.getDisequality();
+      const ConstraintP diseq = vc.getDisequality();
       if(diseq->isTrue()){
-        const Constraint ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
+        const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
 
         if(ub->hasProof()){
-          Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
-          Debug("eq") << " assert upper conflict " << conflict << endl;
-          raiseConflict(conflict);
+          raiseConflict(diseq, ub, constraint);
           return true;
+          // Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
+          // Debug("eq") << " assert upper conflict " << conflict << endl;
+          // raiseConflict(conflict);
+          // return true;
         }else if(!ub->negationHasProof()){
-          Constraint negUb = ub->getNegation();
+          ConstraintP negUb = ub->getNegation();
           negUb->impliedBy(constraint, diseq);
           d_learnedBounds.push_back(negUb);
         }
@@ -393,12 +670,14 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
 
   d_partialModel.setLowerBoundConstraint(constraint);
 
-  if(d_congruenceManager.isWatchedVariable(x_i)){
-    int sgn = c_i.sgn();
-    if(sgn > 0){
-      d_congruenceManager.watchedVariableCannotBeZero(constraint);
-    }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
-      zeroDifferenceDetected(x_i);
+  if(d_cmEnabled){
+    if(d_congruenceManager.isWatchedVariable(x_i)){
+      int sgn = c_i.sgn();
+      if(sgn > 0){
+        d_congruenceManager.watchedVariableCannotBeZero(constraint);
+      }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
+        zeroDifferenceDetected(x_i);
+      }
     }
   }
 
@@ -428,7 +707,7 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
 }
 
 /* procedure AssertUpper( x_i <= c_i) */
-bool TheoryArithPrivate::AssertUpper(Constraint constraint){
+bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
   ArithVar x_i = constraint->getVariable();
   const DeltaRational& c_i = constraint->getValue();
 
@@ -450,34 +729,38 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
   // cmpToLb =  \lowerbound(x_i).cmp(c_i)
   int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
   if( cmpToLB < 0 ){ //  \upperbound(x_i) < \lowerbound(x_i)
-    Constraint lbc = d_partialModel.getLowerBoundConstraint(x_i);
-    Node conflict =  ConstraintValue::explainConflict(lbc, constraint);
-    Debug("arith") << "AssertUpper conflict " << conflict << endl;
+    ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
+    raiseConflict(lbc, constraint);
+    //Node conflict =  ConstraintValue::explainConflict(lbc, constraint);
+    //Debug("arith") << "AssertUpper conflict " << conflict << endl;
     ++(d_statistics.d_statAssertUpperConflicts);
-    raiseConflict(conflict);
+    //raiseConflict(conflict);
     return true;
   }else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i)
     if(isInteger(x_i)){
       d_constantIntegerVariables.push_back(x_i);
       Debug("dio::push") << x_i << endl;
     }
-    Constraint lb = d_partialModel.getLowerBoundConstraint(x_i);
-    if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
-      // if it is not a watched variable report it
-      // if it is is a watched variable and c_i == 0,
-      // let zeroDifferenceDetected(x_i) catch this
-      d_congruenceManager.equalsConstant(lb, constraint);
+    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i);
+    if(d_cmEnabled){
+      if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
+        // if it is not a watched variable report it
+        // if it is is a watched variable and c_i == 0,
+        // let zeroDifferenceDetected(x_i) catch this
+        d_congruenceManager.equalsConstant(lb, constraint);
+      }
     }
 
     const ValueCollection& vc = constraint->getValueCollection();
     if(vc.hasDisequality()){
       Assert(vc.hasEquality());
-      const Constraint diseq = vc.getDisequality();
-      const Constraint eq = vc.getEquality();
+      const ConstraintP diseq = vc.getDisequality();
+      const ConstraintP eq = vc.getEquality();
       if(diseq->isTrue()){
-        Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
-        Debug("eq") << " assert upper conflict " << conflict << endl;
-        raiseConflict(conflict);
+        raiseConflict(diseq, lb, constraint);
+        //Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
+        //Debug("eq") << " assert upper conflict " << conflict << endl;
+        //raiseConflict(conflict);
         return true;
       }else if(!eq->isTrue()){
         Debug("eq") << "lb == ub, propagate eq" << eq << endl;
@@ -488,17 +771,18 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
   }else if(cmpToLB > 0){
     const ValueCollection& vc = constraint->getValueCollection();
     if(vc.hasDisequality()){
-      const Constraint diseq = vc.getDisequality();
+      const ConstraintP diseq = vc.getDisequality();
       if(diseq->isTrue()){
-        const Constraint lb =
+        const ConstraintP lb =
           d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
         if(lb->hasProof()){
-          Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
-          Debug("eq") << " assert upper conflict " << conflict << endl;
-          raiseConflict(conflict);
+          raiseConflict(diseq, lb, constraint);
+          //Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
+          //Debug("eq") << " assert upper conflict " << conflict << endl;
+          //raiseConflict(conflict);
           return true;
         }else if(!lb->negationHasProof()){
-          Constraint negLb = lb->getNegation();
+          ConstraintP negLb = lb->getNegation();
           negLb->impliedBy(constraint, diseq);
           d_learnedBounds.push_back(negLb);
         }
@@ -512,13 +796,15 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
 
   d_partialModel.setUpperBoundConstraint(constraint);
 
-  if(d_congruenceManager.isWatchedVariable(x_i)){
-    int sgn = c_i.sgn();
-     if(sgn < 0){
-       d_congruenceManager.watchedVariableCannotBeZero(constraint);
-     }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
-       zeroDifferenceDetected(x_i);
-     }
+  if(d_cmEnabled){
+    if(d_congruenceManager.isWatchedVariable(x_i)){
+      int sgn = c_i.sgn();
+      if(sgn < 0){
+        d_congruenceManager.watchedVariableCannotBeZero(constraint);
+      }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
+        zeroDifferenceDetected(x_i);
+      }
+    }
   }
 
   d_updatedBounds.softAdd(x_i);
@@ -548,7 +834,7 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
 
 
 /* procedure AssertEquality( x_i == c_i ) */
-bool TheoryArithPrivate::AssertEquality(Constraint constraint){
+bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
   AssertArgument(constraint != NullConstraint,
                  "AssertUpper() called on a NullConstraint.");
 
@@ -570,18 +856,21 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
   }
 
   if(cmpToUB > 0){
-    Constraint ubc = d_partialModel.getUpperBoundConstraint(x_i);
-    Node conflict = ConstraintValue::explainConflict(ubc, constraint);
-    Debug("arith") << "AssertEquality conflicts with upper bound " << conflict << endl;
-    raiseConflict(conflict);
+    ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
+    raiseConflict(ubc, constraint);
+    //Node conflict = ConstraintValue::explainConflict(ubc, constraint);
+    //Debug("arith") << "AssertEquality conflicts with upper bound " << conflict << endl;
+    //raiseConflict(conflict);
     return true;
   }
 
   if(cmpToLB < 0){
-    Constraint lbc = d_partialModel.getLowerBoundConstraint(x_i);
-    Node conflict = ConstraintValue::explainConflict(lbc, constraint);
-    Debug("arith") << "AssertEquality conflicts with lower bound" << conflict << endl;
-    raiseConflict(conflict);
+    ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
+    raiseConflict(lbc, constraint);
+
+    // Node conflict = ConstraintValue::explainConflict(lbc, constraint);
+    // Debug("arith") << "AssertEquality conflicts with lower bound" << conflict << endl;
+    // raiseConflict(conflict);
     return true;
   }
 
@@ -604,16 +893,18 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
   d_partialModel.setUpperBoundConstraint(constraint);
   d_partialModel.setLowerBoundConstraint(constraint);
 
-  if(d_congruenceManager.isWatchedVariable(x_i)){
-    int sgn = c_i.sgn();
-    if(sgn == 0){
-      zeroDifferenceDetected(x_i);
+  if(d_cmEnabled){
+    if(d_congruenceManager.isWatchedVariable(x_i)){
+      int sgn = c_i.sgn();
+      if(sgn == 0){
+        zeroDifferenceDetected(x_i);
+      }else{
+        d_congruenceManager.watchedVariableCannotBeZero(constraint);
+        d_congruenceManager.equalsConstant(constraint);
+      }
     }else{
-      d_congruenceManager.watchedVariableCannotBeZero(constraint);
       d_congruenceManager.equalsConstant(constraint);
     }
-  }else{
-    d_congruenceManager.equalsConstant(constraint);
   }
 
   d_updatedBounds.softAdd(x_i);
@@ -643,7 +934,7 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
 
 
 /* procedure AssertDisequality( x_i != c_i ) */
-bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
+bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
 
   AssertArgument(constraint != NullConstraint,
                  "AssertUpper() called on a NullConstraint.");
@@ -655,32 +946,35 @@ bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
   //Should be fine in integers
   Assert(!isInteger(x_i) || c_i.isIntegral());
 
-  if(d_congruenceManager.isWatchedVariable(x_i)){
-    int sgn = c_i.sgn();
-    if(sgn == 0){
-      d_congruenceManager.watchedVariableCannotBeZero(constraint);
+  if(d_cmEnabled){
+    if(d_congruenceManager.isWatchedVariable(x_i)){
+      int sgn = c_i.sgn();
+      if(sgn == 0){
+        d_congruenceManager.watchedVariableCannotBeZero(constraint);
+      }
     }
   }
 
   const ValueCollection& vc = constraint->getValueCollection();
   if(vc.hasLowerBound() && vc.hasUpperBound()){
-    const Constraint lb = vc.getLowerBound();
-    const Constraint ub = vc.getUpperBound();
+    const ConstraintP lb = vc.getLowerBound();
+    const ConstraintP ub = vc.getUpperBound();
     if(lb->isTrue() && ub->isTrue()){
       //in conflict
       Debug("eq") << "explaining" << endl;
       ++(d_statistics.d_statDisequalityConflicts);
-      Node conflict = ConstraintValue::explainConflict(constraint, lb, ub);
-      raiseConflict(conflict);
+      raiseConflict(constraint, lb, ub);
+      //Node conflict = ConstraintValue::explainConflict(constraint, lb, ub);
+      //raiseConflict(conflict);
       return true;
     }
   }
   if(vc.hasLowerBound() ){
-    const Constraint lb = vc.getLowerBound();
+    const ConstraintP lb = vc.getLowerBound();
     if(lb->isTrue()){
-      const Constraint ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
+      const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
       Debug("eq") << "propagate UpperBound " << constraint << lb << ub << endl;
-      const Constraint negUb = ub->getNegation();
+      const ConstraintP negUb = ub->getNegation();
       if(!negUb->isTrue()){
         negUb->impliedBy(constraint, lb);
         d_learnedBounds.push_back(negUb);
@@ -688,12 +982,12 @@ bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
     }
   }
   if(vc.hasUpperBound()){
-    const Constraint ub = vc.getUpperBound();
+    const ConstraintP ub = vc.getUpperBound();
     if(ub->isTrue()){
-      const Constraint lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
+      const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
 
       Debug("eq") << "propagate LowerBound " << constraint << lb << ub << endl;
-      const Constraint negLb = lb->getNegation();
+      const ConstraintP negLb = lb->getNegation();
       if(!negLb->isTrue()){
         negLb->impliedBy(constraint, ub);
         d_learnedBounds.push_back(negLb);
@@ -930,28 +1224,23 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
       Assert(elim == Rewriter::rewrite(elim));
 
 
-      static const unsigned MAX_SUB_SIZE = 2;
+      static const unsigned MAX_SUB_SIZE = 20;
       if(right.size() > MAX_SUB_SIZE){
         Debug("simplify") << "TheoryArithPrivate::solve(): did not substitute due to the right hand side containing too many terms: " << minVar << ":" << elim << endl;
         Debug("simplify") << right.size() << endl;
-        // cout << "TheoryArithPrivate::solve(): did not substitute due to the right hand side containing too many terms: " << minVar << ":" << elim << endl;
-        // cout << right.size() << endl;
       }else if(elim.hasSubterm(minVar)){
         Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute due to recursive pattern with sharing: " << minVar << ":" << elim << endl;
-        // cout << "TheoryArithPrivate::solve(): can't substitute due to recursive pattern with sharing: " << minVar << ":" << elim << endl;
 
       }else if (!minVar.getType().isInteger() || right.isIntegral()) {
         Assert(!elim.hasSubterm(minVar));
         // cannot eliminate integers here unless we know the resulting
         // substitution is integral
         Debug("simplify") << "TheoryArithPrivate::solve(): substitution " << minVar << " |-> " << elim << endl;
-        //cout << "TheoryArithPrivate::solve(): substitution " << minVar << " |-> " << elim << endl;
 
         outSubstitutions.addSubstitution(minVar, elim);
         return Theory::PP_ASSERT_STATUS_SOLVED;
       } else {
         Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute b/c it's integer: " << minVar << ":" << minVar.getType() << " |-> " << elim << ":" << elim.getType() << endl;
-        //cout << "TheoryArithPrivate::solve(): can't substitute b/c it's integer: " << minVar << ":" << minVar.getType() << " |-> " << elim << ":" << elim.getType() << endl;
 
       }
     }
@@ -1010,7 +1299,7 @@ void TheoryArithPrivate::setupVariable(const Variable& x){
   Assert(!isSetup(n));
 
   ++(d_statistics.d_statUserVariables);
-  requestArithVar(n,false);
+  requestArithVar(n, false,  false);
   //ArithVar varN = requestArithVar(n,false);
   //setupInitialValue(varN);
 
@@ -1049,7 +1338,7 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
     d_nlIncomplete = true;
 
     ++(d_statistics.d_statUserVariables);
-    requestArithVar(vlNode, false);
+    requestArithVar(vlNode, false, false);
     //ArithVar av = requestArithVar(vlNode, false);
     //setupInitialValue(av);
 
@@ -1242,7 +1531,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
     vector<Rational> coefficients;
     asVectors(poly, coefficients, variables);
 
-    ArithVar varSlack = requestArithVar(polyNode, true);
+    ArithVar varSlack = requestArithVar(polyNode, true, false);
     d_tableau.addRow(varSlack, coefficients, variables);
     setupBasicValue(varSlack);
     d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
@@ -1267,7 +1556,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
       }
     }
 
-    ++(d_statistics.d_statSlackVariables);
+    ++(d_statistics.d_statAuxiliaryVariables);
     markSetup(polyNode);
   }
 
@@ -1306,7 +1595,7 @@ void TheoryArithPrivate::preRegisterTerm(TNode n) {
       if(!isSetup(n)){
         setupAtom(n);
       }
-      Constraint c = d_constraintDatabase.lookup(n);
+      ConstraintP c = d_constraintDatabase.lookup(n);
       Assert(c != NullConstraint);
   
       Debug("arith::preregister") << "setup constraint" << c << endl;
@@ -1323,15 +1612,15 @@ void TheoryArithPrivate::preRegisterTerm(TNode n) {
 }
 
 void TheoryArithPrivate::releaseArithVar(ArithVar v){
-  Assert(d_partialModel.hasNode(v));
+  //Assert(d_partialModel.hasNode(v));
 
   d_constraintDatabase.removeVariable(v);
   d_partialModel.releaseArithVar(v);
 }
 
-ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
+ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
   //TODO : The VarList trick is good enough?
-  Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS);
+  Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal);
   if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
     stringstream ss;
     ss << "A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic: " << x << endl
@@ -1342,7 +1631,7 @@ ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
   Assert(x.getType().isReal()); // real or integer
 
   ArithVar max = d_partialModel.getNumberOfVariables();
-  ArithVar varX = d_partialModel.allocate(x, slack);
+  ArithVar varX = d_partialModel.allocate(x, aux);
 
   bool reclaim =  max >= d_partialModel.getNumberOfVariables();;
 
@@ -1354,7 +1643,9 @@ ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
   }
   d_constraintDatabase.addVariable(varX);
 
-  Debug("arith::arithvar") << x << " |-> " << varX << endl;
+  Debug("arith::arithvar") << "@" << getSatContext()->getLevel()
+                           << " " << x << " |-> " << varX
+                           << "(relaiming " << reclaim << ")" << endl;
 
   Assert(!d_partialModel.hasUpperBound(varX));
   Assert(!d_partialModel.hasLowerBound(varX));
@@ -1370,7 +1661,7 @@ void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& c
 
     Node n = variable.getNode();
 
-    Debug("rewriter") << "should be var: " << n << endl;
+    Debug("arith::asVectors") << "should be var: " << n << endl;
 
     // TODO: This VarList::isMember(n) can be stronger
     Assert(isLeaf(n) || VarList::isMember(n));
@@ -1471,6 +1762,9 @@ Node TheoryArithPrivate::dioCutting(){
     Comparison geq = Comparison::mkComparison(GEQ, p, c);
     Node lemma = NodeManager::currentNM()->mkNode(OR, leq.getNode(), geq.getNode());
     Node rewrittenLemma = Rewriter::rewrite(lemma);
+    Debug("arith::dio::ex") << "dioCutting found the plane: " << plane.getNode() << endl;
+    Debug("arith::dio::ex") << "resulting in the cut: " << lemma << endl;
+    Debug("arith::dio::ex") << "rewritten " << rewrittenLemma << endl;
     Debug("arith::dio") << "dioCutting found the plane: " << plane.getNode() << endl;
     Debug("arith::dio") << "resulting in the cut: " << lemma << endl;
     Debug("arith::dio") << "rewritten " << rewrittenLemma << endl;
@@ -1489,16 +1783,16 @@ Node TheoryArithPrivate::callDioSolver(){
     Assert(d_partialModel.boundsAreEqual(v));
 
 
-    Constraint lb = d_partialModel.getLowerBoundConstraint(v);
-    Constraint ub = d_partialModel.getUpperBoundConstraint(v);
+    ConstraintP lb = d_partialModel.getLowerBoundConstraint(v);
+    ConstraintP ub = d_partialModel.getUpperBoundConstraint(v);
 
     Node orig = Node::null();
     if(lb->isEquality()){
-      orig = lb->explainForConflict();
+      orig = lb->externalExplainByAssertions();
     }else if(ub->isEquality()){
-      orig = ub->explainForConflict();
+      orig = ub->externalExplainByAssertions();
     }else {
-      orig = ConstraintValue::explainConflict(ub, lb);
+      orig = Constraint_::externalExplainByAssertions(ub, lb);
     }
 
     Assert(d_partialModel.assignmentIsConsistent(v));
@@ -1521,7 +1815,7 @@ Node TheoryArithPrivate::callDioSolver(){
   return d_diosolver.processEquationsForConflict();
 }
 
-Constraint TheoryArithPrivate::constraintFromFactQueue(){
+ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
   Assert(!done());
   TNode assertion = get();
 
@@ -1530,7 +1824,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
   }
 
   Kind simpleKind = Comparison::comparisonKind(assertion);
-  Constraint constraint = d_constraintDatabase.lookup(assertion);
+  ConstraintP constraint = d_constraintDatabase.lookup(assertion);
   if(constraint == NullConstraint){
     Assert(simpleKind == EQUAL || simpleKind == DISTINCT );
     bool isDistinct = simpleKind == DISTINCT;
@@ -1542,7 +1836,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
         // if is (not true), or false
         Assert((reEq.getConst<bool>() && isDistinct) ||
                (!reEq.getConst<bool>() && !isDistinct));
-        raiseConflict(assertion);
+        blackBoxConflict(assertion);
       }
       return NullConstraint;
     }
@@ -1563,7 +1857,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
   Assert(constraint != NullConstraint);
 
   if(constraint->negationHasProof()){
-    Constraint negation = constraint->getNegation();
+    ConstraintP negation = constraint->getNegation();
     if(negation->isSelfExplaining()){
       if(Debug.isOn("whytheoryenginewhy")){
         debugPrintFacts();
@@ -1572,12 +1866,21 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
     Debug("arith::eq") << constraint << endl;
     Debug("arith::eq") << negation << endl;
 
-    NodeBuilder<> nb(kind::AND);
-    nb << assertion;
-    negation->explainForConflict(nb);
-    Node conflict = nb;
-    Debug("arith::eq") << "conflict" << conflict << endl;
-    raiseConflict(conflict);
+    constraint->setAssertedToTheTheoryWithNegationTrue(assertion);
+    if(!constraint->hasProof()){
+      Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
+      constraint->selfExplainingWithNegationTrue();
+    }else{
+      Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
+    }
+
+    raiseConflict(constraint, negation);
+    // NodeBuilder<> nb(kind::AND);
+    // nb << assertion;
+    // negation->explainForConflict(nb);
+    // Node conflict = nb;
+    // Debug("arith::eq") << "conflict" << conflict << endl;
+    // raiseConflict(conflict);
     return NullConstraint;
   }
   Assert(!constraint->negationHasProof());
@@ -1593,14 +1896,14 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
       Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
       constraint->selfExplaining();
     }else{
-      Debug("arith::constraint") << "already has proof: " << constraint->explainForConflict() << endl;
+      Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
     }
 
     return constraint;
   }
 }
 
-bool TheoryArithPrivate::assertionCases(Constraint constraint){
+bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
   Assert(constraint->hasProof());
   Assert(!constraint->negationHasProof());
 
@@ -1609,11 +1912,12 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
   switch(constraint->getType()){
   case UpperBound:
     if(isInteger(x_i) && constraint->isStrictUpperBound()){
-      Constraint floorConstraint = constraint->getFloor();
+      ConstraintP floorConstraint = constraint->getFloor();
       if(!floorConstraint->isTrue()){
         if(floorConstraint->negationHasProof()){
-          Node conf = ConstraintValue::explainConflict(constraint, floorConstraint->getNegation());
-          raiseConflict(conf);
+          raiseConflict(constraint, floorConstraint->getNegation());
+          //Node conf = Constraint_::explainConflict(constraint, floorConstraint->getNegation());
+          //raiseConflict(conf);
           return true;
         }else{
           floorConstraint->impliedBy(constraint);
@@ -1626,11 +1930,12 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
     }
   case LowerBound:
     if(isInteger(x_i) && constraint->isStrictLowerBound()){
-      Constraint ceilingConstraint = constraint->getCeiling();
+      ConstraintP ceilingConstraint = constraint->getCeiling();
       if(!ceilingConstraint->isTrue()){
         if(ceilingConstraint->negationHasProof()){
-          Node conf = ConstraintValue::explainConflict(constraint, ceilingConstraint->getNegation());
-          raiseConflict(conf);
+          raiseConflict(constraint, ceilingConstraint->getNegation());
+          //Node conf = Constraint_::explainConflict(constraint, ceilingConstraint->getNegation());
+          //raiseConflict(conf);
           return true;
         }
         ceilingConstraint->impliedBy(constraint);
@@ -1649,168 +1954,1165 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
     return false;
   }
 }
-
 /**
- * Looks for the next integer variable without an integer assignment in a round robin fashion.
- * Changes the value of d_nextIntegerCheckVar.
+ * Looks for through the variables starting at d_nextIntegerCheckVar
+ * for the first integer variable that is between its upper and lower bounds
+ * that has a non-integer assignment.
  *
- * If this returns false, d_nextIntegerCheckVar does not have an integer assignment.
- * If this returns true, all integer variables have an integer assignment.
+ * If assumeBounds is true, skip the check that the variable is in bounds.
+ *
+ * If there is no such variable, returns ARITHVAR_SENTINEL;
  */
-bool TheoryArithPrivate::hasIntegerModel(){
-  //if(d_variables.size() > 0){
+ArithVar TheoryArithPrivate::nextIntegerViolatation(bool assumeBounds) const {
   ArithVar numVars = d_partialModel.getNumberOfVariables();
+  ArithVar v = d_nextIntegerCheckVar;
   if(numVars > 0){
     const ArithVar rrEnd = d_nextIntegerCheckVar;
     do {
-      //Do not include slack variables
-      if(isInteger(d_nextIntegerCheckVar) && !isSlackVariable(d_nextIntegerCheckVar)) { // integer
-        const DeltaRational& d = d_partialModel.getAssignment(d_nextIntegerCheckVar);
-        if(!d.isIntegral()){
-          return false;
+      if(isIntegerInput(v)){
+        if(!d_partialModel.integralAssignment(v)){
+          if( assumeBounds || d_partialModel.assignmentIsConsistent(v) ){
+            return v;
+          }
         }
       }
-    } while((d_nextIntegerCheckVar = (1 + d_nextIntegerCheckVar == numVars ? 0 : 1 + d_nextIntegerCheckVar)) != rrEnd);
+      v= (1 + v == numVars) ? 0 : (1 + v);
+    }while(v != rrEnd);
+  }
+  return ARITHVAR_SENTINEL;
+}
+
+/**
+ * Checks the set of integer variables I to see if each variable
+ * in I has an integer assignment.
+ */
+bool TheoryArithPrivate::hasIntegerModel(){
+  ArithVar next = nextIntegerViolatation(true);
+  if(next != ARITHVAR_SENTINEL){
+    d_nextIntegerCheckVar = next;
+    if(Debug.isOn("arith::hasIntegerModel")){
+      Debug("arith::hasIntegerModel") << "has int model? " << next << endl;
+      d_partialModel.printModel(next, Debug("arith::hasIntegerModel"));
+    }
+    return false;
+  }else{
+    return true;
   }
-  return true;
 }
 
 /** Outputs conflicts to the output channel. */
 void TheoryArithPrivate::outputConflicts(){
-  Assert(!d_conflicts.empty());
-  for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
-    Node conflict = d_conflicts[i];
-    Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict << endl;
-    (d_containing.d_out)->conflict(conflict);
-  }
-}
-
-void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
-  //output the lemmas
-  for(vector<ArithVar>::const_iterator i = lemmas.begin(); i != lemmas.end(); ++i){
-    ArithVar v = *i;
-    Assert(!d_cutInContext.contains(v));
-    d_cutInContext.insert(v);
-    d_cutCount = d_cutCount + 1;
-    Node lem = branchIntegerVariable(v);
-    outputLemma(lem);
-    ++(d_statistics.d_externalBranchAndBounds);
+  Assert(anyConflict());
+  if(!conflictQueueEmpty()){
+    Assert(!d_conflicts.empty());
+    for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
+      const ConstraintCPVec& vec = d_conflicts[i];
+      Node conflict = Constraint_::externalExplainByAssertions(vec);
+      Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict << endl;
+      (d_containing.d_out)->conflict(conflict);
+    }
   }
+  if(!d_blackBoxConflict.get().isNull()){
+    Node bb = d_blackBoxConflict.get();
+    Debug("arith::conflict") << "black box conflict" << bb << endl;
+    (d_containing.d_out)->conflict(bb);
+  }
+}
+void TheoryArithPrivate::outputLemma(TNode lem) {
+  (d_containing.d_out)->lemma(lem);
 }
 
-bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
-  Assert(d_qflraStatus != Result::SAT);
+// void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
+//   //output the lemmas
+//   for(vector<ArithVar>::const_iterator i = lemmas.begin(); i != lemmas.end(); ++i){
+//     ArithVar v = *i;
+//     Assert(!d_cutInContext.contains(v));
+//     d_cutInContext.insert(v);
+//     d_cutCount = d_cutCount + 1;
+//     Node lem = branchIntegerVariable(v);
+//     outputLemma(lem);
+//     ++(d_statistics.d_externalBranchAndBounds);
+//   }
+// }
+
+bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){
+  int level = getSatContext()->getLevel();
+  Debug("approx")
+    << "attemptSolveInteger " << d_qflraStatus
+    << " " << emmmittedLemmaOrSplit
+    << " " << effortLevel
+    << " " << d_lastContextIntegerAttempted
+    << " " << level
+    << " " << hasIntegerModel()
+    << endl;
+
+  if(d_qflraStatus == Result::UNSAT){ return false; }
+  if(emmmittedLemmaOrSplit){ return false; }
+  if(!options::useApprox()){ return false; }
+  if(!ApproximateSimplex::enabled()){ return false; }
+
+  if(Theory::fullEffort(effortLevel)){
+    if(hasIntegerModel()){
+      return false;
+    }else{
+      return getSolveIntegerResource();
+    }
+  }
 
-  d_partialModel.stopQueueingBoundCounts();
-  UpdateTrackingCallback utcb(&d_linEq);
-  d_partialModel.processBoundsQueue(utcb);
-  d_linEq.startTrackingBoundCounts();
+  if(d_lastContextIntegerAttempted <= 0){
+    if(hasIntegerModel()){
+      d_lastContextIntegerAttempted = getSatContext()->getLevel();
+      return false;
+    }else{
+      return getSolveIntegerResource();
+    }
+  }
 
-  bool noPivotLimit = Theory::fullEffort(effortLevel) ||
-    !options::restrictedPivots();
 
-  bool emmittedConflictOrSplit = false;
+  if(!options::trySolveIntStandardEffort()){ return false; }
+
+  if (d_lastContextIntegerAttempted <= (level >> 2)){
 
-  SimplexDecisionProcedure& simplex =
-    options::useFC() ? (SimplexDecisionProcedure&)d_fcSimplex :
-    (options::useSOI() ? (SimplexDecisionProcedure&)d_soiSimplex :
-     (SimplexDecisionProcedure&)d_dualSimplex);
+    double d = (double)(d_solveIntMaybeHelp + 1) / (d_solveIntAttempts + 1 + level*level);
+    double t = fRand(0.0, 1.0);
+    if(t < d){
+      return getSolveIntegerResource();
+    }
+  }
+  return false;
+}
+
+bool TheoryArithPrivate::replayLog(ApproximateSimplex* approx){
+  TimerStat::CodeTimer codeTimer(d_statistics.d_replayLogTimer);
+
+  Assert(d_replayVariables.empty());
+  Assert(d_replayConstraints.empty());
+
+  size_t enteringPropN = d_currentPropagationList.size();
+  Assert(conflictQueueEmpty());
+  TreeLog& tl = getTreeLog();
+  //tl.applySelected(); /* set row ids */
 
-  bool useFancyFinal = options::fancyFinal() && ApproximateSimplex::enabled();
+  d_replayedLemmas = false;
+
+  std::vector<ConstraintCPVec> res;
+  try{
+    /* use the try block for the purpose of pushing the sat context */
+    context::Context::ScopedPush speculativePush(getSatContext());
+    d_cmEnabled = false;
+    res = replayLogRec(approx, tl.getRootId(), NullConstraint, 1);
+  }catch(RationalFromDoubleException& rfde){
+    turnOffApproxFor(options::replayNumericFailurePenalty());
+  }
+
+  for(size_t i =0, N = res.size(); i < N; ++i){
+    raiseConflict(res[i]);
+  }
+  if(res.empty()){
+    ++d_statistics.d_replayAttemptFailed;
+  }
+  if(d_currentPropagationList.size() > enteringPropN){
+    d_currentPropagationList.resize(enteringPropN);
+  }
 
-  if(!useFancyFinal){
-    d_qflraStatus = simplex.findModel(noPivotLimit);
+  Assert(d_replayVariables.empty());
+  Assert(d_replayConstraints.empty());
+
+  return !conflictQueueEmpty();
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch)
+{
+  ArithVar added = ARITHVAR_SENTINEL;
+  Node sum = toSumNode(d_partialModel, lhs);
+  if(sum.isNull()){ return make_pair(NullConstraint, added); }
+
+  Node norm = Rewriter::rewrite(sum);
+  DeltaRational dr(rhs);
+
+  ConstraintType t = (k == kind::LEQ) ? UpperBound : LowerBound;
+
+  Assert(!branch || d_partialModel.hasArithVar(norm));
+  ArithVar v = ARITHVAR_SENTINEL;
+  if(d_partialModel.hasArithVar(norm)){
+
+    v = d_partialModel.asArithVar(norm);
+    Debug("approx::constraint") << "replayGetConstraint found "
+                                << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
+    Assert(!branch || d_partialModel.isIntegerInput(v));
   }else{
-    // Fancy final tries the following strategy
-    // At final check, try the preferred simplex solver with a pivot cap
-    // If that failed, swap the the other simplex solver
-    // If that failed, check if there are integer variables to cut
-    // If that failed, do a simplex without a pivot limit
+    v = requestArithVar(norm, true, true);
+    d_replayVariables.push_back(v);
 
-    int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+    added = v;
 
-    static const int32_t pass2Limit = 10;
-    static const int32_t relaxationLimit = 10000;
-    static const int32_t mipLimit = 200000;
+    Debug("approx::constraint") << "replayGetConstraint adding "
+                                << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
 
-    //cout << "start" << endl;
-    d_qflraStatus = simplex.findModel(false);
-    //cout << "end" << endl;
-    if(d_qflraStatus == Result::SAT_UNKNOWN ||
-       (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
+    Polynomial poly = Polynomial::parsePolynomial(norm);
+    vector<ArithVar> variables;
+    vector<Rational> coefficients;
+    asVectors(poly, coefficients, variables);
+    d_tableau.addRow(v, coefficients, variables);
+    setupBasicValue(v);
+    d_linEq.trackRowIndex(d_tableau.basicToRowIndex(v));
+  }
+  Assert(d_partialModel.hasArithVar(norm));
+  Assert(d_partialModel.asArithVar(norm) == v);
+  Assert(d_constraintDatabase.variableDatabaseIsSetup(v));
+
+  ConstraintP imp = d_constraintDatabase.getBestImpliedBound(v, t, dr);
+  if(imp != NullConstraint){
+    if(imp->getValue() == dr){
+      Assert(added == ARITHVAR_SENTINEL);
+      return make_pair(imp, added);
+    }
+  }
+  ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr);
+  d_replayConstraints.push_back(newc);
+  return make_pair(newc, added);
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(ApproximateSimplex* approx, const NodeLog& nl) throw(RationalFromDoubleException){
+  Assert(nl.isBranch());
+  Assert(d_lhsTmp.empty());
+
+  ArithVar v = approx->getBranchVar(nl);
+  if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
+    if(d_partialModel.hasNode(v)){
+      d_lhsTmp.set(v, Rational(1));
+      double dval = nl.branchValue();
+      Rational val = ApproximateSimplex::estimateWithCFE(dval);
+      Rational fl(val.floor());
+      pair<ConstraintP, ArithVar> p;
+      p = replayGetConstraint(d_lhsTmp, kind::LEQ, fl, true);
+      d_lhsTmp.purge();
+      return p;
+    }
+  }
+  return make_pair(NullConstraint, ARITHVAR_SENTINEL);
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const CutInfo& ci) {
+  Assert(ci.reconstructed());
+  const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
+  const Rational& rhs = ci.getReconstruction().rhs;
+  Kind k = ci.getKind();
+
+  return replayGetConstraint(lhs, k, rhs, ci.getKlass() == BranchCutKlass);
+}
+
+// Node denseVectorToLiteral(const ArithVariables& vars, const DenseVector& dv, Kind k){
+//   NodeManager* nm = NodeManager::currentNM();
+//   Node sumLhs = toSumNode(vars, dv.lhs);
+//   Node ineq = nm->mkNode(k, sumLhs, mkRationalNode(dv.rhs) );
+//   Node lit = Rewriter::rewrite(ineq);
+//   return lit;
+// }
+
+Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum){
+  NodeBuilder<> nb(kind::PLUS);
+  NodeManager* nm = NodeManager::currentNM();
+  DenseMap<Rational>::const_iterator iter, end;
+  iter = sum.begin(), end = sum.end();
+  for(; iter != end; ++iter){
+    ArithVar x = *iter;
+    if(!vars.hasNode(x)){ return Node::null(); }
+    Node xNode = vars.asNode(x);
+    const Rational& q = sum[x];
+    nb << nm->mkNode(kind::MULT, mkRationalNode(q), xNode);
+  }
+  return safeConstructNary(nb);
+}
+
+
+void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bci){
+  Assert(conflictQueueEmpty());
+  std::vector< ConstraintCPVec > conflicts;
+
+  approx->tryCut(nid, bci);
+  Debug("approx::branch") << "tryBranchCut" << bci << endl;
+  Assert(bci.reconstructed());
+  Assert(!bci.proven());
+  pair<ConstraintP, ArithVar> p = replayGetConstraint(bci);
+  Assert(p.second == ARITHVAR_SENTINEL);
+  ConstraintP bc = p.first;
+  Assert(bc !=  NullConstraint);
+  if(bc->hasProof()){
+    return;
+  }
+
+  ConstraintP bcneg = bc->getNegation();
+  {
+    context::Context::ScopedPush speculativePush(getSatContext());
+    replayAssert(bcneg);
+    if(conflictQueueEmpty()){
+      TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
+
+      //test for linear feasibility
+      d_partialModel.stopQueueingBoundCounts();
+      UpdateTrackingCallback utcb(&d_linEq);
+      d_partialModel.processBoundsQueue(utcb);
+      d_linEq.startTrackingBoundCounts();
+
+      SimplexDecisionProcedure& simplex = selectSimplex(true);
+      simplex.findModel(false);
+
+      d_linEq.stopTrackingBoundCounts();
+      d_partialModel.startQueueingBoundCounts();
+    }
+    for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
+      conflicts.push_back(d_conflicts[i]);
+      // remove the floor/ceiling contraint implied by bcneg
+      Constraint_::assertionFringe(conflicts.back());
+    }
+
+    if(Debug.isOn("approx::branch")){
+      if(d_conflicts.empty()){
+        entireStateIsConsistent("branchfailure");
+      }
+    }
+  }
+
+  Debug("approx::branch") << "branch constraint " << bc << endl;
+  for(size_t i = 0, N = conflicts.size(); i < N; ++i){
+    ConstraintCPVec& conf = conflicts[i];
+
+    // make sure to be working on the assertion fringe!
+    if(!contains(conf, bcneg)){
+      Debug("approx::branch") << "reraise " << conf  << endl;
+      raiseConflict(conf);
+    }else if(!bci.proven()){
+      drop(conf, bcneg);
+      bci.setExplanation(conf);
+      Debug("approx::branch") << "dropped " << bci  << endl;
+    }
+  }
+}
 
-      ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel);
-      approxSolver->setPivotLimit(relaxationLimit);
+void TheoryArithPrivate::replayAssert(ConstraintP c) {
+  if(!c->assertedToTheTheory()){
+    if(c->negationHasProof()){
+      ConstraintP neg = c->getNegation();
+      raiseConflict(c, neg);
+      Debug("approx::replayAssert") << "replayAssertion conflict " << neg << " : " << c << endl;
+    }else if(!c->hasProof()){
+      c->setInternalDecision();
+      assertionCases(c);
+      Debug("approx::replayAssert") << "replayAssert " << c << " set internal" << endl;
+    }else{
+      assertionCases(c);
+      Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl;
+    }
+  }else{
+    Debug("approx::replayAssert") << "replayAssert " << c << " already asserted" << endl;
+  }
+}
 
-      if(!d_guessedCoeffSet){
-        d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
-        d_guessedCoeffSet = true;
+// ConstraintCPVec TheoryArithPrivate::toExplanation(Node n) const {
+//   ConstraintCPVec res;
+//   cout << "toExplanation" << endl;
+//   if(n.getKind() == kind::AND){
+//     for(unsigned i = 0; i < n.getNumChildren(); ++i){
+//       ConstraintP c = d_constraintDatabase.lookup(n[i]);
+//       if(c == NullConstraint){ return std::vector<Constraint>(); }
+//       res.push_back(c);
+//       cout << "\t"<<c << endl;
+//     }
+//   }else{
+//     ConstraintP c = d_constraintDatabase.lookup(n);
+//     if(c == NullConstraint){ return std::vector<Constraint>(); }
+//     res.push_back(c);
+//   }
+//   return res;
+// }
+
+// void TheoryArithPrivate::enqueueConstraints(std::vector<Constraint>& out, Node n) const{
+//   if(n.getKind() == kind::AND){
+//     for(unsigned i = 0, N = n.getNumChildren(); i < N; ++i){
+//       enqueueConstraints(out, n[i]);
+//     }
+//   }else{
+//     ConstraintP c = d_constraintDatabase.lookup(n);
+//     if(c == NullConstraint){
+//       cout << "failing on " << n << endl;
+//     }
+//     Assert(c != NullConstraint);
+//     out.push_back(c);
+//   }
+// }
+
+// ConstraintCPVec TheoryArithPrivate::resolveOutPropagated(const ConstraintCPVec& v, const std::set<ConstraintCP>& propagated) const {
+//   cout << "resolveOutPropagated()" << conf << endl;
+//   std::set<ConstraintCP> final;
+//   std::set<ConstraintCP> processed;
+//   std::vector<ConstraintCP> to_process;
+//   enqueueConstraints(to_process, conf);
+//   while(!to_process.empty()){
+//     ConstraintP c = to_process.back(); to_process.pop_back();
+//     if(processed.find(c) != processed.end()){
+//       continue;
+//     }else{
+//       if(propagated.find(c) == propagated.end()){
+//         final.insert(c);
+//       }else{
+//         Node exp = c->explainForPropagation();
+//         enqueueConstraints(to_process, exp);
+//       }
+//       processed.insert(c);
+//     }
+//   }
+//   cout << "final size: " << final.size() << std::endl;
+//   NodeBuilder<> nb(kind::AND);
+//   std::set<Constraint>::const_iterator iter = final.begin(), end = final.end();
+//   for(; iter != end; ++iter){
+//     ConstraintP c = *iter;
+//     c->explainForConflict(nb);
+//   }
+//   Node newConf = safeConstructNary(nb);
+//   cout << "resolveOutPropagated("<<conf<<", ...) ->" << newConf << endl;
+//   return newConf;
+// }
+
+void TheoryArithPrivate::resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const {
+  Debug("arith::resolveOutPropagated")
+    << "starting resolveOutPropagated() " << confs.size() << endl;
+  for(size_t i =0, N = confs.size(); i < N; ++i){
+    ConstraintCPVec& conf = confs[i];
+    size_t orig = conf.size();
+    Constraint_::assertionFringe(conf);
+    Debug("arith::resolveOutPropagated")
+      << "  conf["<<i<<"] " << orig << " to " << conf.size() << endl;
+  }
+  Debug("arith::resolveOutPropagated")
+    << "ending resolveOutPropagated() " << confs.size() << endl;
+}
+
+struct SizeOrd {
+  bool operator()(const ConstraintCPVec& a, const ConstraintCPVec& b) const{
+    return a.size() < b.size();
+  }
+};
+void TheoryArithPrivate::subsumption(std::vector<ConstraintCPVec>& confs) const {
+  int checks CVC4_UNUSED = 0;
+  int subsumed CVC4_UNUSED = 0;
+
+  for(size_t i =0, N= confs.size(); i < N; ++i){
+    ConstraintCPVec& conf = confs[i];
+    std::sort(conf.begin(), conf.end());
+  }
+
+  std::sort(confs.begin(), confs.end(), SizeOrd());
+  for(size_t i = 0; i < confs.size(); i++){
+    ConstraintCPVec& a = confs[i];
+    // i is not subsumed
+    for(size_t j = i+1; j < confs.size();){
+      ConstraintCPVec& b = confs[j];
+      checks++;
+      bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end());
+      if(subsumes){
+        ConstraintCPVec& back = confs.back();
+        b.swap(back);
+        confs.pop_back();
+        subsumed++;
+      }else{
+        j++;
       }
-      if(!d_guessedCoeffs.empty()){
-        approxSolver->setOptCoeffs(d_guessedCoeffs);
+    }
+  }
+  Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks << endl;
+}
+
+std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){
+  ++(d_statistics.d_replayLogRecCount);
+  Debug("approx::replayLogRec") << "replayLogRec()"
+                                << d_statistics.d_replayLogRecCount.getData() << std::endl;
+
+  size_t rpvars_size = d_replayVariables.size();
+  size_t rpcons_size = d_replayConstraints.size();
+  std::vector<ConstraintCPVec> res;
+
+  { /* create a block for the purpose of pushing the sat context */
+    context::Context::ScopedPush speculativePush(getSatContext());
+    Assert(!anyConflict());
+    Assert(conflictQueueEmpty());
+    set<ConstraintCP> propagated;
+
+    TreeLog& tl = getTreeLog();
+
+    if(bc != NullConstraint){
+      replayAssert(bc);
+    }
+
+    const NodeLog& nl = tl.getNode(nid);
+    NodeLog::const_iterator iter = nl.begin(), end = nl.end();
+    for(; conflictQueueEmpty() && iter != end; ++iter){
+      CutInfo* ci = *iter;
+      bool reject = false;
+      //cout << "  trying " << *ci << endl;
+      if(ci->getKlass() == RowsDeletedKlass){
+        RowsDeleted* rd = dynamic_cast<RowsDeleted*>(ci);
+
+        tl.applyRowsDeleted(nid, *rd);
+        // The previous line modifies nl
+
+        ++d_statistics.d_applyRowsDeleted;
+      }else if(ci->getKlass() == BranchCutKlass){
+        BranchCutInfo* bci = dynamic_cast<BranchCutInfo*>(ci);
+        Assert(bci != NULL);
+        tryBranchCut(approx, nid, *bci);
+
+        ++d_statistics.d_branchCutsAttempted;
+      }else{
+        approx->tryCut(nid, *ci);
+        if(ci->getKlass() == GmiCutKlass){
+          ++d_statistics.d_gmiCutsAttempted;
+        }else if(ci->getKlass() == MirCutKlass){
+          ++d_statistics.d_mirCutsAttempted;
+        }
+
+        if(ci->reconstructed() && ci->proven()){
+          const DenseMap<Rational>& row = ci->getReconstruction().lhs;
+          reject = !complexityBelow(row, options::replayRejectCutSize());
+        }
       }
+      if(conflictQueueEmpty()){
+        if(reject){
+          ++d_statistics.d_cutsRejectedDuringReplay;
+        }else if(ci->reconstructed()){
+          // success
+          ++d_statistics.d_cutsReconstructed;
+
+          pair<ConstraintP, ArithVar> p = replayGetConstraint(*ci);
+          if(p.second != ARITHVAR_SENTINEL){
+            Assert(ci->getRowId() >= 1);
+            tl.mapRowId(nl.getNodeId(), ci->getRowId(), p.second);
+          }
+          ConstraintP con = p.first;
+          if(Debug.isOn("approx::replayLogRec")){
+            Debug("approx::replayLogRec") << "cut was remade " << con << " " << *ci << endl;
+          }
 
-      ApproximateSimplex::ApproxResult relaxRes, mipRes;
-      ApproximateSimplex::Solution relaxSolution, mipSolution;
-      relaxRes = approxSolver->solveRelaxation();
-      switch(relaxRes){
-      case ApproximateSimplex::ApproxSat:
-        {
-          relaxSolution = approxSolver->extractRelaxation();
+          if(ci->proven()){
+            ++d_statistics.d_cutsProven;
 
-          if(d_likelyIntegerInfeasible){
-            d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+            const ConstraintCPVec& exp = ci->getExplanation();
+            // success
+            Assert(!con->negationHasProof());
+            if(con->isTrue()){
+              Debug("approx::replayLogRec") << "not asserted?" << endl;
+            }else{
+              con->impliedBy(exp);
+              replayAssert(con);
+              Debug("approx::replayLogRec") << "cut prop" << endl;
+            }
           }else{
-            approxSolver->setPivotLimit(mipLimit);
-            mipRes = approxSolver->solveMIP();
-            d_errorSet.reduceToSignals();
-            //Message() << "here" << endl;
-            if(mipRes == ApproximateSimplex::ApproxSat){
-              mipSolution = approxSolver->extractMIP();
-              d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+            ++d_statistics.d_cutsProofFailed;
+            Debug("approx::replayLogRec") << "failed to get proof " << *ci << endl;
+          }
+        }else if(ci->getKlass() != RowsDeletedKlass){
+          ++d_statistics.d_cutsReconstructionFailed;
+        }
+      }
+    }
+
+    /* check if the system is feasible under with the cuts */
+    if(conflictQueueEmpty()){
+      Assert(options::replayEarlyCloseDepths() >= 1);
+      if(!nl.isBranch() || depth % options::replayEarlyCloseDepths() == 0 ){
+        TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
+        //test for linear feasibility
+        d_partialModel.stopQueueingBoundCounts();
+        UpdateTrackingCallback utcb(&d_linEq);
+        d_partialModel.processBoundsQueue(utcb);
+        d_linEq.startTrackingBoundCounts();
+
+        SimplexDecisionProcedure& simplex = selectSimplex(true);
+        simplex.findModel(false);
+
+        d_linEq.stopTrackingBoundCounts();
+        d_partialModel.startQueueingBoundCounts();
+      }
+    }else{
+      ++d_statistics.d_replayLogRecConflictEscalation;
+    }
+
+    if(!conflictQueueEmpty()){
+      /* if a conflict has been found stop */
+      for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
+        res.push_back(d_conflicts[i]);
+      }
+      ++d_statistics.d_replayLogRecEarlyExit;
+    }else if(nl.isBranch()){
+      /* if it is a branch try the branch */
+      pair<ConstraintP, ArithVar> p = replayGetConstraint(approx, nl);
+      Assert(p.second == ARITHVAR_SENTINEL);
+      ConstraintP dnc = p.first;
+      if(dnc != NullConstraint){
+        ConstraintP upc = dnc->getNegation();
+
+        int dnid = nl.getDownId();
+        int upid = nl.getUpId();
+
+        NodeLog& dnlog = tl.getNode(dnid);
+        NodeLog& uplog = tl.getNode(upid);
+        dnlog.copyParentRowIds();
+        uplog.copyParentRowIds();
+
+        std::vector<ConstraintCPVec> dnres;
+        std::vector<ConstraintCPVec> upres;
+        std::vector<size_t> containsdn;
+        std::vector<size_t> containsup;
+        if(res.empty()){
+          dnres = replayLogRec(approx, dnid, dnc, depth+1);
+          for(size_t i = 0, N = dnres.size(); i < N; ++i){
+            ConstraintCPVec& conf = dnres[i];
+            if(contains(conf, dnc)){
+              containsdn.push_back(i);
             }else{
-              if(mipRes == ApproximateSimplex::ApproxUnsat){
-                d_likelyIntegerInfeasible = true;
-              }
-              d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+              res.push_back(conf);
             }
           }
-          options::arithStandardCheckVarOrderPivots.set(pass2Limit);
-          if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
-          //Message() << "done" << endl;
+        }else{
+          Debug("approx::replayLogRec") << "replayLogRec() skipping" << dnlog << std::endl;
+          ++d_statistics.d_replayBranchSkips;
         }
-        break;
-      case ApproximateSimplex::ApproxUnsat:
-        {
-          ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
 
-          d_qflraStatus = d_attemptSolSimplex.attempt(sol);
-          options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+        if(res.empty()){
+          upres = replayLogRec(approx, upid, upc, depth+1);
 
-          if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+          for(size_t i = 0, N = upres.size(); i < N; ++i){
+            ConstraintCPVec& conf = upres[i];
+            if(contains(conf, upc)){
+              containsup.push_back(i);
+            }else{
+              res.push_back(conf);
+            }
+          }
+        }else{
+          Debug("approx::replayLogRec") << "replayLogRec() skipping" << uplog << std::endl;
+          ++d_statistics.d_replayBranchSkips;
+        }
+
+        if(res.empty()){
+          for(size_t i = 0, N = containsdn.size(); i < N; ++i){
+            ConstraintCPVec& dnconf = dnres[containsdn[i]];
+            for(size_t j = 0, M = containsup.size(); j < M; ++j){
+              ConstraintCPVec& upconf = upres[containsup[j]];
+
+              res.push_back(ConstraintCPVec());
+              ConstraintCPVec& back = res.back();
+              resolve(back, dnc, dnconf, upconf);
+            }
+          }
+          if(res.size() >= 2u){
+            subsumption(res);
+
+            if(res.size() > 100u){
+              res.resize(100u);
+            }
+          }
+        }else{
+          Debug("approx::replayLogRec") << "replayLogRec() skipping resolving" << nl << std::endl;
+        }
+        Debug("approx::replayLogRec") << "found #"<<res.size()<<" conflicts on branch " << nid << endl;
+        if(res.empty()){
+          ++d_statistics.d_replayBranchCloseFailures;
+        }
+
+      }else{
+        Debug("approx::replayLogRec") << "failed to make a branch " << nid << endl;
+      }
+    }else{
+      ++d_statistics.d_replayLeafCloseFailures;
+      Debug("approx::replayLogRec") << "failed on node " << nid << endl;
+      Assert(res.empty());
+    }
+    resolveOutPropagated(res, propagated);
+    Debug("approx::replayLogRec") << "replayLogRec() ending" << std::endl;
+
+
+    if(options::replayFailureLemma()){
+      // must be done inside the sat context to get things
+      // propagated at this level
+      if(res.empty() && nid == getTreeLog().getRootId()){
+        Assert(!d_replayedLemmas);
+        d_replayedLemmas = replayLemmas(approx);
+        Assert(d_acTmp.empty());
+        while(!d_approxCuts.empty()){
+          Node lem = d_approxCuts.front();
+          d_approxCuts.pop();
+          d_acTmp.push_back(lem);
+        }
+      }
+    }
+  } /* pop the sat context */
+
+  /* move into the current context. */
+  while(!d_acTmp.empty()){
+    Node lem = d_acTmp.back();
+    d_acTmp.pop_back();
+    d_approxCuts.push_back(lem);
+  }
+  Assert(d_acTmp.empty());
+
+
+  /* Garbage collect the constraints from this call */
+  while(d_replayConstraints.size() > rpcons_size){
+    ConstraintP c = d_replayConstraints.back();
+    d_replayConstraints.pop_back();
+    d_constraintDatabase.deleteConstraintAndNegation(c);
+  }
+
+  /* Garbage collect the ArithVars made by this call */
+  if(d_replayVariables.size() > rpvars_size){
+    d_partialModel.stopQueueingBoundCounts();
+    UpdateTrackingCallback utcb(&d_linEq);
+    d_partialModel.processBoundsQueue(utcb);
+    d_linEq.startTrackingBoundCounts();
+    while(d_replayVariables.size() > rpvars_size){
+      ArithVar v = d_replayVariables.back();
+      d_replayVariables.pop_back();
+      Assert(d_partialModel.canBeReleased(v));
+      if(!d_tableau.isBasic(v)){
+        /* if it is not basic make it basic. */
+        ArithVar b = ARITHVAR_SENTINEL;
+        for(Tableau::ColIterator ci = d_tableau.colIterator(v); !ci.atEnd(); ++ci){
+          const Tableau::Entry& e = *ci;
+          b = d_tableau.rowIndexToBasic(e.getRowIndex());
+          break;
+        }
+        Assert(b != ARITHVAR_SENTINEL);
+        DeltaRational cp = d_partialModel.getAssignment(b);
+        if(d_partialModel.cmpAssignmentLowerBound(b) < 0){
+          cp = d_partialModel.getLowerBound(b);
+        }else if(d_partialModel.cmpAssignmentUpperBound(b) > 0){
+          cp = d_partialModel.getUpperBound(b);
+        }
+        d_linEq.pivotAndUpdate(b, v, cp);
+      }
+      Assert(d_tableau.isBasic(v));
+      d_linEq.stopTrackingRowIndex(d_tableau.basicToRowIndex(v));
+      d_tableau.removeBasicRow(v);
+
+      releaseArithVar(v);
+      Debug("approx::vars") << "releasing " << v << endl;
+    }
+    d_linEq.stopTrackingBoundCounts();
+    d_partialModel.startQueueingBoundCounts();
+    d_partialModel.attemptToReclaimReleased();
+  }
+  return res;
+}
+
+TreeLog& TheoryArithPrivate::getTreeLog(){
+  if(d_treeLog == NULL){
+    d_treeLog = new TreeLog();
+  }
+  return *d_treeLog;
+}
+
+ApproximateStatistics& TheoryArithPrivate::getApproxStats(){
+  if(d_approxStats == NULL){
+    d_approxStats = new ApproximateStatistics();
+  }
+  return *d_approxStats;
+}
+
+Node TheoryArithPrivate::branchToNode(ApproximateSimplex*  approx, const NodeLog& bn) const throw(RationalFromDoubleException) {
+  Assert(bn.isBranch());
+  ArithVar v = approx->getBranchVar(bn);
+  if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
+    if(d_partialModel.hasNode(v)){
+      Node n = d_partialModel.asNode(v);
+      double dval = bn.branchValue();
+      Rational val = ApproximateSimplex::estimateWithCFE(dval);
+      Rational fl(val.floor());
+      NodeManager* nm = NodeManager::currentNM();
+      Node leq = nm->mkNode(kind::LEQ, n, mkRationalNode(fl));
+      Node norm = Rewriter::rewrite(leq);
+      return norm;
+    }
+  }
+  return Node::null();
+}
+
+Node TheoryArithPrivate::cutToLiteral(ApproximateSimplex* approx, const CutInfo& ci) const{
+  Assert(ci.reconstructed());
+
+  const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
+  Node sum = toSumNode(d_partialModel, lhs);
+  if(!sum.isNull()){
+    Kind k = ci.getKind();
+    Assert(k == kind::LEQ || k == kind::GEQ);
+    Node rhs = mkRationalNode(ci.getReconstruction().rhs);
+
+    NodeManager* nm = NodeManager::currentNM();
+    Node ineq = nm->mkNode(k, sum, rhs);
+    return Rewriter::rewrite(ineq);
+  }
+  return Node::null();
+}
+
+bool TheoryArithPrivate::replayLemmas(ApproximateSimplex* approx){
+  try{
+    ++(d_statistics.d_mipReplayLemmaCalls);
+    bool anythingnew = false;
+
+    TreeLog& tl = getTreeLog();
+    NodeLog& root = tl.getRootNode();
+    root.applySelected(); /* set row ids */
+
+    vector<const CutInfo*> cuts = approx->getValidCuts(root);
+    for(size_t i =0, N =cuts.size(); i < N; ++i){
+      const CutInfo* cut = cuts[i];
+      Assert(cut->reconstructed());
+      Assert(cut->proven());
+
+      const DenseMap<Rational>& row =  cut->getReconstruction().lhs;
+      if(!complexityBelow(row, options::lemmaRejectCutSize())){
+        ++(d_statistics.d_cutsRejectedDuringLemmas);
+        continue;
+      }
+
+      Node cutConstraint = cutToLiteral(approx, *cut);
+      if(!cutConstraint.isNull()){
+        const ConstraintCPVec& exp = cut->getExplanation();
+        Node asLemma = Constraint_::externalExplainByAssertions(exp);
+
+        Node implied = Rewriter::rewrite(cutConstraint);
+        anythingnew = anythingnew || !isSatLiteral(implied);
+
+        Node implication = asLemma.impNode(implied);
+        // DO NOT CALL OUTPUT LEMMA!
+        d_approxCuts.push_back(implication);
+        Debug("approx::lemmas") << "cut["<<i<<"] " << implication << endl;
+        ++(d_statistics.d_mipExternalCuts);
+      }
+    }
+    if(root.isBranch()){
+      Node lit = branchToNode(approx, root);
+      if(!lit.isNull()){
+        anythingnew = anythingnew || !isSatLiteral(lit);
+        Node branch = lit.orNode(lit.notNode());
+        d_approxCuts.push_back(branch);
+        ++(d_statistics.d_mipExternalBranch);
+        Debug("approx::lemmas") << "branching "<< root <<" as " << branch << endl;
+      }
+    }
+    return anythingnew;
+  }catch(RationalFromDoubleException& rfde){
+    turnOffApproxFor(options::replayNumericFailurePenalty());
+    return false;
+  }
+}
+
+void TheoryArithPrivate::turnOffApproxFor(int32_t rounds){
+  d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff + rounds;
+  ++(d_statistics.d_approxDisabled);
+}
+
+bool TheoryArithPrivate::safeToCallApprox() const{
+  unsigned numRows = 0;
+  unsigned numCols = 0;
+  var_iterator vi = var_begin(), vi_end = var_end();
+  // Assign each variable to a row and column variable as it appears in the input
+  for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){
+    ArithVar v = *vi;
+
+    if(d_partialModel.isAuxiliary(v)){
+      ++numRows;
+    }else{
+      ++numCols;
+    }
+  }
+  return (numRows > 0 && numCols > 0);
+}
+
+// solve()
+//   res = solveRealRelaxation(effortLevel);
+//   switch(res){
+//   case LinFeas:
+//   case LinInfeas:
+//     return replay()
+//   case Unknown:
+//   case Error
+//     if()
+void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){
+  if(!safeToCallApprox()) { return; }
+
+  Assert(safeToCallApprox());
+  TimerStat::CodeTimer codeTimer(d_statistics.d_solveIntTimer);
+
+  ++(d_statistics.d_solveIntCalls);
+  d_statistics.d_inSolveInteger.setData(1);
+
+  if(!Theory::fullEffort(effortLevel)){
+    d_solveIntAttempts++;
+    ++(d_statistics.d_solveStandardEffort);
+  }
+
+  // if integers are attempted,
+  Assert(options::useApprox());
+  Assert(ApproximateSimplex::enabled());
+
+  int level = getSatContext()->getLevel();
+  d_lastContextIntegerAttempted = level;
+
+
+  static const int32_t mipLimit = 200000;
+
+  TreeLog& tl = getTreeLog();
+  ApproximateStatistics& stats = getApproxStats();
+  ApproximateSimplex* approx =
+    ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
+
+  try{
+    approx->setPivotLimit(mipLimit);
+    if(!d_guessedCoeffSet){
+      d_guessedCoeffs = approx->heuristicOptCoeffs();
+      d_guessedCoeffSet = true;
+    }
+    if(!d_guessedCoeffs.empty()){
+      approx->setOptCoeffs(d_guessedCoeffs);
+    }
+    static const int32_t depthForLikelyInfeasible = 10;
+    int maxDepthPass1 = d_likelyIntegerInfeasible ?
+      depthForLikelyInfeasible : options::maxApproxDepth();
+    approx->setBranchingDepth(maxDepthPass1);
+    approx->setBranchOnVariableLimit(100);
+    LinResult relaxRes = approx->solveRelaxation();
+    if( relaxRes == LinFeasible ){
+      MipResult mipRes = approx->solveMIP(false);
+      Debug("arith::solveInteger") << "mipRes " << mipRes << endl;
+      switch(mipRes) {
+      case MipBingo:
+        // attempt the solution
+        {
+          d_partialModel.stopQueueingBoundCounts();
+          UpdateTrackingCallback utcb(&d_linEq);
+          d_partialModel.processBoundsQueue(utcb);
+          d_linEq.startTrackingBoundCounts();
+
+          ApproximateSimplex::Solution mipSolution;
+          mipSolution = approx->extractMIP();
+          importSolution(mipSolution);
+          solveRelaxationOrPanic(effortLevel);
+
+          // shutdown simplex
+          d_linEq.stopTrackingBoundCounts();
+          d_partialModel.startQueueingBoundCounts();
         }
         break;
-      default:
+      case MipClosed:
+        /* All integer branches closed */
+        approx->setPivotLimit(2*mipLimit);
+        mipRes = approx->solveMIP(true);
+        if(mipRes == MipClosed){
+          d_likelyIntegerInfeasible = true;
+          replayLog(approx);
+        }
+        if(!(anyConflict() || !d_approxCuts.empty())){
+          turnOffApproxFor(options::replayNumericFailurePenalty());
+        }
+        break;
+      case BranchesExhausted:
+      case ExecExhausted:
+      case PivotsExhauasted:
+        if(mipRes == BranchesExhausted){
+          ++d_statistics.d_branchesExhausted;
+        }else if(mipRes == ExecExhausted){
+          ++d_statistics.d_execExhausted;
+        }else if(mipRes == PivotsExhauasted){
+          ++d_statistics.d_pivotsExhausted;
+        }
+
+        approx->setPivotLimit(2*mipLimit);
+        approx->setBranchingDepth(2);
+        mipRes = approx->solveMIP(true);
+        replayLemmas(approx);
+        break;
+      case MipUnknown:
         break;
       }
-      delete approxSolver;
     }
+  }catch(RationalFromDoubleException& rfde){
+    turnOffApproxFor(options::replayNumericFailurePenalty());
+  }
+  delete approx;
 
-    if(d_qflraStatus == Result::SAT_UNKNOWN){
-      //Message() << "got sat unknown" << endl;
-      vector<ArithVar> toCut = cutAllBounded();
-      if(toCut.size() > 0){
-        branchVector(toCut);
-        emmittedConflictOrSplit = true;
-      }else{
-        //Message() << "splitting" << endl;
+  if(!Theory::fullEffort(effortLevel)){
+    if(anyConflict() || !d_approxCuts.empty()){
+      d_solveIntMaybeHelp++;
+    }
+  }
 
-        d_qflraStatus = simplex.findModel(noPivotLimit);
+  d_statistics.d_inSolveInteger.setData(0);
+}
+
+SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){
+  if(pass1){
+    if(d_pass1SDP == NULL){
+      if(options::useFC()){
+        d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
+      }else if(options::useSOI()){
+        d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
+      }else{
+        d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex);
+      }
+    }
+    Assert(d_pass1SDP != NULL);
+    return *d_pass1SDP;
+  }else{
+     if(d_otherSDP == NULL){
+      if(options::useFC()){
+        d_otherSDP  = (SimplexDecisionProcedure*)(&d_fcSimplex);
+      }else if(options::useSOI()){
+        d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
+      }else{
+        d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
       }
     }
+    Assert(d_otherSDP != NULL);
+    return *d_otherSDP;
+  }
+}
+
+void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solution){
+  if(Debug.isOn("arith::importSolution")){
+    Debug("arith::importSolution") << "importSolution before " << d_qflraStatus << endl;
+    d_partialModel.printEntireModel(Debug("arith::importSolution"));
+  }
+
+  d_qflraStatus = d_attemptSolSimplex.attempt(solution);
+
+  if(Debug.isOn("arith::importSolution")){
+    Debug("arith::importSolution") << "importSolution intermediate " << d_qflraStatus << endl;
+    d_partialModel.printEntireModel(Debug("arith::importSolution"));
+  }
+
+  if(d_qflraStatus != Result::UNSAT){
+    static const int32_t pass2Limit = 20;
+    int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+    options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+    SimplexDecisionProcedure& simplex = selectSimplex(false);
+    d_qflraStatus = simplex.findModel(false);
     options::arithStandardCheckVarOrderPivots.set(oldCap);
   }
 
+  if(Debug.isOn("arith::importSolution")){
+    Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl;
+    d_partialModel.printEntireModel(Debug("arith::importSolution"));
+  }
+}
+
+bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel){
+  // if at this point the linear relaxation is still unknown,
+  //  attempt to branch an integer variable as a last ditch effort on full check
+  if(d_qflraStatus == Result::SAT_UNKNOWN){
+    d_qflraStatus = selectSimplex(true).findModel(false);
+  }
+
+  if(Theory::fullEffort(effortLevel)  && d_qflraStatus == Result::SAT_UNKNOWN){
+    ArithVar canBranch = nextIntegerViolatation(false);
+    if(canBranch != ARITHVAR_SENTINEL){
+      ++d_statistics.d_panicBranches;
+      Node branch = branchIntegerVariable(canBranch);
+      Assert(branch.getKind() == kind::OR);
+      Node rwbranch = Rewriter::rewrite(branch[0]);
+      if(!isSatLiteral(rwbranch)){
+        d_approxCuts.push_back(branch);
+        return true;
+      }
+    }
+    d_qflraStatus = selectSimplex(false).findModel(true);
+  }
+  return false;
+}
+
+bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
+  TimerStat::CodeTimer codeTimer(d_statistics.d_solveRealRelaxTimer);
+  Assert(d_qflraStatus != Result::SAT);
+
+  d_partialModel.stopQueueingBoundCounts();
+  UpdateTrackingCallback utcb(&d_linEq);
+  d_partialModel.processBoundsQueue(utcb);
+  d_linEq.startTrackingBoundCounts();
+
+  bool noPivotLimit = Theory::fullEffort(effortLevel) ||
+    !options::restrictedPivots();
+
+  SimplexDecisionProcedure& simplex = selectSimplex(true);
+
+  bool useApprox = options::useApprox() && ApproximateSimplex::enabled() && getSolveIntegerResource();
+
+  bool noPivotLimitPass1 = noPivotLimit && !useApprox;
+  d_qflraStatus = simplex.findModel(noPivotLimitPass1);
+
+  if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
+    // pass2: fancy-final
+    static const int32_t relaxationLimit = 10000;
+    Assert(ApproximateSimplex::enabled());
+
+    TreeLog& tl = getTreeLog();
+    ApproximateStatistics& stats = getApproxStats();
+    ApproximateSimplex* approxSolver =
+      ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
+
+    approxSolver->setPivotLimit(relaxationLimit);
+
+    if(!d_guessedCoeffSet){
+      d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+      d_guessedCoeffSet = true;
+    }
+    if(!d_guessedCoeffs.empty()){
+      approxSolver->setOptCoeffs(d_guessedCoeffs);
+    }
+
+    ++d_statistics.d_relaxCalls;
+
+    ApproximateSimplex::Solution relaxSolution;
+    LinResult relaxRes = approxSolver->solveRelaxation();
+    try{
+      Debug("solveRealRelaxation") << "solve relaxation? " << endl;
+      switch(relaxRes){
+      case LinFeasible:
+        Debug("solveRealRelaxation") << "lin feasible? " << endl;
+        ++d_statistics.d_relaxLinFeas;
+        relaxSolution = approxSolver->extractRelaxation();
+        importSolution(relaxSolution);
+        if(d_qflraStatus != Result::SAT){
+          ++d_statistics.d_relaxLinFeasFailures;
+        }
+        break;
+      case LinInfeasible:
+        // todo attempt to recreate approximate conflict
+        ++d_statistics.d_relaxLinInfeas;
+        Debug("solveRealRelaxation") << "lin infeasible " << endl;
+        relaxSolution = approxSolver->extractRelaxation();
+        importSolution(relaxSolution);
+        if(d_qflraStatus != Result::UNSAT){
+          ++d_statistics.d_relaxLinInfeasFailures;
+        }
+        break;
+      case LinExhausted:
+        ++d_statistics.d_relaxLinExhausted;
+        Debug("solveRealRelaxation") << "exhuasted " << endl;
+        break;
+      case LinUnknown:
+      default:
+        ++d_statistics.d_relaxOthers;
+        break;
+      }
+    }catch(RationalFromDoubleException& rfde){
+      turnOffApproxFor(options::replayNumericFailurePenalty());
+    }
+    delete approxSolver;
+
+  }
+
+  bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel);
+
   // TODO Save zeroes with no conflicts
   d_linEq.stopTrackingBoundCounts();
   d_partialModel.startQueueingBoundCounts();
@@ -1818,8 +3120,162 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
   return emmittedConflictOrSplit;
 }
 
+//   LinUnknown,  /* Unknown error */
+//   LinFeasible, /* Relaxation is feasible */
+//   LinInfeasible,   /* Relaxation is infeasible/all integer branches closed */
+//   LinExhausted
+//     // Fancy final tries the following strategy
+//     // At final check, try the preferred simplex solver with a pivot cap
+//     // If that failed, swap the the other simplex solver
+//     // If that failed, check if there are integer variables to cut
+//     // If that failed, do a simplex without a pivot limit
+
+//     int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+
+//     static const int32_t pass2Limit = 10;
+//     static const int32_t relaxationLimit = 10000;
+//     static const int32_t mipLimit = 200000;
+
+//     //cout << "start" << endl;
+//     d_qflraStatus = simplex.findModel(false);
+//     //cout << "end" << endl;
+//     if(d_qflraStatus == Result::SAT_UNKNOWN ||
+//        (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
+
+//       ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, *(getTreeLog()), *(getApproxStats()));
+//       approxSolver->setPivotLimit(relaxationLimit);
+
+//       if(!d_guessedCoeffSet){
+//         d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+//         d_guessedCoeffSet = true;
+//       }
+//       if(!d_guessedCoeffs.empty()){
+//         approxSolver->setOptCoeffs(d_guessedCoeffs);
+//       }
+
+//       MipResult mipRes;
+//       ApproximateSimplex::Solution relaxSolution, mipSolution;
+//       LinResult relaxRes = approxSolver->solveRelaxation();
+//       switch(relaxRes){
+//       case LinFeasible:
+//         {
+//           relaxSolution = approxSolver->extractRelaxation();
+
+//           /* If the approximate solver  known to be integer infeasible
+//            * only redo*/
+//           int maxDepth =
+//             d_likelyIntegerInfeasible ? 1 : options::arithMaxBranchDepth();
+
+
+//           if(d_likelyIntegerInfeasible){
+//             d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+//           }else{
+//             approxSolver->setPivotLimit(mipLimit);
+//             mipRes = approxSolver->solveMIP(false);
+//             if(mipRes == ApproximateSimplex::ApproxUnsat){
+//               mipRes = approxSolver->solveMIP(true);
+//             }
+//             d_errorSet.reduceToSignals();
+//             //Message() << "here" << endl;
+//             if(mipRes == ApproximateSimplex::ApproxSat){
+//               mipSolution = approxSolver->extractMIP();
+//               d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+//             }else{
+//               if(mipRes == ApproximateSimplex::ApproxUnsat){
+//                 d_likelyIntegerInfeasible = true;
+//               }
+//               vector<Node> lemmas = approxSolver->getValidCuts();
+//               for(size_t i = 0; i < lemmas.size(); ++i){
+//                 d_approxCuts.pushback(lemmas[i]);
+//               }
+//               d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+//             }
+//           }
+//           options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+//           if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+//           //Message() << "done" << endl;
+//         }
+//         break;
+//       case ApproximateSimplex::ApproxUnsat:
+//         {
+//           ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
+
+//           d_qflraStatus = d_attemptSolSimplex.attempt(sol);
+//           options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+
+//           if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+//         }
+//         break;
+//       default:
+//         break;
+//       }
+//       delete approxSolver;
+//     }
+//   }
+
+//   if(!useFancyFinal){
+//     d_qflraStatus = simplex.findModel(noPivotLimit);
+//   }else{
+    
+
+//     if(d_qflraStatus == Result::SAT_UNKNOWN){
+//       //Message() << "got sat unknown" << endl;
+//       vector<ArithVar> toCut = cutAllBounded();
+//       if(toCut.size() > 0){
+//         //branchVector(toCut);
+//         emmittedConflictOrSplit = true;
+//       }else{
+//         //Message() << "splitting" << endl;
+
+//         d_qflraStatus = simplex.findModel(noPivotLimit);
+//       }
+//     }
+//     options::arithStandardCheckVarOrderPivots.set(oldCap);
+//   }
+
+//   // TODO Save zeroes with no conflicts
+//   d_linEq.stopTrackingBoundCounts();
+//   d_partialModel.startQueueingBoundCounts();
+
+//   return emmittedConflictOrSplit;
+// }
+
+bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
+  switch(n.getKind()){
+  case kind::LEQ:
+  case kind::GEQ:
+  case kind::GT:
+  case kind::LT:
+    return !isSatLiteral(n);
+  case kind::EQUAL:
+    if(n[0].getType().isReal()){
+      return !isSatLiteral(n);
+    }else if(n[0].getType().isBoolean()){
+      return hasFreshArithLiteral(n[0]) ||
+        hasFreshArithLiteral(n[1]);
+    }else{
+      return false;
+    }
+  case kind::IMPLIES:
+    // try the rhs first
+    return hasFreshArithLiteral(n[1]) ||
+      hasFreshArithLiteral(n[0]);
+  default:
+    if(n.getType().isBoolean()){
+      for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){
+        Node child = *ni;
+        if(hasFreshArithLiteral(child)){
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+}
+
 void TheoryArithPrivate::check(Theory::Effort effortLevel){
   Assert(d_currentPropagationList.empty());
+  //cout << "TheoryArithPrivate::check " << effortLevel << std::endl;
   Debug("effortlevel") << "TheoryArithPrivate::check " << effortLevel << std::endl;
   Debug("arith") << "TheoryArithPrivate::check begun " << effortLevel << std::endl;
 
@@ -1837,28 +3293,28 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
   }
 
   while(!done()){
-    Constraint curr = constraintFromFactQueue();
+    ConstraintP curr = constraintFromFactQueue();
     if(curr != NullConstraint){
       bool res CVC4_UNUSED = assertionCases(curr);
-      Assert(!res || inConflict());
+      Assert(!res || anyConflict());
     }
-    if(inConflict()){ break; }
+    if(anyConflict()){ break; }
   }
-  if(!inConflict()){
+  if(!anyConflict()){
     while(!d_learnedBounds.empty()){
       // we may attempt some constraints twice.  this is okay!
-      Constraint curr = d_learnedBounds.front();
+      ConstraintP curr = d_learnedBounds.front();
       d_learnedBounds.pop();
       Debug("arith::learned") << curr << endl;
 
       bool res CVC4_UNUSED = assertionCases(curr);
-      Assert(!res || inConflict());
+      Assert(!res || anyConflict());
 
-      if(inConflict()){ break; }
+      if(anyConflict()){ break; }
     }
   }
 
-  if(inConflict()){
+  if(anyConflict()){
     d_qflraStatus = Result::UNSAT;
     if(options::revertArithModels() && previous == Result::SAT){
       ++d_statistics.d_revertsOnConflicts;
@@ -1872,6 +3328,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
       revertOutOfConflict();
     }
     outputConflicts();
+    //cout << "unate conflict 1 " << effortLevel << std::endl;
     return;
   }
 
@@ -1884,9 +3341,33 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
   Assert(d_conflicts.empty());
 
   bool useSimplex = d_qflraStatus != Result::SAT;
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "pre realRelax" << endl;
+
   if(useSimplex){
     emmittedConflictOrSplit = solveRealRelaxation(effortLevel);
   }
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "post realRelax" << endl;
+
+
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "pre solveInteger" << endl;
+
+  if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){
+    solveInteger(effortLevel);
+    if(anyConflict()){
+      ++d_statistics.d_commitsOnConflicts;
+      Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus  << endl;
+      revertOutOfConflict();
+      d_errorSet.clear();
+      outputConflicts();
+      return;
+    }
+  }
+
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "post solveInteger" << endl;
 
   switch(d_qflraStatus){
   case Result::SAT:
@@ -1944,6 +3425,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
     }
     outputConflicts();
     emmittedConflictOrSplit = true;
+    Debug("arith::conflict") << "simplex conflict" << endl;
 
     if(useSimplex && options::collectPivots()){
       if(options::useFC()){
@@ -1958,6 +3440,26 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
   }
   d_statistics.d_avgUnknownsInARow.addEntry(d_unknownsInARow);
 
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "pre approx cuts" << endl;
+  if(!d_approxCuts.empty()){
+    bool anyFresh = false;
+    while(!d_approxCuts.empty()){
+      Node lem = d_approxCuts.front();
+      d_approxCuts.pop();
+      Debug("arith::approx::cuts") << "approximate cut:" << lem << endl;
+      anyFresh = anyFresh || hasFreshArithLiteral(lem);
+      Debug("arith::lemma") << "approximate cut:" << lem << endl;
+      outputLemma(lem);
+    }
+    if(anyFresh){
+      emmittedConflictOrSplit = true;
+    }
+  }
+
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "post approx cuts" << endl;
+
   // This should be fine if sat or unknown
   if(!emmittedConflictOrSplit &&
      (options::arithPropagationMode() == UNATE_PROP ||
@@ -1965,8 +3467,8 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
     TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
     Assert(d_qflraStatus != Result::UNSAT);
 
-    while(!d_currentPropagationList.empty()  && !inConflict()){
-      Constraint curr = d_currentPropagationList.front();
+    while(!d_currentPropagationList.empty()  && !anyConflict()){
+      ConstraintP curr = d_currentPropagationList.front();
       d_currentPropagationList.pop_front();
 
       ConstraintType t = curr->getType();
@@ -1976,23 +3478,23 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
       switch(t){
       case LowerBound:
         {
-          Constraint prev = d_currentPropagationList.front();
+          ConstraintP prev = d_currentPropagationList.front();
           d_currentPropagationList.pop_front();
           d_constraintDatabase.unatePropLowerBound(curr, prev);
           break;
         }
       case UpperBound:
         {
-          Constraint prev = d_currentPropagationList.front();
+          ConstraintP prev = d_currentPropagationList.front();
           d_currentPropagationList.pop_front();
           d_constraintDatabase.unatePropUpperBound(curr, prev);
           break;
         }
       case Equality:
         {
-          Constraint prevLB = d_currentPropagationList.front();
+          ConstraintP prevLB = d_currentPropagationList.front();
           d_currentPropagationList.pop_front();
-          Constraint prevUB = d_currentPropagationList.front();
+          ConstraintP prevUB = d_currentPropagationList.front();
           d_currentPropagationList.pop_front();
           d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB);
           break;
@@ -2002,14 +3504,16 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
       }
     }
 
-    if(inConflict()){
+    if(anyConflict()){
       Debug("arith::unate") << "unate conflict" << endl;
       revertOutOfConflict();
       d_qflraStatus = Result::UNSAT;
       outputConflicts();
       emmittedConflictOrSplit = true;
+      //cout << "unate conflict " << endl;
       Debug("arith::bt") << "committing on unate conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus  << endl;
 
+      Debug("arith::conflict") << "unate arith conflict" << endl;
     }
   }else{
     TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
@@ -2017,12 +3521,23 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
   }
   Assert( d_currentPropagationList.empty());
 
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "post unate" << endl;
+
   if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
     ++d_fullCheckCounter;
   }
   if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
     emmittedConflictOrSplit = splitDisequalities();
   }
+  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+                      << "pos splitting" << endl;
+
+
+  Debug("arith") << "integer? "
+       << " conf/split " << emmittedConflictOrSplit
+       << " fulleffort " << Theory::fullEffort(effortLevel)
+       << " hasintmodel " << hasIntegerModel() << endl;
 
   if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
     Node possibleConflict = Node::null();
@@ -2031,22 +3546,22 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
       if(possibleConflict != Node::null()){
         revertOutOfConflict();
         Debug("arith::conflict") << "dio conflict   " << possibleConflict << endl;
-        //cout << "dio conflict   " << possibleConflict << endl;
-        raiseConflict(possibleConflict);
+        blackBoxConflict(possibleConflict);
         outputConflicts();
         emmittedConflictOrSplit = true;
       }
     }
 
     if(!emmittedConflictOrSplit && d_hasDoneWorkSinceCut && options::arithDioSolver()){
-      Node possibleLemma = dioCutting();
-      if(!possibleLemma.isNull()){
-        Debug("arith") << "dio cut   " << possibleLemma << endl;
-        //cout << "dio cut   " << possibleLemma << endl;
-        emmittedConflictOrSplit = true;
-        d_hasDoneWorkSinceCut = false;
-        d_cutCount = d_cutCount + 1;
-        outputLemma(possibleLemma);
+      if(getDioCuttingResource()){
+        Node possibleLemma = dioCutting();
+        if(!possibleLemma.isNull()){
+          emmittedConflictOrSplit = true;
+          d_hasDoneWorkSinceCut = false;
+          d_cutCount = d_cutCount + 1;
+          Debug("arith::lemma") << "dio cut   " << possibleLemma << endl;
+          outputLemma(possibleLemma);
+        }
       }
     }
 
@@ -2056,7 +3571,10 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
         ++(d_statistics.d_externalBranchAndBounds);
         d_cutCount = d_cutCount + 1;
         emmittedConflictOrSplit = true;
+        Debug("arith::lemma") << "rrbranch lemma"
+                              << possibleLemma << endl;
         outputLemma(possibleLemma);
+
       }
     }
 
@@ -2064,10 +3582,12 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
       if(d_diosolver.hasMoreDecompositionLemmas()){
         while(d_diosolver.hasMoreDecompositionLemmas()){
           Node decompositionLemma = d_diosolver.nextDecompositionLemma();
-          Debug("arith") << "dio decomposition lemma   " << decompositionLemma << endl;
+          Debug("arith::lemma") << "dio decomposition lemma "
+                                << decompositionLemma << endl;
           outputLemma(decompositionLemma);
         }
       }else{
+        Debug("arith::restart") << "arith restart!" << endl;
         outputRestart();
       }
     }
@@ -2077,6 +3597,15 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
     setIncomplete();
   }
 
+  if(Theory::fullEffort(effortLevel)){
+    if(Debug.isOn("arith::consistency::final")){
+      entireStateIsConsistent("arith::consistency::final");
+    }
+    // cout << "fulleffort" << getSatContext()->getLevel() << endl;
+    // entireStateIsConsistent("arith::consistency::final");
+    // cout << "emmittedConflictOrSplit" << emmittedConflictOrSplit << endl;
+  }
+
   if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
   if(Debug.isOn("arith::print_model")) {
     debugPrintModel(Debug("arith::print_model"));
@@ -2127,7 +3656,7 @@ std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{
     for(ArithVar iter = 0; iter != max; ++iter){
     //Do not include slack variables
       const DeltaRational& d = d_partialModel.getAssignment(iter);
-      if(isInteger(iter) && !isSlackVariable(iter) &&
+      if(isIntegerInput(iter) &&
          !d_cutInContext.contains(iter) &&
          d_partialModel.hasUpperBound(iter) &&
          d_partialModel.hasLowerBound(iter) &&
@@ -2147,7 +3676,7 @@ Node TheoryArithPrivate::roundRobinBranch(){
     ArithVar v = d_nextIntegerCheckVar;
 
     Assert(isInteger(v));
-    Assert(!isSlackVariable(v));
+    Assert(!isAuxiliaryVariable(v));
     return branchIntegerVariable(v);
   }
 }
@@ -2155,10 +3684,10 @@ Node TheoryArithPrivate::roundRobinBranch(){
 bool TheoryArithPrivate::splitDisequalities(){
   bool splitSomething = false;
 
-  vector<Constraint> save;
+  vector<ConstraintP> save;
 
   while(!d_diseqQueue.empty()){
-    Constraint front = d_diseqQueue.front();
+    ConstraintP front = d_diseqQueue.front();
     d_diseqQueue.pop();
 
     if(front->isSplit()){
@@ -2179,6 +3708,7 @@ bool TheoryArithPrivate::splitDisequalities(){
 
         Debug("arith::lemma") << "Now " << Rewriter::rewrite(lemma) << endl;
         outputLemma(lemma);
+        //cout << "Now " << Rewriter::rewrite(lemma) << endl;
         splitSomething = true;
       }else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
         Debug("eq") << "can drop as less than lb" << front << endl;
@@ -2190,7 +3720,7 @@ bool TheoryArithPrivate::splitDisequalities(){
       }
     }
   }
-  vector<Constraint>::const_iterator i=save.begin(), i_end = save.end();
+  vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end();
   for(; i != i_end; ++i){
     d_diseqQueue.push(*i);
   }
@@ -2206,17 +3736,17 @@ void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
   for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
     ArithVar i = *vi;
     if (d_partialModel.hasLowerBound(i)) {
-      Constraint lConstr = d_partialModel.getLowerBoundConstraint(i);
+      ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i);
       out << lConstr << endl;
     }
 
     if (d_partialModel.hasUpperBound(i)) {
-      Constraint uConstr = d_partialModel.getUpperBoundConstraint(i);
+      ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i);
       out << uConstr << endl;
     }
   }
-  context::CDQueue<Constraint>::const_iterator it = d_diseqQueue.begin();
-  context::CDQueue<Constraint>::const_iterator it_end = d_diseqQueue.end();
+  context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin();
+  context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end();
   for(; it != it_end; ++ it) {
     out << *it << endl;
   }
@@ -2243,16 +3773,16 @@ Node TheoryArithPrivate::explain(TNode n) {
 
   Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl;
 
-  Constraint c = d_constraintDatabase.lookup(n);
+  ConstraintP c = d_constraintDatabase.lookup(n);
   if(c != NullConstraint){
     Assert(!c->isSelfExplaining());
-    Node exp = c->explainForPropagation();
+    Node exp = c->externalExplainForPropagation();
     Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl;
     return exp;
   }else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){
     c = d_assertionsThatDoNotMatchTheirLiterals[n];
     if(!c->isSelfExplaining()){
-      Node exp = c->explainForPropagation();
+      Node exp = c->externalExplainForPropagation();
       Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
       return exp;
     }else{
@@ -2285,12 +3815,13 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
   }
 
   while(d_constraintDatabase.hasMorePropagations()){
-    Constraint c = d_constraintDatabase.nextPropagation();
+    ConstraintCP c = d_constraintDatabase.nextPropagation();
     Debug("arith::prop") << "next prop" << getSatContext()->getLevel() << ": " << c << endl;
 
     if(c->negationHasProof()){
-      Debug("arith::prop") << "negation has proof " << c->getNegation() << endl
-                           << c->getNegation()->explainForConflict() << endl;
+      Debug("arith::prop") << "negation has proof " << c->getNegation() << endl;
+      Debug("arith::prop") << c->getNegation()->externalExplainByAssertions()
+                           << endl;
     }
     Assert(!c->negationHasProof(), "A constraint has been propagated on the constraint propagation queue, but the negation has been set to true.  Contact Tim now!");
 
@@ -2311,7 +3842,7 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
     //equality engine in the the difference manager.
     Node normalized = Rewriter::rewrite(toProp);
 
-    Constraint constraint = d_constraintDatabase.lookup(normalized);
+    ConstraintP constraint = d_constraintDatabase.lookup(normalized);
     if(constraint == NullConstraint){
       Debug("arith::prop") << "propagating on non-constraint? "  << toProp << endl;
 
@@ -2322,7 +3853,7 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
         normalized[0] : normalized.notNode();
       Node lp = flattenAnd(exp.andNode(notNormalized));
       Debug("arith::prop") << "propagate conflict" <<  lp << endl;
-      raiseConflict(lp);
+      blackBoxConflict(lp);
       outputConflicts();
       return;
     }else{
@@ -2427,11 +3958,11 @@ DeltaRational TheoryArithPrivate::getDeltaValue(TNode n) const throw (DeltaRatio
 Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
   Rational min(2);
   std::set<DeltaRational> relevantDeltaValues;
-  context::CDQueue<Constraint>::const_iterator qiter = d_diseqQueue.begin();
-  context::CDQueue<Constraint>::const_iterator qiter_end = d_diseqQueue.end();
+  context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin();
+  context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end();
 
   for(; qiter != qiter_end; ++qiter){
-    Constraint curr = *qiter;
+    ConstraintP curr = *qiter;
 
     const DeltaRational& rhsValue = curr->getValue();
     relevantDeltaValues.insert(rhsValue);
@@ -2503,7 +4034,7 @@ void TheoryArithPrivate::collectModelInfo( TheoryModel* m, bool fullModel ){
   for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
     ArithVar v = *vi;
 
-    if(!isSlackVariable(v)){
+    if(!isAuxiliaryVariable(v)){
       Node term = d_partialModel.asNode(v);
 
       if(theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end()){
@@ -2550,6 +4081,8 @@ void TheoryArithPrivate::notifyRestart(){
   if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
 
   ++d_restartsCounter;
+  d_solveIntMaybeHelp = 0;
+  d_solveIntAttempts = 0;
 }
 
 bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
@@ -2679,7 +4212,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
     //implies an unknown fact.
 
     ConstraintType t = upperBound ? UpperBound : LowerBound;
-    Constraint bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
+    ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
 
     // Node bestImplied = upperBound ?
     //   d_apm.getBestImpliedUpperBound(basic, bound):
@@ -2694,7 +4227,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
       Assert( upperBound || d_partialModel.greaterThanLowerBound(basic, bestImplied->getValue()));
       //slightly changed
 
-      // Constraint c = d_constraintDatabase.lookup(bestImplied);
+      // ConstraintP c = d_constraintDatabase.lookup(bestImplied);
       // Assert(c != NullConstraint);
 
       bool assertedToTheTheory = bestImplied->assertedToTheTheory();
@@ -2710,7 +4243,8 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
       if(bestImplied->negationHasProof()){
         Warning() << "the negation of " <<  bestImplied << " : " << endl
                   << "has proof " << bestImplied->getNegation() << endl
-                  << bestImplied->getNegation()->explainForConflict() << endl;
+                  << bestImplied->getNegation()->externalExplainByAssertions()
+                  << endl;
       }
 
       if(!assertedToTheTheory && canBePropagated && !hasProof ){
@@ -2724,8 +4258,11 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
         return true;
       }
       if(Debug.isOn("arith::prop")){
-        Debug("arith::prop") << "failed " << basic << " " << bound << assertedToTheTheory << " " <<
-          canBePropagated << " " << hasProof << endl;
+        Debug("arith::prop") << "failed " << basic
+                             << " " << bound
+                             << " " << assertedToTheTheory
+                             << " " << canBePropagated
+                             << " " << hasProof << endl;
         d_partialModel.printModel(basic, Debug("arith::prop"));
       }
     }
@@ -2848,7 +4385,7 @@ bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
       return true;
     }
 
-    Constraint strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
+    ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
     if(strongestPossible == NullConstraint){
       return false;
     }else{
@@ -2944,11 +4481,7 @@ bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, b
   if(weaker){
     ConstraintType t = vUb ? UpperBound : LowerBound;
 
-    if(isInteger(v)){
-      //cout << "maybe" << endl;
-      //cout << bound << endl;
-    }
-    Constraint implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
+    ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
     if(implied != NullConstraint){
       return rowImplicationCanBeApplied(ridx, rowUp, implied);
     }
@@ -2980,7 +4513,7 @@ Node flattenImplication(Node imp){
   return nb;
 }
 
-bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint implied){
+bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){
   Assert(implied != NullConstraint);
   ArithVar v = implied->getVariable();
 
@@ -2997,14 +4530,14 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C
   if(implied->negationHasProof()){
     Warning() << "the negation of " <<  implied << " : " << endl
               << "has proof " << implied->getNegation() << endl
-              << implied->getNegation()->explainForConflict() << endl;
+              << implied->getNegation()->externalExplainByAssertions() << endl;
   }
 
   if(!assertedToTheTheory && canBePropagated && !hasProof ){
-    vector<Constraint> explain;
+    ConstraintCPVec explain;
     d_linEq.propagateRow(explain, ridx, rowUp, implied);
     if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
-      Node implication = implied->makeImplication(explain);
+      Node implication = implied->externalImplication(explain);
       Node clause = flattenImplication(implication);
       outputLemma(clause);
     }else{
index 7ff93b02189b6bc9ac7cc39c78d965cdcc685245..33c588ed4dbf53ae3ef172952d5e73f45a944691 100644 (file)
@@ -88,6 +88,10 @@ namespace quantifiers {
 }
 namespace arith {
 
+class BranchCutInfo;
+class TreeLog;
+class ApproximateStatistics;
+
 /**
  * Implementation of QF_LRA.
  * Based upon:
@@ -107,6 +111,8 @@ private:
 
   BoundInfoMap d_rowTracking;
 
+  ConstraintCPVec d_conflictBuffer;
+
   /**
    * The constraint database associated with the theory.
    * This must be declared before ArithPartialModel.
@@ -122,6 +128,7 @@ private:
   //                     if unknown, the simplex priority queue cannot be emptied
   int d_unknownsInARow;
 
+  bool d_replayedLemmas;
 
   /**
    * This counter is false if nothing has been done since the last cut.
@@ -174,22 +181,22 @@ private:
    * A superset of all of the assertions that currently are not the literal for
    * their constraint do not match constraint literals. Not just the witnesses.
    */
-  context::CDInsertHashMap<Node, Constraint, NodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals;
+  context::CDInsertHashMap<Node, ConstraintP, NodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals;
 
 
   /** Returns true if x is of type Integer. */
   inline bool isInteger(ArithVar x) const {
     return d_partialModel.isInteger(x);
-    //return d_variableTypes[x] >= ATInteger;
   }
 
-  /** This is the set of variables initially introduced as slack variables. */
-  //std::vector<bool> d_slackVars;
 
-  /** Returns true if the variable was initially introduced as a slack variable. */
-  inline bool isSlackVariable(ArithVar x) const{
-    return d_partialModel.isSlack(x);
-    //return d_slackVars[x];
+  /** Returns true if the variable was initially introduced as an auxiliary variable. */
+  inline bool isAuxiliaryVariable(ArithVar x) const{
+    return d_partialModel.isAuxiliary(x);
+  }
+
+  inline bool isIntegerInput(ArithVar x) const {
+    return d_partialModel.isIntegerInput(x);
   }
 
   /**
@@ -215,7 +222,7 @@ private:
    * List of all of the disequalities asserted in the current context that are not known
    * to be satisfied.
    */
-  context::CDQueue<Constraint> d_diseqQueue;
+  context::CDQueue<ConstraintP> d_diseqQueue;
 
   /**
    * Constraints that have yet to be processed by proagation work list.
@@ -231,9 +238,9 @@ private:
    * then d_cPL[1] is the previous lowerBound in d_partialModel,
    * and d_cPL[2] is the previous upperBound in d_partialModel.
    */
-  std::deque<Constraint> d_currentPropagationList;
+  std::deque<ConstraintP> d_currentPropagationList;
 
-  context::CDQueue<Constraint> d_learnedBounds;
+  context::CDQueue<ConstraintP> d_learnedBounds;
 
 
   /**
@@ -277,15 +284,31 @@ private:
 
 
   /** This is only used by simplex at the moment. */
-  context::CDList<Node> d_conflicts;
+  context::CDList<ConstraintCPVec> d_conflicts;
+  context::CDO<Node> d_blackBoxConflict;
 public:
-  inline void raiseConflict(Node n){  d_conflicts.push_back(n); }
+  inline void raiseConflict(const ConstraintCPVec& cv){
+    d_conflicts.push_back(cv);
+  }
+
+  void raiseConflict(ConstraintCP a, ConstraintCP b);
+  void raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c);
+
+  inline void blackBoxConflict(Node bb){
+    if(d_blackBoxConflict.get().isNull()){
+      d_blackBoxConflict = bb;
+    }
+  }
 
 private:
 
+  inline bool conflictQueueEmpty() const {
+    return d_conflicts.empty();
+  }
+
   /** Returns true iff a conflict has been raised. */
-  inline bool inConflict() const {
-    return !d_conflicts.empty();
+  inline bool anyConflict() const {
+    return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
   }
 
   /**
@@ -314,6 +337,7 @@ private:
 
   /** This keeps track of difference equalities. Mostly for sharing. */
   ArithCongruenceManager d_congruenceManager;
+  context::CDO<bool> d_cmEnabled;
 
   /** This implements the Simplex decision procedure. */
   DualSimplexDecisionProcedure d_dualSimplex;
@@ -323,6 +347,22 @@ private:
 
   bool solveRealRelaxation(Theory::Effort effortLevel);
 
+  /* Returns true if this is heuristically a good time to try
+   * to solve the integers.
+   */
+  bool attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit);
+  bool replayLemmas(ApproximateSimplex* approx);
+  void solveInteger(Theory::Effort effortLevel);
+  bool safeToCallApprox() const;
+  SimplexDecisionProcedure& selectSimplex(bool pass1);
+  SimplexDecisionProcedure* d_pass1SDP;
+  SimplexDecisionProcedure* d_otherSDP;
+  /* Sets d_qflraStatus */
+  void importSolution(const ApproximateSimplex::Solution& solution);
+  bool solveRelaxationOrPanic(Theory::Effort effortLevel);
+  context::CDO<int> d_lastContextIntegerAttempted;
+  bool replayLog(ApproximateSimplex* approx);
+
   class ModelException : public Exception {
   public:
     ModelException(TNode n, const char* msg) throw ();
@@ -412,16 +452,28 @@ private:
 
 
   /**
-   * Looks for the next integer variable without an integer assignment in a round robin fashion.
-   * Changes the value of d_nextIntegerCheckVar.
+   * Looks for the next integer variable without an integer assignment in a
+   * round-robin fashion. Changes the value of d_nextIntegerCheckVar.
    *
-   * If this returns false, d_nextIntegerCheckVar does not have an integer assignment.
-   * If this returns true, all integer variables have an integer assignment.
+   * This returns true if all integer variables have integer assignments.
+   * If this returns false, d_nextIntegerCheckVar does not have an integer
+   * assignment.
    */
   bool hasIntegerModel();
 
   /**
-   * Issues branches for non-slack integer variables with non-integer assignments.
+   * Looks for through the variables starting at d_nextIntegerCheckVar
+   * for the first integer variable that is between its upper and lower bounds
+   * that has a non-integer assignment.
+   *
+   * If assumeBounds is true, skip the check that the variable is in bounds.
+   *
+   * If there is no such variable, returns ARITHVAR_SENTINEL;
+   */
+  ArithVar nextIntegerViolatation(bool assumeBounds) const;
+
+  /**
+   * Issues branches for non-auxiliary integer variables with non-integer assignments.
    * Returns a cut for a lemma.
    * If there is an integer model, this returns Node::null().
    */
@@ -432,8 +484,11 @@ public:
    * This requests a new unique ArithVar value for x.
    * This also does initial (not context dependent) set up for a variable,
    * except for setting up the initial.
+   *
+   * If aux is true, this is an auxiliary variable.
+   * If internal is true, x might not be unique up to a constant multiple.
    */
-  ArithVar requestArithVar(TNode x, bool slack);
+  ArithVar requestArithVar(TNode x, bool aux, bool internal);
 
 public:
   const BoundsInfo& boundsInfo(ArithVar basic) const;
@@ -443,8 +498,8 @@ private:
   /** Initial (not context dependent) sets up for a variable.*/
   void setupBasicValue(ArithVar x);
 
-  /** Initial (not context dependent) sets up for a new slack variable.*/
-  void setupSlack(TNode left);
+  /** Initial (not context dependent) sets up for a new auxiliary variable.*/
+  void setupAuxiliary(TNode left);
 
 
   /**
@@ -462,10 +517,10 @@ private:
    * a node describing this conflict is returned.
    * If this new bound is not in conflict, Node::null() is returned.
    */
-  bool AssertLower(Constraint constraint);
-  bool AssertUpper(Constraint constraint);
-  bool AssertEquality(Constraint constraint);
-  bool AssertDisequality(Constraint constraint);
+  bool AssertLower(ConstraintP constraint);
+  bool AssertUpper(ConstraintP constraint);
+  bool AssertEquality(ConstraintP constraint);
+  bool AssertDisequality(ConstraintP constraint);
 
   /** Tracks the bounds that were updated in the current round. */
   DenseSet d_updatedBounds;
@@ -488,7 +543,14 @@ private:
   /** Attempt to perform a row propagation where every variable is a potential candidate.*/
   bool attemptFull(RowIndex ridx, bool rowUp);
   bool tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUp, const DeltaRational& bound);
-  bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint bestImplied);
+  bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP bestImplied);
+  //void enqueueConstraints(std::vector<ConstraintCP>& out, Node n) const;
+  //ConstraintCPVec resolveOutPropagated(const ConstraintCPVec& v, const std::set<ConstraintCP>& propagated) const;
+  void resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const;
+  void subsumption(std::vector<ConstraintCPVec>& confs) const;
+
+  Node cutToLiteral(ApproximateSimplex*  approx, const CutInfo& cut) const;
+  Node branchToNode(ApproximateSimplex*  approx, const NodeLog& cut) const throw(RationalFromDoubleException);
 
 
   void propagateCandidates();
@@ -512,8 +574,8 @@ private:
    * Returns a conflict if one was found.
    * Returns Node::null if no conflict was found.
    */
-  Constraint constraintFromFactQueue();
-  bool assertionCases(Constraint c);
+  ConstraintP constraintFromFactQueue();
+  bool assertionCases(ConstraintP c);
 
   /**
    * Returns the basic variable with the shorted row containing a non-basic variable.
@@ -554,7 +616,7 @@ private:
     (d_containing.d_out)->setIncomplete();
     d_nlIncomplete = true;
   }
-  inline void outputLemma(TNode lem) { (d_containing.d_out)->lemma(lem); }
+  void outputLemma(TNode lem);
   inline void outputPropagate(TNode lit) { (d_containing.d_out)->propagate(lit); }
   inline void outputRestart() { (d_containing.d_out)->demandRestart(); }
 
@@ -565,6 +627,8 @@ private:
     return (d_containing.d_valuation).getSatValue(n);
   }
 
+  context::CDQueue<Node> d_approxCuts;
+  std::vector<Node> d_acTmp;
 
   /** Counts the number of fullCheck calls to arithmetic. */
   uint32_t d_fullCheckCounter;
@@ -581,12 +645,49 @@ private:
   context::CDO<bool> d_guessedCoeffSet;
   ArithRatPairVec d_guessedCoeffs;
 
+
+  TreeLog* d_treeLog;
+  TreeLog& getTreeLog();
+
+
+  ArithVarVec d_replayVariables;
+  std::vector<ConstraintP> d_replayConstraints;
+  DenseMap<Rational> d_lhsTmp;
+
+  /* Approximate simpplex solvers are given a copy of their stats */
+  ApproximateStatistics* d_approxStats;
+  ApproximateStatistics& getApproxStats();
+  context::CDO<int32_t> d_attemptSolveIntTurnedOff;
+  void turnOffApproxFor(int32_t rounds);
+  bool getSolveIntegerResource();
+
+  void tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bl);
+  std::vector<ConstraintCPVec> replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth);
+
+  std::pair<ConstraintP, ArithVar> replayGetConstraint(const CutInfo& info);
+  std::pair<ConstraintP, ArithVar> replayGetConstraint(ApproximateSimplex* approx, const NodeLog& nl) throw(RationalFromDoubleException);
+  std::pair<ConstraintP, ArithVar> replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch);
+
+  void replayAssert(ConstraintP c);
+  //ConstConstraintVec toExplanation(Node n) const;
+
+  // Returns true if the node contains a literal
+  // that is an arithmetic literal and is not a sat literal
+  // No caching is done so this should likely only
+  // be called carefully!
+  bool hasFreshArithLiteral(Node n) const;
+
+  int32_t d_dioSolveResources;
+  bool getDioCuttingResource();
+
+  uint32_t d_solveIntMaybeHelp, d_solveIntAttempts;
+
   /** These fields are designed to be accessible to TheoryArith methods. */
   class Statistics {
   public:
     IntStat d_statAssertUpperConflicts, d_statAssertLowerConflicts;
 
-    IntStat d_statUserVariables, d_statSlackVariables;
+    IntStat d_statUserVariables, d_statAuxiliaryVariables;
     IntStat d_statDisequalitySplits;
     IntStat d_statDisequalityConflicts;
     TimerStat d_simplifyTimer;
@@ -614,6 +715,51 @@ private:
     IntStat d_commitsOnConflicts;
     IntStat d_nontrivialSatChecks;
 
+    IntStat d_replayLogRecCount,
+      d_replayLogRecConflictEscalation,
+      d_replayLogRecEarlyExit,
+      d_replayBranchCloseFailures,
+      d_replayLeafCloseFailures,
+      d_replayBranchSkips,
+      d_mirCutsAttempted,
+      d_gmiCutsAttempted,
+      d_branchCutsAttempted,
+      d_cutsReconstructed,
+      d_cutsReconstructionFailed,
+      d_cutsProven,
+      d_cutsProofFailed,
+      d_mipReplayLemmaCalls,
+      d_mipExternalCuts,
+      d_mipExternalBranch;
+
+    IntStat d_inSolveInteger,
+      d_branchesExhausted,
+      d_execExhausted,
+      d_pivotsExhausted,
+      d_panicBranches,
+      d_relaxCalls,
+      d_relaxLinFeas,
+      d_relaxLinFeasFailures,
+      d_relaxLinInfeas,
+      d_relaxLinInfeasFailures,
+      d_relaxLinExhausted,
+      d_relaxOthers;
+
+    IntStat d_applyRowsDeleted;
+    TimerStat d_replaySimplexTimer;
+
+    TimerStat d_replayLogTimer,
+      d_solveIntTimer,
+      d_solveRealRelaxTimer;
+
+    IntStat d_solveIntCalls,
+      d_solveStandardEffort;
+
+    IntStat d_approxDisabled;
+    IntStat d_replayAttemptFailed;
+
+    IntStat d_cutsRejectedDuringReplay;
+    IntStat d_cutsRejectedDuringLemmas;
 
     HistogramStat<uint32_t> d_satPivots;
     HistogramStat<uint32_t> d_unsatPivots;
index c67a7c4bbedf111d934fdbac426def01963258a5..2a263857a63c79b5218f8182d45baef0714a0b5c 100644 (file)
@@ -17,6 +17,8 @@
 #include <vector>
 #include <list>
 
+#include "theory/arith/arith_ite_utils.h"
+
 #include "decision/decision_engine.h"
 
 #include "expr/attribute.h"
@@ -149,7 +151,8 @@ TheoryEngine::TheoryEngine(context::Context* context,
   d_preRegistrationVisitor(this, context),
   d_sharedTermsVisitor(d_sharedTerms),
   d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)),
-  d_bvToBoolPreprocessor()
+  d_bvToBoolPreprocessor(),
+  d_arithSubstitutionsAdded("zzz::arith::substitutions", 0)
 {
   for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
     d_theoryTable[theoryId] = NULL;
@@ -167,6 +170,8 @@ TheoryEngine::TheoryEngine(context::Context* context,
   PROOF (ProofManager::currentPM()->initTheoryProof(); );
 
   d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
+
+  StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded);
 }
 
 TheoryEngine::~TheoryEngine() {
@@ -191,6 +196,8 @@ TheoryEngine::~TheoryEngine() {
   delete d_unconstrainedSimp;
 
   delete d_iteUtilities;
+
+  StatisticsRegistry::unregisterStat(&d_arithSubstitutionsAdded);
 }
 
 void TheoryEngine::interrupt() throw(ModalException) {
@@ -1461,7 +1468,8 @@ Node TheoryEngine::ppSimpITE(TNode assertion)
 
 bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
   bool result = true;
-  if(d_iteUtilities->simpIteDidALotOfWorkHeuristic()){
+  bool simpDidALotOfWork = d_iteUtilities->simpIteDidALotOfWorkHeuristic();
+  if(simpDidALotOfWork){
     if(options::compressItes()){
       result = d_iteUtilities->compress(assertions);
     }
@@ -1480,6 +1488,57 @@ bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
       }
     }
   }
+
+  // Do theory specific preprocessing passes
+  if(d_logicInfo.isTheoryEnabled(theory::THEORY_ARITH)){
+    if(!simpDidALotOfWork){
+      ContainsTermITEVistor& contains = *d_iteRemover.getContainsVisitor();
+      arith::ArithIteUtils aiteu(contains, d_userContext, getModel());
+      bool anyItes = false;
+      for(size_t i = 0;  i < assertions.size(); ++i){
+        Node curr = assertions[i];
+        if(contains.containsTermITE(curr)){
+          anyItes = true;
+          Node res = aiteu.reduceVariablesInItes(curr);
+          Debug("arith::ite::red") << "@ " << i << " ... " << curr << endl << "   ->" << res << endl;
+          if(curr != res){
+            Node more = aiteu.reduceConstantIteByGCD(res);
+            Debug("arith::ite::red") << "  gcd->" << more << endl;
+            assertions[i] = more;
+          }
+        }
+      }
+      if(!anyItes){
+        unsigned prevSubCount = aiteu.getSubCount();
+        aiteu.learnSubstitutions(assertions);
+        if(prevSubCount < aiteu.getSubCount()){
+          d_arithSubstitutionsAdded += aiteu.getSubCount() - prevSubCount;
+          bool anySuccess = false;
+          for(size_t i = 0, N =  assertions.size();  i < N; ++i){
+            Node curr = assertions[i];
+            Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
+            Node res = aiteu.reduceVariablesInItes(next);
+            Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << "   ->" << res << endl;
+            Node more = aiteu.reduceConstantIteByGCD(res);
+            Debug("arith::ite::red") << "  gcd->" << more << endl;
+            if(more != next){
+              anySuccess = true;
+              break;
+            }
+          }
+          for(size_t i = 0, N =  assertions.size();  anySuccess && i < N; ++i){
+            Node curr = assertions[i];
+            Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
+            Node res = aiteu.reduceVariablesInItes(next);
+            Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << "   ->" << res << endl;
+            Node more = aiteu.reduceConstantIteByGCD(res);
+            Debug("arith::ite::red") << "  gcd->" << more << endl;
+            assertions[i] = Rewriter::rewrite(more);
+          }
+        }
+      }
+    }
+  }
   return result;
 }
 
index db31ef9b77e2c437771f0b3a17d7bdd2d8e31cda..9a987c9d7eb61bbbc0a3a4865832cb664683358d 100644 (file)
@@ -818,6 +818,9 @@ public:
    */
   void checkTheoryAssertionsWithModel();
 
+private:
+  IntStat d_arithSubstitutionsAdded;
+
 };/* class TheoryEngine */
 
 }/* CVC4 namespace */
index 2b29ece228dbfe56f3419a3f91fdeb5f42c92540..f674481de3a1b8d7cdd13073fa53a127547c350e 100644 (file)
@@ -17,6 +17,7 @@
 #include "cvc4autoconfig.h"
 #include "util/rational.h"
 #include <string>
+#include <sstream>
 
 #ifndef CVC4_CLN_IMP
 #  error "This source should only ever be built if CVC4_CLN_IMP is on !"
@@ -50,3 +51,56 @@ std::ostream& CVC4::operator<<(std::ostream& os, const Rational& q){
   return os << q.toString();
 }
 
+
+
+/** Equivalent to calling (this->abs()).cmp(b.abs()) */
+int Rational::absCmp(const Rational& q) const{
+  const Rational& r = *this;
+  int rsgn = r.sgn();
+  int qsgn = q.sgn();
+  if(rsgn == 0){
+    return (qsgn == 0) ? 0 : -1;
+  }else if(qsgn == 0){
+    Assert(rsgn != 0);
+    return 1;
+  }else if((rsgn > 0) && (qsgn > 0)){
+    return r.cmp(q);
+  }else if((rsgn < 0) && (qsgn < 0)){
+    // if r < q < 0, q.cmp(r) = +1, (r.abs()).cmp(q.abs()) = +1
+    // if q < r < 0, q.cmp(r) = -1, (r.abs()).cmp(q.abs()) = -1
+    // if q = r < 0, q.cmp(r) =  0, (r.abs()).cmp(q.abs()) =  0
+    return q.cmp(r);
+  }else if((rsgn < 0) && (qsgn > 0)){
+    Rational rpos = -r;
+    return rpos.cmp(q);
+  }else {
+    Assert(rsgn > 0 && (qsgn < 0));
+    Rational qpos = -q;
+    return r.cmp(qpos);
+  }
+}
+
+Rational Rational::fromDouble(double d) throw(RationalFromDoubleException){
+  try{
+    cln::cl_DF fromD = d;
+    Rational q;
+    q.d_value = cln::rationalize(fromD);
+    return q;
+  }catch(cln::floating_point_underflow_exception& fpue){
+    throw RationalFromDoubleException(d);
+  }catch(cln::floating_point_nan_exception& fpne){
+    throw RationalFromDoubleException(d);
+  }catch(cln::floating_point_overflow_exception& fpoe){
+    throw RationalFromDoubleException(d);
+  }
+}
+
+RationalFromDoubleException::RationalFromDoubleException(double d) throw()
+  : Exception()
+{
+  std::stringstream ss;
+  ss << "RationalFromDoubleException(";
+  ss << d;
+  ss << ")";
+  setMessage(ss.str());
+}
index da2af6c1fb76912d46e7eff448903b416d69671f..b144ab41943066d659a403d1e8f3032b7ea7edce 100644 (file)
 
 namespace CVC4 {
 
+class CVC4_PUBLIC RationalFromDoubleException : public Exception {
+public:
+  RationalFromDoubleException(double d) throw();
+};
+
 /**
  ** A multi-precision rational constant.
  ** This stores the rational as a pair of multi-precision integers,
@@ -189,12 +194,7 @@ public:
   }
 
   /** Return an exact rational for a double d. */
-  static Rational fromDouble(double d){
-    cln::cl_DF fromD = d;
-    Rational q;
-    q.d_value = cln::rationalize(fromD);
-    return q;
-  }
+  static Rational fromDouble(double d) throw(RationalFromDoubleException);
 
   /**
    * Get a double representation of this Rational, which is
@@ -259,6 +259,10 @@ public:
     return Integer(cln::ceiling1(d_value));
   }
 
+  Rational floor_frac() const {
+    return (*this) - Rational(floor());
+  }
+
   Rational& operator=(const Rational& x){
     if(this == &x) return *this;
     d_value = x.d_value;
@@ -349,6 +353,9 @@ public:
     return getNumerator().length() + getDenominator().length();
   }
 
+  /** Equivalent to calling (this->abs()).cmp(b.abs()) */
+  int absCmp(const Rational& q) const;
+
 };/* class Rational */
 
 struct RationalHashFunction {
index d496803dc352690717bd3bf22222773db8475e6d..25c7dab5971cc56ab666d57745ced0474c0aaa91 100644 (file)
@@ -17,6 +17,8 @@
 #include "cvc4autoconfig.h"
 #include "util/rational.h"
 #include <string>
+#include <sstream>
+#include <cmath>
 
 #ifndef CVC4_GMP_IMP
 #  error "This source should only ever be built if CVC4_GMP_IMP is on !"
@@ -50,3 +52,52 @@ std::ostream& CVC4::operator<<(std::ostream& os, const Rational& q){
   return os << q.toString();
 }
 
+
+/** Equivalent to calling (this->abs()).cmp(b.abs()) */
+int Rational::absCmp(const Rational& q) const{
+  const Rational& r = *this;
+  int rsgn = r.sgn();
+  int qsgn = q.sgn();
+  if(rsgn == 0){
+    return (qsgn == 0) ? 0 : -1;
+  }else if(qsgn == 0){
+    Assert(rsgn != 0);
+    return 1;
+  }else if((rsgn > 0) && (qsgn > 0)){
+    return r.cmp(q);
+  }else if((rsgn < 0) && (qsgn < 0)){
+    // if r < q < 0, q.cmp(r) = +1, (r.abs()).cmp(q.abs()) = +1
+    // if q < r < 0, q.cmp(r) = -1, (r.abs()).cmp(q.abs()) = -1
+    // if q = r < 0, q.cmp(r) =  0, (r.abs()).cmp(q.abs()) =  0
+    return q.cmp(r);
+  }else if((rsgn < 0) && (qsgn > 0)){
+    Rational rpos = -r;
+    return rpos.cmp(q);
+  }else {
+    Assert(rsgn > 0 && (qsgn < 0));
+    Rational qpos = -q;
+    return r.cmp(qpos);
+  }
+}
+
+
+/** Return an exact rational for a double d. */
+Rational Rational::fromDouble(double d) throw(RationalFromDoubleException){
+  if(std::isfinite(d)){
+    Rational q;
+    mpq_set_d(q.d_value.get_mpq_t(), d);
+    return q;
+  }
+
+  throw RationalFromDoubleException(d);
+}
+
+RationalFromDoubleException::RationalFromDoubleException(double d) throw()
+  : Exception()
+{
+  std::stringstream ss;
+  ss << "RationalFromDoubleException(";
+  ss << d;
+  ss << ")";
+  setMessage(ss.str());
+}
index 02ccc273c40e99a914760032db865440ef417977..273b3072dd0e418962069dd5da59864f78b51087 100644 (file)
 
 namespace CVC4 {
 
+class CVC4_PUBLIC RationalFromDoubleException : public Exception {
+public:
+  RationalFromDoubleException(double d) throw();
+};
+
 /**
  ** A multi-precision rational constant.
  ** This stores the rational as a pair of multi-precision integers,
@@ -172,12 +177,7 @@ public:
     return Integer(d_value.get_den());
   }
 
-  /** Return an exact rational for a double d. */
-  static Rational fromDouble(double d){
-    Rational q;
-    mpq_set_d(q.d_value.get_mpq_t(), d);
-    return q;
-  }
+  static Rational fromDouble(double d) throw(RationalFromDoubleException);
 
   /**
    * Get a double representation of this Rational, which is
@@ -234,6 +234,10 @@ public:
     return Integer(q);
   }
 
+  Rational floor_frac() const {
+    return (*this) - Rational(floor());
+  }
+
   Rational& operator=(const Rational& x){
     if(this == &x) return *this;
     d_value = x.d_value;
@@ -326,6 +330,10 @@ public:
     uint32_t denLen = getDenominator().length();
     return  numLen + denLen;
   }
+
+  /** Equivalent to calling (this->abs()).cmp(b.abs()) */
+  int absCmp(const Rational& q) const;
+
 };/* class Rational */
 
 struct RationalHashFunction {
index e2d6664cdc5ec16391c8ba8ad63dd2585b7a5f44..ea74eb8ee4cdfc94213f315cbc7c4ab477ff190d 100644 (file)
@@ -140,7 +140,6 @@ BUG_TESTS = \
        bug421.smt2 \
        bug421b.smt2 \
        bug425.cvc \
-       bug480.smt2 \
        bug484.smt2 \
        bug486.cvc \
        bug507.smt2 \
@@ -173,7 +172,8 @@ endif
 EXTRA_DIST += \
        subranges.cvc \
        arrayinuf_error.smt2 \
-       error.cvc
+       error.cvc \
+       bug480.smt2
 
 # synonyms for "check" in this directory
 .PHONY: regress regress0 test