[#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"
[#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"
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 \
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 \
#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;
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;
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;
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();
}
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 */
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;
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;
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() {
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;
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;
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);
}
}
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;
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());
}
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; }
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;
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);
}
}
}
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);
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;
}
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);
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;
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;
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 */
#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>
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:
* 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 */
* 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
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 */
--- /dev/null
+#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 */
--- /dev/null
+
+
+
+
+
+// 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 */
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());
}
#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"
d_minMap(userContext),
d_maxMap(userContext),
d_statistics()
-{}
+{
+}
+
+ArithStaticLearner::~ArithStaticLearner(){
+}
ArithStaticLearner::Statistics::Statistics():
d_iteMinMaxApplications("theory::arith::iteMinMaxApplications", 0),
}
-
-
-
void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet& defTrue){
Debug("arith::static") << "===================== looking at " << n << endl;
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;
}
#include "theory/arith/arith_utilities.h"
#include "context/context.h"
-#include "context/cdlist.h"
#include "context/cdtrail_hashmap.h"
#include <set>
public:
ArithStaticLearner(context::Context* userContext);
+ ~ArithStaticLearner();
void staticLearning(TNode n, NodeBuilder<>& learned);
void addBound(TNode 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 */
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)){
}
}
+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 */
#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 {
private:
TheoryArithPrivate& d_arith;
public:
- SetupLiteralCallBack(TheoryArithPrivate& ta) : d_arith(ta){}
+ SetupLiteralCallBack(TheoryArithPrivate& ta);
void operator()(TNode lit);
};
private:
const TheoryArithPrivate& d_ta;
public:
- DeltaComputeCallback(const TheoryArithPrivate& ta) : d_ta(ta){}
+ DeltaComputeCallback(const TheoryArithPrivate& ta);
Rational operator()() const;
};
private:
TheoryArithPrivate& d_ta;
public:
- BasicVarModelUpdateCallBack(TheoryArithPrivate& ta) : d_ta(ta) {}
+ BasicVarModelUpdateCallBack(TheoryArithPrivate& ta);
void operator()(ArithVar x);
};
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 */
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());
++(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);
//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);
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);
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);
}
}
-void ArithCongruenceManager::equalsConstant(Constraint c){
+void ArithCongruenceManager::equalsConstant(ConstraintCP c){
Assert(c->isEquality());
++(d_statistics.d_equalsConstantCalls);
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());
<< 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());
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;
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);
}
/** 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);
}
}
-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),
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),
}
-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{
}
}
-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() << ')';
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);
}
}
-ValueCollection ValueCollection::mkFromConstraint(Constraint c){
+ValueCollection ValueCollection::mkFromConstraint(ConstraintP c){
ValueCollection ret;
Assert(ret.empty());
switch(c->getType()){
return nonNull()->getValue();
}
-void ValueCollection::add(Constraint c){
+void ValueCollection::add(ConstraintP c){
Assert(c != NullConstraint);
Assert(empty() || getVariable() == c->getVariable());
}
}
-Constraint ValueCollection::getConstraintOfType(ConstraintType t) const{
+ConstraintP ValueCollection::getConstraintOfType(ConstraintType t) const{
switch(t){
case LowerBound:
Assert(hasLowerBound());
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()){
}
}
-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()){
}
}
-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());
return d_database->getConstraint(getVariable(), getType(), ceiling);
}
-Constraint ConstraintValue::getFloor() {
+ConstraintP Constraint_::getFloor() {
Assert(getValue().getInfinitesimalPart().sgn() < 0);
DeltaRational floor(Rational(getValue().floor()));
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;
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();
}
}
-Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
+ConstraintP Constraint_::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
switch(t){
case LowerBound:
{
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:
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;
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);
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){
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();
delete d_watches;
- std::vector<Constraint> constraintList;
+ std::vector<ConstraintP> constraintList;
while(!d_varDatabases.empty()){
PerVariableDatabase* back = d_varDatabases.back();
(i->second).push_into(constraintList);
}
while(!constraintList.empty()){
- Constraint c = constraintList.back();
+ ConstraintP c = constraintList.back();
constraintList.pop_back();
delete c;
}
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;
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));
}
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);
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);
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;
// 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;
ConstraintType negType = constraintTypeOfComparison(negCmp);
DeltaRational negDR = negCmp.normalizedDeltaRational();
- Constraint negC = new ConstraintValue(v, negType, negDR);
+ ConstraintP negC = new Constraint_(v, negType, negDR);
SortedConstraintMapIterator negI;
// }
// }
-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;
}
}
-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());
d_database->d_toPropagate.push(this);
}
-void ConstraintValue::propagate(Constraint a){
+void Constraint_::propagate(ConstraintCP a){
Assert(!hasProof());
Assert(canBePropagated());
propagate();
}
-void ConstraintValue::propagate(Constraint a, Constraint b){
+void Constraint_::propagate(ConstraintCP a, ConstraintCP b){
Assert(!hasProof());
Assert(canBePropagated());
propagate();
}
-void ConstraintValue::propagate(const std::vector<Constraint>& b){
+void Constraint_::propagate(const ConstraintCPVec& b){
Assert(!hasProof());
Assert(canBePropagated());
propagate();
}
-void ConstraintValue::impliedBy(Constraint a){
- Assert(!isTrue());
- Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(ConstraintCP a){
+ Assert(truthIsUnknown());
markAsTrue(a);
if(canBePropagated()){
}
}
-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()){
}
}
-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()){
}
}
-// 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);
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);
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);
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());
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();
}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);
--i;
const ValueCollection& vc = i->second;
if(vc.hasLowerBound()){
- Constraint weaker = vc.getLowerBound();
+ ConstraintP weaker = vc.getLowerBound();
// asserted -> hasLiteral
// hasLiteral -> weaker->hasLiteral()
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();
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;
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);
}
}
}
-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);
}
{}
-void ConstraintValue::setLiteral(Node n) {
+void Constraint_::setLiteral(Node n) {
Assert(!hasLiteral());
Assert(sanityChecking(n));
d_literal = 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();
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();
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);
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();
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()){
}
}
-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);
//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;
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
}
}
-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);
//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;
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
}
}
-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);
//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;
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
//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;
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
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();
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;
* 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;
}
};
-class ConstraintValue {
+class Constraint_ {
private:
/** The ArithVar associated with the constraint. */
const ArithVar d_variable;
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.
* 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;
* 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;
* 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;
}
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;
}
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());
}
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;
}
return d_value;
}
- Constraint getNegation() const {
+ ConstraintP getNegation() const {
return d_negation;
}
/**
* 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();
}
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());
}
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();
*/
void selfExplaining();
+ void selfExplainingWithNegationTrue();
+
/** Returns true if the node is selfExplaining.*/
bool isSelfExplaining() const;
/**
- * 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.
* 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);
}
/**
* 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.
* 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).
* 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 {
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.
* 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();
* 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;
}; /* 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 {
*/
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.
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
};
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);
RaiseConflict d_raiseConflict;
- friend class ConstraintValue;
+ friend class Constraint_;
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.
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;
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
* 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.
* 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
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;
}; /* ConstraintDatabase */
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
** 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 */
--- /dev/null
+#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 */
--- /dev/null
+
+#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 */
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;
}
};
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
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)
return *this;
}
-void ErrorInformation::reset(Constraint c, int sgn){
+void ErrorInformation::reset(ConstraintP c, int sgn){
Assert(!isRelaxed());
Assert(c != NullConstraint);
d_violated = c;
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{
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);
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);
}
* 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
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; }
}
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
return d_errInfo[a].getMetric();
}
- Constraint getViolated(ArithVar a) const {
+ ConstraintP getViolated(ArithVar a) const {
return d_errInfo[a].getViolated();
}
}
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());
return NULL;
}
-void LinearEqualityModule::propagateBasicFromRow(Constraint c){
+void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){
Assert(c != NullConstraint);
Assert(c->isUpperBound() || c->isLowerBound());
Assert(!c->assertedToTheTheory());
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());
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);
<< 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);
weakened = false;
- Constraint weaker = ub?
+ ConstraintP weaker = ub?
c->getStrictlyWeakerUpperBound(true, true):
c->getStrictlyWeakerLowerBound(true, true);
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);
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 {
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 ||
Assert(basicIsTracked(currBasic));
- Constraint bound = ub ?
+ ConstraintP bound = ub ?
d_variables.getUpperBoundConstraint(currBasic):
d_variables.getLowerBoundConstraint(currBasic);
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);
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;
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;
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{
* 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
* 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);
}
/**
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;
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];
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);
#include "theory/arith/normal_form.h"
#include "theory/arith/arith_utilities.h"
#include <list>
+#include "theory/theory.h"
using namespace std;
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:
}
}
+
+
bool VarList::isSorted(iterator start, iterator end) {
return __gnu_cxx::is_sorted(start, end);
}
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 {
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));
// 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);
}
}
++iter;
for(; iter != end(); ++iter){
Monomial curr = *iter;
- if(curr.absLessThan(min)){
+ if(curr.absCmp(min) < 0){
min = curr;
}
}
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;
}
}
}
+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();
}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;
}
}
}
#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>
// 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());
bool operator==(const Variable& v) const { return getNode() == v.getNode();}
+ size_t getComplexity() const;
};/* class Variable */
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));
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(); }
return getValue().getNumerator().length();
}
+ size_t getComplexity() const;
+
};/* class Constant */
}
return true;
}
+ size_t getComplexity() const;
private:
bool isSorted(iterator start, iterator end);
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
*/
* 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();
void print() const;
static void printList(const std::vector<Monomial>& list);
+ size_t getComplexity() const;
};/* class Monomial */
class SumPair;
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.
return getHead().getVarList();
}
+ size_t getComplexity() const;
+
friend class SumPair;
friend class Comparison;
return getConstant().isZero() && isConstant();
}
+ uint32_t size() const{
+ return getPolynomial().size();
+ }
+
bool isNonlinear() const{
return getPolynomial().isNonlinear();
}
return parse.isNormalForm();
}
+ size_t getComplexity() const;
+
SumPair toSumPair() const;
Polynomial normalizedVariablePart() const;
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
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
d_numberOfVariables(0),
d_pool(),
d_released(),
- d_releasedIterator(d_released.begin()),
d_nodeToArithVarMap(),
d_boundsQueue(),
d_enqueueingBoundCounts(true),
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),
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);
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.
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)){
}
}
-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;
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;
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(){
}
}
+
+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;
}
}
-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;
}
}
-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.");
}
}
-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.");
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){
out << getUpperBound(x) << " ";
out << getUpperBoundConstraint(x) << " ";
}
+
+ if(isInteger(x) && !integralAssignment(x)){
+ out << "(not an integer)" << endl;
+ }
out << endl;
}
}
}
+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);
}
** 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"
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(). */
/**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
/**
* 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 {
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);
};
private:
ArithVariables* d_pm;
public:
- UpperBoundCleanUp(ArithVariables* pm) : d_pm(pm) {}
+ UpperBoundCleanUp(ArithVariables* pm);
void operator()(AVCPair* restore);
};
* 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;
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;
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;
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:
/**
bool debugEqualSizes();
- bool inMaps(ArithVar x) const{
- return x < getNumberOfVariables();
- }
+ bool inMaps(ArithVar x) const;
};/* class ArithVariables */
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;
}
}
* 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. */
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),
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);
}
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();
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();
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;
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;
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;
* - 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;
}
/** 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:
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);
* 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 {
}
/** Returns the limiting constraint. */
- inline Constraint limiting() const {
+ inline ConstraintP limiting() const {
return d_limiting;
}
}
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());
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);
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;
}
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();
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);
WitnessImprovement soiRound();
WitnessImprovement SOIConflict();
std::vector< ArithVarVec > greedyConflictSubsets();
- Node generateSOIConflict(const ArithVarVec& subset);
+ void generateSOIConflict(const ArithVarVec& subset);
// WitnessImprovement focusUsingSignDisagreements(ArithVar basic);
// WitnessImprovement focusDownToLastHalf();
}
ArithVar rowIndexToBasic(RowIndex rid) const {
- Assert(rid < d_rowIndex2basic.size());
+ Assert(d_rowIndex2basic.isKey(rid));
return d_rowIndex2basic[rid];
}
#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"
#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"
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),
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);
}
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);
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(){
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);
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(){
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());
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;
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);
}
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);
+ }
}
}
}
/* 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();
// 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;
}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);
}
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);
/* procedure AssertEquality( x_i == c_i ) */
-bool TheoryArithPrivate::AssertEquality(Constraint constraint){
+bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
AssertArgument(constraint != NullConstraint,
"AssertUpper() called on a NullConstraint.");
}
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;
}
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);
/* procedure AssertDisequality( x_i != c_i ) */
-bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
+bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
AssertArgument(constraint != NullConstraint,
"AssertUpper() called on a NullConstraint.");
//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);
}
}
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);
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;
}
}
Assert(!isSetup(n));
++(d_statistics.d_statUserVariables);
- requestArithVar(n,false);
+ requestArithVar(n, false, false);
//ArithVar varN = requestArithVar(n,false);
//setupInitialValue(varN);
d_nlIncomplete = true;
++(d_statistics.d_statUserVariables);
- requestArithVar(vlNode, false);
+ requestArithVar(vlNode, false, false);
//ArithVar av = requestArithVar(vlNode, false);
//setupInitialValue(av);
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));
}
}
- ++(d_statistics.d_statSlackVariables);
+ ++(d_statistics.d_statAuxiliaryVariables);
markSetup(polyNode);
}
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;
}
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
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();;
}
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));
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));
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;
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));
return d_diosolver.processEquationsForConflict();
}
-Constraint TheoryArithPrivate::constraintFromFactQueue(){
+ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
Assert(!done());
TNode assertion = get();
}
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;
// if is (not true), or false
Assert((reEq.getConst<bool>() && isDistinct) ||
(!reEq.getConst<bool>() && !isDistinct));
- raiseConflict(assertion);
+ blackBoxConflict(assertion);
}
return NullConstraint;
}
Assert(constraint != NullConstraint);
if(constraint->negationHasProof()){
- Constraint negation = constraint->getNegation();
+ ConstraintP negation = constraint->getNegation();
if(negation->isSelfExplaining()){
if(Debug.isOn("whytheoryenginewhy")){
debugPrintFacts();
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());
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());
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);
}
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);
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();
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;
}
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;
revertOutOfConflict();
}
outputConflicts();
+ //cout << "unate conflict 1 " << effortLevel << std::endl;
return;
}
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:
}
outputConflicts();
emmittedConflictOrSplit = true;
+ Debug("arith::conflict") << "simplex conflict" << endl;
if(useSimplex && options::collectPivots()){
if(options::useFC()){
}
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 ||
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();
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;
}
}
- 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);
}
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();
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);
+ }
}
}
++(d_statistics.d_externalBranchAndBounds);
d_cutCount = d_cutCount + 1;
emmittedConflictOrSplit = true;
+ Debug("arith::lemma") << "rrbranch lemma"
+ << possibleLemma << endl;
outputLemma(possibleLemma);
+
}
}
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();
}
}
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"));
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) &&
ArithVar v = d_nextIntegerCheckVar;
Assert(isInteger(v));
- Assert(!isSlackVariable(v));
+ Assert(!isAuxiliaryVariable(v));
return branchIntegerVariable(v);
}
}
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()){
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;
}
}
}
- 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);
}
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;
}
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{
}
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!");
//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;
normalized[0] : normalized.notNode();
Node lp = flattenAnd(exp.andNode(notNormalized));
Debug("arith::prop") << "propagate conflict" << lp << endl;
- raiseConflict(lp);
+ blackBoxConflict(lp);
outputConflicts();
return;
}else{
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);
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()){
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
++d_restartsCounter;
+ d_solveIntMaybeHelp = 0;
+ d_solveIntAttempts = 0;
}
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
//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):
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();
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 ){
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"));
}
}
return true;
}
- Constraint strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
+ ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
if(strongestPossible == NullConstraint){
return false;
}else{
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);
}
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();
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{
}
namespace arith {
+class BranchCutInfo;
+class TreeLog;
+class ApproximateStatistics;
+
/**
* Implementation of QF_LRA.
* Based upon:
BoundInfoMap d_rowTracking;
+ ConstraintCPVec d_conflictBuffer;
+
/**
* The constraint database associated with the theory.
* This must be declared before ArithPartialModel.
// 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.
* 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);
}
/**
* 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.
* 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;
/**
/** 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();
}
/**
/** 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;
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 ();
/**
- * 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().
*/
* 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;
/** 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);
/**
* 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;
/** 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();
* 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.
(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(); }
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;
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;
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;
#include <vector>
#include <list>
+#include "theory/arith/arith_ite_utils.h"
+
#include "decision/decision_engine.h"
#include "expr/attribute.h"
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;
PROOF (ProofManager::currentPM()->initTheoryProof(); );
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
+
+ StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded);
}
TheoryEngine::~TheoryEngine() {
delete d_unconstrainedSimp;
delete d_iteUtilities;
+
+ StatisticsRegistry::unregisterStat(&d_arithSubstitutionsAdded);
}
void TheoryEngine::interrupt() throw(ModalException) {
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);
}
}
}
}
+
+ // 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;
}
*/
void checkTheoryAssertionsWithModel();
+private:
+ IntStat d_arithSubstitutionsAdded;
+
};/* class TheoryEngine */
}/* CVC4 namespace */
#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 !"
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());
+}
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,
}
/** 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
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;
return getNumerator().length() + getDenominator().length();
}
+ /** Equivalent to calling (this->abs()).cmp(b.abs()) */
+ int absCmp(const Rational& q) const;
+
};/* class Rational */
struct RationalHashFunction {
#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 !"
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());
+}
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,
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
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;
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 {
bug421.smt2 \
bug421b.smt2 \
bug425.cvc \
- bug480.smt2 \
bug484.smt2 \
bug486.cvc \
bug507.smt2 \
EXTRA_DIST += \
subranges.cvc \
arrayinuf_error.smt2 \
- error.cvc
+ error.cvc \
+ bug480.smt2
# synonyms for "check" in this directory
.PHONY: regress regress0 test