diff options
Diffstat (limited to 'src/theory')
84 files changed, 4335 insertions, 3054 deletions
diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h index 548035aec..e6475b58e 100644 --- a/src/theory/arith/cut_log.h +++ b/src/theory/arith/cut_log.h @@ -234,8 +234,6 @@ 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; diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h index 3e414ca6d..51bbd67f3 100644 --- a/src/theory/arith/theory_arith.h +++ b/src/theory/arith/theory_arith.h @@ -25,10 +25,6 @@ namespace CVC4 { namespace theory { -namespace quantifiers { - class InstStrategySimplex; -} - namespace arith { /** @@ -38,7 +34,6 @@ namespace arith { */ class TheoryArith : public Theory { private: - friend class quantifiers::InstStrategySimplex; friend class TheoryArithPrivate; TheoryArithPrivate* d_internal; diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index e47231128..069d3530c 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -2520,34 +2520,37 @@ struct SizeOrd { return a.size() < b.size(); } }; -void TheoryArithPrivate::subsumption(std::vector<ConstraintCPVec>& confs) const { + +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]; + 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]; + for (size_t i = 0; i < confs.size(); i++) { // i is not subsumed - for(size_t j = i+1; j < confs.size();){ + for (size_t j = i + 1; j < confs.size();) { + ConstraintCPVec& a = confs[i]; ConstraintCPVec& b = confs[j]; checks++; bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end()); - if(subsumes){ + if (subsumes) { ConstraintCPVec& back = confs.back(); b.swap(back); confs.pop_back(); subsumed++; - }else{ + } else { j++; } } } - Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks << endl; + Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks + << endl; } std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){ diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h index edc3a5bc0..ed7efe008 100644 --- a/src/theory/arith/theory_arith_private.h +++ b/src/theory/arith/theory_arith_private.h @@ -70,9 +70,6 @@ namespace CVC4 { namespace theory { -namespace quantifiers { - class InstStrategySimplex; -} namespace arith { class BranchCutInfo; @@ -93,7 +90,6 @@ class InferBoundsResult; */ class TheoryArithPrivate { private: - friend class quantifiers::InstStrategySimplex; static const uint32_t RESET_START = 2; diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp index 8dd7fe782..5ecccdd53 100644 --- a/src/theory/arrays/array_proof_reconstruction.cpp +++ b/src/theory/arrays/array_proof_reconstruction.cpp @@ -107,7 +107,14 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a, // It could be that the guard condition is a constant disequality. In this case, // we need to change it to a different format. - if (childProof->d_id == theory::eq::MERGED_THROUGH_CONSTANTS) { + bool haveNegChild = false; + for (unsigned i = 0; i < childProof->d_children.size(); ++i) { + if (childProof->d_children[i]->d_node.getKind() == kind::NOT) + haveNegChild = true; + } + + if ((childProof->d_children.size() != 0) && + (childProof->d_id == theory::eq::MERGED_THROUGH_CONSTANTS || !haveNegChild)) { // The proof has two children, explaining why each index is a (different) constant. Assert(childProof->d_children.size() == 2); @@ -117,7 +124,7 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a, if (childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) { constantOne = childProof->d_children[0]->d_node; } else { - Assert(childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_EQUALITY); + Assert(childProof->d_children[0]->d_node.getKind() == kind::EQUAL); if ((childProof->d_children[0]->d_node[0] == indexOne) || (childProof->d_children[0]->d_node[0] == indexTwo)) { constantOne = childProof->d_children[0]->d_node[1]; @@ -129,7 +136,7 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a, if (childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) { constantTwo = childProof->d_children[1]->d_node; } else { - Assert(childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_EQUALITY); + Assert(childProof->d_children[1]->d_node.getKind() == kind::EQUAL); if ((childProof->d_children[1]->d_node[0] == indexOne) || (childProof->d_children[1]->d_node[0] == indexTwo)) { constantTwo = childProof->d_children[1]->d_node[1]; diff --git a/src/theory/bv/bv_inequality_graph.h b/src/theory/bv/bv_inequality_graph.h index 452172586..923e1d8c5 100644 --- a/src/theory/bv/bv_inequality_graph.h +++ b/src/theory/bv/bv_inequality_graph.h @@ -242,7 +242,7 @@ public: */ bool addDisequality(TNode a, TNode b, TNode reason); void getConflict(std::vector<TNode>& conflict); - virtual ~InequalityGraph() throw(AssertionException) {} + virtual ~InequalityGraph() {} /** * Check that the currently asserted disequalities that have not been split on * are still true in the current model. diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index f0981044b..de596e3d5 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -100,8 +100,10 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, d_subtheoryMap[SUB_BITBLAST] = bb_solver; } - TheoryBV::~TheoryBV() { + if (d_eagerSolver) { + delete d_eagerSolver; + } for (unsigned i = 0; i < d_subtheories.size(); ++i) { delete d_subtheories[i]; } diff --git a/src/theory/bv/theory_bv_type_rules.h b/src/theory/bv/theory_bv_type_rules.h index b531129f7..cafa7044a 100644 --- a/src/theory/bv/theory_bv_type_rules.h +++ b/src/theory/bv/theory_bv_type_rules.h @@ -26,9 +26,9 @@ namespace theory { namespace bv { class BitVectorConstantTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { if (check) { if (n.getConst<BitVector>().getSize() == 0) { throw TypeCheckingExceptionPrivate(n, "constant of size 0"); @@ -36,14 +36,13 @@ public: } return nodeManager->mkBitVectorType(n.getConst<BitVector>().getSize()); } -};/* class BitVectorConstantTypeRule */ +}; /* class BitVectorConstantTypeRule */ class BitVectorBitOfTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate) { - - if(check) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { BitVectorBitOf info = n.getOperator().getConst<BitVectorBitOf>(); TypeNode t = n[0].getType(check); @@ -51,72 +50,76 @@ public: throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } if (info.bitIndex >= t.getBitVectorSize()) { - throw TypeCheckingExceptionPrivate(n, "extract index is larger than the bitvector size"); + throw TypeCheckingExceptionPrivate( + n, "extract index is larger than the bitvector size"); } } return nodeManager->booleanType(); } -};/* class BitVectorBitOfTypeRule */ +}; /* class BitVectorBitOfTypeRule */ class BitVectorCompTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode lhs = n[0].getType(check); TypeNode rhs = n[1].getType(check); if (!lhs.isBitVector() || lhs != rhs) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms of the same width"); + throw TypeCheckingExceptionPrivate( + n, "expecting bit-vector terms of the same width"); } } return nodeManager->mkBitVectorType(1); } -};/* class BitVectorCompTypeRule */ +}; /* class BitVectorCompTypeRule */ class BitVectorFixedWidthTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TNode::iterator it = n.begin(); TypeNode t = (*it).getType(check); - if( check ) { + if (check) { if (!t.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } TNode::iterator it_end = n.end(); - for (++ it; it != it_end; ++ it) { + for (++it; it != it_end; ++it) { if ((*it).getType(check) != t) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms of the same width"); + throw TypeCheckingExceptionPrivate( + n, "expecting bit-vector terms of the same width"); } } } return t; } -};/* class BitVectorFixedWidthTypeRule */ +}; /* class BitVectorFixedWidthTypeRule */ class BitVectorPredicateTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode lhsType = n[0].getType(check); if (!lhsType.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } TypeNode rhsType = n[1].getType(check); if (lhsType != rhsType) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms of the same width"); + throw TypeCheckingExceptionPrivate( + n, "expecting bit-vector terms of the same width"); } } return nodeManager->booleanType(); } -};/* class BitVectorPredicateTypeRule */ +}; /* class BitVectorPredicateTypeRule */ class BitVectorUnaryPredicateTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode type = n[0].getType(check); if (!type.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); @@ -124,13 +127,13 @@ public: } return nodeManager->booleanType(); } -};/* class BitVectorUnaryPredicateTypeRule */ +}; /* class BitVectorUnaryPredicateTypeRule */ class BitVectorEagerAtomTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode lhsType = n[0].getType(check); if (!lhsType.isBoolean()) { throw TypeCheckingExceptionPrivate(n, "expecting boolean term"); @@ -138,96 +141,98 @@ public: } return nodeManager->booleanType(); } -};/* class BitVectorEagerAtomTypeRule */ +}; /* class BitVectorEagerAtomTypeRule */ class BitVectorAckermanizationUdivTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TypeNode lhsType = n[0].getType(check); - if( check ) { + if (check) { if (!lhsType.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } } return lhsType; } -};/* class BitVectorAckermanizationUdivTypeRule */ +}; /* class BitVectorAckermanizationUdivTypeRule */ class BitVectorAckermanizationUremTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TypeNode lhsType = n[0].getType(check); - if( check ) { + if (check) { if (!lhsType.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } } return lhsType; } -};/* class BitVectorAckermanizationUremTypeRule */ +}; /* class BitVectorAckermanizationUremTypeRule */ class BitVectorExtractTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { BitVectorExtract extractInfo = n.getOperator().getConst<BitVectorExtract>(); // NOTE: We're throwing a type-checking exception here even // if check is false, bc if we allow high < low the resulting // type will be illegal if (extractInfo.high < extractInfo.low) { - throw TypeCheckingExceptionPrivate(n, "high extract index is smaller than the low extract index"); + throw TypeCheckingExceptionPrivate( + n, "high extract index is smaller than the low extract index"); } - if( check ) { + if (check) { TypeNode t = n[0].getType(check); if (!t.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } if (extractInfo.high >= t.getBitVectorSize()) { - throw TypeCheckingExceptionPrivate(n, "high extract index is bigger than the size of the bit-vector"); + throw TypeCheckingExceptionPrivate( + n, "high extract index is bigger than the size of the bit-vector"); } } return nodeManager->mkBitVectorType(extractInfo.high - extractInfo.low + 1); } -};/* class BitVectorExtractTypeRule */ +}; /* class BitVectorExtractTypeRule */ class BitVectorExtractOpTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Assert(n.getKind() == kind::BITVECTOR_EXTRACT_OP); return nodeManager->builtinOperatorType(); } -};/* class BitVectorExtractOpTypeRule */ +}; /* class BitVectorExtractOpTypeRule */ class BitVectorConcatTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { unsigned size = 0; TNode::iterator it = n.begin(); TNode::iterator it_end = n.end(); - for (; it != it_end; ++ it) { - TypeNode t = (*it).getType(check); - // NOTE: We're throwing a type-checking exception here even - // when check is false, bc if we don't check that the arguments - // are bit-vectors the result type will be inaccurate - if (!t.isBitVector()) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); - } - size += t.getBitVectorSize(); + for (; it != it_end; ++it) { + TypeNode t = (*it).getType(check); + // NOTE: We're throwing a type-checking exception here even + // when check is false, bc if we don't check that the arguments + // are bit-vectors the result type will be inaccurate + if (!t.isBitVector()) { + throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); + } + size += t.getBitVectorSize(); } return nodeManager->mkBitVectorType(size); } -};/* class BitVectorConcatTypeRule */ +}; /* class BitVectorConcatTypeRule */ class BitVectorRepeatTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TypeNode t = n[0].getType(check); // NOTE: We're throwing a type-checking exception here even // when check is false, bc if the argument isn't a bit-vector @@ -238,12 +243,12 @@ public: unsigned repeatAmount = n.getOperator().getConst<BitVectorRepeat>(); return nodeManager->mkBitVectorType(repeatAmount * t.getBitVectorSize()); } -};/* class BitVectorRepeatTypeRule */ +}; /* class BitVectorRepeatTypeRule */ class BitVectorExtendTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TypeNode t = n[0].getType(check); // NOTE: We're throwing a type-checking exception here even // when check is false, bc if the argument isn't a bit-vector @@ -251,27 +256,28 @@ public: if (!t.isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } - unsigned extendAmount = n.getKind() == kind::BITVECTOR_SIGN_EXTEND ? - (unsigned) n.getOperator().getConst<BitVectorSignExtend>() : - (unsigned) n.getOperator().getConst<BitVectorZeroExtend>(); + unsigned extendAmount = + n.getKind() == kind::BITVECTOR_SIGN_EXTEND + ? (unsigned)n.getOperator().getConst<BitVectorSignExtend>() + : (unsigned)n.getOperator().getConst<BitVectorZeroExtend>(); return nodeManager->mkBitVectorType(extendAmount + t.getBitVectorSize()); } -};/* class BitVectorExtendTypeRule */ +}; /* class BitVectorExtendTypeRule */ class BitVectorConversionTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if(n.getKind() == kind::BITVECTOR_TO_NAT) { - if(check && !n[0].getType(check).isBitVector()) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (n.getKind() == kind::BITVECTOR_TO_NAT) { + if (check && !n[0].getType(check).isBitVector()) { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } return nodeManager->integerType(); } - if(n.getKind() == kind::INT_TO_BITVECTOR) { + if (n.getKind() == kind::INT_TO_BITVECTOR) { size_t bvSize = n.getOperator().getConst<IntToBitVector>(); - if(check && !n[0].getType(check).isInteger()) { + if (check && !n[0].getType(check).isInteger()) { throw TypeCheckingExceptionPrivate(n, "expecting integer term"); } return nodeManager->mkBitVectorType(bvSize); @@ -279,24 +285,24 @@ public: InternalError("bv-conversion typerule invoked for non-bv-conversion kind"); } -};/* class BitVectorConversionTypeRule */ +}; /* class BitVectorConversionTypeRule */ class CardinalityComputer { -public: + public: inline static Cardinality computeCardinality(TypeNode type) { Assert(type.getKind() == kind::BITVECTOR_TYPE); unsigned size = type.getConst<BitVectorSize>(); - if(size == 0) { + if (size == 0) { return 0; } Integer i = Integer(2).pow(size); return i; } -};/* class CardinalityComputer */ +}; /* class CardinalityComputer */ -}/* CVC4::theory::bv namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ +} /* CVC4::theory::bv namespace */ +} /* CVC4::theory namespace */ +} /* CVC4 namespace */ #endif /* __CVC4__THEORY__BV__THEORY_BV_TYPE_RULES_H */ diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h index 9c8387958..8a440974d 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.h +++ b/src/theory/datatypes/theory_datatypes_type_rules.h @@ -25,56 +25,64 @@ namespace CVC4 { namespace expr { - namespace attr { - struct DatatypeConstructorTypeGroundTermTag {}; - }/* CVC4::expr::attr namespace */ -}/* CVC4::expr namespace */ +namespace attr { +struct DatatypeConstructorTypeGroundTermTag {}; +} /* CVC4::expr::attr namespace */ +} /* CVC4::expr namespace */ namespace theory { namespace datatypes { -typedef expr::Attribute<expr::attr::DatatypeConstructorTypeGroundTermTag, Node> GroundTermAttr; - +typedef expr::Attribute<expr::attr::DatatypeConstructorTypeGroundTermTag, Node> + GroundTermAttr; struct DatatypeConstructorTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate, AssertionException) { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Assert(n.getKind() == kind::APPLY_CONSTRUCTOR); TypeNode consType = n.getOperator().getType(check); Type t = consType.getConstructorRangeType().toType(); - Assert( t.isDatatype() ); + Assert(t.isDatatype()); DatatypeType dt = DatatypeType(t); TNode::iterator child_it = n.begin(); TNode::iterator child_it_end = n.end(); TypeNode::iterator tchild_it = consType.begin(); - if( ( dt.isParametric() || check ) && n.getNumChildren() != consType.getNumChildren() - 1 ){ - throw TypeCheckingExceptionPrivate(n, "number of arguments does not match the constructor type"); + if ((dt.isParametric() || check) && + n.getNumChildren() != consType.getNumChildren() - 1) { + throw TypeCheckingExceptionPrivate( + n, "number of arguments does not match the constructor type"); } - if( dt.isParametric() ){ - Debug("typecheck-idt") << "typecheck parameterized datatype " << n << std::endl; - Matcher m( dt ); - for(; child_it != child_it_end; ++child_it, ++tchild_it) { + if (dt.isParametric()) { + Debug("typecheck-idt") << "typecheck parameterized datatype " << n + << std::endl; + Matcher m(dt); + for (; child_it != child_it_end; ++child_it, ++tchild_it) { TypeNode childType = (*child_it).getType(check); - if( !m.doMatching( *tchild_it, childType ) ){ - throw TypeCheckingExceptionPrivate(n, "matching failed for parameterized constructor"); + if (!m.doMatching(*tchild_it, childType)) { + throw TypeCheckingExceptionPrivate( + n, "matching failed for parameterized constructor"); } } - std::vector< Type > instTypes; - m.getMatches( instTypes ); - TypeNode range = TypeNode::fromType( dt.instantiate( instTypes ) ); + std::vector<Type> instTypes; + m.getMatches(instTypes); + TypeNode range = TypeNode::fromType(dt.instantiate(instTypes)); Debug("typecheck-idt") << "Return " << range << std::endl; return range; - }else{ - if(check) { - Debug("typecheck-idt") << "typecheck cons: " << n << " " << n.getNumChildren() << std::endl; - Debug("typecheck-idt") << "cons type: " << consType << " " << consType.getNumChildren() << std::endl; - for(; child_it != child_it_end; ++child_it, ++tchild_it) { + } else { + if (check) { + Debug("typecheck-idt") << "typecheck cons: " << n << " " + << n.getNumChildren() << std::endl; + Debug("typecheck-idt") << "cons type: " << consType << " " + << consType.getNumChildren() << std::endl; + for (; child_it != child_it_end; ++child_it, ++tchild_it) { TypeNode childType = (*child_it).getType(check); - Debug("typecheck-idt") << "typecheck cons arg: " << childType << " " << (*tchild_it) << std::endl; + Debug("typecheck-idt") << "typecheck cons arg: " << childType << " " + << (*tchild_it) << std::endl; TypeNode argumentType = *tchild_it; - if(!childType.isComparableTo(argumentType)) { + if (!childType.isComparableTo(argumentType)) { std::stringstream ss; - ss << "bad type for constructor argument:\nexpected: " << argumentType << "\ngot : " << childType; + ss << "bad type for constructor argument:\nexpected: " + << argumentType << "\ngot : " << childType; throw TypeCheckingExceptionPrivate(n, ss.str()); } } @@ -83,132 +91,131 @@ struct DatatypeConstructorTypeRule { } } - inline static bool computeIsConst(NodeManager* nodeManager, TNode n) - throw(AssertionException) { + inline static bool computeIsConst(NodeManager* nodeManager, TNode n) { Assert(n.getKind() == kind::APPLY_CONSTRUCTOR); NodeManagerScope nms(nodeManager); - for(TNode::const_iterator i = n.begin(); i != n.end(); ++i) { - if( ! (*i).isConst() ) { + for (TNode::const_iterator i = n.begin(); i != n.end(); ++i) { + if (!(*i).isConst()) { return false; } } return true; } -};/* struct DatatypeConstructorTypeRule */ +}; /* struct DatatypeConstructorTypeRule */ struct DatatypeSelectorTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { - Assert(n.getKind() == kind::APPLY_SELECTOR || n.getKind() == kind::APPLY_SELECTOR_TOTAL ); + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + Assert(n.getKind() == kind::APPLY_SELECTOR || + n.getKind() == kind::APPLY_SELECTOR_TOTAL); TypeNode selType = n.getOperator().getType(check); Type t = selType[0].toType(); - Assert( t.isDatatype() ); + Assert(t.isDatatype()); DatatypeType dt = DatatypeType(t); - if( ( dt.isParametric() || check ) && n.getNumChildren() != 1 ){ - throw TypeCheckingExceptionPrivate(n, "number of arguments does not match the selector type"); + if ((dt.isParametric() || check) && n.getNumChildren() != 1) { + throw TypeCheckingExceptionPrivate( + n, "number of arguments does not match the selector type"); } - if( dt.isParametric() ){ - Debug("typecheck-idt") << "typecheck parameterized sel: " << n << std::endl; - Matcher m( dt ); + if (dt.isParametric()) { + Debug("typecheck-idt") << "typecheck parameterized sel: " << n + << std::endl; + Matcher m(dt); TypeNode childType = n[0].getType(check); - if(! childType.isInstantiatedDatatype()) { - throw TypeCheckingExceptionPrivate(n, "Datatype type not fully instantiated"); + if (!childType.isInstantiatedDatatype()) { + throw TypeCheckingExceptionPrivate( + n, "Datatype type not fully instantiated"); } - if( !m.doMatching( selType[0], childType ) ){ - throw TypeCheckingExceptionPrivate(n, "matching failed for selector argument of parameterized datatype"); + if (!m.doMatching(selType[0], childType)) { + throw TypeCheckingExceptionPrivate( + n, + "matching failed for selector argument of parameterized datatype"); } - std::vector< Type > types, matches; - m.getTypes( types ); - m.getMatches( matches ); + std::vector<Type> types, matches; + m.getTypes(types); + m.getMatches(matches); Type range = selType[1].toType(); - range = range.substitute( types, matches ); + range = range.substitute(types, matches); Debug("typecheck-idt") << "Return " << range << std::endl; - return TypeNode::fromType( range ); - }else{ - if(check) { + return TypeNode::fromType(range); + } else { + if (check) { Debug("typecheck-idt") << "typecheck sel: " << n << std::endl; Debug("typecheck-idt") << "sel type: " << selType << std::endl; TypeNode childType = n[0].getType(check); - if(!selType[0].isComparableTo(childType)) { - Debug("typecheck-idt") << "ERROR: " << selType[0].getKind() << " " << childType.getKind() << std::endl; - throw TypeCheckingExceptionPrivate(n, "bad type for selector argument"); + if (!selType[0].isComparableTo(childType)) { + Debug("typecheck-idt") << "ERROR: " << selType[0].getKind() << " " + << childType.getKind() << std::endl; + throw TypeCheckingExceptionPrivate(n, + "bad type for selector argument"); } } return selType[1]; } } -};/* struct DatatypeSelectorTypeRule */ +}; /* struct DatatypeSelectorTypeRule */ struct DatatypeTesterTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Assert(n.getKind() == kind::APPLY_TESTER); - if(check) { - if(n.getNumChildren() != 1) { - throw TypeCheckingExceptionPrivate(n, "number of arguments does not match the tester type"); + if (check) { + if (n.getNumChildren() != 1) { + throw TypeCheckingExceptionPrivate( + n, "number of arguments does not match the tester type"); } TypeNode testType = n.getOperator().getType(check); TypeNode childType = n[0].getType(check); Type t = testType[0].toType(); - Assert( t.isDatatype() ); + Assert(t.isDatatype()); DatatypeType dt = DatatypeType(t); - if(dt.isParametric()) { - Debug("typecheck-idt") << "typecheck parameterized tester: " << n << std::endl; - Matcher m( dt ); - if( !m.doMatching( testType[0], childType ) ){ - throw TypeCheckingExceptionPrivate(n, "matching failed for tester argument of parameterized datatype"); + if (dt.isParametric()) { + Debug("typecheck-idt") << "typecheck parameterized tester: " << n + << std::endl; + Matcher m(dt); + if (!m.doMatching(testType[0], childType)) { + throw TypeCheckingExceptionPrivate( + n, + "matching failed for tester argument of parameterized datatype"); } } else { Debug("typecheck-idt") << "typecheck test: " << n << std::endl; Debug("typecheck-idt") << "test type: " << testType << std::endl; - if(!testType[0].isComparableTo(childType)) { + if (!testType[0].isComparableTo(childType)) { throw TypeCheckingExceptionPrivate(n, "bad type for tester argument"); } } } return nodeManager->booleanType(); } -};/* struct DatatypeTesterTypeRule */ +}; /* struct DatatypeTesterTypeRule */ struct DatatypeAscriptionTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Debug("typecheck-idt") << "typechecking ascription: " << n << std::endl; Assert(n.getKind() == kind::APPLY_TYPE_ASCRIPTION); - TypeNode t = TypeNode::fromType(n.getOperator().getConst<AscriptionType>().getType()); - if(check) { + TypeNode t = TypeNode::fromType( + n.getOperator().getConst<AscriptionType>().getType()); + if (check) { TypeNode childType = n[0].getType(check); - //if(!t.getKind() == kind::DATATYPE_TYPE) { - // throw TypeCheckingExceptionPrivate(n, "bad type for datatype type ascription"); - //} - //DatatypeType dt = DatatypeType(childType.toType()); - //if( dt.isParametric() ){ - // Debug("typecheck-idt") << "typecheck parameterized ascription: " << n << std::endl; - // Matcher m( dt ); - // if( !m.doMatching( childType, t ) ){ - // throw TypeCheckingExceptionPrivate(n, "matching failed for type ascription argument of parameterized datatype"); - // } - //}else{ - // Debug("typecheck-idt") << "typecheck test: " << n << std::endl; - // if(t != childType) { - // throw TypeCheckingExceptionPrivate(n, "bad type for type ascription argument"); - // } - //} Matcher m; - if( childType.getKind() == kind::CONSTRUCTOR_TYPE ){ - m.addTypesFromDatatype( ConstructorType(childType.toType()).getRangeType() ); - }else if( childType.getKind() == kind::DATATYPE_TYPE ){ - m.addTypesFromDatatype( DatatypeType(childType.toType()) ); + if (childType.getKind() == kind::CONSTRUCTOR_TYPE) { + m.addTypesFromDatatype( + ConstructorType(childType.toType()).getRangeType()); + } else if (childType.getKind() == kind::DATATYPE_TYPE) { + m.addTypesFromDatatype(DatatypeType(childType.toType())); } - if( !m.doMatching( childType, t ) ){ - throw TypeCheckingExceptionPrivate(n, "matching failed for type ascription argument of parameterized datatype"); + if (!m.doMatching(childType, t)) { + throw TypeCheckingExceptionPrivate(n, + "matching failed for type " + "ascription argument of " + "parameterized datatype"); } - } return t; } -};/* struct DatatypeAscriptionTypeRule */ +}; /* struct DatatypeAscriptionTypeRule */ struct ConstructorProperties { inline static Cardinality computeCardinality(TypeNode type) { @@ -217,24 +224,26 @@ struct ConstructorProperties { // that of a tuple than that of a function. AssertArgument(type.isConstructor(), type); Cardinality c = 1; - for(unsigned i = 0, i_end = type.getNumChildren(); i < i_end - 1; ++i) { + for (unsigned i = 0, i_end = type.getNumChildren(); i < i_end - 1; ++i) { c *= type[i].getCardinality(); } return c; } -};/* struct ConstructorProperties */ +}; /* struct ConstructorProperties */ struct TupleUpdateTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Assert(n.getKind() == kind::TUPLE_UPDATE); const TupleUpdate& tu = n.getOperator().getConst<TupleUpdate>(); TypeNode tupleType = n[0].getType(check); TypeNode newValue = n[1].getType(check); - if(check) { - if(!tupleType.isTuple()) { - throw TypeCheckingExceptionPrivate(n, "Tuple-update expression formed over non-tuple"); + if (check) { + if (!tupleType.isTuple()) { + throw TypeCheckingExceptionPrivate( + n, "Tuple-update expression formed over non-tuple"); } - if(tu.getIndex() >= tupleType.getTupleLength()) { + if (tu.getIndex() >= tupleType.getTupleLength()) { std::stringstream ss; ss << "Tuple-update expression index `" << tu.getIndex() << "' is not a valid index; tuple type only has " @@ -244,21 +253,23 @@ struct TupleUpdateTypeRule { } return tupleType; } -};/* struct TupleUpdateTypeRule */ +}; /* struct TupleUpdateTypeRule */ struct RecordUpdateTypeRule { - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { Assert(n.getKind() == kind::RECORD_UPDATE); NodeManagerScope nms(nodeManager); const RecordUpdate& ru = n.getOperator().getConst<RecordUpdate>(); TypeNode recordType = n[0].getType(check); TypeNode newValue = n[1].getType(check); - if(check) { - if(!recordType.isRecord()) { - throw TypeCheckingExceptionPrivate(n, "Record-update expression formed over non-record"); + if (check) { + if (!recordType.isRecord()) { + throw TypeCheckingExceptionPrivate( + n, "Record-update expression formed over non-record"); } const Record& rec = recordType.getRecord(); - if(!rec.contains(ru.getField())) { + if (!rec.contains(ru.getField())) { std::stringstream ss; ss << "Record-update field `" << ru.getField() << "' is not a valid field name for the record type"; @@ -267,44 +278,49 @@ struct RecordUpdateTypeRule { } return recordType; } -};/* struct RecordUpdateTypeRule */ +}; /* struct RecordUpdateTypeRule */ class DtSizeTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode t = n[0].getType(check); if (!t.isDatatype()) { - throw TypeCheckingExceptionPrivate(n, "expecting datatype size term to have datatype argument."); + throw TypeCheckingExceptionPrivate( + n, "expecting datatype size term to have datatype argument."); } } return nodeManager->integerType(); } -};/* class DtSizeTypeRule */ +}; /* class DtSizeTypeRule */ class DtHeightBoundTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode t = n[0].getType(check); if (!t.isDatatype()) { - throw TypeCheckingExceptionPrivate(n, "expecting datatype height bound term to have datatype argument."); + throw TypeCheckingExceptionPrivate( + n, + "expecting datatype height bound term to have datatype argument."); } - if( n[1].getKind()!=kind::CONST_RATIONAL ){ - throw TypeCheckingExceptionPrivate(n, "datatype height bound must be a constant"); + if (n[1].getKind() != kind::CONST_RATIONAL) { + throw TypeCheckingExceptionPrivate( + n, "datatype height bound must be a constant"); } - if( n[1].getConst<Rational>().getNumerator().sgn()==-1 ){ - throw TypeCheckingExceptionPrivate(n, "datatype height bound must be non-negative"); + if (n[1].getConst<Rational>().getNumerator().sgn() == -1) { + throw TypeCheckingExceptionPrivate( + n, "datatype height bound must be non-negative"); } } return nodeManager->booleanType(); } -};/* class DtHeightBoundTypeRule */ +}; /* class DtHeightBoundTypeRule */ -}/* CVC4::theory::datatypes namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ +} /* CVC4::theory::datatypes namespace */ +} /* CVC4::theory namespace */ +} /* CVC4 namespace */ #endif /* __CVC4__THEORY__DATATYPES__THEORY_DATATYPES_TYPE_RULES_H */ diff --git a/src/theory/fp/theory_fp_type_rules.h b/src/theory/fp/theory_fp_type_rules.h index f9bf2e432..edda93de8 100644 --- a/src/theory/fp/theory_fp_type_rules.h +++ b/src/theory/fp/theory_fp_type_rules.h @@ -24,34 +24,36 @@ namespace CVC4 { namespace theory { namespace fp { -#define TRACE(FUNCTION) Trace("fp-type") << FUNCTION "::computeType(" << check << "): " << n << std::endl - +#define TRACE(FUNCTION) \ + Trace("fp-type") << FUNCTION "::computeType(" << check << "): " << n \ + << std::endl class FloatingPointConstantTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointConstantTypeRule"); - const FloatingPoint &f = n.getConst<FloatingPoint>(); - + const FloatingPoint& f = n.getConst<FloatingPoint>(); + if (check) { if (!(validExponentSize(f.t.exponent()))) { - throw TypeCheckingExceptionPrivate(n, "constant with invalid exponent size"); + throw TypeCheckingExceptionPrivate( + n, "constant with invalid exponent size"); } if (!(validSignificandSize(f.t.significand()))) { - throw TypeCheckingExceptionPrivate(n, "constant with invalid significand size"); + throw TypeCheckingExceptionPrivate( + n, "constant with invalid significand size"); } } return nodeManager->mkFloatingPointType(f.t); } }; - class RoundingModeConstantTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("RoundingModeConstantTypeRule"); // Nothing to check! @@ -59,22 +61,20 @@ public: } }; - - class FloatingPointFPTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointFPTypeRule"); TypeNode signType = n[0].getType(check); TypeNode exponentType = n[1].getType(check); TypeNode significandType = n[2].getType(check); - if (!signType.isBitVector() || - !exponentType.isBitVector() || - !significandType.isBitVector()) { - throw TypeCheckingExceptionPrivate(n, "arguments to fp must be bit vectors"); + if (!signType.isBitVector() || !exponentType.isBitVector() || + !significandType.isBitVector()) { + throw TypeCheckingExceptionPrivate(n, + "arguments to fp must be bit vectors"); } unsigned signBits = signType.getBitVectorSize(); @@ -82,41 +82,43 @@ public: unsigned significandBits = significandType.getBitVectorSize(); if (check) { - if (signBits != 1) { - throw TypeCheckingExceptionPrivate(n, "sign bit vector in fp must be 1 bit long"); + throw TypeCheckingExceptionPrivate( + n, "sign bit vector in fp must be 1 bit long"); } else if (!(validExponentSize(exponentBits))) { - throw TypeCheckingExceptionPrivate(n, "exponent bit vector in fp is an invalid size"); + throw TypeCheckingExceptionPrivate( + n, "exponent bit vector in fp is an invalid size"); } else if (!(validSignificandSize(significandBits))) { - throw TypeCheckingExceptionPrivate(n, "significand bit vector in fp is an invalid size"); + throw TypeCheckingExceptionPrivate( + n, "significand bit vector in fp is an invalid size"); } } // The +1 is for the implicit hidden bit - return nodeManager->mkFloatingPointType(exponentBits,significandBits + 1); + return nodeManager->mkFloatingPointType(exponentBits, significandBits + 1); } - }; - class FloatingPointTestTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointTestTypeRule"); if (check) { TypeNode firstOperand = n[0].getType(check); if (!firstOperand.isFloatingPoint()) { - throw TypeCheckingExceptionPrivate(n, "floating-point test applied to a non floating-point sort"); + throw TypeCheckingExceptionPrivate( + n, "floating-point test applied to a non floating-point sort"); } size_t children = n.getNumChildren(); for (size_t i = 1; i < children; ++i) { - if (!(n[i].getType(check) == firstOperand)) { - throw TypeCheckingExceptionPrivate(n, "floating-point test applied to mixed sorts"); - } + if (!(n[i].getType(check) == firstOperand)) { + throw TypeCheckingExceptionPrivate( + n, "floating-point test applied to mixed sorts"); + } } } @@ -124,25 +126,26 @@ public: } }; - class FloatingPointOperationTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointOperationTypeRule"); TypeNode firstOperand = n[0].getType(check); if (check) { if (!firstOperand.isFloatingPoint()) { - throw TypeCheckingExceptionPrivate(n, "floating-point operation applied to a non floating-point sort"); + throw TypeCheckingExceptionPrivate( + n, "floating-point operation applied to a non floating-point sort"); } size_t children = n.getNumChildren(); for (size_t i = 1; i < children; ++i) { - if (!(n[i].getType(check) == firstOperand)) { - throw TypeCheckingExceptionPrivate(n, "floating-point test applied to mixed sorts"); - } + if (!(n[i].getType(check) == firstOperand)) { + throw TypeCheckingExceptionPrivate( + n, "floating-point test applied to mixed sorts"); + } } } @@ -150,34 +153,35 @@ public : } }; - class FloatingPointRoundingOperationTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointRoundingOperationTypeRule"); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } } - TypeNode firstOperand = n[1].getType(check); if (check) { if (!firstOperand.isFloatingPoint()) { - throw TypeCheckingExceptionPrivate(n, "floating-point operation applied to a non floating-point sort"); + throw TypeCheckingExceptionPrivate( + n, "floating-point operation applied to a non floating-point sort"); } size_t children = n.getNumChildren(); for (size_t i = 2; i < children; ++i) { - if (!(n[i].getType(check) == firstOperand)) { - throw TypeCheckingExceptionPrivate(n, "floating-point test applied to mixed sorts"); - } + if (!(n[i].getType(check) == firstOperand)) { + throw TypeCheckingExceptionPrivate( + n, "floating-point test applied to mixed sorts"); + } } } @@ -186,9 +190,9 @@ public : }; class FloatingPointParametricOpTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointParametricOpTypeRule"); return nodeManager->builtinOperatorType(); @@ -196,20 +200,28 @@ public : }; class FloatingPointToFPIEEEBitVectorTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPIEEEBitVectorTypeRule"); - FloatingPointToFPIEEEBitVector info = n.getOperator().getConst<FloatingPointToFPIEEEBitVector>(); + FloatingPointToFPIEEEBitVector info = + n.getOperator().getConst<FloatingPointToFPIEEEBitVector>(); if (check) { TypeNode operandType = n[0].getType(check); - + if (!(operandType.isBitVector())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from bit vector used with sort other than bit vector"); - } else if (!(operandType.getBitVectorSize() == info.t.exponent() + info.t.significand())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from bit vector used with bit vector length that does not match floating point parameters"); + throw TypeCheckingExceptionPrivate(n, + "conversion to floating-point from " + "bit vector used with sort other " + "than bit vector"); + } else if (!(operandType.getBitVectorSize() == + info.t.exponent() + info.t.significand())) { + throw TypeCheckingExceptionPrivate( + n, + "conversion to floating-point from bit vector used with bit vector " + "length that does not match floating point parameters"); } } @@ -217,27 +229,30 @@ public : } }; - class FloatingPointToFPFloatingPointTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPFloatingPointTypeRule"); - FloatingPointToFPFloatingPoint info = n.getOperator().getConst<FloatingPointToFPFloatingPoint>(); + FloatingPointToFPFloatingPoint info = + n.getOperator().getConst<FloatingPointToFPFloatingPoint>(); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isFloatingPoint())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from floating-point used with sort other than floating-point"); + throw TypeCheckingExceptionPrivate(n, + "conversion to floating-point from " + "floating-point used with sort " + "other than floating-point"); } } @@ -245,27 +260,30 @@ public : } }; - class FloatingPointToFPRealTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPRealTypeRule"); - FloatingPointToFPReal info = n.getOperator().getConst<FloatingPointToFPReal>(); + FloatingPointToFPReal info = + n.getOperator().getConst<FloatingPointToFPReal>(); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isReal())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from real used with sort other than real"); + throw TypeCheckingExceptionPrivate(n, + "conversion to floating-point from " + "real used with sort other than " + "real"); } } @@ -273,27 +291,30 @@ public : } }; - class FloatingPointToFPSignedBitVectorTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPSignedBitVectorTypeRule"); - FloatingPointToFPSignedBitVector info = n.getOperator().getConst<FloatingPointToFPSignedBitVector>(); + FloatingPointToFPSignedBitVector info = + n.getOperator().getConst<FloatingPointToFPSignedBitVector>(); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isBitVector())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from signed bit vector used with sort other than bit vector"); + throw TypeCheckingExceptionPrivate(n, + "conversion to floating-point from " + "signed bit vector used with sort " + "other than bit vector"); } } @@ -301,27 +322,30 @@ public : } }; - class FloatingPointToFPUnsignedBitVectorTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPUnsignedBitVectorTypeRule"); - FloatingPointToFPUnsignedBitVector info = n.getOperator().getConst<FloatingPointToFPUnsignedBitVector>(); + FloatingPointToFPUnsignedBitVector info = + n.getOperator().getConst<FloatingPointToFPUnsignedBitVector>(); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isBitVector())) { - throw TypeCheckingExceptionPrivate(n, "conversion to floating-point from unsigned bit vector used with sort other than bit vector"); + throw TypeCheckingExceptionPrivate(n, + "conversion to floating-point from " + "unsigned bit vector used with sort " + "other than bit vector"); } } @@ -329,15 +353,14 @@ public : } }; - - class FloatingPointToFPGenericTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToFPGenericTypeRule"); - FloatingPointToFPGeneric info = n.getOperator().getConst<FloatingPointToFPGeneric>(); + FloatingPointToFPGeneric info = + n.getOperator().getConst<FloatingPointToFPGeneric>(); if (check) { /* As this is a generic kind intended only for parsing, @@ -347,7 +370,7 @@ public : size_t children = n.getNumChildren(); for (size_t i = 0; i < children; ++i) { - n[i].getType(check); + n[i].getType(check); } } @@ -355,12 +378,10 @@ public : } }; - - class FloatingPointToUBVTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToUBVTypeRule"); FloatingPointToUBV info = n.getOperator().getConst<FloatingPointToUBV>(); @@ -369,14 +390,17 @@ public : TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isFloatingPoint())) { - throw TypeCheckingExceptionPrivate(n, "conversion to unsigned bit vector used with a sort other than floating-point"); + throw TypeCheckingExceptionPrivate(n, + "conversion to unsigned bit vector " + "used with a sort other than " + "floating-point"); } } @@ -384,11 +408,10 @@ public : } }; - class FloatingPointToSBVTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToSBVTypeRule"); FloatingPointToSBV info = n.getOperator().getConst<FloatingPointToSBV>(); @@ -397,14 +420,17 @@ public : TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } - TypeNode operandType = n[1].getType(check); - + if (!(operandType.isFloatingPoint())) { - throw TypeCheckingExceptionPrivate(n, "conversion to signed bit vector used with a sort other than floating-point"); + throw TypeCheckingExceptionPrivate(n, + "conversion to signed bit vector " + "used with a sort other than " + "floating-point"); } } @@ -412,25 +438,25 @@ public : } }; - - class FloatingPointToRealTypeRule { -public : - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TRACE("FloatingPointToRealTypeRule"); if (check) { TypeNode roundingModeType = n[0].getType(check); if (!roundingModeType.isRoundingMode()) { - throw TypeCheckingExceptionPrivate(n, "first argument must be a rounding mode"); + throw TypeCheckingExceptionPrivate( + n, "first argument must be a rounding mode"); } TypeNode operand = n[1].getType(check); if (!operand.isFloatingPoint()) { - throw TypeCheckingExceptionPrivate(n, "floating-point to real applied to a non floating-point sort"); + throw TypeCheckingExceptionPrivate( + n, "floating-point to real applied to a non floating-point sort"); } } @@ -438,10 +464,8 @@ public : } }; - - -}/* CVC4::theory::fp namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ +} /* CVC4::theory::fp namespace */ +} /* CVC4::theory namespace */ +} /* CVC4 namespace */ #endif /* __CVC4__THEORY__FP__THEORY_FP_TYPE_RULES_H */ diff --git a/src/theory/ite_utilities.cpp b/src/theory/ite_utilities.cpp index 6fab100de..126f3bfb8 100644 --- a/src/theory/ite_utilities.cpp +++ b/src/theory/ite_utilities.cpp @@ -73,9 +73,9 @@ static bool isTheoryAtom(TNode a){ struct CTIVStackElement { TNode curr; unsigned pos; - CTIVStackElement(){} - CTIVStackElement(TNode c) : curr(c), pos(0){ } -};/* CTIVStackElement */ + CTIVStackElement() : curr(), pos(0) {} + CTIVStackElement(TNode c) : curr(c), pos(0) {} +}; /* CTIVStackElement */ } /* CVC4::theory::ite */ @@ -490,8 +490,8 @@ struct TITEHStackElement { TNode curr; unsigned pos; uint32_t maxChildHeight; - TITEHStackElement(){} - TITEHStackElement(TNode c) : curr(c), pos(0), maxChildHeight(0){ } + TITEHStackElement() : curr(), pos(0), maxChildHeight(0) {} + TITEHStackElement(TNode c) : curr(c), pos(0), maxChildHeight(0) {} }; } /* namespace ite */ diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp index 97116dee4..2ccc17e55 100755 --- a/src/theory/quantifiers/ambqi_builder.cpp +++ b/src/theory/quantifiers/ambqi_builder.cpp @@ -836,7 +836,7 @@ void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) { //--------------------model checking--------------------------------------- //do exhaustive instantiation -bool AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) { +int AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) { Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl; if (effort==0) { FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs(); @@ -868,9 +868,10 @@ bool AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, in d_addedLemmas += lem; Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl; } - return quantValid; + return quantValid ? 1 : 0; + }else{ + return 1; } - return true; } bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) { diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h index 3669d38b7..0adaef638 100755 --- a/src/theory/quantifiers/ambqi_builder.h +++ b/src/theory/quantifiers/ambqi_builder.h @@ -93,7 +93,7 @@ public: //process build model void processBuildModel(TheoryModel* m, bool fullModel); //do exhaustive instantiation - bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ); + int doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ); }; } diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp index c8d18aced..9ccba38cd 100755 --- a/src/theory/quantifiers/anti_skolem.cpp +++ b/src/theory/quantifiers/anti_skolem.cpp @@ -14,18 +14,19 @@ **/ #include "theory/quantifiers/anti_skolem.h" + +#include "options/quantifiers_options.h" +#include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers_engine.h" -#include "theory/quantifiers/first_order_model.h" -#include "options/quantifiers_options.h" using namespace std; -using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; +namespace CVC4 { +namespace theory { +namespace quantifiers { struct sortTypeOrder { TermDb* d_tdb; @@ -74,10 +75,13 @@ bool QuantAntiSkolem::CDSkQuantCache::add( context::Context* c, std::vector< Nod } } -QuantAntiSkolem::QuantAntiSkolem( QuantifiersEngine * qe ) : QuantifiersModule( qe ){ - d_sqc = new CDSkQuantCache( qe->getUserContext() ); +QuantAntiSkolem::QuantAntiSkolem(QuantifiersEngine* qe) + : QuantifiersModule(qe) { + d_sqc = new CDSkQuantCache(qe->getUserContext()); } +QuantAntiSkolem::~QuantAntiSkolem() { delete d_sqc; } + /* Call during quantifier engine's check */ void QuantAntiSkolem::check( Theory::Effort e, unsigned quant_e ) { if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ @@ -267,3 +271,6 @@ bool QuantAntiSkolem::sendAntiSkolemizeLemma( std::vector< Node >& quants, bool } } +}/* namespace CVC4::theory::quantifiers */ +}/* namespace CVC4::theory */ +}/* namespace CVC4 */ diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h index 721371159..48205db9d 100755 --- a/src/theory/quantifiers/anti_skolem.h +++ b/src/theory/quantifiers/anti_skolem.h @@ -17,17 +17,39 @@ #ifndef __CVC4__THEORY__QUANT_ANTI_SKOLEM_H #define __CVC4__THEORY__QUANT_ANTI_SKOLEM_H -#include "theory/quantifiers_engine.h" +#include <map> +#include <vector> + +#include "expr/node.h" +#include "expr/type_node.h" +#include "context/cdhashset.h" #include "context/cdo.h" #include "theory/quantifiers/ce_guided_single_inv.h" +#include "theory/quantifiers_engine.h" namespace CVC4 { namespace theory { namespace quantifiers { class QuantAntiSkolem : public QuantifiersModule { +public: + QuantAntiSkolem( QuantifiersEngine * qe ); + virtual ~QuantAntiSkolem(); + + bool sendAntiSkolemizeLemma( std::vector< Node >& quants, + bool pconnected = true ); + + /* Call during quantifier engine's check */ + void check( Theory::Effort e, unsigned quant_e ); + /* Called for new quantifiers */ + void registerQuantifier( Node q ) {} + void assertNode( Node n ) {} + /** Identify this module (for debugging, dynamic configuration, etc..) */ + std::string identify() const { return "QuantAntiSkolem"; } + + private: typedef context::CDHashSet<Node, NodeHashFunction> NodeSet; -private: + std::map< Node, bool > d_quant_processed; std::map< Node, SingleInvocationPartition > d_quant_sip; std::map< Node, std::vector< TypeNode > > d_ask_types; @@ -54,22 +76,10 @@ private: bool add( context::Context* c, std::vector< Node >& quants, unsigned index = 0 ); }; CDSkQuantCache * d_sqc; -public: - bool sendAntiSkolemizeLemma( std::vector< Node >& quants, bool pconnected = true ); -public: - QuantAntiSkolem( QuantifiersEngine * qe ); - - /* Call during quantifier engine's check */ - void check( Theory::Effort e, unsigned quant_e ); - /* Called for new quantifiers */ - void registerQuantifier( Node q ) {} - void assertNode( Node n ) {} - /** Identify this module (for debugging, dynamic configuration, etc..) */ - std::string identify() const { return "QuantAntiSkolem"; } -}; +}; /* class QuantAntiSkolem */ -} -} -} +}/* namespace CVC4::theory::quantifiers */ +}/* namespace CVC4::theory */ +}/* namespace CVC4 */ #endif diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp index a0d9bda0f..8e8f34cac 100755 --- a/src/theory/quantifiers/candidate_generator.cpp +++ b/src/theory/quantifiers/candidate_generator.cpp @@ -264,6 +264,7 @@ CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mp Assert( mpat.getKind()==INST_CONSTANT ); d_f = quantifiers::TermDb::getInstConstAttr( mpat ); d_index = mpat.getAttribute(InstVarNumAttribute()); + d_firstTime = false; } void CandidateGeneratorQEAll::resetInstantiationRound() { diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp index 71bf7c426..54415d974 100755 --- a/src/theory/quantifiers/ce_guided_instantiation.cpp +++ b/src/theory/quantifiers/ce_guided_instantiation.cpp @@ -767,7 +767,7 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) { Assert( dt.isSygus() ); //get the solution Node sol; - int status; + int status = -1; if( d_last_inst_si ){ Assert( d_conj->getCegConjectureSingleInv() != NULL ); sol = d_conj->getSingleInvocationSolution( i, tn, status ); @@ -786,39 +786,45 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) { for( unsigned j=0; j<svl.getNumChildren(); j++ ){ subs.push_back( Node::fromExpr( svl[j] ) ); } + bool templIsPost = false; + Node templ; if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){ - const CegConjectureSingleInv* ceg_si = - d_conj->getCegConjectureSingleInv(); + const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv(); if(ceg_si->d_trans_pre.find( prog ) != ceg_si->d_trans_pre.end()){ - std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog); - Assert(templ_vars.size() == subs.size()); - Node pre = ceg_si->getTransPre(prog); - pre = pre.substitute( templ_vars.begin(), templ_vars.end(), - subs.begin(), subs.end() ); - TermDbSygus* sygusDb = getTermDatabase()->getTermDatabaseSygus(); - sol = sygusDb->sygusToBuiltin( sol, sol.getType() ); - Trace("cegqi-inv") << "Builtin version of solution is : " - << sol << ", type : " << sol.getType() - << std::endl; - sol = NodeManager::currentNM()->mkNode( OR, sol, pre ); + templ = ceg_si->getTransPre(prog); + templIsPost = false; } }else if(options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST){ - const CegConjectureSingleInv* ceg_si = - d_conj->getCegConjectureSingleInv(); + const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv(); if(ceg_si->d_trans_post.find(prog) != ceg_si->d_trans_post.end()){ - std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog); - Assert( templ_vars.size()==subs.size() ); - Node post = ceg_si->getTransPost(prog); - post = post.substitute( templ_vars.begin(), templ_vars.end(), - subs.begin(), subs.end() ); - TermDbSygus* sygusDb = getTermDatabase()->getTermDatabaseSygus(); - sol = sygusDb->sygusToBuiltin( sol, sol.getType() ); - Trace("cegqi-inv") << "Builtin version of solution is : " - << sol << ", type : " << sol.getType() - << std::endl; - sol = NodeManager::currentNM()->mkNode( AND, sol, post ); + templ = ceg_si->getTransPost(prog); + templIsPost = true; } } + if( !templ.isNull() ){ + std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog); + + //take into consideration Boolean term conversion (this step can be eliminated when boolean term conversion is eliminated) + std::vector< Node > vars; + vars.insert( vars.end(), templ_vars.begin(), templ_vars.end() ); + Node vl = Node::fromExpr( dt.getSygusVarList() ); + Assert(vars.size() == subs.size()); + for( unsigned j=0; j<templ_vars.size(); j++ ){ + if( vl[j].getType().isBoolean() ){ + Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u)); + vars[j] = vars[j].eqNode( c ); + } + Assert( vars[j].getType()==subs[j].getType() ); + } + + templ = templ.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + TermDbSygus* sygusDb = getTermDatabase()->getTermDatabaseSygus(); + sol = sygusDb->sygusToBuiltin( sol, sol.getType() ); + Trace("cegqi-inv") << "Builtin version of solution is : " + << sol << ", type : " << sol.getType() + << std::endl; + sol = NodeManager::currentNM()->mkNode( templIsPost ? AND : OR, sol, templ ); + } if( sol==sygus_sol ){ sol = sygus_sol; status = 1; diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp index 981abea94..e0bbbf8ac 100755 --- a/src/theory/quantifiers/ce_guided_single_inv.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv.cpp @@ -45,27 +45,41 @@ bool CegqiOutputSingleInv::addLemma( Node n ) { return d_out->addLemma( n ); } +CegConjectureSingleInv::CegConjectureSingleInv(QuantifiersEngine* qe, + CegConjecture* p) + : d_qe(qe), + d_parent(p), + d_sip(new SingleInvocationPartition), + d_sol(new CegConjectureSingleInvSol(qe)), + d_ei(NULL), + d_cosi(new CegqiOutputSingleInv(this)), + d_cinst(NULL), + d_c_inst_match_trie(NULL), + d_has_ites(true) { + // third and fourth arguments set to (false,false) until we have solution + // reconstruction for delta and infinity + d_cinst = new CegInstantiator(d_qe, d_cosi, false, false); -CegConjectureSingleInv::CegConjectureSingleInv( QuantifiersEngine * qe, CegConjecture * p ) : d_qe( qe ), d_parent( p ){ - d_has_ites = true; - if( options::incrementalSolving() ){ - d_c_inst_match_trie = new inst::CDInstMatchTrie( qe->getUserContext() ); - }else{ - d_c_inst_match_trie = NULL; + if (options::incrementalSolving()) { + d_c_inst_match_trie = new inst::CDInstMatchTrie(qe->getUserContext()); } - d_cosi = new CegqiOutputSingleInv( this ); - // third and fourth arguments set to (false,false) until we have solution reconstruction for delta and infinity - d_cinst = new CegInstantiator( d_qe, d_cosi, false, false ); - d_sol = new CegConjectureSingleInvSol( qe ); - - d_sip = new SingleInvocationPartition; + if (options::cegqiSingleInvPartial()) { + d_ei = new CegEntailmentInfer(qe, d_sip); + } +} - if( options::cegqiSingleInvPartial() ){ - d_ei = new CegEntailmentInfer( qe, d_sip ); - }else{ - d_ei = NULL; +CegConjectureSingleInv::~CegConjectureSingleInv() { + if (d_c_inst_match_trie) { + delete d_c_inst_match_trie; + } + delete d_cinst; + delete d_cosi; + if (d_ei) { + delete d_ei; } + delete d_sol; // (new CegConjectureSingleInvSol(qe)), + delete d_sip; // d_sip(new SingleInvocationPartition), } void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems ) { diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h index feadeca39..449ab7189 100755 --- a/src/theory/quantifiers/ce_guided_single_inv.h +++ b/src/theory/quantifiers/ce_guided_single_inv.h @@ -31,11 +31,10 @@ class CegConjecture; class CegConjectureSingleInv; class CegEntailmentInfer; -class CegqiOutputSingleInv : public CegqiOutput -{ +class CegqiOutputSingleInv : public CegqiOutput { public: CegqiOutputSingleInv( CegConjectureSingleInv * out ) : d_out( out ){} - ~CegqiOutputSingleInv() {} + virtual ~CegqiOutputSingleInv() {} CegConjectureSingleInv * d_out; bool doAddInstantiation( std::vector< Node >& subs ); bool isEligibleForInstantiation( Node n ); @@ -45,22 +44,13 @@ public: class SingleInvocationPartition; -class CegConjectureSingleInv -{ +class CegConjectureSingleInv { + private: friend class CegqiOutputSingleInv; -private: - SingleInvocationPartition * d_sip; - QuantifiersEngine * d_qe; - CegConjecture * d_parent; - CegConjectureSingleInvSol * d_sol; - CegEntailmentInfer * d_ei; - //the instantiator - CegqiOutputSingleInv * d_cosi; - CegInstantiator * d_cinst; - //for recognizing templates for invariant synthesis + // for recognizing templates for invariant synthesis Node substituteInvariantTemplates( - Node n, std::map< Node, Node >& prog_templ, - std::map< Node, std::vector< Node > >& prog_templ_vars ); + Node n, std::map<Node, Node>& prog_templ, + std::map<Node, std::vector<Node> >& prog_templ_vars); // partially single invocation Node removeDeepEmbedding( Node n, std::vector< Node >& progs, std::vector< TypeNode >& types, int& type_valid, @@ -73,42 +63,56 @@ private: std::vector< Node >& terms, std::map< Node, std::vector< Node > >& teq, Node n, std::vector< Node >& conj ); - //constructing solution - Node constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index, std::map< Node, Node >& weak_imp ); - Node postProcessSolution( Node n ); -private: - //list of skolems for each argument of programs - std::vector< Node > d_single_inv_arg_sk; - //list of variables/skolems for each program - std::vector< Node > d_single_inv_var; - std::vector< Node > d_single_inv_sk; - std::map< Node, int > d_single_inv_sk_index; - //program to solution index - std::map< Node, unsigned > d_prog_to_sol_index; - //lemmas produced + // constructing solution + Node constructSolution(std::vector<unsigned>& indices, unsigned i, + unsigned index, std::map<Node, Node>& weak_imp); + Node postProcessSolution(Node n); + + private: + QuantifiersEngine* d_qe; + CegConjecture* d_parent; + SingleInvocationPartition* d_sip; + CegConjectureSingleInvSol* d_sol; + CegEntailmentInfer* d_ei; + // the instantiator + CegqiOutputSingleInv* d_cosi; + CegInstantiator* d_cinst; + + // list of skolems for each argument of programs + std::vector<Node> d_single_inv_arg_sk; + // list of variables/skolems for each program + std::vector<Node> d_single_inv_var; + std::vector<Node> d_single_inv_sk; + std::map<Node, int> d_single_inv_sk_index; + // program to solution index + std::map<Node, unsigned> d_prog_to_sol_index; + // lemmas produced inst::InstMatchTrie d_inst_match_trie; - inst::CDInstMatchTrie * d_c_inst_match_trie; - //original conjecture + inst::CDInstMatchTrie* d_c_inst_match_trie; + // original conjecture Node d_orig_conjecture; // solution Node d_orig_solution; Node d_solution; Node d_sygus_solution; bool d_has_ites; -public: - //lemmas produced - std::vector< Node > d_lemmas_produced; - std::vector< std::vector< Node > > d_inst; -private: - std::vector< Node > d_curr_lemmas; - //add instantiation + + public: + // lemmas produced + std::vector<Node> d_lemmas_produced; + std::vector<std::vector<Node> > d_inst; + + private: + std::vector<Node> d_curr_lemmas; + // add instantiation bool doAddInstantiation( std::vector< Node >& subs ); //is eligible for instantiation bool isEligibleForInstantiation( Node n ); // add lemma bool addLemma( Node lem ); -public: + public: CegConjectureSingleInv( QuantifiersEngine * qe, CegConjecture * p ); + ~CegConjectureSingleInv(); // original conjecture Node d_quant; // single invocation portion of quantified formula @@ -130,7 +134,7 @@ public: std::map< Node, Node > d_nsi_op_map; std::map< Node, Node > d_nsi_op_map_to_prog; std::map< Node, Node > d_prog_to_eval_op; -public: + public: //get the single invocation lemma(s) void getInitialSingleInvLemma( std::vector< Node >& lems ); //initialize @@ -169,12 +173,12 @@ public: }; -// partitions any formulas given to it into single invocation/non-single invocation -// only processes functions having argument types exactly matching "d_arg_types", -// and all invocations are in the same order across all functions -class SingleInvocationPartition -{ -private: +// partitions any formulas given to it into single invocation/non-single +// invocation only processes functions having argument types exactly matching +// "d_arg_types", and all invocations are in the same order across all +// functions +class SingleInvocationPartition { + private: //options Kind d_checkKind; bool inferArgTypes( Node n, std::vector< TypeNode >& typs, std::map< Node, bool >& visited ); diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp index 0fe4b98c7..61a20ad42 100755 --- a/src/theory/quantifiers/ceg_instantiator.cpp +++ b/src/theory/quantifiers/ceg_instantiator.cpp @@ -11,21 +11,18 @@ ** ** \brief Implementation of counterexample-guided quantifier instantiation **/ + #include "theory/quantifiers/ceg_instantiator.h" +#include "theory/quantifiers/ceg_t_instantiator.h" #include "options/quantifiers_options.h" #include "smt/ite_removal.h" -#include "theory/arith/partial_model.h" -#include "theory/arith/theory_arith.h" -#include "theory/arith/theory_arith_private.h" #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/quantifiers_rewriter.h" +#include "theory/quantifiers/trigger.h" #include "theory/theory_engine.h" -#include "theory/bv/theory_bv_utils.h" -#include "util/bitvector.h" - -//#define MBP_STRICT_ASSERTIONS using namespace std; using namespace CVC4; @@ -36,12 +33,15 @@ using namespace CVC4::theory::quantifiers; CegInstantiator::CegInstantiator( QuantifiersEngine * qe, CegqiOutput * out, bool use_vts_delta, bool use_vts_inf ) : d_qe( qe ), d_out( out ), d_use_vts_delta( use_vts_delta ), d_use_vts_inf( use_vts_inf ){ - d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) ); - d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) ); - d_true = NodeManager::currentNM()->mkConst( true ); d_is_nested_quant = false; } +CegInstantiator::~CegInstantiator() { + for( std::map< Node, Instantiator * >::iterator it = d_instantiator.begin(); it != d_instantiator.end(); ++it ){ + delete it->second; + } +} + void CegInstantiator::computeProgVars( Node n ){ if( d_prog_var.find( n )==d_prog_var.end() ){ d_prog_var[n].clear(); @@ -68,41 +68,108 @@ void CegInstantiator::computeProgVars( Node n ){ } } -bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ){ +bool CegInstantiator::isEligible( Node n ) { + //compute d_subs_fv, which program variables are contained in n, and determines if eligible + computeProgVars( n ); + return d_inelig.find( n )==d_inelig.end(); +} + +bool CegInstantiator::hasVariable( Node n, Node pv ) { + computeProgVars( n ); + return d_prog_var[n].find( pv )!=d_prog_var[n].end(); +} + + +void CegInstantiator::registerInstantiationVariable( Node v, unsigned index ) { + if( d_instantiator.find( v )==d_instantiator.end() ){ + TypeNode tn = v.getType(); + Instantiator * vinst; + if( tn.isReal() ){ + vinst = new ArithInstantiator( d_qe, tn ); + }else if( tn.isSort() ){ + Assert( options::quantEpr() ); + vinst = new EprInstantiator( d_qe, tn ); + }else if( tn.isDatatype() ){ + vinst = new DtInstantiator( d_qe, tn ); + }else if( tn.isBitVector() ){ + vinst = new BvInstantiator( d_qe, tn ); + }else if( tn.isBoolean() ){ + vinst = new ModelValueInstantiator( d_qe, tn ); + }else{ + //default + vinst = new Instantiator( d_qe, tn ); + } + d_instantiator[v] = vinst; + } + d_curr_subs_proc[v].clear(); + d_curr_index[v] = index; +} + +void CegInstantiator::unregisterInstantiationVariable( Node v ) { + d_curr_subs_proc.erase( v ); + d_curr_index.erase( v ); +} + +bool CegInstantiator::doAddInstantiation( SolvedForm& sf, unsigned i, unsigned effort ){ if( i==d_vars.size() ){ //solved for all variables, now construct instantiation - if( !sf.d_has_coeff.empty() ){ - if( options::cbqiSymLia() ){ - //use symbolic solved forms - SolvedForm csf; - csf.copy( ssf ); - return doAddInstantiationCoeff( csf, vars, btyp, 0, cons ); + bool needsPostprocess = false; + std::map< Instantiator *, Node > pp_inst; + for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){ + if( ita->second->needsPostProcessInstantiation( this, sf, ita->first, effort ) ){ + needsPostprocess = true; + pp_inst[ ita->second ] = ita->first; + } + } + if( needsPostprocess ){ + //must make copy so that backtracking reverts sf + SolvedForm sf_tmp; + sf_tmp.copy( sf ); + bool postProcessSuccess = true; + for( std::map< Instantiator *, Node >::iterator itp = pp_inst.begin(); itp != pp_inst.end(); ++itp ){ + if( !itp->first->postProcessInstantiation( this, sf_tmp, itp->second, effort ) ){ + postProcessSuccess = false; + break; + } + } + if( postProcessSuccess ){ + return doAddInstantiation( sf_tmp.d_subs, sf_tmp.d_vars ); }else{ - return doAddInstantiationCoeff( sf, vars, btyp, 0, cons ); + return false; } }else{ - return doAddInstantiation( sf.d_subs, vars, cons ); + return doAddInstantiation( sf.d_subs, sf.d_vars ); } }else{ - std::map< Node, std::map< Node, bool > > subs_proc; //Node v = d_single_inv_map_to_prog[d_single_inv[0][i]]; bool is_cv = false; Node pv; - if( curr_var.empty() ){ + if( d_stack_vars.empty() ){ pv = d_vars[i]; }else{ - pv = curr_var.back(); + pv = d_stack_vars.back(); is_cv = true; + d_stack_vars.pop_back(); + } + registerInstantiationVariable( pv, i ); + + //get the instantiator object + Instantiator * vinst = NULL; + std::map< Node, Instantiator * >::iterator itin = d_instantiator.find( pv ); + if( itin!=d_instantiator.end() ){ + vinst = itin->second; } + Assert( vinst!=NULL ); + d_active_instantiators[pv] = vinst; + vinst->reset( this, sf, pv, effort ); + TypeNode pvtn = pv.getType(); TypeNode pvtnb = pvtn.getBaseType(); Node pvr = pv; if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){ pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv ); } - Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << std::endl; + Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << ", instantiator is " << vinst->identify() << std::endl; Node pv_value; if( options::cbqiModel() ){ pv_value = getModelValue( pv ); @@ -116,72 +183,38 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std:: Trace("cbqi-inst-debug") << "[1] try based on equivalence class." << std::endl; std::map< Node, std::vector< Node > >::iterator it_eqc = d_curr_eqc.find( pvr ); if( it_eqc!=d_curr_eqc.end() ){ + //std::vector< Node > eq_candidates; Trace("cbqi-inst-debug2") << "...eqc has size " << it_eqc->second.size() << std::endl; for( unsigned k=0; k<it_eqc->second.size(); k++ ){ Node n = it_eqc->second[k]; if( n!=pv ){ Trace("cbqi-inst-debug") << "...try based on equal term " << n << std::endl; - //compute d_subs_fv, which program variables are contained in n - computeProgVars( n ); //must be an eligible term - if( d_inelig.find( n )==d_inelig.end() ){ + if( isEligible( n ) ){ Node ns; Node pv_coeff; //coefficient of pv in the equality we solve (null is 1) bool proc = false; if( !d_prog_var[n].empty() ){ - ns = applySubstitution( pvtn, n, sf, vars, pv_coeff, false ); + ns = applySubstitution( pvtn, n, sf, pv_coeff, false ); if( !ns.isNull() ){ computeProgVars( ns ); //substituted version must be new and cannot contain pv - proc = subs_proc[pv_coeff].find( ns )==subs_proc[pv_coeff].end() && d_prog_var[ns].find( pv )==d_prog_var[ns].end(); + proc = d_prog_var[ns].find( pv )==d_prog_var[ns].end(); } }else{ ns = n; proc = true; } if( proc ){ - //try the substitution - subs_proc[ns][pv_coeff] = true; - if( doAddInstantiationInc( ns, pv, pv_coeff, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( vinst->processEqualTerm( this, sf, pv, pv_coeff, ns, effort ) ){ return true; } } } } } - if( pvtn.isDatatype() ){ - Trace("cbqi-inst-debug") << "[2] try based on constructors in equivalence class." << std::endl; - //[2] look in equivalence class for a constructor - for( unsigned k=0; k<it_eqc->second.size(); k++ ){ - Node n = it_eqc->second[k]; - if( n.getKind()==APPLY_CONSTRUCTOR ){ - Trace("cbqi-inst-debug") << "... " << i << "...try based on constructor term " << n << std::endl; - cons[pv] = n.getOperator(); - const Datatype& dt = ((DatatypeType)(pvtn).toType()).getDatatype(); - unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() ); - if( is_cv ){ - curr_var.pop_back(); - } - //now must solve for selectors applied to pv - for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ - curr_var.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][j].getSelector() ), pv ) ); - } - if( doAddInstantiation( sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - }else{ - //cleanup - cons.erase( pv ); - Assert( curr_var.size()>=dt[cindex].getNumArgs() ); - for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ - curr_var.pop_back(); - } - if( is_cv ){ - curr_var.push_back( pv ); - } - break; - } - } - } + if( vinst->processEqualTerms( this, sf, pv, it_eqc->second, effort ) ){ + return true; } }else{ Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl; @@ -189,762 +222,246 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std:: //[3] : we can solve an equality for pv ///iterate over equivalence classes to find cases where we can solve for the variable - Trace("cbqi-inst-debug") << "[3] try based on solving equalities." << std::endl; - for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){ - Node r = d_curr_type_eqc[pvtnb][k]; - std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r ); - std::vector< Node > lhs; - std::vector< bool > lhs_v; - std::vector< Node > lhs_coeff; - Assert( it_reqc!=d_curr_eqc.end() ); - for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){ - Node n = it_reqc->second[kk]; - Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl; - //compute the variables in n - computeProgVars( n ); - //must be an eligible term - if( d_inelig.find( n )==d_inelig.end() ){ - Node ns; - Node pv_coeff; - if( !d_prog_var[n].empty() ){ - ns = applySubstitution( pvtn, n, sf, vars, pv_coeff ); - if( !ns.isNull() ){ - computeProgVars( ns ); + if( vinst->hasProcessEquality( this, sf, pv, effort ) ){ + Trace("cbqi-inst-debug") << "[3] try based on solving equalities." << std::endl; + for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){ + Node r = d_curr_type_eqc[pvtnb][k]; + std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r ); + std::vector< Node > lhs; + std::vector< bool > lhs_v; + std::vector< Node > lhs_coeff; + Assert( it_reqc!=d_curr_eqc.end() ); + for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){ + Node n = it_reqc->second[kk]; + Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl; + //must be an eligible term + if( isEligible( n ) ){ + Node ns; + Node pv_coeff; + if( !d_prog_var[n].empty() ){ + ns = applySubstitution( pvtn, n, sf, pv_coeff ); + if( !ns.isNull() ){ + computeProgVars( ns ); + } + }else{ + ns = n; } - }else{ - ns = n; - } - if( !ns.isNull() ){ - bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end(); - Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl; - for( unsigned j=0; j<lhs.size(); j++ ){ - //if this term or the another has pv in it, try to solve for it - if( hasVar || lhs_v[j] ){ - Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl; - Node val; - Node veq_c; - bool success = false; - if( pvtnb.isReal() ){ - Node eq_lhs = lhs[j]; - Node eq_rhs = ns; - //make the same coefficient - if( pv_coeff!=lhs_coeff[j] ){ - if( !pv_coeff.isNull() ){ - Trace("cbqi-inst-debug") << "...mult lhs by " << pv_coeff << std::endl; - eq_lhs = NodeManager::currentNM()->mkNode( MULT, pv_coeff, eq_lhs ); - eq_lhs = Rewriter::rewrite( eq_lhs ); - } - if( !lhs_coeff[j].isNull() ){ - Trace("cbqi-inst-debug") << "...mult rhs by " << lhs_coeff[j] << std::endl; - eq_rhs = NodeManager::currentNM()->mkNode( MULT, lhs_coeff[j], eq_rhs ); - eq_rhs = Rewriter::rewrite( eq_rhs ); - } - } - Node eq = eq_lhs.eqNode( eq_rhs ); - eq = Rewriter::rewrite( eq ); - Node vts_coeff_inf; - Node vts_coeff_delta; - //isolate pv in the equality - int ires = solve_arith( pv, eq, veq_c, val, vts_coeff_inf, vts_coeff_delta ); - if( ires!=0 ){ - success = true; - } - /* - //cannot contain infinity? - //if( !d_qe->getTermDatabase()->containsVtsInfinity( eq ) ){ - Trace("cbqi-inst-debug") << "...equality is " << eq << std::endl; - std::map< Node, Node > msum; - if( QuantArith::getMonomialSumLit( eq, msum ) ){ - if( Trace.isOn("cbqi-inst-debug") ){ - Trace("cbqi-inst-debug") << "...got monomial sum: " << std::endl; - QuantArith::debugPrintMonomialSum( msum, "cbqi-inst-debug" ); - Trace("cbqi-inst-debug") << "isolate for " << pv << " : " << pv.getType() << "..." << std::endl; - } - Node veq; - if( QuantArith::isolate( pv, msum, veq, EQUAL, true )!=0 ){ - Trace("cbqi-inst-debug") << "...isolated equality " << veq << "." << std::endl; - Node veq_c; - if( veq[0]!=pv ){ - Node veq_v; - if( QuantArith::getMonomial( veq[0], veq_c, veq_v ) ){ - Assert( veq_v==pv ); - } - } - Node val = veq[1]; - if( subs_proc[val].find( veq_c )==subs_proc[val].end() ){ - subs_proc[val][veq_c] = true; - if( doAddInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - */ - }else if( pvtnb.isDatatype() ){ - val = solve_dt( pv, lhs[j], ns, lhs[j], ns ); - if( !val.isNull() ){ - success = true; - } - } - if( success ){ - if( subs_proc[val].find( veq_c )==subs_proc[val].end() ){ - subs_proc[val][veq_c] = true; - if( doAddInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } + if( !ns.isNull() ){ + bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end(); + Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl; + std::vector< Node > term_coeffs; + std::vector< Node > terms; + term_coeffs.push_back( pv_coeff ); + terms.push_back( ns ); + for( unsigned j=0; j<lhs.size(); j++ ){ + //if this term or the another has pv in it, try to solve for it + if( hasVar || lhs_v[j] ){ + Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl; + //processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ) { return false; } + term_coeffs.push_back( lhs_coeff[j] ); + terms.push_back( lhs[j] ); + if( vinst->processEquality( this, sf, pv, term_coeffs, terms, effort ) ){ + return true; } + term_coeffs.pop_back(); + terms.pop_back(); } } + lhs.push_back( ns ); + lhs_v.push_back( hasVar ); + lhs_coeff.push_back( pv_coeff ); + }else{ + Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl; } - lhs.push_back( ns ); - lhs_v.push_back( hasVar ); - lhs_coeff.push_back( pv_coeff ); }else{ - Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl; + Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl; } - }else{ - Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl; } } } //[4] directly look at assertions - Trace("cbqi-inst-debug") << "[4] try based on assertions." << std::endl; - d_vts_sym[0] = d_qe->getTermDatabase()->getVtsInfinity( pvtn, false, false ); - d_vts_sym[1] = d_qe->getTermDatabase()->getVtsDelta( false, false ); - std::vector< Node > mbp_bounds[2]; - std::vector< Node > mbp_coeff[2]; - std::vector< Node > mbp_vts_coeff[2][2]; - std::vector< Node > mbp_lit[2]; - //std::vector< MbpBounds > mbp_bounds[2]; - //unsigned rmax = Theory::theoryOf( pv )==Theory::theoryOf( pv.getType() ) ? 1 : 2; - for( unsigned r=0; r<2; r++ ){ - TheoryId tid = r==0 ? Theory::theoryOf( pvtn ) : THEORY_UF; - Trace("cbqi-inst-debug2") << " look at assertions of " << tid << std::endl; - std::map< TheoryId, std::vector< Node > >::iterator ita = d_curr_asserts.find( tid ); - if( ita!=d_curr_asserts.end() ){ - for (unsigned j = 0; j<ita->second.size(); j++) { - Node lit = ita->second[j]; - Trace("cbqi-inst-debug2") << " look at " << lit << std::endl; - Node atom = lit.getKind()==NOT ? lit[0] : lit; - bool pol = lit.getKind()!=NOT; - if( pvtn.isReal() ){ - //arithmetic inequalities and disequalities - if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){ - Assert( atom.getKind()!=GEQ || atom[1].isConst() ); - Node atom_lhs; - Node atom_rhs; - if( atom.getKind()==GEQ ){ - atom_lhs = atom[0]; - atom_rhs = atom[1]; - }else{ - atom_lhs = NodeManager::currentNM()->mkNode( MINUS, atom[0], atom[1] ); - atom_lhs = Rewriter::rewrite( atom_lhs ); - atom_rhs = d_zero; - } - - computeProgVars( atom_lhs ); - //must be an eligible term - if( d_inelig.find( atom_lhs )==d_inelig.end() ){ - //apply substitution to LHS of atom - if( !d_prog_var[atom_lhs].empty() ){ - Node atom_lhs_coeff; - atom_lhs = applySubstitution( pvtn, atom_lhs, sf, vars, atom_lhs_coeff ); - if( !atom_lhs.isNull() ){ - computeProgVars( atom_lhs ); - if( !atom_lhs_coeff.isNull() ){ - atom_rhs = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, atom_lhs_coeff, atom_rhs ) ); - } - } - } - //if it contains pv, not infinity - if( !atom_lhs.isNull() && d_prog_var[atom_lhs].find( pv )!=d_prog_var[atom_lhs].end() ){ - Node satom = NodeManager::currentNM()->mkNode( atom.getKind(), atom_lhs, atom_rhs ); - //cannot contain infinity? - //if( !d_qe->getTermDatabase()->containsVtsInfinity( atom_lhs ) ){ - Trace("cbqi-inst-debug") << "..[3] From assertion : " << atom << ", pol = " << pol << std::endl; - Trace("cbqi-inst-debug") << " substituted : " << satom << ", pol = " << pol << std::endl; - Node vts_coeff_inf; - Node vts_coeff_delta; - Node val; - Node veq_c; - //isolate pv in the inequality - int ires = solve_arith( pv, satom, veq_c, val, vts_coeff_inf, vts_coeff_delta ); - if( ires!=0 ){ - //disequalities are either strict upper or lower bounds - unsigned rmax = ( atom.getKind()==GEQ && options::cbqiModel() ) ? 1 : 2; - for( unsigned r=0; r<rmax; r++ ){ - int uires = ires; - Node uval = val; - if( atom.getKind()==GEQ ){ - //push negation downwards - if( !pol ){ - uires = -ires; - if( pvtn.isInteger() ){ - uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) ); - uval = Rewriter::rewrite( uval ); - }else{ - Assert( pvtn.isReal() ); - //now is strict inequality - uires = uires*2; - } - } - }else{ - bool is_upper = ( r==0 ); - if( options::cbqiModel() ){ - // disequality is a disjunction : only consider the bound in the direction of the model - //first check if there is an infinity... - if( !vts_coeff_inf.isNull() ){ - //coefficient or val won't make a difference, just compare with zero - Trace("cbqi-inst-debug") << "Disequality : check infinity polarity " << vts_coeff_inf << std::endl; - Assert( vts_coeff_inf.isConst() ); - is_upper = ( vts_coeff_inf.getConst<Rational>().sgn()==1 ); - }else{ - Node rhs_value = getModelValue( val ); - Node lhs_value = pv_value; - if( !veq_c.isNull() ){ - lhs_value = NodeManager::currentNM()->mkNode( MULT, lhs_value, veq_c ); - lhs_value = Rewriter::rewrite( lhs_value ); - } - Trace("cbqi-inst-debug") << "Disequality : check model values " << lhs_value << " " << rhs_value << std::endl; - Assert( lhs_value!=rhs_value ); - Node cmp = NodeManager::currentNM()->mkNode( GEQ, lhs_value, rhs_value ); - cmp = Rewriter::rewrite( cmp ); - Assert( cmp.isConst() ); - is_upper = ( cmp!=d_true ); - } - } - Assert( atom.getKind()==EQUAL && !pol ); - if( pvtn.isInteger() ){ - uires = is_upper ? -1 : 1; - uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) ); - uval = Rewriter::rewrite( uval ); - }else{ - Assert( pvtn.isReal() ); - uires = is_upper ? -2 : 2; - } - } - Trace("cbqi-bound-inf") << "From " << lit << ", got : "; - if( !veq_c.isNull() ){ - Trace("cbqi-bound-inf") << veq_c << " * "; - } - Trace("cbqi-bound-inf") << pv << " -> " << uval << ", styp = " << uires << std::endl; - //take into account delta - if( d_use_vts_delta && ( uires==2 || uires==-2 ) ){ - if( options::cbqiModel() ){ - Node delta_coeff = NodeManager::currentNM()->mkConst( Rational( uires > 0 ? 1 : -1 ) ); - if( vts_coeff_delta.isNull() ){ - vts_coeff_delta = delta_coeff; - }else{ - vts_coeff_delta = NodeManager::currentNM()->mkNode( PLUS, vts_coeff_delta, delta_coeff ); - vts_coeff_delta = Rewriter::rewrite( vts_coeff_delta ); - } - }else{ - Node delta = d_qe->getTermDatabase()->getVtsDelta(); - uval = NodeManager::currentNM()->mkNode( uires==2 ? PLUS : MINUS, uval, delta ); - uval = Rewriter::rewrite( uval ); - } - } - if( options::cbqiModel() ){ - //just store bounds, will choose based on tighest bound - unsigned index = uires>0 ? 0 : 1; - mbp_bounds[index].push_back( uval ); - mbp_coeff[index].push_back( veq_c ); - for( unsigned t=0; t<2; t++ ){ - mbp_vts_coeff[index][t].push_back( t==0 ? vts_coeff_inf : vts_coeff_delta ); - } - mbp_lit[index].push_back( lit ); - }else{ - //try this bound - if( subs_proc[uval].find( veq_c )==subs_proc[uval].end() ){ - subs_proc[uval][veq_c] = true; - if( doAddInstantiationInc( uval, pv, veq_c, uires>0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - } - } - } - } - } - /* TODO: algebraic reasoning for bitvector instantiation - else if( pvtn.isBitVector() ){ - if( atom.getKind()==BITVECTOR_ULT || atom.getKind()==BITVECTOR_ULE ){ - for( unsigned t=0; t<2; t++ ){ - if( atom[t]==pv ){ - computeProgVars( atom[1-t] ); - if( d_inelig.find( atom[1-t] )==d_inelig.end() ){ - //only ground terms TODO: more - if( d_prog_var[atom[1-t]].empty() ){ - Node veq_c; - Node uval; - if( ( !pol && atom.getKind()==BITVECTOR_ULT ) || ( pol && atom.getKind()==BITVECTOR_ULE ) ){ - uval = atom[1-t]; - }else{ - uval = NodeManager::currentNM()->mkNode( (atom.getKind()==BITVECTOR_ULT)==(t==1) ? BITVECTOR_PLUS : BITVECTOR_SUB, atom[1-t], - bv::utils::mkConst(pvtn.getConst<BitVectorSize>(), 1) ); - } - if( subs_proc[uval].find( veq_c )==subs_proc[uval].end() ){ - subs_proc[uval][veq_c] = true; - if( doAddInstantiationInc( uval, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - } - } - } - } - */ - } - } - } - if( options::cbqiModel() ){ - if( pvtn.isInteger() || pvtn.isReal() ){ - bool use_inf = d_use_vts_inf && ( pvtn.isInteger() ? options::cbqiUseInfInt() : options::cbqiUseInfReal() ) && !options::cbqiMidpoint(); - bool upper_first = false; - if( options::cbqiMinBounds() ){ - upper_first = mbp_bounds[1].size()<mbp_bounds[0].size(); - } - int best_used[2]; - std::vector< Node > t_values[3]; - //try optimal bounds - for( unsigned r=0; r<2; r++ ){ - int rr = upper_first ? (1-r) : r; - best_used[rr] = -1; - if( mbp_bounds[rr].empty() ){ - if( use_inf ){ - Trace("cbqi-bound") << "No " << ( rr==0 ? "lower" : "upper" ) << " bounds for " << pv << " (type=" << pvtn << ")" << std::endl; - //no bounds, we do +- infinity - Node val = d_qe->getTermDatabase()->getVtsInfinity( pvtn ); - //TODO : rho value for infinity? - if( rr==0 ){ - val = NodeManager::currentNM()->mkNode( UMINUS, val ); - val = Rewriter::rewrite( val ); - } - if( doAddInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - }else{ - Trace("cbqi-bound") << ( rr==0 ? "Lower" : "Upper" ) << " bounds for " << pv << " (type=" << pvtn << ") : " << std::endl; - int best = -1; - Node best_bound_value[3]; - for( unsigned j=0; j<mbp_bounds[rr].size(); j++ ){ - Node value[3]; - if( Trace.isOn("cbqi-bound") ){ - Assert( !mbp_bounds[rr][j].isNull() ); - Trace("cbqi-bound") << " " << j << ": " << mbp_bounds[rr][j]; - if( !mbp_vts_coeff[rr][0][j].isNull() ){ - Trace("cbqi-bound") << " (+ " << mbp_vts_coeff[rr][0][j] << " * INF)"; - } - if( !mbp_vts_coeff[rr][1][j].isNull() ){ - Trace("cbqi-bound") << " (+ " << mbp_vts_coeff[rr][1][j] << " * DELTA)"; - } - if( !mbp_coeff[rr][j].isNull() ){ - Trace("cbqi-bound") << " (div " << mbp_coeff[rr][j] << ")"; - } - Trace("cbqi-bound") << ", value = "; - } - t_values[rr].push_back( Node::null() ); - //check if it is better than the current best bound : lexicographic order infinite/finite/infinitesimal parts - bool new_best = true; - for( unsigned t=0; t<3; t++ ){ - //get the value - if( t==0 ){ - value[0] = mbp_vts_coeff[rr][0][j]; - if( !value[0].isNull() ){ - Trace("cbqi-bound") << "( " << value[0] << " * INF ) + "; - }else{ - value[0] = d_zero; - } - }else if( t==1 ){ - Node t_value = getModelValue( mbp_bounds[rr][j] ); - t_values[rr][j] = t_value; - value[1] = t_value; - Trace("cbqi-bound") << value[1]; - }else{ - value[2] = mbp_vts_coeff[rr][1][j]; - if( !value[2].isNull() ){ - Trace("cbqi-bound") << " + ( " << value[2] << " * DELTA )"; - }else{ - value[2] = d_zero; - } - } - //multiply by coefficient - if( value[t]!=d_zero && !mbp_coeff[rr][j].isNull() ){ - Assert( mbp_coeff[rr][j].isConst() ); - value[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(1) / mbp_coeff[rr][j].getConst<Rational>() ), value[t] ); - value[t] = Rewriter::rewrite( value[t] ); - } - //check if new best - if( best!=-1 ){ - Assert( !value[t].isNull() && !best_bound_value[t].isNull() ); - if( value[t]!=best_bound_value[t] ){ - Kind k = rr==0 ? GEQ : LEQ; - Node cmp_bound = NodeManager::currentNM()->mkNode( k, value[t], best_bound_value[t] ); - cmp_bound = Rewriter::rewrite( cmp_bound ); - if( cmp_bound!=d_true ){ - new_best = false; - break; - } - } - } - } - Trace("cbqi-bound") << std::endl; - if( new_best ){ - for( unsigned t=0; t<3; t++ ){ - best_bound_value[t] = value[t]; - } - best = j; - } - } - if( best!=-1 ){ - Trace("cbqi-bound") << "...best bound is " << best << " : "; - if( best_bound_value[0]!=d_zero ){ - Trace("cbqi-bound") << "( " << best_bound_value[0] << " * INF ) + "; - } - Trace("cbqi-bound") << best_bound_value[1]; - if( best_bound_value[2]!=d_zero ){ - Trace("cbqi-bound") << " + ( " << best_bound_value[2] << " * DELTA )"; - } - Trace("cbqi-bound") << std::endl; - best_used[rr] = best; - //if using cbqiMidpoint, only add the instance based on one bound if the bound is non-strict - if( !options::cbqiMidpoint() || pvtn.isInteger() || mbp_vts_coeff[rr][1][best].isNull() ){ - Node val = mbp_bounds[rr][best]; - val = getModelBasedProjectionValue( pv, val, rr==0, mbp_coeff[rr][best], pv_value, t_values[rr][best], theta, - mbp_vts_coeff[rr][0][best], mbp_vts_coeff[rr][1][best] ); - if( !val.isNull() ){ - if( subs_proc[val].find( mbp_coeff[rr][best] )==subs_proc[val].end() ){ - subs_proc[val][mbp_coeff[rr][best]] = true; - if( doAddInstantiationInc( val, pv, mbp_coeff[rr][best], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - } - } - } - //if not using infinity, use model value of zero - if( !use_inf && mbp_bounds[0].empty() && mbp_bounds[1].empty() ){ - Node val = d_zero; - Node c; //null (one) coefficient - val = getModelBasedProjectionValue( pv, val, true, c, pv_value, d_zero, theta, Node::null(), Node::null() ); - if( !val.isNull() ){ - if( subs_proc[val].find( c )==subs_proc[val].end() ){ - subs_proc[val][c] = true; - if( doAddInstantiationInc( val, pv, c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - if( options::cbqiMidpoint() && !pvtn.isInteger() ){ - Node vals[2]; - bool bothBounds = true; - Trace("cbqi-bound") << "Try midpoint of bounds..." << std::endl; - for( unsigned rr=0; rr<2; rr++ ){ - int best = best_used[rr]; - if( best==-1 ){ - bothBounds = false; - }else{ - vals[rr] = mbp_bounds[rr][best]; - vals[rr] = getModelBasedProjectionValue( pv, vals[rr], rr==0, Node::null(), pv_value, t_values[rr][best], theta, - mbp_vts_coeff[rr][0][best], Node::null() ); - } - Trace("cbqi-bound") << "Bound : " << vals[rr] << std::endl; - } - Node val; - if( bothBounds ){ - Assert( !vals[0].isNull() && !vals[1].isNull() ); - if( vals[0]==vals[1] ){ - val = vals[0]; - }else{ - val = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkNode( PLUS, vals[0], vals[1] ), - NodeManager::currentNM()->mkConst( Rational(1)/Rational(2) ) ); - val = Rewriter::rewrite( val ); - } - }else{ - if( !vals[0].isNull() ){ - val = NodeManager::currentNM()->mkNode( PLUS, vals[0], d_one ); - val = Rewriter::rewrite( val ); - }else if( !vals[1].isNull() ){ - val = NodeManager::currentNM()->mkNode( MINUS, vals[1], d_one ); - val = Rewriter::rewrite( val ); - } - } - Trace("cbqi-bound") << "Midpoint value : " << val << std::endl; - if( !val.isNull() ){ - if( subs_proc[val].find( Node::null() )==subs_proc[val].end() ){ - subs_proc[val][Node::null()] = true; - if( doAddInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( vinst->hasProcessAssertion( this, sf, pv, effort ) ){ + Trace("cbqi-inst-debug") << "[4] try based on assertions." << std::endl; + std::vector< Node > lits; + //unsigned rmax = Theory::theoryOf( pv )==Theory::theoryOf( pv.getType() ) ? 1 : 2; + for( unsigned r=0; r<2; r++ ){ + TheoryId tid = r==0 ? Theory::theoryOf( pvtn ) : THEORY_UF; + Trace("cbqi-inst-debug2") << " look at assertions of " << tid << std::endl; + std::map< TheoryId, std::vector< Node > >::iterator ita = d_curr_asserts.find( tid ); + if( ita!=d_curr_asserts.end() ){ + for (unsigned j = 0; j<ita->second.size(); j++) { + Node lit = ita->second[j]; + if( std::find( lits.begin(), lits.end(), lit )==lits.end() ){ + lits.push_back( lit ); + if( vinst->processAssertion( this, sf, pv, lit, effort ) ){ return true; } } } } -#ifdef MBP_STRICT_ASSERTIONS - Assert( false ); -#endif - if( options::cbqiNopt() ){ - //try non-optimal bounds (heuristic, may help when nested quantification) ? - Trace("cbqi-bound") << "Try non-optimal bounds..." << std::endl; - for( unsigned r=0; r<2; r++ ){ - int rr = upper_first ? (1-r) : r; - for( unsigned j=0; j<mbp_bounds[rr].size(); j++ ){ - if( (int)j!=best_used[rr] && ( !options::cbqiMidpoint() || mbp_vts_coeff[rr][1][j].isNull() ) ){ - Node val = getModelBasedProjectionValue( pv, mbp_bounds[rr][j], rr==0, mbp_coeff[rr][j], pv_value, t_values[rr][j], theta, - mbp_vts_coeff[rr][0][j], mbp_vts_coeff[rr][1][j] ); - if( !val.isNull() ){ - if( subs_proc[val].find( mbp_coeff[rr][j] )==subs_proc[val].end() ){ - subs_proc[val][mbp_coeff[rr][j]] = true; - if( doAddInstantiationInc( val, pv, mbp_coeff[rr][j], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } - } - } - } - } - } + } + if( vinst->processAssertions( this, sf, pv, lits, effort ) ){ + return true; } } } //[5] resort to using value in model // do so if we are in effort=1, or if the variable is boolean, or if we are solving for a subfield of a datatype - if( ( effort>0 || pvtn.isBoolean() || pvtn.isBitVector() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){ + bool use_model_value = vinst->useModelValue( this, sf, pv, effort ); + if( ( effort>0 || use_model_value || is_cv ) && vinst->allowModelValue( this, sf, pv, effort ) ){ +#ifdef CVC4_ASSERTIONS + if( pvtn.isReal() && options::cbqiNestedQE() && !options::cbqiAll() ){ + Trace("cbqi-warn") << "Had to resort to model value." << std::endl; + Assert( false ); + } +#endif Node mv = getModelValue( pv ); Node pv_coeff_m; Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl; - int new_effort = pvtn.isBoolean() ? effort : 1; -#ifdef MBP_STRICT_ASSERTIONS - //we only resort to values in the case of booleans - Assert( ( pvtn.isInteger() ? !options::cbqiUseInfInt() : !options::cbqiUseInfReal() ) || pvtn.isBoolean() ); -#endif - if( doAddInstantiationInc( mv, pv, pv_coeff_m, 0, sf, ssf, vars, btyp, theta, i, new_effort, cons, curr_var ) ){ + int new_effort = use_model_value ? effort : 1; + if( doAddInstantiationInc( pv, mv, pv_coeff_m, 0, sf, new_effort ) ){ return true; } } Trace("cbqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl; + if( is_cv ){ + d_stack_vars.push_back( pv ); + } + d_active_instantiators.erase( pv ); + unregisterInstantiationVariable( pv ); return false; } } +void CegInstantiator::pushStackVariable( Node v ) { + d_stack_vars.push_back( v ); +} -bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ) { - if( Trace.isOn("cbqi-inst") ){ - for( unsigned j=0; j<sf.d_subs.size(); j++ ){ - Trace("cbqi-inst") << " "; - } - Trace("cbqi-inst") << sf.d_subs.size() << ": "; - if( !pv_coeff.isNull() ){ - Trace("cbqi-inst") << pv_coeff << " * "; - } - Trace("cbqi-inst") << pv << " -> " << n << std::endl; - Assert( n.getType().isSubtypeOf( pv.getType() ) ); - } - //must ensure variables have been computed for n - computeProgVars( n ); - Assert( d_inelig.find( n )==d_inelig.end() ); +void CegInstantiator::popStackVariable() { + Assert( !d_stack_vars.empty() ); + d_stack_vars.pop_back(); +} - //substitute into previous substitutions, when applicable - std::vector< Node > a_subs; - a_subs.push_back( n ); - std::vector< Node > a_var; - a_var.push_back( pv ); - std::vector< Node > a_coeff; - std::vector< Node > a_has_coeff; - if( !pv_coeff.isNull() ){ - a_coeff.push_back( pv_coeff ); - a_has_coeff.push_back( pv ); - } - bool success = true; - std::map< int, Node > prev_subs; - std::map< int, Node > prev_coeff; - std::map< int, Node > prev_sym_subs; - std::vector< Node > new_has_coeff; - Trace("cbqi-inst-debug2") << "Applying substitutions..." << std::endl; - for( unsigned j=0; j<sf.d_subs.size(); j++ ){ - Trace("cbqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl; - Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() ); - if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){ - prev_subs[j] = sf.d_subs[j]; - TNode tv = pv; - TNode ts = n; - Node a_pv_coeff; - Node new_subs = applySubstitution( vars[j].getType(), sf.d_subs[j], a_subs, a_coeff, a_has_coeff, a_var, a_pv_coeff, true ); - if( !new_subs.isNull() ){ - sf.d_subs[j] = new_subs; - if( !a_pv_coeff.isNull() ){ - prev_coeff[j] = sf.d_coeff[j]; - if( sf.d_coeff[j].isNull() ){ - Assert( std::find( sf.d_has_coeff.begin(), sf.d_has_coeff.end(), vars[j] )==sf.d_has_coeff.end() ); - //now has coefficient - new_has_coeff.push_back( vars[j] ); - sf.d_has_coeff.push_back( vars[j] ); - sf.d_coeff[j] = a_pv_coeff; - }else{ - sf.d_coeff[j] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, sf.d_coeff[j], a_pv_coeff ) ); +bool CegInstantiator::doAddInstantiationInc( Node pv, Node n, Node pv_coeff, int bt, SolvedForm& sf, unsigned effort ) { + if( d_curr_subs_proc[pv][n].find( pv_coeff )==d_curr_subs_proc[pv][n].end() ){ + d_curr_subs_proc[pv][n][pv_coeff] = true; + if( Trace.isOn("cbqi-inst") ){ + for( unsigned j=0; j<sf.d_subs.size(); j++ ){ + Trace("cbqi-inst") << " "; + } + Trace("cbqi-inst") << sf.d_subs.size() << ": "; + if( !pv_coeff.isNull() ){ + Trace("cbqi-inst") << pv_coeff << " * "; + } + Trace("cbqi-inst") << pv << " -> " << n << std::endl; + Assert( n.getType().isSubtypeOf( pv.getType() ) ); + } + //must ensure variables have been computed for n + computeProgVars( n ); + Assert( d_inelig.find( n )==d_inelig.end() ); + + //substitute into previous substitutions, when applicable + std::vector< Node > a_subs; + a_subs.push_back( n ); + std::vector< Node > a_var; + a_var.push_back( pv ); + std::vector< Node > a_coeff; + std::vector< Node > a_has_coeff; + if( !pv_coeff.isNull() ){ + a_coeff.push_back( pv_coeff ); + a_has_coeff.push_back( pv ); + } + bool success = true; + std::map< int, Node > prev_subs; + std::map< int, Node > prev_coeff; + std::map< int, Node > prev_sym_subs; + std::vector< Node > new_has_coeff; + Trace("cbqi-inst-debug2") << "Applying substitutions..." << std::endl; + for( unsigned j=0; j<sf.d_subs.size(); j++ ){ + Trace("cbqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl; + Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() ); + if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){ + prev_subs[j] = sf.d_subs[j]; + TNode tv = pv; + TNode ts = n; + Node a_pv_coeff; + Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_subs, a_coeff, a_has_coeff, a_var, a_pv_coeff, true ); + if( !new_subs.isNull() ){ + sf.d_subs[j] = new_subs; + if( !a_pv_coeff.isNull() ){ + prev_coeff[j] = sf.d_coeff[j]; + if( sf.d_coeff[j].isNull() ){ + Assert( std::find( sf.d_has_coeff.begin(), sf.d_has_coeff.end(), sf.d_vars[j] )==sf.d_has_coeff.end() ); + //now has coefficient + new_has_coeff.push_back( sf.d_vars[j] ); + sf.d_has_coeff.push_back( sf.d_vars[j] ); + sf.d_coeff[j] = a_pv_coeff; + }else{ + sf.d_coeff[j] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, sf.d_coeff[j], a_pv_coeff ) ); + } } + if( sf.d_subs[j]!=prev_subs[j] ){ + computeProgVars( sf.d_subs[j] ); + Assert( d_inelig.find( sf.d_subs[j] )==d_inelig.end() ); + } + Trace("cbqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl; + }else{ + Trace("cbqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl; + success = false; + break; } - if( sf.d_subs[j]!=prev_subs[j] ){ - computeProgVars( sf.d_subs[j] ); - Assert( d_inelig.find( sf.d_subs[j] )==d_inelig.end() ); - } - Trace("cbqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl; }else{ - Trace("cbqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl; - success = false; - break; + Trace("cbqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl; } - }else{ - Trace("cbqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl; - } - if( options::cbqiSymLia() && pv_coeff.isNull() ){ - //apply simple substitutions also to sym_subs - prev_sym_subs[j] = ssf.d_subs[j]; - ssf.d_subs[j] = ssf.d_subs[j].substitute( a_var.begin(), a_var.end(), a_subs.begin(), a_subs.end() ); - ssf.d_subs[j] = Rewriter::rewrite( ssf.d_subs[j] ); } - } - if( success ){ - Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl; - vars.push_back( pv ); - btyp.push_back( bt ); - sf.push_back( pv, n, pv_coeff ); - ssf.push_back( pv, n, pv_coeff ); - Node new_theta = theta; - if( !pv_coeff.isNull() ){ - if( new_theta.isNull() ){ - new_theta = pv_coeff; - }else{ - new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, pv_coeff ); - new_theta = Rewriter::rewrite( new_theta ); + if( success ){ + Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl; + sf.push_back( pv, n, pv_coeff, bt ); + Node prev_theta = sf.d_theta; + Node new_theta = sf.d_theta; + if( !pv_coeff.isNull() ){ + if( new_theta.isNull() ){ + new_theta = pv_coeff; + }else{ + new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, pv_coeff ); + new_theta = Rewriter::rewrite( new_theta ); + } } - } - bool is_cv = false; - if( !curr_var.empty() ){ - Assert( curr_var.back()==pv ); - curr_var.pop_back(); - is_cv = true; - } - Trace("cbqi-inst-debug2") << "Recurse..." << std::endl; - success = doAddInstantiation( sf, ssf, vars, btyp, new_theta, curr_var.empty() ? i+1 : i, effort, cons, curr_var ); - if( !success ){ - Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl; - if( is_cv ){ - curr_var.push_back( pv ); + sf.d_theta = new_theta; + Trace("cbqi-inst-debug2") << "Recurse..." << std::endl; + unsigned i = d_curr_index[pv]; + success = doAddInstantiation( sf, d_stack_vars.empty() ? i+1 : i, effort ); + sf.d_theta = prev_theta; + if( !success ){ + Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl; + sf.pop_back( pv, n, pv_coeff, bt ); } - sf.pop_back( pv, n, pv_coeff ); - ssf.pop_back( pv, n, pv_coeff ); - vars.pop_back(); - btyp.pop_back(); - } - } - if( success ){ - return true; - }else{ - Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl; - //revert substitution information - for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){ - sf.d_subs[it->first] = it->second; - } - for( std::map< int, Node >::iterator it = prev_coeff.begin(); it != prev_coeff.end(); it++ ){ - sf.d_coeff[it->first] = it->second; - } - for( unsigned i=0; i<new_has_coeff.size(); i++ ){ - sf.d_has_coeff.pop_back(); - } - for( std::map< int, Node >::iterator it = prev_sym_subs.begin(); it != prev_sym_subs.end(); it++ ){ - ssf.d_subs[it->first] = it->second; } - return false; - } -} - -bool CegInstantiator::doAddInstantiationCoeff( SolvedForm& sf, std::vector< Node >& vars, std::vector< int >& btyp, - unsigned j, std::map< Node, Node >& cons ) { - - - if( j==sf.d_has_coeff.size() ){ - return doAddInstantiation( sf.d_subs, vars, cons ); - }else{ - Assert( std::find( vars.begin(), vars.end(), sf.d_has_coeff[j] )!=vars.end() ); - unsigned index = std::find( vars.begin(), vars.end(), sf.d_has_coeff[j] )-vars.begin(); - Node prev = sf.d_subs[index]; - Assert( !sf.d_coeff[index].isNull() ); - Trace("cbqi-inst-debug") << "Normalize substitution for " << sf.d_coeff[index] << " * " << vars[index] << " = " << sf.d_subs[index] << std::endl; - Assert( vars[index].getType().isInteger() ); - //must ensure that divisibility constraints are met - //solve updated rewritten equality for vars[index], if coefficient is one, then we are successful - Node eq_lhs = NodeManager::currentNM()->mkNode( MULT, sf.d_coeff[index], vars[index] ); - Node eq_rhs = sf.d_subs[index]; - Node eq = eq_lhs.eqNode( eq_rhs ); - eq = Rewriter::rewrite( eq ); - Trace("cbqi-inst-debug") << "...equality is " << eq << std::endl; - std::map< Node, Node > msum; - if( QuantArith::getMonomialSumLit( eq, msum ) ){ - Node veq; - if( QuantArith::isolate( vars[index], msum, veq, EQUAL, true )!=0 ){ - Node veq_c; - if( veq[0]!=vars[index] ){ - Node veq_v; - if( QuantArith::getMonomial( veq[0], veq_c, veq_v ) ){ - Assert( veq_v==vars[index] ); - } - } - sf.d_subs[index] = veq[1]; - if( !veq_c.isNull() ){ - sf.d_subs[index] = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, veq[1], veq_c ); - Trace("cbqi-inst-debug") << "...bound type is : " << btyp[index] << std::endl; - //intger division rounding up if from a lower bound - if( btyp[index]==1 && options::cbqiRoundUpLowerLia() ){ - sf.d_subs[index] = NodeManager::currentNM()->mkNode( PLUS, sf.d_subs[index], - NodeManager::currentNM()->mkNode( ITE, - NodeManager::currentNM()->mkNode( EQUAL, - NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, veq[1], veq_c ), - d_zero ), - d_zero, d_one ) - ); - } - } - Trace("cbqi-inst-debug") << "...normalize integers : " << vars[index] << " -> " << sf.d_subs[index] << std::endl; - if( options::cbqiSymLia() ){ - //must apply substitution to previous subs - std::vector< Node > curr_var; - std::vector< Node > curr_subs; - curr_var.push_back( vars[index] ); - curr_subs.push_back( sf.d_subs[index] ); - for( unsigned k=0; k<index; k++ ){ - Node prevs = sf.d_subs[k]; - sf.d_subs[k] = sf.d_subs[k].substitute( curr_var.begin(), curr_var.end(), curr_subs.begin(), curr_subs.end() ); - if( prevs!=sf.d_subs[k] ){ - Trace("cbqi-inst-debug2") << " rewrite " << vars[k] << " -> " << prevs << " to "; - sf.d_subs[k] = Rewriter::rewrite( sf.d_subs[k] ); - Trace("cbqi-inst-debug2") << sf.d_subs[k] << std::endl; - } - } - } - if( doAddInstantiationCoeff( sf, vars, btyp, j+1, cons ) ){ - return true; - } + if( success ){ + return true; + }else{ + Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl; + //revert substitution information + for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){ + sf.d_subs[it->first] = it->second; + } + for( std::map< int, Node >::iterator it = prev_coeff.begin(); it != prev_coeff.end(); it++ ){ + sf.d_coeff[it->first] = it->second; + } + for( unsigned i=0; i<new_has_coeff.size(); i++ ){ + sf.d_has_coeff.pop_back(); } + return false; } - sf.d_subs[index] = prev; - Trace("cbqi-inst-debug") << "...failed." << std::endl; + }else{ + //already tried this substitution return false; } } -bool CegInstantiator::doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ) { +bool CegInstantiator::doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars ) { if( vars.size()>d_vars.size() ){ Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl; std::map< Node, Node > subs_map; @@ -953,7 +470,9 @@ bool CegInstantiator::doAddInstantiation( std::vector< Node >& subs, std::vector } subs.clear(); for( unsigned i=0; i<d_vars.size(); i++ ){ - Node n = constructInstantiation( d_vars[i], subs_map, cons ); + std::map< Node, Node >::iterator it = subs_map.find( d_vars[i] ); + Assert( it!=subs_map.end() ); + Node n = it->second; Trace("cbqi-inst-debug") << " " << d_vars[i] << " -> " << n << std::endl; subs.push_back( n ); } @@ -967,32 +486,9 @@ bool CegInstantiator::doAddInstantiation( std::vector< Node >& subs, std::vector } } bool ret = d_out->doAddInstantiation( subs ); -#ifdef MBP_STRICT_ASSERTIONS - Assert( ret ); -#endif return ret; } -Node CegInstantiator::constructInstantiation( Node n, std::map< Node, Node >& subs_map, std::map< Node, Node >& cons ) { - std::map< Node, Node >::iterator it = subs_map.find( n ); - if( it!=subs_map.end() ){ - return it->second; - }else{ - it = cons.find( n ); - Assert( it!=cons.end() ); - std::vector< Node > children; - children.push_back( it->second ); - const Datatype& dt = Datatype::datatypeOf( it->second.toExpr() ); - unsigned cindex = Datatype::indexOf( it->second.toExpr() ); - for( unsigned i=0; i<dt[cindex].getNumArgs(); i++ ){ - Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][i].getSelector() ), n ); - Node nc = constructInstantiation( nn, subs_map, cons ); - children.push_back( nc ); - } - return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); - } -} - Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& subs, std::vector< Node >& coeff, std::vector< Node >& has_coeff, std::vector< Node >& vars, Node& pv_coeff, bool try_coeff ) { Assert( d_prog_var.find( n )!=d_prog_var.end() ); @@ -1097,66 +593,6 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node } } -Node CegInstantiator::getModelBasedProjectionValue( Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ) { - Node val = t; - Trace("cbqi-bound2") << "Value : " << val << std::endl; - Assert( !e.getType().isInteger() || t.getType().isInteger() ); - Assert( !e.getType().isInteger() || mt.getType().isInteger() ); - //add rho value - //get the value of c*e - Node ceValue = me; - Node new_theta = theta; - if( !c.isNull() ){ - Assert( c.getType().isInteger() ); - ceValue = NodeManager::currentNM()->mkNode( MULT, ceValue, c ); - ceValue = Rewriter::rewrite( ceValue ); - if( new_theta.isNull() ){ - new_theta = c; - }else{ - new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, c ); - new_theta = Rewriter::rewrite( new_theta ); - } - Trace("cbqi-bound2") << "...c*e = " << ceValue << std::endl; - Trace("cbqi-bound2") << "...theta = " << new_theta << std::endl; - } - if( !new_theta.isNull() && e.getType().isInteger() ){ - Node rho; - //if( !mt.getType().isInteger() ){ - //round up/down - //mt = NodeManager::currentNM()->mkNode( - //} - if( isLower ){ - rho = NodeManager::currentNM()->mkNode( MINUS, ceValue, mt ); - }else{ - rho = NodeManager::currentNM()->mkNode( MINUS, mt, ceValue ); - } - rho = Rewriter::rewrite( rho ); - Trace("cbqi-bound2") << "...rho = " << me << " - " << mt << " = " << rho << std::endl; - Trace("cbqi-bound2") << "..." << rho << " mod " << new_theta << " = "; - rho = NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, rho, new_theta ); - rho = Rewriter::rewrite( rho ); - Trace("cbqi-bound2") << rho << std::endl; - Kind rk = isLower ? PLUS : MINUS; - val = NodeManager::currentNM()->mkNode( rk, val, rho ); - val = Rewriter::rewrite( val ); - Trace("cbqi-bound2") << "(after rho) : " << val << std::endl; - } - if( !inf_coeff.isNull() ){ - Assert( !d_vts_sym[0].isNull() ); - val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, inf_coeff, d_vts_sym[0] ) ); - val = Rewriter::rewrite( val ); - } - if( !delta_coeff.isNull() ){ - //create delta here if necessary - if( d_vts_sym[1].isNull() ){ - d_vts_sym[1] = d_qe->getTermDatabase()->getVtsDelta(); - } - val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, delta_coeff, d_vts_sym[1] ) ); - val = Rewriter::rewrite( val ); - } - return val; -} - bool CegInstantiator::check() { if( d_qe->getTheoryEngine()->needCheck() ){ Trace("cbqi-engine") << " CEGQI instantiator : wait until all ground theories are finished." << std::endl; @@ -1165,14 +601,9 @@ bool CegInstantiator::check() { processAssertions(); for( unsigned r=0; r<2; r++ ){ SolvedForm sf; - SolvedForm ssf; - std::vector< Node > vars; - std::vector< int > btyp; - Node theta; - std::map< Node, Node > cons; - std::vector< Node > curr_var; + d_stack_vars.clear(); //try to add an instantiation - if( doAddInstantiation( sf, ssf, vars, btyp, theta, 0, r==0 ? 0 : 2, cons, curr_var ) ){ + if( doAddInstantiation( sf, 0, r==0 ? 0 : 2 ) ){ return true; } } @@ -1222,25 +653,27 @@ void getPresolveEqConjuncts( std::vector< Node >& vars, std::vector< Node >& ter } void CegInstantiator::presolve( Node q ) { - Trace("cbqi-presolve") << "CBQI presolve " << q << std::endl; //at preregister time, add proxy of obvious instantiations up front, which helps learning during preprocessing - std::vector< Node > vars; - std::map< Node, std::vector< Node > > teq; - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - vars.push_back( q[0][i] ); - teq[q[0][i]].clear(); - } - collectPresolveEqTerms( q[1], teq ); - std::vector< Node > terms; - std::vector< Node > conj; - getPresolveEqConjuncts( vars, terms, teq, q, conj ); - - if( !conj.empty() ){ - Node lem = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); - Node g = NodeManager::currentNM()->mkSkolem( "g", NodeManager::currentNM()->booleanType() ); - lem = NodeManager::currentNM()->mkNode( OR, g, lem ); - Trace("cbqi-presolve-debug") << "Presolve lemma : " << lem << std::endl; - d_qe->getOutputChannel().lemma( lem, false, true ); + //only if no nested quantifiers + if( !QuantifiersRewriter::containsQuantifiers( q[1] ) ){ + std::vector< Node > ps_vars; + std::map< Node, std::vector< Node > > teq; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + ps_vars.push_back( q[0][i] ); + teq[q[0][i]].clear(); + } + collectPresolveEqTerms( q[1], teq ); + std::vector< Node > terms; + std::vector< Node > conj; + getPresolveEqConjuncts( ps_vars, terms, teq, q, conj ); + + if( !conj.empty() ){ + Node lem = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); + Node g = NodeManager::currentNM()->mkSkolem( "g", NodeManager::currentNM()->booleanType() ); + lem = NodeManager::currentNM()->mkNode( OR, g, lem ); + Trace("cbqi-presolve-debug") << "Presolve lemma : " << lem << std::endl; + d_qe->getOutputChannel().lemma( lem, false, true ); + } } } @@ -1362,9 +795,7 @@ void CegInstantiator::processAssertions() { addToAuxVarSubstitution( subs_lhs, subs_rhs, r, it->second ); }else{ Trace("cbqi-proc") << "....no substitution found for auxiliary variable " << r << "!!!" << std::endl; -#ifdef MBP_STRICT_ASSERTIONS Assert( false ); -#endif } } @@ -1397,10 +828,8 @@ void CegInstantiator::processAssertions() { std::vector< Node > akeep; for( unsigned i=0; i<it->second.size(); i++ ){ Node n = it->second[i]; - //compute the variables in assertion - computeProgVars( n ); //must be an eligible term - if( d_inelig.find( n )==d_inelig.end() ){ + if( isEligible( n ) ){ //must contain at least one variable if( !d_prog_var[n].empty() ){ Trace("cbqi-proc") << "...literal[" << it->first << "] : " << n << std::endl; @@ -1453,17 +882,16 @@ Node CegInstantiator::getModelValue( Node n ) { void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) { if( n.getKind()==FORALL ){ d_is_nested_quant = true; - }else{ - if( visited.find( n )==visited.end() ){ - visited[n] = true; - if( TermDb::isBoolConnective( n.getKind() ) ){ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - collectCeAtoms( n[i], visited ); - } - }else{ - if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){ - d_ce_atoms.push_back( n ); - } + }else if( visited.find( n )==visited.end() ){ + visited[n] = true; + if( TermDb::isBoolConnective( n.getKind() ) ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + collectCeAtoms( n[i], visited ); + } + }else{ + if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){ + Trace("cbqi-ce-atoms") << "CE atoms : " << n << std::endl; + d_ce_atoms.push_back( n ); } } } @@ -1479,7 +907,8 @@ struct sortCegVarOrder { void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, std::vector< Node >& ce_vars ) { - Assert( d_vars.empty() ); + //Assert( d_vars.empty() ); + d_vars.clear(); d_vars.insert( d_vars.end(), ce_vars.begin(), ce_vars.end() ); //determine variable order: must do Reals before Ints @@ -1512,7 +941,9 @@ void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, st //remove ITEs IteSkolemMap iteSkolemMap; d_qe->getTheoryEngine()->getIteRemover()->run(lems, iteSkolemMap); - Assert( d_aux_vars.empty() ); + //Assert( d_aux_vars.empty() ); + d_aux_vars.clear(); + d_aux_eq.clear(); for(IteSkolemMap::iterator i = iteSkolemMap.begin(); i != iteSkolemMap.end(); ++i) { Trace("cbqi-debug") << " Auxiliary var (from ITE) : " << i->first << std::endl; d_aux_vars.push_back( i->first ); @@ -1544,159 +975,14 @@ void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, st } } -//this isolates the atom into solved form -// veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf -// ensures val is Int if pv is Int, and val does not contain vts symbols -int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) { - int ires = 0; - Trace("cbqi-inst-debug") << "isolate for " << pv << " in " << atom << std::endl; - std::map< Node, Node > msum; - if( QuantArith::getMonomialSumLit( atom, msum ) ){ - Trace("cbqi-inst-debug") << "got monomial sum: " << std::endl; - if( Trace.isOn("cbqi-inst-debug") ){ - QuantArith::debugPrintMonomialSum( msum, "cbqi-inst-debug" ); - } - TypeNode pvtn = pv.getType(); - //remove vts symbols from polynomial - Node vts_coeff[2]; - for( unsigned t=0; t<2; t++ ){ - if( !d_vts_sym[t].isNull() ){ - std::map< Node, Node >::iterator itminf = msum.find( d_vts_sym[t] ); - if( itminf!=msum.end() ){ - vts_coeff[t] = itminf->second; - if( vts_coeff[t].isNull() ){ - vts_coeff[t] = NodeManager::currentNM()->mkConst( Rational( 1 ) ); - } - //negate if coefficient on variable is positive - std::map< Node, Node >::iterator itv = msum.find( pv ); - if( itv!=msum.end() ){ - //multiply by the coefficient we will isolate for - if( itv->second.isNull() ){ - vts_coeff[t] = QuantArith::negate(vts_coeff[t]); - }else{ - if( !pvtn.isInteger() ){ - vts_coeff[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) / itv->second.getConst<Rational>() ), vts_coeff[t] ); - vts_coeff[t] = Rewriter::rewrite( vts_coeff[t] ); - }else if( itv->second.getConst<Rational>().sgn()==1 ){ - vts_coeff[t] = QuantArith::negate(vts_coeff[t]); - } - } - } - Trace("cbqi-inst-debug") << "vts[" << t << "] coefficient is " << vts_coeff[t] << std::endl; - msum.erase( d_vts_sym[t] ); - } - } - } - ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() ); - if( ires!=0 ){ - Node realPart; - if( Trace.isOn("cbqi-inst-debug") ){ - Trace("cbqi-inst-debug") << "Isolate : "; - if( !veq_c.isNull() ){ - Trace("cbqi-inst-debug") << veq_c << " * "; - } - Trace("cbqi-inst-debug") << pv << " " << atom.getKind() << " " << val << std::endl; - } - if( options::cbqiAll() ){ - // when not pure LIA/LRA, we must check whether the lhs contains pv - if( TermDb::containsTerm( val, pv ) ){ - return 0; - } - } - if( pvtn.isInteger() && ( ( !veq_c.isNull() && !veq_c.getType().isInteger() ) || !val.getType().isInteger() ) ){ - //redo, split integer/non-integer parts - bool useCoeff = false; - Integer coeff = d_one.getConst<Rational>().getNumerator(); - for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ - if( it->first.isNull() || it->first.getType().isInteger() ){ - if( !it->second.isNull() ){ - coeff = coeff.lcm( it->second.getConst<Rational>().getDenominator() ); - useCoeff = true; - } - } - } - //multiply everything by this coefficient - Node rcoeff = NodeManager::currentNM()->mkConst( Rational( coeff ) ); - std::vector< Node > real_part; - for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ - if( useCoeff ){ - if( it->second.isNull() ){ - msum[it->first] = rcoeff; - }else{ - msum[it->first] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, it->second, rcoeff ) ); - } - } - if( !it->first.isNull() && !it->first.getType().isInteger() ){ - real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) ); - } - } - //remove delta TODO: check this - vts_coeff[1] = Node::null(); - //multiply inf - if( !vts_coeff[0].isNull() ){ - vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) ); - } - realPart = real_part.empty() ? d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) ); - Assert( d_out->isEligibleForInstantiation( realPart ) ); - //re-isolate - Trace("cbqi-inst-debug") << "Re-isolate..." << std::endl; - ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() ); - Trace("cbqi-inst-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl; - Trace("cbqi-inst-debug") << " real part : " << realPart << std::endl; - if( ires!=0 ){ - int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1; - val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS, - NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ), - NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) ); //TODO: round up for upper bounds? - Trace("cbqi-inst-debug") << "result : " << val << std::endl; - Assert( val.getType().isInteger() ); - } - } - } - vts_coeff_inf = vts_coeff[0]; - vts_coeff_delta = vts_coeff[1]; - } - return ires; +Instantiator::Instantiator( QuantifiersEngine * qe, TypeNode tn ) : d_type( tn ){ + d_closed_enum_type = qe->getTermDatabase()->isClosedEnumerableType( tn ); } -Node CegInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) { - Trace("cbqi-inst-debug2") << "Solve dt : " << v << " " << a << " " << b << " " << sa << " " << sb << std::endl; - Node ret; - if( !a.isNull() && a==v ){ - ret = sb; - }else if( !b.isNull() && b==v ){ - ret = sa; - }else if( !a.isNull() && a.getKind()==APPLY_CONSTRUCTOR ){ - if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ - if( a.getOperator()==b.getOperator() ){ - for( unsigned i=0; i<a.getNumChildren(); i++ ){ - Node s = solve_dt( v, a[i], b[i], sa[i], sb[i] ); - if( !s.isNull() ){ - return s; - } - } - } - }else{ - unsigned cindex = Datatype::indexOf( a.getOperator().toExpr() ); - TypeNode tn = a.getType(); - const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); - for( unsigned i=0; i<a.getNumChildren(); i++ ){ - Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][i].getSelector() ), sb ); - Node s = solve_dt( v, a[i], Node::null(), sa[i], nn ); - if( !s.isNull() ){ - return s; - } - } - } - }else if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ - return solve_dt( v, b, a, sb, sa ); - } - if( !ret.isNull() ){ - //ensure does not contain - if( TermDb::containsTerm( ret, v ) ){ - ret = Node::null(); - } - } - return ret; + +bool Instantiator::processEqualTerm( CegInstantiator * ci, SolvedForm& sf, Node pv, Node pv_coeff, Node n, unsigned effort ) { + return ci->doAddInstantiationInc( pv, n, pv_coeff, 0, sf, effort ); } + + diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h index 3d7bbcb55..94d02de9b 100755 --- a/src/theory/quantifiers/ceg_instantiator.h +++ b/src/theory/quantifiers/ceg_instantiator.h @@ -38,17 +38,52 @@ public: virtual bool addLemma( Node lem ) = 0; }; +class Instantiator; + + +//solved form, involves substitution with coefficients +class SolvedForm { +public: + std::vector< Node > d_vars; + std::vector< Node > d_subs; + std::vector< Node > d_coeff; + std::vector< int > d_btyp; + std::vector< Node > d_has_coeff; + Node d_theta; + void copy( SolvedForm& sf ){ + d_vars.insert( d_vars.end(), sf.d_vars.begin(), sf.d_vars.end() ); + d_subs.insert( d_subs.end(), sf.d_subs.begin(), sf.d_subs.end() ); + d_coeff.insert( d_coeff.end(), sf.d_coeff.begin(), sf.d_coeff.end() ); + d_btyp.insert( d_btyp.end(), sf.d_btyp.begin(), sf.d_btyp.end() ); + d_has_coeff.insert( d_has_coeff.end(), sf.d_has_coeff.begin(), sf.d_has_coeff.end() ); + d_theta = sf.d_theta; + } + void push_back( Node pv, Node n, Node pv_coeff, int bt ){ + d_vars.push_back( pv ); + d_subs.push_back( n ); + d_coeff.push_back( pv_coeff ); + d_btyp.push_back( bt ); + if( !pv_coeff.isNull() ){ + d_has_coeff.push_back( pv ); + } + } + void pop_back( Node pv, Node n, Node pv_coeff, int bt ){ + d_vars.pop_back(); + d_subs.pop_back(); + d_coeff.pop_back(); + d_btyp.pop_back(); + if( !pv_coeff.isNull() ){ + d_has_coeff.pop_back(); + } + } +}; + class CegInstantiator { private: QuantifiersEngine * d_qe; CegqiOutput * d_out; - //constants - Node d_zero; - Node d_one; - Node d_true; bool d_use_vts_delta; bool d_use_vts_inf; - Node d_vts_sym[2]; //program variable contains cache std::map< Node, std::map< Node, bool > > d_prog_var; std::map< Node, bool > d_inelig; @@ -67,81 +102,116 @@ private: //atoms of the CE lemma bool d_is_nested_quant; std::vector< Node > d_ce_atoms; -private: //collect atoms - void collectCeAtoms( Node n, std::map< Node, bool >& visited ); + void collectCeAtoms( Node n, std::map< Node, bool >& visited ); +private: + //map from variables to their instantiators + std::map< Node, Instantiator * > d_instantiator; + //cache of current substitutions tried between register/unregister + std::map< Node, std::map< Node, std::map< Node, bool > > > d_curr_subs_proc; + std::map< Node, unsigned > d_curr_index; + //stack of temporary variables we are solving (e.g. subfields of datatypes) + std::vector< Node > d_stack_vars; + //used instantiators + std::map< Node, Instantiator * > d_active_instantiators; + //register variable + void registerInstantiationVariable( Node v, unsigned index ); + void unregisterInstantiationVariable( Node v ); +private: //for adding instantiations during check void computeProgVars( Node n ); - //solved form, involves substitution with coefficients - class SolvedForm { - public: - std::vector< Node > d_subs; - std::vector< Node > d_coeff; - std::vector< Node > d_has_coeff; - void copy( SolvedForm& sf ){ - d_subs.insert( d_subs.end(), sf.d_subs.begin(), sf.d_subs.end() ); - d_coeff.insert( d_coeff.end(), sf.d_coeff.begin(), sf.d_coeff.end() ); - d_has_coeff.insert( d_has_coeff.end(), sf.d_has_coeff.begin(), sf.d_has_coeff.end() ); - } - void push_back( Node pv, Node n, Node pv_coeff ){ - d_subs.push_back( n ); - d_coeff.push_back( pv_coeff ); - if( !pv_coeff.isNull() ){ - d_has_coeff.push_back( pv ); - } - } - void pop_back( Node pv, Node n, Node pv_coeff ){ - d_subs.pop_back(); - d_coeff.pop_back(); - if( !pv_coeff.isNull() ){ - d_has_coeff.pop_back(); - } - } - }; - /* - class MbpBound { - public: - Node d_bound; - Node d_coeff; - Node d_vts_coeff[2]; - Node d_lit; - }; - */ // effort=0 : do not use model value, 1: use model value, 2: one must use model value - bool doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ); - bool doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ); - bool doAddInstantiationCoeff( SolvedForm& sf, - std::vector< Node >& vars, std::vector< int >& btyp, - unsigned j, std::map< Node, Node >& cons ); - bool doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ); - Node constructInstantiation( Node n, std::map< Node, Node >& subs_map, std::map< Node, Node >& cons ); - Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, std::vector< Node >& vars, Node& pv_coeff, bool try_coeff = true ) { - return applySubstitution( tn, n, sf.d_subs, sf.d_coeff, sf.d_has_coeff, vars, pv_coeff, try_coeff ); - } - Node applySubstitution( TypeNode tn, Node n, std::vector< Node >& subs, std::vector< Node >& coeff, std::vector< Node >& has_coeff, - std::vector< Node >& vars, Node& pv_coeff, bool try_coeff = true ); - Node getModelBasedProjectionValue( Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ); + bool doAddInstantiation( SolvedForm& sf, unsigned i, unsigned effort ); + bool doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars ); + //process void processAssertions(); void addToAuxVarSubstitution( std::vector< Node >& subs_lhs, std::vector< Node >& subs_rhs, Node l, Node r ); - //get model value - Node getModelValue( Node n ); -private: - int solve_arith( Node v, Node atom, Node & veq_c, Node & val, Node& vts_coeff_inf, Node& vts_coeff_delta ); - Node solve_dt( Node v, Node a, Node b, Node sa, Node sb ); public: CegInstantiator( QuantifiersEngine * qe, CegqiOutput * out, bool use_vts_delta = true, bool use_vts_inf = true ); + virtual ~CegInstantiator(); //check : add instantiations based on valuation of d_vars bool check(); //presolve for quantified formula void presolve( Node q ); //register the counterexample lemma (stored in lems), modify vector void registerCounterexampleLemma( std::vector< Node >& lems, std::vector< Node >& ce_vars ); + //output + CegqiOutput * getOutput() { return d_out; } + //get quantifiers engine + QuantifiersEngine* getQuantifiersEngine() { return d_qe; } + +//interface for instantiators +public: + void pushStackVariable( Node v ); + void popStackVariable(); + bool doAddInstantiationInc( Node pv, Node n, Node pv_coeff, int bt, SolvedForm& sf, unsigned effort ); + Node getModelValue( Node n ); + // TODO: move to solved form? + Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, Node& pv_coeff, bool try_coeff = true ) { + return applySubstitution( tn, n, sf.d_subs, sf.d_coeff, sf.d_has_coeff, sf.d_vars, pv_coeff, try_coeff ); + } + Node applySubstitution( TypeNode tn, Node n, std::vector< Node >& subs, std::vector< Node >& coeff, std::vector< Node >& has_coeff, + std::vector< Node >& vars, Node& pv_coeff, bool try_coeff = true ); +public: + unsigned getNumCEAtoms() { return d_ce_atoms.size(); } + Node getCEAtom( unsigned i ) { return d_ce_atoms[i]; } + // is eligible + bool isEligible( Node n ); + // has variable + bool hasVariable( Node n, Node pv ); + bool useVtsDelta() { return d_use_vts_delta; } + bool useVtsInfinity() { return d_use_vts_inf; } + bool hasNestedQuantification() { return d_is_nested_quant; } }; + + +// an instantiator for individual variables +// will make calls into CegInstantiator::doAddInstantiationInc +class Instantiator { +protected: + TypeNode d_type; + bool d_closed_enum_type; +public: + Instantiator( QuantifiersEngine * qe, TypeNode tn ); + virtual ~Instantiator(){} + virtual void reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) {} + + //called when pv_coeff * pv = n, and n is eligible for instantiation + virtual bool processEqualTerm( CegInstantiator * ci, SolvedForm& sf, Node pv, Node pv_coeff, Node n, unsigned effort ); + //eqc is the equivalence class of pv + virtual bool processEqualTerms( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& eqc, unsigned effort ) { return false; } + + //term_coeffs.size() = terms.size() = 2, called when term_coeff[0] * terms[0] = term_coeff[1] * terms[1], terms are eligible, and at least one of these terms contains pv + virtual bool hasProcessEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return false; } + virtual bool processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ) { return false; } + + //called when assertion lit holds. note that lit is unsubstituted, first must substitute/solve/check eligible + virtual bool hasProcessAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return false; } + virtual bool processAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, Node lit, unsigned effort ) { return false; } + virtual bool processAssertions( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& lits, unsigned effort ) { return false; } + + //do we allow instantiation for the model value of pv + virtual bool useModelValue( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return false; } + virtual bool allowModelValue( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return d_closed_enum_type; } + + //do we need to postprocess the solved form? did we successfully postprocess + virtual bool needsPostProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return false; } + virtual bool postProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + + /** Identify this module (for debugging) */ + virtual std::string identify() const { return "Default"; } +}; + +class ModelValueInstantiator : public Instantiator { +public: + ModelValueInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){} + virtual ~ModelValueInstantiator(){} + bool useModelValue( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + std::string identify() const { return "ModelValue"; } +}; + + } } } diff --git a/src/theory/quantifiers/ceg_t_instantiator.cpp b/src/theory/quantifiers/ceg_t_instantiator.cpp new file mode 100644 index 000000000..3282872d6 --- /dev/null +++ b/src/theory/quantifiers/ceg_t_instantiator.cpp @@ -0,0 +1,868 @@ +/********************* */ +/*! \file ceg_t_instantiator.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief Implementation of theory-specific counterexample-guided quantifier instantiation + **/ + +#include "theory/quantifiers/ceg_t_instantiator.h" + +#include "options/quantifiers_options.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/quantifiers_rewriter.h" +#include "theory/quantifiers/trigger.h" + +#include "theory/arith/partial_model.h" +#include "theory/arith/theory_arith.h" +#include "theory/arith/theory_arith_private.h" +#include "theory/bv/theory_bv_utils.h" +#include "util/bitvector.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + +Node ArithInstantiator::getModelBasedProjectionValue( CegInstantiator * ci, Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ) { + Node val = t; + Trace("cbqi-bound2") << "Value : " << val << std::endl; + Assert( !e.getType().isInteger() || t.getType().isInteger() ); + Assert( !e.getType().isInteger() || mt.getType().isInteger() ); + //add rho value + //get the value of c*e + Node ceValue = me; + Node new_theta = theta; + if( !c.isNull() ){ + Assert( c.getType().isInteger() ); + ceValue = NodeManager::currentNM()->mkNode( MULT, ceValue, c ); + ceValue = Rewriter::rewrite( ceValue ); + if( new_theta.isNull() ){ + new_theta = c; + }else{ + new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, c ); + new_theta = Rewriter::rewrite( new_theta ); + } + Trace("cbqi-bound2") << "...c*e = " << ceValue << std::endl; + Trace("cbqi-bound2") << "...theta = " << new_theta << std::endl; + } + if( !new_theta.isNull() && e.getType().isInteger() ){ + Node rho; + //if( !mt.getType().isInteger() ){ + //round up/down + //mt = NodeManager::currentNM()->mkNode( + //} + if( isLower ){ + rho = NodeManager::currentNM()->mkNode( MINUS, ceValue, mt ); + }else{ + rho = NodeManager::currentNM()->mkNode( MINUS, mt, ceValue ); + } + rho = Rewriter::rewrite( rho ); + Trace("cbqi-bound2") << "...rho = " << me << " - " << mt << " = " << rho << std::endl; + Trace("cbqi-bound2") << "..." << rho << " mod " << new_theta << " = "; + rho = NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, rho, new_theta ); + rho = Rewriter::rewrite( rho ); + Trace("cbqi-bound2") << rho << std::endl; + Kind rk = isLower ? PLUS : MINUS; + val = NodeManager::currentNM()->mkNode( rk, val, rho ); + val = Rewriter::rewrite( val ); + Trace("cbqi-bound2") << "(after rho) : " << val << std::endl; + } + if( !inf_coeff.isNull() ){ + Assert( !d_vts_sym[0].isNull() ); + val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, inf_coeff, d_vts_sym[0] ) ); + val = Rewriter::rewrite( val ); + } + if( !delta_coeff.isNull() ){ + //create delta here if necessary + val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, delta_coeff, ci->getQuantifiersEngine()->getTermDatabase()->getVtsDelta() ) ); + val = Rewriter::rewrite( val ); + } + return val; +} + +//this isolates the atom into solved form +// veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf +// ensures val is Int if pv is Int, and val does not contain vts symbols +int ArithInstantiator::solve_arith( CegInstantiator * ci, Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) { + int ires = 0; + Trace("cbqi-inst-debug") << "isolate for " << pv << " in " << atom << std::endl; + std::map< Node, Node > msum; + if( QuantArith::getMonomialSumLit( atom, msum ) ){ + Trace("cbqi-inst-debug") << "got monomial sum: " << std::endl; + if( Trace.isOn("cbqi-inst-debug") ){ + QuantArith::debugPrintMonomialSum( msum, "cbqi-inst-debug" ); + } + TypeNode pvtn = pv.getType(); + //remove vts symbols from polynomial + Node vts_coeff[2]; + for( unsigned t=0; t<2; t++ ){ + if( !d_vts_sym[t].isNull() ){ + std::map< Node, Node >::iterator itminf = msum.find( d_vts_sym[t] ); + if( itminf!=msum.end() ){ + vts_coeff[t] = itminf->second; + if( vts_coeff[t].isNull() ){ + vts_coeff[t] = NodeManager::currentNM()->mkConst( Rational( 1 ) ); + } + //negate if coefficient on variable is positive + std::map< Node, Node >::iterator itv = msum.find( pv ); + if( itv!=msum.end() ){ + //multiply by the coefficient we will isolate for + if( itv->second.isNull() ){ + vts_coeff[t] = QuantArith::negate(vts_coeff[t]); + }else{ + if( !pvtn.isInteger() ){ + vts_coeff[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) / itv->second.getConst<Rational>() ), vts_coeff[t] ); + vts_coeff[t] = Rewriter::rewrite( vts_coeff[t] ); + }else if( itv->second.getConst<Rational>().sgn()==1 ){ + vts_coeff[t] = QuantArith::negate(vts_coeff[t]); + } + } + } + Trace("cbqi-inst-debug") << "vts[" << t << "] coefficient is " << vts_coeff[t] << std::endl; + msum.erase( d_vts_sym[t] ); + } + } + } + + ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() ); + if( ires!=0 ){ + Node realPart; + if( Trace.isOn("cbqi-inst-debug") ){ + Trace("cbqi-inst-debug") << "Isolate : "; + if( !veq_c.isNull() ){ + Trace("cbqi-inst-debug") << veq_c << " * "; + } + Trace("cbqi-inst-debug") << pv << " " << atom.getKind() << " " << val << std::endl; + } + if( options::cbqiAll() ){ + // when not pure LIA/LRA, we must check whether the lhs contains pv + if( TermDb::containsTerm( val, pv ) ){ + Trace("cbqi-inst-debug") << "fail : contains bad term" << std::endl; + return 0; + } + } + if( pvtn.isInteger() && ( ( !veq_c.isNull() && !veq_c.getType().isInteger() ) || !val.getType().isInteger() ) ){ + //redo, split integer/non-integer parts + bool useCoeff = false; + Integer coeff = ci->getQuantifiersEngine()->getTermDatabase()->d_one.getConst<Rational>().getNumerator(); + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ + if( it->first.isNull() || it->first.getType().isInteger() ){ + if( !it->second.isNull() ){ + coeff = coeff.lcm( it->second.getConst<Rational>().getDenominator() ); + useCoeff = true; + } + } + } + //multiply everything by this coefficient + Node rcoeff = NodeManager::currentNM()->mkConst( Rational( coeff ) ); + std::vector< Node > real_part; + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ + if( useCoeff ){ + if( it->second.isNull() ){ + msum[it->first] = rcoeff; + }else{ + msum[it->first] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, it->second, rcoeff ) ); + } + } + if( !it->first.isNull() && !it->first.getType().isInteger() ){ + real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) ); + } + } + //remove delta TODO: check this + vts_coeff[1] = Node::null(); + //multiply inf + if( !vts_coeff[0].isNull() ){ + vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) ); + } + realPart = real_part.empty() ? ci->getQuantifiersEngine()->getTermDatabase()->d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) ); + Assert( ci->getOutput()->isEligibleForInstantiation( realPart ) ); + //re-isolate + Trace("cbqi-inst-debug") << "Re-isolate..." << std::endl; + ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() ); + Trace("cbqi-inst-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl; + Trace("cbqi-inst-debug") << " real part : " << realPart << std::endl; + if( ires!=0 ){ + int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1; + val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS, + NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ), + NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) ); //TODO: round up for upper bounds? + Trace("cbqi-inst-debug") << "result : " << val << std::endl; + Assert( val.getType().isInteger() ); + } + } + } + vts_coeff_inf = vts_coeff[0]; + vts_coeff_delta = vts_coeff[1]; + Trace("cbqi-inst-debug") << "Return " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << ", vts = (" << vts_coeff_inf << ", " << vts_coeff_delta << ")" << std::endl; + }else{ + Trace("cbqi-inst-debug") << "fail : could not get monomial sum" << std::endl; + } + return ires; +} + +void ArithInstantiator::reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { + d_vts_sym[0] = ci->getQuantifiersEngine()->getTermDatabase()->getVtsInfinity( d_type, false, false ); + d_vts_sym[1] = ci->getQuantifiersEngine()->getTermDatabase()->getVtsDelta( false, false ); + for( unsigned i=0; i<2; i++ ){ + d_mbp_bounds[i].clear(); + d_mbp_coeff[i].clear(); + for( unsigned j=0; j<2; j++ ){ + d_mbp_vts_coeff[i][j].clear(); + } + d_mbp_lit[i].clear(); + } +} + +bool ArithInstantiator::processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ) { + Node eq_lhs = terms[0]; + Node eq_rhs = terms[1]; + Node lhs_coeff = term_coeffs[0]; + Node rhs_coeff = term_coeffs[1]; + //make the same coefficient + if( rhs_coeff!=lhs_coeff ){ + if( !rhs_coeff.isNull() ){ + Trace("cbqi-inst-debug") << "...mult lhs by " << rhs_coeff << std::endl; + eq_lhs = NodeManager::currentNM()->mkNode( MULT, rhs_coeff, eq_lhs ); + eq_lhs = Rewriter::rewrite( eq_lhs ); + } + if( !lhs_coeff.isNull() ){ + Trace("cbqi-inst-debug") << "...mult rhs by " << lhs_coeff << std::endl; + eq_rhs = NodeManager::currentNM()->mkNode( MULT, lhs_coeff, eq_rhs ); + eq_rhs = Rewriter::rewrite( eq_rhs ); + } + } + Node eq = eq_lhs.eqNode( eq_rhs ); + eq = Rewriter::rewrite( eq ); + Node val; + Node veq_c; + Node vts_coeff_inf; + Node vts_coeff_delta; + //isolate pv in the equality + int ires = solve_arith( ci, pv, eq, veq_c, val, vts_coeff_inf, vts_coeff_delta ); + if( ires!=0 ){ + if( ci->doAddInstantiationInc( pv, val, veq_c, 0, sf, effort ) ){ + return true; + } + } + + return false; +} + +bool ArithInstantiator::processAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, Node lit, unsigned effort ) { + Trace("cbqi-inst-debug2") << " look at " << lit << std::endl; + Node atom = lit.getKind()==NOT ? lit[0] : lit; + bool pol = lit.getKind()!=NOT; + //arithmetic inequalities and disequalities + if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){ + Assert( atom.getKind()!=GEQ || atom[1].isConst() ); + Node atom_lhs; + Node atom_rhs; + if( atom.getKind()==GEQ ){ + atom_lhs = atom[0]; + atom_rhs = atom[1]; + }else{ + atom_lhs = NodeManager::currentNM()->mkNode( MINUS, atom[0], atom[1] ); + atom_lhs = Rewriter::rewrite( atom_lhs ); + atom_rhs = ci->getQuantifiersEngine()->getTermDatabase()->d_zero; + } + //must be an eligible term + if( ci->isEligible( atom_lhs ) ){ + //apply substitution to LHS of atom + Node atom_lhs_coeff; + atom_lhs = ci->applySubstitution( d_type, atom_lhs, sf, atom_lhs_coeff ); + if( !atom_lhs.isNull() ){ + if( !atom_lhs_coeff.isNull() ){ + atom_rhs = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, atom_lhs_coeff, atom_rhs ) ); + } + } + //if it contains pv, not infinity + if( !atom_lhs.isNull() && ci->hasVariable( atom_lhs, pv ) ){ + Node pv_value = ci->getModelValue( pv ); + Node satom = NodeManager::currentNM()->mkNode( atom.getKind(), atom_lhs, atom_rhs ); + //cannot contain infinity? + Trace("cbqi-inst-debug") << "..[3] From assertion : " << atom << ", pol = " << pol << std::endl; + Trace("cbqi-inst-debug") << " substituted : " << satom << ", pol = " << pol << std::endl; + Node vts_coeff_inf; + Node vts_coeff_delta; + Node val; + Node veq_c; + //isolate pv in the inequality + int ires = solve_arith( ci, pv, satom, veq_c, val, vts_coeff_inf, vts_coeff_delta ); + if( ires!=0 ){ + //disequalities are either strict upper or lower bounds + unsigned rmax = ( atom.getKind()==GEQ || options::cbqiModel() ) ? 1 : 2; + for( unsigned r=0; r<rmax; r++ ){ + int uires = ires; + Node uval = val; + if( atom.getKind()==GEQ ){ + //push negation downwards + if( !pol ){ + uires = -ires; + if( d_type.isInteger() ){ + uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) ); + uval = Rewriter::rewrite( uval ); + }else{ + Assert( d_type.isReal() ); + //now is strict inequality + uires = uires*2; + } + } + }else{ + bool is_upper; + if( options::cbqiModel() ){ + // disequality is a disjunction : only consider the bound in the direction of the model + //first check if there is an infinity... + if( !vts_coeff_inf.isNull() ){ + //coefficient or val won't make a difference, just compare with zero + Trace("cbqi-inst-debug") << "Disequality : check infinity polarity " << vts_coeff_inf << std::endl; + Assert( vts_coeff_inf.isConst() ); + is_upper = ( vts_coeff_inf.getConst<Rational>().sgn()==1 ); + }else{ + Node rhs_value = ci->getModelValue( val ); + Node lhs_value = pv_value; + if( !veq_c.isNull() ){ + lhs_value = NodeManager::currentNM()->mkNode( MULT, lhs_value, veq_c ); + lhs_value = Rewriter::rewrite( lhs_value ); + } + Trace("cbqi-inst-debug") << "Disequality : check model values " << lhs_value << " " << rhs_value << std::endl; + Assert( lhs_value!=rhs_value ); + Node cmp = NodeManager::currentNM()->mkNode( GEQ, lhs_value, rhs_value ); + cmp = Rewriter::rewrite( cmp ); + Assert( cmp.isConst() ); + is_upper = ( cmp!=ci->getQuantifiersEngine()->getTermDatabase()->d_true ); + } + }else{ + is_upper = (r==0); + } + Assert( atom.getKind()==EQUAL && !pol ); + if( d_type.isInteger() ){ + uires = is_upper ? -1 : 1; + uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) ); + uval = Rewriter::rewrite( uval ); + }else{ + Assert( d_type.isReal() ); + uires = is_upper ? -2 : 2; + } + } + Trace("cbqi-bound-inf") << "From " << lit << ", got : "; + if( !veq_c.isNull() ){ + Trace("cbqi-bound-inf") << veq_c << " * "; + } + Trace("cbqi-bound-inf") << pv << " -> " << uval << ", styp = " << uires << std::endl; + //take into account delta + if( ci->useVtsDelta() && ( uires==2 || uires==-2 ) ){ + if( options::cbqiModel() ){ + Node delta_coeff = NodeManager::currentNM()->mkConst( Rational( uires > 0 ? 1 : -1 ) ); + if( vts_coeff_delta.isNull() ){ + vts_coeff_delta = delta_coeff; + }else{ + vts_coeff_delta = NodeManager::currentNM()->mkNode( PLUS, vts_coeff_delta, delta_coeff ); + vts_coeff_delta = Rewriter::rewrite( vts_coeff_delta ); + } + }else{ + Node delta = ci->getQuantifiersEngine()->getTermDatabase()->getVtsDelta(); + uval = NodeManager::currentNM()->mkNode( uires==2 ? PLUS : MINUS, uval, delta ); + uval = Rewriter::rewrite( uval ); + } + } + if( options::cbqiModel() ){ + //just store bounds, will choose based on tighest bound + unsigned index = uires>0 ? 0 : 1; + d_mbp_bounds[index].push_back( uval ); + d_mbp_coeff[index].push_back( veq_c ); + Trace("cbqi-inst-debug") << "Store bound " << index << " " << uval << " " << veq_c << " " << vts_coeff_inf << " " << vts_coeff_delta << " " << lit << std::endl; + for( unsigned t=0; t<2; t++ ){ + d_mbp_vts_coeff[index][t].push_back( t==0 ? vts_coeff_inf : vts_coeff_delta ); + } + d_mbp_lit[index].push_back( lit ); + }else{ + //try this bound + if( ci->doAddInstantiationInc( pv, uval, veq_c, uires>0 ? 1 : -1, sf, effort ) ){ + return true; + } + } + } + } + } + } + } + + + return false; +} + +bool ArithInstantiator::processAssertions( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& lits, unsigned effort ) { + if( options::cbqiModel() ){ + bool use_inf = ci->useVtsInfinity() && ( d_type.isInteger() ? options::cbqiUseInfInt() : options::cbqiUseInfReal() ); + bool upper_first = false; + if( options::cbqiMinBounds() ){ + upper_first = d_mbp_bounds[1].size()<d_mbp_bounds[0].size(); + } + int best_used[2]; + std::vector< Node > t_values[3]; + Node zero = ci->getQuantifiersEngine()->getTermDatabase()->d_zero; + Node one = ci->getQuantifiersEngine()->getTermDatabase()->d_one; + Node pv_value = ci->getModelValue( pv ); + //try optimal bounds + for( unsigned r=0; r<2; r++ ){ + int rr = upper_first ? (1-r) : r; + best_used[rr] = -1; + if( d_mbp_bounds[rr].empty() ){ + if( use_inf ){ + Trace("cbqi-bound") << "No " << ( rr==0 ? "lower" : "upper" ) << " bounds for " << pv << " (type=" << d_type << ")" << std::endl; + //no bounds, we do +- infinity + Node val = ci->getQuantifiersEngine()->getTermDatabase()->getVtsInfinity( d_type ); + //TODO : rho value for infinity? + if( rr==0 ){ + val = NodeManager::currentNM()->mkNode( UMINUS, val ); + val = Rewriter::rewrite( val ); + } + if( ci->doAddInstantiationInc( pv, val, Node::null(), 0, sf, effort ) ){ + return true; + } + } + }else{ + Trace("cbqi-bound") << ( rr==0 ? "Lower" : "Upper" ) << " bounds for " << pv << " (type=" << d_type << ") : " << std::endl; + int best = -1; + Node best_bound_value[3]; + for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){ + Node value[3]; + if( Trace.isOn("cbqi-bound") ){ + Assert( !d_mbp_bounds[rr][j].isNull() ); + Trace("cbqi-bound") << " " << j << ": " << d_mbp_bounds[rr][j]; + if( !d_mbp_vts_coeff[rr][0][j].isNull() ){ + Trace("cbqi-bound") << " (+ " << d_mbp_vts_coeff[rr][0][j] << " * INF)"; + } + if( !d_mbp_vts_coeff[rr][1][j].isNull() ){ + Trace("cbqi-bound") << " (+ " << d_mbp_vts_coeff[rr][1][j] << " * DELTA)"; + } + if( !d_mbp_coeff[rr][j].isNull() ){ + Trace("cbqi-bound") << " (div " << d_mbp_coeff[rr][j] << ")"; + } + Trace("cbqi-bound") << ", value = "; + } + t_values[rr].push_back( Node::null() ); + //check if it is better than the current best bound : lexicographic order infinite/finite/infinitesimal parts + bool new_best = true; + for( unsigned t=0; t<3; t++ ){ + //get the value + if( t==0 ){ + value[0] = d_mbp_vts_coeff[rr][0][j]; + if( !value[0].isNull() ){ + Trace("cbqi-bound") << "( " << value[0] << " * INF ) + "; + }else{ + value[0] = zero; + } + }else if( t==1 ){ + Node t_value = ci->getModelValue( d_mbp_bounds[rr][j] ); + t_values[rr][j] = t_value; + value[1] = t_value; + Trace("cbqi-bound") << value[1]; + }else{ + value[2] = d_mbp_vts_coeff[rr][1][j]; + if( !value[2].isNull() ){ + Trace("cbqi-bound") << " + ( " << value[2] << " * DELTA )"; + }else{ + value[2] = zero; + } + } + //multiply by coefficient + if( value[t]!=zero && !d_mbp_coeff[rr][j].isNull() ){ + Assert( d_mbp_coeff[rr][j].isConst() ); + value[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(1) / d_mbp_coeff[rr][j].getConst<Rational>() ), value[t] ); + value[t] = Rewriter::rewrite( value[t] ); + } + //check if new best + if( best!=-1 ){ + Assert( !value[t].isNull() && !best_bound_value[t].isNull() ); + if( value[t]!=best_bound_value[t] ){ + Kind k = rr==0 ? GEQ : LEQ; + Node cmp_bound = NodeManager::currentNM()->mkNode( k, value[t], best_bound_value[t] ); + cmp_bound = Rewriter::rewrite( cmp_bound ); + if( cmp_bound!=ci->getQuantifiersEngine()->getTermDatabase()->d_true ){ + new_best = false; + break; + } + } + } + } + Trace("cbqi-bound") << std::endl; + if( new_best ){ + for( unsigned t=0; t<3; t++ ){ + best_bound_value[t] = value[t]; + } + best = j; + } + } + if( best!=-1 ){ + Trace("cbqi-bound") << "...best bound is " << best << " : "; + if( best_bound_value[0]!=zero ){ + Trace("cbqi-bound") << "( " << best_bound_value[0] << " * INF ) + "; + } + Trace("cbqi-bound") << best_bound_value[1]; + if( best_bound_value[2]!=zero ){ + Trace("cbqi-bound") << " + ( " << best_bound_value[2] << " * DELTA )"; + } + Trace("cbqi-bound") << std::endl; + best_used[rr] = best; + //if using cbqiMidpoint, only add the instance based on one bound if the bound is non-strict + if( !options::cbqiMidpoint() || d_type.isInteger() || d_mbp_vts_coeff[rr][1][best].isNull() ){ + Node val = d_mbp_bounds[rr][best]; + val = getModelBasedProjectionValue( ci, pv, val, rr==0, d_mbp_coeff[rr][best], pv_value, t_values[rr][best], sf.d_theta, + d_mbp_vts_coeff[rr][0][best], d_mbp_vts_coeff[rr][1][best] ); + if( !val.isNull() ){ + if( ci->doAddInstantiationInc( pv, val, d_mbp_coeff[rr][best], rr==0 ? 1 : -1, sf, effort ) ){ + return true; + } + } + } + } + } + } + //if not using infinity, use model value of zero + if( !use_inf && d_mbp_bounds[0].empty() && d_mbp_bounds[1].empty() ){ + Node val = zero; + Node c; //null (one) coefficient + val = getModelBasedProjectionValue( ci, pv, val, true, c, pv_value, zero, sf.d_theta, Node::null(), Node::null() ); + if( !val.isNull() ){ + if( ci->doAddInstantiationInc( pv, val, c, 0, sf, effort ) ){ + return true; + } + } + } + if( options::cbqiMidpoint() && !d_type.isInteger() ){ + Node vals[2]; + bool bothBounds = true; + Trace("cbqi-bound") << "Try midpoint of bounds..." << std::endl; + for( unsigned rr=0; rr<2; rr++ ){ + int best = best_used[rr]; + if( best==-1 ){ + bothBounds = false; + }else{ + vals[rr] = d_mbp_bounds[rr][best]; + vals[rr] = getModelBasedProjectionValue( ci, pv, vals[rr], rr==0, Node::null(), pv_value, t_values[rr][best], sf.d_theta, + d_mbp_vts_coeff[rr][0][best], Node::null() ); + } + Trace("cbqi-bound") << "Bound : " << vals[rr] << std::endl; + } + Node val; + if( bothBounds ){ + Assert( !vals[0].isNull() && !vals[1].isNull() ); + if( vals[0]==vals[1] ){ + val = vals[0]; + }else{ + val = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkNode( PLUS, vals[0], vals[1] ), + NodeManager::currentNM()->mkConst( Rational(1)/Rational(2) ) ); + val = Rewriter::rewrite( val ); + } + }else{ + if( !vals[0].isNull() ){ + val = NodeManager::currentNM()->mkNode( PLUS, vals[0], one ); + val = Rewriter::rewrite( val ); + }else if( !vals[1].isNull() ){ + val = NodeManager::currentNM()->mkNode( MINUS, vals[1], one ); + val = Rewriter::rewrite( val ); + } + } + Trace("cbqi-bound") << "Midpoint value : " << val << std::endl; + if( !val.isNull() ){ + if( ci->doAddInstantiationInc( pv, val, Node::null(), 0, sf, effort ) ){ + return true; + } + } + } + //generally should not make it to this point FIXME: write proper assertion + //Assert( ( ci->hasNestedQuantification() && !options::cbqiNestedQE() ) || options::cbqiAll() ); + + if( options::cbqiNopt() ){ + //try non-optimal bounds (heuristic, may help when nested quantification) ? + Trace("cbqi-bound") << "Try non-optimal bounds..." << std::endl; + for( unsigned r=0; r<2; r++ ){ + int rr = upper_first ? (1-r) : r; + for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){ + if( (int)j!=best_used[rr] && ( !options::cbqiMidpoint() || d_mbp_vts_coeff[rr][1][j].isNull() ) ){ + Node val = getModelBasedProjectionValue( ci, pv, d_mbp_bounds[rr][j], rr==0, d_mbp_coeff[rr][j], pv_value, t_values[rr][j], sf.d_theta, + d_mbp_vts_coeff[rr][0][j], d_mbp_vts_coeff[rr][1][j] ); + if( !val.isNull() ){ + if( ci->doAddInstantiationInc( pv, val, d_mbp_coeff[rr][j], rr==0 ? 1 : -1, sf, effort ) ){ + return true; + } + } + } + } + } + } + } + return false; +} + +bool ArithInstantiator::needsPostProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { + return std::find( sf.d_has_coeff.begin(), sf.d_has_coeff.end(), pv )!=sf.d_has_coeff.end(); +} + +bool ArithInstantiator::postProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { + Assert( std::find( sf.d_has_coeff.begin(), sf.d_has_coeff.end(), pv )!=sf.d_has_coeff.end() ); + Assert( std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )!=sf.d_vars.end() ); + unsigned index = std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )-sf.d_vars.begin(); + Assert( !sf.d_coeff[index].isNull() ); + Trace("cbqi-inst-debug") << "Normalize substitution for " << sf.d_coeff[index] << " * " << sf.d_vars[index] << " = " << sf.d_subs[index] << std::endl; + Assert( sf.d_vars[index].getType().isInteger() ); + //must ensure that divisibility constraints are met + //solve updated rewritten equality for vars[index], if coefficient is one, then we are successful + Node eq_lhs = NodeManager::currentNM()->mkNode( MULT, sf.d_coeff[index], sf.d_vars[index] ); + Node eq_rhs = sf.d_subs[index]; + Node eq = eq_lhs.eqNode( eq_rhs ); + eq = Rewriter::rewrite( eq ); + Trace("cbqi-inst-debug") << "...equality is " << eq << std::endl; + std::map< Node, Node > msum; + if( QuantArith::getMonomialSumLit( eq, msum ) ){ + Node veq; + if( QuantArith::isolate( sf.d_vars[index], msum, veq, EQUAL, true )!=0 ){ + Node veq_c; + if( veq[0]!=sf.d_vars[index] ){ + Node veq_v; + if( QuantArith::getMonomial( veq[0], veq_c, veq_v ) ){ + Assert( veq_v==sf.d_vars[index] ); + } + } + sf.d_subs[index] = veq[1]; + if( !veq_c.isNull() ){ + sf.d_subs[index] = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, veq[1], veq_c ); + Trace("cbqi-inst-debug") << "...bound type is : " << sf.d_btyp[index] << std::endl; + //intger division rounding up if from a lower bound + if( sf.d_btyp[index]==1 && options::cbqiRoundUpLowerLia() ){ + sf.d_subs[index] = NodeManager::currentNM()->mkNode( PLUS, sf.d_subs[index], + NodeManager::currentNM()->mkNode( ITE, + NodeManager::currentNM()->mkNode( EQUAL, + NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, veq[1], veq_c ), + ci->getQuantifiersEngine()->getTermDatabase()->d_zero ), + ci->getQuantifiersEngine()->getTermDatabase()->d_zero, ci->getQuantifiersEngine()->getTermDatabase()->d_one ) + ); + } + } + Trace("cbqi-inst-debug") << "...normalize integers : " << sf.d_vars[index] << " -> " << sf.d_subs[index] << std::endl; + }else{ + Trace("cbqi-inst-debug") << "...failed to isolate." << std::endl; + return false; + } + }else{ + Trace("cbqi-inst-debug") << "...failed to get monomial sum." << std::endl; + return false; + } + return true; +} + +void DtInstantiator::reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { + +} + +Node DtInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) { + Trace("cbqi-inst-debug2") << "Solve dt : " << v << " " << a << " " << b << " " << sa << " " << sb << std::endl; + Node ret; + if( !a.isNull() && a==v ){ + ret = sb; + }else if( !b.isNull() && b==v ){ + ret = sa; + }else if( !a.isNull() && a.getKind()==APPLY_CONSTRUCTOR ){ + if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ + if( a.getOperator()==b.getOperator() ){ + for( unsigned i=0; i<a.getNumChildren(); i++ ){ + Node s = solve_dt( v, a[i], b[i], sa[i], sb[i] ); + if( !s.isNull() ){ + return s; + } + } + } + }else{ + unsigned cindex = Datatype::indexOf( a.getOperator().toExpr() ); + TypeNode tn = a.getType(); + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + for( unsigned i=0; i<a.getNumChildren(); i++ ){ + Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][i].getSelector() ), sb ); + Node s = solve_dt( v, a[i], Node::null(), sa[i], nn ); + if( !s.isNull() ){ + return s; + } + } + } + }else if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ + return solve_dt( v, b, a, sb, sa ); + } + if( !ret.isNull() ){ + //ensure does not contain + if( TermDb::containsTerm( ret, v ) ){ + ret = Node::null(); + } + } + return ret; +} + +bool DtInstantiator::processEqualTerms( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& eqc, unsigned effort ) { + Trace("cbqi-inst-debug") << "[2] try based on constructors in equivalence class." << std::endl; + //[2] look in equivalence class for a constructor + for( unsigned k=0; k<eqc.size(); k++ ){ + Node n = eqc[k]; + if( n.getKind()==APPLY_CONSTRUCTOR ){ + Trace("cbqi-inst-debug") << "...try based on constructor term " << n << std::endl; + std::vector< Node > children; + children.push_back( n.getOperator() ); + const Datatype& dt = ((DatatypeType)(d_type).toType()).getDatatype(); + unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() ); + //now must solve for selectors applied to pv + for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ + Node c = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][j].getSelector() ), pv ); + ci->pushStackVariable( c ); + children.push_back( c ); + } + Node val = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children ); + if( ci->doAddInstantiationInc( pv, val, Node::null(), 0, sf, effort ) ){ + return true; + }else{ + //cleanup + for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ + ci->popStackVariable(); + } + break; + } + } + } + return false; +} + +bool DtInstantiator::processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ) { + Node val = solve_dt( pv, terms[0], terms[1], terms[0], terms[1] ); + if( !val.isNull() ){ + Node veq_c; + if( ci->doAddInstantiationInc( pv, val, veq_c, 0, sf, effort ) ){ + return true; + } + } + return false; +} + +void EprInstantiator::reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { + d_equal_terms.clear(); +} + +bool EprInstantiator::processEqualTerm( CegInstantiator * ci, SolvedForm& sf, Node pv, Node pv_coeff, Node n, unsigned effort ) { + if( options::quantEprMatching() ){ + Assert( pv_coeff.isNull() ); + d_equal_terms.push_back( n ); + return false; + }else{ + return ci->doAddInstantiationInc( pv, n, pv_coeff, 0, sf, effort ); + } +} + +void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, std::vector< Node >& arg_reps, TermArgTrie * tat, unsigned index, std::map< Node, int >& match_score ) { + if( index==catom.getNumChildren() ){ + Assert( tat->hasNodeData() ); + Node gcatom = tat->getNodeData(); + Trace("epr-inst") << "Matched : " << catom << " and " << gcatom << std::endl; + for( unsigned i=0; i<catom.getNumChildren(); i++ ){ + if( catom[i]==pv ){ + Trace("epr-inst") << "...increment " << gcatom[i] << std::endl; + match_score[gcatom[i]]++; + }else{ + //recursive matching + computeMatchScore( ci, pv, catom[i], gcatom[i], match_score ); + } + } + }else{ + std::map< TNode, TermArgTrie >::iterator it = tat->d_data.find( arg_reps[index] ); + if( it!=tat->d_data.end() ){ + computeMatchScore( ci, pv, catom, arg_reps, &it->second, index+1, match_score ); + } + } +} + +void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, Node eqc, std::map< Node, int >& match_score ) { + if( inst::Trigger::isAtomicTrigger( catom ) && TermDb::containsTerm( catom, pv ) ){ + Trace("epr-inst") << "Find matches for " << catom << "..." << std::endl; + std::vector< Node > arg_reps; + for( unsigned j=0; j<catom.getNumChildren(); j++ ){ + arg_reps.push_back( ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( catom[j] ) ); + } + if( ci->getQuantifiersEngine()->getMasterEqualityEngine()->hasTerm( eqc ) ){ + Node rep = ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( eqc ); + Node op = ci->getQuantifiersEngine()->getTermDatabase()->getMatchOperator( catom ); + TermArgTrie * tat = ci->getQuantifiersEngine()->getTermDatabase()->getTermArgTrie( rep, op ); + Trace("epr-inst") << "EPR instantiation match term : " << catom << ", check ground terms=" << (tat!=NULL) << std::endl; + if( tat ){ + computeMatchScore( ci, pv, catom, arg_reps, tat, 0, match_score ); + } + } + } +} + +struct sortEqTermsMatch { + std::map< Node, int > d_match_score; + bool operator() (Node i, Node j) { + int match_score_i = d_match_score[i]; + int match_score_j = d_match_score[j]; + return match_score_i>match_score_j || ( match_score_i==match_score_j && i<j ); + } +}; + + +bool EprInstantiator::processEqualTerms( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& eqc, unsigned effort ) { + if( options::quantEprMatching() ){ + //heuristic for best matching constant + sortEqTermsMatch setm; + for( unsigned i=0; i<ci->getNumCEAtoms(); i++ ){ + Node catom = ci->getCEAtom( i ); + computeMatchScore( ci, pv, catom, catom, setm.d_match_score ); + } + //sort by match score + std::sort( d_equal_terms.begin(), d_equal_terms.end(), setm ); + Node pv_coeff; + for( unsigned i=0; i<d_equal_terms.size(); i++ ){ + if( ci->doAddInstantiationInc( pv, d_equal_terms[i], pv_coeff, 0, sf, effort ) ){ + return true; + } + } + } + return false; +} + +bool BvInstantiator::processAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, Node lit, unsigned effort ) { + /* TODO: algebraic reasoning for bitvector instantiation + if( atom.getKind()==BITVECTOR_ULT || atom.getKind()==BITVECTOR_ULE ){ + for( unsigned t=0; t<2; t++ ){ + if( atom[t]==pv ){ + computeProgVars( atom[1-t] ); + if( d_inelig.find( atom[1-t] )==d_inelig.end() ){ + //only ground terms TODO: more + if( d_prog_var[atom[1-t]].empty() ){ + Node veq_c; + Node uval; + if( ( !pol && atom.getKind()==BITVECTOR_ULT ) || ( pol && atom.getKind()==BITVECTOR_ULE ) ){ + uval = atom[1-t]; + }else{ + uval = NodeManager::currentNM()->mkNode( (atom.getKind()==BITVECTOR_ULT)==(t==1) ? BITVECTOR_PLUS : BITVECTOR_SUB, atom[1-t], + bv::utils::mkConst(pvtn.getConst<BitVectorSize>(), 1) ); + } + if( doAddInstantiationInc( pv, uval, veq_c, 0, sf, effort ) ){ + return true; + } + } + } + } + } + } + */ + + return false; +} + + diff --git a/src/theory/quantifiers/ceg_t_instantiator.h b/src/theory/quantifiers/ceg_t_instantiator.h new file mode 100644 index 000000000..2df7946d5 --- /dev/null +++ b/src/theory/quantifiers/ceg_t_instantiator.h @@ -0,0 +1,93 @@ +/********************* */ +/*! \file ceg_t_instantiator.h + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief theory-specific counterexample-guided quantifier instantiation + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__CEG_T_INSTANTIATOR_H +#define __CVC4__CEG_T_INSTANTIATOR_H + +#include "theory/quantifiers/ceg_instantiator.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class ArithInstantiator : public Instantiator { +private: + Node d_vts_sym[2]; + std::vector< Node > d_mbp_bounds[2]; + std::vector< Node > d_mbp_coeff[2]; + std::vector< Node > d_mbp_vts_coeff[2][2]; + std::vector< Node > d_mbp_lit[2]; + int solve_arith( CegInstantiator * ci, Node v, Node atom, Node & veq_c, Node & val, Node& vts_coeff_inf, Node& vts_coeff_delta ); + Node getModelBasedProjectionValue( CegInstantiator * ci, Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ); +public: + ArithInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){} + virtual ~ArithInstantiator(){} + void reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ); + bool hasProcessEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + bool processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ); + bool hasProcessAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + bool processAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, Node lit, unsigned effort ); + bool processAssertions( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& lits, unsigned effort ); + bool needsPostProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ); + bool postProcessInstantiation( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ); + std::string identify() const { return "Arith"; } +}; + +class DtInstantiator : public Instantiator { +private: + Node solve_dt( Node v, Node a, Node b, Node sa, Node sb ); +public: + DtInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){} + virtual ~DtInstantiator(){} + void reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ); + bool processEqualTerms( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& eqc, unsigned effort ); + bool hasProcessEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + bool processEquality( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& term_coeffs, std::vector< Node >& terms, unsigned effort ); + std::string identify() const { return "Dt"; } +}; + +class TermArgTrie; + +class EprInstantiator : public Instantiator { +private: + std::vector< Node > d_equal_terms; + void computeMatchScore( CegInstantiator * ci, Node pv, Node catom, std::vector< Node >& arg_reps, TermArgTrie * tat, unsigned index, std::map< Node, int >& match_score ); + void computeMatchScore( CegInstantiator * ci, Node pv, Node catom, Node eqc, std::map< Node, int >& match_score ); +public: + EprInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){} + virtual ~EprInstantiator(){} + void reset( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ); + bool processEqualTerm( CegInstantiator * ci, SolvedForm& sf, Node pv, Node pv_coeff, Node n, unsigned effort ); + bool processEqualTerms( CegInstantiator * ci, SolvedForm& sf, Node pv, std::vector< Node >& eqc, unsigned effort ); + std::string identify() const { return "Epr"; } +}; + +class BvInstantiator : public Instantiator { +public: + BvInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){} + virtual ~BvInstantiator(){} + bool processAssertion( CegInstantiator * ci, SolvedForm& sf, Node pv, Node lit, unsigned effort ); + bool useModelValue( CegInstantiator * ci, SolvedForm& sf, Node pv, unsigned effort ) { return true; } + std::string identify() const { return "Bv"; } +}; + + +} +} +} + +#endif diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp index f4eb67d74..11adc61fd 100755 --- a/src/theory/quantifiers/conjecture_generator.cpp +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -84,6 +84,9 @@ d_notify( *this ), d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee", false), d_ee_conjectures( c ){ d_fullEffortCount = 0; + d_conj_count = 0; + d_subs_confirmCount = 0; + d_subs_unkCount = 0; d_uequalityEngine.addFunctionKind( kind::APPLY_UF ); d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR ); diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp index be608aeaa..72057e734 100755 --- a/src/theory/quantifiers/full_model_check.cpp +++ b/src/theory/quantifiers/full_model_check.cpp @@ -589,7 +589,7 @@ void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) { } -bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { +int FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl; Assert( !d_qe->inConflict() ); if( optUseModel() ){ @@ -723,15 +723,15 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, if( temp.addEntry(fmfmc, d_quant_models[f].d_cond[j], d_quant_models[f].d_value[j] ) ){ if( !exhaustiveInstantiate(fmfmc, f, d_quant_models[f].d_cond[j], j ) ){ //something went wrong, resort to exhaustive instantiation - return false; + return 0; } } } } } - return true; + return 1; }else{ - return false; + return 0; } } diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h index 411b7a5eb..7d21b4185 100755 --- a/src/theory/quantifiers/full_model_check.h +++ b/src/theory/quantifiers/full_model_check.h @@ -139,7 +139,7 @@ public: void debugPrintCond(const char * tr, Node n, bool dispStar = false); void debugPrint(const char * tr, Node n, bool dispStar = false); - bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ); + int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ); Node getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ); diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index 7e5424d9c..12e15d353 100755 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp @@ -258,7 +258,11 @@ void InstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std:: } } }else{ - insts.push_back( qe->getInstantiation( q, terms, true ) ); + if( hasInstLemma() ){ + insts.push_back( getInstLemma() ); + }else{ + insts.push_back( qe->getInstantiation( q, terms, true ) ); + } } }else{ for( std::map< Node, InstMatchTrie >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){ @@ -428,13 +432,17 @@ void CDInstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std if( terms.size()==q[0].getNumChildren() ){ if( useActive ){ if( hasInstLemma() ){ - Node lem; + Node lem = getInstLemma(); if( std::find( active.begin(), active.end(), lem )!=active.end() ){ insts.push_back( lem ); } } }else{ - insts.push_back( qe->getInstantiation( q, terms, true ) ); + if( hasInstLemma() ){ + insts.push_back( getInstLemma() ); + }else{ + insts.push_back( qe->getInstantiation( q, terms, true ) ); + } } }else{ for( std::map< Node, CDInstMatchTrie* >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){ diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index b3df9ca5d..2a940f1fd 100755 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -388,23 +388,6 @@ int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, Quantif return addedLemmas; } -int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - if( !d_match_pattern.isNull() ){ - InstMatch m( f ); - if( getMatch( f, t, m, qe ) ){ - if( qe->addInstantiation( f, m ) ){ - return 1; - } - } - }else{ - for( unsigned i=0; i<d_children.size(); i++ ){ - d_children[i]->addTerm( f, t, qe ); - } - } - return 0; -} - InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node q, Node pat, QuantifiersEngine* qe ) { std::vector< Node > pats; @@ -716,22 +699,6 @@ void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, } } -int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - int addedLemmas = 0; - for( int i=0; i<(int)d_children.size(); i++ ){ - Node t_op = qe->getTermDatabase()->getMatchOperator( t ); - if( ((InstMatchGenerator*)d_children[i])->d_match_pattern_op==t_op ){ - InstMatch m( q ); - //if it produces a match, then process it with the rest - if( ((InstMatchGenerator*)d_children[i])->getMatch( q, t, m, qe ) ){ - processNewMatch( qe, m, i, addedLemmas ); - } - } - } - return addedLemmas; -} - InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe ) : d_f( q ), d_match_pattern( pat ) { if( d_match_pattern.getKind()==NOT ){ d_match_pattern = d_match_pattern[0]; @@ -774,17 +741,19 @@ int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, Q Node r = qe->getEqualityQuery()->getRepresentative( d_eqc ); //iterate over all classes except r tat = qe->getTermDatabase()->getTermArgTrie( Node::null(), d_op ); - for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ - if( it->first!=r ){ - InstMatch m( q ); - m.add( baseMatch ); - addInstantiations( m, qe, addedLemmas, 0, &(it->second) ); - if( qe->inConflict() ){ - break; + if( tat ){ + for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + if( it->first!=r ){ + InstMatch m( q ); + m.add( baseMatch ); + addInstantiations( m, qe, addedLemmas, 0, &(it->second) ); + if( qe->inConflict() ){ + break; + } } } + tat = NULL; } - tat = NULL; } } Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl; @@ -841,20 +810,6 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin } } -int InstMatchGeneratorSimple::addTerm( Node q, Node t, QuantifiersEngine* qe ){ - //for eager instantiation only - Assert( options::eagerInstQuant() ); - InstMatch m( q ); - for( unsigned i=0; i<t.getNumChildren(); i++ ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - m.setValue(d_var_num[i], t[i]); - }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ - return 0; - } - } - return qe->addInstantiation( q, m ) ? 1 : 0; -} - int InstMatchGeneratorSimple::getActiveScore( QuantifiersEngine * qe ) { Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern ); unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f ); diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index 65c5a1427..c238e3c4e 100755 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -42,8 +42,6 @@ public: virtual bool getNextMatch( Node q, InstMatch& m, QuantifiersEngine* qe ) = 0; /** add instantiations directly */ virtual int addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; - /** add ground term t, called when t is added to term db */ - virtual int addTerm( Node q, Node t, QuantifiersEngine* qe ) { return 0; } /** set active add */ virtual void setActiveAdd( bool val ) {} /** get active score */ @@ -113,8 +111,6 @@ public: bool getNextMatch( Node q, InstMatch& m, QuantifiersEngine* qe ); /** add instantiations */ int addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node q, Node t, QuantifiersEngine* qe ); bool d_active_add; void setActiveAdd( bool val ); @@ -205,8 +201,6 @@ public: bool getNextMatch( Node q, InstMatch& m, QuantifiersEngine* qe ) { return false; } /** add instantiations */ int addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node q, Node t, QuantifiersEngine* qe ); };/* class InstMatchGeneratorMulti */ /** smart (single)-trigger implementation */ @@ -240,8 +234,6 @@ public: bool getNextMatch( Node q, InstMatch& m, QuantifiersEngine* qe ) { return false; } /** add instantiations */ int addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t, possibly add instantiations */ - int addTerm( Node q, Node t, QuantifiersEngine* qe ); /** get active score */ int getActiveScore( QuantifiersEngine * qe ); };/* class InstMatchGeneratorSimple */ diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp index 41c9c40c8..1f68fb787 100755 --- a/src/theory/quantifiers/inst_propagator.cpp +++ b/src/theory/quantifiers/inst_propagator.cpp @@ -597,6 +597,8 @@ void InstPropagator::InstInfo::init( Node q, Node lem, std::vector< Node >& term InstPropagator::InstPropagator( QuantifiersEngine* qe ) : d_qe( qe ), d_notify(*this), d_qy( qe ){ + d_icount = 1; + d_conflict = false; } bool InstPropagator::reset( Theory::Effort e ) { diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp index 523d868b5..ac6e1edbe 100755 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -21,6 +21,7 @@ #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/trigger.h" +#include "theory/quantifiers/quantifiers_rewriter.h" #include "theory/theory_engine.h" using namespace std; @@ -34,9 +35,13 @@ using namespace CVC4::theory::arith; #define ARITH_INSTANTIATOR_USE_MINUS_DELTA InstStrategyCbqi::InstStrategyCbqi( QuantifiersEngine * qe ) - : QuantifiersModule( qe ), d_added_cbqi_lemma( qe->getUserContext() ) + : QuantifiersModule( qe ), d_added_cbqi_lemma( qe->getUserContext() ), +d_elim_quants( qe->getSatContext() ), +d_nested_qe_waitlist_size( qe->getUserContext() ), +d_nested_qe_waitlist_proc( qe->getUserContext() ) //, d_added_inst( qe->getUserContext() ) { + d_qid_count = 0; } InstStrategyCbqi::~InstStrategyCbqi() throw(){} @@ -55,34 +60,117 @@ unsigned InstStrategyCbqi::needsModel( Theory::Effort e ) { return QuantifiersEngine::QEFFORT_NONE; } +bool InstStrategyCbqi::registerCbqiLemma( Node q ) { + if( !hasAddedCbqiLemma( q ) ){ + d_added_cbqi_lemma.insert( q ); + Trace("cbqi-debug") << "Do cbqi for " << q << std::endl; + //add cbqi lemma + //get the counterexample literal + Node ceLit = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); + Node ceBody = d_quantEngine->getTermDatabase()->getInstConstantBody( q ); + if( !ceBody.isNull() ){ + //add counterexample lemma + Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() ); + //require any decision on cel to be phase=true + d_quantEngine->addRequirePhase( ceLit, true ); + Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; + //add counterexample lemma + lem = Rewriter::rewrite( lem ); + Trace("cbqi-lemma") << "Counterexample lemma : " << lem << std::endl; + registerCounterexampleLemma( q, lem ); + + //totality lemmas for EPR + QuantEPR * qepr = d_quantEngine->getQuantEPR(); + if( qepr!=NULL ){ + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + TypeNode tn = q[0][i].getType(); + if( tn.isSort() ){ + if( qepr->isEPR( tn ) ){ + //add totality lemma + std::map< TypeNode, std::vector< Node > >::iterator itc = qepr->d_consts.find( tn ); + if( itc!=qepr->d_consts.end() ){ + Assert( !itc->second.empty() ); + Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( q, i ); + std::vector< Node > disj; + for( unsigned j=0; j<itc->second.size(); j++ ){ + disj.push_back( ic.eqNode( itc->second[j] ) ); + } + Node tlem = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj ); + Trace("cbqi-lemma") << "EPR totality lemma : " << tlem << std::endl; + d_quantEngine->getOutputChannel().lemma( tlem ); + }else{ + Assert( false ); + } + }else{ + Assert( !options::cbqiAll() ); + } + } + } + } + + //compute dependencies between quantified formulas + if( options::cbqiLitDepend() || options::cbqiInnermost() ){ + std::vector< Node > ics; + TermDb::computeVarContains( q, ics ); + d_parent_quant[q].clear(); + d_children_quant[q].clear(); + std::vector< Node > dep; + for( unsigned i=0; i<ics.size(); i++ ){ + Node qi = ics[i].getAttribute(InstConstantAttribute()); + if( std::find( d_parent_quant[q].begin(), d_parent_quant[q].end(), qi )==d_parent_quant[q].end() ){ + d_parent_quant[q].push_back( qi ); + d_children_quant[qi].push_back( q ); + Node qicel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( qi ); + dep.push_back( qi ); + dep.push_back( qicel ); + } + } + if( !dep.empty() ){ + Node dep_lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, ceLit, NodeManager::currentNM()->mkNode( kind::AND, dep ) ); + Trace("cbqi-lemma") << "Counterexample dependency lemma : " << dep_lemma << std::endl; + d_quantEngine->getOutputChannel().lemma( dep_lemma ); + } + } + + //must register all sub-quantifiers of counterexample lemma, register their lemmas + std::vector< Node > quants; + TermDb::computeQuantContains( lem, quants ); + for( unsigned i=0; i<quants.size(); i++ ){ + if( doCbqi( quants[i] ) ){ + registerCbqiLemma( quants[i] ); + } + if( options::cbqiNestedQE() ){ + //record these as counterexample quantifiers + QAttributes qa; + TermDb::computeQuantAttributes( quants[i], qa ); + if( !qa.d_qid_num.isNull() ){ + d_id_to_ce_quant[ qa.d_qid_num ] = quants[i]; + d_ce_quant_to_id[ quants[i] ] = qa.d_qid_num; + Trace("cbqi-nqe") << "CE quant id = " << qa.d_qid_num << " is " << quants[i] << std::endl; + } + } + } + } + return true; + }else{ + return false; + } +} + void InstStrategyCbqi::reset_round( Theory::Effort effort ) { d_cbqi_set_quant_inactive = false; d_incomplete_check = false; + d_active_quant.clear(); //check if any cbqi lemma has not been added yet for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine if( doCbqi( q ) ){ - if( !hasAddedCbqiLemma( q ) ){ - d_added_cbqi_lemma.insert( q ); - Trace("cbqi") << "Do cbqi for " << q << std::endl; - //add cbqi lemma - //get the counterexample literal - Node ceLit = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); - Node ceBody = d_quantEngine->getTermDatabase()->getInstConstantBody( q ); - if( !ceBody.isNull() ){ - //add counterexample lemma - Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() ); - //require any decision on cel to be phase=true - d_quantEngine->addRequirePhase( ceLit, true ); - Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; - //add counterexample lemma - lem = Rewriter::rewrite( lem ); - Trace("cbqi") << "Counterexample lemma : " << lem << std::endl; - registerCounterexampleLemma( q, lem ); - } + if( registerCbqiLemma( q ) ){ + Debug("cbqi-debug") << "Registered cbqi lemma." << std::endl; //set inactive the quantified formulas whose CE literals are asserted false }else if( d_quantEngine->getModel()->isQuantifierActive( q ) ){ + d_active_quant[q] = true; Debug("cbqi-debug") << "Check quantified formula " << q << "..." << std::endl; Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); bool value; @@ -92,8 +180,24 @@ void InstStrategyCbqi::reset_round( Theory::Effort effort ) { if( d_quantEngine->getValuation().isDecision( cel ) ){ Trace("cbqi-warn") << "CBQI WARNING: Bad decision on CE Literal." << std::endl; }else{ + Trace("cbqi") << "Inactive : " << q << std::endl; d_quantEngine->getModel()->setQuantifierActive( q, false ); d_cbqi_set_quant_inactive = true; + d_active_quant.erase( q ); + d_elim_quants.insert( q ); + Trace("cbqi-nqe") << "Inactive, waitlist proc/size = " << d_nested_qe_waitlist_proc[q].get() << "/" << d_nested_qe_waitlist_size[q].get() << std::endl; + //process from waitlist + while( d_nested_qe_waitlist_proc[q]<d_nested_qe_waitlist_size[q] ){ + int index = d_nested_qe_waitlist_proc[q]; + Assert( index>=0 ); + Assert( index<(int)d_nested_qe_waitlist[q].size() ); + Node nq = d_nested_qe_waitlist[q][index]; + Node nqeqn = doNestedQENode( d_nested_qe_info[nq].d_q, q, nq, d_nested_qe_info[nq].d_inst_terms, d_nested_qe_info[nq].d_doVts ); + Node dqelem = nq.iffNode( nqeqn ); + Trace("cbqi-lemma") << "Delayed nested quantifier elimination lemma : " << dqelem << std::endl; + d_quantEngine->getOutputChannel().lemma( dqelem ); + d_nested_qe_waitlist_proc[q] = index + 1; + } } } }else{ @@ -102,6 +206,34 @@ void InstStrategyCbqi::reset_round( Theory::Effort effort ) { } } } + + //refinement: only consider innermost active quantified formulas + if( options::cbqiInnermost() ){ + if( !d_children_quant.empty() && !d_active_quant.empty() ){ + Trace("cbqi-debug") << "Find non-innermost quantifiers..." << std::endl; + std::vector< Node > ninner; + for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){ + std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( it->first ); + if( itc!=d_children_quant.end() ){ + for( unsigned j=0; j<itc->second.size(); j++ ){ + if( d_active_quant.find( itc->second[j] )!=d_active_quant.end() ){ + Trace("cbqi-debug") << "Do not consider " << it->first << " since it is not innermost (" << itc->second[j] << std::endl; + ninner.push_back( it->first ); + break; + } + } + } + } + Trace("cbqi-debug") << "Found " << ninner.size() << " non-innermost." << std::endl; + for( unsigned i=0; i<ninner.size(); i++ ){ + Assert( d_active_quant.find( ninner[i] )!=d_active_quant.end() ); + d_active_quant.erase( ninner[i] ); + } + Assert( !d_active_quant.empty() ); + Trace("cbqi-debug") << "...done removing." << std::endl; + } + } + processResetInstantiationRound( effort ); } @@ -115,13 +247,20 @@ void InstStrategyCbqi::check( Theory::Effort e, unsigned quant_e ) { } unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting(); for( int ee=0; ee<=1; ee++ ){ - for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); - if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ + //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + // Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); + // if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ + for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){ + Node q = it->first; + Trace("cbqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl; + if( d_nested_qe.find( q )==d_nested_qe.end() ){ process( q, e, ee ); if( d_quantEngine->inConflict() ){ break; } + }else{ + Trace("cbqi-warn") << "CBQI : Cannot process already eliminated quantified formula " << q << std::endl; + Assert( false ); } } if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){ @@ -146,11 +285,88 @@ bool InstStrategyCbqi::checkComplete() { } } +bool InstStrategyCbqi::checkCompleteFor( Node q ) { + std::map< Node, int >::iterator it = d_do_cbqi.find( q ); + if( it!=d_do_cbqi.end() ){ + return it->second>0; + }else{ + return false; + } +} + +Node InstStrategyCbqi::getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited ){ + std::map< Node, Node >::iterator it = visited.find( n ); + if( it==visited.end() ){ + Node ret = n; + if( n.getKind()==FORALL ){ + QAttributes qa; + TermDb::computeQuantAttributes( n, qa ); + if( qa.d_qid_num.isNull() ){ + std::vector< Node > rc; + rc.push_back( n[0] ); + rc.push_back( getIdMarkedQuantNode( n[1], visited ) ); + Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() ); + QuantIdNumAttribute ida; + avar.setAttribute(ida,d_qid_count); + d_qid_count++; + std::vector< Node > iplc; + iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) ); + if( n.getNumChildren()==3 ){ + for( unsigned i=0; i<n[2].getNumChildren(); i++ ){ + iplc.push_back( n[2][i] ); + } + } + rc.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) ); + ret = NodeManager::currentNM()->mkNode( FORALL, rc ); + } + }else if( n.getNumChildren()>0 ){ + std::vector< Node > children; + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.push_back( n.getOperator() ); + } + bool childChanged = false; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Node nc = getIdMarkedQuantNode( n[i], visited ); + childChanged = childChanged || nc!=n[i]; + children.push_back( nc ); + } + if( childChanged ){ + ret = NodeManager::currentNM()->mkNode( n.getKind(), children ); + } + } + visited[n] = ret; + return ret; + }else{ + return it->second; + } +} + void InstStrategyCbqi::preRegisterQuantifier( Node q ) { if( d_quantEngine->getOwner( q )==NULL && doCbqi( q ) ){ - if( !options::cbqiAll() && !options::cbqiSplx() ){ + if( d_do_cbqi[q]==2 ){ //take full ownership of the quantified formula d_quantEngine->setOwner( q, this ); + + //mark all nested quantifiers with id + if( options::cbqiNestedQE() ){ + std::map< Node, Node > visited; + Node mq = getIdMarkedQuantNode( q[1], visited ); + if( mq!=q[1] ){ + //do not do cbqi + d_do_cbqi[q] = false; + //instead do reduction + std::vector< Node > qqc; + qqc.push_back( q[0] ); + qqc.push_back( mq ); + if( q.getNumChildren()==3 ){ + qqc.push_back( q[2] ); + } + Node qq = NodeManager::currentNM()->mkNode( FORALL, qqc ); + Node mlem = NodeManager::currentNM()->mkNode( IMPLIES, q, qq ); + Trace("cbqi-lemma") << "Mark quant id lemma : " << mlem << std::endl; + d_quantEngine->getOutputChannel().lemma( mlem ); + } + } } } } @@ -159,6 +375,98 @@ void InstStrategyCbqi::registerQuantifier( Node q ) { } +Node InstStrategyCbqi::doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts ) { + // there is a nested quantified formula (forall y. nq[y,x]) such that + // q is (forall y. nq[y,t]) for ground terms t, + // ceq is (forall y. nq[y,e]) for CE variables e. + // we call this function when we know (forall y. nq[y,e]) is equivalent to quantifier-free formula C[e]. + // in this case, q is equivalent to the quantifier-free formula C[t]. + if( d_nested_qe.find( ceq )==d_nested_qe.end() ){ + d_nested_qe[ceq] = d_quantEngine->getInstantiatedConjunction( ceq ); + Trace("cbqi-nqe") << "CE quantifier elimination : " << std::endl; + Trace("cbqi-nqe") << " " << ceq << std::endl; + Trace("cbqi-nqe") << " " << d_nested_qe[ceq] << std::endl; + //should not contain quantifiers + Assert( !QuantifiersRewriter::containsQuantifiers( d_nested_qe[ceq] ) ); + } + Assert( d_quantEngine->getTermDatabase()->d_inst_constants[q].size()==inst_terms.size() ); + //replace inst constants with instantiation + Node ret = d_nested_qe[ceq].substitute( d_quantEngine->getTermDatabase()->d_inst_constants[q].begin(), + d_quantEngine->getTermDatabase()->d_inst_constants[q].end(), + inst_terms.begin(), inst_terms.end() ); + if( doVts ){ + //do virtual term substitution + ret = Rewriter::rewrite( ret ); + ret = d_quantEngine->getTermDatabase()->rewriteVtsSymbols( ret ); + } + Trace("cbqi-nqe") << "Nested quantifier elimination: " << std::endl; + Trace("cbqi-nqe") << " " << n << std::endl; + Trace("cbqi-nqe") << " " << ret << std::endl; + return ret; +} + +Node InstStrategyCbqi::doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts ) { + if( visited.find( n )==visited.end() ){ + Node ret = n; + if( n.getKind()==FORALL ){ + QAttributes qa; + TermDb::computeQuantAttributes( n, qa ); + if( !qa.d_qid_num.isNull() ){ + //if it has an id, check whether we have done quantifier elimination for this id + std::map< Node, Node >::iterator it = d_id_to_ce_quant.find( qa.d_qid_num ); + if( it!=d_id_to_ce_quant.end() ){ + Node ceq = it->second; + bool doNestedQe = d_elim_quants.contains( ceq ); + if( doNestedQe ){ + ret = doNestedQENode( q, ceq, n, inst_terms, doVts ); + }else{ + Trace("cbqi-nqe") << "Add to nested qe waitlist : " << std::endl; + Node nr = Rewriter::rewrite( n ); + Trace("cbqi-nqe") << " " << ceq << std::endl; + Trace("cbqi-nqe") << " " << nr << std::endl; + int wlsize = d_nested_qe_waitlist_size[ceq] + 1; + d_nested_qe_waitlist_size[ceq] = wlsize; + if( wlsize<(int)d_nested_qe_waitlist[ceq].size() ){ + d_nested_qe_waitlist[ceq][wlsize] = nr; + }else{ + d_nested_qe_waitlist[ceq].push_back( nr ); + } + d_nested_qe_info[nr].d_q = q; + d_nested_qe_info[nr].d_inst_terms.clear(); + d_nested_qe_info[nr].d_inst_terms.insert( d_nested_qe_info[nr].d_inst_terms.end(), inst_terms.begin(), inst_terms.end() ); + d_nested_qe_info[nr].d_doVts = doVts; + //TODO: ensure this holds by restricting prenex when cbqiNestedQe is true. + Assert( !options::cbqiInnermost() ); + } + } + } + }else if( n.getNumChildren()>0 ){ + std::vector< Node > children; + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.push_back( n.getOperator() ); + } + bool childChanged = false; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Node nc = doNestedQERec( q, n[i], visited, inst_terms, doVts ); + childChanged = childChanged || nc!=n[i]; + children.push_back( nc ); + } + if( childChanged ){ + ret = NodeManager::currentNM()->mkNode( n.getKind(), children ); + } + } + visited[n] = ret; + return ret; + }else{ + return n; + } +} + +Node InstStrategyCbqi::doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts ) { + std::map< Node, Node > visited; + return doNestedQERec( q, lem, visited, inst_terms, doVts ); +} + void InstStrategyCbqi::registerCounterexampleLemma( Node q, Node lem ){ Trace("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; d_quantEngine->addLemma( lem, false ); @@ -187,57 +495,91 @@ bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visit } return false; } -bool InstStrategyCbqi::hasNonCbqiVariable( Node q ){ +int InstStrategyCbqi::hasNonCbqiVariable( Node q ){ + int hmin = 1; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ TypeNode tn = q[0][i].getType(); - if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() && !tn.isBitVector() ){ - if( options::cbqiSplx() ){ - return true; - }else{ - //datatypes supported in new implementation - if( !tn.isDatatype() ){ - return true; - } + int handled = -1; + if( tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector() ){ + handled = 0; + }else if( tn.isDatatype() ){ + handled = 0; + }else if( tn.isSort() ){ + QuantEPR * qepr = d_quantEngine->getQuantEPR(); + if( qepr!=NULL ){ + handled = qepr->isEPR( tn ) ? 1 : -1; } } + if( handled==-1 ){ + return -1; + }else if( handled<hmin ){ + hmin = handled; + } } - return false; + return hmin; } bool InstStrategyCbqi::doCbqi( Node q ){ - std::map< Node, bool >::iterator it = d_do_cbqi.find( q ); + std::map< Node, int >::iterator it = d_do_cbqi.find( q ); if( it==d_do_cbqi.end() ){ - bool ret = false; - if( d_quantEngine->getTermDatabase()->isQAttrQuantElim( q ) ){ - ret = true; - }else{ + int ret = 2; + if( !d_quantEngine->getTermDatabase()->isQAttrQuantElim( q ) ){ //if has an instantiation pattern, don't do it if( q.getNumChildren()==3 && options::eMatching() && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){ - ret = false; - }else{ - if( options::cbqiAll() ){ - ret = true; - }else{ - //if quantifier has a non-arithmetic variable, then do not use cbqi - //if quantifier has an APPLY_UF term, then do not use cbqi - //Node cb = d_quantEngine->getTermDatabase()->getInstConstantBody( q ); + for( unsigned i=0; i<q[2].getNumChildren(); i++ ){ + if( q[2][i].getKind()==INST_PATTERN ){ + ret = 0; + } + } + } + if( ret!=0 ){ + //if quantifier has a non-handled variable, then do not use cbqi + //if quantifier has an APPLY_UF term, then do not use cbqi unless EPR + int ncbqiv = hasNonCbqiVariable( q ); + if( ncbqiv==0 || ncbqiv==1 ){ std::map< Node, bool > visited; - ret = !hasNonCbqiVariable( q ) && !hasNonCbqiOperator( q[1], visited ); + if( hasNonCbqiOperator( q[1], visited ) ){ + if( ncbqiv==1 ){ + //all variables are fully handled, this implies this will be handlable regardless of body (e.g. for EPR) + // so, try but not exclusively + ret = 1; + }else{ + //cannot be handled + ret = 0; + } + } + }else{ + // unhandled variable type + ret = 0; + } + if( ret==0 && options::cbqiAll() ){ + //try but not exclusively + ret = 1; } } } - Trace("cbqi") << "doCbqi " << q << " returned " << ret << std::endl; + Trace("cbqi-quant") << "doCbqi " << q << " returned " << ret << std::endl; d_do_cbqi[q] = ret; - return ret; + return ret!=0; }else{ - return it->second; + return it->second!=0; } } -Node InstStrategyCbqi::getNextDecisionRequest(){ - // all counterexample literals that are not asserted - for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); +Node InstStrategyCbqi::getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc ) { + if( proc.find( q )==proc.end() ){ + proc[q] = true; + //first check children + std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( q ); + if( itc!=d_children_quant.end() ){ + for( unsigned j=0; j<itc->second.size(); j++ ){ + Node d = getNextDecisionRequestProc( itc->second[j], proc ); + if( !d.isNull() ){ + return d; + } + } + } + //then check self if( hasAddedCbqiLemma( q ) ){ Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); bool value; @@ -245,328 +587,21 @@ Node InstStrategyCbqi::getNextDecisionRequest(){ Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl; return cel; } - } + } } - return Node::null(); + return Node::null(); } - - - -//old implementation - -InstStrategySimplex::InstStrategySimplex( TheoryArith* th, QuantifiersEngine* ie ) : InstStrategyCbqi( ie ), d_th( th ), d_counter( 0 ){ - d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) ); - d_zero = NodeManager::currentNM()->mkConst( Rational(0) ); -} - -void getInstantiationConstants( Node n, std::vector< Node >& ics ){ - if( n.getKind()==INST_CONSTANT ){ - if( std::find( ics.begin(), ics.end(), n )==ics.end() ){ - ics.push_back( n ); - } - }else{ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - getInstantiationConstants( n[i], ics ); - } - } -} - - -void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){ - Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl; - d_quantActive.clear(); - d_instRows.clear(); - d_tableaux_term.clear(); - d_tableaux.clear(); - d_ceTableaux.clear(); - //search for instantiation rows in simplex tableaux - ArithVariables& avnm = d_th->d_internal->d_partialModel; - ArithVariables::var_iterator vi, vend; - for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ - ArithVar x = *vi; - Node n = avnm.asNode(x); - - //collect instantiation constants - std::vector< Node > ics; - getInstantiationConstants( n, ics ); - for( unsigned i=0; i<ics.size(); i++ ){ - NodeBuilder<> t(kind::PLUS); - if( n.getKind()==PLUS ){ - for( int j=0; j<(int)n.getNumChildren(); j++ ){ - addTermToRow( ics[i], x, n[j], t ); - } - }else{ - addTermToRow( ics[i], x, n, t ); - } - d_instRows[ics[i]].push_back( x ); - //this theory has constraints from f - Node f = TermDb::getInstConstAttr(ics[i]); - Debug("quant-arith") << "Has constraints from " << f << std::endl; - //set that we should process it - d_quantActive[ f ] = true; - //set tableaux term - if( t.getNumChildren()==0 ){ - d_tableaux_term[ics[i]][x] = d_zero; - }else if( t.getNumChildren()==1 ){ - d_tableaux_term[ics[i]][x] = t.getChild( 0 ); - }else{ - d_tableaux_term[ics[i]][x] = t; - } - } - } - //print debug - if( Debug.isOn("quant-arith-debug") ){ - Debug("quant-arith-debug") << std::endl; - debugPrint( "quant-arith-debug" ); - } - d_counter++; -} - -void InstStrategySimplex::addTermToRow( Node i, ArithVar x, Node n, NodeBuilder<>& t ){ - if( n.getKind()==MULT ){ - if( TermDb::hasInstConstAttr(n[1]) && n[0].getKind()==CONST_RATIONAL ){ - if( n[1]==i ){ - d_ceTableaux[i][x][ n[1] ] = n[0]; - }else{ - d_tableaux_ce_term[i][x][ n[1] ] = n[0]; - } - }else{ - d_tableaux[i][x][ n[1] ] = n[0]; - t << n; - } - }else{ - if( TermDb::hasInstConstAttr(n) ){ - if( n==i ){ - d_ceTableaux[i][x][ n ] = Node::null(); - }else{ - d_tableaux_ce_term[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); - } - }else{ - d_tableaux[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); - t << n; - } - } -} - -void InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ - if( e==0 ){ - if( d_quantActive.find( f )!=d_quantActive.end() ){ - //the point instantiation - InstMatch m_point( f ); - bool m_point_valid = true; - int lem = 0; - //scan over all instantiation rows - for( unsigned i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ - Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); - Debug("quant-arith-simplex") << "InstStrategySimplex check " << ic << ", rows = " << d_instRows[ic].size() << std::endl; - for( unsigned j=0; j<d_instRows[ic].size(); j++ ){ - ArithVar x = d_instRows[ic][j]; - if( !d_ceTableaux[ic][x].empty() ){ - if( Debug.isOn("quant-arith-simplex") ){ - Debug("quant-arith-simplex") << "--- Check row " << ic << " " << x << std::endl; - Debug("quant-arith-simplex") << " "; - for( std::map< Node, Node >::iterator it = d_ceTableaux[ic][x].begin(); it != d_ceTableaux[ic][x].end(); ++it ){ - if( it!=d_ceTableaux[ic][x].begin() ){ Debug("quant-arith-simplex") << " + "; } - Debug("quant-arith-simplex") << it->first << " * " << it->second; - } - Debug("quant-arith-simplex") << " = "; - Node v = getTableauxValue( x, false ); - Debug("quant-arith-simplex") << v << std::endl; - Debug("quant-arith-simplex") << " term : " << d_tableaux_term[ic][x] << std::endl; - Debug("quant-arith-simplex") << " ce-term : "; - for( std::map< Node, Node >::iterator it = d_tableaux_ce_term[ic][x].begin(); it != d_tableaux_ce_term[ic][x].end(); it++ ){ - if( it!=d_tableaux_ce_term[ic][x].begin() ){ Debug("quant-arith-simplex") << " + "; } - Debug("quant-arith-simplex") << it->first << " * " << it->second; - } - Debug("quant-arith-simplex") << std::endl; - } - //instantiation row will be A*e + B*t = beta, - // where e is a vector of terms , and t is vector of ground terms. - // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant - // We will construct the term ( beta - B*t)/coeff to use for e_i. - InstMatch m( f ); - for( unsigned k=0; k<f[0].getNumChildren(); k++ ){ - if( f[0][k].getType().isInteger() ){ - m.setValue( k, d_zero ); - } - } - //By default, choose the first instantiation constant to be e_i. - Node var = d_ceTableaux[ic][x].begin()->first; - //if it is integer, we need to find variable with coefficent +/- 1 - if( var.getType().isInteger() ){ - std::map< Node, Node >::iterator it = d_ceTableaux[ic][x].begin(); - while( !var.isNull() && !d_ceTableaux[ic][x][var].isNull() && d_ceTableaux[ic][x][var]!=d_negOne ){ - ++it; - if( it==d_ceTableaux[ic][x].end() ){ - var = Node::null(); - }else{ - var = it->first; - } - } - //Otherwise, try one that divides all ground term coefficients? - // Might be futile, if rewrite ensures gcd of coeffs is 1. - } - if( !var.isNull() ){ - //add to point instantiation if applicable - if( d_tableaux_ce_term[ic][x].empty() && d_tableaux_term[ic][x]==d_zero ){ - Debug("quant-arith-simplex") << "*** Row contributes to point instantiation." << std::endl; - Node v = getTableauxValue( x, false ); - if( !var.getType().isInteger() || v.getType().isInteger() ){ - m_point.setValue( i, v ); - }else{ - m_point_valid = false; - } - } - Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl; - if( doInstantiation( f, ic, d_tableaux_term[ic][x], x, m, var ) ){ - lem++; - } - }else{ - Debug("quant-arith-simplex") << "Could not find var." << std::endl; - } - } - } - } - if( lem==0 && m_point_valid ){ - if( d_quantEngine->addInstantiation( f, m_point ) ){ - Debug("quant-arith-simplex") << "...added point instantiation." << std::endl; - } - } - } - } -} - - -void InstStrategySimplex::debugPrint( const char* c ){ - ArithVariables& avnm = d_th->d_internal->d_partialModel; - ArithVariables::var_iterator vi, vend; - for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ - ArithVar x = *vi; - Node n = avnm.asNode(x); - //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){ - Debug(c) << x << " : " << n << ", bounds = "; - if( d_th->d_internal->d_partialModel.hasLowerBound( x ) ){ - Debug(c) << d_th->d_internal->d_partialModel.getLowerBound( x ); - }else{ - Debug(c) << "-infty"; - } - Debug(c) << " <= "; - Debug(c) << d_th->d_internal->d_partialModel.getAssignment( x ); - Debug(c) << " <= "; - if( d_th->d_internal->d_partialModel.hasUpperBound( x ) ){ - Debug(c) << d_th->d_internal->d_partialModel.getUpperBound( x ); - }else{ - Debug(c) << "+infty"; - } - Debug(c) << std::endl; - //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl; - //Debug(c) << " "; - //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){ - // Debug(c) << "( " << it2->first << ", " << it2->second << " ) "; - //} - //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){ - // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) "; - //} - //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){ - // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) "; - //} - //Debug(c) << std::endl; - //} - } - Debug(c) << std::endl; - +Node InstStrategyCbqi::getNextDecisionRequest(){ + std::map< Node, bool > proc; for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); - Debug(c) << f << std::endl; - Debug(c) << " Inst constants: "; - for( unsigned j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ - if( j>0 ){ - Debug( c ) << ", "; - } - Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); - } - Debug(c) << std::endl; - for( unsigned j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ - Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); - Debug(c) << " Instantiation rows for " << ic << " : "; - for( unsigned k=0; k<d_instRows[ic].size(); k++ ){ - if( k>0 ){ - Debug(c) << ", "; - } - Debug(c) << d_instRows[ic][k]; - } - Debug(c) << std::endl; - } - } -} - -//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta, -// where var is an instantiation constant from f, -// t[e] is a vector of terms containing instantiation constants from f, -// and term is a ground term (c1*t1 + ... + cn*tn). -// We construct the term ( beta - term )/coeff to use as an instantiation for var. -bool InstStrategySimplex::doInstantiation( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var ){ - //first try +delta - if( doInstantiation2( f, ic, term, x, m, var ) ){ - ++(d_quantEngine->d_statistics.d_instantiations_cbqi_arith); - return true; - }else{ -#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA - //otherwise try -delta - if( doInstantiation2( f, ic, term, x, m, var, true ) ){ - ++(d_quantEngine->d_statistics.d_instantiations_cbqi_arith); - return true; - }else{ - return false; - } -#else - return false; -#endif - } -} - -bool InstStrategySimplex::doInstantiation2( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){ - // make term ( beta - term )/coeff - bool vIsInteger = var.getType().isInteger(); - Node beta = getTableauxValue( x, minus_delta ); - if( !vIsInteger || beta.getType().isInteger() ){ - Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term ); - if( !d_ceTableaux[ic][x][var].isNull() ){ - if( vIsInteger ){ - Assert( d_ceTableaux[ic][x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) ); - instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[ic][x][var], instVal ); - }else{ - Assert( d_ceTableaux[ic][x][var].getKind()==CONST_RATIONAL ); - Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[ic][x][var].getConst<Rational>() ); - instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal ); - } + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); + Node d = getNextDecisionRequestProc( q, proc ); + if( !d.isNull() ){ + return d; } - instVal = Rewriter::rewrite( instVal ); - //use as instantiation value for var - int vn = var.getAttribute(InstVarNumAttribute()); - m.setValue( vn, instVal ); - Debug("quant-arith") << "Add instantiation " << m << std::endl; - return d_quantEngine->addInstantiation( f, m ); - }else{ - return false; - } -} -/* -Node InstStrategySimplex::getTableauxValue( Node n, bool minus_delta ){ - if( d_th->d_internal->d_partialModel.hasArithVar(n) ){ - ArithVar v = d_th->d_internal->d_partialModel.asArithVar( n ); - return getTableauxValue( v, minus_delta ); - }else{ - return NodeManager::currentNM()->mkConst( Rational(0) ); } -} -*/ -Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){ - const Rational& delta = d_th->d_internal->d_partialModel.getDelta(); - DeltaRational drv = d_th->d_internal->d_partialModel.getAssignment( v ); - Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta ); - return mkRationalNode(qmodel); + return Node::null(); } @@ -590,6 +625,7 @@ InstStrategyCegqi::InstStrategyCegqi( QuantifiersEngine * qe ) : InstStrategyCbqi( qe ) { d_out = new CegqiOutputInstStrategy( this ); d_small_const = NodeManager::currentNM()->mkConst( Rational(1)/Rational(1000000) ); + d_check_vts_lemma_lc = false; } InstStrategyCegqi::~InstStrategyCegqi() throw () { @@ -654,9 +690,13 @@ bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) { //check if we need virtual term substitution (if used delta or infinity) bool used_vts = d_quantEngine->getTermDatabase()->containsVtsTerm( subs, false ); if( d_quantEngine->addInstantiation( d_curr_quant, subs, false, false, used_vts ) ){ + ++(d_quantEngine->d_statistics.d_instantiations_cbqi); //d_added_inst.insert( d_curr_quant ); return true; }else{ + //this should never happen for monotonic selection strategies + Trace("cbqi-warn") << "WARNING: Existing instantiation" << std::endl; + Assert( !options::cbqiNestedQE() || options::cbqiAll() ); return false; } } @@ -671,6 +711,16 @@ bool InstStrategyCegqi::isEligibleForInstantiation( Node n ) { if( n.getKind()==SKOLEM && d_quantEngine->getTermDatabase()->containsVtsTerm( n ) ){ return true; }else{ + TypeNode tn = n.getType(); + if( tn.isSort() ){ + QuantEPR * qepr = d_quantEngine->getQuantEPR(); + if( qepr!=NULL ){ + //legal if in the finite set of constants of type tn + if( qepr->isEPRConstant( tn, n ) ){ + return true; + } + } + } //only legal if current quantified formula contains n return TermDb::containsTerm( d_curr_quant, n ); } @@ -719,7 +769,9 @@ void InstStrategyCegqi::registerCounterexampleLemma( Node q, Node lem ) { void InstStrategyCegqi::presolve() { if( options::cbqiPreRegInst() ){ for( std::map< Node, CegInstantiator * >::iterator it = d_cinst.begin(); it != d_cinst.end(); ++it ){ + Trace("cbqi-presolve") << "Presolve " << it->first << std::endl; it->second->presolve( it->first ); } } } + diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h index 8ed59778b..c9f62243f 100755 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h @@ -34,25 +34,64 @@ namespace quantifiers { class InstStrategyCbqi : public QuantifiersModule { typedef context::CDHashSet<Node, NodeHashFunction> NodeSet; + typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap; protected: bool d_cbqi_set_quant_inactive; bool d_incomplete_check; /** whether we have added cbqi lemma */ NodeSet d_added_cbqi_lemma; + /** whether we have added cbqi lemma */ + NodeSet d_elim_quants; + /** parent guards */ + std::map< Node, std::vector< Node > > d_parent_quant; + std::map< Node, std::vector< Node > > d_children_quant; + std::map< Node, bool > d_active_quant; /** whether we have instantiated quantified formulas */ //NodeSet d_added_inst; - /** whether to do cbqi for this quantified formula */ - std::map< Node, bool > d_do_cbqi; + /** whether to do cbqi for this quantified formula 0 : no, 2 : yes, 1 : yes but not exclusively, -1 : heuristically */ + std::map< Node, int > d_do_cbqi; /** register ce lemma */ + bool registerCbqiLemma( Node q ); virtual void registerCounterexampleLemma( Node q, Node lem ); /** has added cbqi lemma */ bool hasAddedCbqiLemma( Node q ) { return d_added_cbqi_lemma.find( q )!=d_added_cbqi_lemma.end(); } /** helper functions */ - bool hasNonCbqiVariable( Node q ); + int hasNonCbqiVariable( Node q ); bool hasNonCbqiOperator( Node n, std::map< Node, bool >& visited ); + /** get next decision request with dependency checking */ + Node getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc ); /** process functions */ virtual void processResetInstantiationRound( Theory::Effort effort ) = 0; virtual void process( Node q, Theory::Effort effort, int e ) = 0; +protected: + //for identification + uint64_t d_qid_count; + //nested qe map + std::map< Node, Node > d_nested_qe; + //mark ids on quantifiers + Node getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited ); + // id to ce quant + std::map< Node, Node > d_id_to_ce_quant; + std::map< Node, Node > d_ce_quant_to_id; + //do nested quantifier elimination recursive + Node doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts ); + Node doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts ); + //elimination information (for delayed elimination) + class NestedQEInfo { + public: + NestedQEInfo() : d_doVts(false){} + ~NestedQEInfo(){} + Node d_q; + std::vector< Node > d_inst_terms; + bool d_doVts; + }; + std::map< Node, NestedQEInfo > d_nested_qe_info; + NodeIntMap d_nested_qe_waitlist_size; + NodeIntMap d_nested_qe_waitlist_proc; + std::map< Node, std::vector< Node > > d_nested_qe_waitlist; +public: + //do nested quantifier elimination + Node doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts ); public: InstStrategyCbqi( QuantifiersEngine * qe ); ~InstStrategyCbqi() throw(); @@ -64,56 +103,13 @@ public: void reset_round( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); bool checkComplete(); + bool checkCompleteFor( Node q ); void preRegisterQuantifier( Node q ); void registerQuantifier( Node q ); /** get next decision request */ Node getNextDecisionRequest(); }; - -class InstStrategySimplex : public InstStrategyCbqi { -protected: - /** reference to theory arithmetic */ - arith::TheoryArith* d_th; - /** quantifiers we should process */ - std::map< Node, bool > d_quantActive; - /** delta */ - std::map< TypeNode, Node > d_deltas; - /** for each quantifier, simplex rows */ - std::map< Node, std::vector< arith::ArithVar > > d_instRows; - /** tableaux */ - std::map< Node, std::map< arith::ArithVar, Node > > d_tableaux_term; - std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux_ce_term; - std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux; - /** ce tableaux */ - std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_ceTableaux; - /** get value */ - //Node getTableauxValue( Node n, bool minus_delta = false ); - Node getTableauxValue( arith::ArithVar v, bool minus_delta = false ); - /** do instantiation */ - bool doInstantiation( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var ); - bool doInstantiation2( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false ); - /** add term to row */ - void addTermToRow( Node ic, arith::ArithVar x, Node n, NodeBuilder<>& t ); - /** print debug */ - void debugPrint( const char* c ); -private: - /** */ - int d_counter; - /** constants */ - Node d_zero; - Node d_negOne; - /** process functions */ - void processResetInstantiationRound( Theory::Effort effort ); - void process( Node f, Theory::Effort effort, int e ); -public: - InstStrategySimplex( arith::TheoryArith* th, QuantifiersEngine* ie ); - ~InstStrategySimplex() throw() {} - /** identify */ - std::string identify() const { return std::string("Simplex"); } -}; - - //generalized counterexample guided quantifier instantiation class InstStrategyCegqi; diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index 49e0a698f..c4bf61b28 100755 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -155,6 +155,7 @@ InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe d_regenerate_frequency = 3; d_regenerate = true; }else{ + d_regenerate_frequency = 1; d_regenerate = false; } } diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index db597d031..afeed1e5d 100755 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -114,6 +114,7 @@ void InstantiationEngine::reset_round( Theory::Effort e ){ } void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ + CodeTimer codeTimer(d_quantEngine->d_statistics.d_ematching_time); if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ double clSet = 0; if( Trace.isOn("inst-engine") ){ @@ -151,19 +152,9 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ } } -bool InstantiationEngine::checkComplete() { - if( !options::finiteModelFind() ){ - for( unsigned i=0; i<d_quants.size(); i++ ){ - if( isIncomplete( d_quants[i] ) ){ - return false; - } - } - } - return true; -} - -bool InstantiationEngine::isIncomplete( Node q ) { - return true; +bool InstantiationEngine::checkCompleteFor( Node q ) { + //TODO? + return false; } void InstantiationEngine::preRegisterQuantifier( Node q ) { diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index d2b3740a1..79963cb45 100755 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h @@ -78,7 +78,7 @@ public: bool needsCheck( Theory::Effort e ); void reset_round( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); - bool checkComplete(); + bool checkCompleteFor( Node q ); void preRegisterQuantifier( Node q ); void registerQuantifier( Node q ); Node explain(TNode n){ return Node::null(); } diff --git a/src/theory/quantifiers/local_theory_ext.h b/src/theory/quantifiers/local_theory_ext.h index 94abf3c90..04a6bc9c8 100755 --- a/src/theory/quantifiers/local_theory_ext.h +++ b/src/theory/quantifiers/local_theory_ext.h @@ -66,6 +66,8 @@ public: void check( Theory::Effort e, unsigned quant_e ); /* Called for new quantifiers */ void registerQuantifier( Node q ) {} + /* check complete */ + bool checkComplete() { return !d_wasInvoked; } void assertNode( Node n ) {} /** Identify this module (for debugging, dynamic configuration, etc..) */ std::string identify() const { return "LtePartialInst"; } diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index 582599680..976b81e60 100755 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -33,6 +33,10 @@ using namespace CVC4::theory::quantifiers; using namespace CVC4::kind; +QuantifierMacros::QuantifierMacros( QuantifiersEngine * qe ) : d_qe( qe ){ + d_ground_macros = false; +} + bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ unsigned rmax = options::macrosQuantMode()==MACROS_QUANT_MODE_ALL ? 2 : 1; for( unsigned r=0; r<rmax; r++ ){ diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index 39ec2f0a1..60af7ad0a 100755 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -60,7 +60,7 @@ private: void addMacro( Node op, Node n, std::vector< Node >& opc ); void debugMacroDefinition( Node oo, Node n ); public: - QuantifierMacros( QuantifiersEngine * qe ) : d_qe( qe ){} + QuantifierMacros( QuantifiersEngine * qe ); ~QuantifierMacros(){} bool simplify( std::vector< Node >& assertions, bool doRewrite = false ); diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp index 7bbe06108..b30c2addb 100755 --- a/src/theory/quantifiers/model_builder.cpp +++ b/src/theory/quantifiers/model_builder.cpp @@ -391,7 +391,7 @@ bool QModelBuilderIG::isTermActive( Node n ){ //do exhaustive instantiation -bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { +int QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { if( optUseModel() ){ RepSetIterator riter( d_qe, &(d_qe->getModel()->d_rep_set) ); if( riter.setQuantifier( f ) ){ @@ -470,10 +470,9 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i } } //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round - d_incomplete_check = riter.isIncomplete(); - return true; + return riter.isIncomplete() ? -1 : 1; }else{ - return false; + return 0; } } diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h index e4f9529a8..9b89e5ef6 100755 --- a/src/theory/quantifiers/model_builder.h +++ b/src/theory/quantifiers/model_builder.h @@ -38,13 +38,14 @@ public: virtual ~QModelBuilder() throw() {} // is quantifier active? virtual bool isQuantifierActive( Node f ); - //do exhaustive instantiation - virtual bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; } + //do exhaustive instantiation + // 0 : failed, but resorting to true exhaustive instantiation may work + // >0 : success + // <0 : failed + virtual int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; } //whether to construct model virtual bool optUseModel(); /** number of lemmas generated while building model */ - //is the exhaustive instantiation incomplete? - bool d_incomplete_check; int d_addedLemmas; int d_triedLemmas; /** exist instantiation ? */ @@ -142,7 +143,7 @@ public: // is quantifier active? bool isQuantifierActive( Node f ); //do exhaustive instantiation - bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ); + int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ); //temporary stats int d_numQuantSat; diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index 7658f2b6b..9c09371c4 100755 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -73,7 +73,6 @@ void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ Trace("model-engine") << "---Model Engine Round---" << std::endl; clSet = double(clock())/double(CLOCKS_PER_SEC); } - ++(d_statistics.d_inst_rounds); Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl; //let the strong solver verify that the model is minimal @@ -99,7 +98,7 @@ void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ } if( addedLemmas==0 ){ - Trace("model-engine-debug") << "No lemmas added, incomplete = " << d_incomplete_check << std::endl; + Trace("model-engine-debug") << "No lemmas added, incomplete = " << ( d_incomplete_check || !d_incomplete_quants.empty() ) << std::endl; //CVC4 will answer SAT or unknown if( Trace.isOn("fmf-consistent") ){ Trace("fmf-consistent") << std::endl; @@ -113,6 +112,10 @@ bool ModelEngine::checkComplete() { return !d_incomplete_check; } +bool ModelEngine::checkCompleteFor( Node q ) { + return std::find( d_incomplete_quants.begin(), d_incomplete_quants.end(), q )==d_incomplete_quants.end(); +} + void ModelEngine::registerQuantifier( Node f ){ if( Trace.isOn("fmf-warn") ){ bool canHandle = true; @@ -195,17 +198,18 @@ int ModelEngine::checkModel(){ // FMC uses two sub-effort levels int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 ); for( int e=0; e<e_max; e++) { + d_incomplete_quants.clear(); for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ - Node f = fm->getAssertedQuantifier( i, true ); - Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << f << ", effort = " << e << "..." << std::endl; + Node q = fm->getAssertedQuantifier( i, true ); + Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q << ", effort = " << e << "..." << std::endl; //determine if we should check this quantifier - if( considerQuantifiedFormula( f ) ){ - exhaustiveInstantiate( f, e ); + if( considerQuantifiedFormula( q ) ){ + exhaustiveInstantiate( q, e ); if( d_quantEngine->inConflict() || ( optOneQuantPerRound() && d_addedLemmas>0 ) ){ break; } }else{ - Trace("fmf-exh-inst") << "-> Inactive : " << f << std::endl; + Trace("fmf-exh-inst") << "-> Inactive : " << q << std::endl; } } if( d_addedLemmas>0 ){ @@ -260,13 +264,17 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ quantifiers::QModelBuilder * mb = d_quantEngine->getModelBuilder(); mb->d_triedLemmas = 0; mb->d_addedLemmas = 0; - mb->d_incomplete_check = false; - if( mb->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){ - Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl; + int retEi = mb->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ); + if( retEi!=0 ){ + if( retEi<0 ){ + Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl; + d_incomplete_quants.push_back( f ); + }else{ + Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl; + } d_triedLemmas += mb->d_triedLemmas; d_addedLemmas += mb->d_addedLemmas; - d_incomplete_check = d_incomplete_check || mb->d_incomplete_check; - d_statistics.d_mbqi_inst_lemmas += mb->d_addedLemmas; + d_quantEngine->d_statistics.d_instantiations_fmf_mbqi += mb->d_addedLemmas; }else{ if( Trace.isOn("fmf-exh-inst-debug") ){ Trace("fmf-exh-inst-debug") << " Instantiation Constants: "; @@ -303,13 +311,15 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ } d_addedLemmas += addedLemmas; d_triedLemmas += triedLemmas; - d_statistics.d_exh_inst_lemmas += addedLemmas; + d_quantEngine->d_statistics.d_instantiations_fmf_exh += addedLemmas; } }else{ Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl; } //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round - d_incomplete_check = d_incomplete_check || riter.isIncomplete(); + if( riter.isIncomplete() ){ + d_incomplete_quants.push_back( f ); + } } } @@ -328,18 +338,3 @@ void ModelEngine::debugPrint( const char* c ){ //d_quantEngine->getModel()->debugPrint( c ); } -ModelEngine::Statistics::Statistics(): - d_inst_rounds("ModelEngine::Inst_Rounds", 0), - d_exh_inst_lemmas("ModelEngine::Instantiations_Exhaustive", 0 ), - d_mbqi_inst_lemmas("ModelEngine::Instantiations_Mbqi", 0 ) -{ - smtStatisticsRegistry()->registerStat(&d_inst_rounds); - smtStatisticsRegistry()->registerStat(&d_exh_inst_lemmas); - smtStatisticsRegistry()->registerStat(&d_mbqi_inst_lemmas); -} - -ModelEngine::Statistics::~Statistics(){ - smtStatisticsRegistry()->unregisterStat(&d_inst_rounds); - smtStatisticsRegistry()->unregisterStat(&d_exh_inst_lemmas); - smtStatisticsRegistry()->unregisterStat(&d_mbqi_inst_lemmas); -} diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index 12f18aa08..e89be8d2b 100755 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h @@ -42,6 +42,8 @@ private: //temporary statistics //is the exhaustive instantiation incomplete? bool d_incomplete_check; + // set of quantified formulas for which check was incomplete + std::vector< Node > d_incomplete_quants; int d_addedLemmas; int d_triedLemmas; int d_totalLemmas; @@ -54,21 +56,11 @@ public: void reset_round( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); bool checkComplete(); + bool checkCompleteFor( Node q ); void registerQuantifier( Node f ); void assertNode( Node f ); Node explain(TNode n){ return Node::null(); } void debugPrint( const char* c ); -public: - /** statistics class */ - class Statistics { - public: - IntStat d_inst_rounds; - IntStat d_exh_inst_lemmas; - IntStat d_mbqi_inst_lemmas; - Statistics(); - ~Statistics(); - }; - Statistics d_statistics; /** Identify this module */ std::string identify() const { return "ModelEngine"; } };/* class ModelEngine */ diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index bac2aa35c..1e484311c 100755 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -108,7 +108,7 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { } Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; - if( d_mg->isValid() ){ + if( d_mg->isValid() && options::qcfEagerCheckRd() ){ //optimization : record variable argument positions for terms that must be matched std::vector< TNode > vars; //TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137) @@ -967,7 +967,11 @@ MatchGen::MatchGen() d_n(), d_type( typ_invalid ), d_type_not() -{} +{ + d_qni_size = 0; + d_child_counter = -1; + d_use_children = true; +} MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) @@ -980,6 +984,10 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) d_type(), d_type_not() { + //initialize temporary + d_child_counter = -1; + d_use_children = true; + Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; std::vector< Node > qni_apps; d_qni_size = 0; @@ -1853,7 +1861,7 @@ void MatchGen::setInvalid() { } bool MatchGen::isHandledBoolConnective( TNode n ) { - return TermDb::isBoolConnective( n.getKind() ) && ( n.getKind()!=ITE || n.getType().isBoolean() ); + return TermDb::isBoolConnective( n.getKind() ) && ( n.getKind()!=ITE || n.getType().isBoolean() ) && n.getKind()!=SEP_STAR; } bool MatchGen::isHandledUfTerm( TNode n ) { @@ -2024,6 +2032,7 @@ void QuantConflictFind::setIrrelevantFunction( TNode f ) { /** check */ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { + CodeTimer codeTimer(d_quantEngine->d_statistics.d_qcf_time); if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ Trace("qcf-check") << "QCF : check : " << level << std::endl; if( d_conflict ){ @@ -2098,7 +2107,7 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { ++addedLemmas; if( e==effort_conflict ){ d_quantEngine->markRelevant( q ); - ++(d_statistics.d_conflict_inst); + ++(d_quantEngine->d_statistics.d_instantiations_qcf); if( options::qcfAllConflict() ){ isConflict = true; }else{ @@ -2107,7 +2116,7 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { break; }else if( e==effort_prop_eq ){ d_quantEngine->markRelevant( q ); - ++(d_statistics.d_prop_inst); + ++(d_quantEngine->d_statistics.d_instantiations_qcf); } }else{ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; @@ -2234,20 +2243,14 @@ void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, boo QuantConflictFind::Statistics::Statistics(): d_inst_rounds("QuantConflictFind::Inst_Rounds", 0), - d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ), - d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ), d_entailment_checks("QuantConflictFind::Entailment_Checks",0) { smtStatisticsRegistry()->registerStat(&d_inst_rounds); - smtStatisticsRegistry()->registerStat(&d_conflict_inst); - smtStatisticsRegistry()->registerStat(&d_prop_inst); smtStatisticsRegistry()->registerStat(&d_entailment_checks); } QuantConflictFind::Statistics::~Statistics(){ smtStatisticsRegistry()->unregisterStat(&d_inst_rounds); - smtStatisticsRegistry()->unregisterStat(&d_conflict_inst); - smtStatisticsRegistry()->unregisterStat(&d_prop_inst); smtStatisticsRegistry()->unregisterStat(&d_entailment_checks); } diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 47a66b1b1..dc8a9acb2 100755 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -260,8 +260,6 @@ public: class Statistics { public: IntStat d_inst_rounds; - IntStat d_conflict_inst; - IntStat d_prop_inst; IntStat d_entailment_checks; Statistics(); ~Statistics(); diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp index 5aff1a848..df8533135 100755 --- a/src/theory/quantifiers/quant_split.cpp +++ b/src/theory/quantifiers/quant_split.cpp @@ -48,7 +48,7 @@ void QuantDSplit::preRegisterQuantifier( Node q ) { }else{ int score = -1; if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){ - score = dt.isInterpretedFinite() ? 1 : -1; + score = dt.isInterpretedFinite() ? 1 : 0; }else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){ score = dt.isInterpretedFinite() ? 1 : -1; } @@ -73,6 +73,11 @@ bool QuantDSplit::needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty(); } +bool QuantDSplit::checkCompleteFor( Node q ) { + // true if we split q + return d_added_split.find( q )!=d_added_split.end(); +} + /* Call during quantifier engine's check */ void QuantDSplit::check( Theory::Effort e, unsigned quant_e ) { //add lemmas ASAP (they are a reduction) diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h index d36824998..3e3b08814 100755 --- a/src/theory/quantifiers/quant_split.h +++ b/src/theory/quantifiers/quant_split.h @@ -43,6 +43,7 @@ public: /* Called for new quantifiers */ void registerQuantifier( Node q ) {} void assertNode( Node n ) {} + bool checkCompleteFor( Node q ); /** Identify this module (for debugging, dynamic configuration, etc..) */ std::string identify() const { return "QuantDSplit"; } }; diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp index b9aab0236..f4284a8ab 100755 --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -419,3 +419,107 @@ void QuantPhaseReq::getEntailPolarity( Node n, int child, bool hasPol, bool pol, } } +void QuantEPR::registerNode( Node n, std::map< int, std::map< Node, bool > >& visited, bool beneathQuant, bool hasPol, bool pol ) { + int vindex = hasPol ? ( pol ? 1 : -1 ) : 0; + if( visited[vindex].find( n )==visited[vindex].end() ){ + visited[vindex][n] = true; + Trace("quant-epr-debug") << "QuantEPR::registerNode " << n << std::endl; + if( n.getKind()==FORALL ){ + if( beneathQuant || !hasPol || !pol ){ + for( unsigned i=0; i<n[0].getNumChildren(); i++ ){ + TypeNode tn = n[0][i].getType(); + if( d_non_epr.find( tn )==d_non_epr.end() ){ + Trace("quant-epr") << "Sort " << tn << " is non-EPR because of nested or possible existential quantification." << std::endl; + d_non_epr[tn] = true; + } + } + }else{ + beneathQuant = true; + } + } + TypeNode tn = n.getType(); + + if( n.getNumChildren()>0 ){ + if( tn.isSort() ){ + if( d_non_epr.find( tn )==d_non_epr.end() ){ + Trace("quant-epr") << "Sort " << tn << " is non-EPR because of " << n << std::endl; + d_non_epr[tn] = true; + } + } + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + bool newHasPol; + bool newPol; + QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); + registerNode( n[i], visited, beneathQuant, newHasPol, newPol ); + } + }else if( tn.isSort() ){ + if( n.getKind()==BOUND_VARIABLE ){ + if( d_consts.find( tn )==d_consts.end() ){ + //mark that at least one constant must occur + d_consts[tn].clear(); + } + }else if( std::find( d_consts[tn].begin(), d_consts[tn].end(), n )==d_consts[tn].end() ){ + d_consts[tn].push_back( n ); + Trace("quant-epr") << "...constant of type " << tn << " : " << n << std::endl; + } + } + } +} + +void QuantEPR::registerAssertion( Node assertion ) { + std::map< int, std::map< Node, bool > > visited; + registerNode( assertion, visited, false, true, true ); +} + +void QuantEPR::finishInit() { + Trace("quant-epr-debug") << "QuantEPR::finishInit" << std::endl; + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_consts.begin(); it != d_consts.end(); ++it ){ + Assert( d_epr_axiom.find( it->first )==d_epr_axiom.end() ); + Trace("quant-epr-debug") << "process " << it->first << std::endl; + if( d_non_epr.find( it->first )!=d_non_epr.end() ){ + Trace("quant-epr-debug") << "...non-epr" << std::endl; + it->second.clear(); + }else{ + Trace("quant-epr-debug") << "...epr, #consts = " << it->second.size() << std::endl; + if( it->second.empty() ){ + it->second.push_back( NodeManager::currentNM()->mkSkolem( "e", it->first, "EPR base constant" ) ); + } + if( Trace.isOn("quant-epr") ){ + Trace("quant-epr") << "Type " << it->first << " is EPR, with constants : " << std::endl; + for( unsigned i=0; i<it->second.size(); i++ ){ + Trace("quant-epr") << " " << it->second[i] << std::endl; + } + } + } + } +} + +bool QuantEPR::isEPRConstant( TypeNode tn, Node k ) { + return std::find( d_consts[tn].begin(), d_consts[tn].end(), k )!=d_consts[tn].end(); +} + +void QuantEPR::addEPRConstant( TypeNode tn, Node k ) { + Assert( isEPR( tn ) ); + Assert( d_epr_axiom.find( tn )==d_epr_axiom.end() ); + if( !isEPRConstant( tn, k ) ){ + d_consts[tn].push_back( k ); + } +} + +Node QuantEPR::mkEPRAxiom( TypeNode tn ) { + Assert( isEPR( tn ) ); + std::map< TypeNode, Node >::iterator ita = d_epr_axiom.find( tn ); + if( ita==d_epr_axiom.end() ){ + std::vector< Node > disj; + Node x = NodeManager::currentNM()->mkBoundVar( tn ); + for( unsigned i=0; i<d_consts[tn].size(); i++ ){ + disj.push_back( NodeManager::currentNM()->mkNode( tn.isBoolean() ? IFF : EQUAL, x, d_consts[tn][i] ) ); + } + Assert( !disj.empty() ); + d_epr_axiom[tn] = NodeManager::currentNM()->mkNode( FORALL, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, x ), disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( OR, disj ) ); + return d_epr_axiom[tn]; + }else{ + return ita->second; + } +} + diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h index 79cdae437..3ff21aa6e 100755 --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h @@ -51,8 +51,10 @@ public: virtual void reset_round( Theory::Effort e ){} /* Call during quantifier engine's check */ virtual void check( Theory::Effort e, unsigned quant_e ) = 0; - /* check was complete (e.g. no lemmas implies a model) */ + /* check was complete, return false if there is no way to answer "SAT", true if maybe can answer "SAT" */ virtual bool checkComplete() { return true; } + /* check was complete for quantified formula q (e.g. no lemmas implies a model) */ + virtual bool checkCompleteFor( Node q ) { return false; } /* Called for new quantified formulas */ virtual void preRegisterQuantifier( Node q ) { } /* Called for new quantifiers after owners are finalized */ @@ -149,7 +151,7 @@ public: }; -class EqualityQuery : public QuantifiersUtil{ +class EqualityQuery : public QuantifiersUtil { public: EqualityQuery(){} virtual ~EqualityQuery(){}; @@ -171,6 +173,38 @@ public: virtual TNode getCongruentTerm( Node f, std::vector< TNode >& args ) = 0; };/* class EqualityQuery */ +class QuantEPR +{ +private: + void registerNode( Node n, std::map< int, std::map< Node, bool > >& visited, bool beneathQuant, bool hasPol, bool pol ); + /** non-epr */ + std::map< TypeNode, bool > d_non_epr; + /** axioms for epr */ + std::map< TypeNode, Node > d_epr_axiom; +public: + QuantEPR(){} + virtual ~QuantEPR(){} + /** constants per type */ + std::map< TypeNode, std::vector< Node > > d_consts; + /* reset */ + //bool reset( Theory::Effort e ) {} + /** identify */ + //std::string identify() const { return "QuantEPR"; } + /** register assertion */ + void registerAssertion( Node assertion ); + /** finish init */ + void finishInit(); + /** is EPR */ + bool isEPR( TypeNode tn ) const { return d_non_epr.find( tn )==d_non_epr.end(); } + /** is EPR constant */ + bool isEPRConstant( TypeNode tn, Node k ); + /** add EPR constant */ + void addEPRConstant( TypeNode tn, Node k ); + /** get EPR axiom */ + Node mkEPRAxiom( TypeNode tn ); + /** has EPR axiom */ + bool hasEPRAxiom( TypeNode tn ) const { return d_epr_axiom.find( tn )!=d_epr_axiom.end(); } +}; } } diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index 963889a85..de8875ae3 100755 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -20,11 +20,12 @@ #include "theory/quantifiers/trigger.h" using namespace std; -using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; + +namespace CVC4 { +namespace theory { +namespace quantifiers { bool QuantifiersRewriter::isClause( Node n ){ if( isLiteral( n ) ){ @@ -1074,9 +1075,9 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& return body; } -Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){ +Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, std::vector< Node >& nargs, bool pol, bool prenexAgg ){ if( body.getKind()==FORALL ){ - if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){ + if( ( pol || prenexAgg ) && ( options::prenexQuantUser() || body.getNumChildren()==2 ) ){ std::vector< Node > terms; std::vector< Node > subs; //for doing prenexing of same-signed quantifiers @@ -1085,14 +1086,27 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b terms.push_back( body[0][i] ); subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) ); } - args.insert( args.end(), subs.begin(), subs.end() ); + if( pol ){ + args.insert( args.end(), subs.begin(), subs.end() ); + }else{ + nargs.insert( nargs.end(), subs.begin(), subs.end() ); + } Node newBody = body[1]; newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); return newBody; - }else{ - return body; } - }else{ + //must remove structure + }else if( prenexAgg && body.getKind()==kind::ITE && body.getType().isBoolean() ){ + Node nn = NodeManager::currentNM()->mkNode( kind::AND, + NodeManager::currentNM()->mkNode( kind::OR, body[0].notNode(), body[1] ), + NodeManager::currentNM()->mkNode( kind::OR, body[0], body[2] ) ); + return computePrenex( nn, args, nargs, pol, prenexAgg ); + }else if( prenexAgg && body.getKind()==kind::IFF ){ + Node nn = NodeManager::currentNM()->mkNode( kind::AND, + NodeManager::currentNM()->mkNode( kind::OR, body[0].notNode(), body[1] ), + NodeManager::currentNM()->mkNode( kind::OR, body[0], body[1].notNode() ) ); + return computePrenex( nn, args, nargs, pol, prenexAgg ); + }else if( body.getType().isBoolean() ){ Assert( body.getKind()!=EXISTS ); bool childrenChanged = false; std::vector< Node > newChildren; @@ -1101,7 +1115,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b bool newPol; QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol ); if( newHasPol ){ - Node n = computePrenex( body[i], args, newPol ); + Node n = computePrenex( body[i], args, nargs, newPol, prenexAgg ); newChildren.push_back( n ); if( n!=body[i] ){ childrenChanged = true; @@ -1116,10 +1130,98 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b }else{ return NodeManager::currentNM()->mkNode( body.getKind(), newChildren ); } + } + } + return body; +} + +Node QuantifiersRewriter::computePrenexAgg( Node n, bool topLevel ){ + if( containsQuantifiers( n ) ){ + if( topLevel && options::prenexQuant()==PRENEX_QUANT_DISJ_NORMAL && ( n.getKind()==AND || ( n.getKind()==NOT && n[0].getKind()==OR ) ) ){ + std::vector< Node > children; + Node nc = n.getKind()==NOT ? n[0] : n; + for( unsigned i=0; i<nc.getNumChildren(); i++ ){ + Node ncc = computePrenexAgg( nc[i], true ); + if( n.getKind()==NOT ){ + ncc = ncc.negate(); + } + children.push_back( ncc ); + } + return NodeManager::currentNM()->mkNode( AND, children ); + }else if( n.getKind()==NOT ){ + return computePrenexAgg( n[0], false ).negate(); + }else if( n.getKind()==FORALL ){ + /* + Node nn = computePrenexAgg( n[1], false ); + if( nn!=n[1] ){ + if( n.getNumChildren()==2 ){ + return NodeManager::currentNM()->mkNode( FORALL, n[0], nn ); + }else{ + return NodeManager::currentNM()->mkNode( FORALL, n[0], nn, n[2] ); + } + } + */ + std::vector< Node > children; + if( n[1].getKind()==OR && options::prenexQuant()==PRENEX_QUANT_DISJ_NORMAL ){ + for( unsigned i=0; i<n[1].getNumChildren(); i++ ){ + children.push_back( computePrenexAgg( n[1][i], false ) ); + } + }else{ + children.push_back( computePrenexAgg( n[1], false ) ); + } + std::vector< Node > args; + for( unsigned i=0; i<n[0].getNumChildren(); i++ ){ + args.push_back( n[0][i] ); + } + std::vector< Node > nargs; + //for each child, strip top level quant + for( unsigned i=0; i<children.size(); i++ ){ + if( children[i].getKind()==FORALL ){ + for( unsigned j=0; j<children[i][0].getNumChildren(); j++ ){ + args.push_back( children[i][0][j] ); + } + children[i] = children[i][1]; + } + } + Node nb = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children ); + return mkForall( args, nb, true ); }else{ - return body; + std::vector< Node > args; + std::vector< Node > nargs; + Node nn = computePrenex( n, args, nargs, true, true ); + if( n!=nn ){ + Node nnn = computePrenexAgg( nn, false ); + //merge prenex + if( nnn.getKind()==FORALL ){ + for( unsigned i=0; i<nnn[0].getNumChildren(); i++ ){ + args.push_back( nnn[0][i] ); + } + nnn = nnn[1]; + //pos polarity variables are inner + if( !args.empty() ){ + nnn = mkForall( args, nnn, true ); + } + args.clear(); + }else if( nnn.getKind()==NOT && nnn[0].getKind()==FORALL ){ + for( unsigned i=0; i<nnn[0][0].getNumChildren(); i++ ){ + nargs.push_back( nnn[0][0][i] ); + } + nnn = nnn[0][1].negate(); + } + if( !nargs.empty() ){ + nnn = mkForall( nargs, nnn.negate(), true ).negate(); + } + if( !args.empty() ){ + nnn = mkForall( args, nnn, true ); + } + return nnn; + }else{ + Assert( args.empty() ); + Assert( nargs.empty() ); + } } } + return n; } Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) { @@ -1237,6 +1339,26 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttri return NodeManager::currentNM()->mkNode( kind::FORALL, children ); } } +Node QuantifiersRewriter::mkForall( std::vector< Node >& args, Node body, bool marked ) { + if( args.empty() ){ + return body; + }else{ + std::vector< Node > children; + children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) ); + children.push_back( body ); + std::vector< Node > iplc; + if( marked ){ + Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() ); + QuantIdNumAttribute ida; + avar.setAttribute(ida,0); + iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) ); + } + if( !iplc.empty() ){ + children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) ); + } + return NodeManager::currentNM()->mkNode( FORALL, children ); + } +} //computes miniscoping, also eliminates variables that do not occur free in body Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ){ @@ -1294,21 +1416,25 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo } Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){ - std::map< Node, std::vector< Node > > varLits; - std::map< Node, std::vector< Node > > litVars; - if( body.getKind()==OR ){ + std::map<Node, std::vector<Node> > varLits; + std::map<Node, std::vector<Node> > litVars; + if (body.getKind() == OR) { Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl; - for( size_t i=0; i<body.getNumChildren(); i++ ){ - std::vector< Node > activeArgs; - computeArgVec( args, activeArgs, body[i] ); - for (unsigned j=0; j<activeArgs.size(); j++ ){ - varLits[activeArgs[j]].push_back( body[i] ); - } - litVars[body[i]].insert( litVars[body[i]].begin(), activeArgs.begin(), activeArgs.end() ); + for (size_t i = 0; i < body.getNumChildren(); i++) { + std::vector<Node> activeArgs; + computeArgVec(args, activeArgs, body[i]); + for (unsigned j = 0; j < activeArgs.size(); j++) { + varLits[activeArgs[j]].push_back(body[i]); + } + std::vector<Node>& lit_body_i = litVars[body[i]]; + std::vector<Node>::iterator lit_body_i_begin = lit_body_i.begin(); + std::vector<Node>::const_iterator active_begin = activeArgs.begin(); + std::vector<Node>::const_iterator active_end = activeArgs.end(); + lit_body_i.insert(lit_body_i_begin, active_begin, active_end); } //find the variable in the least number of literals Node bestVar; - for( std::map< Node, std::vector< Node > >::iterator it = varLits.begin(); it != varLits.end(); ++it ){ + for( std::map< Node, std::vector<Node> >::iterator it = varLits.begin(); it != varLits.end(); ++it ){ if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){ bestVar = it->first; } @@ -1318,9 +1444,9 @@ Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& arg //we can miniscope Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl; //make the bodies - std::vector< Node > qlit1; + std::vector<Node> qlit1; qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() ); - std::vector< Node > qlitt; + std::vector<Node> qlitt; //for all literals not containing bestVar for( size_t i=0; i<body.getNumChildren(); i++ ){ if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){ @@ -1328,9 +1454,9 @@ Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& arg } } //make the variable lists - std::vector< Node > qvl1; - std::vector< Node > qvl2; - std::vector< Node > qvsh; + std::vector<Node> qvl1; + std::vector<Node> qvl2; + std::vector<Node> qvsh; for( unsigned i=0; i<args.size(); i++ ){ bool found1 = false; bool found2 = false; @@ -1358,8 +1484,8 @@ Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& arg Assert( !qvl1.empty() ); Assert( !qvl2.empty() || !qvsh.empty() ); //check for literals that only contain shared variables - std::vector< Node > qlitsh; - std::vector< Node > qlit2; + std::vector<Node> qlitsh; + std::vector<Node> qlit2; for( size_t i=0; i<qlitt.size(); i++ ){ bool hasVar2 = false; for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){ @@ -1413,7 +1539,7 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q }else if( computeOption==COMPUTE_COND_SPLIT ){ return ( options::iteDtTesterSplitQuant() || options::condVarSplitQuant() ) && !is_strict_trigger; }else if( computeOption==COMPUTE_PRENEX ){ - return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant() && is_std; + return options::prenexQuant()!=PRENEX_QUANT_NONE && !options::aggressiveMiniscopeQuant() && is_std; }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ return ( options::varElimQuant() || options::dtVarExpandQuant() ) && is_std; }else{ @@ -1423,7 +1549,7 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q //general method for computing various rewrites Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttributes& qa ){ - Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << std::endl; + Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl; std::vector< Node > args; for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ args.push_back( f[0][i] ); @@ -1432,6 +1558,12 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut if( computeOption==COMPUTE_ELIM_SYMBOLS ){ n = computeElimSymbols( n ); }else if( computeOption==COMPUTE_MINISCOPING ){ + if( options::prenexQuant()==PRENEX_QUANT_DISJ_NORMAL || options::prenexQuant()==PRENEX_QUANT_NORMAL ){ + if( !qa.d_qid_num.isNull() ){ + //already processed this, return self + return f; + } + } //return directly return computeMiniscoping( args, n, qa ); }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ @@ -1446,7 +1578,14 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut }else if( computeOption==COMPUTE_COND_SPLIT ){ n = computeCondSplit( n, qa ); }else if( computeOption==COMPUTE_PRENEX ){ - n = computePrenex( n, args, true ); + if( options::prenexQuant()==PRENEX_QUANT_DISJ_NORMAL || options::prenexQuant()==PRENEX_QUANT_NORMAL ){ + //will rewrite at preprocess time + return f; + }else{ + std::vector< Node > nargs; + n = computePrenex( n, args, nargs, true, false ); + Assert( nargs.empty() ); + } }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ n = computeVarElimination( n, args, qa ); } @@ -1592,6 +1731,15 @@ bool QuantifiersRewriter::containsQuantifiers( Node n ){ return cq; } } +bool QuantifiersRewriter::isPrenexNormalForm( Node n ) { + if( n.getKind()==FORALL ){ + return n[1].getKind()!=FORALL && isPrenexNormalForm( n[1] ); + }else if( n.getKind()==NOT ){ + return n[0].getKind()!=NOT && isPrenexNormalForm( n[0] ); + }else{ + return !containsQuantifiers( n ); + } +} Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs ){ Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl; @@ -1662,21 +1810,37 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v return n; } + Node QuantifiersRewriter::preprocess( Node n, bool isInst ) { Node prev = n; - if( options::preSkolemQuant() ){ - if( !isInst || !options::preSkolemQuantNested() ){ - Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl; - //apply pre-skolemization to existential quantifiers - std::vector< TypeNode > fvTypes; - std::vector< TNode > fvs; - n = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ); + if( n.getKind() == kind::REWRITE_RULE ){ + n = quantifiers::QuantifiersRewriter::rewriteRewriteRule( n ); + }else{ + if( options::preSkolemQuant() ){ + if( !isInst || !options::preSkolemQuantNested() ){ + Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl; + //apply pre-skolemization to existential quantifiers + std::vector< TypeNode > fvTypes; + std::vector< TNode > fvs; + n = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ); + } } } + //pull all quantifiers globally + if( options::prenexQuant()==PRENEX_QUANT_DISJ_NORMAL || options::prenexQuant()==PRENEX_QUANT_NORMAL ){ + Trace("quantifiers-prenex") << "Prenexing : " << n << std::endl; + n = quantifiers::QuantifiersRewriter::computePrenexAgg( n, true ); + n = Rewriter::rewrite( n ); + Trace("quantifiers-prenex") << "Prenexing returned : " << n << std::endl; + //Assert( isPrenexNormalForm( n ) ); + } if( n!=prev ){ - Trace("quantifiers-preprocess") << "Preprocess " << prev<< std::endl; + Trace("quantifiers-preprocess") << "Preprocess " << prev << std::endl; Trace("quantifiers-preprocess") << "..returned " << n << std::endl; } return n; } +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h index 60dc8ab10..90a22f4b7 100755 --- a/src/theory/quantifiers/quantifiers_rewriter.h +++ b/src/theory/quantifiers/quantifiers_rewriter.h @@ -38,7 +38,6 @@ public: private: static bool addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ); static void addNodeToOrBuilder( Node n, NodeBuilder<>& t ); - static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ); static void computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n, std::map< Node, bool >& visited ); static void computeArgVec( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ); static void computeArgVec2( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n, Node ipl ); @@ -53,14 +52,15 @@ private: static bool computeVariableElimLit( Node n, bool pol, std::vector< Node >& args, std::vector< Node >& var, std::vector< Node >& subs, std::map< Node, std::map< bool, std::map< Node, bool > > >& num_bounds ); static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa ); -private: +public: static Node computeElimSymbols( Node body ); static Node computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ); static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body ); //cache is dependent upon currCond, icache is not, new_conds are negated conditions static Node computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ); static Node computeCondSplit( Node body, QAttributes& qa ); - static Node computePrenex( Node body, std::vector< Node >& args, bool pol ); + static Node computePrenex( Node body, std::vector< Node >& args, std::vector< Node >& nargs, bool pol, bool prenexAgg ); + static Node computePrenexAgg( Node n, bool topLevel ); static Node computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ); static Node computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ); private: @@ -89,8 +89,11 @@ private: static Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector<TNode>& fvs); public: static Node rewriteRewriteRule( Node r ); - static bool containsQuantifiers(Node n); + static bool containsQuantifiers( Node n ); + static bool isPrenexNormalForm( Node n ); static Node preprocess( Node n, bool isInst = false ); + static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ); + static Node mkForall( std::vector< Node >& args, Node body, bool marked = false ); };/* class QuantifiersRewriter */ }/* CVC4::theory::quantifiers namespace */ diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h index 2b90520fd..aae8f6c5b 100755 --- a/src/theory/quantifiers/relevant_domain.h +++ b/src/theory/quantifiers/relevant_domain.h @@ -51,7 +51,10 @@ private: //what each literal does class RDomainLit { public: - RDomainLit() : d_merge(false){} + RDomainLit() : d_merge(false){ + d_rd[0] = NULL; + d_rd[1] = NULL; + } ~RDomainLit(){} bool d_merge; RDomain * d_rd[2]; @@ -72,6 +75,7 @@ public: RDomain * getRDomain( Node n, int i, bool getParent = true ); };/* class RelevantDomain */ + }/* CVC4::theory::quantifiers namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp index 2c58b8f77..ec1b41a98 100755 --- a/src/theory/quantifiers/rewrite_engine.cpp +++ b/src/theory/quantifiers/rewrite_engine.cpp @@ -20,6 +20,7 @@ #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/inst_match_generator.h" #include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/quant_conflict_find.h" #include "theory/quantifiers/quant_util.h" #include "theory/quantifiers/term_database.h" #include "theory/theory_engine.h" @@ -204,6 +205,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) { Trace("rewrite-engine-inst-debug") << "...No qinfo." << std::endl; } } + d_quantEngine->d_statistics.d_instantiations_rr += addedLemmas; Trace("rewrite-engine-inst") << "-> Generated " << addedLemmas << " lemmas." << std::endl; return addedLemmas; } @@ -294,6 +296,11 @@ void RewriteEngine::assertNode( Node n ) { } +bool RewriteEngine::checkCompleteFor( Node q ) { + // by semantics of rewrite rules, saturation -> SAT + return std::find( d_rr_quant.begin(), d_rr_quant.end(), q )!=d_rr_quant.end(); +} + Node RewriteEngine::getInstConstNode( Node n, Node q ) { std::map< Node, Node >::iterator it = d_inst_const_node[q].find( n ); if( it==d_inst_const_node[q].end() ){ diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h index 424530696..ef3337e53 100755 --- a/src/theory/quantifiers/rewrite_engine.h +++ b/src/theory/quantifiers/rewrite_engine.h @@ -18,19 +18,17 @@ #ifndef __CVC4__REWRITE_ENGINE_H #define __CVC4__REWRITE_ENGINE_H -#include "theory/quantifiers_engine.h" -#include "theory/quantifiers/trigger.h" - +#include "context/cdchunk_list.h" #include "context/context.h" #include "context/context_mm.h" -#include "context/cdchunk_list.h" +#include "theory/quantifiers/trigger.h" +#include "theory/quantifiers/quant_conflict_find.h" +#include "theory/quantifiers_engine.h" namespace CVC4 { namespace theory { namespace quantifiers { -class QuantInfo; - class RewriteEngine : public QuantifiersModule { typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; @@ -57,7 +55,8 @@ public: bool needsCheck( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); - void assertNode( Node n ); + void assertNode( Node n ); + bool checkCompleteFor( Node q ); /** Identify this module */ std::string identify() const { return "RewriteEngine"; } }; diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index d3a5e178f..2c6bfb7d3 100755 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -33,14 +33,14 @@ #include "util/bitvector.h" using namespace std; -using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; - using namespace CVC4::theory::inst; +namespace CVC4 { +namespace theory { +namespace quantifiers { + TNode TermArgTrie::existsTerm( std::vector< TNode >& reps, int argIndex ) { if( argIndex==(int)reps.size() ){ if( d_data.empty() ){ @@ -84,15 +84,25 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) { } } -TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_inactive_map( c ), d_op_id_count( 0 ), d_typ_id_count( 0 ) { - d_true = NodeManager::currentNM()->mkConst( true ); - d_false = NodeManager::currentNM()->mkConst( false ); - d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) ); - d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) ); - if( options::ceGuidedInst() ){ - d_sygus_tdb = new TermDbSygus( c, qe ); - }else{ - d_sygus_tdb = NULL; +TermDb::TermDb(context::Context* c, context::UserContext* u, + QuantifiersEngine* qe) + : d_quantEngine(qe), + d_inactive_map(c), + d_op_id_count(0), + d_typ_id_count(0), + d_sygus_tdb(NULL) { + d_consistent_ee = true; + d_true = NodeManager::currentNM()->mkConst(true); + d_false = NodeManager::currentNM()->mkConst(false); + d_zero = NodeManager::currentNM()->mkConst(Rational(0)); + d_one = NodeManager::currentNM()->mkConst(Rational(1)); + if (options::ceGuidedInst()) { + d_sygus_tdb = new TermDbSygus(c, qe); + } +} +TermDb::~TermDb(){ + if(d_sygus_tdb) { + delete d_sygus_tdb; } } @@ -129,7 +139,7 @@ Node TermDb::getMatchOperator( Node n ) { Kind k = n.getKind(); //datatype operators may be parametric, always assume they are if( k==SELECT || k==STORE || k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON || - k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER ){ + k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER || k==SEP_PTO ){ //since it is parametric, use a particular one as op TypeNode tn = n[0].getType(); Node op = n.getOperator(); @@ -175,17 +185,6 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi if( d_sygus_tdb ){ d_sygus_tdb->registerEvalTerm( n ); } - - if( options::eagerInstQuant() ){ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){ - int addedLemmas = 0; - for( unsigned i=0; i<d_op_triggers[op].size(); i++ ){ - addedLemmas += d_op_triggers[op][i]->addTerm( n ); - } - } - } - } } }else{ setTermInactive( n ); @@ -1319,19 +1318,25 @@ bool TermDb::mayComplete( TypeNode tn ) { void TermDb::computeVarContains( Node n, std::vector< Node >& varContains ) { std::map< Node, bool > visited; - computeVarContains2( n, varContains, visited ); + computeVarContains2( n, INST_CONSTANT, varContains, visited ); +} + +void TermDb::computeQuantContains( Node n, std::vector< Node >& quantContains ) { + std::map< Node, bool > visited; + computeVarContains2( n, FORALL, quantContains, visited ); } -void TermDb::computeVarContains2( Node n, std::vector< Node >& varContains, std::map< Node, bool >& visited ){ + +void TermDb::computeVarContains2( Node n, Kind k, std::vector< Node >& varContains, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; - if( n.getKind()==INST_CONSTANT ){ + if( n.getKind()==k ){ if( std::find( varContains.begin(), varContains.end(), n )==varContains.end() ){ varContains.push_back( n ); } }else{ for( unsigned i=0; i<n.getNumChildren(); i++ ){ - computeVarContains2( n[i], varContains, visited ); + computeVarContains2( n[i], k, varContains, visited ); } } } @@ -1963,7 +1968,7 @@ bool TermDb::isComm( Kind k ) { } bool TermDb::isBoolConnective( Kind k ) { - return k==OR || k==AND || k==IFF || k==ITE || k==FORALL || k==NOT; + return k==OR || k==AND || k==IFF || k==ITE || k==FORALL || k==NOT || k==SEP_STAR; } void TermDb::registerTrigger( theory::inst::Trigger* tr, Node op ){ @@ -2163,6 +2168,10 @@ void TermDb::computeQuantAttributes( Node q, QAttributes& qa ){ qa.d_quant_elim_partial = true; //don't set owner, should happen naturally } + if( avar.hasAttribute(QuantIdNumAttribute()) ){ + qa.d_qid_num = avar; + Trace("quant-attr") << "Attribute : id number " << qa.d_qid_num.getAttribute(QuantIdNumAttribute()) << " : " << q << std::endl; + } if( avar.getKind()==REWRITE_RULE ){ Trace("quant-attr") << "Attribute : rewrite rule : " << q << std::endl; Assert( i==0 ); @@ -2254,6 +2263,25 @@ bool TermDb::isQAttrQuantElimPartial( Node q ) { } } +int TermDb::getQAttrQuantIdNum( Node q ) { + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it!=d_qattr.end() ){ + if( !it->second.d_qid_num.isNull() ){ + return it->second.d_qid_num.getAttribute(QuantIdNumAttribute()); + } + } + return -1; +} + +Node TermDb::getQAttrQuantIdNumNode( Node q ) { + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ + return Node::null(); + }else{ + return it->second.d_qid_num; + } +} + TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){ d_true = NodeManager::currentNM()->mkConst( true ); d_false = NodeManager::currentNM()->mkConst( false ); @@ -3125,7 +3153,6 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node > std::string name = std::string( str.begin() + found +1, str.end() ); out << name; }else{ - Trace("ajr-temp") << "[[print operator " << op << "]]" << std::endl; out << op; } if( n.getNumChildren()>0 ){ @@ -3281,3 +3308,6 @@ void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& lems } } +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index 7ab3668eb..d4fdaa5e5 100755 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -105,6 +105,11 @@ typedef expr::Attribute< QuantElimAttributeId, bool > QuantElimAttribute; struct QuantElimPartialAttributeId {}; typedef expr::Attribute< QuantElimPartialAttributeId, bool > QuantElimPartialAttribute; +/** Attribute for id number */ +struct QuantIdNumAttributeId {}; +typedef expr::Attribute< QuantIdNumAttributeId, uint64_t > QuantIdNumAttribute; + + class QuantifiersEngine; namespace inst{ @@ -145,6 +150,7 @@ public: bool d_quant_elim; bool d_quant_elim_partial; Node d_ipl; + Node d_qid_num; bool isRewriteRule() { return !d_rr.isNull(); } bool isFunDef() { return !d_fundef_f.isNull(); } }; @@ -182,23 +188,25 @@ private: std::map< Node, std::map< TypeNode, Node > > d_par_op_map; /** whether master equality engine is UF-inconsistent */ bool d_consistent_ee; -public: - TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ); - ~TermDb(){} + + public: + TermDb(context::Context* c, context::UserContext* u, QuantifiersEngine* qe); + ~TermDb(); /** boolean terms */ Node d_true; Node d_false; /** constants */ Node d_zero; Node d_one; -public: + + public: /** presolve (called once per user check-sat) */ void presolve(); /** reset (calculate which terms are active) */ bool reset( Theory::Effort effort ); /** identify */ std::string identify() const { return "TermDb"; } -private: + private: /** map from operators to ground terms for that operator */ std::map< Node, std::vector< Node > > d_op_map; /** map from type nodes to terms of that type */ @@ -301,8 +309,6 @@ private: /** map from universal quantifiers to the list of variables */ std::map< Node, std::vector< Node > > d_vars; std::map< Node, std::map< Node, unsigned > > d_var_num; - /** map from universal quantifiers to the list of instantiation constants */ - std::map< Node, std::vector< Node > > d_inst_constants; /** map from universal quantifiers to their inst constant body */ std::map< Node, Node > d_inst_const_body; /** map from universal quantifiers to their counterexample literals */ @@ -312,6 +318,8 @@ private: /** make instantiation constants for */ void makeInstantiationConstantsFor( Node q ); public: + /** map from universal quantifiers to the list of instantiation constants */ + std::map< Node, std::vector< Node > > d_inst_constants; /** get variable number */ unsigned getVariableNum( Node q, Node v ) { return d_var_num[q][v]; } /** get the i^th instantiation constant of q */ @@ -388,7 +396,7 @@ public: //for triggers private: /** helper function for compute var contains */ - static void computeVarContains2( Node n, std::vector< Node >& varContains, std::map< Node, bool >& visited ); + static void computeVarContains2( Node n, Kind k, std::vector< Node >& varContains, std::map< Node, bool >& visited ); /** triggers for each operator */ std::map< Node, std::vector< inst::Trigger* > > d_op_triggers; /** helper for is instance of */ @@ -402,6 +410,8 @@ public: static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); /** get var contains for node n */ static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); + /** compute quant contains */ + static void computeQuantContains( Node n, std::vector< Node >& quantContains ); /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ static int isInstanceOf( Node n1, Node n2 ); /** filter all nodes that have instances */ @@ -541,6 +551,10 @@ public: bool isQAttrQuantElim( Node q ); /** is quant elim partial */ bool isQAttrQuantElimPartial( Node q ); + /** get quant id num */ + int getQAttrQuantIdNum( Node q ); + /** get quant id num */ + Node getQAttrQuantIdNumNode( Node q ); /** compute quantifier attributes */ static void computeQuantAttributes( Node q, QAttributes& qa ); };/* class TermDb */ diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index 7ad13b3a8..e97a76ce6 100755 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -88,6 +88,13 @@ void TheoryQuantifiers::presolve() { } } +void TheoryQuantifiers::ppNotifyAssertions( std::vector< Node >& assertions ) { + Trace("quantifiers-presolve") << "TheoryQuantifiers::ppNotifyAssertions" << std::endl; + if( getQuantifiersEngine() ){ + getQuantifiersEngine()->ppNotifyAssertions( assertions ); + } +} + Node TheoryQuantifiers::getValue(TNode n) { //NodeManager* nodeManager = NodeManager::currentNM(); switch(n.getKind()) { diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index 6775e0536..ba5a75d86 100755 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h @@ -61,6 +61,7 @@ public: void notifyEq(TNode lhs, TNode rhs); void preRegisterTerm(TNode n); void presolve(); + void ppNotifyAssertions( std::vector< Node >& assertions ); void check(Effort e); Node getNextDecisionRequest(); Node getValue(TNode n); diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index 2faed3af0..3017238ca 100755 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -76,12 +76,6 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes ) ++(qe->d_statistics.d_multi_triggers); } //Notice() << "Trigger : " << (*this) << " for " << f << std::endl; - if( options::eagerInstQuant() ){ - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Node op = qe->getTermDatabase()->getMatchOperator( d_nodes[i] ); - qe->getTermDatabase()->registerTrigger( this, op ); - } - } Trace("trigger-debug") << "Finished making trigger." << std::endl; } @@ -107,10 +101,6 @@ bool Trigger::getMatch( Node f, Node t, InstMatch& m ){ return ((InstMatchGenerator*)d_mg)->getMatch( f, t, m, d_quantEngine ); } -int Trigger::addTerm( Node t ){ - return d_mg->addTerm( d_f, t, d_quantEngine ); -} - Node Trigger::getInstPattern(){ return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes ); } @@ -363,7 +353,8 @@ bool Trigger::isAtomicTrigger( Node n ){ bool Trigger::isAtomicTriggerKind( Kind k ) { return k==APPLY_UF || k==SELECT || k==STORE || k==APPLY_CONSTRUCTOR || k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER || - k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON; + k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON || + k==SEP_PTO; } bool Trigger::isRelationalTrigger( Node n ) { diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 6d7bf1f4d..631627331 100755 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -72,8 +72,6 @@ class Trigger { Currently the trigger should not be a multi-trigger. */ bool getMatch( Node f, Node t, InstMatch& m); - /** add ground term t, called when t is added to the TermDb */ - int addTerm( Node t ); /** return whether this is a multi-trigger */ bool isMultiTrigger() { return d_nodes.size()>1; } /** get inst pattern list */ diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index c08fee712..67990ef69 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -19,6 +19,7 @@ #include "smt/smt_statistics_registry.h" #include "theory/arrays/theory_arrays.h" #include "theory/datatypes/theory_datatypes.h" +#include "theory/sep/theory_sep.h" #include "theory/quantifiers/alpha_equivalence.h" #include "theory/quantifiers/ambqi_builder.h" #include "theory/quantifiers/bounded_integers.h" @@ -112,6 +113,14 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* d_quant_rel = NULL; } + if( options::quantEpr() ){ + Assert( !options::incrementalSolving() ); + d_qepr = new QuantEPR; + }else{ + d_qepr = NULL; + } + + d_qcf = NULL; d_sg_gen = NULL; d_inst_engine = NULL; @@ -130,7 +139,7 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* d_rel_dom = NULL; d_builder = NULL; - d_trackInstLemmas = options::proof() && options::trackInstLemmas(); + d_trackInstLemmas = options::cbqiNestedQE() || ( options::proof() && options::trackInstLemmas() ); d_total_inst_count_debug = 0; //allow theory combination to go first, once initially @@ -152,6 +161,7 @@ QuantifiersEngine::~QuantifiersEngine(){ delete d_alpha_equiv; delete d_builder; + delete d_qepr; delete d_rr_engine; delete d_bint; delete d_model_engine; @@ -209,21 +219,15 @@ void QuantifiersEngine::finishInit(){ d_sg_gen = new quantifiers::ConjectureGenerator( this, c ); d_modules.push_back( d_sg_gen ); } - //maintain invariant : either InstantiationEngine or ModelEngine must be in d_modules if( !options::finiteModelFind() || options::fmfInstEngine() ){ d_inst_engine = new quantifiers::InstantiationEngine( this ); d_modules.push_back( d_inst_engine ); } if( options::cbqi() ){ - if( options::cbqiSplx() ){ - d_i_cbqi = new quantifiers::InstStrategySimplex( (arith::TheoryArith*)getTheoryEngine()->theoryOf( THEORY_ARITH ), this ); - d_modules.push_back( d_i_cbqi ); - }else{ - d_i_cbqi = new quantifiers::InstStrategyCegqi( this ); - d_modules.push_back( d_i_cbqi ); - if( options::cbqiModel() ){ - needsBuilder = true; - } + d_i_cbqi = new quantifiers::InstStrategyCegqi( this ); + d_modules.push_back( d_i_cbqi ); + if( options::cbqiModel() ){ + needsBuilder = true; } } if( options::ceGuidedInst() ){ @@ -275,7 +279,7 @@ void QuantifiersEngine::finishInit(){ d_modules.push_back( d_fs ); needsRelDom = true; } - + if( needsRelDom ){ d_rel_dom = new quantifiers::RelevantDomain( this, d_model ); d_util.push_back( d_rel_dom ); @@ -343,6 +347,26 @@ void QuantifiersEngine::presolve() { } } +void QuantifiersEngine::ppNotifyAssertions( std::vector< Node >& assertions ) { + Trace("quant-engine-proc") << "ppNotifyAssertions in QE, #assertions = " << assertions.size() << " check epr = " << (d_qepr!=NULL) << std::endl; + if( ( options::instLevelInputOnly() && options::instMaxLevel()!=-1 ) || d_qepr!=NULL ){ + for( unsigned i=0; i<assertions.size(); i++ ) { + if( options::instLevelInputOnly() && options::instMaxLevel()!=-1 ){ + setInstantiationLevelAttr( assertions[i], 0 ); + } + if( d_qepr!=NULL ){ + d_qepr->registerAssertion( assertions[i] ); + } + } + if( d_qepr!=NULL ){ + //must handle sources of other new constants e.g. separation logic + //FIXME: cleanup + ((sep::TheorySep*)getTheoryEngine()->theoryOf( THEORY_SEP ))->initializeBounds(); + d_qepr->finishInit(); + } + } +} + void QuantifiersEngine::check( Theory::Effort e ){ CodeTimer codeTimer(d_statistics.d_time); if( !getMasterEqualityEngine()->consistent() ){ @@ -370,13 +394,6 @@ void QuantifiersEngine::check( Theory::Effort e ){ d_conflict = false; d_hasAddedLemma = false; bool setIncomplete = false; - if( e==Theory::EFFORT_LAST_CALL ){ - //sources of incompleteness - if( d_lte_part_inst && d_lte_part_inst->wasInvoked() ){ - Trace("quant-engine-debug") << "Set incomplete due to LTE partial instantiation." << std::endl; - setIncomplete = true; - } - } bool usedModelBuilder = false; Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl; @@ -519,20 +536,49 @@ void QuantifiersEngine::check( Theory::Effort e ){ } }else if( quant_e==QEFFORT_MODEL ){ if( e==Theory::EFFORT_LAST_CALL ){ + //sources of incompleteness if( !d_recorded_inst.empty() ){ + Trace("quant-engine-debug") << "Set incomplete due to recorded instantiations." << std::endl; setIncomplete = true; } //if we have a chance not to set incomplete if( !setIncomplete ){ setIncomplete = false; //check if we should set the incomplete flag - for( unsigned i=0; i<qm.size(); i++ ){ - if( !qm[i]->checkComplete() ){ - Trace("quant-engine-debug") << "Set incomplete because " << qm[i]->identify().c_str() << " was incomplete." << std::endl; + for( unsigned i=0; i<d_modules.size(); i++ ){ + if( !d_modules[i]->checkComplete() ){ + Trace("quant-engine-debug") << "Set incomplete because " << d_modules[i]->identify().c_str() << " was incomplete." << std::endl; setIncomplete = true; break; } } + if( !setIncomplete ){ + //look at individual quantified formulas, one module must claim completeness for each one + for( unsigned i=0; i<d_model->getNumAssertedQuantifiers(); i++ ){ + bool hasCompleteM = false; + Node q = d_model->getAssertedQuantifier( i ); + QuantifiersModule * qmd = getOwner( q ); + if( qmd!=NULL ){ + hasCompleteM = qmd->checkCompleteFor( q ); + }else{ + for( unsigned j=0; j<d_modules.size(); j++ ){ + if( d_modules[j]->checkCompleteFor( q ) ){ + qmd = d_modules[j]; + hasCompleteM = true; + break; + } + } + } + if( !hasCompleteM ){ + Trace("quant-engine-debug") << "Set incomplete because " << q << " was not fully processed." << std::endl; + setIncomplete = true; + break; + }else{ + Assert( qmd!=NULL ); + Trace("quant-engine-debug2") << "Complete for " << q << " due to " << qmd->identify().c_str() << std::endl; + } + } + } } //if setIncomplete = false, we will answer SAT, otherwise we will run at quant_e QEFFORT_LAST_CALL if( !setIncomplete ){ @@ -598,6 +644,7 @@ void QuantifiersEngine::notifyCombineTheories() { } bool QuantifiersEngine::reduceQuantifier( Node q ) { + //TODO: this can be unified with preregistration: AlphaEquivalence takes ownership of reducable quants BoolMap::const_iterator it = d_quants_red.find( q ); if( it==d_quants_red.end() ){ Node lem; @@ -704,7 +751,7 @@ void QuantifiersEngine::assertQuantifier( Node f, bool pol ){ //register the quantifier, assert it to each module if( registerQuantifier( f ) ){ d_model->assertQuantifier( f ); - for( int i=0; i<(int)d_modules.size(); i++ ){ + for( unsigned i=0; i<d_modules.size(); i++ ){ d_modules[i]->assertNode( f ); } addTermToDatabase( d_term_db->getInstConstantBody( f ), true ); @@ -747,10 +794,7 @@ void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant, bool within if( !d_presolve || !options::incrementalSolving() ){ std::set< Node > added; getTermDatabase()->addTerm( n, added, withinQuant, withinInstClosure ); - //maybe have triggered instantiations if we are doing eager instantiation - if( options::eagerInstQuant() ){ - flushLemmas(); - } + //added contains also the Node that just have been asserted in this branch if( d_quant_rel ){ for( std::set< Node >::iterator i=added.begin(), end=added.end(); i!=end; i++ ){ @@ -840,10 +884,10 @@ void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t lev InstLevelAttribute ila; n.setAttribute(ila,level); Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl; - } - Assert( n.getNumChildren()==qn.getNumChildren() ); - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - setInstantiationLevelAttr( n[i], qn[i], level ); + Assert( n.getNumChildren()==qn.getNumChildren() ); + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + setInstantiationLevelAttr( n[i], qn[i], level ); + } } } } @@ -853,9 +897,9 @@ void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){ InstLevelAttribute ila; n.setAttribute(ila,level); Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl; - } - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - setInstantiationLevelAttr( n[i], level ); + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + setInstantiationLevelAttr( n[i], level ); + } } } @@ -1089,11 +1133,12 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo } if( d_term_db->isEntailed( q[1], subs, false, true ) ){ Trace("inst-add-debug") << " --> Currently entailed." << std::endl; + ++(d_statistics.d_inst_duplicate_ent); return false; } //Node eval = d_term_db->evaluateTerm( q[1], subs, false, true ); - //Trace("ajr-temp") << "Instantiation evaluates to : " << std::endl; - //Trace("ajr-temp") << " " << eval << std::endl; + //Trace("inst-add-debug2") << "Instantiation evaluates to : " << std::endl; + //Trace("inst-add-debug2") << " " << eval << std::endl; } //check for term vector duplication @@ -1109,6 +1154,9 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo Assert( d_term_db->d_vars[q].size()==terms.size() ); Node body = getInstantiation( q, d_term_db->d_vars[q], terms, doVts ); //do virtual term substitution Node orig_body = body; + if( options::cbqiNestedQE() && d_i_cbqi ){ + body = d_i_cbqi->doNestedQE( q, terms, body, doVts ); + } body = quantifiers::QuantifiersRewriter::preprocess( body, true ); Trace("inst-debug") << "...preprocess to " << body << std::endl; @@ -1217,6 +1265,18 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool return addSplit( fm ); } +bool QuantifiersEngine::addEPRAxiom( TypeNode tn ) { + if( d_qepr ){ + Assert( !options::incrementalSolving() ); + if( d_qepr->isEPR( tn ) && !d_qepr->hasEPRAxiom( tn ) ){ + Node lem = d_qepr->mkEPRAxiom( tn ); + Trace("quant-epr") << "EPR lemma for " << tn << " : " << lem << std::endl; + getOutputChannel().lemma( lem ); + } + } + return false; +} + void QuantifiersEngine::markRelevant( Node q ) { d_model->markRelevant( q ); } @@ -1414,62 +1474,120 @@ void QuantifiersEngine::getInstantiations( std::map< Node, std::vector< Node > > } } +void QuantifiersEngine::getInstantiations( Node q, std::vector< Node >& insts ) { + if( options::incrementalSolving() ){ + std::map< Node, inst::CDInstMatchTrie* >::iterator it = d_c_inst_match_trie.find( q ); + if( it!=d_c_inst_match_trie.end() ){ + std::vector< Node > active_lemmas; + it->second->getInstantiations( insts, it->first, this, false, active_lemmas ); + } + }else{ + std::map< Node, inst::InstMatchTrie >::iterator it = d_inst_match_trie.find( q ); + if( it!=d_inst_match_trie.end() ){ + std::vector< Node > active_lemmas; + it->second.getInstantiations( insts, it->first, this, false, active_lemmas ); + } + } +} + +Node QuantifiersEngine::getInstantiatedConjunction( Node q ) { + Assert( q.getKind()==FORALL ); + std::vector< Node > insts; + getInstantiations( q, insts ); + if( insts.empty() ){ + return NodeManager::currentNM()->mkConst(true); + }else{ + Node ret; + if( insts.size()==1 ){ + ret = insts[0]; + }else{ + ret = NodeManager::currentNM()->mkNode( kind::AND, insts ); + } + //have to remove q, TODO: avoid this in a better way + TNode tq = q; + TNode tt = d_term_db->d_true; + ret = ret.substitute( tq, tt ); + return ret; + } +} + QuantifiersEngine::Statistics::Statistics() : d_time("theory::QuantifiersEngine::time"), + d_qcf_time("theory::QuantifiersEngine::time_qcf"), + d_ematching_time("theory::QuantifiersEngine::time_ematching"), d_num_quant("QuantifiersEngine::Num_Quantifiers", 0), d_instantiation_rounds("QuantifiersEngine::Rounds_Instantiation_Full", 0), d_instantiation_rounds_lc("QuantifiersEngine::Rounds_Instantiation_Last_Call", 0), d_instantiations("QuantifiersEngine::Instantiations_Total", 0), d_inst_duplicate("QuantifiersEngine::Duplicate_Inst", 0), d_inst_duplicate_eq("QuantifiersEngine::Duplicate_Inst_Eq", 0), + d_inst_duplicate_ent("QuantifiersEngine::Duplicate_Inst_Entailed", 0), d_triggers("QuantifiersEngine::Triggers", 0), d_simple_triggers("QuantifiersEngine::Triggers_Simple", 0), d_multi_triggers("QuantifiersEngine::Triggers_Multi", 0), d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0), d_red_alpha_equiv("QuantifiersEngine::Reductions_Alpha_Equivalence", 0), - d_red_lte_partial_inst("QuantifiersEngine::Reductions_Lte_Partial_Inst", 0), d_instantiations_user_patterns("QuantifiersEngine::Instantiations_User_Patterns", 0), d_instantiations_auto_gen("QuantifiersEngine::Instantiations_Auto_Gen", 0), d_instantiations_guess("QuantifiersEngine::Instantiations_Guess", 0), - d_instantiations_cbqi_arith("QuantifiersEngine::Instantiations_Cbqi_Arith", 0) + d_instantiations_qcf("QuantifiersEngine::Instantiations_Qcf_Conflict", 0), + d_instantiations_qcf_prop("QuantifiersEngine::Instantiations_Qcf_Prop", 0), + d_instantiations_fmf_exh("QuantifiersEngine::Instantiations_Fmf_Exh", 0), + d_instantiations_fmf_mbqi("QuantifiersEngine::Instantiations_Fmf_Mbqi", 0), + d_instantiations_cbqi("QuantifiersEngine::Instantiations_Cbqi", 0), + d_instantiations_rr("QuantifiersEngine::Instantiations_Rewrite_Rules", 0) { smtStatisticsRegistry()->registerStat(&d_time); + smtStatisticsRegistry()->registerStat(&d_qcf_time); + smtStatisticsRegistry()->registerStat(&d_ematching_time); smtStatisticsRegistry()->registerStat(&d_num_quant); smtStatisticsRegistry()->registerStat(&d_instantiation_rounds); smtStatisticsRegistry()->registerStat(&d_instantiation_rounds_lc); smtStatisticsRegistry()->registerStat(&d_instantiations); smtStatisticsRegistry()->registerStat(&d_inst_duplicate); smtStatisticsRegistry()->registerStat(&d_inst_duplicate_eq); + smtStatisticsRegistry()->registerStat(&d_inst_duplicate_ent); smtStatisticsRegistry()->registerStat(&d_triggers); smtStatisticsRegistry()->registerStat(&d_simple_triggers); smtStatisticsRegistry()->registerStat(&d_multi_triggers); smtStatisticsRegistry()->registerStat(&d_multi_trigger_instantiations); smtStatisticsRegistry()->registerStat(&d_red_alpha_equiv); - smtStatisticsRegistry()->registerStat(&d_red_lte_partial_inst); smtStatisticsRegistry()->registerStat(&d_instantiations_user_patterns); smtStatisticsRegistry()->registerStat(&d_instantiations_auto_gen); smtStatisticsRegistry()->registerStat(&d_instantiations_guess); - smtStatisticsRegistry()->registerStat(&d_instantiations_cbqi_arith); + smtStatisticsRegistry()->registerStat(&d_instantiations_qcf); + smtStatisticsRegistry()->registerStat(&d_instantiations_qcf_prop); + smtStatisticsRegistry()->registerStat(&d_instantiations_fmf_exh); + smtStatisticsRegistry()->registerStat(&d_instantiations_fmf_mbqi); + smtStatisticsRegistry()->registerStat(&d_instantiations_cbqi); + smtStatisticsRegistry()->registerStat(&d_instantiations_rr); } QuantifiersEngine::Statistics::~Statistics(){ smtStatisticsRegistry()->unregisterStat(&d_time); + smtStatisticsRegistry()->unregisterStat(&d_qcf_time); + smtStatisticsRegistry()->unregisterStat(&d_ematching_time); smtStatisticsRegistry()->unregisterStat(&d_num_quant); smtStatisticsRegistry()->unregisterStat(&d_instantiation_rounds); smtStatisticsRegistry()->unregisterStat(&d_instantiation_rounds_lc); smtStatisticsRegistry()->unregisterStat(&d_instantiations); smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate); smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_eq); + smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_ent); smtStatisticsRegistry()->unregisterStat(&d_triggers); smtStatisticsRegistry()->unregisterStat(&d_simple_triggers); smtStatisticsRegistry()->unregisterStat(&d_multi_triggers); smtStatisticsRegistry()->unregisterStat(&d_multi_trigger_instantiations); smtStatisticsRegistry()->unregisterStat(&d_red_alpha_equiv); - smtStatisticsRegistry()->unregisterStat(&d_red_lte_partial_inst); smtStatisticsRegistry()->unregisterStat(&d_instantiations_user_patterns); smtStatisticsRegistry()->unregisterStat(&d_instantiations_auto_gen); smtStatisticsRegistry()->unregisterStat(&d_instantiations_guess); - smtStatisticsRegistry()->unregisterStat(&d_instantiations_cbqi_arith); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_qcf); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_qcf_prop); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_fmf_exh); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_fmf_mbqi); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_cbqi); + smtStatisticsRegistry()->unregisterStat(&d_instantiations_rr); } eq::EqualityEngine* QuantifiersEngine::getMasterEqualityEngine(){ diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 08ca0564b..232d1d889 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -85,6 +85,7 @@ class EqualityQueryQuantifiersEngine; class QuantifiersEngine { friend class quantifiers::InstantiationEngine; + friend class quantifiers::InstStrategyCbqi; friend class quantifiers::InstStrategyCegqi; friend class quantifiers::ModelEngine; friend class quantifiers::RewriteEngine; @@ -113,6 +114,9 @@ private: quantifiers::AlphaEquivalence * d_alpha_equiv; /** model builder */ quantifiers::QModelBuilder* d_builder; + /** utility for effectively propositional logic */ + QuantEPR * d_qepr; +private: /** instantiation engine */ quantifiers::InstantiationEngine* d_inst_engine; /** model engine */ @@ -228,6 +232,8 @@ public: QuantRelevance* getQuantifierRelevance() { return d_quant_rel; } /** get the model builder */ quantifiers::QModelBuilder* getModelBuilder() { return d_builder; } + /** get utility for EPR */ + QuantEPR* getQuantEPR() { return d_qepr; } public: //modules /** get instantiation engine */ quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; } @@ -273,6 +279,8 @@ public: void finishInit(); /** presolve */ void presolve(); + /** notify preprocessed assertion */ + void ppNotifyAssertions( std::vector< Node >& assertions ); /** check at level */ void check( Theory::Effort e ); /** notify that theories were combined */ @@ -325,6 +333,8 @@ public: bool addSplit( Node n, bool reqPhase = false, bool reqPhasePol = true ); /** add split equality */ bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true ); + /** add EPR axiom */ + bool addEPRAxiom( TypeNode tn ); /** mark relevant quantified formula, this will indicate it should be checked before the others */ void markRelevant( Node q ); /** has added lemma */ @@ -365,7 +375,10 @@ public: /** print solution for synthesis conjectures */ void printSynthSolution( std::ostream& out ); /** get instantiations */ + void getInstantiations( Node q, std::vector< Node >& insts ); void getInstantiations( std::map< Node, std::vector< Node > >& insts ); + /** get instantiated conjunction */ + Node getInstantiatedConjunction( Node q ); /** get unsat core lemmas */ bool getUnsatCoreLemmas( std::vector< Node >& active_lemmas ); bool getUnsatCoreLemmas( std::vector< Node >& active_lemmas, std::map< Node, Node >& weak_imp ); @@ -375,22 +388,29 @@ public: class Statistics { public: TimerStat d_time; + TimerStat d_qcf_time; + TimerStat d_ematching_time; IntStat d_num_quant; IntStat d_instantiation_rounds; IntStat d_instantiation_rounds_lc; IntStat d_instantiations; IntStat d_inst_duplicate; IntStat d_inst_duplicate_eq; + IntStat d_inst_duplicate_ent; IntStat d_triggers; IntStat d_simple_triggers; IntStat d_multi_triggers; IntStat d_multi_trigger_instantiations; IntStat d_red_alpha_equiv; - IntStat d_red_lte_partial_inst; IntStat d_instantiations_user_patterns; IntStat d_instantiations_auto_gen; IntStat d_instantiations_guess; - IntStat d_instantiations_cbqi_arith; + IntStat d_instantiations_qcf; + IntStat d_instantiations_qcf_prop; + IntStat d_instantiations_fmf_exh; + IntStat d_instantiations_fmf_mbqi; + IntStat d_instantiations_cbqi; + IntStat d_instantiations_rr; Statistics(); ~Statistics(); };/* class QuantifiersEngine::Statistics */ diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp index dcba4c379..42c6d1219 100644 --- a/src/theory/sep/theory_sep.cpp +++ b/src/theory/sep/theory_sep.cpp @@ -26,6 +26,7 @@ #include "smt/logic_exception.h" #include "theory/quantifiers_engine.h" #include "theory/quantifiers/term_database.h" +#include "options/quantifiers_options.h" using namespace std; @@ -35,6 +36,7 @@ namespace sep { TheorySep::TheorySep(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) : Theory(THEORY_SEP, c, u, out, valuation, logicInfo), + d_lemmas_produced_c(u), d_notify(*this), d_equalityEngine(d_notify, c, "theory::sep::TheorySep", true), d_conflict(c, false), @@ -45,7 +47,8 @@ TheorySep::TheorySep(context::Context* c, context::UserContext* u, OutputChannel { d_true = NodeManager::currentNM()->mkConst<bool>(true); d_false = NodeManager::currentNM()->mkConst<bool>(false); - + d_bounds_init = false; + // The kinds we are treating as function application in congruence d_equalityEngine.addFunctionKind(kind::SEP_PTO); //d_equalityEngine.addFunctionKind(kind::SEP_STAR); @@ -79,47 +82,9 @@ Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) { Node TheorySep::ppRewrite(TNode term) { Trace("sep-pp") << "ppRewrite : " << term << std::endl; -/* - Node s_atom = term.getKind()==kind::NOT ? term[0] : term; - if( s_atom.getKind()==kind::SEP_PTO || s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_EMP ){ - //get the reference type (will compute d_type_references) - int card = 0; - TypeNode tn = getReferenceType( s_atom, card ); - Trace("sep-pp") << " reference type is " << tn << ", card is " << card << std::endl; - } -*/ return term; } -//must process assertions at preprocess so that quantified assertions are processed properly -void TheorySep::processAssertions( std::vector< Node >& assertions ) { - d_pp_nils.clear(); - std::map< Node, bool > visited; - for( unsigned i=0; i<assertions.size(); i++ ){ - processAssertion( assertions[i], visited ); - } -} - -void TheorySep::processAssertion( Node n, std::map< Node, bool >& visited ) { - if( visited.find( n )==visited.end() ){ - visited[n] = true; - if( n.getKind()==kind::SEP_NIL ){ - if( std::find( d_pp_nils.begin(), d_pp_nils.end(), n )==d_pp_nils.end() ){ - d_pp_nils.push_back( n ); - } - }else if( n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_EMP ){ - //get the reference type (will compute d_type_references) - int card = 0; - TypeNode tn = getReferenceType( n, card ); - Trace("sep-pp") << " reference type is " << tn << ", card is " << card << std::endl; - }else{ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - processAssertion( n[i], visited ); - } - } - } -} - Theory::PPAssertStatus TheorySep::ppAssert(TNode in, SubstitutionMap& outSubstitutions) { return PP_ASSERT_STATUS_UNSOLVED; @@ -164,43 +129,6 @@ void TheorySep::explain(TNode literal, std::vector<TNode>& assumptions) { } } -void TheorySep::preRegisterTermRec(TNode t, std::map< TNode, bool >& visited ) { - if( visited.find( t )==visited.end() ){ - visited[t] = true; - Trace("sep-prereg-debug") << "Preregister : " << t << std::endl; - if( t.getKind()==kind::SEP_NIL ){ - Trace("sep-prereg") << "Preregister nil : " << t << std::endl; - //per type, all nil variable references are equal - TypeNode tn = t.getType(); - std::map< TypeNode, Node >::iterator it = d_nil_ref.find( tn ); - if( it==d_nil_ref.end() ){ - Trace("sep-prereg") << "...set as reference." << std::endl; - setNilRef( tn, t ); - }else{ - Node nr = it->second; - Trace("sep-prereg") << "...reference is " << nr << "." << std::endl; - if( t!=nr ){ - if( d_reduce.find( t )==d_reduce.end() ){ - d_reduce.insert( t ); - Node lem = NodeManager::currentNM()->mkNode( tn.isBoolean() ? kind::IFF : kind::EQUAL, t, nr ); - Trace("sep-lemma") << "Sep::Lemma: nil ref eq : " << lem << std::endl; - d_out->lemma( lem ); - } - } - } - }else{ - for( unsigned i=0; i<t.getNumChildren(); i++ ){ - preRegisterTermRec( t[i], visited ); - } - } - } -} - -void TheorySep::preRegisterTerm(TNode term){ - std::map< TNode, bool > visited; - preRegisterTermRec( term, visited ); -} - void TheorySep::propagate(Effort e){ @@ -272,14 +200,12 @@ void TheorySep::computeCareGraph() { ///////////////////////////////////////////////////////////////////////////// -void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel ) -{ +void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel ){ // Send the equality engine information to the model m->assertEqualityEngine( &d_equalityEngine ); - } -void TheorySep::postProcessModel(TheoryModel* m) { +void TheorySep::postProcessModel( TheoryModel* m ){ Trace("sep-model") << "Printing model for TheorySep..." << std::endl; std::vector< Node > sep_children; @@ -291,11 +217,9 @@ void TheorySep::postProcessModel(TheoryModel* m) { Assert( d_loc_to_data_type.find( it->first )!=d_loc_to_data_type.end() ); Trace("sep-model") << "Model for heap, type = " << it->first << " with data type " << d_loc_to_data_type[it->first] << " : " << std::endl; TypeEnumerator te_range( d_loc_to_data_type[it->first] ); - //m->d_comment_str << "Model for heap, type = " << it->first << " : " << std::endl; computeLabelModel( it->second, d_tmodel ); if( d_label_model[it->second].d_heap_locs_model.empty() ){ Trace("sep-model") << " [empty]" << std::endl; - //m->d_comment_str << " [empty]" << std::endl; }else{ for( unsigned j=0; j<d_label_model[it->second].d_heap_locs_model.size(); j++ ){ Assert( d_label_model[it->second].d_heap_locs_model[j].getKind()==kind::SINGLETON ); @@ -304,20 +228,17 @@ void TheorySep::postProcessModel(TheoryModel* m) { Assert( l.isConst() ); pto_children.push_back( l ); Trace("sep-model") << " " << l << " -> "; - //m->d_comment_str << " " << l << " -> "; if( d_pto_model[l].isNull() ){ Trace("sep-model") << "_"; //m->d_comment_str << "_"; pto_children.push_back( *te_range ); }else{ Trace("sep-model") << d_pto_model[l]; - //m->d_comment_str << d_pto_model[l]; Node vpto = d_valuation.getModel()->getRepresentative( d_pto_model[l] ); Assert( vpto.isConst() ); pto_children.push_back( vpto ); } Trace("sep-model") << std::endl; - //m->d_comment_str << std::endl; sep_children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_PTO, pto_children ) ); } } @@ -326,8 +247,6 @@ void TheorySep::postProcessModel(TheoryModel* m) { m_neq = NodeManager::currentNM()->mkNode( nil.getType().isBoolean() ? kind::IFF : kind::EQUAL, nil, vnil ); Trace("sep-model") << "sep.nil = " << vnil << std::endl; Trace("sep-model") << std::endl; - //m->d_comment_str << "sep.nil = " << vnil << std::endl; - //m->d_comment_str << std::endl; if( sep_children.empty() ){ TypeEnumerator te_domain( it->first ); m_heap = NodeManager::currentNM()->mkNode( kind::SEP_EMP, *te_domain ); @@ -337,8 +256,6 @@ void TheorySep::postProcessModel(TheoryModel* m) { m_heap = NodeManager::currentNM()->mkNode( kind::SEP_STAR, sep_children ); } m->setHeapModel( m_heap, m_neq ); - //m->d_comment_str << m->d_sep_heap << std::endl; - //m->d_comment_str << m->d_sep_nil_eq << std::endl; } Trace("sep-model") << "Finished printing model for TheorySep." << std::endl; } @@ -351,13 +268,6 @@ void TheorySep::postProcessModel(TheoryModel* m) { void TheorySep::presolve() { Trace("sep-pp") << "Presolving" << std::endl; //TODO: cleanup if incremental? - - //we must preregister all instances of sep.nil to ensure they are made equal - for( unsigned i=0; i<d_pp_nils.size(); i++ ){ - std::map< TNode, bool > visited; - preRegisterTermRec( d_pp_nils[i], visited ); - } - d_pp_nils.clear(); } @@ -401,9 +311,8 @@ void TheorySep::check(Effort e) { Trace("sep-lemma-debug") << "Reducing unlabelled assertion " << atom << std::endl; d_reduce.insert( fact ); //introduce top-level label, add iff - int card; - TypeNode refType = getReferenceType( s_atom, card ); - Trace("sep-lemma-debug") << "...reference type is : " << refType << ", card is " << card << std::endl; + TypeNode refType = getReferenceType( s_atom ); + Trace("sep-lemma-debug") << "...reference type is : " << refType << std::endl; Node b_lbl = getBaseLabel( refType ); Node s_atom_new = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, s_atom, b_lbl ); Node lem; @@ -428,44 +337,9 @@ void TheorySep::check(Effort e) { if( s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND ){ std::vector< Node > children; std::vector< Node > c_lems; - int card; - TypeNode tn = getReferenceType( s_atom, card ); + TypeNode tn = getReferenceType( s_atom ); Assert( d_reference_bound.find( tn )!=d_reference_bound.end() ); c_lems.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, s_lbl, d_reference_bound[tn] ) ); - if( options::sepPreciseBound() ){ - //more precise bound - Trace("sep-bound") << "Propagate Bound(" << s_lbl << ") = "; - Assert( d_lbl_reference_bound.find( s_lbl )!=d_lbl_reference_bound.end() ); - for( unsigned j=0; j<d_lbl_reference_bound[s_lbl].size(); j++ ){ - Trace("sep-bound") << d_lbl_reference_bound[s_lbl][j] << " "; - } - Trace("sep-bound") << std::endl << " to children of " << s_atom << std::endl; - //int rb_start = 0; - for( unsigned j=0; j<s_atom.getNumChildren(); j++ ){ - int ccard = 0; - getReferenceType( s_atom, ccard, j ); - Node c_lbl = getLabel( s_atom, j, s_lbl ); - Trace("sep-bound") << " for " << c_lbl << ", card = " << ccard << " : "; - std::vector< Node > bound_loc; - bound_loc.insert( bound_loc.end(), d_references[s_atom][j].begin(), d_references[s_atom][j].end() ); -/* //this is unsound - for( int k=0; k<ccard; k++ ){ - Assert( rb_start<(int)d_lbl_reference_bound[s_lbl].size() ); - d_lbl_reference_bound[c_lbl].push_back( d_lbl_reference_bound[s_lbl][rb_start] ); - Trace("sep-bound") << d_lbl_reference_bound[s_lbl][rb_start] << " "; - bound_loc.push_back( d_lbl_reference_bound[s_lbl][rb_start] ); - rb_start++; - } -*/ - //carry all locations for now - bound_loc.insert( bound_loc.end(), d_lbl_reference_bound[s_lbl].begin(), d_lbl_reference_bound[s_lbl].end() ); - Trace("sep-bound") << std::endl; - Node bound_v = mkUnion( tn, bound_loc ); - Trace("sep-bound") << " ...bound value : " << bound_v << std::endl; - children.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, c_lbl, bound_v ) ); - } - Trace("sep-bound") << "Done propagate Bound(" << s_lbl << ")" << std::endl; - } std::vector< Node > labels; getLabelChildren( s_atom, s_lbl, children, labels ); Node empSet = NodeManager::currentNM()->mkConst(EmptySet(s_lbl.getType().toType())); @@ -568,13 +442,9 @@ void TheorySep::check(Effort e) { Trace("sep-assert") << "Done asserting " << atom << " to EE." << std::endl; }else if( s_atom.getKind()==kind::SEP_PTO ){ Node pto_lbl = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] ); - if( polarity && s_lbl!=pto_lbl ){ - //also propagate equality - Node eq = s_lbl.eqNode( pto_lbl ); - Trace("sep-assert") << "Asserting implied equality " << eq << " to EE..." << std::endl; - d_equalityEngine.assertEquality(eq, true, fact); - Trace("sep-assert") << "Done asserting implied equality " << eq << " to EE." << std::endl; - } + Assert( s_lbl==pto_lbl ); + Trace("sep-assert") << "Asserting " << s_atom << std::endl; + d_equalityEngine.assertPredicate(s_atom, polarity, fact); //associate the equivalence class of the lhs with this pto Node r = getRepresentative( s_lbl ); HeapAssertInfo * ei = getOrMakeEqcInfo( r, true ); @@ -595,6 +465,7 @@ void TheorySep::check(Effort e) { d_tmodel.clear(); d_pto_model.clear(); Trace("sep-process") << "---Locations---" << std::endl; + std::map< Node, int > min_id; for( std::map< TypeNode, std::vector< Node > >::iterator itt = d_type_references_all.begin(); itt != d_type_references_all.end(); ++itt ){ for( unsigned k=0; k<itt->second.size(); k++ ){ Node t = itt->second[k]; @@ -602,7 +473,19 @@ void TheorySep::check(Effort e) { if( d_valuation.getModel()->hasTerm( t ) ){ Node v = d_valuation.getModel()->getRepresentative( t ); Trace("sep-process") << v << std::endl; - d_tmodel[v] = t; + //take minimal id + std::map< Node, unsigned >::iterator itrc = d_type_ref_card_id.find( t ); + int tid = itrc==d_type_ref_card_id.end() ? -1 : (int)itrc->second; + bool set_term_model; + if( d_tmodel.find( v )==d_tmodel.end() ){ + set_term_model = true; + }else{ + set_term_model = min_id[v]>tid; + } + if( set_term_model ){ + d_tmodel[v] = t; + min_id[v] = tid; + } }else{ Trace("sep-process") << "?" << std::endl; } @@ -737,8 +620,7 @@ void TheorySep::check(Effort e) { //add refinement lemma if( d_label_map[s_atom].find( s_lbl )!=d_label_map[s_atom].end() ){ needAddLemma = true; - int card; - TypeNode tn = getReferenceType( s_atom, card ); + TypeNode tn = getReferenceType( s_atom ); tn = NodeManager::currentNM()->mkSetType(tn); //tn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(tn)); Node o_b_lbl_mval = d_label_model[s_lbl].getValue( tn ); @@ -885,17 +767,62 @@ TheorySep::HeapAssertInfo * TheorySep::getOrMakeEqcInfo( Node n, bool doMake ) { } } -TypeNode TheorySep::getReferenceType( Node atom, int& card, int index ) { - Trace("sep-type") << "getReference type " << atom << " " << index << std::endl; +//for now, assume all constraints are for the same heap type (ensured by logic exceptions thrown in computeReferenceType2) +TypeNode TheorySep::getReferenceType( Node n ) { + Assert( !d_type_ref.isNull() ); + return d_type_ref; +} + +TypeNode TheorySep::getDataType( Node n ) { + Assert( !d_type_data.isNull() ); + return d_type_data; +} + +//must process assertions at preprocess so that quantified assertions are processed properly +void TheorySep::ppNotifyAssertions( std::vector< Node >& assertions ) { + std::map< Node, bool > visited; + for( unsigned i=0; i<assertions.size(); i++ ){ + Trace("sep-pp") << "Process assertion : " << assertions[i] << std::endl; + processAssertion( assertions[i], visited ); + } + //if data type is unconstrained, assume a fresh uninterpreted sort + if( !d_type_ref.isNull() ){ + if( d_type_data.isNull() ){ + d_type_data = NodeManager::currentNM()->mkSort("_sep_U"); + Trace("sep-type") << "Sep: assume data type " << d_type_data << std::endl; + d_loc_to_data_type[d_type_ref] = d_type_data; + } + } +} + +void TheorySep::processAssertion( Node n, std::map< Node, bool >& visited ) { + if( visited.find( n )==visited.end() ){ + visited[n] = true; + Trace("sep-pp-debug") << "process assertion : " << n << std::endl; + if( n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_EMP ){ + //get the reference type (will compute d_type_references) + int card = 0; + TypeNode tn = computeReferenceType( n, card ); + Trace("sep-pp") << " reference type is " << tn << ", card is " << card << std::endl; + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + processAssertion( n[i], visited ); + } + } + } +} + +TypeNode TheorySep::computeReferenceType( Node atom, int& card, int index ) { + Trace("sep-pp-debug") << "getReference type " << atom << " " << index << std::endl; Assert( atom.getKind()==kind::SEP_PTO || atom.getKind()==kind::SEP_STAR || atom.getKind()==kind::SEP_WAND || atom.getKind()==kind::SEP_EMP || index!=-1 ); std::map< int, TypeNode >::iterator it = d_reference_type[atom].find( index ); if( it==d_reference_type[atom].end() ){ card = 0; - TypeNode tn; + TypeNode tn; if( index==-1 && ( atom.getKind()==kind::SEP_STAR || atom.getKind()==kind::SEP_WAND ) ){ for( unsigned i=0; i<atom.getNumChildren(); i++ ){ int cardc = 0; - TypeNode ctn = getReferenceType( atom, cardc, i ); + TypeNode ctn = computeReferenceType( atom, cardc, i ); if( !ctn.isNull() ){ tn = ctn; } @@ -910,7 +837,7 @@ TypeNode TheorySep::getReferenceType( Node atom, int& card, int index ) { Node n = index==-1 ? atom : atom[index]; //will compute d_references as well std::map< Node, int > visited; - tn = getReferenceType2( atom, card, index, n, visited ); + tn = computeReferenceType2( atom, card, index, n, visited ); } if( tn.isNull() && index==-1 ){ tn = NodeManager::currentNM()->booleanType(); @@ -940,9 +867,9 @@ TypeNode TheorySep::getReferenceType( Node atom, int& card, int index ) { } } -TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited ) { +TypeNode TheorySep::computeReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited ) { if( visited.find( n )==visited.end() ){ - Trace("sep-type-debug") << "visit : " << n << " : " << atom << " " << index << std::endl; + Trace("sep-pp-debug") << "visit : " << n << " : " << atom << " " << index << std::endl; visited[n] = -1; if( n.getKind()==kind::SEP_PTO ){ //TODO: when THEORY_SETS supports mixed Int/Real sets @@ -951,44 +878,34 @@ TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n, TypeNode tn1 = n[0].getType(); TypeNode tn2 = n[1].getType(); if( quantifiers::TermDb::hasBoundVarAttr( n[0] ) ){ - d_reference_bound_invalid[tn1] = true; + if( options::quantEpr() && n[0].getKind()==kind::BOUND_VARIABLE ){ + // still valid : bound on heap models will include Herbrand universe of n[0].getType() + d_reference_bound_fv[tn1] = true; + }else{ + d_reference_bound_invalid[tn1] = true; + Trace("sep-bound") << "reference cannot be bound (due to quantified pto)." << std::endl; + } }else{ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), n[0] )==d_references[atom][index].end() ){ d_references[atom][index].push_back( n[0] ); } } - std::map< TypeNode, TypeNode >::iterator itt = d_loc_to_data_type.find( tn1 ); - if( itt==d_loc_to_data_type.end() ){ - if( !d_loc_to_data_type.empty() ){ - TypeNode te1 = d_loc_to_data_type.begin()->first; - std::stringstream ss; - ss << "ERROR: specifying heap constraints for two different types : " << tn1 << " -> " << tn2 << " and " << te1 << " -> " << d_loc_to_data_type[te1] << std::endl; - throw LogicException(ss.str()); - Assert( false ); - } - Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl; - d_loc_to_data_type[tn1] = tn2; - }else{ - if( itt->second!=tn2 ){ - std::stringstream ss; - ss << "ERROR: location type " << tn1 << " is already associated with data type " << itt->second << ", offending atom is " << atom << " with data type " << tn2 << std::endl; - throw LogicException(ss.str()); - Assert( false ); - } - } + registerRefDataTypes( tn1, tn2, atom ); card = 1; visited[n] = card; return tn1; - //return n[1].getType(); }else if( n.getKind()==kind::SEP_EMP ){ + TypeNode tn = n[0].getType(); + TypeNode tnd; + registerRefDataTypes( tn, tnd, atom ); card = 1; visited[n] = card; - return n[0].getType(); + return tn; }else if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND ){ Assert( n!=atom ); //get the references card = 0; - TypeNode tn = getReferenceType( n, card ); + TypeNode tn = computeReferenceType( n, card ); for( unsigned j=0; j<d_references[n][-1].size(); j++ ){ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), d_references[n][-1][j] )==d_references[atom][index].end() ){ d_references[atom][index].push_back( d_references[n][-1][j] ); @@ -996,12 +913,17 @@ TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n, } visited[n] = card; return tn; + }else if( n.getKind()==kind::SEP_NIL ){ + TypeNode tn = n.getType(); + TypeNode tnd; + registerRefDataTypes( tn, tnd, n ); + return tn; }else{ card = 0; TypeNode otn; for( unsigned i=0; i<n.getNumChildren(); i++ ){ int cardc = 0; - TypeNode tn = getReferenceType2( atom, cardc, index, n[i], visited ); + TypeNode tn = computeReferenceType2( atom, cardc, index, n[i], visited ); if( !tn.isNull() ){ otn = tn; } @@ -1016,27 +938,108 @@ TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n, return TypeNode::null(); } } -/* -int TheorySep::getCardinality( Node n, std::vector< Node >& refs ) { - std::map< Node, int > visited; - return getCardinality2( n, refs, visited ); +void TheorySep::registerRefDataTypes( TypeNode tn1, TypeNode tn2, Node atom ){ + //separation logic is effectively enabled when we find at least one spatial constraint occurs in the input + if( options::incrementalSolving() ){ + std::stringstream ss; + ss << "ERROR: cannot use separation logic in incremental mode." << std::endl; + throw LogicException(ss.str()); + } + std::map< TypeNode, TypeNode >::iterator itt = d_loc_to_data_type.find( tn1 ); + if( itt==d_loc_to_data_type.end() ){ + if( !d_loc_to_data_type.empty() ){ + TypeNode te1 = d_loc_to_data_type.begin()->first; + std::stringstream ss; + ss << "ERROR: specifying heap constraints for two different types : " << tn1 << " -> " << tn2 << " and " << te1 << " -> " << d_loc_to_data_type[te1] << std::endl; + throw LogicException(ss.str()); + Assert( false ); + } + if( tn2.isNull() ){ + Trace("sep-type") << "Sep: assume location type " << tn1 << " (from " << atom << ")" << std::endl; + }else{ + Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl; + } + d_loc_to_data_type[tn1] = tn2; + //for now, we only allow heap constraints of one type + d_type_ref = tn1; + d_type_data = tn2; + }else{ + if( !tn2.isNull() ){ + if( itt->second!=tn2 ){ + if( itt->second.isNull() ){ + Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl; + //now we know data type + d_loc_to_data_type[tn1] = tn2; + d_type_data = tn2; + }else{ + std::stringstream ss; + ss << "ERROR: location type " << tn1 << " is already associated with data type " << itt->second << ", offending atom is " << atom << " with data type " << tn2 << std::endl; + throw LogicException(ss.str()); + Assert( false ); + } + } + } + } } -int TheorySep::getCardinality2( Node n, std::vector< Node >& refs, std::map< Node, int >& visited ) { - std::map< Node, int >::iterator it = visited.find( n ); - if( it!=visited.end() ){ - return it->second; - }else{ - - +void TheorySep::initializeBounds() { + if( !d_bounds_init ){ + Trace("sep-bound") << "Initialize sep bounds..." << std::endl; + d_bounds_init = true; + for( std::map< TypeNode, TypeNode >::iterator it = d_loc_to_data_type.begin(); it != d_loc_to_data_type.end(); ++it ){ + TypeNode tn = it->first; + Trace("sep-bound") << "Initialize bounds for " << tn << "..." << std::endl; + QuantEPR * qepr = getLogicInfo().isQuantified() ? getQuantifiersEngine()->getQuantEPR() : NULL; + //if pto had free variable reference + if( d_reference_bound_invalid.find( tn )==d_reference_bound_invalid.end() ){ + if( d_reference_bound_fv.find( tn )!=d_reference_bound_fv.end() ){ + //include Herbrand universe of tn + if( qepr && qepr->isEPR( tn ) ){ + for( unsigned j=0; j<qepr->d_consts[tn].size(); j++ ){ + Node k = qepr->d_consts[tn][j]; + if( std::find( d_type_references[tn].begin(), d_type_references[tn].end(), k )==d_type_references[tn].end() ){ + d_type_references[tn].push_back( k ); + } + } + }else{ + d_reference_bound_invalid[tn] = true; + Trace("sep-bound") << "reference cannot be bound (due to non-EPR variable)." << std::endl; + } + } + } + unsigned n_emp = 0; + if( d_reference_bound_invalid.find( tn )==d_reference_bound_invalid.end() ){ + n_emp = d_card_max[tn]>d_card_max[TypeNode::null()] ? d_card_max[tn] : d_card_max[TypeNode::null()]; + }else if( d_type_references[tn].empty() ){ + //must include at least one constant + n_emp = 1; + } + Trace("sep-bound") << "Constructing " << n_emp << " cardinality constants." << std::endl; + for( unsigned r=0; r<n_emp; r++ ){ + Node e = NodeManager::currentNM()->mkSkolem( "e", tn, "cardinality bound element for seplog" ); + d_type_references_card[tn].push_back( e ); + d_type_ref_card_id[e] = r; + //must include this constant back into EPR handling + if( qepr && qepr->isEPR( tn ) ){ + qepr->addEPRConstant( tn, e ); + } + } + //EPR must include nil ref + if( qepr && qepr->isEPR( tn ) ){ + Node nr = getNilRef( tn ); + if( !qepr->isEPRConstant( tn, nr ) ){ + qepr->addEPRConstant( tn, nr ); + } + } + } } } -*/ Node TheorySep::getBaseLabel( TypeNode tn ) { std::map< TypeNode, Node >::iterator it = d_base_label.find( tn ); if( it==d_base_label.end() ){ + initializeBounds(); Trace("sep") << "Make base label for " << tn << std::endl; std::stringstream ss; ss << "__Lb"; @@ -1050,35 +1053,62 @@ Node TheorySep::getBaseLabel( TypeNode tn ) { ss2 << "__Lu"; d_reference_bound[tn] = NodeManager::currentNM()->mkSkolem( ss2.str(), ltn, "" ); d_type_references_all[tn].insert( d_type_references_all[tn].end(), d_type_references[tn].begin(), d_type_references[tn].end() ); + + //check whether monotonic (elements can be added to tn without effecting satisfiability) + bool tn_is_monotonic = true; + if( tn.isSort() ){ + //TODO: use monotonicity inference + tn_is_monotonic = !getLogicInfo().isQuantified(); + }else{ + tn_is_monotonic = tn.getCardinality().isInfinite(); + } //add a reference type for maximum occurrences of empty in a constraint - unsigned n_emp = d_card_max[tn]>d_card_max[TypeNode::null()] ? d_card_max[tn] : d_card_max[TypeNode::null()]; - for( unsigned r=0; r<n_emp; r++ ){ - Node e = NodeManager::currentNM()->mkSkolem( "e", tn, "cardinality bound element for seplog" ); - //d_type_references_all[tn].push_back( NodeManager::currentNM()->mkSkolem( "e", NodeManager::currentNM()->mkRefType(tn) ) ); - if( options::sepDisequalC() ){ + if( options::sepDisequalC() && tn_is_monotonic ){ + for( unsigned r=0; r<d_type_references_card[tn].size(); r++ ){ + Node e = d_type_references_card[tn][r]; //ensure that it is distinct from all other references so far for( unsigned j=0; j<d_type_references_all[tn].size(); j++ ){ Node eq = NodeManager::currentNM()->mkNode( e.getType().isBoolean() ? kind::IFF : kind::EQUAL, e, d_type_references_all[tn][j] ); d_out->lemma( eq.negate() ); } + d_type_references_all[tn].push_back( e ); } - d_type_references_all[tn].push_back( e ); - d_lbl_reference_bound[d_base_label[tn]].push_back( e ); + }else{ + //break symmetries TODO + + d_type_references_all[tn].insert( d_type_references_all[tn].end(), d_type_references_card[tn].begin(), d_type_references_card[tn].end() ); } - //construct bound - d_reference_bound_max[tn] = mkUnion( tn, d_type_references_all[tn] ); - Trace("sep-bound") << "overall bound for " << d_base_label[tn] << " : " << d_reference_bound_max[tn] << std::endl; + Assert( !d_type_references_all[tn].empty() ); + + if( d_reference_bound_invalid.find( tn )==d_reference_bound_invalid.end() ){ + //construct bound + d_reference_bound_max[tn] = mkUnion( tn, d_type_references_all[tn] ); + Trace("sep-bound") << "overall bound for " << d_base_label[tn] << " : " << d_reference_bound_max[tn] << std::endl; - if( d_reference_bound_invalid.find( tn )==d_reference_bound_invalid.end() ){ Node slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_reference_bound[tn], d_reference_bound_max[tn] ); Trace("sep-lemma") << "Sep::Lemma: reference bound for " << tn << " : " << slem << std::endl; d_out->lemma( slem ); - }else{ - Trace("sep-bound") << "reference cannot be bound (possibly due to quantified pto)." << std::endl; + //slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_base_label[tn], d_reference_bound_max[tn] ); + //Trace("sep-lemma") << "Sep::Lemma: base reference bound for " << tn << " : " << slem << std::endl; + //d_out->lemma( slem ); + + //symmetry breaking + std::map< unsigned, Node > lit_mem_map; + for( unsigned i=0; i<d_type_references_card[tn].size(); i++ ){ + lit_mem_map[i] = NodeManager::currentNM()->mkNode( kind::MEMBER, d_type_references_card[tn][i], d_reference_bound[tn]); + } + for( unsigned i=0; i<(d_type_references_card[tn].size()-1); i++ ){ + std::vector< Node > children; + for( unsigned j=(i+1); j<d_type_references_card[tn].size(); j++ ){ + children.push_back( lit_mem_map[j].negate() ); + } + Assert( !children.empty() ); + Node sym_lem = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ); + sym_lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, lit_mem_map[i].negate(), sym_lem ); + Trace("sep-lemma") << "Sep::Lemma: symmetry breaking lemma : " << sym_lem << std::endl; + d_out->lemma( sym_lem ); + } } - //slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_base_label[tn], d_reference_bound_max[tn] ); - //Trace("sep-lemma") << "Sep::Lemma: base reference bound for " << tn << " : " << slem << std::endl; - //d_out->lemma( slem ); //assert that nil ref is not in base label Node nr = getNilRef( tn ); @@ -1095,7 +1125,7 @@ Node TheorySep::getBaseLabel( TypeNode tn ) { Node TheorySep::getNilRef( TypeNode tn ) { std::map< TypeNode, Node >::iterator it = d_nil_ref.find( tn ); if( it==d_nil_ref.end() ){ - Node nil = NodeManager::currentNM()->mkSepNil( tn ); + Node nil = NodeManager::currentNM()->mkUniqueVar( tn, kind::SEP_NIL ); setNilRef( tn, nil ); return nil; }else{ @@ -1132,7 +1162,7 @@ Node TheorySep::getLabel( Node atom, int child, Node lbl ) { std::map< int, Node >::iterator it = d_label_map[atom][lbl].find( child ); if( it==d_label_map[atom][lbl].end() ){ int card; - TypeNode refType = getReferenceType( atom, card ); + TypeNode refType = computeReferenceType( atom, card ); std::stringstream ss; ss << "__Lc" << child; TypeNode ltn = NodeManager::currentNM()->mkSetType(refType); @@ -1372,7 +1402,6 @@ void TheorySep::computeLabelModel( Node lbl, std::map< Node, Node >& tmodel ) { Assert( false ); } } - //end hack for( unsigned j=0; j<d_label_model[lbl].d_heap_locs_model.size(); j++ ){ Node u = d_label_model[lbl].d_heap_locs_model[j]; Assert( u.getKind()==kind::SINGLETON ); @@ -1386,7 +1415,8 @@ void TheorySep::computeLabelModel( Node lbl, std::map< Node, Node >& tmodel ) { //TypeNode tn = u.getType().getRefConstituentType(); TypeNode tn = u.getType(); Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << ", cref type " << tn << std::endl; - Assert( d_type_references_all.find( tn )!=d_type_references_all.end() && !d_type_references_all[tn].empty() ); + Assert( d_type_references_all.find( tn )!=d_type_references_all.end() ); + Assert( !d_type_references_all[tn].empty() ); tt = d_type_references_all[tn][0]; }else{ tt = itm->second; @@ -1489,7 +1519,11 @@ void TheorySep::addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ) Assert( areEqual( pb[1], p[1] ) ); std::vector< Node > exp; if( pb[1]!=p[1] ){ + //if( pb[1].getKind()==kind::SINGLETON && p[1].getKind()==kind::SINGLETON ){ + // exp.push_back( pb[1][0].eqNode( p[1][0] ) ); + //}else{ exp.push_back( pb[1].eqNode( p[1] ) ); + //} } exp.push_back( pb ); exp.push_back( p.negate() ); @@ -1497,10 +1531,12 @@ void TheorySep::addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ) if( pb[0][1]!=p[0][1] ){ conc.push_back( pb[0][1].eqNode( p[0][1] ).negate() ); } - if( pb[1]!=p[1] ){ - conc.push_back( pb[1].eqNode( p[1] ).negate() ); - } + //if( pb[1]!=p[1] ){ + // conc.push_back( pb[1].eqNode( p[1] ).negate() ); + //} Node n_conc = conc.empty() ? d_false : ( conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::OR, conc ) ); + Trace("sep-pto") << "Conclusion is " << n_conc << std::endl; + // propagation for (pto x y) ^ ~(pto z w) ^ x = z => y != w sendLemma( exp, n_conc, "PTO_NEG_PROP" ); } }else{ @@ -1525,6 +1561,7 @@ void TheorySep::mergePto( Node p1, Node p2 ) { } exp.push_back( p1 ); exp.push_back( p2 ); + //enforces injectiveness of pto : (pto x y) ^ (pto y w) ^ x = y => y = w sendLemma( exp, p1[0][1].eqNode( p2[0][1] ), "PTO_PROP" ); } } @@ -1598,8 +1635,11 @@ void TheorySep::doPendingFacts() { } int index = d_pending_lem[i]; Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, d_pending_exp[index], d_pending[index] ); - d_out->lemma( lem ); - Trace("sep-pending") << "Sep : Lemma : " << lem << std::endl; + if( d_lemmas_produced_c.find( lem )==d_lemmas_produced_c.end() ){ + d_lemmas_produced_c.insert( lem ); + d_out->lemma( lem ); + Trace("sep-pending") << "Sep : Lemma : " << lem << std::endl; + } } } d_pending_exp.clear(); diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h index 29e7a008c..982fc3c70 100644 --- a/src/theory/sep/theory_sep.h +++ b/src/theory/sep/theory_sep.h @@ -44,6 +44,8 @@ class TheorySep : public Theory { ///////////////////////////////////////////////////////////////////////////// private: + /** all lemmas sent */ + NodeSet d_lemmas_produced_c; /** True node for predicates = true */ Node d_true; @@ -51,7 +53,8 @@ class TheorySep : public Theory { /** True node for predicates = false */ Node d_false; - std::vector< Node > d_pp_nils; + //whether bounds have been initialized + bool d_bounds_init; Node mkAnd( std::vector< TNode >& assumptions ); @@ -75,7 +78,7 @@ class TheorySep : public Theory { PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions); Node ppRewrite(TNode atom); - void processAssertions( std::vector< Node >& assertions ); + void ppNotifyAssertions( std::vector< Node >& assertions ); ///////////////////////////////////////////////////////////////////////////// // T-PROPAGATION / REGISTRATION ///////////////////////////////////////////////////////////////////////////// @@ -88,10 +91,8 @@ class TheorySep : public Theory { /** Explain why this literal is true by adding assumptions */ void explain(TNode literal, std::vector<TNode>& assumptions); - void preRegisterTermRec(TNode t, std::map< TNode, bool >& visited ); public: - void preRegisterTerm(TNode t); void propagate(Effort e); Node explain(TNode n); @@ -208,6 +209,9 @@ class TheorySep : public Theory { NodeList d_infer_exp; NodeList d_spatial_assertions; + //data,ref type (globally fixed) + TypeNode d_type_ref; + TypeNode d_type_data; //currently fix one data type for each location type, throw error if using more than one std::map< TypeNode, TypeNode > d_loc_to_data_type; //information about types @@ -217,11 +221,12 @@ class TheorySep : public Theory { std::map< TypeNode, Node > d_reference_bound; std::map< TypeNode, Node > d_reference_bound_max; std::map< TypeNode, bool > d_reference_bound_invalid; + std::map< TypeNode, bool > d_reference_bound_fv; std::map< TypeNode, std::vector< Node > > d_type_references; + std::map< TypeNode, std::vector< Node > > d_type_references_card; + std::map< Node, unsigned > d_type_ref_card_id; std::map< TypeNode, std::vector< Node > > d_type_references_all; std::map< TypeNode, unsigned > d_card_max; - //bounds for labels - std::map< Node, std::vector< Node > > d_lbl_reference_bound; //for empty argument std::map< TypeNode, Node > d_emp_arg; //map from ( atom, label, child index ) -> label @@ -242,9 +247,14 @@ class TheorySep : public Theory { std::map< Node, HeapAssertInfo * > d_eqc_info; HeapAssertInfo * getOrMakeEqcInfo( Node n, bool doMake = false ); + //get global reference/data type + TypeNode getReferenceType( Node n ); + TypeNode getDataType( Node n ); //calculate the element type of the heap for spatial assertions - TypeNode getReferenceType( Node atom, int& card, int index = -1 ); - TypeNode getReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited); + TypeNode computeReferenceType( Node atom, int& card, int index = -1 ); + TypeNode computeReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited); + void registerRefDataTypes( TypeNode tn1, TypeNode tn2, Node atom ); + //get location/data type //get the base label for the spatial assertion Node getBaseLabel( TypeNode tn ); Node getNilRef( TypeNode tn ); @@ -291,6 +301,7 @@ public: return &d_equalityEngine; } + void initializeBounds(); };/* class TheorySep */ }/* CVC4::theory::sep namespace */ diff --git a/src/theory/sets/normal_form.h b/src/theory/sets/normal_form.h index 6da7e9f8f..c1f05ae85 100644 --- a/src/theory/sets/normal_form.h +++ b/src/theory/sets/normal_form.h @@ -24,58 +24,64 @@ namespace theory { namespace sets { class NormalForm { -public: - - template<bool ref_count> - static Node elementsToSet(std::set<NodeTemplate<ref_count> > elements, TypeNode setType) - { + public: + template <bool ref_count> + static Node elementsToSet(const std::set<NodeTemplate<ref_count> >& elements, + TypeNode setType) { + typedef typename std::set<NodeTemplate<ref_count> >::const_iterator + ElementsIterator; NodeManager* nm = NodeManager::currentNM(); - - if(elements.size() == 0) { + if (elements.size() == 0) { return nm->mkConst(EmptySet(nm->toType(setType))); } else { - typeof(elements.begin()) it = elements.begin(); + ElementsIterator it = elements.begin(); Node cur = nm->mkNode(kind::SINGLETON, *it); - while( ++it != elements.end() ) { - cur = nm->mkNode(kind::UNION, cur, - nm->mkNode(kind::SINGLETON, *it)); + while (++it != elements.end()) { + cur = nm->mkNode(kind::UNION, cur, nm->mkNode(kind::SINGLETON, *it)); } return cur; } } static bool checkNormalConstant(TNode n) { - Debug("sets-checknormal") << "[sets-checknormal] checkNormal " << n << " :" << std::endl; - if(n.getKind() == kind::EMPTYSET) { + Debug("sets-checknormal") << "[sets-checknormal] checkNormal " << n << " :" + << std::endl; + if (n.getKind() == kind::EMPTYSET) { return true; - } else if(n.getKind() == kind::SINGLETON) { + } else if (n.getKind() == kind::SINGLETON) { return n[0].isConst(); - } else if(n.getKind() == kind::UNION) { - - // assuming (union ... (union {SmallestNodeID} {BiggerNodeId}) ... {BiggestNodeId}) + } else if (n.getKind() == kind::UNION) { + // assuming (union ... (union {SmallestNodeID} {BiggerNodeId}) ... + // {BiggestNodeId}) // store BiggestNodeId in prvs - if(n[1].getKind() != kind::SINGLETON) return false; - if( !n[1][0].isConst() ) return false; - Debug("sets-checknormal") << "[sets-checknormal] frst element = " << n[1][0] << " " << n[1][0].getId() << std::endl; + if (n[1].getKind() != kind::SINGLETON) return false; + if (!n[1][0].isConst()) return false; + Debug("sets-checknormal") + << "[sets-checknormal] frst element = " << n[1][0] << " " + << n[1][0].getId() << std::endl; TNode prvs = n[1][0]; n = n[0]; // check intermediate nodes - while(n.getKind() == kind::UNION) { - if(n[1].getKind() != kind::SINGLETON) return false; - if( !n[1].isConst() ) return false; - Debug("sets-checknormal") << "[sets-checknormal] element = " << n[1][0] << " " << n[1][0].getId() << std::endl; - if( n[1][0] >= prvs ) return false; - TNode prvs = n[1][0]; - n = n[0]; + while (n.getKind() == kind::UNION) { + if (n[1].getKind() != kind::SINGLETON) return false; + if (!n[1].isConst()) return false; + Debug("sets-checknormal") + << "[sets-checknormal] element = " << n[1][0] << " " + << n[1][0].getId() << std::endl; + if (n[1][0] >= prvs) return false; + TNode prvs = n[1][0]; + n = n[0]; } // check SmallestNodeID is smallest - if(n.getKind() != kind::SINGLETON) return false; - if( !n[0].isConst() ) return false; - Debug("sets-checknormal") << "[sets-checknormal] lst element = " << n[0] << " " << n[0].getId() << std::endl; - if( n[0] >= prvs ) return false; + if (n.getKind() != kind::SINGLETON) return false; + if (!n[0].isConst()) return false; + Debug("sets-checknormal") + << "[sets-checknormal] lst element = " << n[0] << " " + << n[0].getId() << std::endl; + if (n[0] >= prvs) return false; // we made it return true; @@ -88,10 +94,10 @@ public: static std::set<Node> getElementsFromNormalConstant(TNode n) { Assert(n.isConst()); std::set<Node> ret; - if(n.getKind() == kind::EMPTYSET) { + if (n.getKind() == kind::EMPTYSET) { return ret; } - while(n.getKind() == kind::UNION) { + while (n.getKind() == kind::UNION) { Assert(n[1].getKind() == kind::SINGLETON); ret.insert(ret.begin(), n[1][0]); n = n[0]; @@ -100,9 +106,7 @@ public: ret.insert(n[0]); return ret; } - }; - } } } diff --git a/src/theory/sets/scrutinize.h b/src/theory/sets/scrutinize.h index 2ada4a3ce..88f6001b9 100644 --- a/src/theory/sets/scrutinize.h +++ b/src/theory/sets/scrutinize.h @@ -17,8 +17,6 @@ #pragma once -#include <boost/foreach.hpp> - #include "theory/sets/theory_sets.h" #include "theory/sets/theory_sets_private.h" @@ -55,7 +53,8 @@ public: } } bool checkPassed = true; - BOOST_FOREACH(TNode term, terms) { + for (std::set<Node>::const_iterator it = terms.begin(); it != terms.end(); it++){ + TNode term = *it; if( term.getType().isSet() ) { checkPassed &= d_theory->checkModel(settermElementsMap, term); } @@ -72,4 +71,3 @@ public: }/* CVC4::theory::sets namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ - diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index aec2c119c..e996cb215 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -218,7 +218,7 @@ void TheorySetsPrivate::assertMemebership(TNode fact, TNode reason, bool learnt) if(x.getType().isSet()) { if(polarity) { const CDTNodeList* l = d_termInfoManager->getNonMembers(S); - for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + for(CDTNodeList::iterator it = l->begin(); it != l->end(); ++it) { TNode n = *it; learnLiteral( /* atom = */ EQUAL(x, n), /* polarity = */ false, @@ -226,7 +226,7 @@ void TheorySetsPrivate::assertMemebership(TNode fact, TNode reason, bool learnt) } } else { const CDTNodeList* l = d_termInfoManager->getMembers(S); - for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + for(CDTNodeList::iterator it = l->begin(); it != l->end(); ++it) { TNode n = *it; learnLiteral( /* atom = */ EQUAL(x, n), /* polarity = */ false, @@ -255,7 +255,7 @@ void TheorySetsPrivate::assertMemebership(TNode fact, TNode reason, bool learnt) Debug("sets-prop") << "[sets-prop] Propagating 'up' for " << x << element_of_str << S << std::endl; const CDTNodeList* parentList = d_termInfoManager->getParents(S); - for(typeof(parentList->begin()) k = parentList->begin(); + for(CDTNodeList::const_iterator k = parentList->begin(); k != parentList->end(); ++k) { doSettermPropagation(x, *k); if(d_conflict) return; @@ -475,9 +475,15 @@ void TheorySetsPrivate::dumpAssertionsHumanified() const context::CDList<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end(); - std::map<TNode, std::set<TNode> > equalities; - std::set< pair<TNode, TNode> > disequalities; - std::map<TNode, std::pair<std::set<TNode>, std::set<TNode> > > members; + typedef std::set<TNode> TNodeSet; + + typedef std::map<TNode, TNodeSet > EqualityMap; + EqualityMap equalities; + + typedef std::set< std::pair<TNode, TNode> > TNodePairSet; + TNodePairSet disequalities; + typedef std::map<TNode, std::pair<TNodeSet, TNodeSet > > MemberMap; + MemberMap members; static std::map<TNode, int> numbering; static int number = 0; @@ -504,10 +510,11 @@ void TheorySetsPrivate::dumpAssertionsHumanified() const (polarity ? members[right].first : members[right].second).insert(left); } } -#define FORIT(it, container) for(typeof((container).begin()) it=(container).begin(); (it) != (container).end(); ++(it)) - FORIT(kt, equalities) { + for(EqualityMap::const_iterator kt =equalities.begin(); kt != equalities.end(); ++kt) { Trace(tag) << " Eq class of t" << numbering[(*kt).first] << ": " << std::endl; - FORIT(jt, (*kt).second) { + + const TNodeSet& kt_second = (*kt).second; + for(TNodeSet::const_iterator jt=kt_second.begin(); jt != kt_second.end(); ++jt) { TNode S = (*jt); if( S.getKind() != kind::UNION && S.getKind() != kind::INTERSECTION && S.getKind() != kind::SETMINUS) { Trace(tag) << " " << *jt << ((*jt).getType().isSet() ? "\n": " "); @@ -529,11 +536,17 @@ void TheorySetsPrivate::dumpAssertionsHumanified() const } Trace(tag) << std::endl; } - FORIT(kt, disequalities) Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl; - FORIT(kt, members) { - if( (*kt).second.first.size() > 0) { - Trace(tag) << "IN t" << numbering[(*kt).first] << ": "; - FORIT(jt, (*kt).second.first) { + for(TNodePairSet::const_iterator kt=disequalities.begin(); kt != disequalities.end(); ++kt){ + Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl; + } + for(MemberMap::const_iterator kt=members.begin(); kt != members.end(); ++kt) { + const TNode& kt_key = (*kt).first; + const TNodeSet& kt_in_set = (*kt).second.first; + const TNodeSet& kt_out_set = (*kt).second.first; + if( kt_in_set.size() > 0) { + Trace(tag) << "IN t" << numbering[kt_key] << ": "; + //FORIT(jt, (*kt).second.first) + for(TNodeSet::const_iterator jt=kt_in_set.begin(); jt != kt_in_set.end(); ++jt) { TNode x = (*jt); if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) { Trace(tag) << x << ", "; @@ -543,9 +556,9 @@ void TheorySetsPrivate::dumpAssertionsHumanified() const } Trace(tag) << std::endl; } - if( (*kt).second.second.size() > 0) { - Trace(tag) << "NOT IN t" << numbering[(*kt).first] << ": "; - FORIT(jt, (*kt).second.second) { + if( kt_out_set.size() > 0) { + Trace(tag) << "NOT IN t" << numbering[kt_key] << ": "; + for(TNodeSet::const_iterator jt=kt_out_set.begin(); jt != kt_out_set.end(); ++jt){ TNode x = (*jt); if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) { Trace(tag) << x << ", "; @@ -557,7 +570,6 @@ void TheorySetsPrivate::dumpAssertionsHumanified() const } } Trace(tag) << std::endl; -#undef FORIT } void TheorySetsPrivate::computeCareGraph() { @@ -871,14 +883,15 @@ Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) con return cur; } } -Node TheorySetsPrivate::elementsToShape(set<Node> elements, TypeNode setType) const + +Node TheorySetsPrivate::elementsToShape(std::set<Node> elements, TypeNode setType) const { NodeManager* nm = NodeManager::currentNM(); if(elements.size() == 0) { return nm->mkConst<EmptySet>(EmptySet(nm->toType(setType))); } else { - typeof(elements.begin()) it = elements.begin(); + std::set<Node>::const_iterator it = elements.begin(); Node cur = SINGLETON(*it); while( ++it != elements.end() ) { cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it)); @@ -892,13 +905,13 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) Trace("sets-model") << "[sets-model] collectModelInfo(..., fullModel=" << (fullModel ? "true)" : "false)") << std::endl; - set<Node> terms; + std::set<Node> terms; NodeManager* nm = NodeManager::currentNM(); // // this is for processCard -- commenting out for now // if(Debug.isOn("sets-card")) { - // for(typeof(d_cardTerms.begin()) it = d_cardTerms.begin(); + // for(CDNodeSet::const_iterator it = d_cardTerms.begin(); // it != d_cardTerms.end(); ++it) { // Debug("sets-card") << "[sets-card] " << *it << " = " // << d_external.d_valuation.getModelValue(*it) @@ -915,7 +928,8 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) //processCard2 begin if(Debug.isOn("sets-card")) { - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + print_graph(true); + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { Node n = nm->mkNode(kind::CARD, *it); Debug("sets-card") << "[sets-card] " << n << " = "; // if(d_external.d_sharedTerms.find(n) == d_external.d_sharedTerms.end()) continue; @@ -1005,7 +1019,7 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) //processCard2 begin leaves.clear(); - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) if(d_E.find(*it) == d_E.end()) leaves.insert(*it); d_statistics.d_numLeaves.setData(leaves.size()); @@ -1102,7 +1116,7 @@ Node mkAnd(const std::vector<TNode>& conjunctions) { if (t.getKind() == kind::AND) { for(TNode::iterator child_it = t.begin(); child_it != t.end(); ++child_it) { - Assert((*child_it).getKind() != kind::AND); + // Assert((*child_it).getKind() != kind::AND); all.insert(*child_it); } } @@ -1311,15 +1325,20 @@ Node TheorySetsPrivate::getLemma() { Assert(n.getKind() == kind::EQUAL && n[0].getType().isSet()); TypeNode elementType = n[0].getType().getSetElementType(); - Node x = NodeManager::currentNM()->mkSkolem("sde_", elementType); - Node l1 = MEMBER(x, n[0]), l2 = MEMBER(x, n[1]); - - if(n[0].getKind() == kind::EMPTYSET) { - lemma = OR(n, l2); - } else if(n[1].getKind() == kind::EMPTYSET) { - lemma = OR(n, l1); - } else { - lemma = OR(n, AND(l1, NOT(l2)), AND(NOT(l1), l2)); + // { x } != { y } => x != y + if( n[0].getKind()==kind::SINGLETON && n[1].getKind()==kind::SINGLETON ){ + lemma = OR(n, NodeManager::currentNM()->mkNode( elementType.isBoolean() ? kind::IFF : kind::EQUAL, n[0][0], n[1][0] ).negate() ); + }else{ + Node x = NodeManager::currentNM()->mkSkolem("sde_", elementType); + Node l1 = MEMBER(x, n[0]), l2 = MEMBER(x, n[1]); + + if(n[0].getKind() == kind::EMPTYSET) { + lemma = OR(n, l2); + } else if(n[1].getKind() == kind::EMPTYSET) { + lemma = OR(n, l1); + } else { + lemma = OR(n, AND(l1, NOT(l2)), AND(NOT(l1), l2)); + } } } @@ -1412,7 +1431,7 @@ void TheorySetsPrivate::propagate(Theory::Effort effort) { } const CDNodeSet& terms = (d_termInfoManager->d_terms); - for(typeof(terms.key_begin()) it = terms.key_begin(); it != terms.key_end(); ++it) { + for(CDNodeSet::key_iterator it = terms.key_begin(); it != terms.key_end(); ++it) { Node node = (*it); Kind k = node.getKind(); if(k == kind::UNION && node[0].getKind() == kind::SINGLETON ) { @@ -1496,7 +1515,11 @@ Node TheorySetsPrivate::explain(TNode literal) Unhandled(); } - return mkAnd(assumptions); + if(assumptions.size()) { + return mkAnd(assumptions); + } else { + return d_trueNode; + } } bool TheorySetsPrivate::lemma(Node n, SetsLemmaTag t) @@ -1568,14 +1591,14 @@ void TheorySetsPrivate::preRegisterTerm(TNode node) void TheorySetsPrivate::presolve() { - for(typeof(d_termInfoManager->d_terms.begin()) it = d_termInfoManager->d_terms.begin(); + for(CDNodeSet::const_iterator it = d_termInfoManager->d_terms.begin(); it != d_termInfoManager->d_terms.end(); ++it) { d_relTerms.insert(*it); } if(Trace.isOn("sets-relterms")) { Trace("sets-relterms") << "[sets-relterms] "; - for(typeof(d_relTerms.begin()) it = d_relTerms.begin(); + for(CDNodeSet::const_iterator it = d_relTerms.begin(); it != d_relTerms.end(); ++it ) { Trace("sets-relterms") << (*it) << ", "; } @@ -1672,18 +1695,18 @@ void TheorySetsPrivate::TermInfoManager::mergeLists } } -TheorySetsPrivate::TermInfoManager::TermInfoManager -(TheorySetsPrivate& theory, context::Context* satContext, eq::EqualityEngine* eq): - d_theory(theory), - d_context(satContext), - d_eqEngine(eq), - d_terms(satContext), - d_info() -{ } +TheorySetsPrivate::TermInfoManager::TermInfoManager( + TheorySetsPrivate& theory, context::Context* satContext, + eq::EqualityEngine* eq) + : d_theory(theory), + d_context(satContext), + d_eqEngine(eq), + d_terms(satContext), + d_info() {} TheorySetsPrivate::TermInfoManager::~TermInfoManager() { - for( typeof(d_info.begin()) it = d_info.begin(); - it != d_info.end(); ++it) { + for (SetsTermInfoMap::iterator it = d_info.begin(); it != d_info.end(); + ++it) { delete (*it).second; } } @@ -1744,14 +1767,14 @@ void TheorySetsPrivate::TermInfoManager::addTerm(TNode n) { d_theory.registerCard(CARD(n)); } - typeof(d_info.begin()) ita = d_info.find(d_eqEngine->getRepresentative(n[i])); + SetsTermInfoMap::iterator ita = d_info.find(d_eqEngine->getRepresentative(n[i])); Assert(ita != d_info.end()); CDTNodeList* l = (*ita).second->elementsNotInThisSet; - for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) { d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) ); } l = (*ita).second->elementsInThisSet; - for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) { d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) ); } } @@ -1782,7 +1805,7 @@ void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue // propagation : parents const CDTNodeList* parentList = getParents(S); - for(typeof(parentList->begin()) k = parentList->begin(); + for(CDTNodeList::const_iterator k = parentList->begin(); k != parentList->end(); ++k) { d_theory.d_settermPropagationQueue.push_back(std::make_pair(x, *k)); }// propagation : parents @@ -1850,8 +1873,8 @@ void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) { << ", b: " << d_eqEngine->getRepresentative(b) << std::endl; - typeof(d_info.begin()) ita = d_info.find(a); - typeof(d_info.begin()) itb = d_info.find(b); + SetsTermInfoMap::iterator ita = d_info.find(a); + SetsTermInfoMap::iterator itb = d_info.find(b); Assert(ita != d_info.end()); Assert(itb != d_info.end()); @@ -1879,29 +1902,33 @@ void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) { d_theory.d_modelCache.clear(); } -Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) -{ - if(d_terms.find(n) == d_terms.end()) { +Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) { + if (d_terms.find(n) == d_terms.end()) { return Node(); } Assert(n.getType().isSet()); - set<Node> elements, elements_const; + std::set<Node> elements; + std::set<Node> elements_const; Node S = d_eqEngine->getRepresentative(n); - typeof(d_theory.d_modelCache.begin()) it = d_theory.d_modelCache.find(S); - if(it != d_theory.d_modelCache.end()) { + context::CDHashMap<Node, Node, NodeHashFunction>::const_iterator it = + d_theory.d_modelCache.find(S); + if (it != d_theory.d_modelCache.end()) { return (*it).second; } const CDTNodeList* l = getMembers(S); - for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + for (CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) { TNode n = *it; elements.insert(d_eqEngine->getRepresentative(n)); } - BOOST_FOREACH(TNode e, elements) { - if(e.isConst()) { + for(std::set<Node>::iterator it = elements.begin(); it != elements.end(); it++) { + TNode e = *it; + if (e.isConst()) { elements_const.insert(e); } else { Node eModelValue = d_theory.d_external.d_valuation.getModelValue(e); - if( eModelValue.isNull() ) return eModelValue; + if (eModelValue.isNull()) { + return eModelValue; + } elements_const.insert(eModelValue); } } @@ -1910,9 +1937,6 @@ Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) return v; } - - - /********************** Cardinality ***************************/ /********************** Cardinality ***************************/ /********************** Cardinality ***************************/ @@ -1927,7 +1951,7 @@ void TheorySetsPrivate::enableCard() cardCreateEmptysetSkolem(t); } - for(typeof(d_termInfoManager->d_terms.begin()) it = d_termInfoManager->d_terms.begin(); + for(CDNodeSet::const_iterator it = d_termInfoManager->d_terms.begin(); it != d_termInfoManager->d_terms.end(); ++it) { Node n = (*it); if(n.getKind() == kind::SINGLETON) { @@ -1944,7 +1968,7 @@ void TheorySetsPrivate::registerCard(TNode node) { // introduce cardinality of any set-term containing this term NodeManager* nm = NodeManager::currentNM(); const CDTNodeList* parentList = d_termInfoManager->getParents(node[0]); - for(typeof(parentList->begin()) it = parentList->begin(); + for(CDTNodeList::const_iterator it = parentList->begin(); it != parentList->end(); ++it) { registerCard(nm->mkNode(kind::CARD, *it)); } @@ -1971,9 +1995,10 @@ void TheorySetsPrivate::buildGraph() { edgesFd.clear(); edgesBk.clear(); disjoint.clear(); - - for(typeof(d_processedCardPairs.begin()) it = d_processedCardPairs.begin(); - it != d_processedCardPairs.end(); ++it) { + + for (std::map<std::pair<Node, Node>, bool>::const_iterator it = + d_processedCardPairs.begin(); + it != d_processedCardPairs.end(); ++it) { Node s = (it->first).first; Assert(Rewriter::rewrite(s) == s); Node t = (it->first).second; @@ -1988,7 +2013,7 @@ void TheorySetsPrivate::buildGraph() { tMs = Rewriter::rewrite(tMs); edgesFd[s].insert(sNt); - edgesFd[s].insert(sMt); + edgesFd[s].insert(sMt); edgesBk[sNt].insert(s); edgesBk[sMt].insert(s); @@ -2000,7 +2025,7 @@ void TheorySetsPrivate::buildGraph() { if(hasUnion) { Node sUt = nm->mkNode(kind::UNION, s, t); sUt = Rewriter::rewrite(sUt); - + edgesFd[sUt].insert(sNt); edgesFd[sUt].insert(sMt); edgesFd[sUt].insert(tMs); @@ -2017,32 +2042,34 @@ void TheorySetsPrivate::buildGraph() { disjoint.insert(make_pair(sMt, tMs)); } - if(Debug.isOn("sets-card-graph")) { + if (Debug.isOn("sets-card-graph")) { Debug("sets-card-graph") << "[sets-card-graph] Fd:" << std::endl; - for(typeof(edgesFd.begin()) it = edgesFd.begin(); - it != edgesFd.end(); ++it) { - Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) << std::endl; - for(typeof( (it->second).begin()) jt = (it->second).begin(); - jt != (it->second).end(); ++jt) { - Debug("sets-card-graph") << "[sets-card-graph] " << (*jt) << std::endl; + for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesFd.begin(); + it != edgesFd.end(); ++it) { + Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) + << std::endl; + for (std::set<TNode>::const_iterator jt = (it->second).begin(); + jt != (it->second).end(); ++jt) { + Debug("sets-card-graph") << "[sets-card-graph] " << (*jt) + << std::endl; } } Debug("sets-card-graph") << "[sets-card-graph] Bk:" << std::endl; - for(typeof(edgesBk.begin()) it = edgesBk.begin(); - it != edgesBk.end(); ++it) { - Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) << std::endl; - for(typeof( (it->second).begin()) jt = (it->second).begin(); - jt != (it->second).end(); ++jt) { - Debug("sets-card-graph") << "[sets-card-graph] " << (*jt) << std::endl; + for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesBk.begin(); + it != edgesBk.end(); ++it) { + Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) + << std::endl; + for (std::set<TNode>::const_iterator jt = (it->second).begin(); + jt != (it->second).end(); ++jt) { + Debug("sets-card-graph") << "[sets-card-graph] " << (*jt) + << std::endl; } } } - - leaves.clear(); - - for(typeof(d_processedCardTerms.begin()) it = d_processedCardTerms.begin(); + + for(CDNodeSet::const_iterator it = d_processedCardTerms.begin(); it != d_processedCardTerms.end(); ++it) { Node n = (*it)[0]; if( edgesFd.find(n) == edgesFd.end() ) { @@ -2247,7 +2274,7 @@ std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2, Node v Node TheorySetsPrivate::eqemptySoFar() { std::vector<Node> V; - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { Node rep = d_equalityEngine.getRepresentative(*it); if(rep.getKind() == kind::EMPTYSET) { V.push_back(EQUAL(rep, (*it))); @@ -2391,11 +2418,12 @@ void TheorySetsPrivate::merge_nodes(std::set<TNode> leaves1, std::set<TNode> lea } -void TheorySetsPrivate::print_graph() { +void TheorySetsPrivate::print_graph(bool printmodel) { + NodeManager* nm = NodeManager::currentNM(); std::string tag = "sets-graph"; if(Trace.isOn("sets-graph")) { Trace(tag) << "[sets-graph] Graph : " << std::endl; - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { TNode v = *it; // BOOST_FOREACH(TNode v, d_V) { Trace(tag) << "[" << tag << "] " << v << " : "; @@ -2414,15 +2442,40 @@ void TheorySetsPrivate::print_graph() { if(Trace.isOn("sets-graph-dot")) { std::ostringstream oss; oss << "digraph G { "; - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { TNode v = *it; + + std::ostringstream v_oss; + v_oss << v; + if(printmodel) + { + Node n = nm->mkNode(kind::CARD, v); + if((Rewriter::rewrite(n)).isConst()) { + v_oss << " " << (Rewriter::rewrite(n)); + } else { + v_oss << " " << d_external.d_valuation.getModelValue(n); + } + } + if(d_E.find(v) != d_E.end()) { BOOST_FOREACH(TNode w, d_E[v].get()) { + + std::ostringstream w_oss; + w_oss << w; + if(printmodel) { + Node n = nm->mkNode(kind::CARD, w); + if((Rewriter::rewrite(n)).isConst()) { + w_oss << " " << (Rewriter::rewrite(n)); + } else { + w_oss << " " << d_external.d_valuation.getModelValue(n); + } + } + //oss << v.getId() << " -> " << w.getId() << "; "; - oss << "\"" << v << "\" -> \"" << w << "\"; "; + oss << "\"" << v_oss.str() << "\" -> \"" << w_oss.str() << "\"; "; } } else { - oss << "\"" << v << "\";"; + oss << "\"" << v_oss.str() << "\";"; } } oss << "}"; @@ -2448,7 +2501,7 @@ void TheorySetsPrivate::guessLeavesEmptyLemmas() { // Guess leaf nodes being empty or non-empty NodeManager* nm = NodeManager::currentNM(); leaves.clear(); - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { TNode v = *it; if(d_E.find(v) == d_E.end()) { leaves.insert(v); @@ -2465,7 +2518,7 @@ void TheorySetsPrivate::guessLeavesEmptyLemmas() { numLeavesCurrentlyNonEmpty = 0, numLemmaAlreadyExisted = 0; - for(typeof(leaves.begin()) it = leaves.begin(); it != leaves.end(); ++it) { + for(std::set<TNode>::iterator it = leaves.begin(); it != leaves.end(); ++it) { bool generateLemma = true; Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType((*it).getType()))); @@ -2526,8 +2579,16 @@ void TheorySetsPrivate::processCard2(Theory::Effort level) { NodeManager* nm = NodeManager::currentNM(); + if(options::setsGuessEmpty() == 0) { + Trace("sets-guess-empty") << "[sets-guess-empty] Generating lemmas before introduce." << std::endl; + guessLeavesEmptyLemmas(); + if(d_newLemmaGenerated) { + return; + } + } + // Introduce - for(typeof(d_cardTerms.begin()) it = d_cardTerms.begin(); + for(CDNodeSet::const_iterator it = d_cardTerms.begin(); it != d_cardTerms.end(); ++it) { for(eq::EqClassIterator j(d_equalityEngine.getRepresentative((*it)[0]), &d_equalityEngine); @@ -2710,14 +2771,14 @@ void TheorySetsPrivate::processCard2(Theory::Effort level) { // merge_nodes(get_leaves(np.first), get_leaves(np.second), EQUAL(np.first, np.second)); merge_nodes(get_leaves(np.first), get_leaves(np.second), eqSoFar()); } - + if(d_newLemmaGenerated) { Trace("sets-card") << "[sets-card] New merge done. Returning." << std::endl; return; } leaves.clear(); - for(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) { TNode v = *it; if(d_E.find(v) == d_E.end()) { leaves.insert(v); @@ -2737,23 +2798,28 @@ void TheorySetsPrivate::processCard2(Theory::Effort level) { } } + typedef std::set<TNode>::const_iterator TNodeSetIterator; + // Elements being either equal or disequal [Members Arrangement rule] - Trace("sets-card") << "[sets-card] Processing elements equality/disequal to each other" << std::endl; - for(typeof(leaves.begin()) it = leaves.begin(); - it != leaves.end(); ++it) { - if(!d_equalityEngine.hasTerm(*it)) continue; + Trace("sets-card") + << "[sets-card] Processing elements equality/disequal to each other" + << std::endl; + for (TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) { + if (!d_equalityEngine.hasTerm(*it)) continue; Node n = d_equalityEngine.getRepresentative(*it); Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end()); - if(n != *it) continue; + if (n != *it) continue; const CDTNodeList* l = d_termInfoManager->getMembers(*it); std::set<TNode> elems; - for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) { + for (CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) { elems.insert(d_equalityEngine.getRepresentative(*l_it)); } - for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) { - for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) { - if(*e1_it == *e2_it) continue; - if(!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) { + for (TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end(); + ++e1_it) { + for (TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end(); + ++e2_it) { + if (*e1_it == *e2_it) continue; + if (!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) { Node lem = nm->mkNode(kind::EQUAL, *e1_it, *e2_it); lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem)); lemma(lem, SETS_LEMMA_GRAPH); @@ -2769,8 +2835,7 @@ void TheorySetsPrivate::processCard2(Theory::Effort level) { // Assert Lower bound Trace("sets-card") << "[sets-card] Processing assert lower bound" << std::endl; - for(typeof(leaves.begin()) it = leaves.begin(); - it != leaves.end(); ++it) { + for(TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) { Trace("sets-cardlower") << "[sets-cardlower] Card Lower: " << *it << std::endl; Assert(d_equalityEngine.hasTerm(*it)); Node n = d_equalityEngine.getRepresentative(*it); @@ -2783,21 +2848,21 @@ void TheorySetsPrivate::processCard2(Theory::Effort level) { // if(n != *it) continue; const CDTNodeList* l = d_termInfoManager->getMembers(n); std::set<TNode> elems; - for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) { + for(CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) { elems.insert(d_equalityEngine.getRepresentative(*l_it)); } if(elems.size() == 0) continue; NodeBuilder<> nb(kind::OR); nb << ( nm->mkNode(kind::LEQ, nm->mkConst(Rational(elems.size())), nm->mkNode(kind::CARD, *it)) ); if(elems.size() > 1) { - for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) { - for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) { + for(TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) { + for(TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) { if(*e1_it == *e2_it) continue; nb << (nm->mkNode(kind::EQUAL, *e1_it, *e2_it)); } } } - for(typeof(elems.begin()) e_it = elems.begin(); e_it != elems.end(); ++e_it) { + for(TNodeSetIterator e_it = elems.begin(); e_it != elems.end(); ++e_it) { nb << nm->mkNode(kind::NOT, nm->mkNode(kind::MEMBER, *e_it, *it)); } Node lem = Node(nb); diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h index 217432670..3ed608b90 100644 --- a/src/theory/sets/theory_sets_private.h +++ b/src/theory/sets/theory_sets_private.h @@ -146,7 +146,8 @@ private: public: CDNodeSet d_terms; private: - std::hash_map<TNode, TheorySetsTermInfo*, TNodeHashFunction> d_info; + typedef std::hash_map<TNode, TheorySetsTermInfo*, TNodeHashFunction> SetsTermInfoMap; + SetsTermInfoMap d_info; void mergeLists(CDTNodeList* la, const CDTNodeList* lb) const; void pushToSettermPropagationQueue(TNode x, TNode S, bool polarity); @@ -252,7 +253,7 @@ private: bool d_cardEnabled; void enableCard(); void cardCreateEmptysetSkolem(TypeNode t); - + CDNodeSet d_cardTerms; std::set<TypeNode> d_typesAdded; CDNodeSet d_processedCardTerms; @@ -282,7 +283,7 @@ private: std::set<TNode> get_leaves(Node vertex1, Node vertex2); std::set<TNode> get_leaves(Node vertex1, Node vertex2, Node vertex3); std::set<TNode> non_empty(std::set<TNode> vertices); - void print_graph(); + void print_graph(bool printmodel=false); context::CDQueue < std::pair<TNode, TNode> > d_graphMergesPending; context::CDList<Node> d_allSetEqualitiesSoFar; Node eqSoFar(); diff --git a/src/theory/sets/theory_sets_type_enumerator.h b/src/theory/sets/theory_sets_type_enumerator.h index 40863b0f2..f2d6bae68 100644 --- a/src/theory/sets/theory_sets_type_enumerator.h +++ b/src/theory/sets/theory_sets_type_enumerator.h @@ -153,14 +153,16 @@ public: } while (d_constituentVec.size() < d_index) { - TypeEnumerator *d_newEnumerator = new TypeEnumerator(*d_constituentVec.back()); - ++(*d_newEnumerator); - if( (*d_newEnumerator).isFinished() ) { + TypeEnumerator* newEnumerator = + new TypeEnumerator(*d_constituentVec.back()); + ++(*newEnumerator); + if (newEnumerator->isFinished()) { Trace("set-type-enum") << "operator++ finished!" << std::endl; + delete newEnumerator; d_finished = true; return *this; } - d_constituentVec.push_back(d_newEnumerator); + d_constituentVec.push_back(newEnumerator); } Trace("set-type-enum") << "operator++ returning, **this = " << **this << std::endl; diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp index 0dc6cc7a1..b78109dfb 100644 --- a/src/theory/shared_terms_database.cpp +++ b/src/theory/shared_terms_database.cpp @@ -37,7 +37,7 @@ SharedTermsDatabase::SharedTermsDatabase(TheoryEngine* theoryEngine, context::Co smtStatisticsRegistry()->registerStat(&d_statSharedTerms); } -SharedTermsDatabase::~SharedTermsDatabase() throw(AssertionException) +SharedTermsDatabase::~SharedTermsDatabase() { smtStatisticsRegistry()->unregisterStat(&d_statSharedTerms); } diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h index c108122ef..cc8959165 100644 --- a/src/theory/shared_terms_database.h +++ b/src/theory/shared_terms_database.h @@ -149,7 +149,7 @@ private: public: SharedTermsDatabase(TheoryEngine* theoryEngine, context::Context* context); - ~SharedTermsDatabase() throw(AssertionException); + ~SharedTermsDatabase(); /** * Asserts the equality to the shared terms database, diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 7caa1cbb1..3ef6df3fc 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -331,6 +331,92 @@ bool TheoryStrings::getCurrentSubstitution( int effort, std::vector< Node >& var return true; } +int TheoryStrings::getReduction( int effort, Node n, Node& nr ) { + //determine the effort level to process the extf at + // 0 - at assertion time, 1+ - after no other reduction is applicable + Assert( d_extf_info_tmp.find( n )!=d_extf_info_tmp.end() ); + if( d_extf_info_tmp[n].d_model_active ){ + int r_effort = -1; + int pol = d_extf_info_tmp[n].d_pol; + if( n.getKind()==kind::STRING_STRCTN ){ + if( pol==1 ){ + r_effort = 1; + }else if( pol==-1 ){ + if( effort==2 ){ + Node x = n[0]; + Node s = n[1]; + std::vector< Node > lexp; + Node lenx = getLength( x, lexp ); + Node lens = getLength( s, lexp ); + if( areEqual( lenx, lens ) ){ + Trace("strings-extf-debug") << " resolve extf : " << n << " based on equal lengths disequality." << std::endl; + //we can reduce to disequality when lengths are equal + if( !areDisequal( x, s ) ){ + lexp.push_back( lenx.eqNode(lens) ); + lexp.push_back( n.negate() ); + Node xneqs = x.eqNode(s).negate(); + sendInference( lexp, xneqs, "NEG-CTN-EQL", true ); + } + return 1; + }else if( !areDisequal( lenx, lens ) ){ + //split on their lenths + sendSplit( lenx, lens, "NEG-CTN-SP" ); + }else{ + r_effort = 2; + } + } + } + }else{ + if( options::stringLazyPreproc() ){ + if( n.getKind()==kind::STRING_SUBSTR ){ + r_effort = 1; + }else if( n.getKind()!=kind::STRING_IN_REGEXP ){ + r_effort = 2; + } + } + } + if( effort==r_effort ){ + Node c_n = pol==-1 ? n.negate() : n; + if( d_preproc_cache.find( c_n )==d_preproc_cache.end() ){ + d_preproc_cache[ c_n ] = true; + Trace("strings-process-debug") << "Process reduction for " << n << ", pol = " << pol << std::endl; + if( n.getKind()==kind::STRING_STRCTN && pol==1 ){ + Node x = n[0]; + Node s = n[1]; + //positive contains reduces to a equality + Node sk1 = mkSkolemCached( x, s, sk_id_ctn_pre, "sc1" ); + Node sk2 = mkSkolemCached( x, s, sk_id_ctn_post, "sc2" ); + Node eq = Rewriter::rewrite( x.eqNode( mkConcat( sk1, s, sk2 ) ) ); + std::vector< Node > exp_vec; + exp_vec.push_back( n ); + sendInference( d_empty_vec, exp_vec, eq, "POS-CTN", true ); + //we've reduced this n + Trace("strings-extf-debug") << " resolve extf : " << n << " based on positive contain reduction." << std::endl; + return 1; + }else{ + // for STRING_SUBSTR, STRING_STRCTN with pol=-1, + // STRING_STRIDOF, STRING_ITOS, STRING_U16TOS, STRING_U32TOS, STRING_STOI, STRING_STOU16, STRING_STOU32, STRING_STRREPL + std::vector< Node > new_nodes; + Node res = d_preproc.simplify( n, new_nodes ); + Assert( res!=n ); + new_nodes.push_back( NodeManager::currentNM()->mkNode( res.getType().isBoolean() ? kind::IFF : kind::EQUAL, res, n ) ); + Node nnlem = new_nodes.size()==1 ? new_nodes[0] : NodeManager::currentNM()->mkNode( kind::AND, new_nodes ); + nnlem = Rewriter::rewrite( nnlem ); + Trace("strings-red-lemma") << "Reduction_" << effort << " lemma : " << nnlem << std::endl; + Trace("strings-red-lemma") << "...from " << n << std::endl; + sendInference( d_empty_vec, nnlem, "Reduction", true ); + //we've reduced this n + Trace("strings-extf-debug") << " resolve extf : " << n << " based on reduction." << std::endl; + return 1; + } + }else{ + return 1; + } + } + } + return 0; +} + ///////////////////////////////////////////////////////////////////////////// // NOTIFICATIONS ///////////////////////////////////////////////////////////////////////////// @@ -404,15 +490,13 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) { for( unsigned j=0; j<col[i].size(); j++ ) { Trace("strings-model") << col[i][j] << " "; //check if col[i][j] has only variables - EqcInfo* ei = getOrMakeEqcInfo( col[i][j], false ); - Node cst = ei ? ei->d_const_term : Node::null(); - if( cst.isNull() ){ + if( !col[i][j].isConst() ){ Assert( d_normal_forms.find( col[i][j] )!=d_normal_forms.end() ); if( d_normal_forms[col[i][j]].size()==1 ){//&& d_normal_forms[col[i][j]][0]==col[i][j] ){ pure_eq.push_back( col[i][j] ); } }else{ - processed[col[i][j]] = cst; + processed[col[i][j]] = col[i][j]; } } Trace("strings-model") << "have length " << lts_values[i] << std::endl; @@ -692,104 +776,29 @@ bool TheoryStrings::needsCheckLastEffort() { } void TheoryStrings::checkExtfReductions( int effort ) { + //standardize this? + //std::vector< Node > nred; + //d_extt->doReductions( effort, nred, false ); + std::vector< Node > extf; d_extt->getActive( extf ); + Trace("strings-process") << "checking " << extf.size() << " active extf" << std::endl; for( unsigned i=0; i<extf.size(); i++ ){ Node n = extf[i]; - if( d_extf_info_tmp[n].d_model_active ){ - Assert( d_extf_info_tmp.find( n )!=d_extf_info_tmp.end() ); - if( checkExtfReduction( n, d_extf_info_tmp[n].d_pol, effort ) ){ - d_extt->markReduced( n ); - } - if( hasProcessed() ){ + Trace("strings-process") << "Check " << n << ", active in model=" << d_extf_info_tmp[n].d_model_active << std::endl; + Node nr; + int ret = getReduction( effort, n, nr ); + Assert( nr.isNull() ); + if( ret!=0 ){ + d_extt->markReduced( extf[i] ); + if( options::stringOpt1() && hasProcessed() ){ return; } } } } -bool TheoryStrings::checkExtfReduction( Node atom, int pol, int effort ) { - //determine the effort level to process the extf at - // 0 - at assertion time, 1+ - after no other reduction is applicable - int r_effort = -1; - if( atom.getKind()==kind::STRING_STRCTN ){ - if( pol==1 ){ - r_effort = 1; - }else{ - Assert( pol==-1 ); - if( effort==2 ){ - Node x = atom[0]; - Node s = atom[1]; - std::vector< Node > lexp; - Node lenx = getLength( x, lexp ); - Node lens = getLength( s, lexp ); - if( areEqual( lenx, lens ) ){ - Trace("strings-extf-debug") << " resolve extf : " << atom << " based on equal lengths disequality." << std::endl; - //we can reduce to disequality when lengths are equal - if( !areDisequal( x, s ) ){ - lexp.push_back( lenx.eqNode(lens) ); - lexp.push_back( atom.negate() ); - Node xneqs = x.eqNode(s).negate(); - sendInference( lexp, xneqs, "NEG-CTN-EQL", true ); - } - return true; - }else if( !areDisequal( lenx, lens ) ){ - //split on their lenths - sendSplit( lenx, lens, "NEG-CTN-SP" ); - }else{ - r_effort = 2; - } - } - } - }else{ - if( options::stringLazyPreproc() ){ - if( atom.getKind()==kind::STRING_SUBSTR ){ - r_effort = 1; - }else if( atom.getKind()!=kind::STRING_IN_REGEXP ){ - r_effort = 2; - } - } - } - if( effort==r_effort ){ - Node c_atom = pol==-1 ? atom.negate() : atom; - if( d_preproc_cache.find( c_atom )==d_preproc_cache.end() ){ - d_preproc_cache[ c_atom ] = true; - Trace("strings-process-debug") << "Process reduction for " << atom << ", pol = " << pol << std::endl; - if( atom.getKind()==kind::STRING_STRCTN && pol==1 ){ - Node x = atom[0]; - Node s = atom[1]; - //positive contains reduces to a equality - Node sk1 = mkSkolemCached( x, s, sk_id_ctn_pre, "sc1" ); - Node sk2 = mkSkolemCached( x, s, sk_id_ctn_post, "sc2" ); - Node eq = Rewriter::rewrite( x.eqNode( mkConcat( sk1, s, sk2 ) ) ); - std::vector< Node > exp_vec; - exp_vec.push_back( atom ); - sendInference( d_empty_vec, exp_vec, eq, "POS-CTN", true ); - //we've reduced this atom - Trace("strings-extf-debug") << " resolve extf : " << atom << " based on positive contain reduction." << std::endl; - return true; - }else{ - // for STRING_SUBSTR, STRING_STRCTN with pol=-1, - // STRING_STRIDOF, STRING_ITOS, STRING_U16TOS, STRING_U32TOS, STRING_STOI, STRING_STOU16, STRING_STOU32, STRING_STRREPL - std::vector< Node > new_nodes; - Node res = d_preproc.simplify( atom, new_nodes ); - Assert( res!=atom ); - new_nodes.push_back( NodeManager::currentNM()->mkNode( res.getType().isBoolean() ? kind::IFF : kind::EQUAL, res, atom ) ); - Node nnlem = new_nodes.size()==1 ? new_nodes[0] : NodeManager::currentNM()->mkNode( kind::AND, new_nodes ); - nnlem = Rewriter::rewrite( nnlem ); - Trace("strings-red-lemma") << "Reduction_" << effort << " lemma : " << nnlem << std::endl; - Trace("strings-red-lemma") << "...from " << atom << std::endl; - sendInference( d_empty_vec, nnlem, "Reduction", true ); - //we've reduced this atom - Trace("strings-extf-debug") << " resolve extf : " << atom << " based on reduction." << std::endl; - return true; - } - } - } - return false; -} - -TheoryStrings::EqcInfo::EqcInfo( context::Context* c ) : d_const_term(c), d_length_term(c), d_cardinality_lem_k(c), d_normalized_length(c) { +TheoryStrings::EqcInfo::EqcInfo( context::Context* c ) : d_length_term(c), d_cardinality_lem_k(c), d_normalized_length(c) { } @@ -827,10 +836,6 @@ void TheoryStrings::conflict(TNode a, TNode b){ /** called when a new equivalance class is created */ void TheoryStrings::eqNotifyNewClass(TNode t){ - if( t.getKind() == kind::CONST_STRING ){ - EqcInfo * ei =getOrMakeEqcInfo( t, true ); - ei->d_const_term = t; - } if( t.getKind() == kind::STRING_LENGTH ){ Trace("strings-debug") << "New length eqc : " << t << std::endl; Node r = d_equalityEngine.getRepresentative(t[0]); @@ -838,6 +843,8 @@ void TheoryStrings::eqNotifyNewClass(TNode t){ ei->d_length_term = t[0]; //we care about the length of this string registerTerm( t[0], 1 ); + }else{ + //d_extt->registerTerm( t ); } } @@ -847,9 +854,6 @@ void TheoryStrings::eqNotifyPreMerge(TNode t1, TNode t2){ if( e2 ){ EqcInfo * e1 = getOrMakeEqcInfo( t1 ); //add information from e2 to e1 - if( !e2->d_const_term.get().isNull() ){ - e1->d_const_term.set( e2->d_const_term ); - } if( !e2->d_length_term.get().isNull() ){ e1->d_length_term.set( e2->d_length_term ); } @@ -905,7 +909,6 @@ void TheoryStrings::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::Te } for (unsigned c = 0; c < currentPairs.size(); ++ c) { Trace("strings-cg-pair") << "TheoryStrings::computeCareGraph(): pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl; - Trace("ajr-temp") << currentPairs[c].first << ", " << currentPairs[c].second << std::endl; addCarePair(currentPairs[c].first, currentPairs[c].second); } } @@ -988,7 +991,6 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) { d_equalityEngine.assertPredicate( atom, polarity, exp ); //process extf if( atom.getKind()==kind::STRING_IN_REGEXP ){ - d_extt->registerTerm( atom ); if( polarity && atom[1].getKind()==kind::REGEXP_RANGE ){ if( d_extf_infer_cache_u.find( atom )==d_extf_infer_cache_u.end() ){ d_extf_infer_cache_u.insert( atom ); @@ -1000,6 +1002,8 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) { } } } + //register the atom here, since it may not create a new equivalence class + //d_extt->registerTerm( atom ); } Trace("strings-pending-debug") << " Now collect terms" << std::endl; //collect extended function terms in the atom @@ -1293,7 +1297,8 @@ void TheoryStrings::checkExtfEval( int effort ) { std::vector< Node > terms; std::vector< Node > sterms; std::vector< std::vector< Node > > exp; - d_extt->getInferences( effort, terms, sterms, exp ); + d_extt->getActive( terms ); + d_extt->getSubstitutedTerms( effort, terms, sterms, exp ); for( unsigned i=0; i<terms.size(); i++ ){ Node n = terms[i]; Node sn = sterms[i]; @@ -2955,7 +2960,7 @@ void TheoryStrings::processDeq( Node ni, Node nj ) { } }else{ Node sk = mkSkolemCached( nconst_k, firstChar, sk_id_dc_spt, "dc_spt", 2 ); - Node skr = mkSkolemCached( nconst_k, firstChar, sk_id_dc_spt_rem, "dc_spt_rem", -1 ); + Node skr = mkSkolemCached( nconst_k, firstChar, sk_id_dc_spt_rem, "dc_spt_rem" ); Node eq1 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, skr ) ); eq1 = Rewriter::rewrite( eq1 ); Node eq2 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, firstChar, skr ) ); @@ -3876,16 +3881,6 @@ Node TheoryStrings::ppRewrite(TNode atom) { return atom; } -void TheoryStrings::collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited ) { - if( visited.find( n )==visited.end() ){ - visited[n] = true; - d_extt->registerTerm( n ); - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - collectExtendedFuncTerms( n[i], visited ); - } - } -} - // Stats TheoryStrings::Statistics::Statistics(): d_splits("TheoryStrings::NumOfSplitOnDemands", 0), @@ -4868,6 +4863,16 @@ Node TheoryStrings::getNormalSymRegExp(Node r, std::vector<Node> &nf_exp) { return ret; } +void TheoryStrings::collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited ) { + if( visited.find( n )==visited.end() ){ + visited[n] = true; + d_extt->registerTerm( n ); + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + collectExtendedFuncTerms( n[i], visited ); + } + } +} + }/* CVC4::theory::strings namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h index fe72bd8e7..fd984bd58 100644 --- a/src/theory/strings/theory_strings.h +++ b/src/theory/strings/theory_strings.h @@ -72,6 +72,7 @@ public: Node explain( TNode literal ); eq::EqualityEngine * getEqualityEngine() { return &d_equalityEngine; } bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ); + int getReduction( int effort, Node n, Node& nr ); // NotifyClass for equality engine class NotifyClass : public eq::EqualityEngineNotify { @@ -237,7 +238,6 @@ private: EqcInfo( context::Context* c ); ~EqcInfo(){} //constant in this eqc - context::CDO< Node > d_const_term; context::CDO< Node > d_length_term; context::CDO< unsigned > d_cardinality_lem_k; // 1 = added length lemma @@ -274,8 +274,6 @@ private: int d_pol; //explanation std::vector< Node > d_exp; - //reps -> list of variables - //std::map< Node, std::vector< Node > > d_rep_vars; //false if it is reduced in the model bool d_model_active; }; @@ -321,7 +319,6 @@ private: Node getSymbolicDefinition( Node n, std::vector< Node >& exp ); //check extf reduction void checkExtfReductions( int effort ); - bool checkExtfReduction( Node atom, int pol, int effort ); //flat forms check void checkFlatForms(); Node checkCycles( Node eqc, std::vector< Node >& curr, std::vector< Node >& exp ); @@ -523,6 +520,7 @@ public: ~Statistics(); };/* class TheoryStrings::Statistics */ Statistics d_statistics; + };/* class TheoryStrings */ }/* CVC4::theory::strings namespace */ diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 92b18eed0..2ee367cfc 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -741,6 +741,7 @@ bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned i return ( s2 == r[0].getConst<String>() ); } else { Assert( false, "RegExp contains variables" ); + return false; } } case kind::REGEXP_CONCAT: { diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index 7fa74df6a..9e71a1ddf 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -314,15 +314,18 @@ EntailmentCheckSideEffects::~EntailmentCheckSideEffects() { ExtTheory::ExtTheory( Theory * p ) : d_parent( p ), -d_ext_func_terms( p->getSatContext() ), d_has_extf( p->getSatContext() ){ - +d_ext_func_terms( p->getSatContext() ), d_ci_inactive( p->getUserContext() ), +d_lemmas( p->getUserContext() ), d_pp_lemmas( p->getUserContext() ), d_has_extf( p->getSatContext() ){ + d_true = NodeManager::currentNM()->mkConst( true ); } +//gets all leaf terms in n void ExtTheory::collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited ) { if( !n.isConst() ){ if( visited.find( n )==visited.end() ){ visited[n] = true; - if( n.getNumChildren()>0 ){ + //treat terms not belonging to this theory as leaf + if( n.getNumChildren()>0 ){//&& Theory::theoryOf(n)==d_parent->getId() ){ for( unsigned i=0; i<n.getNumChildren(); i++ ){ collectVars( n[i], vars, visited ); } @@ -334,17 +337,17 @@ void ExtTheory::collectVars( Node n, std::vector< Node >& vars, std::map< Node, } //do inferences -void ExtTheory::getInferences( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp ) { - //all variables we need to find a substitution for - std::vector< Node > vars; - std::vector< Node > sub; - std::map< Node, std::vector< Node > > expc; - Trace("extt-debug") << "Checking " << d_ext_func_terms.size() << " extended functions." << std::endl; - for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){ - //if not already reduced - if( (*it).second ){ - Node n = (*it).first; - terms.push_back( n ); +void ExtTheory::getSubstitutedTerms( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp ) { + Trace("extt-debug") << "Currently " << d_ext_func_terms.size() << " extended functions." << std::endl; + Trace("extt-debug") << "..." << terms.size() << " to reduce." << std::endl; + if( !terms.empty() ){ + //all variables we need to find a substitution for + std::vector< Node > vars; + std::vector< Node > sub; + std::map< Node, std::vector< Node > > expc; + for( unsigned i=0; i<terms.size(); i++ ){ + //do substitution, rewrite + Node n = terms[i]; std::map< Node, ExtfInfo >::iterator iti = d_extf_info.find( n ); Assert( iti!=d_extf_info.end() ); for( unsigned i=0; i<iti->second.d_vars.size(); i++ ){ @@ -353,13 +356,11 @@ void ExtTheory::getInferences( int effort, std::vector< Node >& terms, std::vect } } } - } - Trace("extt-debug") << "..." << terms.size() << " unreduced." << std::endl; - if( !terms.empty() ){ - //get the current substitution + //get the current substitution for all variables if( d_parent->getCurrentSubstitution( effort, vars, sub, expc ) ){ + Assert( vars.size()==sub.size() ); for( unsigned i=0; i<terms.size(); i++ ){ - //do substitution, rewrite + //do substitution Node n = terms[i]; Node ns = n.substitute( vars.begin(), vars.end(), sub.begin(), sub.end() ); std::vector< Node > expn; @@ -392,13 +393,134 @@ void ExtTheory::getInferences( int effort, std::vector< Node >& terms, std::vect } } +bool ExtTheory::doInferencesInternal( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch, bool isRed ) { + if( batch ){ + bool addedLemma = false; + if( isRed ){ + for( unsigned i=0; i<terms.size(); i++ ){ + Node n = terms[i]; + Node nr; + //TODO: reduction with substitution? + int ret = d_parent->getReduction( effort, n, nr ); + if( ret==0 ){ + nred.push_back( n ); + }else{ + if( !nr.isNull() && n!=nr ){ + Node lem = NodeManager::currentNM()->mkNode( n.getType().isBoolean() ? kind::IFF : kind::EQUAL, n, nr ); + if( sendLemma( lem, true ) ){ + Trace("extt-lemma") << "ExtTheory : Reduction lemma : " << lem << std::endl; + addedLemma = true; + } + } + markReduced( terms[i], ret<0 ); + } + } + }else{ + std::vector< Node > sterms; + std::vector< std::vector< Node > > exp; + getSubstitutedTerms( effort, terms, sterms, exp ); + for( unsigned i=0; i<terms.size(); i++ ){ + bool processed = false; + if( sterms[i]!=terms[i] ){ + Node sr = Rewriter::rewrite( sterms[i] ); + if( sr.isConst() ){ + processed = true; + markReduced( terms[i] ); + Node eq = terms[i].eqNode( sr ); + Node expn = exp[i].size()>1 ? NodeManager::currentNM()->mkNode( kind::AND, exp[i] ) : ( exp[i].size()==1 ? exp[i][0] : d_true ); + Trace("extt-debug") << "ExtTheory::doInferences : infer : " << eq << " by " << expn << std::endl; + Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, expn, eq ); + Trace("extt-debug") << "...send lemma " << lem << std::endl; + if( sendLemma( lem ) ){ + Trace("extt-lemma") << "ExtTheory : Constant rewrite lemma : " << lem << std::endl; + addedLemma = true; + } + } + } + if( !processed ){ + nred.push_back( terms[i] ); + } + } + } + return addedLemma; + }else{ + std::vector< Node > nnred; + if( terms.empty() ){ + for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){ + if( (*it).second && !isContextIndependentInactive( (*it).first ) ){ + std::vector< Node > nterms; + nterms.push_back( (*it).first ); + if( doInferencesInternal( effort, nterms, nnred, true, isRed ) ){ + return true; + } + } + } + }else{ + for( unsigned i=0; i<terms.size(); i++ ){ + std::vector< Node > nterms; + nterms.push_back( terms[i] ); + if( doInferencesInternal( effort, nterms, nnred, true, isRed ) ){ + return true; + } + } + } + return false; + } +} + +bool ExtTheory::sendLemma( Node lem, bool preprocess ) { + if( preprocess ){ + if( d_pp_lemmas.find( lem )==d_pp_lemmas.end() ){ + d_pp_lemmas.insert( lem ); + d_parent->getOutputChannel().lemma( lem, false, true ); + return true; + } + }else{ + if( d_lemmas.find( lem )==d_lemmas.end() ){ + d_lemmas.insert( lem ); + d_parent->getOutputChannel().lemma( lem ); + return true; + } + } + return false; +} + +bool ExtTheory::doInferences( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch ) { + if( !terms.empty() ){ + return doInferencesInternal( effort, terms, nred, batch, false ); + }else{ + return false; + } +} + +bool ExtTheory::doInferences( int effort, std::vector< Node >& nred, bool batch ) { + std::vector< Node > terms; + getActive( terms ); + return doInferencesInternal( effort, terms, nred, batch, false ); +} + +bool ExtTheory::doReductions( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch ) { + if( !terms.empty() ){ + return doInferencesInternal( effort, terms, nred, batch, true ); + }else{ + return false; + } +} + +bool ExtTheory::doReductions( int effort, std::vector< Node >& nred, bool batch ) { + std::vector< Node > terms; + getActive( terms ); + return doInferencesInternal( effort, terms, nred, batch, true ); +} + + //register term void ExtTheory::registerTerm( Node n ) { if( d_extf_kind.find( n.getKind() )!=d_extf_kind.end() ){ if( d_ext_func_terms.find( n )==d_ext_func_terms.end() ){ Trace("extt-debug") << "Found extended function : " << n << " in " << d_parent->getId() << std::endl; d_ext_func_terms[n] = true; - d_has_extf = true; + d_has_extf = n; std::map< Node, bool > visited; collectVars( n, d_extf_info[n].d_vars, visited ); } @@ -406,9 +528,22 @@ void ExtTheory::registerTerm( Node n ) { } //mark reduced -void ExtTheory::markReduced( Node n ) { +void ExtTheory::markReduced( Node n, bool contextDepend ) { d_ext_func_terms[n] = false; - //TODO update has_extf + if( !contextDepend ){ + d_ci_inactive.insert( n ); + } + + //update has_extf + if( d_has_extf.get()==n ){ + for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){ + //if not already reduced + if( (*it).second && !isContextIndependentInactive( (*it).first ) ){ + d_has_extf = (*it).first; + } + } + + } } //mark congruent @@ -424,11 +559,19 @@ void ExtTheory::markCongruent( Node a, Node b ) { } } +bool ExtTheory::isContextIndependentInactive( Node n ) { + return d_ci_inactive.find( n )!=d_ci_inactive.end(); +} + +bool ExtTheory::hasActiveTerm() { + return !d_has_extf.get().isNull(); +} + //is active bool ExtTheory::isActive( Node n ) { NodeBoolMap::const_iterator it = d_ext_func_terms.find( n ); if( it!=d_ext_func_terms.end() ){ - return (*it).second; + return (*it).second && !isContextIndependentInactive( n ); }else{ return false; } @@ -437,7 +580,7 @@ bool ExtTheory::isActive( Node n ) { void ExtTheory::getActive( std::vector< Node >& active ) { for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){ //if not already reduced - if( (*it).second ){ + if( (*it).second && !isContextIndependentInactive( (*it).first ) ){ active.push_back( (*it).first ); } } @@ -446,7 +589,7 @@ void ExtTheory::getActive( std::vector< Node >& active ) { void ExtTheory::getActive( std::vector< Node >& active, Kind k ) { for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){ //if not already reduced - if( (*it).second && (*it).first.getKind()==k ){ + if( (*it).first.getKind()==k && (*it).second && !isContextIndependentInactive( (*it).first ) ){ active.push_back( (*it).first ); } } diff --git a/src/theory/theory.h b/src/theory/theory.h index ede06fd2d..5d64c6446 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -24,6 +24,7 @@ #include <string> #include "context/cdlist.h" +#include "context/cdhashset.h" #include "context/cdo.h" #include "context/context.h" #include "expr/node.h" @@ -642,6 +643,12 @@ public: * Don't preprocess subterm of this term */ virtual bool ppDontRewriteSubterm(TNode atom) { return false; } + + /** notify preprocessed assertions + * Called on new assertions after preprocessing before they are asserted to theory engine. + * Should not modify assertions. + */ + virtual void ppNotifyAssertions( std::vector< Node >& assertions ) {} /** * A Theory is called with presolve exactly one time per user @@ -885,8 +892,11 @@ public: */ virtual std::pair<bool, Node> entailmentCheck(TNode lit, const EntailmentCheckParameters* params = NULL, EntailmentCheckSideEffects* out = NULL); - /* equality engine */ + /* equality engine TODO: use? */ virtual eq::EqualityEngine * getEqualityEngine() { return NULL; } + + /* get extended theory */ + virtual ExtTheory * getExtTheory() { return d_extt; } /* get current substitution at an effort * input : vars @@ -894,6 +904,13 @@ public: * where ( exp[vars[i]] => vars[i] = subs[i] ) holds for all i */ virtual bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) { return false; } + + /* get reduction for node + if return value is not 0, then n is reduced. + if return value <0 then n is reduced SAT-context-independently (e.g. by a lemma that persists at this user-context level). + if nr is non-null, then ( n = nr ) should be added as a lemma by caller, and return value should be <0. + */ + virtual int getReduction( int effort, Node n, Node& nr ) { return 0; } /** * Turn on proof-production mode. @@ -968,15 +985,23 @@ public: class ExtTheory { friend class Theory; typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; + typedef context::CDHashSet<Node, NodeHashFunction> NodeSet; protected: Theory * d_parent; + Node d_true; //extended string terms, map to whether they are active NodeBoolMap d_ext_func_terms; - //any non-reduced extended functions exist - context::CDO< bool > d_has_extf; + //set of terms from d_ext_func_terms that are SAT-context-independently inactive + // (e.g. term t when a reduction lemma of the form t = t' was added) + NodeSet d_ci_inactive; + //cache of all lemmas sent + NodeSet d_lemmas; + NodeSet d_pp_lemmas; + //watched term for checking if any non-reduced extended functions exist + context::CDO< Node > d_has_extf; //extf kind std::map< Kind, bool > d_extf_kind; - //information for extf + //information for each term in d_ext_func_terms class ExtfInfo { public: //all variables in this term @@ -985,25 +1010,49 @@ protected: std::map< Node, ExtfInfo > d_extf_info; //collect variables void collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited ); + // is context dependent inactive + bool isContextIndependentInactive( Node n ); + //do inferences internal + bool doInferencesInternal( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch, bool isRed ); + //send lemma + bool sendLemma( Node lem, bool preprocess = false ); public: ExtTheory( Theory * p ); virtual ~ExtTheory(){} //add extf kind void addFunctionKind( Kind k ) { d_extf_kind[k] = true; } - //do inferences - // input : effort - // output : terms, sterms, exp, where ( exp[i] => terms[i] = sterms[i] ) for all i - void getInferences( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp ); //register term + // adds n to d_ext_func_terms if addFunctionKind( n.getKind() ) was called void registerTerm( Node n ); - //mark reduced - void markReduced( Node n ); - //mark congruent + // set n as reduced/inactive + // if contextDepend = false, then n remains inactive in the duration of this user-context level + void markReduced( Node n, bool contextDepend = true ); + // mark that a and b are congruent terms: set b inactive, set a to inactive if b was inactive void markCongruent( Node a, Node b ); - //is active + + //getSubstitutedTerms + // input : effort, terms + // output : sterms, exp, where ( exp[i] => terms[i] = sterms[i] ) for all i + void getSubstitutedTerms( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp ); + //doInferences + // * input : effort, terms, batch (whether to send one lemma or lemmas for all terms) + // * sends rewriting lemmas of the form ( exp => t = c ) where t is in terms and c is a constant, c = rewrite( t*sigma ) where exp |= sigma + // * output : nred (the terms that are still active) + // * return : true iff lemma is sent + bool doInferences( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch=true ); + bool doInferences( int effort, std::vector< Node >& nred, bool batch=true ); + //doReductions + // same as doInferences, but will send reduction lemmas of the form ( t = t' ) where t is in terms, t' is equivalent, reduced term + bool doReductions( int effort, std::vector< Node >& terms, std::vector< Node >& nred, bool batch=true ); + bool doReductions( int effort, std::vector< Node >& nred, bool batch=true ); + + //has active term + bool hasActiveTerm(); + //is n active bool isActive( Node n ); - //get active + //get the set of active terms from d_ext_func_terms void getActive( std::vector< Node >& active ); + //get the set of active terms from d_ext_func_terms of kind k void getActive( std::vector< Node >& active, Kind k ); }; diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 94281156f..a14534efe 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -1123,6 +1123,15 @@ Node TheoryEngine::preprocess(TNode assertion) { return d_ppCache[assertion]; } +void TheoryEngine::notifyPreprocessedAssertions( std::vector< Node >& assertions ){ + // call all the theories + for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) { + if(d_theoryTable[theoryId]) { + theoryOf(theoryId)->ppNotifyAssertions( assertions ); + } + } +} + bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { // What and where we are asserting @@ -1444,6 +1453,15 @@ void TheoryEngine::getInstantiations( std::map< Node, std::vector< Node > >& ins } } +Node TheoryEngine::getInstantiatedConjunction( Node q ) { + if( d_quantEngine ){ + return d_quantEngine->getInstantiatedConjunction( q ); + }else{ + Assert( false ); + return Node::null(); + } +} + static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) { diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index 9316066a5..4366f8d3a 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -35,7 +35,6 @@ #include "theory/atom_requests.h" #include "theory/bv/bv_to_bool.h" #include "theory/interrupted.h" -#include "theory/quantifiers/quant_conflict_find.h" #include "theory/rewriter.h" #include "theory/shared_terms_database.h" #include "theory/sort_inference.h" @@ -605,6 +604,12 @@ public: */ Node preprocess(TNode node); + + /** + * Notify (preprocessed) assertions + */ + void notifyPreprocessedAssertions( std::vector< Node >& assertions ); + /** * Return whether or not we are incomplete (in the current context). */ @@ -784,6 +789,12 @@ public: * Get instantiations */ void getInstantiations( std::map< Node, std::vector< Node > >& insts ); + + /** + * Get instantiated conjunction, returns q[t1] ^ ... ^ q[tn] where t1...tn are current set of instantiations for q. + * Can be used for quantifier elimination when satisfiable and q[t1] ^ ... ^ q[tn] |= q + */ + Node getInstantiatedConjunction( Node q ); /** * Forwards an entailment check according to the given theoryOfMode. diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h index 7157433f9..c30d1eabc 100644 --- a/src/theory/theory_model.h +++ b/src/theory/theory_model.h @@ -53,7 +53,7 @@ public: Node d_true; Node d_false; mutable std::hash_map<Node, Node, NodeHashFunction> d_modelCache; -public: +public: /** comment stream to include in printing */ std::stringstream d_comment_str; /** get comments */ diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp index 09d348584..5d929a708 100644 --- a/src/theory/uf/equality_engine.cpp +++ b/src/theory/uf/equality_engine.cpp @@ -97,7 +97,7 @@ void EqualityEngine::init() { d_freshMergeReasonType = eq::NUMBER_OF_MERGE_REASONS; } -EqualityEngine::~EqualityEngine() throw(AssertionException) { +EqualityEngine::~EqualityEngine() { free(d_triggerDatabase); } @@ -987,7 +987,14 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec } if (eqp) { - if(eqp->d_children.size() == 1) { + if (eqp->d_children.size() == 0) { + // Corner case where this is actually a disequality between two constants + Debug("pf::ee") << "Encountered a constant disequality (not a transitivity proof): " + << eqp->d_node << std::endl; + Assert(eqp->d_node[0][0].isConst()); + Assert(eqp->d_node[0][1].isConst()); + eqp->d_id = MERGED_THROUGH_CONSTANTS; + } else if (eqp->d_children.size() == 1) { // The transitivity proof has just one child. Simplify. EqProof* temp = eqp->d_children[0]; eqp->d_children.clear(); diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h index 843e7ce7f..18e83bd1a 100644 --- a/src/theory/uf/equality_engine.h +++ b/src/theory/uf/equality_engine.h @@ -186,7 +186,7 @@ public: /** * Just a destructor. */ - virtual ~EqualityEngine() throw(AssertionException); + virtual ~EqualityEngine(); /** * Set the master equality engine for this one. Master engine will get copies of all diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp index cda94e1c4..4713c7dcf 100644 --- a/src/theory/uf/theory_uf_strong_solver.cpp +++ b/src/theory/uf/theory_uf_strong_solver.cpp @@ -1645,34 +1645,37 @@ Node SortModel::getCardinalityLiteral( int c ) { StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, - OutputChannel& out, - TheoryUF* th) - : d_out( &out ) - , d_th( th ) - , d_conflict( c, false ) - , d_rep_model() - , d_aloc_com_card( u, 0 ) - , d_com_card_assertions( c ) - , d_min_pos_com_card( c, -1 ) - , d_card_assertions_eqv_lemma( u ) - , d_min_pos_tn_master_card( c, -1 ) - , d_rel_eqc( c ) -{ - if( options::ufssDiseqPropagation() ){ - d_deq_prop = new DisequalityPropagator( th->getQuantifiersEngine(), this ); - }else{ - d_deq_prop = NULL; + OutputChannel& out, TheoryUF* th) + : d_out(&out), + d_th(th), + d_conflict(c, false), + d_rep_model(), + d_aloc_com_card(u, 0), + d_com_card_assertions(c), + d_min_pos_com_card(c, -1), + d_card_assertions_eqv_lemma(u), + d_min_pos_tn_master_card(c, -1), + d_rel_eqc(c), + d_deq_prop(NULL), + d_sym_break(NULL) { + if (options::ufssDiseqPropagation()) { + d_deq_prop = new DisequalityPropagator(th->getQuantifiersEngine(), this); + } + if (options::ufssSymBreak()) { + d_sym_break = new SubsortSymmetryBreaker(th->getQuantifiersEngine(), c); + } +} + +StrongSolverTheoryUF::~StrongSolverTheoryUF() { + for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin(); + it != d_rep_model.end(); ++it) { + delete it->second; } - if( options::ufssSymBreak() ){ - d_sym_break = new SubsortSymmetryBreaker( th->getQuantifiersEngine(), c ); - }else{ - d_sym_break = NULL; + if (d_sym_break) { + delete d_sym_break; } -} - -StrongSolverTheoryUF::~StrongSolverTheoryUF() { - for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ - delete it->second; + if (d_deq_prop) { + delete d_deq_prop; } } diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h index 4e4dbef83..40026522d 100644 --- a/src/theory/uf/theory_uf_strong_solver.h +++ b/src/theory/uf/theory_uf_strong_solver.h @@ -365,55 +365,10 @@ public: /** get number of regions (for debugging) */ int getNumRegions(); }; /** class SortModel */ -private: - /** The output channel for the strong solver. */ - OutputChannel* d_out; - /** theory uf pointer */ - TheoryUF* d_th; - /** Are we in conflict */ - context::CDO<bool> d_conflict; - /** rep model structure, one for each type */ - std::map< TypeNode, SortModel* > d_rep_model; - /** get sort model */ - SortModel* getSortModel( Node n ); -private: - /** allocated combined cardinality */ - context::CDO< int > d_aloc_com_card; - /** combined cardinality constraints */ - std::map< int, Node > d_com_card_literal; - /** combined cardinality assertions (indexed by cardinality literals ) */ - NodeBoolMap d_com_card_assertions; - /** minimum positive combined cardinality */ - context::CDO< int > d_min_pos_com_card; - /** cardinality literals for which we have added */ - NodeBoolMap d_card_assertions_eqv_lemma; - /** the master monotone type (if ufssFairnessMonotone enabled) */ - TypeNode d_tn_mono_master; - std::map< TypeNode, bool > d_tn_mono_slave; - context::CDO< int > d_min_pos_tn_master_card; - /** initialize */ - void initializeCombinedCardinality(); - /** allocateCombinedCardinality */ - void allocateCombinedCardinality(); - /** check */ - void checkCombinedCardinality(); -private: - /** relevant eqc */ - NodeBoolMap d_rel_eqc; - /** ensure eqc */ - void ensureEqc( SortModel* c, Node a ); - /** ensure eqc for all subterms of n */ - void ensureEqcRec( Node n ); -public: - /** has eqc */ - bool hasEqc( Node a ); -private: - /** disequality propagator */ - DisequalityPropagator* d_deq_prop; - /** symmetry breaking techniques */ - SubsortSymmetryBreaker* d_sym_break; + public: - StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th); + StrongSolverTheoryUF(context::Context* c, context::UserContext* u, + OutputChannel& out, TheoryUF* th); ~StrongSolverTheoryUF(); /** get theory */ TheoryUF* getTheory() { return d_th; } @@ -437,7 +392,6 @@ public: void assertNode( Node n, bool isDecision ); /** are disequal */ bool areDisequal( Node a, Node b ); -public: /** check */ void check( Theory::Effort level ); /** presolve */ @@ -448,18 +402,14 @@ public: Node getNextDecisionRequest(); /** preregister a term */ void preRegisterTerm( TNode n ); - /** preregister a quantifier */ - //void registerQuantifier( Node f ); /** notify restart */ void notifyRestart(); -public: /** identify */ std::string identify() const { return std::string("StrongSolverTheoryUF"); } //print debug void debugPrint( const char* c ); /** debug a model */ bool debugModel( TheoryModel* m ); -public: /** get is in conflict */ bool isConflict() { return d_conflict; } /** get cardinality for node */ @@ -468,9 +418,11 @@ public: int getCardinality( TypeNode tn ); /** minimize */ bool minimize( TheoryModel* m = NULL ); + /** has eqc */ + bool hasEqc(Node a); class Statistics { - public: + public: IntStat d_clique_conflicts; IntStat d_clique_lemmas; IntStat d_split_lemmas; @@ -483,7 +435,50 @@ public: }; /** statistics class */ Statistics d_statistics; -};/* class StrongSolverTheoryUF */ + + private: + /** get sort model */ + SortModel* getSortModel(Node n); + /** initialize */ + void initializeCombinedCardinality(); + /** allocateCombinedCardinality */ + void allocateCombinedCardinality(); + /** check */ + void checkCombinedCardinality(); + /** ensure eqc */ + void ensureEqc(SortModel* c, Node a); + /** ensure eqc for all subterms of n */ + void ensureEqcRec(Node n); + + /** The output channel for the strong solver. */ + OutputChannel* d_out; + /** theory uf pointer */ + TheoryUF* d_th; + /** Are we in conflict */ + context::CDO<bool> d_conflict; + /** rep model structure, one for each type */ + std::map<TypeNode, SortModel*> d_rep_model; + /** allocated combined cardinality */ + context::CDO<int> d_aloc_com_card; + /** combined cardinality constraints */ + std::map<int, Node> d_com_card_literal; + /** combined cardinality assertions (indexed by cardinality literals ) */ + NodeBoolMap d_com_card_assertions; + /** minimum positive combined cardinality */ + context::CDO<int> d_min_pos_com_card; + /** cardinality literals for which we have added */ + NodeBoolMap d_card_assertions_eqv_lemma; + /** the master monotone type (if ufssFairnessMonotone enabled) */ + TypeNode d_tn_mono_master; + std::map<TypeNode, bool> d_tn_mono_slave; + context::CDO<int> d_min_pos_tn_master_card; + /** relevant eqc */ + NodeBoolMap d_rel_eqc; + /** disequality propagator */ + DisequalityPropagator* d_deq_prop; + /** symmetry breaking techniques */ + SubsortSymmetryBreaker* d_sym_break; +}; /* class StrongSolverTheoryUF */ class DisequalityPropagator { public: diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h index ab42aaf15..5d97dda38 100644 --- a/src/theory/uf/theory_uf_type_rules.h +++ b/src/theory/uf/theory_uf_type_rules.h @@ -24,27 +24,31 @@ namespace theory { namespace uf { class UfTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { TNode f = n.getOperator(); TypeNode fType = f.getType(check); - if( !fType.isFunction() ) { - throw TypeCheckingExceptionPrivate(n, "operator does not have function type"); + if (!fType.isFunction()) { + throw TypeCheckingExceptionPrivate( + n, "operator does not have function type"); } - if( check ) { + if (check) { if (n.getNumChildren() != fType.getNumChildren() - 1) { - throw TypeCheckingExceptionPrivate(n, "number of arguments does not match the function type"); + throw TypeCheckingExceptionPrivate( + n, "number of arguments does not match the function type"); } TNode::iterator argument_it = n.begin(); TNode::iterator argument_it_end = n.end(); TypeNode::iterator argument_type_it = fType.begin(); - for(; argument_it != argument_it_end; ++argument_it, ++argument_type_it) { + for (; argument_it != argument_it_end; + ++argument_it, ++argument_type_it) { TypeNode currentArgument = (*argument_it).getType(); TypeNode currentArgumentType = *argument_type_it; - if(!currentArgument.isComparableTo(currentArgumentType)) { + if (!currentArgument.isComparableTo(currentArgumentType)) { std::stringstream ss; - ss << "argument type is not a subtype of the function's argument type:\n" + ss << "argument type is not a subtype of the function's argument " + << "type:\n" << "argument: " << *argument_it << "\n" << "has type: " << (*argument_it).getType() << "\n" << "not subtype: " << *argument_type_it; @@ -54,80 +58,88 @@ public: } return fType.getRangeType(); } -};/* class UfTypeRule */ +}; /* class UfTypeRule */ class CardinalityConstraintTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { // don't care what it is, but it should be well-typed n[0].getType(check); TypeNode valType = n[1].getType(check); - if( valType != nodeManager->integerType() ) { - throw TypeCheckingExceptionPrivate(n, "cardinality constraint must be integer"); + if (valType != nodeManager->integerType()) { + throw TypeCheckingExceptionPrivate( + n, "cardinality constraint must be integer"); } - if( n[1].getKind()!=kind::CONST_RATIONAL ){ - throw TypeCheckingExceptionPrivate(n, "cardinality constraint must be a constant"); + if (n[1].getKind() != kind::CONST_RATIONAL) { + throw TypeCheckingExceptionPrivate( + n, "cardinality constraint must be a constant"); } CVC4::Rational r(INT_MAX); - if( n[1].getConst<Rational>()>r ){ - throw TypeCheckingExceptionPrivate(n, "Exceeded INT_MAX in cardinality constraint"); + if (n[1].getConst<Rational>() > r) { + throw TypeCheckingExceptionPrivate( + n, "Exceeded INT_MAX in cardinality constraint"); } - if( n[1].getConst<Rational>().getNumerator().sgn()!=1 ){ - throw TypeCheckingExceptionPrivate(n, "cardinality constraint must be positive"); + if (n[1].getConst<Rational>().getNumerator().sgn() != 1) { + throw TypeCheckingExceptionPrivate( + n, "cardinality constraint must be positive"); } } return nodeManager->booleanType(); } -};/* class CardinalityConstraintTypeRule */ +}; /* class CardinalityConstraintTypeRule */ class CombinedCardinalityConstraintTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { TypeNode valType = n[0].getType(check); - if( valType != nodeManager->integerType() ) { - throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be integer"); + if (valType != nodeManager->integerType()) { + throw TypeCheckingExceptionPrivate( + n, "combined cardinality constraint must be integer"); } - if( n[0].getKind()!=kind::CONST_RATIONAL ){ - throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be a constant"); + if (n[0].getKind() != kind::CONST_RATIONAL) { + throw TypeCheckingExceptionPrivate( + n, "combined cardinality constraint must be a constant"); } CVC4::Rational r(INT_MAX); - if( n[0].getConst<Rational>()>r ){ - throw TypeCheckingExceptionPrivate(n, "Exceeded INT_MAX in combined cardinality constraint"); + if (n[0].getConst<Rational>() > r) { + throw TypeCheckingExceptionPrivate( + n, "Exceeded INT_MAX in combined cardinality constraint"); } - if( n[0].getConst<Rational>().getNumerator().sgn()==-1 ){ - throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be non-negative"); + if (n[0].getConst<Rational>().getNumerator().sgn() == -1) { + throw TypeCheckingExceptionPrivate( + n, "combined cardinality constraint must be non-negative"); } } return nodeManager->booleanType(); } -};/* class CardinalityConstraintTypeRule */ +}; /* class CardinalityConstraintTypeRule */ class PartialTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw (TypeCheckingExceptionPrivate, AssertionException) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { return n.getOperator().getType().getRangeType(); } -};/* class PartialTypeRule */ +}; /* class PartialTypeRule */ class CardinalityValueTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) - throw(TypeCheckingExceptionPrivate) { - if( check ) { + public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, + bool check) { + if (check) { n[0].getType(check); } return nodeManager->integerType(); } -};/* class CardinalityValueTypeRule */ +}; /* class CardinalityValueTypeRule */ -}/* CVC4::theory::uf namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ +} /* CVC4::theory::uf namespace */ +} /* CVC4::theory namespace */ +} /* CVC4 namespace */ #endif /* __CVC4__THEORY__UF__THEORY_UF_TYPE_RULES_H */ diff --git a/src/theory/unconstrained_simplifier.cpp b/src/theory/unconstrained_simplifier.cpp index 6a33adc56..d13cc1f03 100644 --- a/src/theory/unconstrained_simplifier.cpp +++ b/src/theory/unconstrained_simplifier.cpp @@ -79,7 +79,7 @@ void UnconstrainedSimplifier::visitAll(TNode assertion) d_visitedOnce[current] = parent; if (current.getNumChildren() == 0) { - if (current.isVar()) { + if (current.getKind()==kind::VARIABLE || current.getKind()==kind::SKOLEM) { d_unconstrained.insert(current); } } @@ -563,39 +563,56 @@ void UnconstrainedSimplifier::processUnconstrained() } break; - // Bit-vector comparisons: replace with new Boolean variable, but have to also conjoin with a side condition - // as there is always one case when the comparison is forced to be false + // Bit-vector comparisons: replace with new Boolean variable, but have + // to also conjoin with a side condition as there is always one case + // when the comparison is forced to be false case kind::BITVECTOR_ULT: - strict = true; case kind::BITVECTOR_UGE: - goto bvineq; - case kind::BITVECTOR_UGT: - strict = true; case kind::BITVECTOR_ULE: - swap = true; - goto bvineq; - case kind::BITVECTOR_SLT: - strict = true; case kind::BITVECTOR_SGE: - isSigned = true; - goto bvineq; - case kind::BITVECTOR_SGT: - strict = true; - case kind::BITVECTOR_SLE: - isSigned = true; - swap = true; - - bvineq: { + case kind::BITVECTOR_SLE: { + // Tuples over (signed, swap, strict). + switch (parent.getKind()) { + case kind::BITVECTOR_UGE: + break; + case kind::BITVECTOR_ULT: + strict = true; + break; + case kind::BITVECTOR_ULE: + swap = true; + break; + case kind::BITVECTOR_UGT: + swap = true; + strict = true; + break; + case kind::BITVECTOR_SGE: + isSigned = true; + break; + case kind::BITVECTOR_SLT: + isSigned = true; + strict = true; + break; + case kind::BITVECTOR_SLE: + isSigned = true; + swap = true; + break; + case kind::BITVECTOR_SGT: + isSigned = true; + swap = true; + strict = true; + break; + default: + Unreachable(); + } TNode other; bool left = false; if (parent[0] == current) { other = parent[1]; left = true; - } - else { + } else { Assert(parent[1] == current); other = parent[0]; } @@ -608,14 +625,14 @@ void UnconstrainedSimplifier::processUnconstrained() } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; - } - else { + } else { currentSub = Node(); } - } - else { + } else { unsigned size = current.getType().getBitVectorSize(); - BitVector bv = isSigned ? BitVector(size, Integer(1).multiplyByPow2(size - 1)) : BitVector(size, unsigned(0)); + BitVector bv = + isSigned ? BitVector(size, Integer(1).multiplyByPow2(size - 1)) + : BitVector(size, unsigned(0)); if (swap == left) { bv = ~bv; } @@ -625,14 +642,14 @@ void UnconstrainedSimplifier::processUnconstrained() currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; NodeManager* nm = NodeManager::currentNM(); - Node test = Rewriter::rewrite(other.eqNode(nm->mkConst<BitVector>(bv))); + Node test = + Rewriter::rewrite(other.eqNode(nm->mkConst<BitVector>(bv))); if (test == nm->mkConst<bool>(false)) { break; } if (strict) { currentSub = currentSub.andNode(test.notNode()); - } - else { + } else { currentSub = currentSub.orNode(test); } // Delay adding this substitution - see comment at end of function |