summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
authorPaulMeng <pmtruth@hotmail.com>2016-07-05 13:56:53 -0400
committerPaulMeng <pmtruth@hotmail.com>2016-07-05 13:56:53 -0400
commit36a0d1d948f201471596e092136c5a00103f78af (patch)
tree7a9b0d79074da1cb0c1cbed986584d50792a30e9 /src/theory
parent66525e81928d0d025dbcc197ab3ef772eac31103 (diff)
parenta58abbe71fb1fc07129ff9c7568ac544145fb57c (diff)
Merge branch 'master' of https://github.com/CVC4/CVC4.git
Conflicts: proofs/signatures/Makefile.am src/Makefile.am src/expr/datatype.cpp src/options/datatypes_options src/options/options_template.cpp src/options/quantifiers_options src/proof/arith_proof.cpp src/proof/arith_proof.h src/proof/array_proof.cpp src/proof/array_proof.h src/proof/bitvector_proof.cpp src/proof/bitvector_proof.h src/proof/cnf_proof.cpp src/proof/cnf_proof.h src/proof/proof_manager.cpp src/proof/proof_manager.h src/proof/sat_proof.h src/proof/sat_proof_implementation.h src/proof/skolemization_manager.h src/proof/theory_proof.cpp src/proof/theory_proof.h src/proof/uf_proof.cpp src/proof/uf_proof.h src/prop/cnf_stream.cpp src/prop/cnf_stream.h src/prop/minisat/core/Solver.cc src/prop/prop_engine.cpp src/prop/prop_engine.h src/prop/theory_proxy.cpp src/smt/smt_engine.cpp src/smt/smt_engine_check_proof.cpp src/theory/arrays/array_proof_reconstruction.cpp src/theory/arrays/theory_arrays.cpp src/theory/bv/eager_bitblaster.cpp src/theory/bv/lazy_bitblaster.cpp src/theory/datatypes/theory_datatypes.cpp src/theory/quantifiers/alpha_equivalence.cpp src/theory/quantifiers/candidate_generator.cpp src/theory/quantifiers/candidate_generator.h src/theory/quantifiers/ce_guided_single_inv.cpp src/theory/quantifiers/ceg_instantiator.cpp src/theory/quantifiers/conjecture_generator.cpp src/theory/quantifiers/equality_infer.cpp src/theory/quantifiers/equality_infer.h src/theory/quantifiers/inst_match_generator.cpp src/theory/quantifiers/inst_propagator.cpp src/theory/quantifiers/inst_propagator.h src/theory/quantifiers/inst_strategy_e_matching.cpp src/theory/quantifiers/inst_strategy_e_matching.h src/theory/quantifiers/instantiation_engine.cpp src/theory/quantifiers/model_builder.cpp src/theory/quantifiers/model_engine.cpp src/theory/quantifiers/quant_conflict_find.cpp src/theory/quantifiers/quant_conflict_find.h src/theory/quantifiers/quant_split.cpp src/theory/quantifiers/quant_util.cpp src/theory/quantifiers/quantifiers_rewriter.cpp src/theory/quantifiers/quantifiers_rewriter.h src/theory/quantifiers/term_database.cpp src/theory/quantifiers/term_database.h src/theory/quantifiers/trigger.cpp src/theory/quantifiers/trigger.h src/theory/quantifiers_engine.cpp src/theory/quantifiers_engine.h src/theory/sets/kinds src/theory/sets/theory_sets_private.cpp src/theory/sets/theory_sets_private.h src/theory/sets/theory_sets_rewriter.cpp src/theory/sets/theory_sets_type_rules.h src/theory/strings/theory_strings.cpp src/theory/strings/theory_strings.h src/theory/theory_engine.cpp src/theory/theory_engine.h src/theory/uf/equality_engine.cpp test/regress/regress0/fmf/Makefile.am test/regress/regress0/quantifiers/Makefile.am test/regress/regress0/strings/Makefile.am test/regress/regress0/sygus/Makefile.am test/regress/regress0/sygus/max2-univ.sy
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/arrays/array_proof_reconstruction.cpp51
-rw-r--r--src/theory/arrays/theory_arrays.cpp5
-rw-r--r--src/theory/bv/abstraction.cpp352
-rw-r--r--src/theory/bv/abstraction.h90
-rw-r--r--src/theory/bv/aig_bitblaster.cpp26
-rw-r--r--src/theory/bv/bitblaster_template.h8
-rw-r--r--src/theory/bv/bv_subtheory_algebraic.cpp3
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp37
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h6
-rw-r--r--src/theory/bv/eager_bitblaster.cpp25
-rw-r--r--src/theory/bv/lazy_bitblaster.cpp2
-rw-r--r--src/theory/bv/theory_bv.cpp184
-rw-r--r--src/theory/bv/theory_bv.h47
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h4
-rw-r--r--src/theory/datatypes/datatypes_sygus.cpp283
-rw-r--r--src/theory/datatypes/kinds2
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp337
-rw-r--r--src/theory/datatypes/theory_datatypes.h20
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h3
-rw-r--r--src/theory/datatypes/type_enumerator.cpp2
-rw-r--r--src/theory/datatypes/type_enumerator.h2
-rw-r--r--src/theory/logic_info.cpp11
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/alpha_equivalence.cpp25
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/alpha_equivalence.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ambqi_builder.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ambqi_builder.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/anti_skolem.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/anti_skolem.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/bounded_integers.cpp365
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/bounded_integers.h61
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/candidate_generator.cpp10
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/candidate_generator.h16
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_instantiation.cpp182
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_instantiation.h5
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv.cpp305
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_ei.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_ei.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_sol.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_sol.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ceg_instantiator.cpp48
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ceg_instantiator.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/conjecture_generator.cpp13
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/conjecture_generator.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/equality_infer.cpp49
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/equality_infer.h8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/first_order_model.cpp4
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/first_order_model.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/full_model_check.cpp15
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/full_model_check.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_engine.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_process.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_process.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match_generator.cpp43
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match_generator.h12
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_propagator.cpp476
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_propagator.h28
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_cbqi.cpp10
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_cbqi.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_e_matching.cpp145
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_e_matching.h8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/instantiation_engine.cpp6
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/instantiation_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/kinds0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/local_theory_ext.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/local_theory_ext.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/macros.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/macros.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_builder.cpp43
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_builder.h11
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_engine.cpp56
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.cpp592
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.h26
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_equality_engine.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_equality_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_split.cpp6
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_split.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_util.cpp15
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_util.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_attributes.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_attributes.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_rewriter.cpp518
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_rewriter.h9
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/rewrite_engine.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/rewrite_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/symmetry_breaking.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/symmetry_breaking.h2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/term_database.cpp455
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/term_database.h54
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers.cpp7
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers_type_rules.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/trigger.cpp169
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/trigger.h19
-rw-r--r--src/theory/quantifiers_engine.cpp107
-rw-r--r--src/theory/quantifiers_engine.h8
-rw-r--r--src/theory/rep_set.cpp283
-rw-r--r--src/theory/rep_set.h55
-rw-r--r--src/theory/sep/kinds37
-rw-r--r--src/theory/sep/theory_sep.cpp1534
-rw-r--r--src/theory/sep/theory_sep.h294
-rw-r--r--src/theory/sep/theory_sep_rewriter.cpp184
-rw-r--r--src/theory/sep/theory_sep_rewriter.h53
-rw-r--r--src/theory/sep/theory_sep_type_rules.h114
-rw-r--r--src/theory/sets/kinds1
-rw-r--r--src/theory/sets/theory_sets_private.h14
-rw-r--r--src/theory/sets/theory_sets_type_rules.h1
-rw-r--r--src/theory/strings/regexp_operation.cpp4
-rw-r--r--src/theory/strings/regexp_operation.h1
-rw-r--r--src/theory/strings/theory_strings.cpp511
-rw-r--r--src/theory/strings/theory_strings.h23
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp4
-rw-r--r--src/theory/strings/theory_strings_preprocess.h1
-rw-r--r--src/theory/term_registration_visitor.cpp56
-rw-r--r--src/theory/theory.h8
-rw-r--r--src/theory/theory_engine.cpp372
-rw-r--r--src/theory/theory_engine.h46
-rw-r--r--src/theory/theory_model.cpp3
-rw-r--r--src/theory/theory_model.h4
-rw-r--r--src/theory/type_enumerator.h2
-rw-r--r--src/theory/uf/equality_engine.cpp26
-rw-r--r--src/theory/uf/equality_engine.h8
-rw-r--r--src/theory/uf/theory_uf.cpp167
-rw-r--r--src/theory/uf/theory_uf.h7
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp6
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h2
-rw-r--r--src/theory/valuation.cpp4
-rw-r--r--src/theory/valuation.h6
134 files changed, 6493 insertions, 2775 deletions
diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp
index 11c3dc081..6dfd14157 100644
--- a/src/theory/arrays/array_proof_reconstruction.cpp
+++ b/src/theory/arrays/array_proof_reconstruction.cpp
@@ -101,8 +101,59 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a,
Debug("pf::ee") << "Getting explanation for ROW guard: "
<< indexOne << " != " << indexTwo << std::endl;
+
eq::EqProof* childProof = new eq::EqProof;
d_equalityEngine->explainEquality(indexOne, indexTwo, false, equalities, childProof);
+
+ // 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) {
+ // The proof has two children, explaining why each index is a (different) constant.
+ Assert(childProof->d_children.size() == 2);
+
+ Node constantOne, constantTwo;
+ // Each subproof explains why one of the indices is constant.
+
+ 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);
+ 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];
+ } else {
+ constantOne = childProof->d_children[0]->d_node[0];
+ }
+ }
+
+ 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);
+ 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];
+ } else {
+ constantTwo = childProof->d_children[1]->d_node[0];
+ }
+ }
+
+ eq::EqProof* constantDisequalityProof = new eq::EqProof;
+ constantDisequalityProof->d_id = theory::eq::MERGED_THROUGH_CONSTANTS;
+ constantDisequalityProof->d_node =
+ NodeManager::currentNM()->mkNode(kind::EQUAL, constantOne, constantTwo).negate();
+
+ // Middle is where we need to insert the new disequality
+ std::vector<eq::EqProof *>::iterator middle = childProof->d_children.begin();
+ ++middle;
+
+ childProof->d_children.insert(middle, constantDisequalityProof);
+
+ childProof->d_id = theory::eq::MERGED_THROUGH_TRANS;
+ childProof->d_node =
+ NodeManager::currentNM()->mkNode(kind::EQUAL, indexOne, indexTwo).negate();
+ }
+
proof->d_children.push_back(childProof);
} else {
// This is the case of (i == k) because ((a[i]:=t)[k] != a[k]),
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 6add1b55f..28a08630e 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -829,7 +829,8 @@ void TheoryArrays::propagate(Effort e)
Node TheoryArrays::explain(TNode literal) {
- return explain(literal, NULL);
+ Node explanation = explain(literal, NULL);
+ return explanation;
}
Node TheoryArrays::explain(TNode literal, eq::EqProof *proof)
@@ -1394,6 +1395,7 @@ void TheoryArrays::check(Effort e) {
break;
default:
Unreachable();
+ break;
}
}
@@ -2231,6 +2233,7 @@ bool TheoryArrays::dischargeLemmas()
void TheoryArrays::conflict(TNode a, TNode b) {
Debug("pf::array") << "TheoryArrays::Conflict called" << std::endl;
eq::EqProof* proof = d_proofsEnabled ? new eq::EqProof() : NULL;
+
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b), proof);
} else {
diff --git a/src/theory/bv/abstraction.cpp b/src/theory/bv/abstraction.cpp
index fdc36ce72..dc5520411 100644
--- a/src/theory/bv/abstraction.cpp
+++ b/src/theory/bv/abstraction.cpp
@@ -41,7 +41,7 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
continue;
}
Node signature = computeSignature(assertions[i][j]);
- storeSignature(signature, assertions[i][j]);
+ storeSignature(signature, assertions[i][j]);
Debug("bv-abstraction") << " assertion: " << assertions[i][j] <<"\n";
Debug("bv-abstraction") << " signature: " << signature <<"\n";
}
@@ -52,7 +52,7 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
for (unsigned i = 0; i < assertions.size(); ++i) {
if (assertions[i].getKind() == kind::OR &&
assertions[i][0].getKind() == kind::AND) {
- std::vector<Node> new_children;
+ std::vector<Node> new_children;
for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) {
if (hasSignature(assertions[i][j])) {
new_children.push_back(abstractSignatures(assertions[i][j]));
@@ -60,10 +60,10 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
new_children.push_back(assertions[i][j]);
}
}
- new_assertions.push_back(utils::mkNode(kind::OR, new_children));
+ new_assertions.push_back(utils::mkNode(kind::OR, new_children));
} else {
// assertions that are not changed
- new_assertions.push_back(assertions[i]);
+ new_assertions.push_back(assertions[i]);
}
}
@@ -71,21 +71,21 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
skolemizeArguments(new_assertions);
}
-
+
// if we are using the eager solver reverse the abstraction
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
if (d_funcToSignature.size() == 0) {
// we did not change anything
return false;
}
- NodeNodeMap seen;
+ NodeNodeMap seen;
for (unsigned i = 0; i < new_assertions.size(); ++i) {
- new_assertions[i] = reverseAbstraction(new_assertions[i], seen);
+ new_assertions[i] = reverseAbstraction(new_assertions[i], seen);
}
// we undo the abstraction functions so the logic is QF_BV still
- return true;
+ return true;
}
-
+
// return true if we have created new function symbols for the problem
return d_funcToSignature.size() != 0;
}
@@ -99,7 +99,7 @@ bool AbstractionModule::isConjunctionOfAtoms(TNode node) {
bool AbstractionModule::isConjunctionOfAtomsRec(TNode node, TNodeSet& seen) {
if (seen.find(node)!= seen.end())
return true;
-
+
if (!node.getType().isBitVector()) {
return (node.getKind() == kind::AND || utils::isBVPredicate(node));
}
@@ -120,30 +120,30 @@ Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) {
if (seen.find(assertion) != seen.end())
return seen[assertion];
-
+
if (isAbstraction(assertion)) {
Node interp = getInterpretation(assertion);
seen[assertion] = interp;
- Assert (interp.getType() == assertion.getType());
+ Assert (interp.getType() == assertion.getType());
return interp;
}
if (assertion.getNumChildren() == 0) {
seen[assertion] = assertion;
- return assertion;
+ return assertion;
}
-
+
NodeBuilder<> result(assertion.getKind());
if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) {
- result << assertion.getOperator();
+ result << assertion.getOperator();
}
for (unsigned i = 0; i < assertion.getNumChildren(); ++i) {
- result << reverseAbstraction(assertion[i], seen);
+ result << reverseAbstraction(assertion[i], seen);
}
Node res = result;
seen[assertion] = res;
- return res;
+ return res;
}
void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
@@ -151,7 +151,7 @@ void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
TNode assertion = assertions[i];
if (assertion.getKind() != kind::OR)
continue;
-
+
bool is_skolemizable = true;
for (unsigned k = 0; k < assertion.getNumChildren(); ++k) {
if (assertion[k].getKind() != kind::EQUAL ||
@@ -191,54 +191,54 @@ void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
NodeBuilder<> skolem_func (kind::APPLY_UF);
skolem_func << func;
std::vector<Node> skolem_args;
-
+
for (unsigned j = 0; j < args.getArity(); ++j) {
bool all_same = true;
for (unsigned k = 1; k < args.getNumEntries(); ++k) {
if ( args.getEntry(k)[j] != args.getEntry(0)[j])
- all_same = false;
+ all_same = false;
}
- Node new_arg = all_same ? (Node)args.getEntry(0)[j] : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
+ Node new_arg = all_same ? (Node)args.getEntry(0)[j] : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
skolem_args.push_back(new_arg);
- skolem_func << new_arg;
+ skolem_func << new_arg;
}
-
- Node skolem_func_eq1 = utils::mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
-
+
+ Node skolem_func_eq1 = utils::mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
+
// enumerate arguments assignments
- std::vector<Node> or_assignments;
+ std::vector<Node> or_assignments;
for (ArgsTableEntry::iterator it = args.begin(); it != args.end(); ++it) {
NodeBuilder<> arg_assignment(kind::AND);
ArgsVec& args = *it;
for (unsigned k = 0; k < args.size(); ++k) {
Node eq = utils::mkNode(kind::EQUAL, args[k], skolem_args[k]);
- arg_assignment << eq;
+ arg_assignment << eq;
}
or_assignments.push_back(arg_assignment);
}
-
+
Node new_func_def = utils::mkNode(kind::AND, skolem_func_eq1, utils::mkNode(kind::OR, or_assignments));
- assertion_builder << new_func_def;
+ assertion_builder << new_func_def;
}
Node new_assertion = assertion_builder;
Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments " << assertions[i] << " => \n";
- Debug("bv-abstraction-dbg") << " " << new_assertion;
+ Debug("bv-abstraction-dbg") << " " << new_assertion;
assertions[i] = new_assertion;
}
}
void AbstractionModule::storeSignature(Node signature, TNode assertion) {
if(d_signatures.find(signature) == d_signatures.end()) {
- d_signatures[signature] = 0;
+ d_signatures[signature] = 0;
}
- d_signatures[signature] = d_signatures[signature] + 1;
- d_assertionToSignature[assertion] = signature;
+ d_signatures[signature] = d_signatures[signature] + 1;
+ d_assertionToSignature[assertion] = signature;
}
Node AbstractionModule::computeSignature(TNode node) {
- resetSignatureIndex();
- NodeNodeMap cache;
+ resetSignatureIndex();
+ NodeNodeMap cache;
Node sig = computeSignatureRec(node, cache);
return sig;
}
@@ -247,17 +247,17 @@ Node AbstractionModule::getSignatureSkolem(TNode node) {
Assert (node.getKind() == kind::VARIABLE);
unsigned bitwidth = utils::getSize(node);
if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end()) {
- d_signatureSkolems[bitwidth] = vector<Node>();
+ d_signatureSkolems[bitwidth] = vector<Node>();
}
-
+
vector<Node>& skolems = d_signatureSkolems[bitwidth];
// get the index of bv variables of this size
- unsigned index = getBitwidthIndex(bitwidth);
+ unsigned index = getBitwidthIndex(bitwidth);
Assert (skolems.size() + 1 >= index );
if (skolems.size() == index) {
ostringstream os;
os << "sig_" <<bitwidth <<"_" << index;
- NodeManager* nm = NodeManager::currentNM();
+ NodeManager* nm = NodeManager::currentNM();
skolems.push_back(nm->mkSkolem(os.str(), nm->mkBitVectorType(bitwidth), "skolem for computing signatures"));
}
++(d_signatureIndices[bitwidth]);
@@ -268,12 +268,12 @@ unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) {
if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) {
d_signatureIndices[bitwidth] = 0;
}
- return d_signatureIndices[bitwidth];
+ return d_signatureIndices[bitwidth];
}
void AbstractionModule::resetSignatureIndex() {
for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) {
- it->second = 0;
+ it->second = 0;
}
}
@@ -282,24 +282,24 @@ bool AbstractionModule::hasSignature(Node node) {
}
Node AbstractionModule::getGeneralizedSignature(Node node) {
- NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
+ NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
Assert (it != d_assertionToSignature.end());
- Node generalized_signature = getGeneralization(it->second);
- return generalized_signature;
+ Node generalized_signature = getGeneralization(it->second);
+ return generalized_signature;
}
Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
if (cache.find(node) != cache.end()) {
- return cache.find(node)->second;
+ return cache.find(node)->second;
}
-
+
if (node.getNumChildren() == 0) {
if (node.getKind() == kind::CONST_BITVECTOR)
return node;
Node sig = getSignatureSkolem(node);
- cache[node] = sig;
- return sig;
+ cache[node] = sig;
+ return sig;
}
NodeBuilder<> builder(node.getKind());
@@ -308,30 +308,30 @@ Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
}
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
Node converted = computeSignatureRec(node[i], cache);
- builder << converted;
+ builder << converted;
}
Node result = builder;
cache[node] = result;
- return result;
+ return result;
}
-/**
+/**
* Returns 0, if the two are equal,
* 1 if s is a generalization of t
* 2 if t is a generalization of s
* -1 if the two cannot be unified
*
- * @param s
- * @param t
- *
- * @return
+ * @param s
+ * @param t
+ *
+ * @return
*/
int AbstractionModule::comparePatterns(TNode s, TNode t) {
if (s.getKind() == kind::SKOLEM &&
t.getKind() == kind::SKOLEM) {
return 0;
}
-
+
if (s.getKind() == kind::CONST_BITVECTOR &&
t.getKind() == kind::CONST_BITVECTOR) {
if (s == t) {
@@ -350,7 +350,7 @@ int AbstractionModule::comparePatterns(TNode s, TNode t) {
t.getKind() == kind::SKOLEM) {
return 2;
}
-
+
if (s.getNumChildren() != t.getNumChildren() ||
s.getKind() != t.getKind())
return -1;
@@ -370,26 +370,26 @@ int AbstractionModule::comparePatterns(TNode s, TNode t) {
}
TNode AbstractionModule::getGeneralization(TNode term) {
- NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
+ NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
// if not in the map we add it
if (it == d_sigToGeneralization.end()) {
d_sigToGeneralization[term] = term;
- return term;
+ return term;
}
- // doesn't have a generalization
+ // doesn't have a generalization
if (it->second == term)
return term;
-
+
TNode generalization = getGeneralization(it->second);
Assert (generalization != term);
d_sigToGeneralization[term] = generalization;
- return generalization;
+ return generalization;
}
void AbstractionModule::storeGeneralization(TNode s, TNode t) {
Assert (s == getGeneralization(s));
Assert (t == getGeneralization(t));
- d_sigToGeneralization[s] = t;
+ d_sigToGeneralization[s] = t;
}
void AbstractionModule::finalizeSignatures() {
@@ -402,29 +402,29 @@ void AbstractionModule::finalizeSignatures() {
for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt) {
TNode t = getGeneralization(tt->first);
TNode s = getGeneralization(ss->first);
-
+
if (t != s) {
int status = comparePatterns(s, t);
- Assert (status);
+ Assert (status);
if (status < 0)
continue;
if (status == 1) {
- storeGeneralization(t, s);
+ storeGeneralization(t, s);
} else {
- storeGeneralization(s, t);
+ storeGeneralization(s, t);
}
}
}
}
// keep only most general signatures
for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
- TNode sig = it->first;
+ TNode sig = it->first;
TNode gen = getGeneralization(sig);
if (sig != gen) {
- Assert (d_signatures.find(gen) != d_signatures.end());
+ Assert (d_signatures.find(gen) != d_signatures.end());
// update the count
d_signatures[gen]+= d_signatures[sig];
- d_signatures.erase(it++);
+ d_signatures.erase(it++);
} else {
++it;
}
@@ -434,12 +434,12 @@ void AbstractionModule::finalizeSignatures() {
// remove signatures that are not frequent enough
for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
if (it->second <= 7) {
- d_signatures.erase(it++);
+ d_signatures.erase(it++);
} else {
++it;
}
}
-
+
for (SignatureMap::const_iterator it = d_signatures.begin(); it != d_signatures.end(); ++it) {
TNode signature = it->first;
// we already processed this signature
@@ -451,31 +451,31 @@ void AbstractionModule::finalizeSignatures() {
collectArgumentTypes(signature, arg_types, seen);
Assert (signature.getType().isBoolean());
// make function return a bitvector of size 1
- //Node bv_function = utils::mkNode(kind::ITE, signature, utils::mkConst(1, 1u), utils::mkConst(1, 0u));
+ //Node bv_function = utils::mkNode(kind::ITE, signature, utils::mkConst(1, 1u), utils::mkConst(1, 0u));
TypeNode range = NodeManager::currentNM()->mkBitVectorType(1);
-
+
TypeNode abs_type = nm->mkFunctionType(arg_types, range);
Node abs_func = nm->mkSkolem("abs_$$", abs_type, "abstraction function for bv theory");
Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n";
// NOTE: signature expression type is BOOLEAN
d_signatureToFunc[signature] = abs_func;
- d_funcToSignature[abs_func] = signature;
+ d_funcToSignature[abs_func] = signature;
}
d_statistics.d_numFunctionsAbstracted.setData(d_signatureToFunc.size());
-
+
Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted " << d_signatureToFunc.size() << " signatures. \n";
}
void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) {
if (seen.find(sig) != seen.end())
return;
-
+
if (sig.getKind() == kind::SKOLEM) {
types.push_back(sig.getType());
- seen.insert(sig);
- return;
+ seen.insert(sig);
+ return;
}
for (unsigned i = 0; i < sig.getNumChildren(); ++i) {
@@ -487,36 +487,36 @@ void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& t
void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) {
if (seen.find(node)!= seen.end())
return;
-
+
if (node.getKind() == kind::VARIABLE ||
node.getKind() == kind::CONST_BITVECTOR) {
// a constant in the node can either map to an argument of the abstraction
- // or can be hard-coded and part of the abstraction
+ // or can be hard-coded and part of the abstraction
if (signature.getKind() == kind::SKOLEM) {
args.push_back(node);
seen.insert(node);
} else {
- Assert (signature.getKind() == kind::CONST_BITVECTOR);
+ Assert (signature.getKind() == kind::CONST_BITVECTOR);
}
- //
- return;
+ //
+ return;
}
Assert (node.getKind() == signature.getKind() &&
- node.getNumChildren() == signature.getNumChildren());
+ node.getNumChildren() == signature.getNumChildren());
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- collectArguments(node[i], signature[i], args, seen);
- seen.insert(node);
+ collectArguments(node[i], signature[i], args, seen);
+ seen.insert(node);
}
}
Node AbstractionModule::abstractSignatures(TNode assertion) {
- Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "<< assertion <<"\n";
+ Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "<< assertion <<"\n";
// assume the assertion has been fully abstracted
Node signature = getGeneralizedSignature(assertion);
-
- Debug("bv-abstraction") << " with sig "<< signature <<"\n";
+
+ Debug("bv-abstraction") << " with sig "<< signature <<"\n";
NodeNodeMap::iterator it = d_signatureToFunc.find(signature);
if (it!= d_signatureToFunc.end()) {
std::vector<Node> args;
@@ -527,16 +527,16 @@ Node AbstractionModule::abstractSignatures(TNode assertion) {
collectArguments(assertion, signature, args, seen);
std::vector<TNode> real_args;
for (unsigned i = 1; i < args.size(); ++i) {
- real_args.push_back(args[i]);
+ real_args.push_back(args[i]);
}
- d_argsTable.addEntry(func, real_args);
- Node result = utils::mkNode(kind::EQUAL, utils::mkNode(kind::APPLY_UF, args),
+ d_argsTable.addEntry(func, real_args);
+ Node result = utils::mkNode(kind::EQUAL, utils::mkNode(kind::APPLY_UF, args),
utils::mkConst(1, 1u));
- Debug("bv-abstraction") << "=> "<< result << "\n";
- Assert (result.getType() == assertion.getType());
- return result;
+ Debug("bv-abstraction") << "=> "<< result << "\n";
+ Assert (result.getType() == assertion.getType());
+ return result;
}
- return assertion;
+ return assertion;
}
bool AbstractionModule::isAbstraction(TNode node) {
@@ -557,11 +557,11 @@ bool AbstractionModule::isAbstraction(TNode node) {
if (constant != utils::mkConst(1, 1u))
return false;
- TNode func_symbol = func.getOperator();
+ TNode func_symbol = func.getOperator();
if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end())
return false;
- return true;
+ return true;
}
Node AbstractionModule::getInterpretation(TNode node) {
@@ -571,51 +571,51 @@ Node AbstractionModule::getInterpretation(TNode node) {
Assert (constant.getKind() == kind::CONST_BITVECTOR &&
apply.getKind() == kind::APPLY_UF);
- Node func = apply.getOperator();
+ Node func = apply.getOperator();
Assert (d_funcToSignature.find(func) != d_funcToSignature.end());
-
+
Node sig = d_funcToSignature[func];
-
+
// substitute arguments in signature
TNodeTNodeMap seen;
unsigned index = 0;
Node result = substituteArguments(sig, apply, index, seen);
- Assert (result.getType().isBoolean());
+ Assert (result.getType().isBoolean());
Assert (index == apply.getNumChildren());
// Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n";
// Debug("bv-abstraction") << " => " << result << "\n";
- return result;
+ return result;
}
Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) {
if (seen.find(signature) != seen.end()) {
- return seen[signature];
+ return seen[signature];
}
-
+
if (signature.getKind() == kind::SKOLEM) {
// return corresponding argument and increment counter
seen[signature] = apply[index];
- return apply[index++];
+ return apply[index++];
}
if (signature.getNumChildren() == 0) {
Assert (signature.getKind() != kind::VARIABLE &&
- signature.getKind() != kind::SKOLEM);
+ signature.getKind() != kind::SKOLEM);
seen[signature] = signature;
- return signature;
+ return signature;
}
-
+
NodeBuilder<> builder(signature.getKind());
if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) {
builder << signature.getOperator();
}
-
+
for (unsigned i = 0; i < signature.getNumChildren(); ++i) {
Node child = substituteArguments(signature[i], apply, index, seen);
- builder << child;
+ builder << child;
}
- Node result = builder;
+ Node result = builder;
seen[signature]= result;
return result;
@@ -625,20 +625,20 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
if (Dump.isOn("bv-abstraction")) {
NodeNodeMap seen;
Node c = reverseAbstraction(conflict, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(c.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
- Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
+ Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
if (conflict.getKind() != kind::AND)
- return conflict;
+ return conflict;
std::vector<Node> conjuncts;
for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
conjuncts.push_back(conflict[i]);
-
+
theory::SubstitutionMap subst(new context::Context());
for (unsigned i = 0; i < conjuncts.size(); ++i) {
TNode conjunct = conjuncts[i];
@@ -658,12 +658,12 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
} else {
continue;
}
-
+
Assert (!subst.hasSubstitution(s));
Assert (!t.isNull() &&
!s.isNull() &&
s!= t);
- subst.addSubstitution(s, t);
+ subst.addSubstitution(s, t);
for (unsigned k = 0; k < conjuncts.size(); k++) {
conjuncts[k] = subst.apply(conjuncts[k]);
@@ -671,28 +671,28 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
}
}
Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts));
-
+
Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
Debug("bv-abstraction") << " => " << new_conflict <<"\n";
if (Dump.isOn("bv-abstraction")) {
-
+
NodeNodeMap seen;
Node nc = reverseAbstraction(new_conflict, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(nc.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
-
- return new_conflict;
+
+ return new_conflict;
}
void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instantiations,
const std::vector<TNode> functions) {
// print header
- Debug("bv-abstraction-dbg") <<"[ ";
+ Debug("bv-abstraction-dbg") <<"[ ";
for (unsigned i = 0; i < functions.size(); ++i) {
for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) {
Debug("bv-abstraction-dgb") << functions[i][j] <<" ";
@@ -706,16 +706,16 @@ void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instant
const std::vector<ArgsVec>& inst = instantiations[i];
for (unsigned j = 0; j < inst.size(); ++j) {
for (unsigned k = 0; k < inst[j].size(); ++k) {
- Debug("bv-abstraction-dbg") << inst[j][k] << " ";
+ Debug("bv-abstraction-dbg") << inst[j][k] << " ";
}
- Debug("bv-abstraction-dbg") << " || ";
+ Debug("bv-abstraction-dbg") << " || ";
}
Debug("bv-abstraction-dbg") <<"]\n";
}
}
void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) {
- Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
+ Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
std::vector<TNode> functions;
// collect abstract functions
@@ -737,11 +737,11 @@ void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& le
// if (functions.size() >= 3) {
// // dump conflict
// NodeNodeMap seen;
- // Node reversed = reverseAbstraction(conflict, seen);
- // std::cout << "CONFLICT " << reversed << "\n";
+ // Node reversed = reverseAbstraction(conflict, seen);
+ // std::cout << "CONFLICT " << reversed << "\n";
// }
-
+
if (functions.size() == 0 || functions.size() > options::bvNumFunc()) {
return;
}
@@ -751,31 +751,31 @@ void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& le
SubstitutionMap skolem_subst(new context::Context());
SubstitutionMap reverse_skolem(new context::Context());
makeFreshSkolems(conflict, skolem_subst, reverse_skolem);
-
+
Node skolemized_conflict = skolem_subst.apply(conflict);
for (unsigned i = 0; i < functions.size(); ++i) {
functions[i] = skolem_subst.apply(functions[i]);
}
- conflict = skolem_subst.apply(conflict);
+ conflict = skolem_subst.apply(conflict);
LemmaInstantiatior inst(functions, d_argsTable, conflict);
std::vector<Node> new_lemmas;
- inst.generateInstantiations(new_lemmas);
+ inst.generateInstantiations(new_lemmas);
for (unsigned i = 0; i < new_lemmas.size(); ++i) {
TNode lemma = reverse_skolem.apply(new_lemmas[i]);
if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) {
lemmas.push_back(lemma);
- Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
+ Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
storeLemma(lemma);
if (Dump.isOn("bv-abstraction")) {
NodeNodeMap seen;
Node l = reverseAbstraction(lemma, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(l.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
}
}
@@ -787,18 +787,18 @@ int AbstractionModule::LemmaInstantiatior::next(int val, int index) {
return -1;
}
-/**
+/**
* Assumes the stack without top is consistent, and checks that the
* full stack is consistent
- *
- * @param stack
- *
- * @return
+ *
+ * @param stack
+ *
+ * @return
*/
bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) {
if (stack.empty())
return true;
-
+
unsigned current = stack.size() - 1;
TNode func = d_functions[current];
ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator());
@@ -807,12 +807,12 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
for (unsigned k = 0; k < args.size(); ++k) {
TNode s = func[k];
TNode t = args[k];
-
+
TNode s0 = s;
while (d_subst.hasSubstitution(s0)) {
s0 = d_subst.getSubstitution(s0);
}
-
+
TNode t0 = t;
while (d_subst.hasSubstitution(t0)) {
t0 = d_subst.getSubstitution(t0);
@@ -824,7 +824,7 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
else
continue;
}
-
+
if(s0.getMetaKind() == kind::metakind::VARIABLE &&
t0.isConst()) {
d_subst.addSubstitution(s0, t0);
@@ -839,12 +839,12 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
t0.getMetaKind() == kind::metakind::VARIABLE);
-
+
if (s0 != t0) {
d_subst.addSubstitution(s0, t0);
}
}
- return true;
+ return true;
}
bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
@@ -854,13 +854,13 @@ bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
void AbstractionModule::LemmaInstantiatior::mkLemma() {
Node lemma = d_subst.apply(d_conflict);
// Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n";
- d_lemmas.push_back(lemma);
+ d_lemmas.push_back(lemma);
}
void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
if (!isConsistent(stack))
return;
-
+
if (accept(stack)) {
mkLemma();
return;
@@ -871,7 +871,7 @@ void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
d_ctx->push();
stack.push_back(x);
backtrack(stack);
-
+
d_ctx->pop();
stack.pop_back();
x = next(x, stack.size());
@@ -880,13 +880,13 @@ void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) {
- Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
+ Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
std::vector<int> stack;
backtrack(stack);
- Assert (d_ctx->getLevel() == 0);
- Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
- lemmas.swap(d_lemmas);
+ Assert (d_ctx->getLevel() == 0);
+ Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
+ lemmas.swap(d_lemmas);
}
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
@@ -910,7 +910,7 @@ void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, Subst
void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
Assert (fresh_args.size() == 0);
Assert (func.getKind() == kind::APPLY_UF);
- TNodeNodeMap d_map;
+ TNodeNodeMap d_map;
for (unsigned i = 0; i < func.getNumChildren(); ++i) {
TNode arg = func[i];
if (arg.isConst()) {
@@ -918,9 +918,9 @@ void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args)
continue;
}
Assert (arg.getMetaKind() == kind::metakind::VARIABLE);
- TNodeNodeMap::iterator it = d_map.find(arg);
+ TNodeNodeMap::iterator it = d_map.find(arg);
if (it != d_map.end()) {
- fresh_args.push_back(it->second);
+ fresh_args.push_back(it->second);
} else {
Node skolem = utils::mkVar(utils::getSize(arg));
d_map[arg] = skolem;
@@ -947,7 +947,7 @@ Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vect
Debug("bv-abstraction-dbg") <<"\n";
}
-
+
SubstitutionMap subst(new context::Context());
for (unsigned i = 0; i < ss.size(); ++i) {
@@ -982,10 +982,10 @@ Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vect
Assert (s0 != t0);
subst.addSubstitution(s0, t0);
}
-
+
Node res = subst.apply(conflict);
- Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n";
- return res;
+ Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n";
+ return res;
}
void AbstractionModule::storeLemma(TNode lemma) {
@@ -996,7 +996,7 @@ void AbstractionModule::storeLemma(TNode lemma) {
atom = atom.getKind() == kind::NOT ? atom[0] : atom;
Assert (atom.getKind() != kind::NOT);
Assert (utils::isBVPredicate(atom));
- d_lemmaAtoms.insert(atom);
+ d_lemmaAtoms.insert(atom);
}
} else {
lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma;
@@ -1009,9 +1009,9 @@ void AbstractionModule::storeLemma(TNode lemma) {
bool AbstractionModule::isLemmaAtom(TNode node) const {
Assert (node.getType().isBoolean());
node = node.getKind() == kind::NOT? node[0] : node;
-
+
return d_inputAtoms.find(node) == d_inputAtoms.end() &&
- d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
+ d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
}
void AbstractionModule::addInputAtom(TNode atom) {
@@ -1022,31 +1022,31 @@ void AbstractionModule::addInputAtom(TNode atom) {
void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) {
Assert (args.size() == d_arity);
- d_data.push_back(args);
+ d_data.push_back(args);
}
void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) {
if (d_data.find(signature) == d_data.end()) {
- d_data[signature] = ArgsTableEntry(args.size());
+ d_data[signature] = ArgsTableEntry(args.size());
}
ArgsTableEntry& entry = d_data[signature];
- entry.addArguments(args);
+ entry.addArguments(args);
}
bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const {
- return d_data.find(signature) != d_data.end();
+ return d_data.find(signature) != d_data.end();
}
AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) {
Assert (hasEntry(signature));
- return d_data.find(signature)->second;
+ return d_data.find(signature)->second;
}
-AbstractionModule::Statistics::Statistics()
- : d_numFunctionsAbstracted("theory::bv::AbstractioModule::NumFunctionsAbstracted", 0)
- , d_numArgsSkolemized("theory::bv::AbstractioModule::NumArgsSkolemized", 0)
- , d_abstractionTime("theory::bv::AbstractioModule::AbstractionTime")
+AbstractionModule::Statistics::Statistics(const std::string& name)
+ : d_numFunctionsAbstracted(name + "theory::bv::AbstractioModule::NumFunctionsAbstracted", 0)
+ , d_numArgsSkolemized(name + "theory::bv::AbstractioModule::NumArgsSkolemized", 0)
+ , d_abstractionTime(name + "theory::bv::AbstractioModule::AbstractionTime")
{
smtStatisticsRegistry()->registerStat(&d_numFunctionsAbstracted);
smtStatisticsRegistry()->registerStat(&d_numArgsSkolemized);
diff --git a/src/theory/bv/abstraction.h b/src/theory/bv/abstraction.h
index 5d580f6ce..5d48b926e 100644
--- a/src/theory/bv/abstraction.h
+++ b/src/theory/bv/abstraction.h
@@ -38,11 +38,11 @@ class AbstractionModule {
IntStat d_numFunctionsAbstracted;
IntStat d_numArgsSkolemized;
TimerStat d_abstractionTime;
- Statistics();
+ Statistics(const std::string& name);
~Statistics();
};
-
+
class ArgsTableEntry {
std::vector<ArgsVec> d_data;
unsigned d_arity;
@@ -61,11 +61,11 @@ class AbstractionModule {
unsigned getArity() { return d_arity; }
unsigned getNumEntries() { return d_data.size(); }
ArgsVec& getEntry(unsigned i ) { Assert (i < d_data.size()); return d_data[i]; }
- };
+ };
class ArgsTable {
__gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction > d_data;
- bool hasEntry(TNode signature) const;
+ bool hasEntry(TNode signature) const;
public:
typedef __gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction >::iterator iterator;
ArgsTable() {}
@@ -75,12 +75,12 @@ class AbstractionModule {
iterator end() { return d_data.end(); }
};
- /**
+ /**
* Checks if one pattern is a generalization of the other
- *
- * @param s
- * @param t
- *
+ *
+ * @param s
+ * @param t
+ *
* @return 1 if s :> t, 2 if s <: t, 0 if they equivalent and -1 if they are incomparable
*/
static int comparePatterns(TNode s, TNode t);
@@ -93,7 +93,7 @@ class AbstractionModule {
theory::SubstitutionMap d_subst;
TNode d_conflict;
std::vector<Node> d_lemmas;
-
+
void backtrack(std::vector<int>& stack);
int next(int val, int index);
bool isConsistent(const std::vector<int>& stack);
@@ -108,7 +108,7 @@ class AbstractionModule {
, d_conflict(conflict)
, d_lemmas()
{
- Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n";
+ Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n";
// initializing the search space
for (unsigned i = 0; i < functions.size(); ++i) {
TNode func_op = functions[i].getOperator();
@@ -118,31 +118,31 @@ class AbstractionModule {
}
}
- void generateInstantiations(std::vector<Node>& lemmas);
-
+ void generateInstantiations(std::vector<Node>& lemmas);
+
};
-
+
typedef __gnu_cxx::hash_map<Node, std::vector<Node>, NodeHashFunction> NodeVecMap;
typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> NodeTNodeMap;
typedef __gnu_cxx::hash_map<TNode, TNode, TNodeHashFunction> TNodeTNodeMap;
typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeNodeMap;
typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> TNodeNodeMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
- typedef __gnu_cxx::hash_map<unsigned, Node> IntNodeMap;
+ typedef __gnu_cxx::hash_map<unsigned, Node> IntNodeMap;
typedef __gnu_cxx::hash_map<unsigned, unsigned> IndexMap;
typedef __gnu_cxx::hash_map<unsigned, std::vector<Node> > SkolemMap;
typedef __gnu_cxx::hash_map<TNode, unsigned, TNodeHashFunction > SignatureMap;
-
- ArgsTable d_argsTable;
+
+ ArgsTable d_argsTable;
// mapping between signature and uninterpreted function symbol used to
// abstract the signature
NodeNodeMap d_signatureToFunc;
- NodeNodeMap d_funcToSignature;
+ NodeNodeMap d_funcToSignature;
- NodeNodeMap d_assertionToSignature;
+ NodeNodeMap d_assertionToSignature;
SignatureMap d_signatures;
- NodeNodeMap d_sigToGeneralization;
+ NodeNodeMap d_sigToGeneralization;
TNodeSet d_skolems;
// skolems maps
@@ -165,7 +165,7 @@ class AbstractionModule {
Node getGeneralizedSignature(Node node);
Node getSignatureSkolem(TNode node);
- unsigned getBitwidthIndex(unsigned bitwidth);
+ unsigned getBitwidthIndex(unsigned bitwidth);
void resetSignatureIndex();
Node computeSignatureRec(TNode, NodeNodeMap&);
void storeSignature(Node signature, TNode assertion);
@@ -175,14 +175,14 @@ class AbstractionModule {
// crazy instantiation methods
void generateInstantiations(unsigned current,
- std::vector<ArgsTableEntry>& matches,
+ std::vector<ArgsTableEntry>& matches,
std::vector<std::vector<ArgsVec> >& instantiations,
std::vector<std::vector<ArgsVec> >& new_instantiations);
Node tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict);
void makeFreshArgs(TNode func, std::vector<Node>& fresh_args);
void makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map);
-
+
void skolemizeArguments(std::vector<Node>& assertions);
Node reverseAbstraction(Node assertion, NodeNodeMap& seen);
@@ -192,9 +192,9 @@ class AbstractionModule {
void storeLemma(TNode lemma);
Statistics d_statistics;
-
+
public:
- AbstractionModule()
+ AbstractionModule(const std::string& name)
: d_argsTable()
, d_signatureToFunc()
, d_funcToSignature()
@@ -207,34 +207,34 @@ public:
, d_addedLemmas()
, d_lemmaAtoms()
, d_inputAtoms()
- , d_statistics()
+ , d_statistics(name)
{}
- /**
+ /**
* returns true if there are new uninterepreted functions symbols in the output
- *
- * @param assertions
- * @param new_assertions
- *
- * @return
+ *
+ * @param assertions
+ * @param new_assertions
+ *
+ * @return
*/
bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
- /**
- * Returns true if the node represents an abstraction predicate.
- *
- * @param node
- *
- * @return
+ /**
+ * Returns true if the node represents an abstraction predicate.
+ *
+ * @param node
+ *
+ * @return
*/
bool isAbstraction(TNode node);
- /**
- * Returns the interpretation of the abstraction predicate.
- *
- * @param node
- *
- * @return
+ /**
+ * Returns the interpretation of the abstraction predicate.
+ *
+ * @param node
+ *
+ * @return
*/
Node getInterpretation(TNode node);
- Node simplifyConflict(TNode conflict);
+ Node simplifyConflict(TNode conflict);
void generalizeConflict(TNode conflict, std::vector<Node>& lemmas);
void addInputAtom(TNode atom);
bool isLemmaAtom(TNode node) const;
diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp
index 887daa1bd..37e9f4476 100644
--- a/src/theory/bv/aig_bitblaster.cpp
+++ b/src/theory/bv/aig_bitblaster.cpp
@@ -19,7 +19,7 @@
#include "options/bv_options.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
-
+#include "smt/smt_statistics_registry.h"
#ifdef CVC4_USE_ABC
// Function is defined as static in ABC. Not sure how else to do this.
@@ -140,10 +140,24 @@ AigBitblaster::AigBitblaster()
, d_bbAtoms()
, d_aigOutputNode(NULL)
{
- d_nullContext = new context::Context();
- d_satSolver = prop::SatSolverFactory::createMinisat(d_nullContext, "AigBitblaster");
- MinisatEmptyNotify* notify = new MinisatEmptyNotify();
- d_satSolver->setNotify(notify);
+ d_nullContext = new context::Context();
+ switch(options::bvSatSolver()) {
+ case SAT_SOLVER_MINISAT: {
+ prop::BVSatSolverInterface* minisat = prop::SatSolverFactory::createMinisat(d_nullContext,
+ smtStatisticsRegistry(),
+ "AigBitblaster");
+ MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+ minisat->setNotify(notify);
+ d_satSolver = minisat;
+ break;
+ }
+ case SAT_SOLVER_CRYPTOMINISAT:
+ d_satSolver = prop::SatSolverFactory::createCryptoMinisat(smtStatisticsRegistry(),
+ "AigBitblaster");
+ break;
+ default:
+ Unreachable("Unknown SAT solver type");
+ }
}
AigBitblaster::~AigBitblaster() {
@@ -402,7 +416,7 @@ void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
prop::SatLiteral lit(sat_variables[index-1], int_lit < 0);
clause.push_back(lit);
}
- d_satSolver->addClause(clause, false, RULE_INVALID);
+ d_satSolver->addClause(clause, false);
}
}
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
index cfbadbf32..c6c0d6def 100644
--- a/src/theory/bv/bitblaster_template.h
+++ b/src/theory/bv/bitblaster_template.h
@@ -257,7 +257,7 @@ public:
class EagerBitblaster : public TBitblaster<Node> {
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
// sat solver used for bitblasting and associated CnfStream
- prop::BVSatSolverInterface* d_satSolver;
+ prop::SatSolver* d_satSolver;
BitblastingRegistrar* d_bitblastingRegistrar;
context::Context* d_nullContext;
prop::CnfStream* d_cnfStream;
@@ -268,6 +268,8 @@ class EagerBitblaster : public TBitblaster<Node> {
MinisatEmptyNotify d_notify;
+ MinisatEmptyNotify d_notify;
+
Node getModelFromSatSolver(TNode a, bool fullModel);
bool isSharedTerm(TNode node);
@@ -306,7 +308,7 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> {
static Abc_Ntk_t* abcAigNetwork;
context::Context* d_nullContext;
- prop::BVSatSolverInterface* d_satSolver;
+ prop::SatSolver* d_satSolver;
TNodeAigMap d_aigCache;
NodeAigMap d_bbAtoms;
@@ -459,7 +461,7 @@ Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) {
if (Theory::isLeafOf(node, theory::THEORY_BV)) {
// if it is a leaf may ask for fullModel
- value = getModelFromSatSolver(node, fullModel);
+ value = getModelFromSatSolver(node, true);
Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from VarValue" << node <<" => " << value <<"\n";
Assert ((fullModel && !value.isNull() && value.isConst()) || !fullModel);
if (!value.isNull()) {
diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp
index 00d337395..b7e973928 100644
--- a/src/theory/bv/bv_subtheory_algebraic.cpp
+++ b/src/theory/bv/bv_subtheory_algebraic.cpp
@@ -714,7 +714,8 @@ void AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel) {
Assert (!value.isNull() || !fullModel);
// may be a shared term that did not appear in the current assertions
- if (!value.isNull()) {
+ // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
+ if (!value.isNull() && !d_modelMap->hasSubstitution(var)) {
Debug("bitvector-model") << " " << var << " => " << value << "\n";
Assert (value.getKind() == kind::CONST_BITVECTOR);
d_modelMap->addSubstitution(var, value);
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index b7619c4bb..6c6c13ee8 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -37,9 +37,9 @@ namespace bv {
BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
: SubtheorySolver(c, bv),
- d_bitblaster(new TLazyBitblaster(c, bv, "lazy")),
+ d_bitblaster(new TLazyBitblaster(c, bv, bv->getFullInstanceName() + "lazy")),
d_bitblastQueue(c),
- d_statistics(),
+ d_statistics(bv->getFullInstanceName()),
d_validModelCache(c, true),
d_lemmaAtomsQueue(c),
d_useSatPropagation(options::bitvectorPropagate()),
@@ -55,9 +55,9 @@ BitblastSolver::~BitblastSolver() {
delete d_bitblaster;
}
-BitblastSolver::Statistics::Statistics()
- : d_numCallstoCheck("theory::bv::BitblastSolver::NumCallsToCheck", 0)
- , d_numBBLemmas("theory::bv::BitblastSolver::NumTimesLemmasBB", 0)
+BitblastSolver::Statistics::Statistics(const std::string &instanceName)
+ : d_numCallstoCheck(instanceName + "theory::bv::BitblastSolver::NumCallsToCheck", 0)
+ , d_numBBLemmas(instanceName + "theory::bv::BitblastSolver::NumTimesLemmasBB", 0)
{
smtStatisticsRegistry()->registerStat(&d_numCallstoCheck);
smtStatisticsRegistry()->registerStat(&d_numBBLemmas);
@@ -68,8 +68,8 @@ BitblastSolver::Statistics::~Statistics() {
}
void BitblastSolver::setAbstraction(AbstractionModule* abs) {
- d_abstractionModule = abs;
- d_bitblaster->setAbstraction(abs);
+ d_abstractionModule = abs;
+ d_bitblaster->setAbstraction(abs);
}
void BitblastSolver::preRegister(TNode node) {
@@ -117,7 +117,7 @@ void BitblastSolver::bitblastQueue() {
bool BitblastSolver::check(Theory::Effort e) {
Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
- Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
+ Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
++(d_statistics.d_numCallstoCheck);
@@ -135,10 +135,10 @@ bool BitblastSolver::check(Theory::Effort e) {
// skip atoms that are the result of abstraction lemmas
if (d_abstractionModule->isLemmaAtom(fact)) {
d_lemmaAtomsQueue.push_back(fact);
- continue;
+ continue;
}
}
-
+
if (!d_bv->inConflict() &&
(!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
// Some atoms have not been bit-blasted yet
@@ -183,7 +183,7 @@ bool BitblastSolver::check(Theory::Effort e) {
if (options::bvAbstraction() &&
e == Theory::EFFORT_FULL &&
d_lemmaAtomsQueue.size()) {
-
+
// bit-blast lemma atoms
while(!d_lemmaAtomsQueue.empty()) {
TNode lemma_atom = d_lemmaAtomsQueue.front();
@@ -199,7 +199,7 @@ bool BitblastSolver::check(Theory::Effort e) {
return false;
}
}
-
+
Assert(!d_bv->inConflict());
bool ok = d_bitblaster->solve();
if (!ok) {
@@ -210,9 +210,9 @@ bool BitblastSolver::check(Theory::Effort e) {
++(d_statistics.d_numBBLemmas);
return false;
}
-
+
}
-
+
return true;
}
@@ -228,9 +228,9 @@ void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
Node BitblastSolver::getModelValue(TNode node)
{
if (d_bv->d_invalidateModelCache.get()) {
- d_bitblaster->invalidateModelCache();
+ d_bitblaster->invalidateModelCache();
}
- d_bv->d_invalidateModelCache.set(false);
+ d_bv->d_invalidateModelCache.set(false);
Node val = d_bitblaster->getTermModel(node, true);
return val;
}
@@ -241,9 +241,9 @@ void BitblastSolver::setConflict(TNode conflict) {
Node final_conflict = conflict;
if (options::bitvectorQuickXplain() &&
conflict.getKind() == kind::AND) {
- // std::cout << "Original conflict " << conflict.getNumChildren() << "\n";
+ // std::cout << "Original conflict " << conflict.getNumChildren() << "\n";
final_conflict = d_quickXplain->minimizeConflict(conflict);
- //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n";
+ //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n";
}
d_bv->setConflict(final_conflict);
}
@@ -256,4 +256,3 @@ void BitblastSolver::setProofLog( BitVectorProof * bvp ) {
}/* namespace CVC4::theory::bv */
}/* namespace CVC4::theory */
}/* namespace CVC4 */
-
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index e9300138b..fe16d2702 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -37,7 +37,7 @@ class BitblastSolver : public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
IntStat d_numBBLemmas;
- Statistics();
+ Statistics(const std::string &instanceName);
~Statistics();
};
/** Bitblaster */
@@ -71,8 +71,8 @@ public:
Node getModelValue(TNode node);
bool isComplete() { return true; }
void bitblastQueue();
- void setAbstraction(AbstractionModule* module);
- uint64_t computeAtomWeight(TNode atom);
+ void setAbstraction(AbstractionModule* module);
+ uint64_t computeAtomWeight(TNode atom);
void setProofLog( BitVectorProof * bvp );
};
diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp
index 3b54e3794..53fb4f94b 100644
--- a/src/theory/bv/eager_bitblaster.cpp
+++ b/src/theory/bv/eager_bitblaster.cpp
@@ -47,15 +47,30 @@ EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv)
{
d_bitblastingRegistrar = new BitblastingRegistrar(this);
d_nullContext = new context::Context();
-
- d_satSolver = prop::SatSolverFactory::createMinisat(
- d_nullContext, smtStatisticsRegistry(), "EagerBitblaster");
+
+ switch(options::bvSatSolver()) {
+ case SAT_SOLVER_MINISAT: {
+ prop::BVSatSolverInterface* minisat =
+ prop::SatSolverFactory::createMinisat(d_nullContext,
+ smtStatisticsRegistry(),
+ "EagerBitblaster");
+ MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+ minisat->setNotify(notify);
+ d_satSolver = minisat;
+ break;
+ }
+ case SAT_SOLVER_CRYPTOMINISAT:
+ d_satSolver = prop::SatSolverFactory::createCryptoMinisat(smtStatisticsRegistry(),
+ "EagerBitblaster");
+ break;
+ default:
+ Unreachable("Unknown SAT solver type");
+ }
d_cnfStream = new prop::TseitinCnfStream(
d_satSolver, d_bitblastingRegistrar, d_nullContext, options::proof(),
"EagerBitblaster");
- d_satSolver->setNotify(&d_notify);
d_bvp = NULL;
}
@@ -216,7 +231,7 @@ void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
// only shared terms could not have been bit-blasted
Assert (hasBBTerm(var) || isSharedTerm(var));
- Node const_value = getModelFromSatSolver(var, fullModel);
+ Node const_value = getModelFromSatSolver(var, true);
if(const_value != Node()) {
Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= "
diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp
index c821b50cd..b549c329a 100644
--- a/src/theory/bv/lazy_bitblaster.cpp
+++ b/src/theory/bv/lazy_bitblaster.cpp
@@ -491,7 +491,7 @@ void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
// only shared terms could not have been bit-blasted
Assert (hasBBTerm(var) || isSharedTerm(var));
- Node const_value = getModelFromSatSolver(var, fullModel);
+ Node const_value = getModelFromSatSolver(var, true);
Assert (const_value.isNull() || const_value.isConst());
if(const_value != Node()) {
Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 2edadce72..fec93e033 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -44,25 +44,29 @@ namespace bv {
TheoryBV::TheoryBV(context::Context* c, context::UserContext* u,
OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo)
- : Theory(THEORY_BV, c, u, out, valuation, logicInfo),
- d_context(c),
- d_alreadyPropagatedSet(c),
- d_sharedTermsSet(c),
- d_subtheories(),
- d_subtheoryMap(),
- d_statistics(),
- d_staticLearnCache(),
- d_lemmasAdded(c, false),
- d_conflict(c, false),
- d_invalidateModelCache(c, true),
- d_literalsToPropagate(c),
- d_literalsToPropagateIndex(c, 0),
- d_propagatedBy(c),
- d_eagerSolver(NULL),
- d_abstractionModule(new AbstractionModule()),
- d_isCoreTheory(false),
- d_calledPreregister(false)
+ const LogicInfo& logicInfo, std::string name)
+ : Theory(THEORY_BV, c, u, out, valuation, logicInfo, name),
+ d_context(c),
+ d_alreadyPropagatedSet(c),
+ d_sharedTermsSet(c),
+ d_subtheories(),
+ d_subtheoryMap(),
+ d_statistics(getFullInstanceName()),
+ d_staticLearnCache(),
+ d_BVDivByZero(),
+ d_BVRemByZero(),
+ d_funcToArgs(),
+ d_funcToSkolem(u),
+ d_lemmasAdded(c, false),
+ d_conflict(c, false),
+ d_invalidateModelCache(c, true),
+ d_literalsToPropagate(c),
+ d_literalsToPropagateIndex(c, 0),
+ d_propagatedBy(c),
+ d_eagerSolver(NULL),
+ d_abstractionModule(new AbstractionModule(getFullInstanceName())),
+ d_isCoreTheory(false),
+ d_calledPreregister(false)
{
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
@@ -117,14 +121,14 @@ void TheoryBV::spendResource(unsigned ammount) throw(UnsafeInterruptException) {
getOutputChannel().spendResource(ammount);
}
-TheoryBV::Statistics::Statistics():
- d_avgConflictSize("theory::bv::AvgBVConflictSize"),
- d_solveSubstitutions("theory::bv::NumberOfSolveSubstitutions", 0),
- d_solveTimer("theory::bv::solveTimer"),
- d_numCallsToCheckFullEffort("theory::bv::NumberOfFullCheckCalls", 0),
- d_numCallsToCheckStandardEffort("theory::bv::NumberOfStandardCheckCalls", 0),
- d_weightComputationTimer("theory::bv::weightComputationTimer"),
- d_numMultSlice("theory::bv::NumMultSliceApplied", 0)
+TheoryBV::Statistics::Statistics(const std::string &name):
+ d_avgConflictSize(name + "theory::bv::AvgBVConflictSize"),
+ d_solveSubstitutions(name + "theory::bv::NumberOfSolveSubstitutions", 0),
+ d_solveTimer(name + "theory::bv::solveTimer"),
+ d_numCallsToCheckFullEffort(name + "theory::bv::NumberOfFullCheckCalls", 0),
+ d_numCallsToCheckStandardEffort(name + "theory::bv::NumberOfStandardCheckCalls", 0),
+ d_weightComputationTimer(name + "theory::bv::weightComputationTimer"),
+ d_numMultSlice(name + "theory::bv::NumMultSliceApplied", 0)
{
smtStatisticsRegistry()->registerStat(&d_avgConflictSize);
smtStatisticsRegistry()->registerStat(&d_solveSubstitutions);
@@ -175,30 +179,31 @@ Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
}
-void TheoryBV::collectNumerators(TNode term, TNodeSet& seen) {
+void TheoryBV::collectFunctionSymbols(TNode term, TNodeSet& seen) {
if (seen.find(term) != seen.end())
return;
- if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UDIV) {
- unsigned size = utils::getSize(term[0]);
- if (d_BVDivByZeroAckerman.find(size) == d_BVDivByZeroAckerman.end()) {
- d_BVDivByZeroAckerman[size] = TNodeSet();
- }
- d_BVDivByZeroAckerman[size].insert(term[0]);
- seen.insert(term);
- } else if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UREM) {
- unsigned size = utils::getSize(term[0]);
- if (d_BVRemByZeroAckerman.find(size) == d_BVRemByZeroAckerman.end()) {
- d_BVRemByZeroAckerman[size] = TNodeSet();
- }
- d_BVRemByZeroAckerman[size].insert(term[0]);
- seen.insert(term);
+ if (term.getKind() == kind::APPLY_UF) {
+ TNode func = term.getOperator();
+ storeFunction(func, term);
}
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- collectNumerators(term[i], seen);
+ collectFunctionSymbols(term[i], seen);
}
seen.insert(term);
}
+void TheoryBV::storeFunction(TNode func, TNode term) {
+ if (d_funcToArgs.find(func) == d_funcToArgs.end()) {
+ d_funcToArgs.insert(make_pair(func, NodeSet()));
+ }
+ NodeSet& set = d_funcToArgs[func];
+ if (set.find(term) == set.end()) {
+ set.insert(term);
+ Node skolem = utils::mkVar(utils::getSize(term));
+ d_funcToSkolem.addSubstitution(term, skolem);
+ }
+}
+
void TheoryBV::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
Debug("bv-ackermanize") << "TheoryBV::mkAckermanizationAsssertions\n";
@@ -206,51 +211,44 @@ void TheoryBV::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
AlwaysAssert(!options::incrementalSolving());
TNodeSet seen;
for (unsigned i = 0; i < assertions.size(); ++i) {
- collectNumerators(assertions[i], seen);
- }
-
- // process division UF
- Debug("bv-ackermanize") << "Process division UF...\n";
- for (WidthToNumerators::const_iterator it = d_BVDivByZeroAckerman.begin(); it != d_BVDivByZeroAckerman.end(); ++it) {
- const TNodeSet& numerators= it->second;
- for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
- TNodeSet::const_iterator j = i;
- j++;
- for (; j != numerators.end(); ++j) {
- TNode arg1 = *i;
- TNode arg2 = *j;
- TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg1);
- TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg2);
-
- Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
- Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
- Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
- Debug("bv-ackermanize") << " " << lemma << "\n";
- assertions.push_back(lemma);
- }
- }
+ collectFunctionSymbols(assertions[i], seen);
}
- // process remainder UF
- Debug("bv-ackermanize") << "Process remainder UF...\n";
- for (WidthToNumerators::const_iterator it = d_BVRemByZeroAckerman.begin(); it != d_BVRemByZeroAckerman.end(); ++it) {
- const TNodeSet& numerators= it->second;
- for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
- TNodeSet::const_iterator j = i;
- j++;
- for (; j != numerators.end(); ++j) {
- TNode arg1 = *i;
- TNode arg2 = *j;
- TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg1);
- TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg2);
-
- Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
- Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
- Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
- Debug("bv-ackermanize") << " " << lemma << "\n";
+
+ FunctionToArgs::const_iterator it = d_funcToArgs.begin();
+ NodeManager* nm = NodeManager::currentNM();
+ for (; it!= d_funcToArgs.end(); ++it) {
+ TNode func = it->first;
+ const NodeSet& args = it->second;
+ NodeSet::const_iterator it1 = args.begin();
+ for ( ; it1 != args.end(); ++it1) {
+ for(NodeSet::const_iterator it2 = it1; it2 != args.end(); ++it2) {
+ TNode args1 = *it1;
+ TNode args2 = *it2;
+
+ AlwaysAssert (args1.getKind() == kind::APPLY_UF &&
+ args1.getOperator() == func);
+ AlwaysAssert (args2.getKind() == kind::APPLY_UF &&
+ args2.getOperator() == func);
+ AlwaysAssert (args1.getNumChildren() == args2.getNumChildren());
+
+ std::vector<Node> eqs(args1.getNumChildren());
+
+ for (unsigned i = 0; i < args1.getNumChildren(); ++i) {
+ eqs[i] = nm->mkNode(kind::EQUAL, args1[i], args2[i]);
+ }
+
+ Node args_eq = eqs.size() == 1 ? eqs[0] : nm->mkNode(kind::AND, eqs);
+ Node func_eq = nm->mkNode(kind::EQUAL, args1, args2);
+ Node lemma = nm->mkNode(kind::IMPLIES, args_eq, func_eq);
assertions.push_back(lemma);
}
}
}
+
+ // replace applications of UF by skolems (FIXME for model building)
+ for(unsigned i = 0; i < assertions.size(); ++i) {
+ assertions[i] = d_funcToSkolem.apply(assertions[i]);
+ }
}
Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
@@ -278,18 +276,18 @@ Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
kind::BITVECTOR_UREM_TOTAL, num, den);
- if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- // Ackermanize UF if using eager bit-blasting
- Node ackerman_var = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_ACKERMANIZE_UDIV : kind::BITVECTOR_ACKERMANIZE_UREM, num);
- node = nm->mkNode(kind::ITE, den_eq_0, ackerman_var, divTotalNumDen);
- return node;
- } else {
+ // if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ // // Ackermanize UF if using eager bit-blasting
+ // Node ackerman_var = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_ACKERMANIZE_UDIV : kind::BITVECTOR_ACKERMANIZE_UREM, num);
+ // node = nm->mkNode(kind::ITE, den_eq_0, ackerman_var, divTotalNumDen);
+ // return node;
+ // } else {
Node divByZero = getBVDivByZero(node.getKind(), width);
Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
logicRequest.widenLogic(THEORY_UF);
return node;
- }
+ //}
}
break;
@@ -331,7 +329,7 @@ void TheoryBV::sendConflict() {
if (d_conflictNode.isNull()) {
return;
} else {
- Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode;
+ Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode << std::endl;
d_out->conflict(d_conflictNode);
d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
d_conflictNode = Node::null();
@@ -707,7 +705,7 @@ Node TheoryBV::explain(TNode node) {
// return the explanation
Node explanation = utils::mkAnd(assumptions);
Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
- Debug("bitvector::explain") << "TheoryBV::explain done. \n";
+ Debug("bitvector::explain") << "TheoryBV::explain done. \n";
return explanation;
}
@@ -725,6 +723,8 @@ void TheoryBV::addSharedTerm(TNode t) {
EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
{
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
+ return EQUALITY_UNKNOWN;
Assert (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 0bbcba9b0..ba2a4fc2a 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -56,7 +56,8 @@ class TheoryBV : public Theory {
public:
TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out,
- Valuation valuation, const LogicInfo& logicInfo);
+ Valuation valuation, const LogicInfo& logicInfo,
+ std::string name = "");
~TheoryBV();
@@ -88,8 +89,8 @@ public:
void presolve();
- bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
-
+ bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+
void setProofLog( BitVectorProof * bvp );
private:
@@ -100,10 +101,10 @@ private:
IntStat d_solveSubstitutions;
TimerStat d_solveTimer;
IntStat d_numCallsToCheckFullEffort;
- IntStat d_numCallsToCheckStandardEffort;
+ IntStat d_numCallsToCheckStandardEffort;
TimerStat d_weightComputationTimer;
IntStat d_numMultSlice;
- Statistics();
+ Statistics(const std::string &name);
~Statistics();
};
@@ -121,12 +122,12 @@ private:
*/
Node getBVDivByZero(Kind k, unsigned width);
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
- void collectNumerators(TNode term, TNodeSet& seen);
-
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ void collectFunctionSymbols(TNode term, TNodeSet& seen);
+ void storeFunction(TNode func, TNode term);
typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
NodeSet d_staticLearnCache;
-
+
/**
* Maps from bit-vector width to division-by-zero uninterpreted
* function symbols.
@@ -134,17 +135,15 @@ private:
__gnu_cxx::hash_map<unsigned, Node> d_BVDivByZero;
__gnu_cxx::hash_map<unsigned, Node> d_BVRemByZero;
- /**
- * Maps from bit-vector width to numerators
- * of uninterpreted function symbol
- */
- typedef __gnu_cxx::hash_map<unsigned, TNodeSet > WidthToNumerators;
- WidthToNumerators d_BVDivByZeroAckerman;
- WidthToNumerators d_BVRemByZeroAckerman;
+ typedef __gnu_cxx::hash_map<Node, NodeSet, NodeHashFunction> FunctionToArgs;
+ typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeToNode;
+ // for ackermanization
+ FunctionToArgs d_funcToArgs;
+ CVC4::theory::SubstitutionMap d_funcToSkolem;
context::CDO<bool> d_lemmasAdded;
-
+
// Are we in conflict?
context::CDO<bool> d_conflict;
@@ -167,17 +166,17 @@ private:
typedef context::CDHashMap<Node, SubTheory, NodeHashFunction> PropagatedMap;
PropagatedMap d_propagatedBy;
- EagerBitblastSolver* d_eagerSolver;
+ EagerBitblastSolver* d_eagerSolver;
AbstractionModule* d_abstractionModule;
bool d_isCoreTheory;
bool d_calledPreregister;
-
+
bool wasPropagatedBySubtheory(TNode literal) const {
- return d_propagatedBy.find(literal) != d_propagatedBy.end();
+ return d_propagatedBy.find(literal) != d_propagatedBy.end();
}
-
+
SubTheory getPropagatingSubtheory(TNode literal) const {
- Assert(wasPropagatedBySubtheory(literal));
+ Assert(wasPropagatedBySubtheory(literal));
PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
return (*find).second;
}
@@ -193,7 +192,7 @@ private:
void addSharedTerm(TNode t);
bool isSharedTerm(TNode t) { return d_sharedTermsSet.contains(t); }
-
+
EqualityStatus getEqualityStatus(TNode a, TNode b);
Node getModelValue(TNode var);
@@ -214,7 +213,7 @@ private:
void lemma(TNode node) { d_out->lemma(node, RULE_CONFLICT); d_lemmasAdded = true; }
- void checkForLemma(TNode node);
+ void checkForLemma(TNode node);
friend class LazyBitblaster;
friend class TLazyBitblaster;
diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
index 152a335a5..2bcb6ca1b 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -349,7 +349,7 @@ Node RewriteRule<SdivEliminate>::apply(TNode node) {
Node abs_a = utils::mkNode(kind::ITE, a_lt_0, utils::mkNode(kind::BITVECTOR_NEG, a), a);
Node abs_b = utils::mkNode(kind::ITE, b_lt_0, utils::mkNode(kind::BITVECTOR_NEG, b), b);
- Node a_udiv_b = utils::mkNode(kind::BITVECTOR_UDIV, abs_a, abs_b);
+ Node a_udiv_b = utils::mkNode(options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UDIV_TOTAL : kind::BITVECTOR_UDIV, abs_a, abs_b);
Node neg_result = utils::mkNode(kind::BITVECTOR_NEG, a_udiv_b);
Node condition = utils::mkNode(kind::XOR, a_lt_0, b_lt_0);
@@ -377,7 +377,7 @@ Node RewriteRule<SremEliminate>::apply(TNode node) {
Node abs_a = utils::mkNode(kind::ITE, a_lt_0, utils::mkNode(kind::BITVECTOR_NEG, a), a);
Node abs_b = utils::mkNode(kind::ITE, b_lt_0, utils::mkNode(kind::BITVECTOR_NEG, b), b);
- Node a_urem_b = utils::mkNode(kind::BITVECTOR_UREM, abs_a, abs_b);
+ Node a_urem_b = utils::mkNode( options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UREM_TOTAL : kind::BITVECTOR_UREM, abs_a, abs_b);
Node neg_result = utils::mkNode(kind::BITVECTOR_NEG, a_urem_b);
Node result = utils::mkNode(kind::ITE, a_lt_0, neg_result, a_urem_b);
diff --git a/src/theory/datatypes/datatypes_sygus.cpp b/src/theory/datatypes/datatypes_sygus.cpp
index 5bd6680f2..4514453db 100644
--- a/src/theory/datatypes/datatypes_sygus.cpp
+++ b/src/theory/datatypes/datatypes_sygus.cpp
@@ -402,6 +402,60 @@ void SygusSplit::registerSygusTypeConstructorArg( TypeNode tnn, const Datatype&
}
}
+class ReqTrie {
+public:
+ ReqTrie() : d_req_kind( UNDEFINED_KIND ){}
+ std::map< unsigned, ReqTrie > d_children;
+ Kind d_req_kind;
+ TypeNode d_req_type;
+ Node d_req_const;
+ void print( const char * c, int indent = 0 ){
+ if( d_req_kind!=UNDEFINED_KIND ){
+ Trace(c) << d_req_kind << " ";
+ }else if( !d_req_type.isNull() ){
+ Trace(c) << d_req_type;
+ }else if( !d_req_const.isNull() ){
+ Trace(c) << d_req_const;
+ }else{
+ Trace(c) << "_";
+ }
+ Trace(c) << std::endl;
+ for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ for( int i=0; i<=indent; i++ ) { Trace(c) << " "; }
+ Trace(c) << it->first << " : ";
+ it->second.print( c, indent+1 );
+ }
+ }
+ bool satisfiedBy( quantifiers::TermDbSygus * tdb, TypeNode tn ){
+ if( d_req_kind!=UNDEFINED_KIND ){
+ int c = tdb->getKindArg( tn, d_req_kind );
+ if( c!=-1 ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ if( it->first<dt[c].getNumArgs() ){
+ TypeNode tnc = tdb->getArgType( dt[c], it->first );
+ if( !it->second.satisfiedBy( tdb, tnc ) ){
+ return false;
+ }
+ }else{
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+ }else if( !d_req_const.isNull() ){
+ return tdb->hasConst( tn, d_req_const );
+ }else if( !d_req_type.isNull() ){
+ return tn==d_req_type;
+ }else{
+ return true;
+ }
+ }
+};
+
+
//this function gets all easy redundant cases, before consulting rewriters
bool SygusSplit::considerSygusSplitKind( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Kind k, Kind parent, int arg ) {
Assert( d_tds->hasKind( tn, k ) );
@@ -419,101 +473,168 @@ bool SygusSplit::considerSygusSplitKind( const Datatype& dt, const Datatype& pdt
return arg==firstArg;
}
}
- //push
+ //describes the shape of an alternate term to construct
+ // we check whether this term is in the sygus grammar below
+ ReqTrie rt;
+ bool rt_valid = false;
+
+ //construct rt by cases
if( parent==NOT || parent==BITVECTOR_NOT || parent==UMINUS || parent==BITVECTOR_NEG ){
- //negation normal form
- if( parent==k && isArgDatatype( dt[c], 0, pdt ) ){
- return false;
- }
- Kind nk = UNDEFINED_KIND;
- Kind reqk = UNDEFINED_KIND; //required kind for all children
- if( parent==NOT ){
- if( k==AND ) {
- nk = OR;reqk = NOT;
- }else if( k==OR ){
- nk = AND;reqk = NOT;
- }else if( k==IFF ) {
- nk = XOR;
- }else if( k==XOR ) {
- nk = IFF;
- }
- }
- if( parent==BITVECTOR_NOT ){
- if( k==BITVECTOR_AND ) {
- nk = BITVECTOR_OR;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_OR ){
- nk = BITVECTOR_AND;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_XNOR ) {
- nk = BITVECTOR_XOR;
- }else if( k==BITVECTOR_XOR ) {
- nk = BITVECTOR_XNOR;
- }
- }
- if( parent==UMINUS ){
- if( k==PLUS ){
- nk = PLUS;reqk = UMINUS;
- }
- }
- if( parent==BITVECTOR_NEG ){
- if( k==PLUS ){
- nk = PLUS;reqk = BITVECTOR_NEG;
- }
- }
- if( nk!=UNDEFINED_KIND ){
- Trace("sygus-split-debug") << "Push " << parent << " over " << k << " to " << nk;
- if( reqk!=UNDEFINED_KIND ){
- Trace("sygus-split-debug") << ", reqk = " << reqk;
+ rt_valid = true;
+ //negation normal form
+ if( parent==k ){
+ rt.d_req_type = d_tds->getArgType( dt[c], 0 );
+ }else{
+ Kind reqk = UNDEFINED_KIND; //required kind for all children
+ std::map< unsigned, Kind > reqkc; //required kind for some children
+ if( parent==NOT ){
+ if( k==AND ) {
+ rt.d_req_kind = OR;reqk = NOT;
+ }else if( k==OR ){
+ rt.d_req_kind = AND;reqk = NOT;
+ }else if( k==IFF ) {
+ rt.d_req_kind = XOR;
+ }else if( k==XOR ) {
+ rt.d_req_kind = IFF;
+ }else if( k==ITE ){
+ rt.d_req_kind = ITE;reqkc[1] = NOT;reqkc[2] = NOT;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ }else if( k==LEQ || k==GT ){
+ // (not (~ x y)) -----> (~ (+ y 1) x)
+ rt.d_req_kind = k;
+ rt.d_children[0].d_req_kind = PLUS;
+ rt.d_children[0].d_children[0].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt.d_children[0].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+ rt.d_children[1].d_req_type = d_tds->getArgType( dt[c], 0 );
+ //TODO: other possibilities?
+ }else if( k==LT || k==GEQ ){
+ // (not (~ x y)) -----> (~ y (+ x 1))
+ rt.d_req_kind = k;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt.d_children[1].d_req_kind = PLUS;
+ rt.d_children[1].d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==BITVECTOR_NOT ){
+ if( k==BITVECTOR_AND ) {
+ rt.d_req_kind = BITVECTOR_OR;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_OR ){
+ rt.d_req_kind = BITVECTOR_AND;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_XNOR ) {
+ rt.d_req_kind = BITVECTOR_XOR;
+ }else if( k==BITVECTOR_XOR ) {
+ rt.d_req_kind = BITVECTOR_XNOR;
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==UMINUS ){
+ if( k==PLUS ){
+ rt.d_req_kind = PLUS;reqk = UMINUS;
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==BITVECTOR_NEG ){
+ if( k==PLUS ){
+ rt.d_req_kind = PLUS;reqk = BITVECTOR_NEG;
+ }else{
+ rt_valid = false;
+ }
}
- Trace("sygus-split-debug") << "?" << std::endl;
- int pcr = d_tds->getKindArg( tnp, nk );
- if( pcr!=-1 ){
- Assert( pcr<(int)pdt.getNumConstructors() );
- if( reqk!=UNDEFINED_KIND ){
+ if( rt_valid && ( reqk!=UNDEFINED_KIND || !reqkc.empty() ) ){
+ int pcr = d_tds->getKindArg( tnp, rt.d_req_kind );
+ if( pcr!=-1 ){
+ Assert( pcr<(int)pdt.getNumConstructors() );
//must have same number of arguments
if( pdt[pcr].getNumArgs()==dt[c].getNumArgs() ){
- bool success = true;
- std::map< int, TypeNode > childTypes;
for( unsigned i=0; i<pdt[pcr].getNumArgs(); i++ ){
- TypeNode tna = d_tds->getArgType( pdt[pcr], i );
- Assert( datatypes::DatatypesRewriter::isTypeDatatype( tna ) );
- if( reqk!=UNDEFINED_KIND ){
- //child must have a NOT
- int nindex = d_tds->getKindArg( tna, reqk );
- if( nindex!=-1 ){
- const Datatype& adt = ((DatatypeType)(tn).toType()).getDatatype();
- if( d_tds->getArgType( dt[c], i )!=d_tds->getArgType( adt[nindex], 0 ) ){
- Trace("sygus-split-debug") << "...arg " << i << " type mismatch." << std::endl;
- success = false;
- break;
- }
- }else{
- Trace("sygus-split-debug") << "...argument " << i << " does not have " << reqk << "." << std::endl;
- success = false;
- break;
+ Kind rk = reqk;
+ if( reqk==UNDEFINED_KIND ){
+ std::map< unsigned, Kind >::iterator itr = reqkc.find( i );
+ if( itr!=reqkc.end() ){
+ rk = itr->second;
}
- }else{
- childTypes[i] = tna;
}
- }
- if( success ){
- Trace("sygus-split-debug") << "...success" << std::endl;
- return false;
+ if( rk!=UNDEFINED_KIND ){
+ rt.d_children[i].d_req_kind = rk;
+ rt.d_children[i].d_children[0].d_req_type = d_tds->getArgType( dt[c], i );
+ }
}
}else{
- Trace("sygus-split-debug") << "...#arg mismatch." << std::endl;
+ rt_valid = false;
}
}else{
- return !isTypeMatch( pdt[pcr], dt[c] );
+ rt_valid = false;
}
- }else{
- Trace("sygus-split-debug") << "...operator not available." << std::endl;
}
}
+ }else if( k==MINUS || k==BITVECTOR_SUB ){
+ if( parent==EQUAL ||
+ parent==MINUS || parent==BITVECTOR_SUB ||
+ parent==LEQ || parent==LT || parent==GEQ || parent==GT ){
+ int oarg = arg==0 ? 1 : 0;
+ // (~ x (- y z)) ----> (~ (+ x z) y)
+ // (~ (- y z) x) ----> (~ y (+ x z))
+ rt.d_req_kind = parent;
+ rt.d_children[arg].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[oarg].d_req_kind = k==MINUS ? PLUS : BITVECTOR_PLUS;
+ rt.d_children[oarg].d_children[0].d_req_type = d_tds->getArgType( pdt[pc], oarg );
+ rt.d_children[oarg].d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt_valid = true;
+ }else if( parent==PLUS || parent==BITVECTOR_PLUS ){
+ // (+ x (- y z)) -----> (- (+ x y) z)
+ // (+ (- y z) x) -----> (- (+ x y) z)
+ rt.d_req_kind = parent==PLUS ? MINUS : BITVECTOR_SUB;
+ int oarg = arg==0 ? 1 : 0;
+ rt.d_children[0].d_req_kind = parent;
+ rt.d_children[0].d_children[0].d_req_type = d_tds->getArgType( pdt[pc], oarg );
+ rt.d_children[0].d_children[1].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt_valid = true;
+ }
+ }else if( k==ITE ){
+ if( parent!=ITE ){
+ // (o X (ite y z w) X') -----> (ite y (o X z X') (o X w X'))
+ rt.d_req_kind = ITE;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ unsigned n_args = pdt[pc].getNumArgs();
+ for( unsigned r=1; r<=2; r++ ){
+ rt.d_children[r].d_req_kind = parent;
+ for( unsigned q=0; q<n_args; q++ ){
+ if( (int)q==arg ){
+ rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( dt[c], r );
+ }else{
+ rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( pdt[pc], q );
+ }
+ }
+ }
+ rt_valid = true;
+ //TODO: this increases term size but is probably a good idea
+ }
+ }else if( k==NOT ){
+ if( parent==ITE ){
+ // (ite (not y) z w) -----> (ite y w z)
+ rt.d_req_kind = ITE;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_req_type = d_tds->getArgType( pdt[pc], 2 );
+ rt.d_children[2].d_req_type = d_tds->getArgType( pdt[pc], 1 );
+ }
}
- if( parent==MINUS || parent==BITVECTOR_SUB ){
-
-
+ Trace("sygus-consider-split") << "Consider sygus split kind " << k << ", parent = " << parent << ", arg = " << arg << "?" << std::endl;
+ if( rt_valid ){
+ rt.print("sygus-consider-split");
+ //check if it meets the requirements
+ if( rt.satisfiedBy( d_tds, tnp ) ){
+ Trace("sygus-consider-split") << "...success!" << std::endl;
+ //do not need to consider the kind in the search since there are ways to construct equivalent terms
+ return false;
+ }else{
+ Trace("sygus-consider-split") << "...failed." << std::endl;
+ }
+ Trace("sygus-consider-split") << std::endl;
}
+ //must consider this kind in the search
return true;
}
@@ -616,6 +737,7 @@ bool SygusSplit::isGenericRedundant( TypeNode tn, Node g, bool active ) {
d_gen_terms[tn][gr] = g;
d_gen_terms_inactive[tn][gr] = g;
Trace("sygus-gnf-debug") << "...not redundant." << std::endl;
+ Trace("sygus-nf-reg") << "*** Sygus (generic) normal form : normal form of " << g << " is " << gr << std::endl;
}else{
Trace("sygus-gnf-debug") << "...redundant." << std::endl;
Trace("sygus-nf") << "* Sygus normal form : simplify since " << g << " and " << itg->second << " both rewrite to " << gr << std::endl;
@@ -849,6 +971,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
}else{
d_redundant[at][prog] = false;
red = false;
+ Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << std::endl;
}
}else{
rep_prog = itnp->second;
@@ -858,6 +981,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
d_redundant[at].erase( rep_prog );
d_redundant[at][prog] = false;
red = false;
+ Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << " (redundant but smaller than " << rep_prog << ") " << std::endl;
}else{
Assert( prog!=itnp->second );
d_redundant[at][prog] = true;
@@ -1090,6 +1214,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
}
}else{
red = it->second;
+ Trace("sygus-nf-debug") << "Already processed, redundant : " << red << std::endl;
}
if( red ){
if( std::find( d_lemmas_reported[at][prog].begin(), d_lemmas_reported[at][prog].end(), a )==d_lemmas_reported[at][prog].end() ){
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index d035f0fa7..3338e5f31 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -105,7 +105,7 @@ typerule RECORD_UPDATE ::CVC4::theory::datatypes::RecordUpdateTypeRule
operator DT_SIZE 1 "datatypes size"
typerule DT_SIZE ::CVC4::theory::datatypes::DtSizeTypeRule
-operator DT_HEIGHT_BOUND 1 "datatypes height bound"
+operator DT_HEIGHT_BOUND 2 "datatypes height bound"
typerule DT_HEIGHT_BOUND ::CVC4::theory::datatypes::DtHeightBoundTypeRule
endtheory
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index eb8b23973..a2f995935 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -27,9 +27,11 @@
#include "theory/datatypes/datatypes_rewriter.h"
#include "theory/datatypes/theory_datatypes_type_rules.h"
#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/valuation.h"
+#include "options/theory_options.h"
using namespace std;
using namespace CVC4::kind;
@@ -54,8 +56,7 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
//d_consEqc( c ),
d_conflict( c, false ),
d_collectTermsCache( c ),
- d_consTerms( c ),
- d_selTerms( c ),
+ d_functionTerms( c ),
d_singleton_eq( u ),
d_lemmas_produced_c( u )
{
@@ -81,6 +82,8 @@ TheoryDatatypes::~TheoryDatatypes() {
Assert(current != NULL);
delete current;
}
+ delete d_sygus_split;
+ delete d_sygus_sym_break;
}
void TheoryDatatypes::setMasterEqualityEngine(eq::EqualityEngine* eq) {
@@ -91,9 +94,7 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( TNode n, bool doMak
if( !hasEqcInfo( n ) ){
if( doMake ){
//add to labels
- NodeList* lbl = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_labels.insertDataFromContextMemory( n, lbl );
+ d_labels[ n ] = 0;
std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
EqcInfo* ei;
@@ -106,10 +107,10 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( TNode n, bool doMak
if( n.getKind()==APPLY_CONSTRUCTOR ){
ei->d_constructor = n;
}
+
//add to selectors
- NodeList* sel = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_selector_apps.insertDataFromContextMemory( n, sel );
+ d_selector_apps[n] = 0;
+
return ei;
}else{
return NULL;
@@ -178,6 +179,7 @@ void TheoryDatatypes::check(Effort e) {
Trace("datatypes-debug") << "Check for splits " << e << endl;
do {
d_addedFact = false;
+ bool added_split = false;
std::map< TypeNode, Node > rec_singletons;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
@@ -190,7 +192,7 @@ void TheoryDatatypes::check(Effort e) {
if( !hasLabel( eqc, n ) ){
Trace("datatypes-debug") << "No constructor..." << std::endl;
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- Trace("datatypes-debug") << "Datatype " << dt << " is " << dt.isFinite() << " " << dt.isUFinite() << " " << dt.isRecursiveSingleton() << std::endl;
+ Trace("datatypes-debug") << "Datatype " << dt << " is " << dt.isFinite() << " " << dt.isInterpretedFinite() << " " << dt.isRecursiveSingleton() << std::endl;
bool continueProc = true;
if( dt.isRecursiveSingleton() ){
Trace("datatypes-debug") << "Check recursive singleton..." << std::endl;
@@ -251,7 +253,7 @@ void TheoryDatatypes::check(Effort e) {
if( consIndex==-1 ){
consIndex = j;
}
- if( options::finiteModelFind() ? !dt[ j ].isUFinite() : !dt[ j ].isFinite() ) {
+ if( !dt[ j ].isInterpretedFinite() ) {
if( !eqc || !eqc->d_selectors ){
needSplit = false;
}
@@ -311,7 +313,10 @@ void TheoryDatatypes::check(Effort e) {
//doSendLemma( lemma );
d_out->lemma( lemma, false, false, true );
}
- return;
+ added_split = true;
+ if( !options::dtBlastSplits() ){
+ return;
+ }
}
}else{
Trace("dt-split-debug") << "Do not split constructor for " << n << " : " << n.getType() << " " << dt.getNumConstructors() << std::endl;
@@ -323,6 +328,9 @@ void TheoryDatatypes::check(Effort e) {
}
++eqcs_i;
}
+ if( added_split ){
+ return;
+ }
Trace("datatypes-debug") << "Flush pending facts..." << std::endl;
flushPendingFacts();
/*
@@ -870,33 +878,36 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
//merge labels
- NodeListMap::iterator lbl_i = d_labels.find( t2 );
+ NodeIntMap::iterator lbl_i = d_labels.find( t2 );
if( lbl_i != d_labels.end() ){
Trace("datatypes-debug") << " merge labels from " << eqc2 << " " << t2 << std::endl;
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); ++j ){
- Node tt = (*j).getKind()==kind::NOT ? (*j)[0] : (*j);
+ int n_label = (*lbl_i).second;
+ for( int i=0; i<n_label; i++ ){
+ Assert( i<(int)d_labels_data[ t2 ].size() );
+ Node t = d_labels_data[ t2 ][i];
+ Node tt = t.getKind()==kind::NOT ? t[0] : t;
Node t_arg;
int tindex = DatatypesRewriter::isTester( tt, t_arg );
Assert( tindex!=-1 );
- addTester( tindex, *j, eqc1, t1, t_arg );
+ addTester( tindex, t, eqc1, t1, t_arg );
if( d_conflict ){
Trace("datatypes-debug") << " conflict!" << std::endl;
return;
}
}
+
}
//merge selectors
if( !eqc1->d_selectors && eqc2->d_selectors ){
eqc1->d_selectors = true;
checkInst = true;
}
- NodeListMap::iterator sel_i = d_selector_apps.find( t2 );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( t2 );
if( sel_i != d_selector_apps.end() ){
Trace("datatypes-debug") << " merge selectors from " << eqc2 << " " << t2 << std::endl;
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
- addSelector( *j, eqc1, t1, eqc2->d_constructor.get().isNull() );
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ addSelector( d_selector_apps_data[t2][j], eqc1, t1, eqc2->d_constructor.get().isNull() );
}
}
if( checkInst ){
@@ -927,11 +938,11 @@ bool TheoryDatatypes::hasLabel( EqcInfo* eqc, Node n ){
}
Node TheoryDatatypes::getLabel( Node n ) {
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- if( !(*lbl).empty() && (*lbl)[ (*lbl).size() - 1 ].getKind()!=kind::NOT ){
- return (*lbl)[ (*lbl).size() - 1 ];
+ unsigned n_lbl = (*lbl_i).second;
+ if( n_lbl>0 && d_labels_data[n][ n_lbl-1 ].getKind()!=kind::NOT ){
+ return d_labels_data[n][ n_lbl-1 ];
}
}
return Node::null();
@@ -954,9 +965,9 @@ int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){
}
bool TheoryDatatypes::hasTester( Node n ) {
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- return !(*(*lbl_i).second).empty();
+ return (*lbl_i).second>0;
}else{
return false;
}
@@ -969,13 +980,14 @@ void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >
if( lindex!=-1 ){
pcons[ lindex ] = true;
}else{
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- Assert( (*i).getKind()==NOT );
- //pcons[ Datatype::indexOf( (*i)[0].getOperator().toExpr() ) ] = false;
- int tindex = DatatypesRewriter::isTester( (*i)[0] );
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node t = d_labels_data[n][i];
+ Assert( t.getKind()==NOT );
+ //pcons[ Datatype::indexOf( t[0].getOperator().toExpr() ) ] = false;
+ int tindex = DatatypesRewriter::isTester( t[0] );
Assert( tindex!=-1 );
pcons[ tindex ] = false;
}
@@ -984,11 +996,11 @@ void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >
}
void TheoryDatatypes::getSelectorsForCons( Node r, std::map< int, bool >& sels ) {
- NodeListMap::iterator sel_i = d_selector_apps.find( r );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( r );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); j++ ){
- int sindex = Datatype::indexOf( (*j).getOperator().toExpr() );
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ int sindex = Datatype::indexOf( d_selector_apps_data[r][j].getOperator().toExpr() );
sels[sindex] = true;
}
}
@@ -1055,12 +1067,13 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
}
}else{
//otherwise, scan list of labels
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
Assert( lbl_i != d_labels.end() );
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- Assert( (*i).getKind()==NOT );
- j = *i;
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node ti = d_labels_data[n][i];
+ Assert( ti.getKind()==NOT );
+ j = ti;
jt = j[0];
//int jtindex = Datatype::indexOf( jt.getOperator().toExpr() );
int jtindex = DatatypesRewriter::isTester( jt );
@@ -1076,16 +1089,24 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
}
if( !makeConflict ){
Debug("datatypes-labels") << "Add to labels " << t << std::endl;
- lbl->push_back( t );
+ //lbl->push_back( t );
+ d_labels[n] = n_lbl + 1;
+ if( n_lbl<(int)d_labels_data[n].size() ){
+ d_labels_data[n][n_lbl] = t;
+ }else{
+ d_labels_data[n].push_back( t );
+ }
+ n_lbl++;
+
const Datatype& dt = ((DatatypeType)(t_arg.getType()).toType()).getDatatype();
- Debug("datatypes-labels") << "Labels at " << lbl->size() << " / " << dt.getNumConstructors() << std::endl;
+ Debug("datatypes-labels") << "Labels at " << n_lbl << " / " << dt.getNumConstructors() << std::endl;
if( tpolarity ){
instantiate( eqc, n );
}else{
//check if we have reached the maximum number of testers
// in this case, add the positive tester
//this should not be done for sygus, since cases may be limited
- if( lbl->size()==dt.getNumConstructors()-1 && !dt.isSygus() ){
+ if( n_lbl==(int)dt.getNumConstructors()-1 && !dt.isSygus() ){
std::vector< bool > pcons;
getPossibleCons( eqc, n, pcons );
int testerIndex = -1;
@@ -1099,11 +1120,14 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
//we must explain why each term in the set of testers for this equivalence class is equal
std::vector< Node > eq_terms;
NodeBuilder<> nb(kind::AND);
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- nb << (*i);
- Assert( (*i).getKind()==NOT );
+ //for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
+
+ for( int i=0; i<n_lbl; i++ ){
+ Node ti = d_labels_data[n][i];
+ nb << ti;
+ Assert( ti.getKind()==NOT );
Node t_arg2;
- DatatypesRewriter::isTester( (*i)[0], t_arg2 );
+ DatatypesRewriter::isTester( ti[0], t_arg2 );
//Assert( tindex!=-1 );
if( std::find( eq_terms.begin(), eq_terms.end(), t_arg2 )==eq_terms.end() ){
eq_terms.push_back( t_arg2 );
@@ -1140,19 +1164,26 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
void TheoryDatatypes::addSelector( Node s, EqcInfo* eqc, Node n, bool assertFacts ) {
Trace("dt-collapse-sel") << "Add selector : " << s << " to eqc(" << n << ")" << std::endl;
//check to see if it is redundant
- NodeListMap::iterator sel_i = d_selector_apps.find( n );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( n );
Assert( sel_i != d_selector_apps.end() );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
- Node ss = *j;
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ Node ss = d_selector_apps_data[n][j];
if( s.getOperator()==ss.getOperator() && ( s.getKind()!=DT_HEIGHT_BOUND || s[1]==ss[1] ) ){
Trace("dt-collapse-sel") << "...redundant." << std::endl;
return;
}
}
//add it to the vector
- sel->push_back( s );
+ //sel->push_back( s );
+ d_selector_apps[n] = n_sel + 1;
+ if( n_sel<(int)d_selector_apps_data[n].size() ){
+ d_selector_apps_data[n][n_sel] = s;
+ }else{
+ d_selector_apps_data[n].push_back( s );
+ }
+
eqc->d_selectors = true;
}
if( assertFacts && !eqc->d_constructor.get().isNull() ){
@@ -1165,19 +1196,19 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
Trace("datatypes-debug") << "Add constructor : " << c << " to eqc(" << n << ")" << std::endl;
Assert( eqc->d_constructor.get().isNull() );
//check labels
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
size_t constructorIndex = Datatype::indexOf(c.getOperator().toExpr());
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- if( (*i).getKind()==NOT ){
- int tindex = DatatypesRewriter::isTester( (*i)[0] );
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node t = d_labels_data[n][i];
+ if( t.getKind()==NOT ){
+ int tindex = DatatypesRewriter::isTester( t[0] );
Assert( tindex!=-1 );
if( tindex==(int)constructorIndex ){
- Node n = *i;
std::vector< TNode > assumptions;
- explain( *i, assumptions );
- explainEquality( c, (*i)[0][0], true, assumptions );
+ explain( t, assumptions );
+ explainEquality( c, t[0][0], true, assumptions );
d_conflictNode = mkAnd( assumptions );
Trace("dt-conflict") << "CONFLICT: Tester merge eq conflict : " << d_conflictNode << std::endl;
d_out->conflict( d_conflictNode );
@@ -1188,12 +1219,13 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
}
}
//check selectors
- NodeListMap::iterator sel_i = d_selector_apps.find( n );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( n );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ Node s = d_selector_apps_data[n][j];
//collapse the selector
- collapseSelector( *j, c );
+ collapseSelector( s, c );
}
}
eqc->d_constructor.set( c );
@@ -1277,61 +1309,114 @@ EqualityStatus TheoryDatatypes::getEqualityStatus(TNode a, TNode b){
return EQUALITY_FALSE_IN_MODEL;
}
-void TheoryDatatypes::computeCareGraph(){
- Trace("dt-cg") << "Compute graph for dt..." << std::endl;
- vector< pair<TNode, TNode> > currentPairs;
- for( unsigned r=0; r<2; r++ ){
- unsigned functionTerms = r==0 ? d_consTerms.size() : d_selTerms.size();
- for( unsigned i=0; i<functionTerms; i++ ){
- TNode f1 = r==0 ? d_consTerms[i] : d_selTerms[i];
- Assert(d_equalityEngine.hasTerm(f1));
- for( unsigned j=i+1; j<functionTerms; j++ ){
- TNode f2 = r==0 ? d_consTerms[j] : d_selTerms[j];
- Trace("dt-cg-debug") << "dt-cg(" << r << "): " << f1 << " and " << f2 << " " << (f1.getOperator()==f2.getOperator()) << " " << areEqual( f1, f2 ) << std::endl;
- Assert(d_equalityEngine.hasTerm(f2));
- if( f1.getOperator()==f2.getOperator() &&
- ( ( f1.getKind()!=DT_SIZE && f1.getKind()!=DT_HEIGHT_BOUND ) || f1[0].getType()==f2[0].getType() ) &&
- !areEqual( f1, f2 ) ){
- Trace("dt-cg") << "Check " << f1 << " and " << f2 << std::endl;
- bool somePairIsDisequal = false;
- currentPairs.clear();
- for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
- TNode x = f1[k];
- TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- //need to consider types for parametric selectors
- if( x.getType()!=y.getType() || areDisequal(x, y) ){
- somePairIsDisequal = true;
- break;
- }else if( !d_equalityEngine.areEqual( x, y ) ){
- Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
- if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
- Trace("dt-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
- EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
- Trace("dt-cg") << "...eq status is " << eqStatus << std::endl;
- if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
- somePairIsDisequal = true;
- break;
- }else{
- currentPairs.push_back(make_pair(x_shared, y_shared));
- }
+
+
+void TheoryDatatypes::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs ){
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !areEqual( f1, f2 ) ){
+ Trace("dt-cg") << "Check " << f1 << " and " << f2 << std::endl;
+ vector< pair<TNode, TNode> > currentPairs;
+ for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+ TNode x = f1[k];
+ TNode y = f2[k];
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !areDisequal( x, y ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
+ Trace("dt-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ Trace("dt-cg") << "...eq status is " << eqStatus << std::endl;
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
}
}
}
- if (!somePairIsDisequal) {
- for (unsigned c = 0; c < currentPairs.size(); ++ c) {
- Trace("dt-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
- addCarePair(currentPairs[c].first, currentPairs[c].second);
- }
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Trace("dt-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
+ addCarePair(currentPairs[c].first, currentPairs[c].second);
+ n_pairs++;
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1, n_pairs );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
+ }
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
}
}
}
}
}
- Trace("dt-cg") << "Done Compute graph for dt." << std::endl;
+}
+
+void TheoryDatatypes::computeCareGraph(){
+ unsigned n_pairs = 0;
+ Trace("dt-cg-summary") << "Compute graph for dt..." << d_functionTerms.size() << " " << d_sharedTerms.size() << std::endl;
+ Trace("dt-cg") << "Build indices..." << std::endl;
+ std::map< TypeNode, std::map< Node, quantifiers::TermArgTrie > > index;
+ std::map< Node, unsigned > arity;
+ //populate indices
+ unsigned functionTerms = d_functionTerms.size();
+ for( unsigned i=0; i<functionTerms; i++ ){
+ TNode f1 = d_functionTerms[i];
+ Assert(d_equalityEngine.hasTerm(f1));
+ Trace("dt-cg-debug") << "...build for " << f1 << std::endl;
+ //break into index based on operator, and type of first argument (since some operators are parametric)
+ Node op = f1.getOperator();
+ TypeNode tn = f1[0].getType();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_DATATYPES ) ){
+ has_trigger_arg = true;
+ }
+ }
+ //only may contribute to care pairs if has at least one trigger argument
+ if( has_trigger_arg ){
+ index[tn][op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< TypeNode, std::map< Node, quantifiers::TermArgTrie > >::iterator iti = index.begin(); iti != index.end(); ++iti ){
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = iti->second.begin(); itii != iti->second.end(); ++itii ){
+ Trace("dt-cg") << "Process index " << itii->first << ", " << iti->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0, n_pairs );
+ }
+ }
+ Trace("dt-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
}
void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
@@ -1443,7 +1528,7 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
if( neqc.isNull() ){
for( unsigned i=0; i<pcons.size(); i++ ){
//must try the infinite ones first
- bool cfinite = options::finiteModelFind() ? dt[ i ].isUFinite() : dt[ i ].isFinite();
+ bool cfinite = dt[ i ].isInterpretedFinite();
if( pcons[i] && (r==1)==cfinite ){
neqc = DatatypesRewriter::getInstCons( eqc, dt, i );
//for( unsigned j=0; j<neqc.getNumChildren(); j++ ){
@@ -1543,16 +1628,18 @@ Node TheoryDatatypes::getSingletonLemma( TypeNode tn, bool pol ) {
void TheoryDatatypes::collectTerms( Node n ) {
if( d_collectTermsCache.find( n )==d_collectTermsCache.end() ){
d_collectTermsCache[n] = true;
- for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- collectTerms( n[i] );
- }
+ //for( int i=0; i<(int)n.getNumChildren(); i++ ) {
+ // collectTerms( n[i] );
+ //}
if( n.getKind() == APPLY_CONSTRUCTOR ){
Debug("datatypes") << " Found constructor " << n << endl;
- d_consTerms.push_back( n );
+ if( n.getNumChildren()>0 ){
+ d_functionTerms.push_back( n );
+ }
}else{
if( n.getKind() == APPLY_SELECTOR_TOTAL || n.getKind() == DT_SIZE || n.getKind() == DT_HEIGHT_BOUND ){
- d_selTerms.push_back( n );
+ d_functionTerms.push_back( n );
//we must also record which selectors exist
Trace("dt-collapse-sel") << " Found selector " << n << endl;
Node rep = getRepresentative( n[0] );
@@ -2040,21 +2127,19 @@ void TheoryDatatypes::printModelDebug( const char* c ){
if( hasLabel( ei, eqc ) ){
Trace( c ) << getLabel( eqc );
}else{
- NodeListMap::iterator lbl_i = d_labels.find( eqc );
+ NodeIntMap::iterator lbl_i = d_labels.find( eqc );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ){
- Trace( c ) << *j << " ";
+ for( int j=0; j<(*lbl_i).second; j++ ){
+ Trace( c ) << d_labels_data[eqc][j] << " ";
}
}
}
Trace( c ) << std::endl;
Trace( c ) << " Selectors : " << ( ei->d_selectors ? "yes, " : "no " );
- NodeListMap::iterator sel_i = d_selector_apps.find( eqc );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( eqc );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); j++ ){
- Trace( c ) << *j << " ";
+ for( int j=0; j<(*sel_i).second; j++ ){
+ Trace( c ) << d_selector_apps_data[eqc][j] << " ";
}
}
Trace( c ) << std::endl;
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 4bf04e08c..5722e7822 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -32,12 +32,17 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace datatypes {
class TheoryDatatypes : public Theory {
private:
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+ typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
@@ -157,9 +162,11 @@ private:
* NOT is_[constructor_1]( t )...NOT is_[constructor_n]( t ) followed by
* is_[constructor_(n+1)]( t ), each of which is a unique tester.
*/
- NodeListMap d_labels;
+ NodeIntMap d_labels;
+ std::map< Node, std::vector< Node > > d_labels_data;
/** selector apps for eqch equivalence class */
- NodeListMap d_selector_apps;
+ NodeIntMap d_selector_apps;
+ std::map< Node, std::vector< Node > > d_selector_apps_data;
/** constructor terms */
//BoolMap d_consEqc;
/** Are we in conflict */
@@ -176,10 +183,8 @@ private:
std::vector< Node > d_pending;
std::map< Node, Node > d_pending_exp;
std::vector< Node > d_pending_merge;
- /** All the constructor terms that the theory has seen */
- context::CDList<TNode> d_consTerms;
- /** All the selector terms that the theory has seen */
- context::CDList<TNode> d_selTerms;
+ /** All the function terms that the theory has seen */
+ context::CDList<TNode> d_functionTerms;
/** counter for forcing assignments (ensures fairness) */
unsigned d_dtfCounter;
/** expand definition skolem functions */
@@ -216,6 +221,7 @@ private:
TNode getEqcConstructor( TNode r );
protected:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs );
/** compute care graph */
void computeCareGraph();
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index 5a3645691..9c8387958 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -299,11 +299,10 @@ public:
throw TypeCheckingExceptionPrivate(n, "datatype height bound must be non-negative");
}
}
- return nodeManager->integerType();
+ return nodeManager->booleanType();
}
};/* class DtHeightBoundTypeRule */
-
}/* CVC4::theory::datatypes namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/datatypes/type_enumerator.cpp b/src/theory/datatypes/type_enumerator.cpp
index 6c1155237..c0539743f 100644
--- a/src/theory/datatypes/type_enumerator.cpp
+++ b/src/theory/datatypes/type_enumerator.cpp
@@ -172,7 +172,7 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
Debug("dt-enum") << "datatype is " << d_type << std::endl;
Debug("dt-enum") << "properties : " << d_datatype.isCodatatype() << " " << d_datatype.isRecursiveSingleton();
Debug("dt-enum") << " " << d_datatype.isFinite() << std::endl;
- Debug("dt-enum") << " " << d_datatype.isUFinite() << std::endl;
+ Debug("dt-enum") << " " << d_datatype.isInterpretedFinite() << std::endl;
if( d_datatype.isCodatatype() && hasCyclesDt( d_datatype ) ){
//start with uninterpreted constant
diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h
index bbfd951b3..8473b5d69 100644
--- a/src/theory/datatypes/type_enumerator.h
+++ b/src/theory/datatypes/type_enumerator.h
@@ -159,7 +159,7 @@ public:
}
if( d_ctor>=d_has_debruijn+d_datatype.getNumConstructors() ){
//try next size limit as long as new terms were generated at last size, or other cases
- if( prevSize==d_size_limit || ( d_size_limit==0 && d_datatype.isCodatatype() ) || ( options::finiteModelFind() ? !d_datatype.isUFinite() : !d_datatype.isFinite() ) ){
+ if( prevSize==d_size_limit || ( d_size_limit==0 && d_datatype.isCodatatype() ) || !d_datatype.isInterpretedFinite() ){
d_size_limit++;
d_ctor = d_zeroCtor;
for( unsigned i=0; i<d_sel_sum.size(); i++ ){
diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp
index 04cac7ae5..6ac1c5e32 100644
--- a/src/theory/logic_info.cpp
+++ b/src/theory/logic_info.cpp
@@ -270,7 +270,7 @@ std::string LogicInfo::getLogicString() const {
if(d_theories[THEORY_FP]) {
ss << "FP";
++seen;
- }
+ }
if(d_theories[THEORY_DATATYPES]) {
ss << "DT";
++seen;
@@ -296,7 +296,10 @@ std::string LogicInfo::getLogicString() const {
ss << "FS";
++seen;
}
-
+ if(d_theories[THEORY_SEP]) {
+ ss << "SEP";
+ ++seen;
+ }
if(seen != d_sharingTheories) {
Unhandled("can't extract a logic string from LogicInfo; at least one "
"active theory is unknown to LogicInfo::getLogicString() !");
@@ -439,6 +442,10 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_SETS);
p += 2;
}
+ if(!strncmp(p, "SEP", 3)) {
+ enableTheory(THEORY_SEP);
+ p += 3;
+ }
}
}
if(*p != '\0') {
diff --git a/src/theory/quantifiers/alpha_equivalence.cpp b/src/theory/quantifiers/alpha_equivalence.cpp
index 80066d690..a00d6d8a1 100644..100755
--- a/src/theory/quantifiers/alpha_equivalence.cpp
+++ b/src/theory/quantifiers/alpha_equivalence.cpp
@@ -30,17 +30,30 @@ struct sortTypeOrder {
};
Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ) {
+ std::map< Node, bool > visited;
while( !tt.empty() ){
if( tt.size()==arg_index.size()+1 ){
Node t = tt.back();
- Node op = t.hasOperator() ? t.getOperator() : t;
- arg_index.push_back( 0 );
+ Node op;
+ if( t.hasOperator() ){
+ if( visited.find( t )==visited.end() ){
+ visited[t] = true;
+ op = t.getOperator();
+ arg_index.push_back( 0 );
+ }else{
+ op = t;
+ arg_index.push_back( -1 );
+ }
+ }else{
+ op = t;
+ arg_index.push_back( 0 );
+ }
Trace("aeq-debug") << op << " ";
aen = &(aen->d_children[op][t.getNumChildren()]);
}else{
Node t = tt.back();
int i = arg_index.back();
- if( i==(int)t.getNumChildren() ){
+ if( i==-1 || i==(int)t.getNumChildren() ){
tt.pop_back();
arg_index.pop_back();
}else{
@@ -56,9 +69,9 @@ Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersE
}else{
if( q.getNumChildren()==2 ){
//lemma ( q <=> d_quant )
- Trace("quant-ae") << "Alpha equivalent : " << std::endl;
- Trace("quant-ae") << " " << q << std::endl;
- Trace("quant-ae") << " " << aen->d_quant << std::endl;
+ Trace("alpha-eq") << "Alpha equivalent : " << std::endl;
+ Trace("alpha-eq") << " " << q << std::endl;
+ Trace("alpha-eq") << " " << aen->d_quant << std::endl;
lem = q.iffNode( aen->d_quant );
}else{
//do not reduce annotated quantified formulas based on alpha equivalence
diff --git a/src/theory/quantifiers/alpha_equivalence.h b/src/theory/quantifiers/alpha_equivalence.h
index 8e7556eb6..8e7556eb6 100644..100755
--- a/src/theory/quantifiers/alpha_equivalence.h
+++ b/src/theory/quantifiers/alpha_equivalence.h
diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp
index 5192da7de..97116dee4 100644..100755
--- a/src/theory/quantifiers/ambqi_builder.cpp
+++ b/src/theory/quantifiers/ambqi_builder.cpp
@@ -787,7 +787,7 @@ void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
Node n = fm->d_uf_terms[f][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
fapps.push_back( n );
}
diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h
index 3669d38b7..3669d38b7 100644..100755
--- a/src/theory/quantifiers/ambqi_builder.h
+++ b/src/theory/quantifiers/ambqi_builder.h
diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp
index c8d18aced..c8d18aced 100644..100755
--- a/src/theory/quantifiers/anti_skolem.cpp
+++ b/src/theory/quantifiers/anti_skolem.cpp
diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h
index 721371159..721371159 100644..100755
--- a/src/theory/quantifiers/anti_skolem.h
+++ b/src/theory/quantifiers/anti_skolem.h
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index d32ef59a1..7184624da 100644..100755
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -28,7 +28,7 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
-BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
+BoundedIntegers::IntRangeModel::IntRangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) {
if( options::fmfBoundIntLazy() ){
d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
@@ -40,7 +40,7 @@ BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::C
}
}
-void BoundedIntegers::RangeModel::initialize() {
+void BoundedIntegers::IntRangeModel::initialize() {
//add initial split lemma
Node ltr = NodeManager::currentNM()->mkNode( LT, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
ltr = Rewriter::rewrite( ltr );
@@ -55,7 +55,7 @@ void BoundedIntegers::RangeModel::initialize() {
d_bi->addLiteralFromRange(ltr_lit, d_range);
}
-void BoundedIntegers::RangeModel::assertNode(Node n) {
+void BoundedIntegers::IntRangeModel::assertNode(Node n) {
bool pol = n.getKind()!=NOT;
Node nlit = n.getKind()==NOT ? n[0] : n;
if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){
@@ -93,7 +93,7 @@ void BoundedIntegers::RangeModel::assertNode(Node n) {
}
}
-void BoundedIntegers::RangeModel::allocateRange() {
+void BoundedIntegers::IntRangeModel::allocateRange() {
d_curr_max++;
int newBound = d_curr_max;
Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
@@ -110,7 +110,7 @@ void BoundedIntegers::RangeModel::allocateRange() {
d_bi->addLiteralFromRange(ltr_lit, d_range);
}
-Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
+Node BoundedIntegers::IntRangeModel::getNextDecisionRequest() {
//request the current cardinality as a decision literal, if not already asserted
for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
int i = (*it).second;
@@ -129,7 +129,7 @@ Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
return Node::null();
}
-bool BoundedIntegers::RangeModel::proxyCurrentRange() {
+bool BoundedIntegers::IntRangeModel::proxyCurrentRange() {
//Trace("model-engine") << "Range(" << d_range << ") currently is " << d_curr_max.get() << std::endl;
if( d_range!=d_proxy_range ){
//int curr = d_curr_range.get();
@@ -148,11 +148,24 @@ bool BoundedIntegers::RangeModel::proxyCurrentRange() {
}
+
+
+
BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
QuantifiersModule(qe), d_assertions(c){
}
+BoundedIntegers::~BoundedIntegers() {
+ for( std::map< Node, RangeModel * >::iterator it = d_rms.begin(); it != d_rms.end(); ++it ){
+ delete it->second;
+ }
+}
+
+void BoundedIntegers::presolve() {
+ d_bnd_it.clear();
+}
+
bool BoundedIntegers::isBound( Node f, Node v ) {
return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
}
@@ -172,62 +185,79 @@ bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
return false;
}
-void BoundedIntegers::processLiteral( Node f, Node lit, bool pol,
+void BoundedIntegers::processLiteral( Node q, Node lit, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map ) {
- if( lit.getKind()==GEQ && lit[0].getType().isInteger() ){
- std::map< Node, Node > msum;
- if (QuantArith::getMonomialSumLit( lit, msum )){
- Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl;
- QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" );
- for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
- if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( f, it->first ) ){
- Node veq;
- if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){
- Node n1 = veq[0];
- Node n2 = veq[1];
- if(pol){
- //flip
- n1 = veq[1];
- n2 = veq[0];
- if( n1.getKind()==BOUND_VARIABLE ){
- n2 = QuantArith::offset( n2, 1 );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term ) {
+ if( lit.getKind()==GEQ ){
+ if( lit[0].getType().isInteger() ){
+ std::map< Node, Node > msum;
+ if( QuantArith::getMonomialSumLit( lit, msum ) ){
+ Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl;
+ QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" );
+ for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){
+ Node veq;
+ if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){
+ Node n1 = veq[0];
+ Node n2 = veq[1];
+ if(pol){
+ //flip
+ n1 = veq[1];
+ n2 = veq[0];
+ if( n1.getKind()==BOUND_VARIABLE ){
+ n2 = QuantArith::offset( n2, 1 );
+ }else{
+ n1 = QuantArith::offset( n1, -1 );
+ }
+ veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
+ }
+ Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
+ Node t = n1==it->first ? n2 : n1;
+ if( !hasNonBoundVar( q, t ) ) {
+ Trace("bound-int-debug") << "The bound is relevant." << std::endl;
+ int loru = n1==it->first ? 0 : 1;
+ bound_lit_type_map[it->first] = BOUND_INT_RANGE;
+ bound_int_range_term[loru][it->first] = t;
+ bound_lit_map[loru][it->first] = lit;
+ bound_lit_pol_map[loru][it->first] = pol;
}else{
- n1 = QuantArith::offset( n1, -1 );
+ Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
}
- veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
- }
- Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
- Node t = n1==it->first ? n2 : n1;
- if( !hasNonBoundVar( f, t ) ) {
- Trace("bound-int-debug") << "The bound is relevant." << std::endl;
- int loru = n1==it->first ? 0 : 1;
- d_bounds[loru][f][it->first] = t;
- bound_lit_map[loru][it->first] = lit;
- bound_lit_pol_map[loru][it->first] = pol;
- }else{
- Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
}
}
}
}
}
+ }else if( lit.getKind()==MEMBER ){
+ //TODO: enable this when sets models are fixed
+ /*
+ if( !pol && lit[0].getKind()==BOUND_VARIABLE && !isBound( q, lit[0] ) && !lit[1].hasBoundVar() ){
+ Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is membership." << std::endl;
+ bound_lit_type_map[lit[0]] = BOUND_SET_MEMBER;
+ bound_lit_map[0][lit[0]] = lit;
+ bound_lit_pol_map[0][lit[0]] = pol;
+ }
+ */
}else if( lit.getKind()==LEQ || lit.getKind()==LT || lit.getKind()==GT ) {
Message() << "BoundedIntegers : Bad kind for literal : " << lit << std::endl;
}
}
-void BoundedIntegers::process( Node f, Node n, bool pol,
+void BoundedIntegers::process( Node q, Node n, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term ){
if( (n.getKind()==OR && pol) || (n.getKind()==AND && !pol) ){
for( unsigned i=0; i<n.getNumChildren(); i++) {
- process( f, n[i], pol, bound_lit_map, bound_lit_pol_map );
+ process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}
}else if( n.getKind()==NOT ){
- process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map );
+ process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}else {
- processLiteral( f, n, pol, bound_lit_map, bound_lit_pol_map );
+ processLiteral( q, n, pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}
}
@@ -258,58 +288,99 @@ void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
}
}
+void BoundedIntegers::setBoundedVar( Node q, Node v, unsigned bound_type ) {
+ d_bound_type[q][v] = bound_type;
+ d_set_nums[q][v] = d_set[q].size();
+ d_set[q].push_back( v );
+ Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v << std::endl;
+}
+
void BoundedIntegers::registerQuantifier( Node f ) {
Trace("bound-int") << "Register quantifier " << f << std::endl;
- bool hasIntType = false;
- int finiteTypes = 0;
- std::map< Node, int > numMap;
- for( unsigned i=0; i<f[0].getNumChildren(); i++) {
- numMap[f[0][i]] = i;
- if( f[0][i].getType().isInteger() ){
- hasIntType = true;
- }
- else if( f[0][i].getType().isSort() || f[0][i].getType().getCardinality().isFinite() ){
- finiteTypes++;
- }
- }
- if( hasIntType ){
- bool success;
- do{
- std::map< int, std::map< Node, Node > > bound_lit_map;
- std::map< int, std::map< Node, bool > > bound_lit_pol_map;
- success = false;
- process( f, f[1], true, bound_lit_map, bound_lit_pol_map );
- for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
- Node v = it->first;
- if( !isBound(f,v) ){
- if( d_bounds[1][f].find(v)!=d_bounds[1][f].end() ){
- d_set[f].push_back(v);
- d_set_nums[f].push_back(numMap[v]);
+
+ bool success;
+ do{
+ std::map< Node, unsigned > bound_lit_type_map;
+ std::map< int, std::map< Node, Node > > bound_lit_map;
+ std::map< int, std::map< Node, bool > > bound_lit_pol_map;
+ std::map< int, std::map< Node, Node > > bound_int_range_term;
+ success = false;
+ process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
+ //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
+ for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
+ Node v = it->first;
+ if( !isBound( f, v ) ){
+ bool setBoundVar = false;
+ if( it->second==BOUND_INT_RANGE ){
+ //must have both
+ if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){
+ setBoundedVar( f, v, BOUND_INT_RANGE );
+ setBoundVar = true;
success = true;
- //set Attributes on literals
for( unsigned b=0; b<2; b++ ){
- Assert( bound_lit_map[b].find( v )!=bound_lit_map[b].end() );
+ //set the bounds
+ Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() );
+ d_bounds[b][f][v] = bound_int_range_term[b][v];
+ }
+ Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
+ d_range[f][v] = Rewriter::rewrite( r );
+ Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
+ }
+ }else if( it->second==BOUND_SET_MEMBER ){
+ setBoundedVar( f, v, BOUND_SET_MEMBER );
+ setBoundVar = true;
+ d_setm_range[f][v] = bound_lit_map[0][v][1];
+ Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl;
+ }
+ if( setBoundVar ){
+ //set Attributes on literals
+ for( unsigned b=0; b<2; b++ ){
+ if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){
Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
BoundIntLitAttribute bila;
bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
+ }else{
+ Assert( it->second!=BOUND_INT_RANGE );
}
- Trace("bound-int") << "Variable " << v << " is bound because of literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
}
}
}
- }while( success );
- Trace("bound-int") << "Bounds are : " << std::endl;
- for( unsigned i=0; i<d_set[f].size(); i++) {
- Node v = d_set[f][i];
- Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
- d_range[f][v] = Rewriter::rewrite( r );
+ }
+ }while( success );
+
+ Trace("bound-int") << "Bounds are : " << std::endl;
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ if( d_bound_type[f][v]==BOUND_INT_RANGE ){
Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
+ }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl;
+ }
+ }
+
+ bool bound_success = true;
+ for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+ if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
+ TypeNode tn = f[0][i].getType();
+ if( !tn.isSort() && !getTermDatabase()->mayComplete( tn ) ){
+ Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
+ bound_success = false;
+ break;
+ }
}
- if( d_set[f].size()==(f[0].getNumChildren()-finiteTypes) ){
- d_bound_quants.push_back( f );
- for( unsigned i=0; i<d_set[f].size(); i++) {
- Node v = d_set[f][i];
- Node r = d_range[f][v];
+ }
+
+ if( bound_success ){
+ d_bound_quants.push_back( f );
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ if( d_bound_type[f][v]==BOUND_INT_RANGE || d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ Node r;
+ if( d_bound_type[f][v]==BOUND_INT_RANGE ){
+ r = d_range[f][v];
+ }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ r = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] );
+ }
bool isProxy = false;
if( r.hasBoundVar() ){
//introduce a new bound
@@ -319,18 +390,15 @@ void BoundedIntegers::registerQuantifier( Node f ) {
r = new_range;
isProxy = true;
}
- if( r.getKind()!=CONST_RATIONAL ){
+ if( !r.isConst() ){
if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
- Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << " " << r.getKind() << std::endl;
+ Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
d_ranges.push_back( r );
- d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
+ d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
d_rms[r]->initialize();
}
}
}
- }else{
- Trace("bound-int-warn") << "Warning : Bounded Integers : Could not find bounds for " << f << std::endl;
- //Message() << "Bound integers : Cannot infer bounds of " << f << std::endl;
}
}
}
@@ -376,39 +444,28 @@ Node BoundedIntegers::getNextDecisionRequest() {
return Node::null();
}
+unsigned BoundedIntegers::getBoundVarType( Node q, Node v ) {
+ std::map< Node, unsigned >::iterator it = d_bound_type[q].find( v );
+ if( it==d_bound_type[q].end() ){
+ return BOUND_NONE;
+ }else{
+ return it->second;
+ }
+}
+
void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
l = d_bounds[0][f][v];
u = d_bounds[1][f][v];
if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
- //must create substitution
+ //get the substitution
std::vector< Node > vars;
std::vector< Node > subs;
- Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
- for( unsigned i=0; i<d_set[f].size(); i++) {
- if( d_set[f][i]!=v ){
- Trace("bound-int-rsi") << "Look up the value for " << d_set[f][i] << " " << rsi->d_var_order[d_set_nums[f][i]] << std::endl;
- Trace("bound-int-rsi") << "term : " << rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]) << std::endl;
- vars.push_back(d_set[f][i]);
- subs.push_back(rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]));
- }else{
- break;
- }
- }
- Trace("bound-int-rsi") << "Do substitution..." << std::endl;
- //check if it has been instantiated
- if (!vars.empty() && !d_bnd_it[f][v].hasInstantiated(subs)){
- //must add the lemma
- Node nn = d_nground_range[f][v];
- nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[f][v] );
- Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
- d_quantEngine->getOutputChannel().lemma(lem, false, true);
- l = Node::null();
- u = Node::null();
- return;
- }else{
+ if( getRsiSubsitution( f, v, vars, subs, rsi ) ){
u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }else{
+ u = Node::null();
+ l = Node::null();
}
}
}
@@ -416,12 +473,86 @@ void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l,
void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
getBounds( f, v, rsi, l, u );
Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
- l = d_quantEngine->getModel()->getCurrentModelValue( l );
- u = d_quantEngine->getModel()->getCurrentModelValue( u );
+ if( !l.isNull() ){
+ l = d_quantEngine->getModel()->getCurrentModelValue( l );
+ }
+ if( !u.isNull() ){
+ u = d_quantEngine->getModel()->getCurrentModelValue( u );
+ }
Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
return;
}
-bool BoundedIntegers::isGroundRange(Node f, Node v) {
- return isBoundVar(f,v) && !getLowerBound(f,v).hasBoundVar() && !getUpperBound(f,v).hasBoundVar();
+bool BoundedIntegers::isGroundRange( Node q, Node v ) {
+ if( isBoundVar(q,v) ){
+ if( d_bound_type[q][v]==BOUND_INT_RANGE ){
+ return !getLowerBound(q,v).hasBoundVar() && !getUpperBound(q,v).hasBoundVar();
+ }else if( d_bound_type[q][v]==BOUND_SET_MEMBER ){
+ return !d_setm_range[q][v].hasBoundVar();
+ }
+ }
+ return false;
}
+
+Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) {
+ Node sr = d_setm_range[q][v];
+ if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){
+ //get the substitution
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
+ sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }else{
+ sr = Node::null();
+ }
+ }
+ return sr;
+}
+
+Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
+ Node sr = getSetRange( q, v, rsi );
+ if( !sr.isNull() ){
+ Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl;
+ sr = d_quantEngine->getModel()->getCurrentModelValue( sr );
+ Trace("bound-int-rsi") << "Value is " << sr << std::endl;
+ }
+ return sr;
+}
+
+bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) {
+
+ Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
+ Assert( d_set_nums[q].find( v )!=d_set_nums[q].end() );
+ int vindex = d_set_nums[q][v];
+ Assert( d_set_nums[q][v]==vindex );
+ Trace("bound-int-rsi-debug") << " index order is " << vindex << std::endl;
+ //must take substitution for all variables that are iterating at higher level
+ for( int i=0; i<vindex; i++) {
+ Assert( d_set_nums[q][d_set[q][i]]==i );
+ Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl;
+ int v = rsi->getVariableOrder( i );
+ Assert( q[0][v]==d_set[q][i] );
+ Node t = rsi->getCurrentTerm( v );
+ Trace("bound-int-rsi") << "term : " << t << std::endl;
+ vars.push_back( d_set[q][i] );
+ subs.push_back( t );
+ }
+
+ //check if it has been instantiated
+ if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){
+ if( d_bound_type[q][v]==BOUND_INT_RANGE ){
+ //must add the lemma
+ Node nn = d_nground_range[q][v];
+ nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] );
+ Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
+ d_quantEngine->getOutputChannel().lemma(lem, false, true);
+ }else{
+ //TODO : sets
+ }
+ return false;
+ }else{
+ return true;
+ }
+}
+
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
index 7d15097bd..ab4bcba96 100644..100755
--- a/src/theory/quantifiers/bounded_integers.h
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -39,31 +39,57 @@ class BoundedIntegers : public QuantifiersModule
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
typedef context::CDHashMap<int, bool> IntBoolMap;
+public:
+ enum {
+ BOUND_FINITE,
+ BOUND_INT_RANGE,
+ BOUND_SET_MEMBER,
+ BOUND_NONE
+ };
private:
//for determining bounds
bool isBound( Node f, Node v );
bool hasNonBoundVar( Node f, Node b );
- std::map< Node, std::map< Node, Node > > d_bounds[2];
+ //bound type
+ std::map< Node, std::map< Node, unsigned > > d_bound_type;
std::map< Node, std::vector< Node > > d_set;
- std::map< Node, std::vector< int > > d_set_nums;
+ std::map< Node, std::map< Node, int > > d_set_nums;
+ //integer lower/upper bounds
+ std::map< Node, std::map< Node, Node > > d_bounds[2];
std::map< Node, std::map< Node, Node > > d_range;
std::map< Node, std::map< Node, Node > > d_nground_range;
+ //set membership range
+ std::map< Node, std::map< Node, Node > > d_setm_range;
void hasFreeVar( Node f, Node n );
void process( Node f, Node n, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term );
void processLiteral( Node f, Node lit, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term );
std::vector< Node > d_bound_quants;
private:
class RangeModel {
+ public:
+ RangeModel(){}
+ virtual ~RangeModel(){}
+ virtual void initialize() = 0;
+ virtual void assertNode(Node n) = 0;
+ virtual Node getNextDecisionRequest() = 0;
+ virtual bool proxyCurrentRange() = 0;
+ };
+ class IntRangeModel : public RangeModel {
private:
BoundedIntegers * d_bi;
void allocateRange();
Node d_proxy_range;
public:
- RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
+ IntRangeModel( BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
+ virtual ~IntRangeModel(){}
Node d_range;
int d_curr_max;
std::map< int, Node > d_range_literal;
@@ -108,27 +134,36 @@ private:
std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
private:
void addLiteralFromRange( Node lit, Node r );
+
+ void setBoundedVar( Node f, Node v, unsigned bound_type );
public:
BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
- ~BoundedIntegers() throw() {}
-
+ virtual ~BoundedIntegers();
+
+ void presolve();
bool needsCheck( Theory::Effort e );
void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
Node getNextDecisionRequest();
- bool isBoundVar( Node f, Node v ) { return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end(); }
- unsigned getNumBoundVars( Node f ) { return d_set[f].size(); }
- Node getBoundVar( Node f, int i ) { return d_set[f][i]; }
- int getBoundVarNum( Node f, int i ) { return d_set_nums[f][i]; }
- Node getLowerBound( Node f, Node v ){ return d_bounds[0][f][v]; }
- Node getUpperBound( Node f, Node v ){ return d_bounds[1][f][v]; }
+ bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); }
+ unsigned getBoundVarType( Node q, Node v );
+ unsigned getNumBoundVars( Node q ) { return d_set[q].size(); }
+ Node getBoundVar( Node q, int i ) { return d_set[q][i]; }
+ //for integer range
+ Node getLowerBound( Node q, Node v ){ return d_bounds[0][q][v]; }
+ Node getUpperBound( Node q, Node v ){ return d_bounds[1][q][v]; }
void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
bool isGroundRange(Node f, Node v);
+ //for set range
+ Node getSetRange( Node q, Node v, RepSetIterator * rsi );
+ Node getSetRangeValue( Node q, Node v, RepSetIterator * rsi );
/** Identify this module */
std::string identify() const { return "BoundedIntegers"; }
+private:
+ bool getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi );
};
}
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 43f5ee2fd..a0d9bda0f 100644..100755
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -28,7 +28,7 @@ using namespace CVC4::theory;
using namespace CVC4::theory::inst;
bool CandidateGenerator::isLegalCandidate( Node n ){
- return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ) );
+ return d_qe->getTermDatabase()->isTermActive( n ) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) );
}
void CandidateGeneratorQueue::addCandidate( Node n ) {
@@ -59,7 +59,7 @@ Node CandidateGeneratorQueue::getNextCandidate(){
}
CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node pat ) :
- d_qe( qe ), d_term_iter( -1 ){
+CandidateGenerator( qe ), d_term_iter( -1 ){
d_op = qe->getTermDatabase()->getMatchOperator( pat );
Assert( !d_op.isNull() );
d_op_arity = pat.getNumChildren();
@@ -186,7 +186,7 @@ Node CandidateGeneratorQE::getNextCandidate(){
}
CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+ CandidateGenerator( qe ), d_match_pattern( mpat ){
Assert( mpat.getKind()==EQUAL );
for( unsigned i=0; i<2; i++ ){
if( !quantifiers::TermDb::hasInstConstAttr(mpat[i]) ){
@@ -225,7 +225,7 @@ Node CandidateGeneratorQELitEq::getNextCandidate(){
CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+CandidateGenerator( qe ), d_match_pattern( mpat ){
Assert( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF );
d_match_pattern_type = d_match_pattern[0].getType();
@@ -259,7 +259,7 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+ CandidateGenerator( qe ), d_match_pattern( mpat ){
d_match_pattern_type = mpat.getType();
Assert( mpat.getKind()==INST_CONSTANT );
d_f = quantifiers::TermDb::getInstConstAttr( mpat );
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 18ef6a086..4fc6969fc 100644..100755
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -33,8 +33,10 @@ namespace inst {
/** base class for generating candidates for matching */
class CandidateGenerator {
+protected:
+ QuantifiersEngine* d_qe;
public:
- CandidateGenerator(){}
+ CandidateGenerator( QuantifiersEngine* qe ) : d_qe( qe ){}
virtual ~CandidateGenerator(){}
/** Get candidates functions. These set up a context to get all match candidates.
@@ -54,7 +56,7 @@ public:
virtual void resetInstantiationRound() = 0;
public:
/** legal candidate */
- static bool isLegalCandidate( Node n );
+ bool isLegalCandidate( Node n );
};/* class CandidateGenerator */
/** candidate generator queue (for manual candidate generation) */
@@ -63,7 +65,7 @@ private:
std::vector< Node > d_candidates;
int d_candidate_index;
public:
- CandidateGeneratorQueue() : d_candidate_index( 0 ){}
+ CandidateGeneratorQueue( QuantifiersEngine* qe ) : CandidateGenerator( qe ), d_candidate_index( 0 ){}
~CandidateGeneratorQueue() throw() {}
void addCandidate( Node n );
@@ -80,8 +82,6 @@ class CandidateGeneratorQE : public CandidateGenerator
private:
//operator you are looking for
Node d_op;
- //instantiator pointer
- QuantifiersEngine* d_qe;
//the equality class iterator
unsigned d_op_arity;
std::vector< quantifiers::TermArgTrie* > d_tindex;
@@ -122,8 +122,6 @@ private:
Node d_match_pattern;
Node d_match_gterm;
bool d_do_mgt;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
public:
CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQELitEq() throw() {}
@@ -142,8 +140,6 @@ private:
Node d_match_pattern;
//type of disequality
TypeNode d_match_pattern_type;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
public:
CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQELitDeq() throw() {}
@@ -161,8 +157,6 @@ private:
//equality you are trying to match equalities for
Node d_match_pattern;
TypeNode d_match_pattern_type;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
// quantifier/index for the variable we are matching
Node d_f;
unsigned d_index;
diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp
index d9059a3e6..71bf7c426 100644..100755
--- a/src/theory/quantifiers/ce_guided_instantiation.cpp
+++ b/src/theory/quantifiers/ce_guided_instantiation.cpp
@@ -21,6 +21,8 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/theory_engine.h"
+#include "prop/prop_engine.h"
+#include "theory/bv/theory_bv_rewriter.h"
using namespace CVC4::kind;
using namespace std;
@@ -46,7 +48,7 @@ void CegConjecture::assign( Node q ) {
Assert( q.getKind()==FORALL );
d_assert_quant = q;
//register with single invocation if applicable
- if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInv() ){
+ if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
d_ceg_si->initialize( q );
if( q!=d_ceg_si->d_quant ){
//Node red_lem = NodeManager::currentNM()->mkNode( OR, q.negate(), d_cegqi_si->d_quant );
@@ -55,12 +57,15 @@ void CegConjecture::assign( Node q ) {
}
}
d_quant = q;
+ Assert( d_candidates.empty() );
+ std::vector< Node > vars;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ vars.push_back( q[0][i] );
d_candidates.push_back( NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() ) );
}
Trace("cegqi") << "Base quantified formula is : " << q << std::endl;
//construct base instantiation
- d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, d_candidates ) );
+ d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, vars, d_candidates ) );
Trace("cegqi") << "Base instantiation is : " << d_base_inst << std::endl;
if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) ){
CegInstantiation::collectDisjuncts( d_base_inst, d_base_disj );
@@ -130,14 +135,18 @@ Node CegConjecture::getLiteral( QuantifiersEngine * qe, int i ) {
qe->getOutputChannel().lemma( lem );
qe->getOutputChannel().requirePhase( lit, true );
- if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){
//implies height bounds on each candidate variable
std::vector< Node > lem_c;
for( unsigned j=0; j<d_candidates.size(); j++ ){
- lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) );
+ if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) );
+ }else{
+ //lem_c.push_back( NodeManager::currentNM()->mkNode( DT_SIZE_BOUND, d_candidates[j], c ) );
+ }
}
Node hlem = NodeManager::currentNM()->mkNode( OR, lit.negate(), lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c ) );
- Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (dt-height-pred) : " << hlem << std::endl;
+ Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (pred) : " << hlem << std::endl;
qe->getOutputChannel().lemma( hlem );
}
return lit;
@@ -257,8 +266,45 @@ void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) {
}
}
+void CegInstantiation::preRegisterQuantifier( Node q ) {
+ if( options::sygusDirectEval() ){
+ if( q.getNumChildren()==3 && q[2].getKind()==INST_PATTERN_LIST && q[2][0].getKind()==INST_PATTERN ){
+ //check whether it is an evaluation axiom
+ Node pat = q[2][0][0];
+ if( pat.getKind()==APPLY_UF ){
+ TypeNode tn = pat[0].getType();
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ //do unfolding if it induces Boolean structure,
+ //do direct evaluation if it does not induce Boolean structure,
+ // the reasoning is unfolding over these terms does not lead to helpful conflict analysis, and introduces many shared terms
+ bool directEval = true;
+ TypeNode ptn = pat.getType();
+ if( ptn.isBoolean() || ptn.isBitVector() ){
+ directEval = false;
+ }else{
+ unsigned cindex = Datatype::indexOf(pat[0].getOperator().toExpr() );
+ Node base = d_quantEngine->getTermDatabaseSygus()->getGenericBase( tn, dt, cindex );
+ Trace("cegqi-debug") << "Generic base term for " << pat[0] << " is " << base << std::endl;
+ if( base.getKind()==ITE ){
+ directEval = false;
+ }
+ }
+ if( directEval ){
+ //take ownership of this quantified formula (will use direct evaluation instead of unfolding instantiation)
+ d_quantEngine->setOwner( q, this );
+ d_eval_axioms[q] = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
void CegInstantiation::registerQuantifier( Node q ) {
- if( d_quantEngine->getOwner( q )==this ){
+ if( d_quantEngine->getOwner( q )==this && d_eval_axioms.find( q )==d_eval_axioms.end() ){
if( !d_conj->isAssigned() ){
Trace("cegqi") << "Register conjecture : " << q << std::endl;
d_conj->assign( q );
@@ -278,7 +324,7 @@ void CegInstantiation::registerQuantifier( Node q ) {
if( it!=d_uf_measure.end() ){
mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, d_conj->d_candidates[j] ) );
}
- }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){
//measure term is a fresh constant
mc.push_back( NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() ) );
}
@@ -291,6 +337,8 @@ void CegInstantiation::registerQuantifier( Node q ) {
}else{
Assert( d_conj->d_quant==q );
}
+ }else{
+ Trace("cegqi-debug") << "Register quantifier : " << q << std::endl;
}
}
@@ -317,7 +365,7 @@ Node CegInstantiation::getNextDecisionRequest() {
Trace("cegqi-debug") << "CEGQI : Decide next on : " << req_dec[i] << "..." << std::endl;
return req_dec[i];
}else{
- Trace("cegqi-debug") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
+ Trace("cegqi-debug2") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
}
}
@@ -350,6 +398,11 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
Trace("cegqi-engine-debug") << conj->d_candidates[i] << " ";
}
Trace("cegqi-engine-debug") << std::endl;
+ Trace("cegqi-engine-debug") << " * Candidate ce skolems : ";
+ for( unsigned i=0; i<conj->d_ce_sk.size(); i++ ){
+ Trace("cegqi-engine-debug") << conj->d_ce_sk[i] << " ";
+ }
+ Trace("cegqi-engine-debug") << std::endl;
if( conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){
Trace("cegqi-engine") << " * Current term size : " << conj->d_curr_lit.get() << std::endl;
}
@@ -374,6 +427,24 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
}
std::vector< Node > model_values;
if( getModelValues( conj, conj->d_candidates, model_values ) ){
+ if( options::sygusDirectEval() ){
+ std::vector< Node > eager_eval_lem;
+ for( unsigned j=0; j<conj->d_candidates.size(); j++ ){
+ d_quantEngine->getTermDatabaseSygus()->registerModelValue( conj->d_candidates[j], model_values[j], eager_eval_lem );
+ }
+ if( !eager_eval_lem.empty() ){
+ for( unsigned j=0; j<eager_eval_lem.size(); j++ ){
+ Node lem = eager_eval_lem[j];
+ if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){
+ //FIXME: hack to incorporate hacks from BV for division by zero
+ lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem );
+ }
+ Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
+ d_quantEngine->addLemma( lem );
+ }
+ return;
+ }
+ }
//check if we must apply fairness lemmas
if( conj->getCegqiFairMode()==CEGQI_FAIR_UF_DT_SIZE ){
std::vector< Node > lems;
@@ -390,6 +461,7 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
}
}
//must get a counterexample to the value of the current candidate
+ Assert( conj->d_candidates.size()==model_values.size() );
Node inst = conj->d_base_inst.substitute( conj->d_candidates.begin(), conj->d_candidates.end(), model_values.begin(), model_values.end() );
//check whether we will run CEGIS on inner skolem variables
bool sk_refine = ( !conj->isGround() || conj->d_refine_count==0 );
@@ -422,10 +494,30 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
Node lem = NodeManager::currentNM()->mkNode( OR, ic );
lem = Rewriter::rewrite( lem );
d_last_inst_si = false;
+ //eagerly unfold applications of evaluation function
+ if( options::sygusDirectEval() ){
+ Trace("cegqi-eager") << "pre-unfold counterexample : " << lem << std::endl;
+ std::map< Node, Node > visited_n;
+ lem = getEagerUnfold( lem, visited_n );
+ }
+
Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl;
- d_quantEngine->addLemma( lem );
- ++(d_statistics.d_cegqi_lemmas_ce);
- Trace("cegqi-engine") << " ...find counterexample." << std::endl;
+ if( d_quantEngine->addLemma( lem ) ){
+ ++(d_statistics.d_cegqi_lemmas_ce);
+ Trace("cegqi-engine") << " ...find counterexample." << std::endl;
+ }else{
+ //this may happen if we eagerly unfold, simplify to true
+ if( !options::sygusDirectEval() ){
+ Trace("cegqi-engine") << " ...FAILED to add candidate!" << std::endl;
+ }else{
+ Trace("cegqi-engine-debug") << " ...FAILED to add candidate!" << std::endl;
+ }
+ if( conj->d_refine_count==0 ){
+ //immediately go to refine candidate
+ checkCegConjecture( conj );
+ return;
+ }
+ }
}
}else{
@@ -589,6 +681,74 @@ void CegInstantiation::getMeasureLemmas( Node n, Node v, std::vector< Node >& le
}
}
+Node CegInstantiation::getEagerUnfold( Node n, std::map< Node, Node >& visited ) {
+ std::map< Node, Node >::iterator itv = visited.find( n );
+ if( itv==visited.end() ){
+ Trace("cegqi-eager-debug") << "getEagerUnfold " << n << std::endl;
+ Node ret;
+ if( n.getKind()==APPLY_UF ){
+ TypeNode tn = n[0].getType();
+ Trace("cegqi-eager-debug") << "check " << n[0].getType() << std::endl;
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ Trace("cegqi-eager") << "Unfold eager : " << n << std::endl;
+ Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( n[0], tn );
+ Trace("cegqi-eager") << "Built-in term : " << bTerm << std::endl;
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ Assert( var_list.getNumChildren()+1==n.getNumChildren() );
+ for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+ vars.push_back( var_list[j] );
+ }
+ for( unsigned j=1; j<n.getNumChildren(); j++ ){
+ Node nc = getEagerUnfold( n[j], visited );
+ if( var_list[j-1].getType().isBoolean() ){
+ //TODO: remove this case when boolean term conversion is eliminated
+ Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u));
+ subs.push_back( nc.eqNode( c ) );
+ }else{
+ subs.push_back( nc );
+ }
+ Assert( subs[j-1].getType()==var_list[j-1].getType() );
+ }
+ Assert( vars.size()==subs.size() );
+ bTerm = bTerm.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ Trace("cegqi-eager") << "Built-in term after subs : " << bTerm << std::endl;
+ Trace("cegqi-eager-debug") << "Types : " << bTerm.getType() << " " << n.getType() << std::endl;
+ Assert( n.getType()==bTerm.getType() );
+ ret = bTerm;
+ }
+ }
+ }
+ if( ret.isNull() ){
+ if( n.getKind()!=FORALL ){
+ bool childChanged = false;
+ std::vector< Node > children;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node nc = getEagerUnfold( n[i], visited );
+ childChanged = childChanged || n[i]!=nc;
+ children.push_back( nc );
+ }
+ if( childChanged ){
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.insert( children.begin(), n.getOperator() );
+ }
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ }
+ if( ret.isNull() ){
+ ret = n;
+ }
+ }
+ visited[n] = ret;
+ return ret;
+ }else{
+ return itv->second;
+ }
+}
+
void CegInstantiation::printSynthSolution( std::ostream& out ) {
if( d_conj->isAssigned() ){
Trace("cegqi-debug") << "Printing synth solution..." << std::endl;
diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h
index 57dc31850..c8b41c035 100644..100755
--- a/src/theory/quantifiers/ce_guided_instantiation.h
+++ b/src/theory/quantifiers/ce_guided_instantiation.h
@@ -126,6 +126,8 @@ private:
CegConjecture * d_conj;
/** last instantiation by single invocation module? */
bool d_last_inst_si;
+ /** evaluation axioms */
+ std::map< Node, bool > d_eval_axioms;
private: //for enforcing fairness
/** measure functions */
std::map< TypeNode, Node > d_uf_measure;
@@ -139,6 +141,8 @@ private: //for enforcing fairness
std::map< Node, std::map< int, Node > > d_size_term_lemma;
/** get measure lemmas */
void getMeasureLemmas( Node n, Node v, std::vector< Node >& lems );
+ /** get eager unfolding */
+ Node getEagerUnfold( Node n, std::map< Node, Node >& visited );
private:
/** check conjecture */
void checkCegConjecture( CegConjecture * conj );
@@ -156,6 +160,7 @@ public:
/* Call during quantifier engine's check */
void check( Theory::Effort e, unsigned quant_e );
/* Called for new quantifiers */
+ void preRegisterQuantifier( Node q );
void registerQuantifier( Node q );
void assertNode( Node n );
Node getNextDecisionRequest();
diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp
index 33856d226..3177739ac 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv.cpp
@@ -111,6 +111,7 @@ void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems
void CegConjectureSingleInv::initialize( Node q ) {
Assert( d_quant.isNull() );
+ Assert( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE );
//initialize data
d_quant = q;
//process
@@ -121,6 +122,7 @@ void CegConjectureSingleInv::initialize( Node q ) {
std::map< Node, std::map< Node, std::vector< Node > > > prog_invoke;
std::vector< Node > progs;
std::map< Node, std::map< Node, bool > > contains;
+ bool is_syntax_restricted = false;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
progs.push_back( q[0][i] );
//check whether all types have ITE
@@ -131,161 +133,173 @@ void CegConjectureSingleInv::initialize( Node q ) {
d_has_ites = false;
}
}
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( dt.isSygus() );
+ if( !dt.getSygusAllowAll() ){
+ is_syntax_restricted = true;
+ }
}
- Node qq = q[1];
- if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
- qq = q[1][0][1];
- }else{
- qq = TermDb::simpleNegate( qq );
- }
- //remove the deep embedding
- std::map< Node, Node > visited;
- std::vector< TypeNode > types;
- std::vector< Node > order_vars;
- std::map< Node, Node > single_inv_app_map;
- int type_valid = 0;
- qq = removeDeepEmbedding( qq, progs, types, type_valid, visited );
- Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl;
+ //abort if not aggressive
bool singleInvocation = true;
- if( type_valid==0 ){
- //process the single invocation-ness of the property
- d_sip->init( types, qq );
- Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
- d_sip->debugPrint( "cegqi-si" );
- //map from program to bound variables
- for( unsigned j=0; j<progs.size(); j++ ){
- Node prog = progs[j];
- std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog );
- if( it_nsi!=d_nsi_op_map.end() ){
- Node op = it_nsi->second;
- std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op );
- if( it_fov!=d_sip->d_func_fo_var.end() ){
- Node pv = it_fov->second;
- Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() );
- Node inv = d_sip->d_func_inv[op];
- single_inv_app_map[prog] = inv;
- Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl;
- d_prog_to_sol_index[prog] = order_vars.size();
- order_vars.push_back( pv );
+ if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_USE && is_syntax_restricted ){
+ singleInvocation = false;
+ Trace("cegqi-si") << "...grammar is restricted, do not use single invocation techniques." << std::endl;
+ }else{
+ Node qq = q[1];
+ if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
+ qq = q[1][0][1];
+ }else{
+ qq = TermDb::simpleNegate( qq );
+ }
+ //remove the deep embedding
+ std::map< Node, Node > visited;
+ std::vector< TypeNode > types;
+ std::vector< Node > order_vars;
+ std::map< Node, Node > single_inv_app_map;
+ int type_valid = 0;
+ qq = removeDeepEmbedding( qq, progs, types, type_valid, visited );
+ Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl;
+ if( type_valid==0 ){
+ //process the single invocation-ness of the property
+ d_sip->init( types, qq );
+ Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
+ d_sip->debugPrint( "cegqi-si" );
+ //map from program to bound variables
+ for( unsigned j=0; j<progs.size(); j++ ){
+ Node prog = progs[j];
+ std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog );
+ if( it_nsi!=d_nsi_op_map.end() ){
+ Node op = it_nsi->second;
+ std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op );
+ if( it_fov!=d_sip->d_func_fo_var.end() ){
+ Node pv = it_fov->second;
+ Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() );
+ Node inv = d_sip->d_func_inv[op];
+ single_inv_app_map[prog] = inv;
+ Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl;
+ d_prog_to_sol_index[prog] = order_vars.size();
+ order_vars.push_back( pv );
+ }
+ }else{
+ //does not mention the function
}
- }else{
- //does not mention the function
}
- }
- //reorder the variables
- Assert( d_sip->d_func_vars.size()==order_vars.size() );
- d_sip->d_func_vars.clear();
- d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() );
+ //reorder the variables
+ Assert( d_sip->d_func_vars.size()==order_vars.size() );
+ d_sip->d_func_vars.clear();
+ d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() );
- //check if it is single invocation
- if( !d_sip->d_conjuncts[1].empty() ){
- singleInvocation = false;
- if( options::cegqiSingleInvPartial() ){
- //this enables partially single invocation techniques
- d_nsingle_inv = d_sip->getNonSingleInvocation();
- d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv );
- d_full_inv = d_sip->getFullSpecification();
- d_full_inv = TermDb::simpleNegate( d_full_inv );
- singleInvocation = true;
- }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
- //if we are doing invariant templates, then construct the template
- std::map< Node, bool > has_inv;
- std::map< Node, std::vector< Node > > inv_pre_post[2];
- for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){
- std::vector< Node > disjuncts;
- Node func;
- int pol = -1;
- Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl;
- d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts );
- if( pol>=0 ){
- Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() );
- Node prog = d_nsi_op_map_to_prog[func];
- Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl;
- Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) );
- c = pol==0 ? TermDb::simpleNegate( c ) : c;
- Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl;
- inv_pre_post[pol][prog].push_back( c );
- has_inv[prog] = true;
- }else{
- Trace("cegqi-inv") << "...no status." << std::endl;
+ //check if it is single invocation
+ if( !d_sip->d_conjuncts[1].empty() ){
+ singleInvocation = false;
+ if( options::cegqiSingleInvPartial() ){
+ //this enables partially single invocation techniques
+ d_nsingle_inv = d_sip->getNonSingleInvocation();
+ d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv );
+ d_full_inv = d_sip->getFullSpecification();
+ d_full_inv = TermDb::simpleNegate( d_full_inv );
+ singleInvocation = true;
+ }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
+ //if we are doing invariant templates, then construct the template
+ std::map< Node, bool > has_inv;
+ std::map< Node, std::vector< Node > > inv_pre_post[2];
+ for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){
+ std::vector< Node > disjuncts;
+ Node func;
+ int pol = -1;
+ Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl;
+ d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts );
+ if( pol>=0 ){
+ Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() );
+ Node prog = d_nsi_op_map_to_prog[func];
+ Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl;
+ Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) );
+ c = pol==0 ? TermDb::simpleNegate( c ) : c;
+ Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl;
+ inv_pre_post[pol][prog].push_back( c );
+ has_inv[prog] = true;
+ }else{
+ Trace("cegqi-inv") << "...no status." << std::endl;
+ }
}
- }
- Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl;
- //now, contruct the template for the invariant(s)
- std::map< Node, Node > prog_templ;
- for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){
- Node prog = iti->first;
- Trace("cegqi-inv") << "...for " << prog << "..." << std::endl;
- Trace("cegqi-inv") << " args : ";
+ Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl;
+ //now, contruct the template for the invariant(s)
+ std::map< Node, Node > prog_templ;
+ for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){
+ Node prog = iti->first;
+ Trace("cegqi-inv") << "...for " << prog << "..." << std::endl;
+ Trace("cegqi-inv") << " args : ";
+ for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
+ std::stringstream ss;
+ ss << "i_" << j;
+ Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() );
+ d_prog_templ_vars[prog].push_back( v );
+ Trace("cegqi-inv") << v << " ";
+ }
+ Trace("cegqi-inv") << std::endl;
+ Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) :
+ ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) );
+ d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) :
+ ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) );
+ d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
+ Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
+ Node invariant = single_inv_app_map[prog];
+ invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
+ //construct template
+ Node templ;
+ if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
+ //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
+ templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant );
+ }else{
+ Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
+ //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
+ templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant );
+ }
+ visited.clear();
+ templ = addDeepEmbedding( templ, visited );
+ Trace("cegqi-inv") << " template : " << templ << std::endl;
+ prog_templ[prog] = templ;
+ }
+ Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] );
+ visited.clear();
+ bd = addDeepEmbedding( bd, visited );
+ Trace("cegqi-inv") << " body : " << bd << std::endl;
+ bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars );
+ Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl;
+ //make inner existential
+ std::vector< Node > new_var_bv;
for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
std::stringstream ss;
- ss << "i_" << j;
- Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() );
- d_prog_templ_vars[prog].push_back( v );
- Trace("cegqi-inv") << v << " ";
+ ss << "ss_" << j;
+ new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) );
}
- Trace("cegqi-inv") << std::endl;
- Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) :
- ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) );
- d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) :
- ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) );
- d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
- Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
- Node invariant = single_inv_app_map[prog];
- invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
- //construct template
- Node templ;
- if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
- //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
- templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant );
- }else{
- Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
- //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
- templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant );
+ bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() );
+ Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
+ for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
+ new_var_bv.push_back( q[1][0][0][j] );
}
- visited.clear();
- templ = addDeepEmbedding( templ, visited );
- Trace("cegqi-inv") << " template : " << templ << std::endl;
- prog_templ[prog] = templ;
- }
- Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] );
- visited.clear();
- bd = addDeepEmbedding( bd, visited );
- Trace("cegqi-inv") << " body : " << bd << std::endl;
- bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars );
- Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl;
- //make inner existential
- std::vector< Node > new_var_bv;
- for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
- std::stringstream ss;
- ss << "ss_" << j;
- new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) );
- }
- bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() );
- Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
- for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
- new_var_bv.push_back( q[1][0][0][j] );
- }
- if( !new_var_bv.empty() ){
- Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv );
- bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate();
+ if( !new_var_bv.empty() ){
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv );
+ bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate();
+ }
+ //make outer universal
+ bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd );
+ bd = Rewriter::rewrite( bd );
+ Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl;
+ d_quant = bd;
}
- //make outer universal
- bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd );
- bd = Rewriter::rewrite( bd );
- Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl;
- d_quant = bd;
+ }else{
+ //we are fully single invocation
}
}else{
- //we are fully single invocation
+ Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl;
+ singleInvocation = false;
}
- }else{
- Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl;
- singleInvocation = false;
}
if( singleInvocation ){
d_single_inv = d_sip->getSingleInvocation();
@@ -534,6 +548,7 @@ bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){
return false;
}else{
Trace("cegqi-engine") << siss.str() << std::endl;
+ Assert( d_single_inv_var.size()==subs.size() );
Node lem = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), subs.begin(), subs.end() );
if( d_qe->getTermDatabase()->containsVtsTerm( lem ) ){
Trace("cegqi-engine-debug") << "Rewrite based on vts symbols..." << std::endl;
@@ -595,6 +610,7 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
for( unsigned i=0; i<d_sip->d_all_vars.size(); i++ ){
subs.push_back( NodeManager::currentNM()->mkSkolem( "kv", d_sip->d_all_vars[i].getType(), "created for verifying nsi" ) );
}
+ Assert( d_sip->d_all_vars.size()==subs.size() );
inst = inst.substitute( d_sip->d_all_vars.begin(), d_sip->d_all_vars.end(), subs.begin(), subs.end() );
Trace("cegqi-nsi") << "NSI : verification : " << inst << std::endl;
Trace("cegqi-lemma") << "Cegqi::Lemma : verification lemma : " << inst << std::endl;
@@ -751,6 +767,7 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int&
std::sort( indices.begin(), indices.end(), ssii );
Trace("csi-sol") << "Construct solution" << std::endl;
s = constructSolution( indices, sol_index, 0 );
+ Assert( vars.size()==d_sol->d_varList.size() );
s = s.substitute( vars.begin(), vars.end(), d_sol->d_varList.begin(), d_sol->d_varList.end() );
}
d_orig_solution = s;
@@ -826,8 +843,8 @@ Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& rec
}
bool CegConjectureSingleInv::needsCheck() {
- if( options::cegqiSingleInvMultiInstAbort() ){
- if( !hasITEs() ){
+ if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_ALL_ABORT ){
+ if( !d_has_ites ){
return d_inst.empty();
}
}
@@ -922,6 +939,7 @@ void SingleInvocationPartition::process( Node n ) {
std::vector< Node > funcs;
//normalize the invocations
if( !terms.empty() ){
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
}
std::vector< Node > children;
@@ -940,6 +958,7 @@ void SingleInvocationPartition::process( Node n ) {
}
Trace("si-prt") << std::endl;
cr = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
Trace("si-prt-debug") << "...normalized invocations to " << cr << std::endl;
//now must check if it has other bound variables
@@ -974,6 +993,7 @@ void SingleInvocationPartition::process( Node n ) {
}
}
}
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
}
cr = Rewriter::rewrite( cr );
@@ -982,6 +1002,7 @@ void SingleInvocationPartition::process( Node n ) {
TermDb::getBoundVars( cr, d_all_vars );
if( singleInvocation ){
//replace with single invocation formulation
+ Assert( si_terms.size()==si_subs.size() );
cr = cr.substitute( si_terms.begin(), si_terms.end(), si_subs.begin(), si_subs.end() );
cr = Rewriter::rewrite( cr );
Trace("si-prt") << ".....si version=" << cr << std::endl;
diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h
index 4d2f9a0e5..4d2f9a0e5 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv.h
+++ b/src/theory/quantifiers/ce_guided_single_inv.h
diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
index 6394fca3d..6394fca3d 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.h b/src/theory/quantifiers/ce_guided_single_inv_ei.h
index 42e0b0820..42e0b0820 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_ei.h
+++ b/src/theory/quantifiers/ce_guided_single_inv_ei.h
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
index 240c2ed12..240c2ed12 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.h b/src/theory/quantifiers/ce_guided_single_inv_sol.h
index cb6f6bc41..cb6f6bc41 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_sol.h
+++ b/src/theory/quantifiers/ce_guided_single_inv_sol.h
diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp
index da488ea98..cd263e90c 100644..100755
--- a/src/theory/quantifiers/ceg_instantiator.cpp
+++ b/src/theory/quantifiers/ceg_instantiator.cpp
@@ -22,6 +22,9 @@
#include "theory/quantifiers/term_database.h"
#include "theory/theory_engine.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "util/bitvector.h"
+
//#define MBP_STRICT_ASSERTIONS
using namespace std;
@@ -466,6 +469,36 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::
}
}
}
+ /* 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ */
}
}
}
@@ -685,7 +718,7 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::
//[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() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){
+ if( ( effort>0 || pvtn.isBoolean() || pvtn.isBitVector() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){
Node mv = getModelValue( pv );
Node pv_coeff_m;
Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl;
@@ -781,6 +814,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
}
}
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 );
@@ -800,8 +834,10 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
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 );
}
@@ -814,6 +850,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
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;
@@ -1035,7 +1072,13 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node
if( !it->second.isNull() ){
c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
}
- Node c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
+ Assert( !c_coeff.isNull() );
+ Node c;
+ if( msum_term[it->first].isNull() ){
+ c = c_coeff;
+ }else{
+ c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
+ }
children.push_back( c );
Trace("cegqi-si-apply-subs-debug") << "Add child : " << c << std::endl;
}
@@ -1594,6 +1637,7 @@ int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, No
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;
diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h
index 3d7bbcb55..3d7bbcb55 100644..100755
--- a/src/theory/quantifiers/ceg_instantiator.h
+++ b/src/theory/quantifiers/ceg_instantiator.h
diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp
index 2cc49ef5a..f4eb67d74 100644..100755
--- a/src/theory/quantifiers/conjecture_generator.cpp
+++ b/src/theory/quantifiers/conjecture_generator.cpp
@@ -285,7 +285,7 @@ Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
}
bool ConjectureGenerator::isHandledTerm( TNode n ){
- return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
+ return d_quantEngine->getTermDatabase()->isTermActive( n ) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
}
Node ConjectureGenerator::getGroundEqc( TNode r ) {
@@ -425,7 +425,7 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {
eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
while( !eqc_i.isFinished() ){
TNode n = (*eqc_i);
- if( getTermDatabase()->hasTermCurrent( n ) && !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){
+ if( getTermDatabase()->hasTermCurrent( n ) && getTermDatabase()->isTermActive( n ) && ( n.getKind()!=EQUAL || isFalse ) ){
if( firstTime ){
Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;
firstTime = false;
@@ -1572,7 +1572,6 @@ bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode,
if( d_match_status_child_num==0 ){
//initial binding
TNode f = s->getTgFunc( d_typ, d_status_num );
- //std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );
Assert( !eqc.isNull() );
TermArgTrie * tat = s->getTermDatabase()->getTermArgTrie( eqc, f );
if( tat ){
@@ -1726,9 +1725,9 @@ void TermGenEnv::collectSignatureInformation() {
d_func_kind.clear();
d_func_args.clear();
TypeNode tnull;
- for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){
- if( getTermDatabase()->getNumGroundTerms( it->first )>0 ){
- Node nn = getTermDatabase()->getGroundTerm( it->first, 0 );
+ for( std::map< Node, std::vector< Node > >::iterator it = getTermDatabase()->d_op_map.begin(); it != getTermDatabase()->d_op_map.end(); ++it ){
+ if( !it->second.empty() ){
+ Node nn = it->second[0];
Trace("sg-rel-sig-debug") << "Check in signature : " << nn << std::endl;
if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){
bool do_enum = true;
@@ -1750,7 +1749,7 @@ void TermGenEnv::collectSignatureInformation() {
d_typ_tg_funcs[nn.getType()].push_back( it->first );
d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED );
Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;
- getTermDatabase()->computeUfEqcTerms( it->first );
+ //getTermDatabase()->computeUfEqcTerms( it->first );
}
}
Trace("sg-rel-sig-debug") << "Done check in signature : " << nn << std::endl;
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h
index c89d0f2ee..c89d0f2ee 100644..100755
--- a/src/theory/quantifiers/conjecture_generator.h
+++ b/src/theory/quantifiers/conjecture_generator.h
diff --git a/src/theory/quantifiers/equality_infer.cpp b/src/theory/quantifiers/equality_infer.cpp
index c3064116f..5190025ee 100644..100755
--- a/src/theory/quantifiers/equality_infer.cpp
+++ b/src/theory/quantifiers/equality_infer.cpp
@@ -53,10 +53,10 @@ void EqualityInference::addToExplanation( std::vector< Node >& exp, Node e ) {
}
void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc ) {
- NodeListMap::iterator re_i = d_rep_exp.find( eqc );
+ NodeIntMap::iterator re_i = d_rep_exp.find( eqc );
if( re_i!=d_rep_exp.end() ){
- for( unsigned i=0; i<(*re_i).second->size(); i++ ){
- addToExplanation( exp, (*(*re_i).second)[i] );
+ for( int i=0; i<(*re_i).second; i++ ){
+ addToExplanation( exp, d_rep_exp_data[eqc][i] );
}
}
//for( unsigned i=0; i<d_eqci[n]->d_rep_exp.size(); i++ ){
@@ -65,16 +65,19 @@ void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc
}
void EqualityInference::addToExplanationEqc( Node eqc, std::vector< Node >& exp_to_add ) {
- NodeListMap::iterator re_i = d_rep_exp.find( eqc );
- NodeList* re;
+ NodeIntMap::iterator re_i = d_rep_exp.find( eqc );
+ int n_re = 0;
if( re_i != d_rep_exp.end() ){
- re = (*re_i).second;
- }else{
- re = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) );
- d_rep_exp.insertDataFromContextMemory( eqc, re );
+ n_re = (*re_i).second;
}
+ d_rep_exp[eqc] = n_re + exp_to_add.size();
for( unsigned i=0; i<exp_to_add.size(); i++ ){
- re->push_back( exp_to_add[i] );
+ if( n_re<(int)d_rep_exp_data[eqc].size() ){
+ d_rep_exp_data[eqc][n_re] = exp_to_add[i];
+ }else{
+ d_rep_exp_data[eqc].push_back( exp_to_add[i] );
+ }
+ n_re++;
}
//for( unsigned i=0; i<exp_to_add.size(); i++ ){
// eqci->d_rep_exp.push_back( exp_to_add[i] );
@@ -204,16 +207,18 @@ void EqualityInference::eqNotifyNewClass(TNode t) {
void EqualityInference::addToUseList( Node used, Node eqc ) {
#if 1
- NodeListMap::iterator ul_i = d_uselist.find( used );
- NodeList* ul;
+ NodeIntMap::iterator ul_i = d_uselist.find( used );
+ int n_ul = 0;
if( ul_i != d_uselist.end() ){
- ul = (*ul_i).second;
- }else{
- ul = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) );
- d_uselist.insertDataFromContextMemory( used, ul );
+ n_ul = (*ul_i).second;
}
+ d_uselist[ used ] = n_ul + 1;
Trace("eq-infer-debug") << " add to use list : " << used << " -> " << eqc << std::endl;
- (*ul).push_back( eqc );
+ if( n_ul<(int)d_uselist_data[used].size() ){
+ d_uselist_data[used][n_ul] = eqc;
+ }else{
+ d_uselist_data[used].push_back( eqc );
+ }
#else
std::map< Node, EqcInfo * >::iterator itu = d_eqci.find( used );
EqcInfo * eqci_used;
@@ -356,12 +361,12 @@ void EqualityInference::eqNotifyMerge(TNode t1, TNode t2) {
//go through all equivalence classes that may refer to v_solve
std::map< Node, bool > processed;
processed[v_solve] = true;
- NodeListMap::iterator ul_i = d_uselist.find( v_solve );
+ NodeIntMap::iterator ul_i = d_uselist.find( v_solve );
if( ul_i != d_uselist.end() ){
- NodeList* ul = (*ul_i).second;
- Trace("eq-infer-debug") << " use list size = " << ul->size() << std::endl;
- for( unsigned j=0; j<ul->size(); j++ ){
- Node r = (*ul)[j];
+ int n_ul = (*ul_i).second;
+ Trace("eq-infer-debug") << " use list size = " << n_ul << std::endl;
+ for( int j=0; j<n_ul; j++ ){
+ Node r = d_uselist_data[v_solve][j];
//Trace("eq-infer-debug") << " use list size = " << eqci_solved->d_uselist.size() << std::endl;
//for( unsigned j=0; j<eqci_solved->d_uselist.size(); j++ ){
// Node r = eqci_solved->d_uselist[j];
diff --git a/src/theory/quantifiers/equality_infer.h b/src/theory/quantifiers/equality_infer.h
index 93c7bd080..80d6ef98b 100644..100755
--- a/src/theory/quantifiers/equality_infer.h
+++ b/src/theory/quantifiers/equality_infer.h
@@ -39,7 +39,7 @@ class EqualityInference
typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap< Node, NodeList *, NodeHashFunction > NodeListMap;
+ typedef context::CDHashMap< Node, int, NodeHashFunction > NodeIntMap;
private:
context::Context * d_c;
Node d_one;
@@ -67,11 +67,13 @@ private:
BoolMap d_elim_vars;
std::map< Node, EqcInfo * > d_eqci;
NodeMap d_rep_to_eqc;
- NodeListMap d_rep_exp;
+ NodeIntMap d_rep_exp;
+ std::map< Node, std::vector< Node > > d_rep_exp_data;
/** set eqc rep */
void setEqcRep( Node t, Node r, std::vector< Node >& exp_to_add, EqcInfo * eqci );
/** use list */
- NodeListMap d_uselist;
+ NodeIntMap d_uselist;
+ std::map< Node, std::vector< Node > > d_uselist_data;
void addToUseList( Node used, Node eqc );
/** pending merges */
NodeList d_pending_merges;
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index a833f48d2..670f0eff3 100644..100755
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -406,8 +406,8 @@ Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri
//check the type of n
if( n.getKind()==INST_CONSTANT ){
int v = n.getAttribute(InstVarNumAttribute());
- depIndex = ri->d_var_order[ v ];
- val = ri->getTerm( v );
+ depIndex = ri->getIndexOrder( v );
+ val = ri->getCurrentTerm( v );
}else if( n.getKind()==ITE ){
int depIndex1, depIndex2;
int eval = evaluate( n[0], depIndex1, ri );
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index cbe83cfa5..cbe83cfa5 100644..100755
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index 33c853328..a0665cb7f 100644..100755
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -405,7 +405,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
bool needsDefault = true;
for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
Node n = fm->d_uf_terms[op][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
add_conds.push_back( n );
add_values.push_back( n );
Node r = fm->getUsedRepresentative(n);
@@ -764,7 +764,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
//set the domains based on the entry
for (unsigned i=0; i<c.getNumChildren(); i++) {
- if (riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS) {
+ if( riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS || riter.d_enum_type[i]==RepSetIterator::ENUM_SET_MEMBERS ){
TypeNode tn = c[i].getType();
if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
if( fm->isInterval(c[i]) || fm->isStar(c[i]) ){
@@ -773,6 +773,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
if (d_rep_ids[tn].find(c[i])!=d_rep_ids[tn].end()) {
riter.d_domain[i].clear();
riter.d_domain[i].push_back(d_rep_ids[tn][c[i]]);
+ riter.d_enum_type[i] = RepSetIterator::ENUM_DOMAIN_ELEMENTS;
}else{
Trace("fmc-exh") << "---- Does not have rep : " << c[i] << " for type " << tn << std::endl;
return false;
@@ -792,7 +793,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
std::vector< Node > ev_inst;
std::vector< Node > inst;
for( int i=0; i<riter.getNumTerms(); i++ ){
- Node rr = riter.getTerm( i );
+ Node rr = riter.getCurrentTerm( i );
Node r = rr;
//if( r.getType().isSort() ){
r = fm->getUsedRepresentative( r );
@@ -826,18 +827,18 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
int index = riter.increment();
Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
if( !riter.isFinished() ){
- if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
+ if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_INT_RANGE) {
Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
riter.increment2( index-1 );
}
}
}
d_addedLemmas += addedLemmas;
- Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.d_incomplete << std::endl;
- return addedLemmas>0 || !riter.d_incomplete;
+ Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
+ return addedLemmas>0 || !riter.isIncomplete();
}else{
Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl;
- return false;
+ return !riter.isIncomplete();
}
}
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
index 411b7a5eb..411b7a5eb 100644..100755
--- a/src/theory/quantifiers/full_model_check.h
+++ b/src/theory/quantifiers/full_model_check.h
diff --git a/src/theory/quantifiers/fun_def_engine.cpp b/src/theory/quantifiers/fun_def_engine.cpp
index cf1d14663..cf1d14663 100644..100755
--- a/src/theory/quantifiers/fun_def_engine.cpp
+++ b/src/theory/quantifiers/fun_def_engine.cpp
diff --git a/src/theory/quantifiers/fun_def_engine.h b/src/theory/quantifiers/fun_def_engine.h
index 3b95281c0..3b95281c0 100644..100755
--- a/src/theory/quantifiers/fun_def_engine.h
+++ b/src/theory/quantifiers/fun_def_engine.h
diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp
index 9109aab8a..9109aab8a 100644..100755
--- a/src/theory/quantifiers/fun_def_process.cpp
+++ b/src/theory/quantifiers/fun_def_process.cpp
diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h
index 1f6ee6562..1f6ee6562 100644..100755
--- a/src/theory/quantifiers/fun_def_process.h
+++ b/src/theory/quantifiers/fun_def_process.h
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index 8818175db..8818175db 100644..100755
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index ad287c1a3..ad287c1a3 100644..100755
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index bf05de3bb..2d3bf76f6 100644..100755
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -32,6 +32,7 @@ namespace theory {
namespace inst {
InstMatchGenerator::InstMatchGenerator( Node pat ){
+ d_cg = NULL;
d_needsReset = true;
d_active_add = false;
Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
@@ -43,12 +44,20 @@ InstMatchGenerator::InstMatchGenerator( Node pat ){
}
InstMatchGenerator::InstMatchGenerator() {
+ d_cg = NULL;
d_needsReset = true;
d_active_add = false;
d_next = NULL;
d_matchPolicy = MATCH_GEN_DEFAULT;
}
+InstMatchGenerator::~InstMatchGenerator() throw() {
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ delete d_children[i];
+ }
+ delete d_cg;
+}
+
void InstMatchGenerator::setActiveAdd(bool val){
d_active_add = val;
if( d_next!=NULL ){
@@ -150,7 +159,7 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector<
d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
}
}else{
- d_cg = new CandidateGeneratorQueue;
+ d_cg = new CandidateGeneratorQueue( qe );
Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
@@ -249,7 +258,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
Trace("matching-debug2") << "Reset children..." << std::endl;
//now, fit children into match
//we will be requesting candidates for matching terms for each child
- for( int i=0; i<(int)d_children.size(); i++ ){
+ for( unsigned i=0; i<d_children.size(); i++ ){
d_children[i]->reset( t[ d_children_index[i] ], qe );
}
Trace("matching-debug2") << "Continue next " << d_next << std::endl;
@@ -484,7 +493,7 @@ d_f( q ){
}
Debug("smart-multi-trigger") << std::endl;
}
- for( int i=0; i<(int)pats.size(); i++ ){
+ for( unsigned i=0; i<pats.size(); i++ ){
Node n = pats[i];
//make the match generator
d_children.push_back( InstMatchGenerator::mkInstMatchGenerator(q, n, qe ) );
@@ -492,7 +501,7 @@ d_f( q ){
std::vector< int > unique_vars;
std::map< int, bool > shared_vars;
int numSharedVars = 0;
- for( int j=0; j<(int)d_var_contains[n].size(); j++ ){
+ for( unsigned j=0; j<d_var_contains[n].size(); j++ ){
if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
unique_vars.push_back( d_var_contains[n][j] );
@@ -503,7 +512,7 @@ d_f( q ){
}
//we use the latest shared variables, then unique variables
std::vector< int > vars;
- int index = i==0 ? (int)(pats.size()-1) : (i-1);
+ unsigned index = i==0 ? pats.size()-1 : (i-1);
while( numSharedVars>0 && index!=i ){
for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
if( it->second ){
@@ -519,16 +528,24 @@ d_f( q ){
}
vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
Debug("smart-multi-trigger") << " Index[" << i << "]: ";
- for( int i=0; i<(int)vars.size(); i++ ){
- Debug("smart-multi-trigger") << vars[i] << " ";
+ for( unsigned j=0; j<vars.size(); j++ ){
+ Debug("smart-multi-trigger") << vars[j] << " ";
}
Debug("smart-multi-trigger") << std::endl;
//make ordered inst match trie
- InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder;
- imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() );
- d_children_trie.push_back( InstMatchTrieOrdered( imtio ) );
+ d_imtio[i] = new InstMatchTrie::ImtIndexOrder;
+ d_imtio[i]->d_order.insert( d_imtio[i]->d_order.begin(), vars.begin(), vars.end() );
+ d_children_trie.push_back( InstMatchTrieOrdered( d_imtio[i] ) );
}
+}
+InstMatchGeneratorMulti::~InstMatchGeneratorMulti() throw() {
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ delete d_children[i];
+ }
+ for( std::map< unsigned, InstMatchTrie::ImtIndexOrder* >::iterator it = d_imtio.begin(); it != d_imtio.end(); ++it ){
+ delete it->second;
+ }
}
/** reset instantiation round (call this whenever equivalence classes have changed) */
@@ -697,7 +714,7 @@ int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){
return addedLemmas;
}
-InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q ), d_match_pattern( pat ) {
+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];
d_pol = false;
@@ -720,10 +737,11 @@ InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q
}
d_match_pattern_arg_types.push_back( d_match_pattern[i].getType() );
}
+ d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
}
void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) {
- d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+
}
int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ){
@@ -751,6 +769,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, Q
tat = NULL;
}
}
+ Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl;
if( tat ){
InstMatch m( q );
m.add( baseMatch );
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index a1d907001..096774c51 100644..100755
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -91,7 +91,7 @@ public:
InstMatchGenerator( Node pat );
InstMatchGenerator();
/** destructor */
- ~InstMatchGenerator() throw() {}
+ virtual ~InstMatchGenerator() throw();
/** The pattern we are producing matches for.
If null, this is a multi trigger that is merging matches from d_children.
*/
@@ -125,7 +125,7 @@ public:
class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
public:
VarMatchGeneratorBooleanTerm( Node var, Node comp );
- ~VarMatchGeneratorBooleanTerm() throw() {}
+ virtual ~VarMatchGeneratorBooleanTerm() throw() {}
Node d_comp;
bool d_rm_prev;
/** reset instantiation round (call this at beginning of instantiation round) */
@@ -142,7 +142,7 @@ public:
class VarMatchGeneratorTermSubs : public InstMatchGenerator {
public:
VarMatchGeneratorTermSubs( Node var, Node subs );
- ~VarMatchGeneratorTermSubs() throw() {}
+ virtual ~VarMatchGeneratorTermSubs() throw() {}
TNode d_var;
TypeNode d_var_type;
Node d_subs;
@@ -183,6 +183,8 @@ private:
int d_matchPolicy;
/** children generators */
std::vector< InstMatchGenerator* > d_children;
+ /** order */
+ std::map< unsigned, InstMatchTrie::ImtIndexOrder* > d_imtio;
/** inst match tries for each child */
std::vector< InstMatchTrieOrdered > d_children_trie;
/** calculate matches */
@@ -191,7 +193,7 @@ public:
/** constructors */
InstMatchGeneratorMulti( Node q, std::vector< Node >& pats, QuantifiersEngine* qe );
/** destructor */
- ~InstMatchGeneratorMulti() throw() {}
+ virtual ~InstMatchGeneratorMulti() throw();
/** reset instantiation round (call this whenever equivalence classes have changed) */
void resetInstantiationRound( QuantifiersEngine* qe );
/** reset, eqc is the equivalence class to search in (any if eqc=null) */
@@ -224,7 +226,7 @@ private:
void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat );
public:
/** constructors */
- InstMatchGeneratorSimple( Node q, Node pat );
+ InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe );
/** destructor */
~InstMatchGeneratorSimple() throw() {}
/** reset instantiation round (call this whenever equivalence classes have changed) */
diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp
index d4be58636..41c9c40c8 100644..100755
--- a/src/theory/quantifiers/inst_propagator.cpp
+++ b/src/theory/quantifiers/inst_propagator.cpp
@@ -34,6 +34,7 @@ bool EqualityQueryInstProp::reset( Theory::Effort e ) {
d_uf.clear();
d_uf_exp.clear();
d_diseq_list.clear();
+ d_uf_func_map_trie.clear();
return true;
}
@@ -103,8 +104,7 @@ TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& arg
if( !t.isNull() ){
return t;
}else{
- //TODO?
- return TNode::null();
+ return d_uf_func_map_trie[f].existsTerm( args );
}
}
@@ -118,6 +118,7 @@ Node EqualityQueryInstProp::getRepresentativeExp( Node a, std::vector< Node >& e
Node ar = getUfRepresentative( a, exp );
if( !ar.isNull() ){
if( engine_has_a || getEngine()->hasTerm( ar ) ){
+ Trace("qip-eq") << "getRepresentativeExp " << a << " returns " << ar << std::endl;
Assert( getEngine()->hasTerm( ar ) );
Assert( getEngine()->getRepresentative( ar )==ar );
return ar;
@@ -168,6 +169,21 @@ bool EqualityQueryInstProp::areDisequalExp( Node a, Node b, std::vector< Node >&
}
}
+TNode EqualityQueryInstProp::getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp ) {
+ TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args );
+ if( !t.isNull() ){
+ return t;
+ }else{
+ TNode tt = d_uf_func_map_trie[f].existsTerm( args );
+ if( !tt.isNull() ){
+ //TODO?
+ return tt;
+ }else{
+ return tt;
+ }
+ }
+}
+
Node EqualityQueryInstProp::getUfRepresentative( Node a, std::vector< Node >& exp ) {
Assert( exp.empty() );
std::map< Node, Node >::iterator it = d_uf.find( a );
@@ -252,7 +268,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
}
-
+
if( swap ){
//swap
Node temp_r = ar;
@@ -262,7 +278,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
Assert( !getEngine()->hasTerm( ar ) || getEngine()->hasTerm( br ) );
Assert( ar!=br );
-
+
std::vector< Node > exp_d;
if( areDisequalExp( ar, br, exp_d ) ){
if( pol ){
@@ -279,18 +295,20 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
Assert( d_uf_exp[ar].empty() );
Assert( d_uf_exp[br].empty() );
+ //registerUfTerm( ar );
d_uf[ar] = br;
merge_exp( d_uf_exp[ar], exp_a );
merge_exp( d_uf_exp[ar], exp_b );
merge_exp( d_uf_exp[ar], reason );
+ //registerUfTerm( br );
d_uf[br] = br;
d_uf_exp[br].clear();
Trace("qip-eq") << "EqualityQueryInstProp::setEqual : merge " << ar << " -> " << br << ", exp size = " << d_uf_exp[ar].size() << ", status = " << status << std::endl;
a = ar;
b = br;
-
+
//carry disequality list
std::map< Node, std::map< Node, std::vector< Node > > >::iterator itd = d_diseq_list.find( ar );
if( itd!=d_diseq_list.end() ){
@@ -302,13 +320,13 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
}
-
+
return status;
}else{
Trace("qip-eq") << "EqualityQueryInstProp::setEqual : disequal " << ar << " <> " << br << std::endl;
Assert( d_diseq_list[ar].find( br )==d_diseq_list[ar].end() );
Assert( d_diseq_list[br].find( ar )==d_diseq_list[br].end() );
-
+
merge_exp( d_diseq_list[ar][br], reason );
merge_exp( d_diseq_list[br][ar], reason );
return STATUS_NONE;
@@ -316,187 +334,234 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
-void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) {
- if( is_prop ){
- if( isLiteral( n ) ){
- props.push_back( pol ? n : n.negate() );
- return;
+void EqualityQueryInstProp::registerUfTerm( TNode n ) {
+ if( d_uf.find( n )==d_uf.end() ){
+ if( !getEngine()->hasTerm( n ) ){
+ TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !getEngine()->hasTerm( n[i] ) ){
+ return;
+ }else{
+ args.push_back( n[i] );
+ }
+ }
+ d_uf_func_map_trie[f].addTerm( n, args );
+ }
}
}
+}
+
+//void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) {
+void EqualityQueryInstProp::addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch ) {
+ if( is_watch ){
+ watch.push_back( n );
+ }
args.push_back( n );
}
-bool EqualityQueryInstProp::isLiteral( Node n ) {
- Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind();
- Assert( ak!=NOT );
- return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE;
+bool EqualityQueryInstProp::isPropagateLiteral( Node n ) {
+ if( n==d_true || n==d_false ){
+ return false;
+ }else{
+ Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind();
+ Assert( ak!=NOT );
+ return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE;
+ }
+}
+
+void EqualityQueryInstProp::setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out ) {
+ if( watch.empty() ){
+ watch.push_back( n );
+ }
+ for( unsigned j=0; j<watch.size(); j++ ){
+ Trace("qip-eval") << "Watch : " << n << " -> " << watch[j] << std::endl;
+ watch_list_out[n].push_back( watch[j] );
+ }
+}
+
+void EqualityQueryInstProp::collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list ) {
+ std::map< Node, std::vector< Node > >::iterator it = watch_list_out.find( n );
+ if( it!=watch_list_out.end() && std::find( watch_list.begin(), watch_list.end(), n )==watch_list.end() ){
+ watch_list.push_back( n );
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ collectWatchList( it->second[j], watch_list_out, watch_list );
+ }
+ }
}
-//this is identical to TermDb::evaluateTerm2, but tracks more information
-Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol,
- std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) {
- std::map< Node, Node >::iterator itv = visited.find( n );
- if( itv != visited.end() ){
+//this is similar to TermDb::evaluateTerm2, but tracks more information
+Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited,
+ bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props ) {
+ int polIndex = hasPol ? ( pol ? 1 : -1 ) : 0;
+ std::map< Node, Node >::iterator itv = visited[polIndex].find( n );
+ if( itv!=visited[polIndex].end() ){
return itv->second;
}else{
- visited[n] = n;
- Trace("qip-eval") << "evaluate term : " << n << std::endl;
- std::vector< Node > exp_n;
- Node ret = getRepresentativeExp( n, exp_n );
- if( ret.isNull() ){
- //term is not known to be equal to a representative in equality engine, evaluate it
- Kind k = n.getKind();
- if( k==FORALL ){
- ret = Node::null();
- }else{
- std::map< Node, bool > watch_list_out_curr;
- TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
- std::vector< Node > args;
- bool ret_set = false;
- bool childChanged = false;
- int abort_i = -1;
- //get the child entailed polarity
- Assert( n.getKind()!=IMPLIES );
- bool newHasPol, newPol;
- QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );
- //for each child
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props );
- if( c.isNull() ){
- ret = Node::null();
- ret_set = true;
- break;
- }else if( c==d_true || c==d_false ){
- //short-circuiting
- if( k==kind::AND || k==kind::OR ){
- if( (k==kind::AND)==(c==d_false) ){
- ret = c;
- ret_set = true;
- break;
- }else{
- //redundant
- c = Node::null();
- childChanged = true;
- }
- }else if( k==kind::ITE && i==0 ){
- Assert( watch_list_out_curr.empty() );
- ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props );
- ret_set = true;
- break;
- }else if( k==kind::NOT ){
- ret = c==d_true ? d_false : d_true;
+ visited[polIndex][n] = n;
+ Node ret;
+ //check if it should be propagated in this context
+ if( hasPol && isPropagateLiteral( n ) ){
+ Assert( n.getType().isBoolean() );
+ //must be Boolean
+ ret = evaluateTermExp( n, exp, visited, false, pol, watch_list_out, props );
+ if( isPropagateLiteral( ret ) ){
+ Trace("qip-eval") << "-----> propagate : " << ret << std::endl;
+ props.push_back( pol ? ret : ret.negate() );
+ ret = pol ? d_true : d_false;
+ }
+ }else{
+ Trace("qip-eval") << "evaluate term : " << n << " [" << polIndex << "]" << std::endl;
+ std::vector< Node > exp_n;
+ ret = getRepresentativeExp( n, exp_n );
+ if( ret.isNull() ){
+ //term is not known to be equal to a representative in equality engine, evaluate it
+ Kind k = n.getKind();
+ if( k!=FORALL ){
+ TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
+ std::vector< Node > args;
+ bool ret_set = false;
+ bool childChanged = false;
+ int abort_i = -1;
+ //get the child entailed polarity
+ Assert( n.getKind()!=IMPLIES );
+ bool newHasPol, newPol;
+ QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );
+ std::vector< Node > watch;
+ //for each child
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out, props );
+ if( c.isNull() ){
+ ret = Node::null();
ret_set = true;
break;
- }
- }
- if( !c.isNull() ){
- childChanged = childChanged || n[i]!=c;
- if( !f.isNull() && !watch_list_out_curr.empty() ){
- // we are done if this is an UF application and an argument is unevaluated
- args.push_back( c );
- abort_i = i;
- break;
- }else if( ( k==kind::AND || k==kind::OR ) ){
- if( c.getKind()==k ){
- //flatten
- for( unsigned j=0; j<c.getNumChildren(); j++ ){
- addArgument( args, props, c[j], newHasPol, newPol );
+ }else if( c==d_true || c==d_false ){
+ //short-circuiting
+ if( k==kind::AND || k==kind::OR ){
+ if( (k==kind::AND)==(c==d_false) ){
+ ret = c;
+ ret_set = true;
+ break;
+ }else{
+ //redundant
+ c = Node::null();
+ childChanged = true;
}
- }else{
- addArgument( args, props, c, newHasPol, newPol );
+ }else if( k==kind::ITE && i==0 ){
+ ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out, props );
+ ret_set = true;
+ break;
+ }else if( k==kind::NOT ){
+ ret = c==d_true ? d_false : d_true;
+ ret_set = true;
+ break;
}
- //if we are in a branching position
- if( hasPol && !newHasPol && args.size()>=2 ){
- //we are done if at least two args are unevaluated
+ }
+ if( !c.isNull() ){
+ childChanged = childChanged || n[i]!=c;
+ bool is_watch = watch_list_out.find( c )!=watch_list_out.end();
+ if( !f.isNull() && is_watch ){
+ // we are done if this is an UF application and an argument is unevaluated
+ addArgument( c, args, watch, is_watch );
abort_i = i;
break;
+ }else if( k==kind::AND || k==kind::OR || k==kind::ITE || k==IFF ){
+ Trace("qip-eval-debug") << "Adding argument " << c << " to " << k << ", isProp = " << newHasPol << std::endl;
+ if( ( k==kind::AND || k==kind::OR ) && c.getKind()==k ){
+ //flatten
+ for( unsigned j=0; j<c.getNumChildren(); j++ ){
+ addArgument( c[j], args, watch, is_watch );
+ }
+ }else{
+ addArgument( c, args, watch, is_watch );
+ }
+ Trace("qip-eval-debug") << "props/args = " << props.size() << "/" << args.size() << std::endl;
+ //if we are in a branching position
+ if( hasPol && !newHasPol && args.size()>=2 ){
+ //we are done if at least two args are unevaluated
+ abort_i = i;
+ break;
+ }
+ }else{
+ addArgument( c, args, watch, is_watch );
}
- }else if( k==kind::ITE ){
- //we are done if we are ITE and condition is unevaluated
- Assert( i==0 );
- args.push_back( c );
- abort_i = i;
- break;
- }else{
- args.push_back( c );
}
}
- }
- //add remaining children if we aborted
- if( abort_i!=-1 ){
- for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){
- args.push_back( n[i] );
- }
- }
- //copy over the watch list
- for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){
- watch_list_out[itc->first] = itc->second;
- }
-
- //if we have not short-circuited evaluation
- if( !ret_set ){
- //if it is an indexed term, return the congruent term
- if( !f.isNull() && watch_list_out.empty() ){
- std::vector< TNode > t_args;
- for( unsigned i=0; i<args.size(); i++ ) {
- t_args.push_back( args[i] );
- }
- Assert( args.size()==n.getNumChildren() );
- //args contains terms known by the equality engine
- TNode nn = getCongruentTerm( f, t_args );
- Trace("qip-eval") << " got congruent term " << nn << " from DB for " << n << std::endl;
- if( !nn.isNull() ){
- //successfully constructed representative in EE
- Assert( exp_n.empty() );
- ret = getRepresentativeExp( nn, exp_n );
- Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl;
- merge_exp( exp, exp_n );
- ret_set = true;
- Assert( !ret.isNull() );
+ //add remaining children if we aborted
+ if( abort_i!=-1 ){
+ Trace("qip-eval-debug") << "..." << n << " aborted at " << abort_i << std::endl;
+ for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){
+ args.push_back( n[i] );
}
}
+ //if we have not short-circuited evaluation
if( !ret_set ){
- if( childChanged ){
- Trace("qip-eval") << "return rewrite" << std::endl;
- if( ( k==kind::AND || k==kind::OR ) ){
- if( args.empty() ){
- ret = k==kind::AND ? d_true : d_false;
- ret_set = true;
- }else if( args.size()==1 ){
- ret = args[0];
- ret_set = true;
- }
+ //if it is an indexed term, return the congruent term
+ if( !f.isNull() && watch.empty() ){
+ std::vector< TNode > t_args;
+ for( unsigned i=0; i<args.size(); i++ ) {
+ Trace("qip-eval") << "arg " << i << " : " << args[i] << std::endl;
+ t_args.push_back( args[i] );
+ }
+ Assert( args.size()==n.getNumChildren() );
+ //args contains terms known by the equality engine
+ TNode nn = getCongruentTerm( f, t_args );
+ Trace("qip-eval") << " got congruent term " << nn << " for " << n << std::endl;
+ if( !nn.isNull() ){
+ //successfully constructed representative in EE
+ Assert( exp_n.empty() );
+ ret = getRepresentativeExp( nn, exp_n );
+ Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl;
+ merge_exp( exp, exp_n );
+ ret_set = true;
+ Assert( !ret.isNull() );
+ Assert( ret!=n );
+ // we have that n == ret, check if the union find should be updated TODO?
}else{
- Assert( args.size()==n.getNumChildren() );
+ watch.push_back( ret );
}
- if( !ret_set ){
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- args.insert( args.begin(), n.getOperator() );
+ }
+ if( !ret_set ){
+ if( childChanged || args.size()!=n.getNumChildren() ){
+ Trace("qip-eval") << "return rewrite" << std::endl;
+ if( k==kind::AND || k==kind::OR ){
+ if( args.empty() ){
+ ret = k==kind::AND ? d_true : d_false;
+ ret_set = true;
+ }else if( args.size()==1 ){
+ //need to re-evaluate (may be new propagations)
+ ret = evaluateTermExp( args[0], exp, visited, hasPol, pol, watch_list_out, props );
+ ret_set = true;
+ }
+ }else{
+ Assert( args.size()==n.getNumChildren() );
}
- ret = NodeManager::currentNM()->mkNode( k, args );
- ret = Rewriter::rewrite( ret );
- //re-evaluate
- Node ret_eval = getRepresentativeExp( ret, exp_n );
- if( !ret_eval.isNull() ){
- ret = ret_eval;
- watch_list_out.clear();
- }else{
- watch_list_out[ret] = true;
+ if( !ret_set ){
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ args.insert( args.begin(), n.getOperator() );
+ }
+ ret = NodeManager::currentNM()->mkNode( k, args );
+ setWatchList( ret, watch, watch_list_out );
+ ret = Rewriter::rewrite( ret );
+ //need to re-evaluate
+ ret = evaluateTermExp( ret, exp, visited, hasPol, pol, watch_list_out, props );
}
+ }else{
+ ret = n;
+ setWatchList( ret, watch, watch_list_out );
}
- }else{
- ret = n;
- watch_list_out[ret] = true;
}
}
}
+ }else{
+ Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;
+ merge_exp( exp, exp_n );
}
- }else{
- Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;
- merge_exp( exp, exp_n );
}
- Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl;
- visited[n] = ret;
+
+ Trace("qip-eval") << "evaluated term : " << n << " [" << polIndex << "], got : " << ret << ", exp size = " << exp.size() << ", watch list size = " << watch_list_out.size() << std::endl;
+ visited[polIndex][n] = ret;
return ret;
}
}
@@ -545,6 +610,7 @@ bool InstPropagator::reset( Theory::Effort e ) {
d_watch_list.clear();
d_update_list.clear();
d_relevant_inst.clear();
+ d_has_relevant_inst = false;
return d_qy.reset( e );
}
@@ -556,10 +622,7 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st
Trace("qip-prop") << " " << terms[i] << std::endl;
}
}
- unsigned id = d_icount;
- d_icount++;
- Trace("qip-prop") << "...assign id=" << id << std::endl;
- d_ii[id].init( q, lem, terms, body );
+ unsigned id = allocateInstantiation( q, lem, terms, body );
//initialize the information
if( cacheConclusion( id, body ) ){
Assert( d_update_list.empty() );
@@ -582,35 +645,67 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st
return !d_conflict;
}else{
Assert( false );
- return true;
+ return false;
+ }
+}
+
+void InstPropagator::filterInstantiations() {
+ if( d_has_relevant_inst ){
+ //now, inform quantifiers engine which instances should be retracted
+ Trace("qip-prop-debug") << "...remove instantiation ids : ";
+ for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){
+ if( !it->second.d_q.isNull() ){
+ if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){
+ if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){
+ Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl;
+ Assert( false );
+ }else{
+ Trace("qip-prop-debug") << it->first << " ";
+ }
+ }else{
+ //mark the quantified formula as relevant
+ d_qe->markRelevant( it->second.d_q );
+ }
+ }
+ }
+ Trace("qip-prop-debug") << std::endl;
+ Trace("quant-engine-conflict") << "-----> InstPropagator::" << ( d_conflict ? "conflict" : "propagate" ) << " with " << d_relevant_inst.size() << " instances." << std::endl;
}
}
+unsigned InstPropagator::allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body ) {
+ unsigned id = d_icount;
+ d_icount++;
+ Trace("qip-prop") << "...assign id=" << id << std::endl;
+ d_ii[id].init( q, lem, terms, body );
+ return id;
+}
+
bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
Assert( !d_conflict );
Assert( ii.d_active );
Trace("qip-prop-debug") << "Update info [" << id << "]..." << std::endl;
//update the evaluation of the current lemma
- std::map< Node, Node > visited;
- std::map< Node, bool > watch_list;
+ std::map< Node, std::vector< Node > > watch_list_out;
+ std::map< int, std::map< Node, Node > > visited;
+ std::vector< Node > exp;
std::vector< Node > props;
- Node eval = d_qy.evaluateTermExp( ii.d_curr, ii.d_curr_exp, visited, true, true, watch_list, props );
+ Node eval = d_qy.evaluateTermExp( ii.d_curr, exp, visited, true, true, watch_list_out, props );
+ EqualityQueryInstProp::merge_exp( ii.d_curr_exp, exp );
if( eval.isNull() ){
ii.d_active = false;
}else if( firstTime || eval!=ii.d_curr ){
- if( EqualityQueryInstProp::isLiteral( eval ) ){
- props.push_back( eval );
- eval = d_qy.d_true;
- watch_list.clear();
- }
+ std::vector< Node > watch_list;
+ d_qy.collectWatchList( eval, watch_list_out, watch_list );
if( Trace.isOn("qip-prop") ){
Trace("qip-prop") << "Update info [" << id << "]..." << std::endl;
- Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << ", exp = ";
+ Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << std::endl;
+ Trace("qip-prop") << "...explanation = ";
debugPrintExplanation( ii.d_curr_exp, "qip-prop" );
Trace("qip-prop") << std::endl;
Trace("qip-prop") << "...watch list: " << std::endl;
- for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw!=watch_list.end(); ++itw ){
- Trace("qip-prop") << " " << itw->first << std::endl;
+ for( unsigned i=0; i<watch_list.size(); i++ ){
+ Trace("qip-prop") << " " << watch_list[i] << std::endl;
}
Trace("qip-prop") << "...new propagations: " << std::endl;
for( unsigned i=0; i<props.size(); i++ ){
@@ -627,8 +722,13 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
}else{
for( unsigned i=0; i<props.size(); i++ ){
Trace("qip-prop-debug2") << "Process propagation " << props[i] << std::endl;
+ Assert( d_qy.isPropagateLiteral( props[i] ) );
//if we haven't propagated this literal yet
if( cacheConclusion( id, props[i], 1 ) ){
+ //watch list for propagated literal: may not yet be purely EE representatives
+ std::vector< Node > prop_watch_list;
+ d_qy.collectWatchList( props[i], watch_list_out, prop_watch_list );
+
Node lit = props[i].getKind()==NOT ? props[i][0] : props[i];
bool pol = props[i].getKind()!=NOT;
if( lit.getKind()==EQUAL ){
@@ -647,10 +747,10 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
ii.d_curr = eval;
//update the watch list
Trace("qip-prop-debug") << "...updating watch list for [" << id << "], curr is " << ii.d_curr << std::endl;
- //Here, we need to be notified of enough terms such that if we are not notified, then update( ii ) will return no propagations.
- // Similar to two-watched literals, but since we are in UF, we need to watch all terms on a complete path of two terms.
- for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw != watch_list.end(); ++itw ){
- d_watch_list[ itw->first ][ id ] = true;
+ //Here, we need to be notified of enough terms such that if we are not notified, then update( id, ii ) will return no propagations.
+ // Similar to two-watched literals, but since we are taking into account UF, we need to watch all terms on a complete path of two terms.
+ for( unsigned i=0; i<watch_list.size(); i++ ){
+ d_watch_list[ watch_list[i] ][ id ] = true;
}
}else{
Trace("qip-prop-debug") << "...conclusion " << eval << " is duplicate." << std::endl;
@@ -682,10 +782,12 @@ void InstPropagator::propagate( Node a, Node b, bool pol, std::vector< Node >& e
}
if( pol ){
if( status==EqualityQueryInstProp::STATUS_MERGED_KNOWN ){
+ Trace("qip-rlv-propagate") << "Relevant propagation : " << a << ( pol ? " == " : " != " ) << b << std::endl;
Assert( d_qy.getEngine()->hasTerm( a ) );
Assert( d_qy.getEngine()->hasTerm( b ) );
Trace("qip-prop-debug") << "...equality between known terms." << std::endl;
addRelevantInstances( exp, "qip-propagate" );
+ //d_has_relevant_inst = true;
}
Trace("qip-prop-debug") << "...merged representatives " << a << " and " << b << std::endl;
for( unsigned i=0; i<2; i++ ){
@@ -712,25 +814,7 @@ void InstPropagator::conflict( std::vector< Node >& exp ) {
d_conflict = true;
d_relevant_inst.clear();
addRelevantInstances( exp, "qip-propagate" );
-
- //now, inform quantifiers engine which instances should be retracted
- Trace("qip-prop-debug") << "...remove instantiation ids : ";
- for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){
- if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){
- if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){
- Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl;
- Assert( false );
- }else{
- Trace("qip-prop-debug") << it->first << " ";
- }
- }else{
- //mark the quantified formula as relevant
- d_qe->markRelevant( it->second.d_q );
- }
- }
- Trace("qip-prop-debug") << std::endl;
- //will interupt the quantifiers engine
- Trace("quant-engine-conflict") << "-----> InstPropagator::conflict with " << exp.size() << " instances." << std::endl;
+ d_has_relevant_inst = true;
}
bool InstPropagator::cacheConclusion( unsigned id, Node body, int prop_index ) {
diff --git a/src/theory/quantifiers/inst_propagator.h b/src/theory/quantifiers/inst_propagator.h
index 0c02c7f95..6201cf152 100644..100755
--- a/src/theory/quantifiers/inst_propagator.h
+++ b/src/theory/quantifiers/inst_propagator.h
@@ -64,9 +64,11 @@ public:
bool areEqualExp( Node a, Node b, std::vector< Node >& exp );
/** returns true is a and b are disequal in the current context */
bool areDisequalExp( Node a, Node b, std::vector< Node >& exp );
+ /** get congruent term */
+ TNode getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp );
private:
/** term index */
- std::map< Node, TermArgTrie > d_func_map_trie;
+ std::map< Node, TermArgTrie > d_uf_func_map_trie;
/** union find for terms beyond what is stored in equality engine */
std::map< Node, Node > d_uf;
std::map< Node, std::vector< Node > > d_uf_exp;
@@ -74,7 +76,9 @@ private:
/** disequality list, stores explanations */
std::map< Node, std::map< Node, std::vector< Node > > > d_diseq_list;
/** add arg */
- void addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol );
+ void addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch );
+ /** register term */
+ void registerUfTerm( TNode n );
public:
enum {
STATUS_CONFLICT,
@@ -89,10 +93,13 @@ public:
public:
//for explanations
static void merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size = -1 );
+ //for watch list
+ static void setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out );
+ static void collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list );
- Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol,
- std::map< Node, bool >& watch_list_out, std::vector< Node >& props );
- static bool isLiteral( Node n );
+ Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited,
+ bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props );
+ bool isPropagateLiteral( Node n );
};
class InstPropagator : public QuantifiersUtil {
@@ -104,13 +111,18 @@ private:
InstPropagator& d_ip;
public:
InstantiationNotifyInstPropagator(InstPropagator& ip): d_ip(ip) {}
- virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) {
- return d_ip.notifyInstantiation( quant_e, q, lem, terms, body );
+ virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) {
+ return d_ip.notifyInstantiation( quant_e, q, lem, terms, body );
}
+ virtual void filterInstantiations() { d_ip.filterInstantiations(); }
};
InstantiationNotifyInstPropagator d_notify;
/** notify instantiation method */
bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body );
+ /** remove instance ids */
+ void filterInstantiations();
+ /** allocate instantiation */
+ unsigned allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body );
/** equality query */
EqualityQueryInstProp d_qy;
class InstInfo {
@@ -137,13 +149,13 @@ private:
std::vector< unsigned > d_update_list;
/** relevant instances */
std::map< unsigned, bool > d_relevant_inst;
+ bool d_has_relevant_inst;
private:
bool update( unsigned id, InstInfo& i, bool firstTime = false );
void propagate( Node a, Node b, bool pol, std::vector< Node >& exp );
void conflict( std::vector< Node >& exp );
bool cacheConclusion( unsigned id, Node body, int prop_index = 0 );
void addRelevantInstances( std::vector< Node >& exp, const char * c );
-
void debugPrintExplanation( std::vector< Node >& exp, const char * c );
public:
InstPropagator( QuantifiersEngine* qe );
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index 149330c61..523d868b5 100644..100755
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -190,7 +190,7 @@ bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visit
bool InstStrategyCbqi::hasNonCbqiVariable( Node q ){
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
TypeNode tn = q[0][i].getType();
- if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() ){
+ if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() && !tn.isBitVector() ){
if( options::cbqiSplx() ){
return true;
}else{
@@ -242,7 +242,7 @@ Node InstStrategyCbqi::getNextDecisionRequest(){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q );
bool value;
if( !d_quantEngine->getValuation().hasSatValue( cel, value ) ){
- Trace("cbqi-debug2") << "CBQI: get next decision " << cel << std::endl;
+ Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl;
return cel;
}
}
@@ -692,8 +692,10 @@ CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
void InstStrategyCegqi::registerQuantifier( Node q ) {
if( options::cbqiPreRegInst() ){
- //just get the instantiator
- getInstantiator( q );
+ if( doCbqi( q ) ){
+ //just get the instantiator
+ getInstantiator( q );
+ }
}
}
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
index 8ed59778b..8ed59778b 100644..100755
--- a/src/theory/quantifiers/inst_strategy_cbqi.h
+++ b/src/theory/quantifiers/inst_strategy_cbqi.h
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 630880690..efd765c86 100644..100755
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -34,9 +34,10 @@ using namespace CVC4::theory::quantifiers;
struct sortQuantifiersForSymbol {
QuantifiersEngine* d_qe;
+ std::map< Node, Node > d_op_map;
bool operator() (Node i, Node j) {
- int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() );
- int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() );
+ int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[i] );
+ int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[j] );
if( nqfsi<nqfsj ){
return true;
}else if( nqfsi>nqfsj ){
@@ -83,9 +84,8 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl;
if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
- int matchOption = 0;
for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){
- Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL );
+ Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], true, Trigger::TR_RETURN_NULL );
if( t ){
d_user_gen[f].push_back( t );
}
@@ -134,11 +134,10 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){
if( usable ){
Trace("user-pat") << "Add user pattern: " << pat << " for " << q << std::endl;
//check match option
- int matchOption = 0;
if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
d_user_gen_wait[q].push_back( nodes );
}else{
- Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, matchOption, true, Trigger::TR_MAKE_NEW );
+ Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, true, Trigger::TR_MAKE_NEW );
if( t ){
d_user_gen[q].push_back( t );
}else{
@@ -279,8 +278,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
for( unsigned i=0; i<patTermsF.size(); i++ ){
Assert( tinfo.find( patTermsF[i] )!=tinfo.end() );
- Trace("auto-gen-trigger-debug") << " " << patTermsF[i];
- Trace("auto-gen-trigger-debug") << " info[" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
+ Trace("auto-gen-trigger-debug") << " " << patTermsF[i] << std::endl;
+ Trace("auto-gen-trigger-debug2") << " info = [" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
}
Trace("auto-gen-trigger-debug") << std::endl;
}
@@ -306,10 +305,28 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
last_weight = curr_w;
}
}
+ d_num_trigger_vars[f] = vcMap.size();
+ if( d_num_trigger_vars[f]>0 && d_num_trigger_vars[f]<f[0].getNumChildren() ){
+ Trace("auto-gen-trigger-partial") << "Quantified formula : " << f << std::endl;
+ Trace("auto-gen-trigger-partial") << "...does not contain all variables in triggers!!!" << std::endl;
+ if( options::partialTriggers() ){
+ std::vector< Node > vcs[2];
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
+ vcs[ vcMap.find( ic )==vcMap.end() ? 0 : 1 ].push_back( f[0][i] );
+ }
+ for( unsigned i=0; i<2; i++ ){
+ d_vc_partition[i][f] = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, vcs[i] );
+ }
+ }else{
+ return;
+ }
+ }
for( unsigned i=0; i<patTermsF.size(); i++ ){
Node pat = patTermsF[i];
if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){
Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl;
+ Node mpat = pat;
//process the pattern: if it has a required polarity, consider it
Assert( tinfo.find( pat )!=tinfo.end() );
int rpol = tinfo[pat].d_reqPol;
@@ -317,19 +334,30 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
unsigned num_fv = tinfo[pat].d_fv.size();
Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl;
if( rpol!=0 ){
+ Assert( rpol==1 || rpol==-1 );
if( Trigger::isRelationalTrigger( pat ) ){
pat = rpol==-1 ? pat.negate() : pat;
}else{
Assert( Trigger::isAtomicTrigger( pat ) );
if( pat.getType().isBoolean() && rpoleq.isNull() ){
- pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
+ if( options::literalMatchMode()==LITERAL_MATCH_USE ){
+ pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
+ }else if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+ pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==1 ) );
+ }
}else{
Assert( !rpoleq.isNull() );
if( rpol==-1 ){
- //all equivalence classes except rpoleq
- pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
+ if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+ //all equivalence classes except rpoleq
+ pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
+ }
}else if( rpol==1 ){
- //all equivalence classes that are not disequal to rpoleq TODO
+ if( options::literalMatchMode()==LITERAL_MATCH_AGG ){
+ //only equivalence class rpoleq
+ pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq );
+ }
+ //all equivalence classes that are not disequal to rpoleq TODO?
}
}
}
@@ -337,10 +365,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}else{
if( Trigger::isRelationalTrigger( pat ) ){
//consider both polarities
- addPatternToPool( f, pat.negate(), num_fv );
+ addPatternToPool( f, pat.negate(), num_fv, mpat );
}
}
- addPatternToPool( f, pat, num_fv );
+ addPatternToPool( f, pat, num_fv, mpat );
}
}
//tinfo not used below this point
@@ -372,19 +400,23 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
if( options::relevantTriggers() ){
sortQuantifiersForSymbol sqfs;
sqfs.d_qe = d_quantEngine;
+ for( unsigned i=0; i<patTerms.size(); i++ ){
+ Assert( d_pat_to_mpat.find( patTerms[i] )!=d_pat_to_mpat.end() );
+ Assert( d_pat_to_mpat[patTerms[i]].hasOperator() );
+ sqfs.d_op_map[ patTerms[i] ] = d_pat_to_mpat[patTerms[i]].getOperator();
+ }
//sort based on # occurrences (this will cause Trigger to select rarer symbols)
std::sort( patTerms.begin(), patTerms.end(), sqfs );
Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
for( unsigned i=0; i<patTerms.size(); i++ ){
- Debug("relevant-trigger") << " " << patTerms[i] << " (";
- Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
+ Debug("relevant-trigger") << " " << patTerms[i] << " from " << d_pat_to_mpat[patTerms[i]] << " (";
+ Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_pat_to_mpat[patTerms[i]].getOperator() ) << ")" << std::endl;
}
}
//now, generate the trigger...
- int matchOption = 0;
Trigger* tr = NULL;
if( d_is_single_trigger[ patTerms[0] ] ){
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL );
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
d_single_trigger_gen[ patTerms[0] ] = true;
}else{
//only generate multi trigger if option set, or if no single triggers exist
@@ -402,29 +434,14 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
d_made_multi_trigger[f] = true;
}
//will possibly want to get an old trigger
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD );
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, false, Trigger::TR_GET_OLD, d_num_trigger_vars[f] );
}
if( tr ){
- unsigned tindex;
- if( tr->isMultiTrigger() ){
- //disable all other multi triggers
- for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][f].begin(); it != d_auto_gen_trigger[1][f].end(); ++it ){
- d_auto_gen_trigger[1][f][ it->first ] = false;
- }
- tindex = 1;
- }else{
- tindex = 0;
- }
- //making it during an instantiation round, so must reset
- if( d_auto_gen_trigger[tindex][f].find( tr )==d_auto_gen_trigger[tindex][f].end() ){
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- }
- d_auto_gen_trigger[tindex][f][tr] = true;
+ addTrigger( tr, f );
//if we are generating additional triggers...
- if( tindex==0 ){
- int index = 0;
- if( index<(int)patTerms.size() ){
+ if( !tr->isMultiTrigger() ){
+ unsigned index = 0;
+ if( index<patTerms.size() ){
//Notice() << "check add additional" << std::endl;
//check if similar patterns exist, and if so, add them additionally
int nqfs_curr = 0;
@@ -433,18 +450,13 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}
index++;
bool success = true;
- while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
+ while( success && index<patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
success = false;
if( !options::relevantTriggers() ||
d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
d_single_trigger_gen[ patTerms[index] ] = true;
- Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL );
- if( tr2 ){
- //Notice() << "Add additional trigger " << patTerms[index] << std::endl;
- tr2->resetInstantiationRound();
- tr2->reset( Node::null() );
- d_auto_gen_trigger[0][f][tr2] = true;
- }
+ Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
+ addTrigger( tr2, f );
success = true;
}
index++;
@@ -457,8 +469,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}
}
-void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv ) {
- if( num_fv==q[0].getNumChildren() && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
+void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
+ d_pat_to_mpat[pat] = mpat;
+ unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
+ if( num_fv==num_vars && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
d_patTerms[0][q].push_back( pat );
d_is_single_trigger[ pat ] = true;
}else{
@@ -467,6 +481,38 @@ void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned n
}
}
+
+void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
+ if( tr ){
+ if( d_num_trigger_vars[q]<q[0].getNumChildren() ){
+ //partial trigger : generate implication to mark user pattern
+ Node ipl = NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, d_quantEngine->getTermDatabase()->getVariableNode( tr->getInstPattern(), q ) );
+ Node qq = NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[1][q], NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[0][q], q[1] ), ipl );
+ Trace("auto-gen-trigger-partial") << "Make partially specified user pattern: " << std::endl;
+ Trace("auto-gen-trigger-partial") << " " << qq << std::endl;
+ Node lem = NodeManager::currentNM()->mkNode( OR, q.negate(), qq );
+ d_quantEngine->addLemma( lem );
+ }else{
+ unsigned tindex;
+ if( tr->isMultiTrigger() ){
+ //disable all other multi triggers
+ for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][q].begin(); it != d_auto_gen_trigger[1][q].end(); ++it ){
+ d_auto_gen_trigger[1][q][ it->first ] = false;
+ }
+ tindex = 1;
+ }else{
+ tindex = 0;
+ }
+ //making it during an instantiation round, so must reset
+ if( d_auto_gen_trigger[tindex][q].find( tr )==d_auto_gen_trigger[tindex][q].end() ){
+ tr->resetInstantiationRound();
+ tr->reset( Node::null() );
+ }
+ d_auto_gen_trigger[tindex][q][tr] = true;
+ }
+ }
+}
+
bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
if( q.getNumChildren()==3 ){
std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q );
@@ -519,8 +565,7 @@ bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) {
Trace("local-t-ext") << " " << patTerms[i] << std::endl;
}
Trace("local-t-ext") << std::endl;
- int matchOption = 0;
- Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, true, Trigger::TR_GET_OLD );
+ Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, true, Trigger::TR_GET_OLD );
d_lte_trigger[f] = tr;
}else{
Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl;
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h
index 028f24b27..e6d993294 100644..100755
--- a/src/theory/quantifiers/inst_strategy_e_matching.h
+++ b/src/theory/quantifiers/inst_strategy_e_matching.h
@@ -83,14 +83,18 @@ private:
std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
//instantiation no patterns
std::map< Node, std::vector< Node > > d_user_no_gen;
+ // number of trigger variables per quantifier
+ std::map< Node, unsigned > d_num_trigger_vars;
+ std::map< Node, Node > d_vc_partition[2];
+ std::map< Node, Node > d_pat_to_mpat;
private:
/** process functions */
void processResetInstantiationRound( Theory::Effort effort );
int process( Node q, Theory::Effort effort, int e );
/** generate triggers */
void generateTriggers( Node q );
- void addPatternToPool( Node q, Node pat, unsigned num_fv );
- //bool addTrigger( inst::Trigger * tr, Node f, unsigned r );
+ void addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat );
+ void addTrigger( inst::Trigger * tr, Node f );
/** has user patterns */
bool hasUserPatterns( Node q );
/** has user patterns */
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 955dc5d86..db597d031 100644..100755
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -137,11 +137,7 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){
doInstantiationRound( e );
if( d_quantEngine->inConflict() ){
Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting );
- Trace("inst-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound();
- if( lastWaiting>0 ){
- Trace("inst-engine") << " (prev " << lastWaiting << ")";
- }
- Trace("inst-engine") << std::endl;
+ Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
}else if( d_quantEngine->hasAddedLemma() ){
Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
}
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
index d2b3740a1..d2b3740a1 100644..100755
--- a/src/theory/quantifiers/instantiation_engine.h
+++ b/src/theory/quantifiers/instantiation_engine.h
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
index b03c4ad3b..b03c4ad3b 100644..100755
--- a/src/theory/quantifiers/kinds
+++ b/src/theory/quantifiers/kinds
diff --git a/src/theory/quantifiers/local_theory_ext.cpp b/src/theory/quantifiers/local_theory_ext.cpp
index ada28c084..ada28c084 100644..100755
--- a/src/theory/quantifiers/local_theory_ext.cpp
+++ b/src/theory/quantifiers/local_theory_ext.cpp
diff --git a/src/theory/quantifiers/local_theory_ext.h b/src/theory/quantifiers/local_theory_ext.h
index 94abf3c90..94abf3c90 100644..100755
--- a/src/theory/quantifiers/local_theory_ext.h
+++ b/src/theory/quantifiers/local_theory_ext.h
diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp
index 582599680..582599680 100644..100755
--- a/src/theory/quantifiers/macros.cpp
+++ b/src/theory/quantifiers/macros.cpp
diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h
index 39ec2f0a1..39ec2f0a1 100644..100755
--- a/src/theory/quantifiers/macros.h
+++ b/src/theory/quantifiers/macros.h
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 3ae36b1d4..10a5ae41b 100644..100755
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -66,7 +66,7 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){
tests++;
std::vector< Node > terms;
for( int k=0; k<riter.getNumTerms(); k++ ){
- terms.push_back( riter.getTerm( k ) );
+ terms.push_back( riter.getCurrentTerm( k ) );
}
Node n = d_qe->getInstantiation( f, vars, terms );
Node val = fm->getValue( n );
@@ -84,7 +84,9 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){
}
Trace("quant-check-model") << "." << std::endl;
}else{
- Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
+ if( riter.isIncomplete() ){
+ Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
+ }
}
}
}
@@ -114,7 +116,7 @@ bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
QModelBuilderIG::QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ) {
+QModelBuilder( c, qe ), d_basisNoMatch( c ) {
}
@@ -302,7 +304,7 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
Node n = fmig->d_uf_terms[op][i];
//for calculating if op is constant
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
Node v = fmig->getRepresentative( n );
if( i==0 ){
d_uf_prefs[op].d_const_val = v;
@@ -312,12 +314,11 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
}
}
//for calculating terms that we don't need to consider
- if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
- if( !n.getAttribute(BasisNoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
+ if( d_basisNoMatch.find( n )==d_basisNoMatch.end() ){
//need to consider if it is not congruent modulo model basis
if( !tabt.addTerm( fmig, n ) ){
- BasisNoMatchAttribute bnma;
- n.setAttribute(bnma,true);
+ d_basisNoMatch[n] = true;
}
}
}
@@ -382,8 +383,8 @@ bool QModelBuilderIG::isQuantifierActive( Node f ){
}
bool QModelBuilderIG::isTermActive( Node n ){
- return !n.getAttribute(NoMatchAttribute()) || //it is not congruent to another active term
- ( n.getAttribute(ModelBasisArgAttribute())!=0 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
+ return d_qe->getTermDatabase()->isTermActive( n ) || //it is not congruent to another active term
+ ( n.getAttribute(ModelBasisArgAttribute())!=0 && d_basisNoMatch.find( n )==d_basisNoMatch.end() ); //or it has model basis arguments
//and is not congruent modulo model basis
//to another active term
}
@@ -400,15 +401,19 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
d_triedLemmas++;
- for( int i=0; i<(int)riter.d_index.size(); i++ ){
- Trace("try") << i << " : " << riter.d_index[i] << " : " << riter.getTerm( i ) << std::endl;
+ if( Debug.isOn("inst-fmf-ei-debug") ){
+ for( int i=0; i<(int)riter.d_index.size(); i++ ){
+ Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl;
+ }
}
int eval = 0;
int depIndex;
//see if instantiation is already true in current model
- Debug("fmf-model-eval") << "Evaluating ";
- riter.debugPrintSmall("fmf-model-eval");
- Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ if( Debug.isOn("fmf-model-eval") ){
+ Debug("fmf-model-eval") << "Evaluating ";
+ riter.debugPrintSmall("fmf-model-eval");
+ Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ }
//if evaluate(...)==1, then the instantiation is already true in the model
// depIndex is the index of the least significant variable that this evaluation relies upon
depIndex = riter.getNumTerms()-1;
@@ -426,7 +431,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
//instantiation was not shown to be true, construct the match
InstMatch m( f );
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_qe, riter.d_index_order[i], riter.getTerm( i ) );
+ m.set( d_qe, i, riter.getCurrentTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
//add as instantiation
@@ -464,8 +469,8 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
Trace("model-engine-warn") << std::endl;
}
}
- //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
- d_incomplete_check = riter.d_incomplete;
+ //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;
}else{
return false;
@@ -667,7 +672,7 @@ int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
//if applicable, try to add exceptions here
if( !tr_terms.empty() ){
//make a trigger for these terms, add instantiations
- inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW );
+ inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW );
//Notice() << "Trigger = " << (*tr) << std::endl;
tr->resetInstantiationRound();
tr->reset( Node::null() );
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
index 906673903..e4f9529a8 100644..100755
--- a/src/theory/quantifiers/model_builder.h
+++ b/src/theory/quantifiers/model_builder.h
@@ -57,15 +57,6 @@ public:
-/** Attribute true for nodes that should not be used when considered for inst-gen basis */
-struct BasisNoMatchAttributeId {};
-/** use the special for boolean flag */
-typedef expr::Attribute< BasisNoMatchAttributeId,
- bool,
- expr::attr::NullCleanupStrategy,
- true // context dependent
- > BasisNoMatchAttribute;
-
class TermArgBasisTrie {
private:
bool addTerm2( FirstOrderModel* fm, Node n, int argIndex );
@@ -85,7 +76,9 @@ public:
*/
class QModelBuilderIG : public QModelBuilder
{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
protected:
+ BoolMap d_basisNoMatch;
//map from operators to model preference data
std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
//built model uf
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index 0bbca88eb..5d575969f 100644..100755
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -153,27 +153,23 @@ int ModelEngine::checkModel(){
//d_quantEngine->getEqualityQuery()->flattenRepresentatives( fm->d_rep_set.d_type_reps );
//for debugging
- if( Trace.isOn("model-engine") || Trace.isOn("model-engine-debug") ){
- for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
- it != fm->d_rep_set.d_type_reps.end(); ++it ){
- if( it->first.isSort() ){
- Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
- if( Trace.isOn("model-engine-debug") ){
- Trace("model-engine-debug") << " Reps : ";
- for( size_t i=0; i<it->second.size(); i++ ){
- Trace("model-engine-debug") << it->second[i] << " ";
- }
- Trace("model-engine-debug") << std::endl;
- Trace("model-engine-debug") << " Term reps : ";
- for( size_t i=0; i<it->second.size(); i++ ){
- Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
- Trace("model-engine-debug") << r << " ";
- }
- Trace("model-engine-debug") << std::endl;
- Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
- Trace("model-engine-debug") << " Basis term : " << mbt << std::endl;
- }
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
+ it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+ Trace("model-engine-debug") << " Reps : ";
+ for( size_t i=0; i<it->second.size(); i++ ){
+ Trace("model-engine-debug") << it->second[i] << " ";
}
+ Trace("model-engine-debug") << std::endl;
+ Trace("model-engine-debug") << " Term reps : ";
+ for( size_t i=0; i<it->second.size(); i++ ){
+ Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
+ Trace("model-engine-debug") << r << " ";
+ }
+ Trace("model-engine-debug") << std::endl;
+ Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
+ Trace("model-engine-debug") << " Basis term : " << mbt << std::endl;
}
}
@@ -221,11 +217,12 @@ int ModelEngine::checkModel(){
//print debug information
if( d_quantEngine->inConflict() ){
- Trace("model-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound() << std::endl;
+ Trace("model-engine") << "Conflict, added lemmas = ";
}else{
- Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
- Trace("model-engine") << d_totalLemmas << std::endl;
- }
+ Trace("model-engine") << "Added Lemmas = ";
+ }
+ Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / ";
+ Trace("model-engine") << d_totalLemmas << std::endl;
return d_addedLemmas;
}
@@ -281,15 +278,15 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
//create a rep set iterator and iterate over the (relevant) domain of the quantifier
RepSetIterator riter( d_quantEngine, &(d_quantEngine->getModel()->d_rep_set) );
if( riter.setQuantifier( f ) ){
- Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.d_incomplete << "..." << std::endl;
- if( !riter.d_incomplete ){
+ Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
+ if( !riter.isIncomplete() ){
int triedLemmas = 0;
int addedLemmas = 0;
while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
//instantiation was not shown to be true, construct the match
InstMatch m( f );
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_quantEngine, riter.d_index_order[i], riter.getTerm( i ) );
+ m.set( d_quantEngine, i, riter.getCurrentTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
@@ -309,11 +306,10 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
d_statistics.d_exh_inst_lemmas += addedLemmas;
}
}else{
- Trace("fmf-exh-inst") << "...exhaustive instantiation failed to set, incomplete=" << riter.d_incomplete << "..." << std::endl;
- Assert( riter.d_incomplete );
+ 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.d_incomplete;
+ d_incomplete_check = d_incomplete_check || riter.isIncomplete();
}
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 12f18aa08..12f18aa08 100644..100755
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index ca87a607d..bac2aa35c 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -49,6 +49,7 @@ QuantInfo::~QuantInfo() {
void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
d_q = q;
+ d_extra_var.clear();
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
d_match.push_back( TNode::null() );
d_match_term.push_back( TNode::null() );
@@ -77,33 +78,31 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
}
}
*/
- if( d_mg->isValid() ){
- for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- if( d_vars[j].getKind()!=BOUND_VARIABLE ){
- d_var_mg[j] = NULL;
- bool is_tsym = false;
- if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
- is_tsym = true;
- d_tsym_vars.push_back( j );
- }
- if( !is_tsym || options::qcfTConstraint() ){
- d_var_mg[j] = new MatchGen( this, d_vars[j], true );
- }
- if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
- Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
- d_mg->setInvalid();
- break;
- }else{
- std::vector< int > bvars;
- d_var_mg[j]->determineVariableOrder( this, bvars );
- }
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){
+ d_var_mg[j] = NULL;
+ bool is_tsym = false;
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
+ is_tsym = true;
+ d_tsym_vars.push_back( j );
+ }
+ if( !is_tsym || options::qcfTConstraint() ){
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );
+ }
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
+ d_mg->setInvalid();
+ break;
+ }else{
+ std::vector< int > bvars;
+ d_var_mg[j]->determineVariableOrder( this, bvars );
}
- }
- if( d_mg->isValid() ){
- std::vector< int > bvars;
- d_mg->determineVariableOrder( this, bvars );
}
}
+ if( d_mg->isValid() ){
+ std::vector< int > bvars;
+ d_mg->determineVariableOrder( this, bvars );
+ }
}else{
Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
}
@@ -113,14 +112,15 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
//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)
- //if( options::qcfSkipRd() ){
- // for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- // vars.push_back( d_vars[j] );
- // }
- //}
- //get all variables that are always relevant
- std::map< TNode, bool > visited;
- getPropagateVars( vars, q[1], false, visited );
+ if( options::qcfSkipRd() ){
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ vars.push_back( d_vars[j] );
+ }
+ }else{
+ //get all variables that are always relevant
+ std::map< TNode, bool > visited;
+ getPropagateVars( p, vars, q[1], false, visited );
+ }
for( unsigned j=0; j<vars.size(); j++ ){
Node v = vars[j];
TNode f = p->getTermDatabase()->getMatchOperator( v );
@@ -141,7 +141,7 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
}
}
-void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){
+void QuantInfo::getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){
std::map< TNode, bool >::iterator itv = visited.find( n );
if( itv==visited.end() ){
visited[n] = true;
@@ -150,6 +150,12 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol,
if( d_var_num.find( n )!=d_var_num.end() ){
Assert( std::find( vars.begin(), vars.end(), n )==vars.end() );
vars.push_back( n );
+ TNode f = p->getTermDatabase()->getMatchOperator( n );
+ if( !f.isNull() ){
+ if( std::find( p->d_func_rel_dom[f].begin(), p->d_func_rel_dom[f].end(), d_q )==p->d_func_rel_dom[f].end() ){
+ p->d_func_rel_dom[f].push_back( d_q );
+ }
+ }
}else if( MatchGen::isHandledBoolConnective( n ) ){
Assert( n.getKind()!=IMPLIES );
QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol );
@@ -157,12 +163,16 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol,
Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl;
if( rec ){
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- getPropagateVars( vars, n[i], pol, visited );
+ getPropagateVars( p, vars, n[i], pol, visited );
}
}
}
}
+bool QuantInfo::isBaseMatchComplete() {
+ return d_vars_set.size()==(d_q[0].getNumChildren()+d_extra_var.size());
+}
+
void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
if( n.getKind()==FORALL ){
@@ -209,7 +219,6 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
if( n.getKind()==BOUND_VARIABLE ){
d_inMatchConstraint[n] = true;
}
- //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
if( d_var_num.find( n )==d_var_num.end() ){
Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
d_var_num[n] = d_vars.size();
@@ -219,6 +228,8 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
d_match_term.push_back( TNode::null() );
if( n.getKind()==ITE ){
registerNode( n, false, false );
+ }else if( n.getKind()==BOUND_VARIABLE ){
+ d_extra_var.push_back( n );
}else{
for( unsigned i=0; i<n.getNumChildren(); i++ ){
flatten( n[i], beneathQuant );
@@ -233,13 +244,15 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
}
-void QuantInfo::reset_round( QuantConflictFind * p ) {
+bool QuantInfo::reset_round( QuantConflictFind * p ) {
for( unsigned i=0; i<d_match.size(); i++ ){
d_match[i] = TNode::null();
d_match_term[i] = TNode::null();
}
+ d_vars_set.clear();
d_curr_var_deq.clear();
d_tconstraints.clear();
+
//add built-in variable constraints
for( unsigned r=0; r<2; r++ ){
for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
@@ -257,7 +270,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) {
d_mg->d_children.clear();
d_mg->d_n = NodeManager::currentNM()->mkConst( true );
d_mg->d_type = MatchGen::typ_ground;
- return;
+ return false;
}
}
}
@@ -268,6 +281,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) {
}
//now, reset for matching
d_mg->reset( p, false, this );
+ return true;
}
int QuantInfo::getCurrentRepVar( int v ) {
@@ -377,11 +391,12 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo
}
}
}
- d_match[v] = TNode::null();
+ unsetMatch( p, v );
return 1;
}else{
//std::map< int, TNode >::iterator itm = d_match.find( v );
bool isGroundRep = false;
+ bool isGround = false;
if( vn!=-1 ){
Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
//std::map< int, TNode >::iterator itmn = d_match.find( vn );
@@ -428,13 +443,14 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo
Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
if( d_match[v].isNull() ){
//isGroundRep = true; ??
+ isGround = true;
}else{
//compare ground values
Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
}
}
- if( setMatch( p, v, n, isGroundRep ) ){
+ if( setMatch( p, v, n, isGroundRep, isGround ) ){
Debug("qcf-match-debug") << " -> success" << std::endl;
return 1;
}else{
@@ -500,7 +516,7 @@ bool QuantInfo::isConstrainedVar( int v ) {
}
}
-bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ) {
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ) {
if( getCurrentCanBeEqual( p, v, n ) ){
if( isGroundRep ){
//fail if n does not exist in the relevant domain of each of the argument positions
@@ -518,6 +534,12 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe
}
}
Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ if( isGround ){
+ if( d_vars[v].getKind()==BOUND_VARIABLE ){
+ d_vars_set[v] = true;
+ Debug("qcf-match-debug") << "---- now bound " << d_vars_set.size() << " / " << d_q[0].getNumChildren() << " base variables." << std::endl;
+ }
+ }
d_match[v] = n;
return true;
}else{
@@ -525,6 +547,14 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe
}
}
+void QuantInfo::unsetMatch( QuantConflictFind * p, int v ) {
+ Debug("qcf-match-debug") << "-- unbind : " << v << std::endl;
+ if( d_vars[v].getKind()==BOUND_VARIABLE && d_vars_set.find( v )!=d_vars_set.end() ){
+ d_vars_set.erase( v );
+ }
+ d_match[ v ] = TNode::null();
+}
+
bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
for( int i=0; i<getNumVars(); i++ ){
//std::map< int, TNode >::iterator it = d_match.find( i );
@@ -538,6 +568,42 @@ bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
}
bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
+ if( options::qcfEagerTest() ){
+ //check whether the instantiation evaluates as expected
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ Trace("qcf-instance-check") << "Possible conflict instance for " << d_q << " : " << std::endl;
+ std::map< TNode, TNode > subs;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ Trace("qcf-instance-check") << " " << terms[i] << std::endl;
+ subs[d_q[0][i]] = terms[i];
+ }
+ for( unsigned i=0; i<d_extra_var.size(); i++ ){
+ Node n = getCurrentExpValue( d_extra_var[i] );
+ Trace("qcf-instance-check") << " " << d_extra_var[i] << " -> " << n << std::endl;
+ subs[d_extra_var[i]] = n;
+ }
+ if( !p->getTermDatabase()->isEntailed( d_q[1], subs, false, false ) ){
+ Trace("qcf-instance-check") << "...not entailed to be false." << std::endl;
+ return true;
+ }
+ }else{
+ Node inst = p->d_quantEngine->getInstantiation( d_q, terms );
+ Node inst_eval = p->getTermDatabase()->evaluateTerm( inst, NULL, options::qcfTConstraint() );
+ if( Trace.isOn("qcf-instance-check") ){
+ Trace("qcf-instance-check") << "Possible propagating instance for " << d_q << " : " << std::endl;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ Trace("qcf-instance-check") << " " << terms[i] << std::endl;
+ }
+ Trace("qcf-instance-check") << "...evaluates to " << inst_eval << std::endl;
+ }
+ if( inst_eval.isNull() || inst_eval==p->getTermDatabase()->d_true || !isPropagatingInstance( p, inst_eval ) ){
+ Trace("qcf-instance-check") << "...spurious." << std::endl;
+ return true;
+ }else{
+ Trace("qcf-instance-check") << "...not spurious." << std::endl;
+ }
+ }
+ }
if( !d_tconstraints.empty() ){
//check constraints
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
@@ -552,6 +618,26 @@ bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node
return false;
}
+bool QuantInfo::isPropagatingInstance( QuantConflictFind * p, Node n ) {
+ if( n.getKind()==FORALL ){
+ //TODO?
+ return true;
+ }else if( n.getKind()==NOT || n.getKind()==AND || n.getKind()==OR || n.getKind()==EQUAL || n.getKind()==ITE || n.getKind()==IFF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isPropagatingInstance( p, n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ if( p->getEqualityEngine()->hasTerm( n ) || isGroundSubterm( n ) ){
+ return true;
+ }
+ }
+ Trace("qcf-instance-check-debug") << "...not propagating instance because of " << n << std::endl;
+ return false;
+}
+
bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
Node rew = Rewriter::rewrite( lit );
@@ -606,6 +692,9 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
doFail = true;
success = false;
}else{
+ if( isBaseMatchComplete() && options::qcfEagerTest() ){
+ return true;
+ }
//solve for interpreted symbol matches
// this breaks the invariant that all introduced constraints are over existing terms
for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
@@ -636,7 +725,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
if( !z.isNull() ){
Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
assigned.push_back( vn );
- if( !setMatch( p, vn, z, false ) ){
+ if( !setMatch( p, vn, z, false, true ) ){
success = false;
break;
}
@@ -678,7 +767,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
if( !sum.isNull() ){
assigned.push_back( slv_v );
Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
- if( !setMatch( p, slv_v, sum, false ) ){
+ if( !setMatch( p, slv_v, sum, false, true ) ){
success = false;
}
p->d_tempCache.push_back( sum );
@@ -764,7 +853,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
int currIndex = d_una_eqc_count[d_una_index];
d_una_eqc_count[d_una_index]++;
Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
- if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true ) ){
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true, true ) ){
d_match_term[d_unassigned[d_una_index]] = TNode::null();
Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
d_una_index++;
@@ -813,9 +902,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
}
return true;
}else{
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
+ revertMatch( p, assigned );
assigned.clear();
return false;
}
@@ -837,9 +924,9 @@ void QuantInfo::getMatch( std::vector< Node >& terms ){
}
}
-void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+void QuantInfo::revertMatch( QuantConflictFind * p, std::vector< int >& assigned ) {
for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
+ unsetMatch( p, assigned[i] );
}
}
@@ -899,26 +986,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
if( isVar ){
Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
if( n.getKind()==ITE ){
- /*
- d_type = typ_ite_var;
- d_type_not = false;
- d_n = n;
- d_children.push_back( MatchGen( qi, d_n[0] ) );
- if( d_children[0].isValid() ){
- d_type = typ_ite_var;
- for( unsigned i=1; i<=2; i++ ){
- Node nn = n.eqNode( n[i] );
- d_children.push_back( MatchGen( qi, nn ) );
- d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- }else{
-*/
- d_type = typ_invalid;
- //}
+ d_type = typ_invalid;
}else{
d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
d_qni_var_num[0] = qi->getVarNum( n );
@@ -961,26 +1029,6 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
break;
}
}
- /*
- else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
- Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
- //if variable equality/disequality at top level, remove immediately
- bool cIsNot = d_children[d_children.size()-1].d_type_not;
- Node cn = d_children[d_children.size()-1].d_n;
- Assert( cn.getKind()==EQUAL );
- Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
- //make it a built-in constraint instead
- for( unsigned i=0; i<2; i++ ){
- if( p->d_qinfo[q].isVar( cn[i] ) ){
- int v = p->d_qinfo[q].getVarNum( cn[i] );
- Node cno = cn[i==0 ? 1 : 0];
- p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
- break;
- }
- }
- d_children.pop_back();
- }
- */
}
}else{
d_type = typ_invalid;
@@ -1003,6 +1051,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
}
}else{
d_qni_gterm[i] = d_n[i];
+ qi->setGroundSubterm( d_n[i] );
}
}
d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
@@ -1013,21 +1062,8 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
//we will just evaluate
d_n = n;
d_type = typ_ground;
+ qi->setGroundSubterm( d_n );
}
- //if( d_type!=typ_invalid ){
- //determine an efficient children ordering
- //if( !d_children.empty() ){
- //for( unsigned i=0; i<d_children.size(); i++ ){
- // d_children_order.push_back( i );
- //}
- //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
- //sort based on the type of the constraint : ground comes first, then literals, then others
- //MatchGenSort mgs;
- //mgs.d_mg = this;
- //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
- //}
- //}
- //}
}
Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
debugPrintType( "qcf-qregister-debug", d_type, true );
@@ -1036,78 +1072,96 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
}
-void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
- int v = qi->getVarNum( n );
- if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
- cbvars.push_back( v );
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectBoundVar( qi, n[i], cbvars );
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getKind()==FORALL ){
+ hasNested = true;
+ }
+ int v = qi->getVarNum( n );
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
+ cbvars.push_back( v );
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectBoundVar( qi, n[i], cbvars, visited, hasNested );
+ }
}
}
void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
- Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
- bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
- std::map< int, std::vector< int > > c_to_vars;
- std::map< int, std::vector< int > > vars_to_c;
- std::map< int, int > vb_count;
- std::map< int, int > vu_count;
- std::vector< bool > assigned;
- Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
- for( unsigned i=0; i<d_children.size(); i++ ){
- collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
- assigned.push_back( false );
- vb_count[i] = 0;
- vu_count[i] = 0;
- for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
- int v = c_to_vars[i][j];
- vars_to_c[v].push_back( i );
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- vu_count[i]++;
- if( !isCom ){
- bvars.push_back( v );
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << ", #bvars = " << bvars.size() << std::endl;
+ bool isComm = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
+ if( isComm ){
+ std::map< int, std::vector< int > > c_to_vars;
+ std::map< int, std::vector< int > > vars_to_c;
+ std::map< int, int > vb_count;
+ std::map< int, int > vu_count;
+ std::map< int, bool > has_nested;
+ std::vector< bool > assigned;
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ std::map< Node, bool > visited;
+ has_nested[i] = false;
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i], visited, has_nested[i] );
+ assigned.push_back( false );
+ vb_count[i] = 0;
+ vu_count[i] = 0;
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
+ int v = c_to_vars[i][j];
+ vars_to_c[v].push_back( i );
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ vu_count[i]++;
+ }else{
+ vb_count[i]++;
}
- }else{
- vb_count[i]++;
}
}
- }
- if( isCom ){
- //children that bind the least number of unbound variables go first
+ //children that bind no unbound variable, then the most number of bound, unbound variables go first
+ Trace("qcf-qregister-vo") << "Variable order for " << d_n << " : " << std::endl;
do {
+ int min_score0 = -1;
int min_score = -1;
int min_score_index = -1;
for( unsigned i=0; i<d_children.size(); i++ ){
if( !assigned[i] ){
- int score = vu_count[i];
- if( min_score==-1 || score<min_score ){
+ Trace("qcf-qregister-debug2") << "Child " << i << " has b/ub : " << vb_count[i] << "/" << vu_count[i] << std::endl;
+ int score0 = 0;//has_nested[i] ? 0 : 1;
+ int score;
+ if( !options::qcfVoExp() ){
+ score = vu_count[i];
+ }else{
+ score = vu_count[i]==0 ? 0 : ( 1 + qi->d_vars.size()*( qi->d_vars.size() - vb_count[i] ) + ( qi->d_vars.size() - vu_count[i] ) );
+ }
+ if( min_score==-1 || score0<min_score0 || ( score0==min_score0 && score<min_score ) ){
+ min_score0 = score0;
min_score = score;
min_score_index = i;
}
}
}
- Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
+ Trace("qcf-qregister-vo") << " " << d_children_order.size()+1 << ": " << d_children[min_score_index].d_n << " : ";
+ Trace("qcf-qregister-vo") << vu_count[min_score_index] << " " << vb_count[min_score_index] << " " << has_nested[min_score_index] << std::endl;
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << std::endl;
+ Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl;
Assert( min_score_index!=-1 );
//add to children order
d_children_order.push_back( min_score_index );
assigned[min_score_index] = true;
- //if( vb_count[min_score_index]==0 ){
- // d_independent.push_back( min_score_index );
- //}
//determine order internal to children
d_children[min_score_index].determineVariableOrder( qi, bvars );
Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
//now, make it a bound variable
- for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
- int v = c_to_vars[min_score_index][i];
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
- int vc = vars_to_c[v][j];
- vu_count[vc]--;
- vb_count[vc]++;
+ if( vu_count[min_score_index]>0 ){
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
+ int v = c_to_vars[min_score_index][i];
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
+ int vc = vars_to_c[v][j];
+ vu_count[vc]--;
+ vb_count[vc]++;
+ }
+ bvars.push_back( v );
}
- bvars.push_back( v );
}
}
Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
@@ -1117,6 +1171,16 @@ void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars
for( unsigned i=0; i<d_children.size(); i++ ){
d_children_order.push_back( i );
d_children[i].determineVariableOrder( qi, bvars );
+ //now add to bvars
+ std::map< Node, bool > visited;
+ std::vector< int > cvars;
+ bool has_nested = false;
+ collectBoundVar( qi, d_children[i].d_n, cvars, visited, has_nested );
+ for( unsigned j=0; j<cvars.size(); j++ ){
+ if( std::find( bvars.begin(), bvars.end(), cvars[j] )==bvars.end() ){
+ bvars.push_back( cvars[j] );
+ }
+ }
}
}
}
@@ -1169,15 +1233,20 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qni.clear();
d_qni_bound.clear();
d_child_counter = -1;
+ d_use_children = true;
d_tgt_orig = d_tgt;
//set up processing matches
if( d_type==typ_invalid ){
- //do nothing
+ d_use_children = false;
}else if( d_type==typ_ground ){
+ d_use_children = false;
if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
d_child_counter = 0;
}
+ }else if( qi->isBaseMatchComplete() && options::qcfEagerTest() ){
+ d_use_children = false;
+ d_child_counter = 0;
}else if( d_type==typ_bool_var ){
//get current value of the variable
TNode n = qi->getCurrentValue( d_n );
@@ -1195,7 +1264,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}else{
//unassigned, set match to true/false
d_qni_bound[0] = vn;
- qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false );
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false, true );
d_child_counter = 0;
}
if( d_child_counter==0 ){
@@ -1203,11 +1272,14 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
}else if( d_type==typ_var ){
Assert( isHandledUfTerm( d_n ) );
- Node f = getMatchOperator( p, d_n );
+ TNode f = getMatchOperator( p, d_n );
Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );
if( qni!=NULL ){
d_qn.push_back( qni );
+ }else{
+ //inform irrelevant quantifiers
+ p->setIrrelevantFunction( f );
}
d_matched_basis = false;
}else if( d_type==typ_tsym || d_type==typ_tconstraint ){
@@ -1257,7 +1329,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
}
}else{
- //otherwise, add a constraint to a variable
+ //otherwise, add a constraint to a variable TODO: this may be over-eager at effort > conflict, since equality may be a propagation
if( vn[1]!=-1 && vn[0]==-1 ){
//swap
Node t = nn[1];
@@ -1292,7 +1364,9 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qn.push_back( NULL );
}else{
if( d_tgt && d_n.getKind()==FORALL ){
- //do nothing
+ //fail
+ }else if( d_n.getKind()==FORALL && p->d_effort==QuantConflictFind::effort_conflict && !options::qcfNestedConflict() ){
+ //fail
}else{
//reset the first child to d_tgt
d_child_counter = 0;
@@ -1309,7 +1383,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
debugPrintType( "qcf-match", d_type );
Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
- if( d_type==typ_invalid || d_type==typ_ground ){
+ if( !d_use_children ){
if( d_child_counter==0 ){
d_child_counter = -1;
return true;
@@ -1423,7 +1497,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
Assert( it->second<qi->getNumVars() );
- qi->d_match[ it->second ] = TNode::null();
+ qi->unsetMatch( p, it->second );
qi->d_match_term[ it->second ] = TNode::null();
}
d_qni_bound.clear();
@@ -1654,7 +1728,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
if( it != d_qn[index]->d_data.end() ) {
d_qni.push_back( it );
//set the match
- if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true ) ){
+ if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true, true ) ){
Debug("qcf-match-debug") << " Binding variable" << std::endl;
if( d_qn.size()<d_qni_size ){
d_qn.push_back( &it->second );
@@ -1699,7 +1773,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
d_qni[index]++;
if( d_qni[index]!=d_qn[index]->d_data.end() ){
success = true;
- if( qi->setMatch( p, itb->second, d_qni[index]->first, true ) ){
+ if( qi->setMatch( p, itb->second, d_qni[index]->first, true, true ) ){
Debug("qcf-match-debug") << " Bind next variable" << std::endl;
if( d_qn.size()<d_qni_size ){
d_qn.push_back( &d_qni[index]->second );
@@ -1709,7 +1783,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
invalidMatch = true;
}
}else{
- qi->d_match[ itb->second ] = TNode::null();
+ qi->unsetMatch( p, itb->second );
qi->d_match_term[ itb->second ] = TNode::null();
Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
}
@@ -1779,7 +1853,7 @@ void MatchGen::setInvalid() {
}
bool MatchGen::isHandledBoolConnective( TNode n ) {
- return n.getType().isBoolean() && TermDb::isBoolConnective( n.getKind() );
+ return TermDb::isBoolConnective( n.getKind() ) && ( n.getKind()!=ITE || n.getType().isBoolean() );
}
bool MatchGen::isHandledUfTerm( TNode n ) {
@@ -1835,28 +1909,31 @@ void QuantConflictFind::registerQuantifier( Node q ) {
if( d_quantEngine->hasOwnership( q, this ) ){
d_quants.push_back( q );
d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
+ if( Trace.isOn("qcf-qregister") ){
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ }
//make QcfNode structure
Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
d_qinfo[q].initialize( this, q, q[1] );
//debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
- }
- }
-
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ if( Trace.isOn("qcf-qregister") ){
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
}
}
@@ -1933,6 +2010,18 @@ void QuantConflictFind::reset_round( Theory::Effort level ) {
d_needs_computeRelEqr = true;
}
+void QuantConflictFind::setIrrelevantFunction( TNode f ) {
+ if( d_irr_func.find( f )==d_irr_func.end() ){
+ d_irr_func[f] = true;
+ std::map< TNode, std::vector< Node > >::iterator it = d_func_rel_dom.find( f );
+ if( it != d_func_rel_dom.end()){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ d_irr_quant[it->second[j]] = true;
+ }
+ }
+ }
+}
+
/** check */
void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){
@@ -1955,14 +2044,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
}
computeRelevantEqr();
- //determine order for quantified formulas
- std::vector< Node > qorder;
- for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
- Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
- if( d_quantEngine->hasOwnership( q, this ) ){
- qorder.push_back( q );
- }
- }
+ d_irr_func.clear();
+ d_irr_quant.clear();
+
if( Trace.isOn("qcf-debug") ){
Trace("qcf-debug") << std::endl;
debugPrint("qcf-debug");
@@ -1973,77 +2057,83 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
for( short e = effort_conflict; e<=end_e; e++ ){
d_effort = e;
Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
- for( unsigned j=0; j<qorder.size(); j++ ){
- Node q = qorder[j];
- QuantInfo * qi = &d_qinfo[q];
-
- Assert( d_qinfo.find( q )!=d_qinfo.end() );
- if( qi->matchGeneratorIsValid() ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->getNextMatch( this ) ){
- Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- std::vector< int > assigned;
- if( !qi->isMatchSpurious( this ) ){
- if( qi->completeMatch( this, assigned ) ){
- std::vector< Node > terms;
- qi->getMatch( terms );
- if( !qi->isTConstraintSpurious( this, terms ) ){
- //for debugging
- if( Debug.isOn("qcf-check-inst") ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( !getTermDatabase()->isEntailed( inst, true ) );
- Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict );
- }
- if( d_quantEngine->addInstantiation( q, terms ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quantEngine->markRelevant( q );
- ++(d_statistics.d_conflict_inst);
- if( options::qcfAllConflict() ){
- isConflict = true;
+ for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
+ if( d_quantEngine->hasOwnership( q, this ) && d_irr_quant.find( q )==d_irr_quant.end() ){
+ QuantInfo * qi = &d_qinfo[q];
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( qi->matchGeneratorIsValid() ){
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ if( qi->reset_round( this ) ){
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->getNextMatch( this ) ){
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ if( !qi->isMatchSpurious( this ) ){
+ std::vector< int > assigned;
+ if( qi->completeMatch( this, assigned ) ){
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ bool tcs = qi->isTConstraintSpurious( this, terms );
+ if( !tcs ){
+ //for debugging
+ if( Debug.isOn("qcf-check-inst") ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( !getTermDatabase()->isEntailed( inst, true ) );
+ Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict );
+ }
+ if( d_quantEngine->addInstantiation( q, terms ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quantEngine->markRelevant( q );
+ ++(d_statistics.d_conflict_inst);
+ if( options::qcfAllConflict() ){
+ isConflict = true;
+ }else{
+ d_conflict.set( true );
+ }
+ break;
+ }else if( e==effort_prop_eq ){
+ d_quantEngine->markRelevant( q );
+ ++(d_statistics.d_prop_inst);
+ }
}else{
- d_conflict.set( true );
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
+ //this should only happen if the algorithm generates the same propagating instance twice this round
+ //in this case, break to avoid exponential behavior
+ break;
}
- break;
- }else if( e==effort_prop_eq ){
- d_quantEngine->markRelevant( q );
- ++(d_statistics.d_prop_inst);
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is T-inconsistent)" << std::endl;
}
+ //clean up assigned
+ qi->revertMatch( this, assigned );
+ d_tempCache.clear();
}else{
- Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
- //this should only happen if the algorithm generates the same propagating instance twice this round
- //in this case, break to avoid exponential behavior
- break;
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
}
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
}
- //clean up assigned
- qi->revertMatch( assigned );
- d_tempCache.clear();
- }else{
- Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
}
- }else{
- Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl;
+ if( d_conflict ){
+ break;
+ }
}
}
- Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl;
- if( d_conflict ){
- break;
- }
}
}
if( addedLemmas>0 ){
@@ -2074,17 +2164,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
void QuantConflictFind::computeRelevantEqr() {
if( d_needs_computeRelEqr ){
d_needs_computeRelEqr = false;
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
- //d_uf_terms.clear();
- //d_eqc_uf_terms.clear();
+ Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl;
d_eqcs.clear();
- //d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
- //now, store matches
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
while( !eqcs_i.isFinished() ){
Node r = (*eqcs_i);
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index 8b42b0916..47a66b1b1 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -35,6 +35,7 @@ class MatchGen {
private:
//current children information
int d_child_counter;
+ bool d_use_children;
//children of this object
std::vector< int > d_children_order;
unsigned getNumChildren() { return d_children.size(); }
@@ -61,7 +62,7 @@ private:
std::map< int, Node > d_ground_eval;
//determine variable order
void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
- void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested );
public:
//type of the match generator
enum {
@@ -116,7 +117,16 @@ private: //for completing match
std::vector< int > d_una_eqc_count;
//optimization: track which arguments variables appear under UF terms in
std::map< int, std::map< TNode, std::vector< unsigned > > > d_var_rel_dom;
- void getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited );
+ void getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited );
+ //optimization: number of variables set, to track when we can stop
+ std::map< int, bool > d_vars_set;
+ std::map< Node, bool > d_ground_terms;
+ std::vector< Node > d_extra_var;
+public:
+ void setGroundSubterm( Node t ) { d_ground_terms[t] = true; }
+ bool isGroundSubterm( Node t ) { return d_ground_terms.find( t )!=d_ground_terms.end(); }
+ bool isBaseMatchComplete();
+ bool isPropagatingInstance( QuantConflictFind * p, Node n );
public:
QuantInfo();
~QuantInfo();
@@ -146,7 +156,7 @@ public:
}
Node d_q;
- void reset_round( QuantConflictFind * p );
+ bool reset_round( QuantConflictFind * p );
public:
//initialize
void initialize( QuantConflictFind * p, Node q, Node qn );
@@ -161,12 +171,13 @@ public:
bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
- bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep );
+ bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround );
+ void unsetMatch( QuantConflictFind * p, int v );
bool isMatchSpurious( QuantConflictFind * p );
bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
- void revertMatch( std::vector< int >& assigned );
+ void revertMatch( QuantConflictFind * p, std::vector< int >& assigned );
void debugPrintMatch( const char * c );
bool isConstrainedVar( int v );
public:
@@ -184,6 +195,11 @@ private:
std::map< Kind, Node > d_zero;
//for storing nodes created during t-constraint solving (prevents memory leaks)
std::vector< Node > d_tempCache;
+ //optimization: list of quantifiers that depend on ground function applications
+ std::map< TNode, std::vector< Node > > d_func_rel_dom;
+ std::map< TNode, bool > d_irr_func;
+ std::map< Node, bool > d_irr_quant;
+ void setIrrelevantFunction( TNode f );
private:
std::map< Node, Node > d_op_node;
int d_fid_count;
diff --git a/src/theory/quantifiers/quant_equality_engine.cpp b/src/theory/quantifiers/quant_equality_engine.cpp
index 3f89a799c..3f89a799c 100644..100755
--- a/src/theory/quantifiers/quant_equality_engine.cpp
+++ b/src/theory/quantifiers/quant_equality_engine.cpp
diff --git a/src/theory/quantifiers/quant_equality_engine.h b/src/theory/quantifiers/quant_equality_engine.h
index 26654de4d..26654de4d 100644..100755
--- a/src/theory/quantifiers/quant_equality_engine.h
+++ b/src/theory/quantifiers/quant_equality_engine.h
diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp
index 9fb943e5e..5aff1a848 100644..100755
--- a/src/theory/quantifiers/quant_split.cpp
+++ b/src/theory/quantifiers/quant_split.cpp
@@ -48,11 +48,11 @@ void QuantDSplit::preRegisterQuantifier( Node q ) {
}else{
int score = -1;
if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){
- score = dt.isUFinite() ? 1 : -1;
+ score = dt.isInterpretedFinite() ? 1 : -1;
}else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){
- score = dt.isUFinite() ? 1 : -1;
+ score = dt.isInterpretedFinite() ? 1 : -1;
}
- Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isUFinite() << " " << dt.isFinite() << ")" << std::endl;
+ Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isInterpretedFinite() << " " << dt.isFinite() << ")" << std::endl;
if( score>max_score ){
max_index = i;
max_score = score;
diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h
index d36824998..d36824998 100644..100755
--- a/src/theory/quantifiers/quant_split.h
+++ b/src/theory/quantifiers/quant_split.h
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 3b7787a20..b9aab0236 100644..100755
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -33,22 +33,15 @@ eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
}
bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+ return d_quantEngine->getEqualityQuery()->areEqual( n1, n2 );
}
bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+ return d_quantEngine->getEqualityQuery()->areDisequal( n1, n2 );
}
TNode QuantifiersModule::getRepresentative( TNode n ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- if( ee->hasTerm( n ) ){
- return ee->getRepresentative( n );
- }else{
- return n;
- }
+ return d_quantEngine->getEqualityQuery()->getRepresentative( n );
}
quantifiers::TermDb * QuantifiersModule::getTermDatabase() {
@@ -389,7 +382,7 @@ void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int
}
void QuantPhaseReq::getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ) {
- if( n.getKind()==AND || n.getKind()==OR ){
+ if( n.getKind()==AND || n.getKind()==OR || n.getKind()==SEP_STAR ){
newHasPol = hasPol;
newPol = pol;
}else if( n.getKind()==IMPLIES ){
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 79cdae437..79cdae437 100644..100755
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index b797f4ce9..b797f4ce9 100644..100755
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index 53cef796a..53cef796a 100644..100755
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 5aae4d640..68f824c57 100644..100755
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -48,7 +48,7 @@ bool QuantifiersRewriter::isClause( Node n ){
bool QuantifiersRewriter::isLiteral( Node n ){
switch( n.getKind() ){
case NOT:
- return isLiteral( n[0] );
+ return n[0].getKind()!=NOT && isLiteral( n[0] );
break;
case OR:
case AND:
@@ -59,7 +59,8 @@ bool QuantifiersRewriter::isLiteral( Node n ){
return false;
break;
case EQUAL:
- return n[0].getType()!=NodeManager::currentNM()->booleanType();
+ //for boolean terms
+ return !n[0].getType().isBoolean();
break;
default:
break;
@@ -185,19 +186,10 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
std::vector< Node > args;
- for( int i=0; i<(int)in[0].getNumChildren(); i++ ){
- args.push_back( in[0][i] );
- }
- Node body = in[1];
+ Node body = in;
bool doRewrite = false;
- std::vector< Node > ipl;
- while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){
- if( body.getNumChildren()==3 ){
- for( unsigned i=0; i<body[2].getNumChildren(); i++ ){
- ipl.push_back( body[2][i] );
- }
- }
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
args.push_back( body[0][i] );
}
body = body[1];
@@ -205,16 +197,11 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
if( doRewrite ){
std::vector< Node > children;
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
+ args.push_back( body[0][i] );
+ }
children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
- children.push_back( body );
- if( in.getNumChildren()==3 ){
- for( unsigned i=0; i<in[2].getNumChildren(); i++ ){
- ipl.push_back( in[2][i] );
- }
- }
- if( !ipl.empty() ){
- children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) );
- }
+ children.push_back( body[1] );
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
@@ -244,7 +231,7 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
ret = ret.negate();
status = REWRITE_AGAIN_FULL;
}else if( in.getKind()==FORALL ){
- if( in[1].isConst() ){
+ if( in[1].isConst() && in.getNumChildren()==2 ){
return RewriteResponse( status, in[1] );
}else{
//compute attributes
@@ -273,121 +260,98 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
return RewriteResponse( status, ret );
}
-Node QuantifiersRewriter::computeElimSymbols( Node body ) {
- if( isLiteral( body ) ){
- return body;
- }else{
- bool childrenChanged = false;
- Kind k = body.getKind();
- if( body.getKind()==IMPLIES ){
- k = OR;
- childrenChanged = true;
- }else if( body.getKind()==XOR ){
- k = IFF;
+bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){
+ if( ( k==OR || k==AND ) && options::elimTautQuant() ){
+ Node lit = c.getKind()==NOT ? c[0] : c;
+ bool pol = c.getKind()!=NOT;
+ std::map< Node, bool >::iterator it = lit_pol.find( lit );
+ if( it==lit_pol.end() ){
+ lit_pol[lit] = pol;
+ children.push_back( c );
+ }else{
childrenChanged = true;
- }
- std::vector< Node > children;
- std::map< Node, bool > lit_pol;
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- Node c = computeElimSymbols( body[i] );
- if( i==0 && ( body.getKind()==IMPLIES || body.getKind()==XOR ) ){
- c = c.negate();
- }
- if( ( k==OR || k==AND ) && options::elimTautQuant() ){
- Node lit = c.getKind()==NOT ? c[0] : c;
- bool pol = c.getKind()!=NOT;
- std::map< Node, bool >::iterator it = lit_pol.find( lit );
- if( it==lit_pol.end() ){
- lit_pol[lit] = pol;
- children.push_back( c );
- }else{
- childrenChanged = true;
- if( it->second!=pol ){
- return NodeManager::currentNM()->mkConst( k==OR );
- }
- }
- }else{
- children.push_back( c );
+ if( it->second!=pol ){
+ return false;
}
- childrenChanged = childrenChanged || c!=body[i];
- }
- //if( body.getKind()==ITE && isLiteral( body[0] ) ){
- // ret = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ),
- // NodeManager::currentNM()->mkNode( OR, body[0], body[2] ) );
- //}
- if( childrenChanged ){
- return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
- }else{
- return body;
}
+ }else{
+ children.push_back( c );
}
+ return true;
}
-Node QuantifiersRewriter::computeNNF( Node body ){
- if( body.getKind()==NOT ){
+// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF
+Node QuantifiersRewriter::computeElimSymbols( Node body ) {
+ Kind ok = body.getKind();
+ Kind k = ok;
+ bool negAllCh = false;
+ bool negCh1 = false;
+ if( ok==IMPLIES ){
+ k = OR;
+ negCh1 = true;
+ }else if( ok==XOR ){
+ k = IFF;
+ negCh1 = true;
+ }else if( ok==NOT ){
if( body[0].getKind()==NOT ){
- return computeNNF( body[0][0] );
- }else if( isLiteral( body[0] ) ){
- return body;
+ return computeElimSymbols( body[0][0] );
+ }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
+ k = AND;
+ negAllCh = true;
+ negCh1 = body[0].getKind()==IMPLIES;
+ body = body[0];
+ }else if( body[0].getKind()==AND ){
+ k = OR;
+ negAllCh = true;
+ body = body[0];
+ }else if( body[0].getKind()==XOR || body[0].getKind()==IFF ){
+ k = IFF;
+ negCh1 = ( body[0].getKind()==IFF );
+ body = body[0];
+ }else if( body[0].getKind()==ITE ){
+ k = body[0].getKind();
+ negAllCh = true;
+ negCh1 = true;
+ body = body[0];
}else{
- std::vector< Node > children;
- Kind k = body[0].getKind();
-
- if( body[0].getKind()==OR || body[0].getKind()==AND ){
- k = body[0].getKind()==AND ? OR : AND;
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node nc = computeNNF( body[0][i].notNode() );
- if( nc.getKind()==k ){
- for( unsigned j=0; j<nc.getNumChildren(); j++ ){
- children.push_back( nc[j] );
- }
- }else{
- children.push_back( nc );
- }
- }
- }else if( body[0].getKind()==IFF ){
- for( int i=0; i<2; i++ ){
- Node nn = i==0 ? body[0][i] : body[0][i].notNode();
- children.push_back( computeNNF( nn ) );
- }
- }else if( body[0].getKind()==ITE ){
- for( int i=0; i<3; i++ ){
- Node nn = i==0 ? body[0][i] : body[0][i].notNode();
- children.push_back( computeNNF( nn ) );
- }
- }else{
- Notice() << "Unhandled Quantifiers NNF: " << body << std::endl;
- return body;
- }
- return NodeManager::currentNM()->mkNode( k, children );
+ return body;
}
- }else if( isLiteral( body ) ){
+ }else if( ok!=IFF && ok!=ITE && ok!=AND && ok!=OR ){
+ //a literal
return body;
- }else{
- std::vector< Node > children;
- bool childrenChanged = false;
- bool isAssoc = body.getKind()==AND || body.getKind()==OR;
- for( int i=0; i<(int)body.getNumChildren(); i++ ){
- Node nc = computeNNF( body[i] );
- if( isAssoc && nc.getKind()==body.getKind() ){
- for( unsigned j=0; j<nc.getNumChildren(); j++ ){
- children.push_back( nc[j] );
+ }
+ bool childrenChanged = false;
+ std::vector< Node > children;
+ std::map< Node, bool > lit_pol;
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
+ bool success = true;
+ if( c.getKind()==k && ( k==OR || k==AND ) ){
+ //flatten
+ childrenChanged = true;
+ for( unsigned j=0; j<c.getNumChildren(); j++ ){
+ if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
+ success = false;
+ break;
}
- childrenChanged = true;
- }else{
- children.push_back( nc );
- childrenChanged = childrenChanged || nc!=body[i];
}
- }
- if( childrenChanged ){
- return NodeManager::currentNM()->mkNode( body.getKind(), children );
}else{
- return body;
+ success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
}
+ if( !success ){
+ // tautology
+ Assert( k==OR || k==AND );
+ return NodeManager::currentNM()->mkConst( k==OR );
+ }
+ childrenChanged = childrenChanged || c!=body[i];
+ }
+ if( childrenChanged || k!=ok ){
+ return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
+ }else{
+ return body;
}
}
-
void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons,
std::vector< Node >& conj ){
if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){
@@ -463,6 +427,8 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){
std::map< Node, bool >::iterator it = currCond.find( n );
if( it!=currCond.end() ){
return it->second ? 1 : -1;
+ }else if( n.getKind()==NOT ){
+ return -getEntailedCond( n[0], currCond );
}else if( n.getKind()==AND || n.getKind()==OR ){
bool hasZero = false;
for( unsigned i=0; i<n.getNumChildren(); i++ ){
@@ -483,8 +449,7 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){
}else if( res==-1 ){
return getEntailedCond( n[2], currCond );
}
- }
- if( n.getKind()==IFF || n.getKind()==ITE ){
+ }else if( n.getKind()==IFF || n.getKind()==ITE ){
unsigned start = n.getKind()==IFF ? 0 : 1;
int res1 = 0;
for( unsigned j=start; j<=(start+1); j++ ){
@@ -1049,144 +1014,6 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
return body;
}
-Node QuantifiersRewriter::computeClause( Node n ){
- Assert( isClause( n ) );
- if( isLiteral( n ) ){
- return n;
- }else{
- NodeBuilder<> t(OR);
- if( n.getKind()==NOT ){
- if( n[0].getKind()==NOT ){
- return computeClause( n[0][0] );
- }else{
- //De-Morgan's law
- Assert( n[0].getKind()==AND );
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- Node nn = computeClause( n[0][i].notNode() );
- addNodeToOrBuilder( nn, t );
- }
- }
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nn = computeClause( n[i] );
- addNodeToOrBuilder( nn, t );
- }
- }
- return t.constructNode();
- }
-}
-
-Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){
- if( isLiteral( n ) ){
- return n;
- }else if( !forcePred && isClause( n ) ){
- return computeClause( n );
- }else{
- Kind k = n.getKind();
- NodeBuilder<> t(k);
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nc = n[i];
- Node ncnf = computeCNF( nc, args, defs, k!=OR );
- if( k==OR ){
- addNodeToOrBuilder( ncnf, t );
- }else{
- t << ncnf;
- }
- }
- if( !forcePred && k==OR ){
- return t.constructNode();
- }else{
- //compute the free variables
- Node nt = t;
- std::vector< Node > activeArgs;
- computeArgVec( args, activeArgs, nt );
- std::vector< TypeNode > argTypes;
- for( int i=0; i<(int)activeArgs.size(); i++ ){
- argTypes.push_back( activeArgs[i].getType() );
- }
- //create the predicate
- Assert( argTypes.size()>0 );
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, NodeManager::currentNM()->booleanType() );
- std::stringstream ss;
- ss << "cnf_" << n.getKind() << "_" << n.getId();
- Node op = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "was created by the quantifiers rewriter" );
- std::vector< Node > predArgs;
- predArgs.push_back( op );
- predArgs.insert( predArgs.end(), activeArgs.begin(), activeArgs.end() );
- Node pred = NodeManager::currentNM()->mkNode( APPLY_UF, predArgs );
- Trace("quantifiers-rewrite-cnf-debug") << "Made predicate " << pred << " for " << nt << std::endl;
- //create the bound var list
- Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, activeArgs );
- //now, look at the structure of nt
- if( nt.getKind()==NOT ){
- //case for NOT
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( i==0 ? nt[0].notNode() : nt[0] );
- tt << ( i==0 ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else if( nt.getKind()==OR ){
- //case for OR
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- NodeBuilder<> tt(OR);
- tt << nt[i].notNode() << pred;
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- NodeBuilder<> tt(OR);
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- tt << nt[i];
- }
- tt << pred.notNode();
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }else if( nt.getKind()==AND ){
- //case for AND
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- NodeBuilder<> tt(OR);
- tt << nt[i] << pred.notNode();
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- NodeBuilder<> tt(OR);
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- tt << nt[i].notNode();
- }
- tt << pred;
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }else if( nt.getKind()==IFF ){
- //case for IFF
- for( int i=0; i<4; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( ( i==0 || i==3 ) ? nt[0].notNode() : nt[0] );
- tt << ( ( i==1 || i==3 ) ? nt[1].notNode() : nt[1] );
- tt << ( ( i==0 || i==1 ) ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else if( nt.getKind()==ITE ){
- //case for ITE
- for( int j=1; j<=2; j++ ){
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( ( j==1 ) ? nt[0].notNode() : nt[0] );
- tt << ( ( i==1 ) ? nt[j].notNode() : nt[j] );
- tt << ( ( i==0 ) ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( i==0 ? nt[1].notNode() : nt[1] );
- tt << ( i==0 ? nt[2].notNode() : nt[2] );
- tt << ( i==1 ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else{
- Notice() << "Unhandled Quantifiers CNF: " << nt << std::endl;
- }
- return pred;
- }
- }
-}
-
Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){
if( body.getKind()==FORALL ){
if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){
@@ -1194,15 +1021,13 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
std::vector< Node > subs;
//for doing prenexing of same-signed quantifiers
//must rename each variable that already exists
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
terms.push_back( body[0][i] );
subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) );
}
args.insert( args.end(), subs.begin(), subs.end() );
Node newBody = body[1];
newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
- Debug("quantifiers-substitute-debug") << "Did substitute have an effect" << (body[1] != newBody) << body[1] << " became " << newBody << endl;
return newBody;
}else{
return body;
@@ -1211,7 +1036,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
Assert( body.getKind()!=EXISTS );
bool childrenChanged = false;
std::vector< Node > newChildren;
- for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
bool newHasPol;
bool newPol;
QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
@@ -1237,7 +1062,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
}
}
-Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node body ) {
+Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) {
Assert( body.getKind()==OR );
size_t var_found_count = 0;
size_t eqc_count = 0;
@@ -1253,8 +1078,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
Node n = body[i];
std::vector< Node > lit_args;
computeArgVec( args, lit_args, n );
- if (lit_args.empty()) {
- lits.push_back(n);
+ if( lit_args.empty() ){
+ lits.push_back( n );
}else {
//collect the equivalence classes this literal belongs to, and the new variables it contributes
std::vector< int > eqcs;
@@ -1306,8 +1131,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
eqc_to_lit[eqcz].push_back(n);
}
}
- if ( eqc_active>1 || !lits.empty() ){
- Trace("clause-split-debug") << "Split clause " << f << std::endl;
+ if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
+ Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
Trace("clause-split-debug") << " Ground literals: " << std::endl;
for( size_t i=0; i<lits.size(); i++) {
Trace("clause-split-debug") << " " << lits[i] << std::endl;
@@ -1330,27 +1155,21 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
Node fa = NodeManager::currentNM()->mkNode( FORALL, bvl, body );
lits.push_back(fa);
}
- Assert( lits.size()>1 );
- Node nf = NodeManager::currentNM()->mkNode(OR,lits);
+ Assert( !lits.empty() );
+ Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
Trace("clause-split-debug") << "Made node : " << nf << std::endl;
return nf;
+ }else{
+ return mkForAll( args, body, qa );
}
- return f;
}
Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ){
- std::vector< Node > activeArgs;
- //if cegqi is on, may be synthesis conjecture, in which case we want to keep all variables
- if( options::ceGuidedInst() && qa.d_sygus ){
- activeArgs.insert( activeArgs.end(), args.begin(), args.end() );
- }else{
- computeArgVec2( args, activeArgs, body, qa.d_ipl );
- }
- if( activeArgs.empty() ){
+ if( args.empty() ){
return body;
}else{
std::vector< Node > children;
- children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) );
+ children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
children.push_back( body );
if( !qa.d_ipl.isNull() ){
children.push_back( qa.d_ipl );
@@ -1359,82 +1178,59 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttri
}
}
-Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ){
+//computes miniscoping, also eliminates variables that do not occur free in body
+Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ){
if( body.getKind()==FORALL ){
- //combine arguments
+ //combine prenex
std::vector< Node > newArgs;
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ newArgs.insert( newArgs.end(), args.begin(), args.end() );
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
newArgs.push_back( body[0][i] );
}
- newArgs.insert( newArgs.end(), args.begin(), args.end() );
- return mkForAll( newArgs, body[ 1 ], qa );
- }else{
- if( body.getKind()==NOT ){
- //push not downwards
- if( body[0].getKind()==NOT ){
- return computeMiniscoping( f, args, body[0][0], qa );
- }else if( body[0].getKind()==AND ){
- if( options::miniscopeQuantFreeVar() ){
- NodeBuilder<> t(kind::OR);
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
- }
- return computeMiniscoping( f, args, t.constructNode(), qa );
- }
- }else if( body[0].getKind()==OR ){
- if( options::miniscopeQuant() ){
- NodeBuilder<> t(kind::AND);
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node trm = body[0][i].negate();
- t << computeMiniscoping( f, args, trm, qa );
- }
- return t.constructNode();
+ return mkForAll( newArgs, body[1], qa );
+ }else if( body.getKind()==AND ){
+ if( options::miniscopeQuant() ){
+ //break apart
+ NodeBuilder<> t(kind::AND);
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ t << computeMiniscoping( args, body[i], qa );
+ }
+ Node retVal = t;
+ return retVal;
+ }
+ }else if( body.getKind()==OR ){
+ if( options::quantSplit() ){
+ //splitting subsumes free variable miniscoping, apply it with higher priority
+ return computeSplit( args, body, qa );
+ }else if( options::miniscopeQuantFreeVar() ){
+ Node newBody = body;
+ NodeBuilder<> body_split(kind::OR);
+ NodeBuilder<> tb(kind::OR);
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ Node trm = body[i];
+ if( TermDb::containsTerms( body[i], args ) ){
+ tb << trm;
+ }else{
+ body_split << trm;
}
}
- }else if( body.getKind()==AND ){
- if( options::miniscopeQuant() ){
- //break apart
- NodeBuilder<> t(kind::AND);
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- t << computeMiniscoping( f, args, body[i], qa );
- }
- Node retVal = t;
- return retVal;
- }
- }else if( body.getKind()==OR ){
- if( options::quantSplit() ){
- //splitting subsumes free variable miniscoping, apply it with higher priority
- Node nf = computeSplit( f, args, body );
- if( nf!=f ){
- return nf;
- }
- }else if( options::miniscopeQuantFreeVar() ){
- Node newBody = body;
- NodeBuilder<> body_split(kind::OR);
- NodeBuilder<> tb(kind::OR);
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- Node trm = body[i];
- if( TermDb::containsTerms( body[i], args ) ){
- tb << trm;
- }else{
- body_split << trm;
- }
- }
- if( tb.getNumChildren()==0 ){
- return body_split;
- }else if( body_split.getNumChildren()>0 ){
- newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- body_split << mkForAll( args, newBody, qa );
- return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
- }
+ if( tb.getNumChildren()==0 ){
+ return body_split;
+ }else if( body_split.getNumChildren()>0 ){
+ newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
+ std::vector< Node > activeArgs;
+ computeArgVec2( args, activeArgs, newBody, qa.d_ipl );
+ body_split << mkForAll( activeArgs, newBody, qa );
+ return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
}
}
+ }else if( body.getKind()==NOT ){
+ Assert( isLiteral( body[0] ) );
}
- //if( body==f[1] ){
- // return f;
- //}else{
- return mkForAll( args, body, qa );
- //}
+ //remove variables that don't occur
+ std::vector< Node > activeArgs;
+ computeArgVec2( args, activeArgs, body, qa.d_ipl );
+ return mkForAll( activeArgs, body, qa );
}
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){
@@ -1552,19 +1348,14 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q
return is_std;
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return options::aggressiveMiniscopeQuant() && is_std;
- }else if( computeOption==COMPUTE_NNF ){
- return true;
}else if( computeOption==COMPUTE_PROCESS_TERMS ){
- return true;
- //return options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE || options::iteCondVarSplitQuant();
+ return options::condRewriteQuant();
}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;
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
return ( options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant() ) && is_std;
- //}else if( computeOption==COMPUTE_CNF ){
- // return options::cnfQuant();
}else if( computeOption==COMPUTE_PURIFY_EXPAND ){
return options::purifyQuant() && is_std;
}else{
@@ -1584,11 +1375,9 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut
n = computeElimSymbols( n );
}else if( computeOption==COMPUTE_MINISCOPING ){
//return directly
- return computeMiniscoping( f, args, n, qa );
+ return computeMiniscoping( args, n, qa );
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return computeAggressiveMiniscoping( args, n );
- }else if( computeOption==COMPUTE_NNF ){
- n = computeNNF( n );
}else if( computeOption==COMPUTE_PROCESS_TERMS ){
std::vector< Node > new_conds;
n = computeProcessTerms( n, args, new_conds, f, qa );
@@ -1602,9 +1391,6 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut
n = computePrenex( n, args, true );
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
n = computeVarElimination( n, args, qa );
- //}else if( computeOption==COMPUTE_CNF ){
- //n = computeCNF( n, args, defs, false );
- //ipl = Node::null();
}else if( computeOption==COMPUTE_PURIFY_EXPAND ){
std::vector< Node > conj;
computePurifyExpand( n, conj, args, qa );
@@ -1738,15 +1524,15 @@ struct ContainsQuantAttributeId {};
typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute;
// check if the given node contains a universal quantifier
-bool QuantifiersRewriter::containsQuantifiers(Node n) {
+bool QuantifiersRewriter::containsQuantifiers( Node n ){
if( n.hasAttribute(ContainsQuantAttribute()) ){
return n.getAttribute(ContainsQuantAttribute())==1;
- } else if(n.getKind() == kind::FORALL) {
+ }else if( n.getKind() == kind::FORALL ){
return true;
- } else {
+ }else{
bool cq = false;
for( unsigned i = 0; i < n.getNumChildren(); ++i ){
- if( containsQuantifiers(n[i]) ){
+ if( containsQuantifiers( n[i] ) ){
cq = true;
break;
}
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index 2071d1793..776517109 100644..100755
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -38,6 +38,7 @@ public:
static int getPurifyId( Node n );
static int getPurifyIdLit( Node n );
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 );
@@ -46,7 +47,6 @@ private:
static Node computeProcessTerms2( Node body, bool hasPol, bool pol, std::map< Node, bool >& currCond, int nCurrCond,
std::map< Node, Node >& cache, std::map< Node, Node >& icache,
std::vector< Node >& new_vars, std::vector< Node >& new_conds );
- static Node computeClause( Node n );
static void computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons, std::vector< Node >& conj );
static bool isConditionalVariableElim( Node n, int pol=0 );
static bool isVariableElim( Node v, Node s, std::map< Node, std::vector< int > >& var_parent );
@@ -57,15 +57,13 @@ private:
static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent );
private:
static Node computeElimSymbols( Node body );
- static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa );
+ static Node computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa );
static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body );
- static Node computeNNF( 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 computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred );
static Node computePrenex( Node body, std::vector< Node >& args, bool pol );
- static Node computeSplit( Node f, std::vector< Node >& args, Node body );
+ static Node computeSplit( std::vector< Node >& args, Node body, QAttributes& qa );
static Node computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa );
static Node computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent );
static void computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa );
@@ -74,7 +72,6 @@ private:
COMPUTE_ELIM_SYMBOLS = 0,
COMPUTE_MINISCOPING,
COMPUTE_AGGRESSIVE_MINISCOPING,
- COMPUTE_NNF,
COMPUTE_PROCESS_TERMS,
COMPUTE_PRENEX,
COMPUTE_VAR_ELIMINATION,
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index b353fce2f..b4b51fd84 100644..100755
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -110,7 +110,7 @@ void RelevantDomain::compute(){
for( unsigned i=0; i<sz; i++ ){
Node n = it->second[i];
//if it is a non-redundant term
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( db->isTermActive( n ) ){
for( unsigned j=0; j<n.getNumChildren(); j++ ){
RDomain * rf = getRDomain( op, j );
rf->addTerm( n[j] );
diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h
index 2b90520fd..2b90520fd 100644..100755
--- a/src/theory/quantifiers/relevant_domain.h
+++ b/src/theory/quantifiers/relevant_domain.h
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
index 5365dbcfa..2c58b8f77 100644..100755
--- a/src/theory/quantifiers/rewrite_engine.cpp
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -175,7 +175,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) {
for( unsigned j=0; j<to_remove.size(); j++ ){
Node ns = d_quantEngine->getSubstitute( to_remove[j], inst );
Trace("rewrite-engine-inst-debug") << "Will remove : " << ns << std::endl;
- ns.setAttribute(NoMatchAttribute(),true);
+ d_quantEngine->getTermDatabase()->setTermInactive( ns );
}
*/
}else{
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
index 424530696..424530696 100644..100755
--- a/src/theory/quantifiers/rewrite_engine.h
+++ b/src/theory/quantifiers/rewrite_engine.h
diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp
index 2a2b13583..2a2b13583 100644..100755
--- a/src/theory/quantifiers/symmetry_breaking.cpp
+++ b/src/theory/quantifiers/symmetry_breaking.cpp
diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h
index 38fea4f45..e682955e7 100644..100755
--- a/src/theory/quantifiers/symmetry_breaking.h
+++ b/src/theory/quantifiers/symmetry_breaking.h
@@ -42,9 +42,7 @@ class SubsortSymmetryBreaker {
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
- //typedef context::CDChunkList<int> IntList;
typedef context::CDList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
private:
/** quantifiers engine */
QuantifiersEngine* d_qe;
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 8b09d8e5d..d3a5e178f 100644..100755
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -84,13 +84,13 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
}
}
-TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_id_count( 0 ), d_typ_id_count( 0 ) {
+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;
+ d_sygus_tdb = new TermDbSygus( c, qe );
}else{
d_sygus_tdb = NULL;
}
@@ -163,9 +163,18 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi
//if this is an atomic trigger, consider adding it
if( inst::Trigger::isAtomicTrigger( n ) ){
Trace("term-db") << "register term in db " << n << std::endl;
+ if( options::finiteModelFind() ){
+ computeModelBasisArgAttribute( n );
+ }
+
Node op = getMatchOperator( n );
+ Trace("term-db-debug") << " match operator is : " << op << std::endl;
d_op_map[op].push_back( n );
added.insert( n );
+
+ if( d_sygus_tdb ){
+ d_sygus_tdb->registerEvalTerm( n );
+ }
if( options::eagerInstQuant() ){
for( unsigned i=0; i<n.getNumChildren(); i++ ){
@@ -178,6 +187,8 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi
}
}
}
+ }else{
+ setTermInactive( n );
}
rec = true;
}
@@ -210,7 +221,7 @@ void TermDb::computeUfEqcTerms( TNode f ) {
for( unsigned i=0; i<d_op_map[f].size(); i++ ){
TNode n = d_op_map[f][i];
if( hasTermCurrent( n ) ){
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( isTermActive( n ) ){
computeArgReps( n );
TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n;
d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] );
@@ -220,7 +231,84 @@ void TermDb::computeUfEqcTerms( TNode f ) {
}
}
+void TermDb::computeUfTerms( TNode f ) {
+ if( d_op_nonred_count.find( f )==d_op_nonred_count.end() ){
+ d_op_nonred_count[ f ] = 0;
+ std::map< Node, std::vector< Node > >::iterator it = d_op_map.find( f );
+ if( it!=d_op_map.end() ){
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
+ Trace("term-db-debug") << "Adding terms for operator " << f << std::endl;
+ unsigned congruentCount = 0;
+ unsigned nonCongruentCount = 0;
+ unsigned alreadyCongruentCount = 0;
+ unsigned relevantCount = 0;
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ //to be added to term index, term must be relevant, and exist in EE
+ if( hasTermCurrent( n ) && ee->hasTerm( n ) ){
+ relevantCount++;
+ if( isTermActive( n ) ){
+ computeArgReps( n );
+
+ Trace("term-db-debug") << "Adding term " << n << " with arg reps : ";
+ for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){
+ Trace("term-db-debug") << d_arg_reps[n][i] << " ";
+ if( std::find( d_func_map_rel_dom[f][i].begin(),
+ d_func_map_rel_dom[f][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[f][i].end() ){
+ d_func_map_rel_dom[f][i].push_back( d_arg_reps[n][i] );
+ }
+ }
+ Trace("term-db-debug") << std::endl;
+ Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl;
+ Node at = d_func_map_trie[ f ].addOrGetTerm( n, d_arg_reps[n] );
+ Trace("term-db-debug2") << "...add term returned " << at << std::endl;
+ if( at!=n && ee->areEqual( at, n ) ){
+ setTermInactive( n );
+ Trace("term-db-debug") << n << " is redundant." << std::endl;
+ congruentCount++;
+ }else{
+ if( at!=n && ee->areDisequal( at, n, false ) ){
+ std::vector< Node > lits;
+ lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) );
+ for( unsigned i=0; i<at.getNumChildren(); i++ ){
+ if( at[i]!=n[i] ){
+ lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() );
+ }
+ }
+ Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits );
+ if( Trace.isOn("term-db-lemma") ){
+ Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl;
+ if( !d_quantEngine->getTheoryEngine()->needCheck() ){
+ Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl;
+ }
+ Trace("term-db-lemma") << " add lemma : " << lem << std::endl;
+ }
+ d_quantEngine->addLemma( lem );
+ d_consistent_ee = false;
+ return;
+ }
+ nonCongruentCount++;
+ d_op_nonred_count[ f ]++;
+ }
+ }else{
+ Trace("term-db-debug") << n << " is already redundant." << std::endl;
+ alreadyCongruentCount++;
+ }
+ }else{
+ Trace("term-db-debug") << n << " is not relevant." << std::endl;
+ }
+ }
+ if( Trace.isOn("tdb") ){
+ Trace("tdb") << "Term db size [" << f << "] : " << nonCongruentCount << " / ";
+ Trace("tdb") << ( nonCongruentCount + congruentCount ) << " / " << ( nonCongruentCount + congruentCount + alreadyCongruentCount ) << " / ";
+ Trace("tdb") << relevantCount << " / " << it->second.size() << std::endl;
+ }
+ }
+ }
+}
+
bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) {
+ computeUfTerms( f );
Assert( d_quantEngine->getTheoryEngine()->getMasterEqualityEngine()->getRepresentative( r )==r );
std::map< Node, std::map< unsigned, std::vector< Node > > >::iterator it = d_func_map_rel_dom.find( f );
if( it != d_func_map_rel_dom.end() ){
@@ -237,25 +325,23 @@ bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) {
//return a term n' equivalent to n
// maximal subterms of n' are representatives in the equality engine qy
-Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ) {
+Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests ) {
std::map< TNode, Node >::iterator itv = visited.find( n );
if( itv != visited.end() ){
return itv->second;
}
Trace("term-db-eval") << "evaluate term : " << n << std::endl;
- Node ret;
- if( n.getKind()==BOUND_VARIABLE ){
- return n;
+ Node ret = n;
+ if( n.getKind()==FORALL || n.getKind()==BOUND_VARIABLE ){
+ //do nothing
}else if( !qy->hasTerm( n ) ){
//term is not known to be equal to a representative in equality engine, evaluate it
- if( n.getKind()==FORALL ){
- ret = Node::null();
- }else if( n.hasOperator() ){
+ if( n.hasOperator() ){
TNode f = getMatchOperator( n );
std::vector< TNode > args;
bool ret_set = false;
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- TNode c = evaluateTerm2( n[i], visited, qy );
+ TNode c = evaluateTerm2( n[i], visited, qy, useEntailmentTests );
if( c.isNull() ){
ret = Node::null();
ret_set = true;
@@ -267,7 +353,7 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ
ret_set = true;
break;
}else if( n.getKind()==kind::ITE && i==0 ){
- ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy );
+ ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy, useEntailmentTests );
ret_set = true;
break;
}
@@ -295,6 +381,22 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ
}
ret = NodeManager::currentNM()->mkNode( n.getKind(), args );
ret = Rewriter::rewrite( ret );
+ if( ret.getKind()==kind::EQUAL ){
+ if( qy->areDisequal( ret[0], ret[1] ) ){
+ ret = d_false;
+ }
+ }
+ if( useEntailmentTests ){
+ if( ret.getKind()==kind::EQUAL || ret.getKind()==kind::GEQ ){
+ for( unsigned j=0; j<2; j++ ){
+ std::pair<bool, Node> et = d_quantEngine->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, j==0 ? ret : ret.negate() );
+ if( et.first ){
+ ret = j==0 ? d_true : d_false;
+ break;
+ }
+ }
+ }
+ }
}
}
}
@@ -316,14 +418,16 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su
return n;
}else if( n.getKind()==BOUND_VARIABLE ){
if( hasSubs ){
- Assert( subs.find( n )!=subs.end() );
- Trace("term-db-entail") << "...substitution is : " << subs[n] << std::endl;
- if( subsRep ){
- Assert( qy->getEngine()->hasTerm( subs[n] ) );
- Assert( qy->getEngine()->getRepresentative( subs[n] )==subs[n] );
- return subs[n];
- }else{
- return getEntailedTerm2( subs[n], subs, subsRep, hasSubs, qy );
+ std::map< TNode, TNode >::iterator it = subs.find( n );
+ if( it!=subs.end() ){
+ Trace("term-db-entail") << "...substitution is : " << it->second << std::endl;
+ if( subsRep ){
+ Assert( qy->getEngine()->hasTerm( it->second ) );
+ Assert( qy->getEngine()->getRepresentative( it->second )==it->second );
+ return it->second;
+ }else{
+ return getEntailedTerm2( it->second, subs, subsRep, hasSubs, qy );
+ }
}
}
}else if( n.getKind()==ITE ){
@@ -355,12 +459,12 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su
return TNode::null();
}
-Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy ) {
+Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy, bool useEntailmentTests ) {
if( qy==NULL ){
qy = d_quantEngine->getEqualityQuery();
}
std::map< TNode, Node > visited;
- return evaluateTerm2( n, visited, qy );
+ return evaluateTerm2( n, visited, qy, useEntailmentTests );
}
TNode TermDb::getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy ) {
@@ -436,6 +540,8 @@ bool TermDb::isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
return qy->getEngine()->getRepresentative( n1 ) == ( pol ? d_true : d_false );
}
}
+ }else if( n.getKind()==FORALL && !pol ){
+ return isEntailed2( n[1], subs, subsRep, hasSubs, pol, qy );
}
return false;
}
@@ -457,6 +563,18 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
return isEntailed2( n, subs, subsRep, true, pol, qy );
}
+bool TermDb::isTermActive( Node n ) {
+ return d_inactive_map.find( n )==d_inactive_map.end();
+ //return !n.getAttribute(NoMatchAttribute());
+}
+
+void TermDb::setTermInactive( Node n ) {
+ d_inactive_map[n] = true;
+ //Trace("term-db-debug2") << "set no match attribute" << std::endl;
+ //NoMatchAttribute nma;
+ //n.setAttribute(nma,true);
+}
+
bool TermDb::hasTermCurrent( Node n, bool useMode ) {
if( !useMode ){
return d_has_map.find( n )!=d_has_map.end();
@@ -556,10 +674,6 @@ void TermDb::presolve() {
}
bool TermDb::reset( Theory::Effort effort ){
- int nonCongruentCount = 0;
- int congruentCount = 0;
- int alreadyCongruentCount = 0;
- int nonRelevantCount = 0;
d_op_nonred_count.clear();
d_arg_reps.clear();
d_func_map_trie.clear();
@@ -614,89 +728,20 @@ bool TermDb::reset( Theory::Effort effort ){
}
}
+/*
//rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- d_op_nonred_count[ it->first ] = 0;
- Trace("term-db-debug") << "Adding terms for operator " << it->first << std::endl;
- for( unsigned i=0; i<it->second.size(); i++ ){
- Node n = it->second[i];
- //to be added to term index, term must be relevant, and exist in EE
- if( hasTermCurrent( n ) && ee->hasTerm( n ) ){
- if( !n.getAttribute(NoMatchAttribute()) ){
- if( options::finiteModelFind() ){
- computeModelBasisArgAttribute( n );
- }
- computeArgReps( n );
-
- Trace("term-db-debug") << "Adding term " << n << " with arg reps : ";
- for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){
- Trace("term-db-debug") << d_arg_reps[n][i] << " ";
- if( std::find( d_func_map_rel_dom[it->first][i].begin(),
- d_func_map_rel_dom[it->first][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[it->first][i].end() ){
- d_func_map_rel_dom[it->first][i].push_back( d_arg_reps[n][i] );
- }
- }
- Trace("term-db-debug") << std::endl;
- if( ee->hasTerm( n ) ){
- Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl;
- }
- Node at = d_func_map_trie[ it->first ].addOrGetTerm( n, d_arg_reps[n] );
- if( at!=n && ee->areEqual( at, n ) ){
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- Trace("term-db-debug") << n << " is redundant." << std::endl;
- congruentCount++;
- }else{
- if( at!=n && ee->areDisequal( at, n, false ) ){
- std::vector< Node > lits;
- lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) );
- for( unsigned i=0; i<at.getNumChildren(); i++ ){
- if( at[i]!=n[i] ){
- lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() );
- }
- }
- Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits );
- if( Trace.isOn("term-db-lemma") ){
- Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl;
- if( !d_quantEngine->getTheoryEngine()->needCheck() ){
- Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl;
- }
- Trace("term-db-lemma") << " add lemma : " << lem << std::endl;
- }
- d_quantEngine->addLemma( lem );
- d_consistent_ee = false;
- return false;
- }
- nonCongruentCount++;
- d_op_nonred_count[ it->first ]++;
- }
- }else{
- Trace("term-db-debug") << n << " is already redundant." << std::endl;
- congruentCount++;
- alreadyCongruentCount++;
- }
- }else{
- Trace("term-db-debug") << n << " is not relevant." << std::endl;
- nonRelevantCount++;
- }
- }
- }
- Trace("term-db-stats") << "TermDb: Reset" << std::endl;
- Trace("term-db-stats") << "Non-Congruent/Congruent/Non-Relevant = ";
- Trace("term-db-stats") << nonCongruentCount << " / " << congruentCount << " (" << alreadyCongruentCount << ") / " << nonRelevantCount << std::endl;
- if( Trace.isOn("term-db-index") ){
- Trace("term-db-index") << "functions : " << std::endl;
- for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- if( it->second.size()>0 ){
- Trace("term-db-index") << "- " << it->first << std::endl;
- d_func_map_trie[ it->first ].debugPrint("term-db-index", it->second[0]);
- }
+ computeUfTerms( it->first );
+ if( !d_consistent_ee ){
+ return false;
}
}
+*/
return true;
}
TermArgTrie * TermDb::getTermArgTrie( Node f ) {
+ computeUfTerms( f );
std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
if( itut!=d_func_map_trie.end() ){
return &itut->second;
@@ -725,11 +770,18 @@ TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) {
}
TNode TermDb::getCongruentTerm( Node f, Node n ) {
- computeArgReps( n );
- return d_func_map_trie[f].existsTerm( d_arg_reps[n] );
+ computeUfTerms( f );
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
+ if( itut!=d_func_map_trie.end() ){
+ computeArgReps( n );
+ return itut->second.existsTerm( d_arg_reps[n] );
+ }else{
+ return TNode::null();
+ }
}
TNode TermDb::getCongruentTerm( Node f, std::vector< TNode >& args ) {
+ computeUfTerms( f );
return d_func_map_trie[f].existsTerm( args );
}
@@ -822,6 +874,7 @@ void TermDb::makeInstantiationConstantsFor( Node q ){
Debug("quantifiers-engine") << "Instantiation constants for " << q << " : " << std::endl;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
d_vars[q].push_back( q[0][i] );
+ d_var_num[q][q[0][i]] = i;
//make instantiation constants
Node ic = NodeManager::currentNM()->mkInstConstant( q[0][i].getType() );
d_inst_constants_map[ic] = q;
@@ -832,9 +885,8 @@ void TermDb::makeInstantiationConstantsFor( Node q ){
ic.setAttribute( ivna, i );
InstConstantAttribute ica;
ic.setAttribute( ica, q );
- //also set the no-match attribute
- NoMatchAttribute nma;
- ic.setAttribute(nma,true);
+ //also set the term inactive
+ setTermInactive( ic );
}
}
}
@@ -892,11 +944,6 @@ Node TermDb::getInstConstAttr( Node n ) {
}
InstConstantAttribute ica;
n.setAttribute(ica, q);
- if( !q.isNull() ){
- //also set the no-match attribute
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- }
}
return n.getAttribute(InstConstantAttribute());
}
@@ -1005,9 +1052,12 @@ Node TermDb::getCounterexampleLiteral( Node q ){
Node TermDb::getInstConstantNode( Node n, Node q ){
makeInstantiationConstantsFor( q );
- Node n2 = n.substitute( d_vars[q].begin(), d_vars[q].end(),
- d_inst_constants[q].begin(), d_inst_constants[q].end() );
- return n2;
+ return n.substitute( d_vars[q].begin(), d_vars[q].end(), d_inst_constants[q].begin(), d_inst_constants[q].end() );
+}
+
+Node TermDb::getVariableNode( Node n, Node q ) {
+ makeInstantiationConstantsFor( q );
+ return n.substitute( d_inst_constants[q].begin(), d_inst_constants[q].end(), d_vars[q].begin(), d_vars[q].end() );
}
Node TermDb::getInstantiatedNode( Node n, Node q, std::vector< Node >& terms ) {
@@ -1512,7 +1562,7 @@ struct sortTermOrder {
//this function makes a canonical representation of a term (
// - orders variables left to right
// - if apply_torder, then sort direct subterms of commutative operators
-Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder ) {
+Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder, std::map< TNode, Node >& visited ) {
Trace("canon-term-debug") << "Get canonical term for " << n << std::endl;
if( n.getKind()==BOUND_VARIABLE ){
std::map< TNode, TNode >::iterator it = subs.find( n );
@@ -1529,32 +1579,38 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun
return it->second;
}
}else if( n.getNumChildren()>0 ){
- //collect children
- Trace("canon-term-debug") << "Collect children" << std::endl;
- std::vector< Node > cchildren;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- cchildren.push_back( n[i] );
- }
- //if applicable, first sort by term order
- if( apply_torder && isComm( n.getKind() ) ){
- Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl;
- sortTermOrder sto;
- sto.d_tdb = this;
- std::sort( cchildren.begin(), cchildren.end(), sto );
- }
- //now make canonical
- Trace("canon-term-debug") << "Make canonical children" << std::endl;
- for( unsigned i=0; i<cchildren.size(); i++ ){
- cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder );
- }
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl;
- cchildren.insert( cchildren.begin(), n.getOperator() );
- }
- Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl;
- Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren );
- Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl;
- return ret;
+ std::map< TNode, Node >::iterator it = visited.find( n );
+ if( it!=visited.end() ){
+ return it->second;
+ }else{
+ //collect children
+ Trace("canon-term-debug") << "Collect children" << std::endl;
+ std::vector< Node > cchildren;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ cchildren.push_back( n[i] );
+ }
+ //if applicable, first sort by term order
+ if( apply_torder && isComm( n.getKind() ) ){
+ Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl;
+ sortTermOrder sto;
+ sto.d_tdb = this;
+ std::sort( cchildren.begin(), cchildren.end(), sto );
+ }
+ //now make canonical
+ Trace("canon-term-debug") << "Make canonical children" << std::endl;
+ for( unsigned i=0; i<cchildren.size(); i++ ){
+ cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder, visited );
+ }
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl;
+ cchildren.insert( cchildren.begin(), n.getOperator() );
+ }
+ Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl;
+ Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren );
+ Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl;
+ visited[n] = ret;
+ return ret;
+ }
}else{
Trace("canon-term-debug") << "...return 0-child term." << std::endl;
return n;
@@ -1564,7 +1620,8 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun
Node TermDb::getCanonicalTerm( TNode n, bool apply_torder ){
std::map< TypeNode, unsigned > var_count;
std::map< TNode, TNode > subs;
- return getCanonicalTerm( n, var_count, subs, apply_torder );
+ std::map< TNode, Node > visited;
+ return getCanonicalTerm( n, var_count, subs, apply_torder, visited );
}
void TermDb::getVtsTerms( std::vector< Node >& t, bool isFree, bool create, bool inc_delta ) {
@@ -1790,6 +1847,18 @@ bool TermDb::getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& c
}
}
+void TermDb::getRelevancyCondition( Node n, std::vector< Node >& cond ) {
+ if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+ unsigned scindex = Datatype::cindexOf(n.getOperator().toExpr());
+ const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
+ Node rc = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[scindex].getTester() ), n[0] ).negate();
+ if( std::find( cond.begin(), cond.end(), rc )==cond.end() ){
+ cond.push_back( rc );
+ }
+ getRelevancyCondition( n[0], cond );
+ }
+}
+
bool TermDb::containsTerm2( Node n, Node t, std::map< Node, bool >& visited ) {
if( n==t ){
return true;
@@ -1856,7 +1925,7 @@ bool TermDb::containsUninterpretedConstant( Node n ) {
bool ret = false;
if( n.getKind()==UNINTERPRETED_CONSTANT ){
ret = true;
- }else{
+ }else{
for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( containsUninterpretedConstant( n[i] ) ){
ret = true;
@@ -1884,7 +1953,8 @@ Node TermDb::simpleNegate( Node n ){
bool TermDb::isAssoc( Kind k ) {
return k==PLUS || k==MULT || k==AND || k==OR || k==XOR || k==IFF ||
- k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT;
+ k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT ||
+ k==STRING_CONCAT;
}
bool TermDb::isComm( Kind k ) {
@@ -2184,11 +2254,15 @@ bool TermDb::isQAttrQuantElimPartial( Node q ) {
}
}
-TermDbSygus::TermDbSygus(){
+TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
}
+bool TermDbSygus::reset( Theory::Effort e ) {
+ return true;
+}
+
TNode TermDbSygus::getVar( TypeNode tn, int i ) {
while( i>=(int)d_fv[tn].size() ){
std::stringstream ss;
@@ -2400,8 +2474,8 @@ Node TermDbSygus::sygusToBuiltin( Node n, TypeNode tn ) {
std::map< Node, Node >::iterator it = d_sygus_to_builtin[tn].find( n );
if( it==d_sygus_to_builtin[tn].end() ){
Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n << ", type = " << tn << std::endl;
- Assert( n.getKind()==APPLY_CONSTRUCTOR );
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( n.getKind()==APPLY_CONSTRUCTOR );
unsigned i = Datatype::indexOf( n.getOperator().toExpr() );
Assert( n.getNumChildren()==dt[i].getNumArgs() );
std::map< TypeNode, int > var_count;
@@ -3051,6 +3125,7 @@ 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 ){
@@ -3118,3 +3193,91 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node >
out << n;
}
}
+
+Node TermDbSygus::getAnchor( Node n ) {
+ if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+ return getAnchor( n[0] );
+ }else{
+ return n;
+ }
+}
+
+void TermDbSygus::registerEvalTerm( Node n ) {
+ if( options::sygusDirectEval() ){
+ if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){
+ Trace("sygus-eager") << "TermDbSygus::eager: Register eval term : " << n << std::endl;
+ TypeNode tn = n[0].getType();
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ Node f = n.getOperator();
+ Trace("sygus-eager") << "...the evaluation function is : " << f << std::endl;
+ if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
+ d_evals[n[0]].push_back( n );
+ TypeNode tn = n[0].getType();
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ Assert( dt.isSygus() );
+ d_eval_args[n[0]].push_back( std::vector< Node >() );
+ for( unsigned j=1; j<n.getNumChildren(); j++ ){
+ if( var_list[j-1].getType().isBoolean() ){
+ //TODO: remove this case when boolean term conversion is eliminated
+ Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u));
+ d_eval_args[n[0]].back().push_back( n[j].eqNode( c ) );
+ }else{
+ d_eval_args[n[0]].back().push_back( n[j] );
+ }
+ }
+ Node a = getAnchor( n[0] );
+ d_subterms[a][n[0]] = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& lems ) {
+ std::map< Node, std::map< Node, bool > >::iterator its = d_subterms.find( a );
+ if( its!=d_subterms.end() ){
+ Trace("sygus-eager") << "registerModelValue : " << a << ", has " << its->second.size() << " registered subterms." << std::endl;
+ for( std::map< Node, bool >::iterator itss = its->second.begin(); itss != its->second.end(); ++itss ){
+ Node n = itss->first;
+ Trace("sygus-eager-debug") << "...process : " << n << std::endl;
+ std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_eval_args.find( n );
+ if( it!=d_eval_args.end() && !it->second.empty() ){
+ TNode at = a;
+ TNode vt = v;
+ Node vn = n.substitute( at, vt );
+ vn = Rewriter::rewrite( vn );
+ unsigned start = d_node_mv_args_proc[n][vn];
+ Node antec = n.eqNode( vn ).negate();
+ TypeNode tn = n.getType();
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( dt.isSygus() );
+ Trace("sygus-eager") << "TermDbSygus::eager: Register model value : " << vn << " for " << n << std::endl;
+ Trace("sygus-eager") << "...it has " << it->second.size() << " evaluations, already processed " << start << "." << std::endl;
+ Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( vn, tn );
+ Trace("sygus-eager") << "Built-in term : " << bTerm << std::endl;
+ std::vector< Node > vars;
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+ vars.push_back( var_list[j] );
+ }
+ //for each evaluation
+ for( unsigned i=start; i<it->second.size(); i++ ){
+ Assert( vars.size()==it->second[i].size() );
+ Node sBTerm = bTerm.substitute( vars.begin(), vars.end(), it->second[i].begin(), it->second[i].end() );
+ Node lem = NodeManager::currentNM()->mkNode( n.getType().isBoolean() ? IFF : EQUAL, d_evals[n][i], sBTerm );
+ lem = NodeManager::currentNM()->mkNode( OR, antec, lem );
+ Trace("sygus-eager") << "Lemma : " << lem << std::endl;
+ lems.push_back( lem );
+ }
+ d_node_mv_args_proc[n][vn] = it->second.size();
+ }
+ }
+ }
+}
+
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index a62b343a2..7ab3668eb 100644..100755
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -47,15 +47,6 @@ typedef expr::Attribute< SygusAttributeId, bool > SygusAttribute;
struct SynthesisAttributeId {};
typedef expr::Attribute< SynthesisAttributeId, bool > SynthesisAttribute;
-/** Attribute true for nodes that should not be used for matching */
-struct NoMatchAttributeId {};
-/** use the special for boolean flag */
-typedef expr::Attribute< NoMatchAttributeId,
- bool,
- expr::attr::NullCleanupStrategy,
- true // context dependent
- > NoMatchAttribute;
-
// attribute for "contains instantiation constants from"
struct InstConstantAttributeId {};
typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute;
@@ -179,6 +170,7 @@ class TermDb : public QuantifiersUtil {
friend class ::CVC4::theory::quantifiers::ConjectureGenerator;
friend class ::CVC4::theory::quantifiers::TermGenEnv;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
private:
/** reference to the quantifiers engine */
QuantifiersEngine* d_quantEngine;
@@ -211,6 +203,8 @@ private:
std::map< Node, std::vector< Node > > d_op_map;
/** map from type nodes to terms of that type */
std::map< TypeNode, std::vector< Node > > d_type_map;
+ /** inactive map */
+ NodeBoolMap d_inactive_map;
/** count number of non-redundant ground terms per operator */
std::map< Node, int > d_op_nonred_count;
@@ -228,7 +222,7 @@ private:
/** set has term */
void setHasTerm( Node n );
/** evaluate term */
- Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy );
+ Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests );
TNode getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy );
bool isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy );
public:
@@ -254,18 +248,23 @@ public:
void computeArgReps( TNode n );
/** compute uf eqc terms */
void computeUfEqcTerms( TNode f );
+ /** compute uf terms */
+ void computeUfTerms( TNode f );
/** in relevant domain */
bool inRelevantDomain( TNode f, unsigned i, TNode r );
/** evaluate a term under a substitution. Return representative in EE if possible.
* subsRep is whether subs contains only representatives
*/
- Node evaluateTerm( TNode n, EqualityQuery * qy = NULL );
+ Node evaluateTerm( TNode n, EqualityQuery * qy = NULL, bool useEntailmentTests = false );
/** get entailed term, does not construct new terms, less aggressive */
TNode getEntailedTerm( TNode n, EqualityQuery * qy = NULL );
TNode getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy = NULL );
/** is entailed (incomplete check) */
bool isEntailed( TNode n, bool pol, EqualityQuery * qy = NULL );
bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy = NULL );
+ /** is active */
+ bool isTermActive( Node n );
+ void setTermInactive( Node n );
/** has term */
bool hasTermCurrent( Node n, bool useMode = true );
/** is term eligble for instantiation? */
@@ -274,7 +273,7 @@ public:
Node getEligibleTermInEqc( TNode r );
/** is inst closure */
bool isInstClosure( Node r );
-
+
//for model basis
private:
//map from types to model basis terms
@@ -301,6 +300,7 @@ public:
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 */
@@ -312,6 +312,8 @@ private:
/** make instantiation constants for */
void makeInstantiationConstantsFor( Node q );
public:
+ /** get variable number */
+ unsigned getVariableNum( Node q, Node v ) { return d_var_num[q][v]; }
/** get the i^th instantiation constant of q */
Node getInstantiationConstant( Node q, int i ) const;
/** get number of instantiation constants for q */
@@ -327,6 +329,7 @@ public:
instantiation.
*/
Node getInstConstantNode( Node n, Node q );
+ Node getVariableNode( Node n, Node q );
/** get substituted node */
Node getInstantiatedNode( Node n, Node q, std::vector< Node >& terms );
@@ -419,7 +422,8 @@ private:
//free variables
std::map< TypeNode, std::vector< Node > > d_cn_free_var;
// get canonical term, return null if it contains a term apart from handled signature
- Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder );
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder,
+ std::map< TNode, Node >& visited );
public:
/** get id for operator */
int getIdForOperator( Node op );
@@ -461,6 +465,8 @@ public:
static Node ensureType( Node n, TypeNode tn );
/** get ensure type condition */
static bool getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& cond );
+ /** get relevancy condition */
+ static void getRelevancyCondition( Node n, std::vector< Node >& cond );
private:
//helper for contains term
static bool containsTerm2( Node n, Node t, std::map< Node, bool >& visited );
@@ -541,6 +547,8 @@ public:
class TermDbSygus {
private:
+ /** reference to the quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
std::map< TypeNode, std::vector< Node > > d_fv;
std::map< Node, TypeNode > d_fv_stype;
std::map< Node, int > d_fv_num;
@@ -554,7 +562,6 @@ public:
private:
std::map< TypeNode, std::map< int, Node > > d_generic_base;
std::map< TypeNode, std::vector< Node > > d_generic_templ;
- Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
bool getMatch( Node p, Node n, std::map< int, Node >& s );
bool getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s );
public:
@@ -581,7 +588,11 @@ private:
std::map< TypeNode, std::map< Node, Node > > d_sygus_to_builtin;
std::map< TypeNode, std::map< Node, Node > > d_builtin_const_to_sygus;
public:
- TermDbSygus();
+ TermDbSygus( context::Context* c, QuantifiersEngine* qe );
+ ~TermDbSygus(){}
+ bool reset( Theory::Effort e );
+ std::string identify() const { return "TermDbSygus"; }
+
bool isRegistered( TypeNode tn );
TypeNode sygusToBuiltinType( TypeNode tn );
int getKindArg( TypeNode tn, Kind k );
@@ -615,6 +626,7 @@ public:
/** get value */
Node getTypeMaxValue( TypeNode tn );
TypeNode getSygusTypeForVar( Node v );
+ Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
Node mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre );
Node sygusToBuiltin( Node n, TypeNode tn );
Node builtinToSygusConst( Node c, TypeNode tn, int rcons_depth = 0 );
@@ -633,6 +645,18 @@ public:
static Kind getOperatorKind( Node op );
/** print sygus term */
static void printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs );
+
+ /** get anchor */
+ static Node getAnchor( Node n );
+//for eager instantiation
+private:
+ std::map< Node, std::map< Node, bool > > d_subterms;
+ std::map< Node, std::vector< Node > > d_evals;
+ std::map< Node, std::vector< std::vector< Node > > > d_eval_args;
+ std::map< Node, std::map< Node, unsigned > > d_node_mv_args_proc;
+public:
+ void registerEvalTerm( Node n );
+ void registerModelValue( Node n, Node v, std::vector< Node >& lems );
};
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index efe40aaa8..7ad13b3a8 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -72,8 +72,11 @@ void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) {
void TheoryQuantifiers::preRegisterTerm(TNode n) {
Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
- if( n.getKind()==FORALL && !TermDb::hasInstConstAttr(n) ){
- getQuantifiersEngine()->registerQuantifier( n );
+ if( n.getKind()==FORALL ){
+ if( !options::cbqi() || options::recurseCbqi() || !TermDb::hasInstConstAttr(n) ){
+ getQuantifiersEngine()->registerQuantifier( n );
+ Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() done " << n << endl;
+ }
}
}
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index 6775e0536..6775e0536 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
index 6ba57afb4..6ba57afb4 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index 38635b37b..ee091919d 100644..100755
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -43,9 +43,8 @@ void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){
}
/** trigger class constructor */
-Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption )
- : d_quantEngine( qe ), d_f( f )
-{
+Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes )
+ : d_quantEngine( qe ), d_f( f ) {
d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
Trace("trigger") << "Trigger for " << f << ": " << std::endl;
for( unsigned i=0; i<d_nodes.size(); i++ ){
@@ -53,7 +52,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int
}
if( d_nodes.size()==1 ){
if( isSimpleTrigger( d_nodes[0] ) ){
- d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] );
+ d_mg = new InstMatchGeneratorSimple( f, d_nodes[0], qe );
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes[0], qe );
d_mg->setActiveAdd(true);
@@ -87,7 +86,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int
}
Trigger::~Trigger() {
- if(d_mg != NULL) { delete d_mg; }
+ delete d_mg;
}
void Trigger::resetInstantiationRound(){
@@ -112,6 +111,10 @@ 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 );
+}
+
int Trigger::addInstantiations( InstMatch& baseMatch ){
int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine );
if( addedLemmas>0 ){
@@ -124,77 +127,85 @@ int Trigger::addInstantiations( InstMatch& baseMatch ){
return addedLemmas;
}
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption ){
- std::vector< Node > trNodes;
- if( !keepAll ){
- //only take nodes that contribute variables to the trigger when added
- std::vector< Node > temp;
- temp.insert( temp.begin(), nodes.begin(), nodes.end() );
- std::map< Node, bool > vars;
- std::map< Node, std::vector< Node > > patterns;
- size_t varCount = 0;
- std::map< Node, std::vector< Node > > varContains;
- quantifiers::TermDb::getVarContains( f, temp, varContains );
- for( unsigned i=0; i<temp.size(); i++ ){
- bool foundVar = false;
+bool Trigger::mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ) {
+ //only take nodes that contribute variables to the trigger when added
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+ std::map< Node, bool > vars;
+ std::map< Node, std::vector< Node > > patterns;
+ size_t varCount = 0;
+ std::map< Node, std::vector< Node > > varContains;
+ quantifiers::TermDb::getVarContains( q, temp, varContains );
+ for( unsigned i=0; i<temp.size(); i++ ){
+ bool foundVar = false;
+ for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
+ Node v = varContains[ temp[i] ][j];
+ Assert( quantifiers::TermDb::getInstConstAttr(v)==q );
+ if( vars.find( v )==vars.end() ){
+ varCount++;
+ vars[ v ] = true;
+ foundVar = true;
+ }
+ }
+ if( foundVar ){
+ trNodes.push_back( temp[i] );
for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
Node v = varContains[ temp[i] ][j];
- Assert( quantifiers::TermDb::getInstConstAttr(v)==f );
- if( vars.find( v )==vars.end() ){
- varCount++;
- vars[ v ] = true;
- foundVar = true;
- }
- }
- if( foundVar ){
- trNodes.push_back( temp[i] );
- for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
- Node v = varContains[ temp[i] ][j];
- patterns[ v ].push_back( temp[i] );
- }
- }
- if( varCount==f[0].getNumChildren() ){
- break;
+ patterns[ v ].push_back( temp[i] );
}
}
- if( varCount<f[0].getNumChildren() && !options::partialTriggers() ){
- Trace("trigger-debug") << "Don't consider trigger since it does not contain all variables in " << f << std::endl;
- for( unsigned i=0; i<nodes.size(); i++) {
- Trace("trigger-debug") << nodes[i] << " ";
- }
- Trace("trigger-debug") << std::endl;
+ if( varCount==n_vars ){
+ break;
+ }
+ }
+ if( varCount<n_vars ){
+ Trace("trigger-debug") << "Don't consider trigger since it does not contain specified number of variables." << std::endl;
+ for( unsigned i=0; i<nodes.size(); i++) {
+ Trace("trigger-debug") << nodes[i] << " ";
+ }
+ Trace("trigger-debug") << std::endl;
- //do not generate multi-trigger if it does not contain all variables
- return NULL;
- }else{
- //now, minimize the trigger
- for( unsigned i=0; i<trNodes.size(); i++ ){
- bool keepPattern = false;
- Node n = trNodes[i];
+ //do not generate multi-trigger if it does not contain all variables
+ return false;
+ }else{
+ //now, minimize the trigger
+ for( unsigned i=0; i<trNodes.size(); i++ ){
+ bool keepPattern = false;
+ Node n = trNodes[i];
+ for( unsigned j=0; j<varContains[ n ].size(); j++ ){
+ Node v = varContains[ n ][j];
+ if( patterns[v].size()==1 ){
+ keepPattern = true;
+ break;
+ }
+ }
+ if( !keepPattern ){
+ //remove from pattern vector
for( unsigned j=0; j<varContains[ n ].size(); j++ ){
Node v = varContains[ n ][j];
- if( patterns[v].size()==1 ){
- keepPattern = true;
- break;
- }
- }
- if( !keepPattern ){
- //remove from pattern vector
- for( unsigned j=0; j<varContains[ n ].size(); j++ ){
- Node v = varContains[ n ][j];
- for( unsigned k=0; k<patterns[v].size(); k++ ){
- if( patterns[v][k]==n ){
- patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
- break;
- }
+ for( unsigned k=0; k<patterns[v].size(); k++ ){
+ if( patterns[v][k]==n ){
+ patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
+ break;
}
}
- //remove from trigger nodes
- trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
- i--;
}
+ //remove from trigger nodes
+ trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
+ i--;
}
}
+ }
+ return true;
+}
+
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, bool keepAll, int trOption, unsigned use_n_vars ){
+ std::vector< Node > trNodes;
+ if( !keepAll ){
+ unsigned n_vars = use_n_vars==0 ? f[0].getNumChildren() : use_n_vars;
+ if( !mkTriggerTerms( f, nodes, n_vars, trNodes ) ){
+ return NULL;
+ }
}else{
trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
}
@@ -211,15 +222,15 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
}
}
- Trigger* t = new Trigger( qe, f, trNodes, matchOption );
+ Trigger* t = new Trigger( qe, f, trNodes );
qe->getTriggerDatabase()->addTrigger( trNodes, t );
return t;
}
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption ){
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll, int trOption, unsigned use_n_vars ){
std::vector< Node > nodes;
nodes.push_back( n );
- return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption );
+ return mkTrigger( qe, f, nodes, keepAll, trOption, use_n_vars );
}
bool Trigger::isUsable( Node n, Node q ){
@@ -273,7 +284,7 @@ bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) {
return true;
}
}
- }else if( isAtomicTrigger( n1 ) && isUsable( n1, q ) ){
+ }else if( isUsableAtomicTrigger( n1, q ) ){
if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermDb::containsTerm( n1, n2 ) ){
return true;
}else if( !quantifiers::TermDb::hasInstConstAttr(n2) ){
@@ -328,24 +339,25 @@ Node Trigger::getIsUsableTrigger( Node n, Node q ) {
return rtr2;
}
}else{
- bool usable = quantifiers::TermDb::getInstConstAttr(n)==q && isAtomicTrigger( n ) && isUsable( n, q );
- Trace("trigger-debug") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==q) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
- if( usable ){
+ Trace("trigger-debug") << n << " usable : " << ( quantifiers::TermDb::getInstConstAttr(n)==q ) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
+ if( isUsableAtomicTrigger( n, q ) ){
return pol ? n : NodeManager::currentNM()->mkNode( IFF, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
}
}
return Node::null();
}
+bool Trigger::isUsableAtomicTrigger( Node n, Node q ) {
+ return quantifiers::TermDb::getInstConstAttr( n )==q && isAtomicTrigger( n ) && isUsable( n, q );
+}
+
bool Trigger::isUsableTrigger( Node n, Node q ){
Node nu = getIsUsableTrigger( n, q );
return !nu.isNull();
}
bool Trigger::isAtomicTrigger( Node n ){
- Kind k = n.getKind();
- return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
- ( k!=APPLY_UF && isAtomicTriggerKind( k ) );
+ return isAtomicTriggerKind( n.getKind() );
}
bool Trigger::isAtomicTriggerKind( Kind k ) {
@@ -363,8 +375,13 @@ bool Trigger::isRelationalTriggerKind( Kind k ) {
}
bool Trigger::isCbqiKind( Kind k ) {
- return quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ||
- k==APPLY_CONSTRUCTOR || k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER;
+ if( quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ){
+ return true;
+ }else{
+ //CBQI typically works for satisfaction-complete theories
+ TheoryId t = kindToTheoryId( k );
+ return t==THEORY_BV || t==THEORY_DATATYPES;
+ }
}
bool Trigger::isSimpleTrigger( Node n ){
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index 41f2a1c38..a3da4d398 100644..100755
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -76,6 +76,8 @@ class Trigger {
int addTerm( Node t );
/** return whether this is a multi-trigger */
bool isMultiTrigger() { return d_nodes.size()>1; }
+ /** get inst pattern list */
+ Node getInstPattern();
/** add all available instantiations exhaustively, in any equivalence class
if limitInst>0, limitInst is the max # of instantiations to try */
@@ -84,8 +86,6 @@ class Trigger {
ie : quantifier engine;
f : forall something ....
nodes : (multi-)trigger
- matchOption : which policy to use for creating matches
- (one of InstMatchGenerator::MATCH_GEN_* )
keepAll: don't remove unneeded patterns;
trOption : policy for dealing with triggers that already existed
(see below)
@@ -95,18 +95,19 @@ class Trigger {
TR_GET_OLD, //return a previous trigger if it had already been created
TR_RETURN_NULL //return null if a duplicate is found
};
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f,
- std::vector< Node >& nodes, int matchOption = 0,
- bool keepAll = true, int trOption = TR_MAKE_NEW );
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n,
- int matchOption = 0, bool keepAll = true,
- int trOption = TR_MAKE_NEW );
+ //nodes input, trNodes output
+ static bool mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes );
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes,
+ bool keepAll = true, int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 );
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll = true,
+ int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 );
static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt,
std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo,
bool filterInst = false );
/** is usable trigger */
static bool isUsableTrigger( Node n, Node q );
static Node getIsUsableTrigger( Node n, Node q );
+ static bool isUsableAtomicTrigger( Node n, Node q );
static bool isAtomicTrigger( Node n );
static bool isAtomicTriggerKind( Kind k );
static bool isRelationalTrigger( Node n );
@@ -135,7 +136,7 @@ class Trigger {
}
private:
/** trigger constructor */
- Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0 );
+ Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes );
/** is subterm of trigger usable */
static bool isUsable( Node n, Node q );
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 6d3b17254..d81efe1da 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -57,6 +57,7 @@ using namespace CVC4::theory::inst;
QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te):
d_te( te ),
+ d_conflict_c(c, false),
//d_quants(u),
d_quants_red(u),
d_lemmas_produced_c(u),
@@ -88,7 +89,6 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
d_tr_trie = new inst::TriggerTrie;
d_curr_effort_level = QEFFORT_NONE;
d_conflict = false;
- d_num_added_lemmas_round = 0;
d_hasAddedLemma = false;
//don't add true lemma
d_lemmas_produced_c[d_term_db->d_true] = true;
@@ -352,7 +352,7 @@ void QuantifiersEngine::check( Theory::Effort e ){
std::vector< QuantifiersModule* > qm;
if( d_model->checkNeeded() ){
needsCheck = needsCheck || e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
- for( int i=0; i<(int)d_modules.size(); i++ ){
+ for( unsigned i=0; i<d_modules.size(); i++ ){
if( d_modules[i]->needsCheck( e ) ){
qm.push_back( d_modules[i] );
needsCheck = true;
@@ -366,7 +366,6 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
d_conflict = false;
- d_num_added_lemmas_round = 0;
d_hasAddedLemma = false;
bool setIncomplete = false;
if( e==Theory::EFFORT_LAST_CALL ){
@@ -380,6 +379,8 @@ void QuantifiersEngine::check( Theory::Effort e ){
Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl;
if( needsCheck ){
+ //this will fail if a set of instances is marked as a conflict, but is not
+ Assert( !d_conflict_c.get() );
//flush previous lemmas (for instance, if was interupted), or other lemmas to process
flushLemmas();
if( d_hasAddedLemma ){
@@ -393,6 +394,12 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
d_recorded_inst.clear();
}
+
+ double clSet = 0;
+ if( Trace.isOn("quant-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("quant-engine") << ">>>>> Quantifiers Engine Round, effort = " << e << " <<<<<" << std::endl;
+ }
if( Trace.isOn("quant-engine-debug") ){
Trace("quant-engine-debug") << "Quantifiers Engine check, level = " << e << std::endl;
@@ -453,7 +460,6 @@ void QuantifiersEngine::check( Theory::Effort e ){
flushLemmas();
if( d_hasAddedLemma ){
return;
-
}
if( e==Theory::EFFORT_LAST_CALL ){
@@ -545,6 +551,13 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
}
+ if( Trace.isOn("quant-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("quant-engine") << "Finished quantifiers engine, total time = " << (clSet2-clSet);
+ Trace("quant-engine") << ", added lemma = " << d_hasAddedLemma;
+ Trace("quant-engine") << std::endl;
+ }
+
Trace("quant-engine-debug2") << "Finished quantifiers engine check." << std::endl;
}else{
Trace("quant-engine-debug2") << "Quantifiers Engine does not need check." << std::endl;
@@ -564,7 +577,7 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
if( setIncomplete ){
- Trace("quant-engine-debug") << "Set incomplete flag." << std::endl;
+ Trace("quant-engine") << "Set incomplete flag." << std::endl;
getOutputChannel().setIncomplete();
}
//output debug stats
@@ -621,6 +634,7 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
//check whether we should apply a reduction
if( reduceQuantifier( f ) ){
+ Trace("quant") << "...reduced." << std::endl;
d_quants[f] = false;
return false;
}else{
@@ -628,6 +642,7 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
d_term_db->makeInstantiationConstantsFor( f );
d_term_db->computeAttributes( f );
for( unsigned i=0; i<d_modules.size(); i++ ){
+ Trace("quant-debug") << "pre-register with " << d_modules[i]->identify() << "..." << std::endl;
d_modules[i]->preRegisterQuantifier( f );
}
QuantifiersModule * qm = getOwner( f );
@@ -640,11 +655,11 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
}
//register with each module
for( unsigned i=0; i<d_modules.size(); i++ ){
+ Trace("quant-debug") << "register with " << d_modules[i]->identify() << "..." << std::endl;
d_modules[i]->registerQuantifier( f );
}
+ //TODO: remove this
Node ceBody = d_term_db->getInstConstantBody( f );
- //generate the phase requirements
- //d_phase_reqs[f] = new QuantPhaseReq( ceBody, true );
//also register it with the strong solver
//if( options::finiteModelFind() ){
// ((uf::TheoryUF*)d_te->theoryOf( THEORY_UF ))->getStrongSolver()->registerQuantifier( f );
@@ -874,8 +889,9 @@ Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){
Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& vars, std::vector< Node >& terms, bool doVts ){
Node body;
+ Assert( vars.size()==terms.size() );
//process partial instantiation if necessary
- if( d_term_db->d_vars[q].size()!=vars.size() ){
+ if( q[0].getNumChildren()!=vars.size() ){
body = q[ 1 ].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
std::vector< Node > uninst_vars;
//doing a partial instantiation, must add quantifier for all uninstantiated variables
@@ -884,6 +900,8 @@ Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& vars, std
uninst_vars.push_back( q[0][i] );
}
}
+ Trace("partial-inst") << "Partially instantiating with " << vars.size() << " / " << q[0].getNumChildren() << " for " << q << std::endl;
+ Assert( !uninst_vars.empty() );
Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, uninst_vars );
body = NodeManager::currentNM()->mkNode( FORALL, bvl, body );
Trace("partial-inst") << "Partial instantiation : " << q << std::endl;
@@ -922,6 +940,7 @@ Node QuantifiersEngine::getInstantiation( Node q, InstMatch& m, bool doVts ){
}
Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& terms, bool doVts ) {
+ Assert( d_term_db->d_vars.find( q )!=d_term_db->d_vars.end() );
return getInstantiation( q, d_term_db->d_vars[q], terms, doVts );
}
@@ -956,7 +975,6 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
d_lemmas_produced_c[ lem ] = true;
d_lemmas_waiting.push_back( lem );
Trace("inst-add-debug") << "Added lemma" << std::endl;
- d_num_added_lemmas_round++;
return true;
}else{
Trace("inst-add-debug") << "Duplicate." << std::endl;
@@ -965,7 +983,6 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
}else{
//do not need to rewrite, will be rewritten after sending
d_lemmas_waiting.push_back( lem );
- d_num_added_lemmas_round++;
return true;
}
}
@@ -997,6 +1014,7 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
Assert( !d_conflict );
Assert( terms.size()==q[0].getNumChildren() );
Trace("inst-add-debug") << "For quantified formula " << q << ", add instantiation: " << std::endl;
+ std::vector< Node > rlv_cond;
for( unsigned i=0; i<terms.size(); i++ ){
Trace("inst-add-debug") << " " << q[0][i];
Trace("inst-add-debug2") << " -> " << terms[i];
@@ -1014,20 +1032,29 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
if( terms[i].isNull() ){
Trace("inst-add-debug") << " --> Failed to make term vector, due to term/type restrictions." << std::endl;
return false;
+ }else{
+ //get relevancy conditions
+ if( options::instRelevantCond() ){
+ quantifiers::TermDb::getRelevancyCondition( terms[i], rlv_cond );
+ }
}
#ifdef CVC4_ASSERTIONS
bool bad_inst = false;
if( quantifiers::TermDb::containsUninterpretedConstant( terms[i] ) ){
+ Trace("inst") << "***& inst contains uninterpreted constant : " << terms[i] << std::endl;
bad_inst = true;
}else if( !terms[i].getType().isSubtypeOf( q[0][i].getType() ) ){
+ Trace("inst") << "***& inst bad type : " << terms[i] << " " << terms[i].getType() << "/" << q[0][i].getType() << std::endl;
bad_inst = true;
}else if( options::cbqi() ){
Node icf = quantifiers::TermDb::getInstConstAttr(terms[i]);
if( !icf.isNull() ){
if( icf==q ){
+ Trace("inst") << "***& inst contains inst constant attr : " << terms[i] << std::endl;
+ bad_inst = true;
+ }else if( quantifiers::TermDb::containsTerms( terms[i], d_term_db->d_inst_constants[q] ) ){
+ Trace("inst") << "***& inst contains inst constants : " << terms[i] << std::endl;
bad_inst = true;
- }else{
- bad_inst = quantifiers::TermDb::containsTerms( terms[i], d_term_db->d_inst_constants[q] );
}
}
}
@@ -1079,13 +1106,21 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
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;
body = quantifiers::QuantifiersRewriter::preprocess( body, true );
Trace("inst-debug") << "...preprocess to " << body << std::endl;
//construct the lemma
Trace("inst-assert") << "(assert " << body << ")" << std::endl;
body = Rewriter::rewrite(body);
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, q.negate(), body );
+ Node lem;
+ if( rlv_cond.empty() ){
+ lem = NodeManager::currentNM()->mkNode( kind::OR, q.negate(), body );
+ }else{
+ rlv_cond.push_back( q.negate() );
+ rlv_cond.push_back( body );
+ lem = NodeManager::currentNM()->mkNode( kind::OR, rlv_cond );
+ }
lem = Rewriter::rewrite(lem);
//check for lemma duplication
@@ -1106,15 +1141,20 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
}
}
if( options::instMaxLevel()!=-1 ){
- uint64_t maxInstLevel = 0;
- for( unsigned i=0; i<terms.size(); i++ ){
- if( terms[i].hasAttribute(InstLevelAttribute()) ){
- if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
- maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
+ if( doVts ){
+ //virtual term substitution/instantiation level features are incompatible
+ Assert( false );
+ }else{
+ uint64_t maxInstLevel = 0;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ if( terms[i].hasAttribute(InstLevelAttribute()) ){
+ if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
+ maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
+ }
}
}
+ setInstantiationLevelAttr( orig_body, q[1], maxInstLevel+1 );
}
- setInstantiationLevelAttr( body, q[1], maxInstLevel+1 );
}
if( d_curr_effort_level>QEFFORT_CONFLICT && d_curr_effort_level<QEFFORT_NONE ){
//notify listeners
@@ -1122,6 +1162,7 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
if( !d_inst_notify[j]->notifyInstantiation( d_curr_effort_level, q, lem, terms, body ) ){
Trace("inst-add-debug") << "...we are in conflict." << std::endl;
d_conflict = true;
+ d_conflict_c = true;
Assert( !d_lemmas_waiting.empty() );
break;
}
@@ -1205,9 +1246,19 @@ quantifiers::UserPatMode QuantifiersEngine::getInstUserPatMode() {
void QuantifiersEngine::flushLemmas(){
if( !d_lemmas_waiting.empty() ){
+ //filter based on notify classes
+ if( !d_inst_notify.empty() ){
+ unsigned prev_lem_sz = d_lemmas_waiting.size();
+ for( unsigned j=0; j<d_inst_notify.size(); j++ ){
+ d_inst_notify[j]->filterInstantiations();
+ }
+ if( prev_lem_sz!=d_lemmas_waiting.size() ){
+ Trace("quant-engine") << "...filtered instances : " << d_lemmas_waiting.size() << " / " << prev_lem_sz << std::endl;
+ }
+ }
//take default output channel if none is provided
d_hasAddedLemma = true;
- for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
+ for( unsigned i=0; i<d_lemmas_waiting.size(); i++ ){
Trace("qe-lemma") << "Lemma : " << d_lemmas_waiting[i] << std::endl;
getOutputChannel().lemma( d_lemmas_waiting[i], false, true );
}
@@ -1403,7 +1454,7 @@ bool EqualityQueryQuantifiersEngine::processInferences( Theory::Effort e ) {
Trace("quant-engine-ee-proc") << " explanation : " << eq_exp << std::endl;
Assert( ee->hasTerm( eq[0] ) );
Assert( ee->hasTerm( eq[1] ) );
- if( ee->areDisequal( eq[0], eq[1], false ) ){
+ if( areDisequal( eq[0], eq[1] ) ){
Trace("quant-engine-ee-proc") << "processInferences : Conflict : " << eq << std::endl;
if( Trace.isOn("term-db-lemma") ){
Trace("term-db-lemma") << "Disequal terms, equal by normalization : " << eq[0] << " " << eq[1] << "!!!!" << std::endl;
@@ -1445,11 +1496,10 @@ bool EqualityQueryQuantifiersEngine::areEqual( Node a, Node b ){
}else{
eq::EqualityEngine* ee = getEngine();
if( ee->hasTerm( a ) && ee->hasTerm( b ) ){
- if( ee->areEqual( a, b ) ){
- return true;
- }
+ return ee->areEqual( a, b );
+ }else{
+ return false;
}
- return false;
}
}
@@ -1459,11 +1509,10 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){
}else{
eq::EqualityEngine* ee = getEngine();
if( ee->hasTerm( a ) && ee->hasTerm( b ) ){
- if( ee->areDisequal( a, b, false ) ){
- return true;
- }
+ return ee->areDisequal( a, b, false );
+ }else{
+ return a.isConst() && b.isConst();
}
- return false;
}
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 4ee66f9e7..1f4a04218 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -48,6 +48,7 @@ class InstantiationNotify {
public:
InstantiationNotify(){}
virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) = 0;
+ virtual void filterInstantiations() = 0;
};
namespace quantifiers {
@@ -156,8 +157,7 @@ private: //this information is reset during check
unsigned d_curr_effort_level;
/** are we in conflict */
bool d_conflict;
- /** number of lemmas we actually added this round (for debugging) */
- unsigned d_num_added_lemmas_round;
+ context::CDO< bool > d_conflict_c;
/** has added lemma this round */
bool d_hasAddedLemma;
private:
@@ -295,9 +295,9 @@ private:
bool removeInstantiationInternal( Node q, std::vector< Node >& terms );
/** set instantiation level attr */
static void setInstantiationLevelAttr( Node n, Node qn, uint64_t level );
+public:
/** flush lemmas */
void flushLemmas();
-public:
/** get instantiation */
Node getInstantiation( Node q, std::vector< Node >& vars, std::vector< Node >& terms, bool doVts = false );
/** get instantiation */
@@ -330,8 +330,6 @@ public:
bool inConflict() { return d_conflict; }
/** get number of waiting lemmas */
unsigned getNumLemmasWaiting() { return d_lemmas_waiting.size(); }
- /** get number of waiting lemmas */
- unsigned getNumLemmasAddedThisRound() { return d_num_added_lemmas_round; }
/** get needs check */
bool getInstWhenNeedsCheck( Theory::Effort e );
/** get user pat mode */
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index d7178a8c1..184553ba7 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -127,19 +127,11 @@ int RepSet::getNumRelevantGroundReps( TypeNode t ) {
}
void RepSet::toStream(std::ostream& out){
-#if 0
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- out << it->first << " : " << std::endl;
- for( int i=0; i<(int)it->second.size(); i++ ){
- out << " " << i << ": " << it->second[i] << std::endl;
- }
- }
-#else
for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
if( !it->first.isFunction() && !it->first.isPredicate() ){
out << "(" << it->first << " " << it->second.size();
out << " (";
- for( int i=0; i<(int)it->second.size(); i++ ){
+ for( unsigned i=0; i<it->second.size(); i++ ){
if( i>0 ){ out << " "; }
out << it->second[i];
}
@@ -147,7 +139,6 @@ void RepSet::toStream(std::ostream& out){
out << ")" << std::endl;
}
}
-#endif
}
@@ -157,10 +148,11 @@ RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe),
int RepSetIterator::domainSize( int i ) {
Assert(i>=0);
- if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){
- return d_domain[i].size();
+ int v = d_var_order[i];
+ if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
+ return d_domain[v].size();
}else{
- return d_domain[i][0];
+ return d_domain[v][0];
}
}
@@ -188,15 +180,15 @@ bool RepSetIterator::setFunctionDomain( Node op ){
bool RepSetIterator::initialize(){
Trace("rsi") << "Initialize rep set iterator..." << std::endl;
- for( size_t i=0; i<d_types.size(); i++ ){
+ for( unsigned v=0; v<d_types.size(); v++ ){
d_index.push_back( 0 );
//store default index order
- d_index_order.push_back( i );
- d_var_order[i] = i;
+ d_index_order.push_back( v );
+ d_var_order[v] = v;
//store default domain
d_domain.push_back( RepDomain() );
- TypeNode tn = d_types[i];
- Trace("rsi") << "Var #" << i << " is type " << tn << "..." << std::endl;
+ TypeNode tn = d_types[v];
+ Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl;
if( tn.isSort() ){
//must ensure uninterpreted type is non-empty.
if( !d_rep_set->hasType( tn ) ){
@@ -209,59 +201,59 @@ bool RepSetIterator::initialize(){
Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
d_rep_set->add( tn, var );
}
- }else if( tn.isInteger() ){
- bool inc = false;
- //check if it is bound
+ }else{
+ bool inc = true;
+ //check if it is bound by bounded integer module
if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
- if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
+ unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
+ if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
Trace("rsi") << " variable is bounded integer." << std::endl;
- d_enum_type.push_back( ENUM_RANGE );
- }else{
- inc = true;
+ d_enum_type.push_back( ENUM_INT_RANGE );
+ inc = false;
+ }else if( bvt==quantifiers::BoundedIntegers::BOUND_SET_MEMBER ){
+ Trace("rsi") << " variable is bounded by set membership." << std::endl;
+ d_enum_type.push_back( ENUM_SET_MEMBERS );
+ inc = false;
}
- }else{
- inc = true;
}
if( inc ){
//check if it is otherwise bound
- if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){
+ if( d_bounds[0].find( v )!=d_bounds[0].end() && d_bounds[1].find( v )!=d_bounds[1].end() ){
Trace("rsi") << " variable is bounded." << std::endl;
- d_enum_type.push_back( ENUM_RANGE );
+ d_enum_type.push_back( ENUM_INT_RANGE );
+ }else if( d_qe->getTermDatabase()->mayComplete( tn ) ){
+ Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
+ d_rep_set->complete( tn );
+ //must have succeeded
+ Assert( d_rep_set->hasType( tn ) );
}else{
Trace("rsi") << " variable cannot be bounded." << std::endl;
- Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
+ Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
d_incomplete = true;
}
}
- //enumerate if the sort is reasonably small
- }else if( d_qe->getTermDatabase()->mayComplete( tn ) ){
- Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
- d_rep_set->complete( tn );
- //must have succeeded
- Assert( d_rep_set->hasType( tn ) );
- }else{
- Trace("rsi") << " variable cannot be bounded." << std::endl;
- Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
- d_incomplete = true;
}
//if we have yet to determine the type of enumeration
- if( d_enum_type.size()<=i ){
+ if( d_enum_type.size()<=v ){
d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
if( d_rep_set->hasType( tn ) ){
- for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
- d_domain[i].push_back( j );
+ for( unsigned j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
+ d_domain[v].push_back( j );
}
}else{
+ Assert( d_incomplete );
return false;
}
}
}
//must set a variable index order based on bounded integers
- if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) {
+ if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
std::vector< int > varOrder;
- for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){
- varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i));
+ for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars( d_owner ); i++ ){
+ Node v = d_qe->getBoundedIntegers()->getBoundVar( d_owner, i );
+ Trace("bound-int-rsi") << " bound var #" << i << " is " << v << std::endl;
+ varOrder.push_back( d_qe->getTermDatabase()->getVariableNum( d_owner, v ) );
}
for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
@@ -283,14 +275,10 @@ bool RepSetIterator::initialize(){
Trace("bound-int-rsi") << indexOrder[i] << " ";
}
Trace("bound-int-rsi") << std::endl;
- setIndexOrder(indexOrder);
+ setIndexOrder( indexOrder );
}
//now reset the indices
- for (unsigned i=0; i<d_index.size(); i++) {
- if (!resetIndex(i, true)){
- break;
- }
- }
+ do_reset_increment( -1, true );
return true;
}
@@ -298,46 +286,40 @@ void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
d_index_order.clear();
d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
//make the d_var_order mapping
- for( int i=0; i<(int)d_index_order.size(); i++ ){
+ for( unsigned i=0; i<d_index_order.size(); i++ ){
d_var_order[d_index_order[i]] = i;
}
}
-/*
-void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
- d_domain.clear();
- d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
- //we are done if a domain is empty
- for( int i=0; i<(int)d_domain.size(); i++ ){
- if( d_domain[i].empty() ){
- d_index.clear();
- }
- }
-}
-*/
-bool RepSetIterator::resetIndex( int i, bool initial ) {
+
+int RepSetIterator::resetIndex( int i, bool initial ) {
d_index[i] = 0;
- int ii = d_index_order[i];
- Trace("bound-int-rsi") << "Reset " << i << " " << ii << " " << initial << std::endl;
+ int v = d_var_order[i];
+ Trace("bound-int-rsi") << "Reset " << i << ", var order = " << v << ", initial = " << initial << std::endl;
//determine the current range
- if( d_enum_type[ii]==ENUM_RANGE ){
- if( initial || ( d_qe->getBoundedIntegers() && !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][ii] ) ) ){
- Trace("bound-int-rsi") << "Getting range of " << d_owner[0][ii] << std::endl;
+ if( initial || ( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() &&
+ d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) &&
+ !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][v] ) ) ){
+ Trace("bound-int-rsi") << "Getting range of " << d_owner[0][v] << std::endl;
+ if( d_enum_type[v]==ENUM_INT_RANGE ){
Node actual_l;
Node l, u;
- if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
- d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][ii], this, l, u );
+ if( d_qe->getBoundedIntegers() ){
+ unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
+ if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
+ d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][v], this, l, u );
+ }
}
for( unsigned b=0; b<2; b++ ){
- if( d_bounds[b].find(ii)!=d_bounds[b].end() ){
- Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][ii] << std::endl;
- if( b==0 && (l.isNull() || d_bounds[b][ii].getConst<Rational>() > l.getConst<Rational>()) ){
+ if( d_bounds[b].find(v)!=d_bounds[b].end() ){
+ Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][v] << std::endl;
+ if( b==0 && (l.isNull() || d_bounds[b][v].getConst<Rational>() > l.getConst<Rational>()) ){
if( !l.isNull() ){
//bound was limited externally, record that the value lower bound is not equal to the term lower bound
- actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii], l );
+ actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v], l );
}
- l = d_bounds[b][ii];
- }else if( b==1 && (u.isNull() || d_bounds[b][ii].getConst<Rational>() <= u.getConst<Rational>()) ){
- u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii],
+ l = d_bounds[b][v];
+ }else if( b==1 && (u.isNull() || d_bounds[b][v].getConst<Rational>() <= u.getConst<Rational>()) ){
+ u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v],
NodeManager::currentNM()->mkConst( Rational(1) ) );
u = Rewriter::rewrite( u );
}
@@ -346,73 +328,109 @@ bool RepSetIterator::resetIndex( int i, bool initial ) {
if( l.isNull() || u.isNull() ){
//failed, abort the iterator
- d_index.clear();
- return false;
+ return -1;
}else{
- Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " to " << l << "..." << u << std::endl;
+ Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][v] << " to " << l << "..." << u << std::endl;
Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
- d_domain[ii].clear();
+ d_domain[v].clear();
Node tl = l;
Node tu = u;
- if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
- d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][ii], this, tl, tu );
+ if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) ){
+ d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][v], this, tl, tu );
}
- d_lower_bounds[ii] = tl;
+ d_lower_bounds[v] = tl;
if( !actual_l.isNull() ){
//if bound was limited externally, must consider the offset
- d_lower_bounds[ii] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
+ d_lower_bounds[v] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
}
- if( ra==NodeManager::currentNM()->mkConst(true) ){
+ if( ra==d_qe->getTermDatabase()->d_true ){
long rr = range.getConst<Rational>().getNumerator().getLong()+1;
Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl;
- d_domain[ii].push_back( (int)rr );
+ d_domain[v].push_back( (int)rr );
+ if( rr<=0 ){
+ return 0;
+ }
}else{
- Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][ii] << "." << std::endl;
- d_incomplete = true;
- d_domain[ii].push_back( 0 );
+ Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][v] << "." << std::endl;
+ return -1;
}
}
- }else{
- Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl;
+ }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
+ Assert( d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] )==quantifiers::BoundedIntegers::BOUND_SET_MEMBER );
+ Node srv = d_qe->getBoundedIntegers()->getSetRangeValue( d_owner, d_owner[0][v], this );
+ if( srv.isNull() ){
+ return -1;
+ }
+ Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
+ d_domain[v].clear();
+ d_setm_bounds[v].clear();
+ if( srv.getKind()!=EMPTYSET ){
+ //TODO: need term model, not value model
+ while( srv.getKind()==UNION ){
+ Assert( srv[1].getKind()==kind::SINGLETON );
+ d_setm_bounds[v].push_back( srv[1][0] );
+ srv = srv[0];
+ }
+ d_setm_bounds[v].push_back( srv[0] );
+ d_domain[v].push_back( d_setm_bounds[v].size() );
+ }else{
+ d_domain[v].push_back( 0 );
+ return 0;
+ }
}
}
- return true;
+ return 1;
}
-int RepSetIterator::increment2( int counter ){
+int RepSetIterator::increment2( int i ){
Assert( !isFinished() );
#ifdef DISABLE_EVAL_SKIP_MULTIPLE
- counter = (int)d_index.size()-1;
+ i = (int)d_index.size()-1;
#endif
//increment d_index
- if( counter>=0){
- Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ if( i>=0){
+ Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
}
- while( counter>=0 && d_index[counter]>=(int)(domainSize(counter)-1) ){
- counter--;
- if( counter>=0){
- Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ while( i>=0 && d_index[i]>=(int)(domainSize(i)-1) ){
+ i--;
+ if( i>=0){
+ Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
}
}
- if( counter==-1 ){
+ if( i==-1 ){
d_index.clear();
+ return -1;
}else{
- d_index[counter]++;
- bool emptyDomain = false;
- for( int i=(int)d_index.size()-1; i>counter; i-- ){
- if (!resetIndex(i)){
- break;
- }else if( domainSize(i)<=0 ){
- emptyDomain = true;
- }
+ Trace("rsi-debug") << "increment " << i << std::endl;
+ d_index[i]++;
+ return do_reset_increment( i );
+ }
+}
+
+int RepSetIterator::do_reset_increment( int i, bool initial ) {
+ bool emptyDomain = false;
+ for( unsigned ii=(i+1); ii<d_index.size(); ii++ ){
+ int ri_res = resetIndex( ii, initial );
+ if( ri_res==-1 ){
+ //failed
+ d_index.clear();
+ d_incomplete = true;
+ break;
+ }else if( ri_res==0 ){
+ emptyDomain = true;
}
+ //force next iteration if currently an empty domain
if( emptyDomain ){
- Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl;
- return increment();
+ d_index[ii] = domainSize(ii)-1;
}
}
- return counter;
+ if( emptyDomain ){
+ Trace("rsi-debug") << "This is an empty domain, increment." << std::endl;
+ return increment();
+ }else{
+ return i;
+ }
}
int RepSetIterator::increment(){
@@ -427,33 +445,38 @@ bool RepSetIterator::isFinished(){
return d_index.empty();
}
-Node RepSetIterator::getTerm( int i ){
- Trace("rsi-debug") << "rsi : get term " << i << ", index order = " << d_index_order[i] << std::endl;
- //int index = d_index_order[i];
- int index = i;
- if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){
- TypeNode tn = d_types[index];
+Node RepSetIterator::getCurrentTerm( int v ){
+ Trace("rsi-debug") << "rsi : get term " << v << ", index order = " << d_index_order[v] << std::endl;
+ int ii = d_index_order[v];
+ int curr = d_index[ii];
+ if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
+ TypeNode tn = d_types[v];
Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
- return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
+ Assert( 0<=d_domain[v][curr] && d_domain[v][curr]<(int)d_rep_set->d_type_reps[tn].size() );
+ return d_rep_set->d_type_reps[tn][d_domain[v][curr]];
+ }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
+ Assert( 0<=curr && curr<(int)d_setm_bounds[v].size() );
+ return d_setm_bounds[v][curr];
}else{
- Trace("rsi-debug") << "Get, with offset : " << index << " " << d_lower_bounds[index] << " " << d_index[index] << std::endl;
- Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[index],
- NodeManager::currentNM()->mkConst( Rational(d_index[index]) ) );
+ Trace("rsi-debug") << "Get, with offset : " << v << " " << d_lower_bounds[v] << " " << curr << std::endl;
+ Assert( !d_lower_bounds[v].isNull() );
+ Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[v], NodeManager::currentNM()->mkConst( Rational(curr) ) );
t = Rewriter::rewrite( t );
return t;
}
}
void RepSetIterator::debugPrint( const char* c ){
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;
+ for( unsigned v=0; v<d_index.size(); v++ ){
+ Debug( c ) << v << " : " << getCurrentTerm( v ) << std::endl;
}
}
void RepSetIterator::debugPrintSmall( const char* c ){
Debug( c ) << "RI: ";
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";
+ for( unsigned v=0; v<d_index.size(); v++ ){
+ Debug( c ) << v << ": " << getCurrentTerm( v ) << " ";
}
Debug( c ) << std::endl;
}
+
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 08fc7dd52..ee927de86 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -64,22 +64,42 @@ class RepSetIterator {
public:
enum {
ENUM_DOMAIN_ELEMENTS,
- ENUM_RANGE,
+ ENUM_INT_RANGE,
+ ENUM_SET_MEMBERS,
};
private:
QuantifiersEngine * d_qe;
//initialize function
bool initialize();
- //for enum ranges
+ //for int ranges
std::map< int, Node > d_lower_bounds;
+ //for set ranges
+ std::map< int, std::vector< Node > > d_setm_bounds;
//domain size
int domainSize( int i );
//node this is rep set iterator is for
Node d_owner;
- //reset index
- bool resetIndex( int i, bool initial = false );
+ //reset index, 1:success, 0:empty, -1:fail
+ int resetIndex( int i, bool initial = false );
/** set index order */
void setIndexOrder( std::vector< int >& indexOrder );
+ /** do reset increment the iterator at index=counter */
+ int do_reset_increment( int counter, bool initial = false );
+ //ordering for variables we are indexing over
+ // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
+ // then we consider instantiations in this order:
+ // a/x a/y a/z
+ // a/x b/y a/z
+ // b/x a/y a/z
+ // b/x b/y a/z
+ // ...
+ std::vector< int > d_index_order;
+ //variables to index they are considered at
+ // for example, if d_index_order = { 2, 0, 1 }
+ // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
+ std::map< int, int > d_var_order;
+ //are we only considering a strict subset of the domain of the quantifier?
+ bool d_incomplete;
public:
RepSetIterator( QuantifiersEngine * qe, RepSet* rs );
~RepSetIterator(){}
@@ -92,43 +112,34 @@ public:
RepSet* d_rep_set;
//enumeration type?
std::vector< int > d_enum_type;
- //index we are considering
+ //current tuple we are considering
std::vector< int > d_index;
//types we are considering
std::vector< TypeNode > d_types;
//domain we are considering
std::vector< RepDomain > d_domain;
- //are we only considering a strict subset of the domain of the quantifier?
- bool d_incomplete;
- //ordering for variables we are indexing over
- // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
- // then we consider instantiations in this order:
- // a/x a/y a/z
- // a/x b/y a/z
- // b/x a/y a/z
- // b/x b/y a/z
- // ...
- std::vector< int > d_index_order;
- //variables to index they are considered at
- // for example, if d_index_order = { 2, 0, 1 }
- // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
- std::map< int, int > d_var_order;
//intervals
std::map< int, Node > d_bounds[2];
public:
/** increment the iterator at index=counter */
- int increment2( int counter );
+ int increment2( int i );
/** increment the iterator */
int increment();
/** is the iterator finished? */
bool isFinished();
/** get the i_th term we are considering */
- Node getTerm( int i );
+ Node getCurrentTerm( int v );
/** get the number of terms we are considering */
int getNumTerms() { return (int)d_index_order.size(); }
/** debug print */
void debugPrint( const char* c );
void debugPrintSmall( const char* c );
+ //get index order, returns var #
+ int getIndexOrder( int v ) { return d_index_order[v]; }
+ //get variable order, returns index #
+ int getVariableOrder( int i ) { return d_var_order[i]; }
+ //is incomplete
+ bool isIncomplete() { return d_incomplete; }
};/* class RepSetIterator */
}/* CVC4::theory namespace */
diff --git a/src/theory/sep/kinds b/src/theory/sep/kinds
new file mode 100644
index 000000000..6c4ad33db
--- /dev/null
+++ b/src/theory/sep/kinds
@@ -0,0 +1,37 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+theory THEORY_SEP ::CVC4::theory::sep::TheorySep "theory/sep/theory_sep.h"
+typechecker "theory/sep/theory_sep_type_rules.h"
+
+properties polite stable-infinite parametric
+properties check propagate presolve getNextDecisionRequest
+
+rewriter ::CVC4::theory::sep::TheorySepRewriter "theory/sep/theory_sep_rewriter.h"
+
+# constants
+constant SEP_NIL_REF \
+ ::CVC4::NilRef \
+ ::CVC4::NilRefHashFunction \
+ "expr/sepconst.h" \
+ "the nil reference constant; payload is an instance of the CVC4::NilRef class"
+
+variable SEP_NIL "separation nil"
+
+operator SEP_EMP 1 "separation empty heap"
+operator SEP_PTO 2 "points to relation"
+operator SEP_STAR 2: "separation star"
+operator SEP_WAND 2 "separation magic wand"
+operator SEP_LABEL 2 "separation label"
+
+typerule SEP_NIL_REF ::CVC4::theory::sep::SepNilRefTypeRule
+typerule SEP_EMP ::CVC4::theory::sep::SepEmpTypeRule
+typerule SEP_PTO ::CVC4::theory::sep::SepPtoTypeRule
+typerule SEP_STAR ::CVC4::theory::sep::SepStarTypeRule
+typerule SEP_WAND ::CVC4::theory::sep::SepWandTypeRule
+typerule SEP_LABEL ::CVC4::theory::sep::SepLabelTypeRule
+
+endtheory
diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp
new file mode 100644
index 000000000..836a04afa
--- /dev/null
+++ b/src/theory/sep/theory_sep.cpp
@@ -0,0 +1,1534 @@
+/********************* */
+/*! \file theory_sep.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of the theory of sep.
+ **
+ ** Implementation of the theory of sep.
+ **/
+
+
+#include "theory/sep/theory_sep.h"
+#include "theory/valuation.h"
+#include "expr/kind.h"
+#include <map>
+#include "theory/rewriter.h"
+#include "theory/theory_model.h"
+#include "options/sep_options.h"
+#include "options/smt_options.h"
+#include "smt/logic_exception.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+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_notify(*this),
+ d_equalityEngine(d_notify, c, "theory::sep::TheorySep", true),
+ d_conflict(c, false),
+ d_reduce(u),
+ d_infer(c),
+ d_infer_exp(c),
+ d_spatial_assertions(c)
+{
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::SEP_PTO);
+ //d_equalityEngine.addFunctionKind(kind::SEP_STAR);
+}
+
+TheorySep::~TheorySep() {
+ for( std::map< Node, HeapAssertInfo * >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){
+ delete it->second;
+ }
+}
+
+void TheorySep::setMasterEqualityEngine(eq::EqualityEngine* eq) {
+ d_equalityEngine.setMasterEqualityEngine(eq);
+}
+
+Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) {
+ if( assumptions.empty() ){
+ return d_true;
+ }else if( assumptions.size()==1 ){
+ return assumptions[0];
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::AND, assumptions );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// PREPROCESSING
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+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 ) {
+ 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_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;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// T-PROPAGATION / REGISTRATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+bool TheorySep::propagate(TNode literal)
+{
+ Debug("sep") << "TheorySep::propagate(" << literal << ")" << std::endl;
+ // If already in conflict, no more propagation
+ if (d_conflict) {
+ Debug("sep") << "TheorySep::propagate(" << literal << "): already in conflict" << std::endl;
+ return false;
+ }
+ bool ok = d_out->propagate(literal);
+ if (!ok) {
+ d_conflict = true;
+ }
+ return ok;
+}/* TheorySep::propagate(TNode) */
+
+
+void TheorySep::explain(TNode literal, std::vector<TNode>& assumptions) {
+ if( literal.getKind()==kind::SEP_LABEL ||
+ ( literal.getKind()==kind::NOT && literal[0].getKind()==kind::SEP_LABEL ) ){
+ //labelled assertions are never given to equality engine and should only come from the outside
+ assumptions.push_back( literal );
+ }else{
+ // Do the work
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+ if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+ d_equalityEngine.explainEquality( atom[0], atom[1], polarity, assumptions, NULL );
+ } else {
+ d_equalityEngine.explainPredicate( atom, polarity, 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;
+ d_nil_ref[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){
+
+}
+
+
+Node TheorySep::explain(TNode literal)
+{
+ Debug("sep") << "TheorySep::explain(" << literal << ")" << std::endl;
+ std::vector<TNode> assumptions;
+ explain(literal, assumptions);
+ return mkAnd(assumptions);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// SHARING
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::addSharedTerm(TNode t) {
+ Debug("sep") << "TheorySep::addSharedTerm(" << t << ")" << std::endl;
+ d_equalityEngine.addTriggerTerm(t, THEORY_SEP);
+}
+
+
+EqualityStatus TheorySep::getEqualityStatus(TNode a, TNode b) {
+ Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ else if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
+}
+
+
+void TheorySep::computeCareGraph() {
+ Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl;
+ for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) {
+ TNode a = d_sharedTerms[i];
+ TypeNode aType = a.getType();
+ for (unsigned j = i + 1; j < d_sharedTerms.size(); ++ j) {
+ TNode b = d_sharedTerms[j];
+ if (b.getType() != aType) {
+ // We don't care about the terms of different types
+ continue;
+ }
+ switch (d_valuation.getEqualityStatus(a, b)) {
+ case EQUALITY_TRUE_AND_PROPAGATED:
+ case EQUALITY_FALSE_AND_PROPAGATED:
+ // If we know about it, we should have propagated it, so we can skip
+ break;
+ default:
+ // Let's split on it
+ addCarePair(a, b);
+ break;
+ }
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// MODEL GENERATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel )
+{
+ // Send the equality engine information to the model
+ m->assertEqualityEngine( &d_equalityEngine );
+
+ if( fullModel ){
+ for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){
+ Trace("sep-model") << "; 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;
+ }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 );
+ Node l = d_label_model[it->second].d_heap_locs_model[j][0];
+ Trace("sep-model") << "; " << l << " -> ";
+ if( d_pto_model[l].isNull() ){
+ Trace("sep-model") << "_";
+ }else{
+ Trace("sep-model") << d_pto_model[l];
+ }
+ Trace("sep-model") << std::endl;
+ }
+ }
+ Node nil = getNilRef( it->first );
+ Node vnil = d_valuation.getModel()->getRepresentative( nil );
+ Trace("sep-model") << "; sep.nil = " << vnil << std::endl;
+ Trace("sep-model") << std::endl;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NOTIFICATIONS
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::presolve() {
+ Trace("sep-pp") << "Presolving" << std::endl;
+ //TODO: cleanup if incremental?
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// MAIN SOLVER
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::check(Effort e) {
+ if (done() && !fullEffort(e) && e != EFFORT_LAST_CALL) {
+ return;
+ }
+
+ getOutputChannel().spendResource(options::theoryCheckStep());
+
+ TimerStat::CodeTimer checkTimer(d_checkTime);
+ Trace("sep-check") << "Sep::check(): " << e << endl;
+
+ while( !done() && !d_conflict ){
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+
+ Trace("sep-assert") << "TheorySep::check(): processing " << fact << std::endl;
+
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if( atom.getKind()==kind::SEP_EMP ){
+ TypeNode tn = atom[0].getType();
+ if( d_emp_arg.find( tn )==d_emp_arg.end() ){
+ d_emp_arg[tn] = atom[0];
+ }else{
+ //normalize argument TODO
+ }
+ }
+ TNode s_atom = atom.getKind()==kind::SEP_LABEL ? atom[0] : atom;
+ TNode s_lbl = atom.getKind()==kind::SEP_LABEL ? atom[1] : TNode::null();
+ bool is_spatial = s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_PTO || s_atom.getKind()==kind::SEP_EMP;
+ if( is_spatial && s_lbl.isNull() ){
+ if( d_reduce.find( fact )==d_reduce.end() ){
+ 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;
+ Node b_lbl = getBaseLabel( refType );
+ Node s_atom_new = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, s_atom, b_lbl );
+ Node lem;
+ if( polarity ){
+ lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom.negate(), s_atom_new );
+ }else{
+ lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom, s_atom_new.negate() );
+ }
+ Trace("sep-lemma-debug") << "Sep::Lemma : base reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
+ }else{
+ //do reductions
+ if( is_spatial ){
+ if( d_reduce.find( fact )==d_reduce.end() ){
+ Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl;
+ d_reduce.insert( fact );
+ Node conc;
+ std::map< Node, Node >::iterator its = d_red_conc[s_lbl].find( s_atom );
+ if( its==d_red_conc[s_lbl].end() ){
+ //make conclusion based on type of assertion
+ 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 );
+ 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()));
+ Assert( children.size()>1 );
+ if( s_atom.getKind()==kind::SEP_STAR ){
+ //reduction for heap : union, pairwise disjoint
+ Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, labels[0], labels[1] );
+ for( unsigned i=2; i<labels.size(); i++ ){
+ ulem = NodeManager::currentNM()->mkNode( kind::UNION, ulem, labels[i] );
+ }
+ ulem = s_lbl.eqNode( ulem );
+ Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, union : " << ulem << std::endl;
+ c_lems.push_back( ulem );
+ for( unsigned i=0; i<labels.size(); i++ ){
+ for( unsigned j=(i+1); j<labels.size(); j++ ){
+ Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, labels[i], labels[j] );
+ Node ilem = s.eqNode( empSet );
+ Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, disjoint : " << ilem << std::endl;
+ c_lems.push_back( ilem );
+ }
+ }
+ }else{
+ Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, s_lbl, labels[0] );
+ ulem = ulem.eqNode( labels[1] );
+ Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, union : " << ulem << std::endl;
+ c_lems.push_back( ulem );
+ Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, s_lbl, labels[0] );
+ Node ilem = s.eqNode( empSet );
+ Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl;
+ c_lems.push_back( ilem );
+ }
+ //send out definitional lemmas for introduced sets
+ for( unsigned j=0; j<c_lems.size(); j++ ){
+ Trace("sep-lemma") << "Sep::Lemma : definition : " << c_lems[j] << std::endl;
+ d_out->lemma( c_lems[j] );
+ }
+ //children.insert( children.end(), c_lems.begin(), c_lems.end() );
+ conc = NodeManager::currentNM()->mkNode( kind::AND, children );
+ }else if( s_atom.getKind()==kind::SEP_PTO ){
+ Node ss = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] );
+ if( s_lbl!=ss ){
+ conc = s_lbl.eqNode( ss );
+ }
+ Node ssn = NodeManager::currentNM()->mkNode( kind::EQUAL, s_atom[0], getNilRef(s_atom[0].getType()) ).negate();
+ conc = conc.isNull() ? ssn : NodeManager::currentNM()->mkNode( kind::AND, conc, ssn );
+ }else{
+ //labeled emp should be rewritten
+ Assert( false );
+ }
+ d_red_conc[s_lbl][s_atom] = conc;
+ }else{
+ conc = its->second;
+ }
+ if( !conc.isNull() ){
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( !use_polarity ){
+ // introduce guard, assert positive version
+ Trace("sep-lemma-debug") << "Negated spatial constraint asserted to sep theory: " << fact << std::endl;
+ Node lit = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+ lit = getValuation().ensureLiteral( lit );
+ d_neg_guard[s_lbl][s_atom] = lit;
+ Trace("sep-lemma-debug") << "Neg guard : " << s_lbl << " " << s_atom << " " << lit << std::endl;
+ AlwaysAssert( !lit.isNull() );
+ d_out->requirePhase( lit, true );
+ d_neg_guards.push_back( lit );
+ d_guard_to_assertion[lit] = s_atom;
+ //Node lem = NodeManager::currentNM()->mkNode( kind::IFF, lit, conc );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit.negate(), conc );
+ Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }else{
+ //reduce based on implication
+ Node ant = atom;
+ if( polarity ){
+ ant = atom.negate();
+ }
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, ant, conc );
+ Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
+ }else{
+ Trace("sep-lemma-debug") << "Trivial conclusion, do not add lemma." << std::endl;
+ }
+ }
+ }
+ //assert to equality engine
+ if( !is_spatial ){
+ Trace("sep-assert") << "Asserting " << atom << ", pol = " << polarity << " to EE..." << std::endl;
+ if( s_atom.getKind()==kind::EQUAL ){
+ d_equalityEngine.assertEquality(atom, polarity, fact);
+ }else{
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ }
+ 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;
+ }
+ //associate the equivalence class of the lhs with this pto
+ Node r = getRepresentative( s_lbl );
+ HeapAssertInfo * ei = getOrMakeEqcInfo( r, true );
+ addPto( ei, r, atom, polarity );
+ }
+ //maybe propagate
+ doPendingFacts();
+ //add to spatial assertions
+ if( !d_conflict && is_spatial ){
+ d_spatial_assertions.push_back( fact );
+ }
+ }
+ }
+
+ if( e == EFFORT_LAST_CALL && !d_conflict && !d_valuation.needCheck() ){
+ Trace("sep-process") << "Checking heap at full effort..." << std::endl;
+ d_label_model.clear();
+ d_tmodel.clear();
+ d_pto_model.clear();
+ Trace("sep-process") << "---Locations---" << std::endl;
+ 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];
+ Trace("sep-process") << " " << t << " = ";
+ if( d_valuation.getModel()->hasTerm( t ) ){
+ Node v = d_valuation.getModel()->getRepresentative( t );
+ Trace("sep-process") << v << std::endl;
+ d_tmodel[v] = t;
+ }else{
+ Trace("sep-process") << "?" << std::endl;
+ }
+ }
+ }
+ Trace("sep-process") << "---" << std::endl;
+ //build positive/negative assertion lists for labels
+ std::map< Node, bool > assert_active;
+ //get the inactive assertions
+ std::map< Node, std::vector< Node > > lbl_to_assertions;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ lbl_to_assertions[s_lbl].push_back( fact );
+ //check whether assertion is active : either polarity=true, or guard is not asserted false
+ assert_active[fact] = true;
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( use_polarity ){
+ if( s_atom.getKind()==kind::SEP_PTO ){
+ Node vv = d_valuation.getModel()->getRepresentative( s_atom[0] );
+ if( d_pto_model.find( vv )==d_pto_model.end() ){
+ Trace("sep-inst") << "Pto : " << s_atom[0] << " (" << vv << ") -> " << s_atom[1] << std::endl;
+ d_pto_model[vv] = s_atom[1];
+ }
+ }
+ }else{
+ if( d_neg_guard[s_lbl].find( s_atom )!=d_neg_guard[s_lbl].end() ){
+ //check if the guard is asserted positively
+ Node guard = d_neg_guard[s_lbl][s_atom];
+ bool value;
+ if( getValuation().hasSatValue( guard, value ) ) {
+ assert_active[fact] = value;
+ }
+ }
+ }
+ }
+ //(recursively) set inactive sub-assertions
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ if( !assert_active[fact] ){
+ setInactiveAssertionRec( fact, lbl_to_assertions, assert_active );
+ }
+ }
+ //set up model information based on active assertions
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ if( assert_active[fact] ){
+ computeLabelModel( s_lbl, d_tmodel );
+ }
+ }
+ //debug print
+ if( Trace.isOn("sep-process") ){
+ Trace("sep-process") << "--- Current spatial assertions : " << std::endl;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ Trace("sep-process") << " " << fact;
+ if( !assert_active[fact] ){
+ Trace("sep-process") << " [inactive]";
+ }
+ Trace("sep-process") << std::endl;
+ }
+ Trace("sep-process") << "---" << std::endl;
+ }
+ if(Trace.isOn("sep-eqc")) {
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ Trace("sep-eqc") << "EQC:" << std::endl;
+ while( !eqcs2_i.isFinished() ){
+ Node eqc = (*eqcs2_i);
+ eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ Trace("sep-eqc") << "Eqc( " << eqc << " ) : { ";
+ while( !eqc2_i.isFinished() ) {
+ if( (*eqc2_i)!=eqc ){
+ Trace("sep-eqc") << (*eqc2_i) << " ";
+ }
+ ++eqc2_i;
+ }
+ Trace("sep-eqc") << " } " << std::endl;
+ ++eqcs2_i;
+ }
+ Trace("sep-eqc") << std::endl;
+ }
+
+ if( options::sepCheckNeg() ){
+ //get active labels
+ std::map< Node, bool > active_lbl;
+ if( options::sepMinimalRefine() ){
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( !use_polarity ){
+ Assert( assert_active.find( fact )!=assert_active.end() );
+ if( assert_active[fact] ){
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_lbl = atom[1];
+ if( d_label_map[s_atom].find( s_lbl )!=d_label_map[s_atom].end() ){
+ Trace("sep-process-debug") << "Active lbl : " << s_lbl << std::endl;
+ active_lbl[s_lbl] = true;
+ }
+ }
+ }
+ }
+ }
+
+ //process spatial assertions
+ bool addedLemma = false;
+ bool needAddLemma = false;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ Trace("sep-process-debug") << " check atom : " << s_atom << " use polarity " << use_polarity << std::endl;
+ if( !use_polarity ){
+ Assert( assert_active.find( fact )!=assert_active.end() );
+ if( assert_active[fact] ){
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_lbl = atom[1];
+ Trace("sep-process") << "--> Active negated atom : " << s_atom << ", lbl = " << s_lbl << std::endl;
+ //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 );
+ 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 );
+ Trace("sep-process") << " Model for " << s_lbl << " : " << o_b_lbl_mval << std::endl;
+
+ //get model values
+ std::map< int, Node > mvals;
+ for( std::map< int, Node >::iterator itl = d_label_map[s_atom][s_lbl].begin(); itl != d_label_map[s_atom][s_lbl].end(); ++itl ){
+ Node sub_lbl = itl->second;
+ int sub_index = itl->first;
+ computeLabelModel( sub_lbl, d_tmodel );
+ Node lbl_mval = d_label_model[sub_lbl].getValue( tn );
+ Trace("sep-process-debug") << " child " << sub_index << " : " << sub_lbl << ", mval = " << lbl_mval << std::endl;
+ mvals[sub_index] = lbl_mval;
+ }
+
+ // Now, assert model-instantiated implication based on the negation
+ Assert( d_label_model.find( s_lbl )!=d_label_model.end() );
+ std::vector< Node > conc;
+ bool inst_success = true;
+ if( options::sepExp() ){
+ //old refinement lemmas
+ for( std::map< int, Node >::iterator itl = d_label_map[s_atom][s_lbl].begin(); itl != d_label_map[s_atom][s_lbl].end(); ++itl ){
+ int sub_index = itl->first;
+ std::map< Node, Node > visited;
+ Node c = applyLabel( s_atom[itl->first], mvals[sub_index], visited );
+ Trace("sep-process-debug") << " applied inst : " << c << std::endl;
+ if( s_atom.getKind()==kind::SEP_STAR || sub_index==0 ){
+ conc.push_back( c.negate() );
+ }else{
+ conc.push_back( c );
+ }
+ }
+ }else{
+ //new refinement
+ std::map< Node, Node > visited;
+ Node inst = instantiateLabel( s_atom, s_lbl, s_lbl, o_b_lbl_mval, visited, d_pto_model, d_tmodel, tn, active_lbl );
+ Trace("sep-inst-debug") << " applied inst : " << inst << std::endl;
+ if( inst.isNull() ){
+ inst_success = false;
+ }else{
+ inst = Rewriter::rewrite( inst );
+ if( inst==( polarity ? d_true : d_false ) ){
+ inst_success = false;
+ }
+ conc.push_back( polarity ? inst : inst.negate() );
+ }
+ }
+ if( inst_success ){
+ std::vector< Node > lemc;
+ Node pol_atom = atom;
+ if( polarity ){
+ pol_atom = atom.negate();
+ }
+ lemc.push_back( pol_atom );
+ //lemc.push_back( s_lbl.eqNode( o_b_lbl_mval ).negate() );
+ //lemc.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, o_b_lbl_mval, s_lbl ).negate() );
+ lemc.insert( lemc.end(), conc.begin(), conc.end() );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lemc );
+ if( std::find( d_refinement_lem[s_atom][s_lbl].begin(), d_refinement_lem[s_atom][s_lbl].end(), lem )==d_refinement_lem[s_atom][s_lbl].end() ){
+ d_refinement_lem[s_atom][s_lbl].push_back( lem );
+ Trace("sep-process") << "-----> refinement lemma (#" << d_refinement_lem[s_atom][s_lbl].size() << ") : " << lem << std::endl;
+ Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : " << lem << std::endl;
+ d_out->lemma( lem );
+ addedLemma = true;
+ }else{
+ Trace("sep-process") << "*** repeated refinement lemma : " << lem << std::endl;
+ }
+ }
+ }else{
+ Trace("sep-process-debug") << " no children." << std::endl;
+ Assert( s_atom.getKind()==kind::SEP_PTO );
+ }
+ }else{
+ Trace("sep-process-debug") << "--> inactive negated assertion " << s_atom << std::endl;
+ }
+ }
+ }
+ if( !addedLemma ){
+ if( needAddLemma ){
+ Trace("sep-process") << "WARNING : could not find refinement lemma!!!" << std::endl;
+ Assert( false );
+ d_out->setIncomplete();
+ }
+ }
+ }
+ }
+ Trace("sep-check") << "Sep::check(): " << e << " done, conflict=" << d_conflict.get() << endl;
+}
+
+
+Node TheorySep::getNextDecisionRequest() {
+ for( unsigned i=0; i<d_neg_guards.size(); i++ ){
+ Node g = d_neg_guards[i];
+ bool success = true;
+ if( getLogicInfo().isQuantified() ){
+ Assert( d_guard_to_assertion.find( g )!= d_guard_to_assertion.end() );
+ Node a = d_guard_to_assertion[g];
+ Node q = quantifiers::TermDb::getInstConstAttr( a );
+ if( !q.isNull() ){
+ //must wait to decide on counterexample literal from quantified formula
+ Node cel = getQuantifiersEngine()->getTermDatabase()->getCounterexampleLiteral( q );
+ bool value;
+ if( d_valuation.hasSatValue( cel, value ) ){
+ success = value;
+ }else{
+ Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : wait to decide on " << g << " until " << cel << " is set " << std::endl;
+ success = false;
+ }
+ }
+ }
+ if( success ){
+ bool value;
+ if( !d_valuation.hasSatValue( g, value ) ) {
+ Trace("sep-dec") << "TheorySep::getNextDecisionRequest : " << g << " (" << i << "/" << d_neg_guards.size() << ")" << std::endl;
+ return g;
+ }
+ }
+ }
+ Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : null" << std::endl;
+ return Node::null();
+}
+
+void TheorySep::conflict(TNode a, TNode b) {
+ Trace("sep-conflict") << "Sep::conflict : " << a << " " << b << std::endl;
+ Node conflictNode;
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ conflictNode = explain(a.iffNode(b));
+ } else {
+ conflictNode = explain(a.eqNode(b));
+ }
+ d_conflict = true;
+ d_out->conflict( conflictNode );
+}
+
+
+TheorySep::HeapAssertInfo::HeapAssertInfo( context::Context* c ) : d_pto(c), d_has_neg_pto(c,false) {
+
+}
+
+TheorySep::HeapAssertInfo * TheorySep::getOrMakeEqcInfo( Node n, bool doMake ) {
+ std::map< Node, HeapAssertInfo* >::iterator e_i = d_eqc_info.find( n );
+ if( e_i==d_eqc_info.end() ){
+ if( doMake ){
+ HeapAssertInfo* ei = new HeapAssertInfo( getSatContext() );
+ d_eqc_info[n] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*e_i).second;
+ }
+}
+
+TypeNode TheorySep::getReferenceType( Node atom, int& card, int index ) {
+ Trace("sep-type") << "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;
+ 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 );
+ if( !ctn.isNull() ){
+ tn = ctn;
+ }
+ for( unsigned j=0; j<d_references[atom][i].size(); j++ ){
+ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), d_references[atom][i][j] )==d_references[atom][index].end() ){
+ d_references[atom][index].push_back( d_references[atom][i][j] );
+ }
+ }
+ card = card + cardc;
+ }
+ }else{
+ 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 );
+ }
+ if( tn.isNull() && index==-1 ){
+ tn = NodeManager::currentNM()->booleanType();
+ }
+ d_reference_type[atom][index] = tn;
+ d_reference_type_card[atom][index] = card;
+ Trace("sep-type") << "...ref type return " << card << " for " << atom << " " << index << std::endl;
+ //add to d_type_references
+ if( index==-1 ){
+ //only contributes if top-level (index=-1)
+ for( unsigned i=0; i<d_references[atom][index].size(); i++ ){
+ Assert( !d_references[atom][index][i].isNull() );
+ if( std::find( d_type_references[tn].begin(), d_type_references[tn].end(), d_references[atom][index][i] )==d_type_references[tn].end() ){
+ d_type_references[tn].push_back( d_references[atom][index][i] );
+ }
+ }
+ // update maximum cardinality value
+ if( card>(int)d_card_max[tn] ){
+ d_card_max[tn] = card;
+ }
+ }
+ return tn;
+ }else{
+ Assert( d_reference_type_card[atom].find( index )!=d_reference_type_card[atom].end() );
+ card = d_reference_type_card[atom][index];
+ return it->second;
+ }
+}
+
+TypeNode TheorySep::getReferenceType2( 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;
+ visited[n] = -1;
+ if( n.getKind()==kind::SEP_PTO ){
+ TypeNode tn1 = n[0].getType();
+ TypeNode tn2 = n[1].getType();
+ if( quantifiers::TermDb::hasBoundVarAttr( n[0] ) ){
+ d_reference_bound_invalid[tn1] = true;
+ }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() ){
+ 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 );
+ }
+ }
+ card = 1;
+ visited[n] = card;
+ return tn1;
+ //return n[1].getType();
+ }else if( n.getKind()==kind::SEP_EMP ){
+ card = 1;
+ visited[n] = card;
+ return n[0].getType();
+ }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 );
+ 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] );
+ }
+ }
+ visited[n] = card;
+ 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 );
+ if( !tn.isNull() ){
+ otn = tn;
+ }
+ card = cardc>card ? cardc : card;
+ }
+ visited[n] = card;
+ return otn;
+ }
+ }else{
+ Trace("sep-type-debug") << "already visit : " << n << " : " << atom << " " << index << std::endl;
+ card = 0;
+ return TypeNode::null();
+ }
+}
+/*
+
+int TheorySep::getCardinality( Node n, std::vector< Node >& refs ) {
+ std::map< Node, int > visited;
+ return getCardinality2( n, refs, visited );
+}
+
+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{
+
+
+ }
+}
+*/
+
+Node TheorySep::getBaseLabel( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_base_label.find( tn );
+ if( it==d_base_label.end() ){
+ Trace("sep") << "Make base label for " << tn << std::endl;
+ std::stringstream ss;
+ ss << "__Lb";
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(tn);
+ //TypeNode ltn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(tn));
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "" );
+ d_base_label[tn] = n_lbl;
+ //make reference bound
+ Trace("sep") << "Make reference bound label for " << tn << std::endl;
+ std::stringstream ss2;
+ 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() );
+ //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() ){
+ //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_lbl_reference_bound[d_base_label[tn]].push_back( e );
+ }
+ //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 );
+ return n_lbl;
+ }else{
+ return it->second;
+ }
+}
+
+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 );
+ d_nil_ref[tn] = nil;
+ return nil;
+ }else{
+ return it->second;
+ }
+}
+
+Node TheorySep::mkUnion( TypeNode tn, std::vector< Node >& locs ) {
+ Node u;
+ if( locs.empty() ){
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(tn);
+ return NodeManager::currentNM()->mkConst(EmptySet(ltn.toType()));
+ }else{
+ for( unsigned i=0; i<locs.size(); i++ ){
+ Node s = locs[i];
+ Assert( !s.isNull() );
+ s = NodeManager::currentNM()->mkNode( kind::SINGLETON, s );
+ if( u.isNull() ){
+ u = s;
+ }else{
+ u = NodeManager::currentNM()->mkNode( kind::UNION, s, u );
+ }
+ }
+ return u;
+ }
+}
+
+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 );
+ std::stringstream ss;
+ ss << "__Lc" << child;
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(refType);
+ //TypeNode ltn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(refType));
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "" );
+ d_label_map[atom][lbl][child] = n_lbl;
+ d_label_map_parent[n_lbl] = lbl;
+ return n_lbl;
+ }else{
+ return (*it).second;
+ }
+}
+
+Node TheorySep::applyLabel( Node n, Node lbl, std::map< Node, Node >& visited ) {
+ Assert( n.getKind()!=kind::SEP_LABEL );
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){
+ return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl );
+ }else if( !n.getType().isBoolean() || n.getNumChildren()==0 ){
+ return n;
+ }else{
+ std::map< Node, Node >::iterator it = visited.find( n );
+ if( it==visited.end() ){
+ 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 aln = applyLabel( n[i], lbl, visited );
+ children.push_back( aln );
+ childChanged = childChanged || aln!=n[i];
+ }
+ Node ret = n;
+ if( childChanged ){
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ visited[n] = ret;
+ return ret;
+ }else{
+ return it->second;
+ }
+ }
+}
+
+Node TheorySep::instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std::map< Node, Node >& visited, std::map< Node, Node >& pto_model, std::map< Node, Node >& tmodel,
+ TypeNode rtn, std::map< Node, bool >& active_lbl, unsigned ind ) {
+ Trace("sep-inst-debug") << "Instantiate label " << n << " " << lbl << " " << lbl_v << std::endl;
+ if( options::sepMinimalRefine() && lbl!=o_lbl && active_lbl.find( lbl )!=active_lbl.end() ){
+ Trace("sep-inst") << "...do not instantiate " << o_lbl << " since it has an active sublabel " << lbl << std::endl;
+ return Node::null();
+ }else{
+ if( Trace.isOn("sep-inst") ){
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){
+ for( unsigned j=0; j<ind; j++ ){ Trace("sep-inst") << " "; }
+ Trace("sep-inst") << n << "[" << lbl << "] :: " << lbl_v << std::endl;
+ }
+ }
+ Assert( n.getKind()!=kind::SEP_LABEL );
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND ){
+ if( lbl==o_lbl ){
+ std::vector< Node > children;
+ children.resize( n.getNumChildren() );
+ Assert( d_label_map[n].find( lbl )!=d_label_map[n].end() );
+ for( std::map< int, Node >::iterator itl = d_label_map[n][lbl].begin(); itl != d_label_map[n][lbl].end(); ++itl ){
+ Node sub_lbl = itl->second;
+ int sub_index = itl->first;
+ Assert( sub_index>=0 && sub_index<(int)children.size() );
+ Trace("sep-inst-debug") << "Sublabel " << sub_index << " is " << sub_lbl << std::endl;
+ Node lbl_mval;
+ if( n.getKind()==kind::SEP_WAND && sub_index==1 ){
+ Assert( d_label_map[n][lbl].find( 0 )!=d_label_map[n][lbl].end() );
+ Node sub_lbl_0 = d_label_map[n][lbl][0];
+ computeLabelModel( sub_lbl_0, tmodel );
+ Assert( d_label_model.find( sub_lbl_0 )!=d_label_model.end() );
+ lbl_mval = NodeManager::currentNM()->mkNode( kind::UNION, lbl, d_label_model[sub_lbl_0].getValue( rtn ) );
+ }else{
+ computeLabelModel( sub_lbl, tmodel );
+ Assert( d_label_model.find( sub_lbl )!=d_label_model.end() );
+ lbl_mval = d_label_model[sub_lbl].getValue( rtn );
+ }
+ Trace("sep-inst-debug") << "Sublabel value is " << lbl_mval << std::endl;
+ children[sub_index] = instantiateLabel( n[sub_index], o_lbl, sub_lbl, lbl_mval, visited, pto_model, tmodel, rtn, active_lbl, ind+1 );
+ if( children[sub_index].isNull() ){
+ return Node::null();
+ }
+ }
+ if( n.getKind()==kind::SEP_STAR ){
+ Assert( children.size()>1 );
+ return NodeManager::currentNM()->mkNode( kind::AND, children );
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::OR, children[0].negate(), children[1] );
+ }
+ }else{
+ //nested star/wand, label it and return
+ return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl_v );
+ }
+ }else if( n.getKind()==kind::SEP_PTO ){
+ //check if this pto reference is in the base label, if not, then it does not need to be added as an assumption
+ Assert( d_label_model.find( o_lbl )!=d_label_model.end() );
+ Node vr = d_valuation.getModel()->getRepresentative( n[0] );
+ Node svr = NodeManager::currentNM()->mkNode( kind::SINGLETON, vr );
+ bool inBaseHeap = std::find( d_label_model[o_lbl].d_heap_locs_model.begin(), d_label_model[o_lbl].d_heap_locs_model.end(), svr )!=d_label_model[o_lbl].d_heap_locs_model.end();
+ Trace("sep-inst-debug") << "Is in base (non-instantiating) heap : " << inBaseHeap << " for value ref " << vr << " in " << o_lbl << std::endl;
+ std::vector< Node > children;
+ if( inBaseHeap ){
+ Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] );
+ children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, n[0], n[1] ), s ) );
+ }else{
+ //look up value of data
+ std::map< Node, Node >::iterator it = pto_model.find( vr );
+ if( it!=pto_model.end() ){
+ if( n[1]!=it->second ){
+ children.push_back( NodeManager::currentNM()->mkNode( n[1].getType().isBoolean() ? kind::IFF : kind::EQUAL, n[1], it->second ) );
+ }
+ }else{
+ Trace("sep-inst-debug") << "Data for " << vr << " was not specified, do not add condition." << std::endl;
+ }
+ }
+ children.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] ), lbl_v ) );
+ Node ret = children.empty() ? NodeManager::currentNM()->mkConst( true ) : ( children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ) );
+ Trace("sep-inst-debug") << "Return " << ret << std::endl;
+ return ret;
+ }else if( n.getKind()==kind::SEP_EMP ){
+ //return NodeManager::currentNM()->mkConst( lbl_v.getKind()==kind::EMPTYSET );
+ return lbl_v.eqNode( NodeManager::currentNM()->mkConst(EmptySet(lbl_v.getType().toType())) );
+ }else{
+ std::map< Node, Node >::iterator it = visited.find( n );
+ if( it==visited.end() ){
+ 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 aln = instantiateLabel( n[i], o_lbl, lbl, lbl_v, visited, pto_model, tmodel, rtn, active_lbl, ind );
+ if( aln.isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( aln );
+ childChanged = childChanged || aln!=n[i];
+ }
+ }
+ Node ret = n;
+ if( childChanged ){
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ //careful about caching
+ //visited[n] = ret;
+ return ret;
+ }else{
+ return it->second;
+ }
+ }
+ }
+}
+
+void TheorySep::setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active ) {
+ Trace("sep-process-debug") << "setInactiveAssertionRec::inactive : " << fact << std::endl;
+ assert_active[fact] = false;
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ if( s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_STAR ){
+ for( unsigned j=0; j<s_atom.getNumChildren(); j++ ){
+ Node lblc = getLabel( s_atom, j, s_lbl );
+ for( unsigned k=0; k<lbl_to_assertions[lblc].size(); k++ ){
+ setInactiveAssertionRec( lbl_to_assertions[lblc][k], lbl_to_assertions, assert_active );
+ }
+ }
+ }
+}
+
+void TheorySep::getLabelChildren( Node s_atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels ) {
+ for( unsigned i=0; i<s_atom.getNumChildren(); i++ ){
+ Node lblc = getLabel( s_atom, i, lbl );
+ Assert( !lblc.isNull() );
+ std::map< Node, Node > visited;
+ Node lc = applyLabel( s_atom[i], lblc, visited );
+ Assert( !lc.isNull() );
+ if( i==1 && s_atom.getKind()==kind::SEP_WAND ){
+ lc = lc.negate();
+ }
+ children.push_back( lc );
+ labels.push_back( lblc );
+ }
+ Assert( children.size()>1 );
+}
+
+void TheorySep::computeLabelModel( Node lbl, std::map< Node, Node >& tmodel ) {
+ if( !d_label_model[lbl].d_computed ){
+ d_label_model[lbl].d_computed = true;
+
+ //we must get the value of lbl from the model: this is being run at last call, after the model is constructed
+ //Assert(...); TODO
+ Node v_val = d_valuation.getModel()->getRepresentative( lbl );
+ Trace("sep-process") << "Model value (from valuation) for " << lbl << " : " << v_val << std::endl;
+ if( v_val.getKind()!=kind::EMPTYSET ){
+ while( v_val.getKind()==kind::UNION ){
+ Assert( v_val[1].getKind()==kind::SINGLETON );
+ d_label_model[lbl].d_heap_locs_model.push_back( v_val[1] );
+ v_val = v_val[0];
+ }
+ Assert( v_val.getKind()==kind::SINGLETON );
+ d_label_model[lbl].d_heap_locs_model.push_back( v_val );
+ }
+ //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 );
+ u = u[0];
+ Node tt;
+ std::map< Node, Node >::iterator itm = tmodel.find( u );
+ if( itm==tmodel.end() ) {
+ //Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << std::endl;
+ //Assert( false );
+ //tt = u;
+ //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() );
+ tt = d_type_references_all[tn][0];
+ }else{
+ tt = itm->second;
+ }
+ Node stt = NodeManager::currentNM()->mkNode( kind::SINGLETON, tt );
+ Trace("sep-process-debug") << "...model : add " << tt << " for " << u << " in lbl " << lbl << std::endl;
+ d_label_model[lbl].d_heap_locs.push_back( stt );
+ }
+ }
+}
+
+Node TheorySep::getRepresentative( Node t ) {
+ if( d_equalityEngine.hasTerm( t ) ){
+ return d_equalityEngine.getRepresentative( t );
+ }else{
+ return t;
+ }
+}
+
+bool TheorySep::hasTerm( Node a ){
+ return d_equalityEngine.hasTerm( a );
+}
+
+bool TheorySep::areEqual( Node a, Node b ){
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areEqual( a, b );
+ }else{
+ return false;
+ }
+}
+
+bool TheorySep::areDisequal( Node a, Node b ){
+ if( a==b ){
+ return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ if( d_equalityEngine.areDisequal( a, b, false ) ){
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void TheorySep::eqNotifyPreMerge(TNode t1, TNode t2) {
+
+}
+
+void TheorySep::eqNotifyPostMerge(TNode t1, TNode t2) {
+ HeapAssertInfo * e2 = getOrMakeEqcInfo( t2, false );
+ if( e2 && ( !e2->d_pto.get().isNull() || e2->d_has_neg_pto.get() ) ){
+ HeapAssertInfo * e1 = getOrMakeEqcInfo( t1, true );
+ if( !e2->d_pto.get().isNull() ){
+ if( !e1->d_pto.get().isNull() ){
+ Trace("sep-pto-debug") << "While merging " << t1 << " " << t2 << ", merge pto." << std::endl;
+ mergePto( e1->d_pto.get(), e2->d_pto.get() );
+ }else{
+ e1->d_pto.set( e2->d_pto.get() );
+ }
+ }
+ e1->d_has_neg_pto.set( e1->d_has_neg_pto.get() || e2->d_has_neg_pto.get() );
+ //validate
+ validatePto( e1, t1 );
+ }
+}
+
+void TheorySep::validatePto( HeapAssertInfo * ei, Node ei_n ) {
+ if( !ei->d_pto.get().isNull() && ei->d_has_neg_pto.get() ){
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ if( !polarity ){
+ TNode atom = polarity ? fact : fact[0];
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_atom = atom[0];
+ if( s_atom.getKind()==kind::SEP_PTO ){
+ if( areEqual( atom[1], ei_n ) ){
+ addPto( ei, ei_n, atom, false );
+ }
+ }
+ }
+ }
+ //we have now processed all pending negated pto
+ ei->d_has_neg_pto.set( false );
+ }
+}
+
+void TheorySep::addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ) {
+ Trace("sep-pto") << "Add pto " << p << ", pol = " << polarity << " to eqc " << ei_n << std::endl;
+ if( !ei->d_pto.get().isNull() ){
+ if( polarity ){
+ Trace("sep-pto-debug") << "...eqc " << ei_n << " already has pto " << ei->d_pto.get() << ", merge." << std::endl;
+ mergePto( ei->d_pto.get(), p );
+ }else{
+ Node pb = ei->d_pto.get();
+ Trace("sep-pto") << "Process positive/negated pto " << " " << pb << " " << p << std::endl;
+ Assert( pb.getKind()==kind::SEP_LABEL && pb[0].getKind()==kind::SEP_PTO );
+ Assert( p.getKind()==kind::SEP_LABEL && p[0].getKind()==kind::SEP_PTO );
+ Assert( areEqual( pb[1], p[1] ) );
+ std::vector< Node > exp;
+ if( pb[1]!=p[1] ){
+ exp.push_back( pb[1].eqNode( p[1] ) );
+ }
+ exp.push_back( pb );
+ exp.push_back( p.negate() );
+ std::vector< Node > conc;
+ 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() );
+ }
+ Node n_conc = conc.empty() ? d_false : ( conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::OR, conc ) );
+ sendLemma( exp, n_conc, "PTO_NEG_PROP" );
+ }
+ }else{
+ if( polarity ){
+ ei->d_pto.set( p );
+ validatePto( ei, ei_n );
+ }else{
+ ei->d_has_neg_pto.set( true );
+ }
+ }
+}
+
+void TheorySep::mergePto( Node p1, Node p2 ) {
+ Trace("sep-lemma-debug") << "Merge pto " << p1 << " " << p2 << std::endl;
+ Assert( p1.getKind()==kind::SEP_LABEL && p1[0].getKind()==kind::SEP_PTO );
+ Assert( p2.getKind()==kind::SEP_LABEL && p2[0].getKind()==kind::SEP_PTO );
+ if( !areEqual( p1[0][1], p2[0][1] ) ){
+ std::vector< Node > exp;
+ if( p1[1]!=p2[1] ){
+ Assert( areEqual( p1[1], p2[1] ) );
+ exp.push_back( p1[1].eqNode( p2[1] ) );
+ }
+ exp.push_back( p1 );
+ exp.push_back( p2 );
+ sendLemma( exp, p1[0][1].eqNode( p2[0][1] ), "PTO_PROP" );
+ }
+}
+
+void TheorySep::sendLemma( std::vector< Node >& ant, Node conc, const char * c, bool infer ) {
+ Trace("sep-lemma-debug") << "Do rewrite on inference : " << conc << std::endl;
+ conc = Rewriter::rewrite( conc );
+ Trace("sep-lemma-debug") << "Got : " << conc << std::endl;
+ if( conc!=d_true ){
+ if( infer && conc!=d_false ){
+ Node ant_n;
+ if( ant.empty() ){
+ ant_n = d_true;
+ }else if( ant.size()==1 ){
+ ant_n = ant[0];
+ }else{
+ ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant );
+ }
+ Trace("sep-lemma") << "Sep::Infer: " << conc << " from " << ant_n << " by " << c << std::endl;
+ d_pending_exp.push_back( ant_n );
+ d_pending.push_back( conc );
+ d_infer.push_back( ant_n );
+ d_infer_exp.push_back( conc );
+ }else{
+ std::vector< TNode > ant_e;
+ for( unsigned i=0; i<ant.size(); i++ ){
+ Trace("sep-lemma-debug") << "Explain : " << ant[i] << std::endl;
+ explain( ant[i], ant_e );
+ }
+ Node ant_n;
+ if( ant_e.empty() ){
+ ant_n = d_true;
+ }else if( ant_e.size()==1 ){
+ ant_n = ant_e[0];
+ }else{
+ ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant_e );
+ }
+ if( conc==d_false ){
+ Trace("sep-lemma") << "Sep::Conflict: " << ant_n << " by " << c << std::endl;
+ d_out->conflict( ant_n );
+ d_conflict = true;
+ }else{
+ Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant_n << " by " << c << std::endl;
+ d_pending_exp.push_back( ant_n );
+ d_pending.push_back( conc );
+ d_pending_lem.push_back( d_pending.size()-1 );
+ }
+ }
+ }
+}
+
+void TheorySep::doPendingFacts() {
+ if( d_pending_lem.empty() ){
+ for( unsigned i=0; i<d_pending.size(); i++ ){
+ if( d_conflict ){
+ break;
+ }
+ Node atom = d_pending[i].getKind()==kind::NOT ? d_pending[i][0] : d_pending[i];
+ bool pol = d_pending[i].getKind()!=kind::NOT;
+ Trace("sep-pending") << "Sep : Assert to EE : " << atom << ", pol = " << pol << std::endl;
+ if( atom.getKind()==kind::EQUAL ){
+ d_equalityEngine.assertEquality(atom, pol, d_pending_exp[i]);
+ }else{
+ d_equalityEngine.assertPredicate(atom, pol, d_pending_exp[i]);
+ }
+ }
+ }else{
+ for( unsigned i=0; i<d_pending_lem.size(); i++ ){
+ if( d_conflict ){
+ break;
+ }
+ 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;
+ }
+ }
+ d_pending_exp.clear();
+ d_pending.clear();
+ d_pending_lem.clear();
+}
+
+void TheorySep::debugPrintHeap( HeapInfo& heap, const char * c ) {
+ Trace(c) << "[" << std::endl;
+ Trace(c) << " ";
+ for( unsigned j=0; j<heap.d_heap_locs.size(); j++ ){
+ Trace(c) << heap.d_heap_locs[j] << " ";
+ }
+ Trace(c) << std::endl;
+ Trace(c) << "]" << std::endl;
+}
+
+Node TheorySep::HeapInfo::getValue( TypeNode tn ) {
+ Assert( d_heap_locs.size()==d_heap_locs_model.size() );
+ if( d_heap_locs.empty() ){
+ return NodeManager::currentNM()->mkConst(EmptySet(tn.toType()));
+ }else if( d_heap_locs.size()==1 ){
+ return d_heap_locs[0];
+ }else{
+ Node curr = NodeManager::currentNM()->mkNode( kind::UNION, d_heap_locs[0], d_heap_locs[1] );
+ for( unsigned j=2; j<d_heap_locs.size(); j++ ){
+ curr = NodeManager::currentNM()->mkNode( kind::UNION, curr, d_heap_locs[j] );
+ }
+ return curr;
+ }
+}
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h
new file mode 100644
index 000000000..852a36721
--- /dev/null
+++ b/src/theory/sep/theory_sep.h
@@ -0,0 +1,294 @@
+/********************* */
+/*! \file theory_sep.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: Dejan Jovanovic, Clark Barrett
+ ** Minor contributors (to current version): Tim King, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Theory of sep
+ **
+ ** Theory of sep.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_H
+
+#include "theory/theory.h"
+#include "util/statistics_registry.h"
+#include "theory/uf/equality_engine.h"
+#include "context/cdchunk_list.h"
+#include "context/cdhashmap.h"
+#include "context/cdhashset.h"
+#include "context/cdqueue.h"
+
+namespace CVC4 {
+namespace theory {
+
+class TheoryModel;
+
+namespace sep {
+
+class TheorySep : public Theory {
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MISC
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ /** True node for predicates = true */
+ Node d_true;
+
+ /** True node for predicates = false */
+ Node d_false;
+
+ Node mkAnd( std::vector< TNode >& assumptions );
+
+ void processAssertion( Node n, std::map< Node, bool >& visited );
+
+ public:
+
+ TheorySep(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ ~TheorySep();
+
+ void setMasterEqualityEngine(eq::EqualityEngine* eq);
+
+ std::string identify() const { return std::string("TheorySep"); }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PREPROCESSING
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+ Node ppRewrite(TNode atom);
+
+ void processAssertions( std::vector< Node >& assertions );
+ /////////////////////////////////////////////////////////////////////////////
+ // T-PROPAGATION / REGISTRATION
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ /** Should be called to propagate the literal. */
+ bool propagate(TNode literal);
+
+ /** 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);
+
+ public:
+
+ void addSharedTerm(TNode t);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+ void computeCareGraph();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MODEL GENERATION
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // NOTIFICATIONS
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+ public:
+
+ Node getNextDecisionRequest();
+
+ void presolve();
+ void shutdown() { }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MAIN SOLVER
+ /////////////////////////////////////////////////////////////////////////////
+ public:
+
+ void check(Effort e);
+
+ private:
+
+ // NotifyClass: template helper class for d_equalityEngine - handles call-back from congruence closure module
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheorySep& d_sep;
+ public:
+ NotifyClass(TheorySep& sep): d_sep(sep) {}
+
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
+ // Just forward to sep
+ if (value) {
+ return d_sep.propagate(equality);
+ } else {
+ return d_sep.propagate(equality.notNode());
+ }
+ }
+
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Unreachable();
+ }
+
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ // Propagate equality between shared terms
+ return d_sep.propagate(t1.eqNode(t2));
+ } else {
+ return d_sep.propagate(t1.eqNode(t2).notNode());
+ }
+ return true;
+ }
+
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_sep.conflict(t1, t2);
+ }
+
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sep.eqNotifyPreMerge( t1, t2 ); }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sep.eqNotifyPostMerge( t1, t2 ); }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+ };
+
+ /** The notify class for d_equalityEngine */
+ NotifyClass d_notify;
+
+ /** Equaltity engine */
+ eq::EqualityEngine d_equalityEngine;
+
+ /** Are we in conflict? */
+ context::CDO<bool> d_conflict;
+ std::vector< Node > d_pending_exp;
+ std::vector< Node > d_pending;
+ std::vector< int > d_pending_lem;
+
+ /** list of all refinement lemms */
+ std::map< Node, std::map< Node, std::vector< Node > > > d_refinement_lem;
+
+ /** Conflict when merging constants */
+ void conflict(TNode a, TNode b);
+
+ //cache for positive polarity start reduction
+ NodeSet d_reduce;
+ std::map< Node, std::map< Node, Node > > d_red_conc;
+ std::map< Node, std::map< Node, Node > > d_neg_guard;
+ std::vector< Node > d_neg_guards;
+ std::map< Node, Node > d_guard_to_assertion;
+ //cache for references
+ std::map< Node, std::map< int, TypeNode > > d_reference_type;
+ std::map< Node, std::map< int, int > > d_reference_type_card;
+ std::map< Node, std::map< int, std::vector< Node > > > d_references;
+ /** inferences: maintained to ensure ref count for internally introduced nodes */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ NodeList d_spatial_assertions;
+
+ //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
+ std::map< TypeNode, Node > d_base_label;
+ std::map< TypeNode, Node > d_nil_ref;
+ //reference bound
+ 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, std::vector< Node > > d_type_references;
+ 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
+ std::map< Node, std::map< Node, std::map< int, Node > > > d_label_map;
+ std::map< Node, Node > d_label_map_parent;
+
+ //term model
+ std::map< Node, Node > d_tmodel;
+ std::map< Node, Node > d_pto_model;
+
+ class HeapAssertInfo {
+ public:
+ HeapAssertInfo( context::Context* c );
+ ~HeapAssertInfo(){}
+ context::CDO< Node > d_pto;
+ context::CDO< bool > d_has_neg_pto;
+ };
+ std::map< Node, HeapAssertInfo * > d_eqc_info;
+ HeapAssertInfo * getOrMakeEqcInfo( Node n, bool doMake = false );
+
+ //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);
+ //get the base label for the spatial assertion
+ Node getBaseLabel( TypeNode tn );
+ Node getNilRef( TypeNode tn );
+ Node getLabel( Node atom, int child, Node lbl );
+ Node applyLabel( Node n, Node lbl, std::map< Node, Node >& visited );
+ void getLabelChildren( Node atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels );
+
+ class HeapInfo {
+ public:
+ HeapInfo() : d_computed(false) {}
+ //information about the model
+ bool d_computed;
+ std::vector< Node > d_heap_locs;
+ std::vector< Node > d_heap_locs_model;
+ //get value
+ Node getValue( TypeNode tn );
+ };
+ //heap info ( label -> HeapInfo )
+ std::map< Node, HeapInfo > d_label_model;
+
+ void debugPrintHeap( HeapInfo& heap, const char * c );
+ void validatePto( HeapAssertInfo * ei, Node ei_n );
+ void addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity );
+ void mergePto( Node p1, Node p2 );
+ void computeLabelModel( Node lbl, std::map< Node, Node >& tmodel );
+ Node instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std::map< Node, Node >& visited, std::map< Node, Node >& pto_model, std::map< Node, Node >& tmodel,
+ TypeNode rtn, std::map< Node, bool >& active_lbl, unsigned ind = 0 );
+ void setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active );
+
+ Node mkUnion( TypeNode tn, std::vector< Node >& locs );
+private:
+ Node getRepresentative( Node t );
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+
+ void sendLemma( std::vector< Node >& ant, Node conc, const char * c, bool infer = false );
+ void doPendingFacts();
+public:
+ eq::EqualityEngine* getEqualityEngine() {
+ return &d_equalityEngine;
+ }
+
+};/* class TheorySep */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_H */
diff --git a/src/theory/sep/theory_sep_rewriter.cpp b/src/theory/sep/theory_sep_rewriter.cpp
new file mode 100644
index 000000000..d58c2c13d
--- /dev/null
+++ b/src/theory/sep/theory_sep_rewriter.cpp
@@ -0,0 +1,184 @@
+/********************* */
+/*! \file theory_sep_rewriter.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "expr/attribute.h"
+#include "theory/sep/theory_sep_rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+void TheorySepRewriter::getStarChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children ){
+ Assert( n.getKind()==kind::SEP_STAR );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==kind::SEP_EMP ){
+ s_children.push_back( n[i] );
+ }else if( n[i].getKind()==kind::SEP_STAR ){
+ getStarChildren( n[i], s_children, ns_children );
+ }else if( n[i].getKind()==kind::SEP_PTO ){
+ s_children.push_back( n[i] );
+ }else{
+ std::vector< Node > temp_s_children;
+ getAndChildren( n[i], temp_s_children, ns_children );
+ Node to_add;
+ if( temp_s_children.size()==0 ){
+ to_add = NodeManager::currentNM()->mkConst( true );
+ }else{
+ //remove empty star
+ std::vector< Node > temp_s_children2;
+ for( unsigned i=0; i<temp_s_children.size(); i++ ){
+ if( temp_s_children[i].getKind()!=kind::SEP_EMP ){
+ temp_s_children2.push_back( temp_s_children[i] );
+ }
+ }
+ if( temp_s_children2.size()==1 ){
+ to_add = temp_s_children2[0];
+ }else if( temp_s_children2.size()>1 ){
+ to_add = NodeManager::currentNM()->mkNode( kind::AND, temp_s_children2 );
+ }
+ }
+ if( !to_add.isNull() ){
+ //flatten star
+ if( to_add.getKind()==kind::SEP_STAR ){
+ getStarChildren( to_add, s_children, ns_children );
+ }else if( std::find( s_children.begin(), s_children.end(), to_add )==s_children.end() ){
+ s_children.push_back( to_add );
+ }
+ }
+ }
+ }
+}
+
+void TheorySepRewriter::getAndChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children ) {
+ if( n.getKind()==kind::AND ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getAndChildren( n[i], s_children, ns_children );
+ }
+ }else{
+ std::map< Node, bool > visited;
+ if( isSpatial( n, visited ) ){
+ if( std::find( s_children.begin(), s_children.end(), n )==s_children.end() ){
+ s_children.push_back( n );
+ }
+ }else{
+ if( std::find( ns_children.begin(), ns_children.end(), n )==ns_children.end() ){
+ if( n!=NodeManager::currentNM()->mkConst(true) ){
+ ns_children.push_back( n );
+ }
+ }
+ }
+ }
+}
+
+bool TheorySepRewriter::isSpatial( Node n, std::map< Node, bool >& visited ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP || n.getKind()==kind::SEP_LABEL ){
+ return true;
+ }else if( n.getType().isBoolean() ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( isSpatial( n[i], visited ) ){
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+RewriteResponse TheorySepRewriter::postRewrite(TNode node) {
+ Trace("sep-postrewrite") << "Sep::postRewrite start " << node << std::endl;
+ Node retNode = node;
+ switch (node.getKind()) {
+ case kind::SEP_LABEL: {
+ if( node[0].getKind()==kind::SEP_PTO ){
+ Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, node[0][0] );
+ if( node[1]!=s ){
+ Node c1 = node[1].eqNode( s );
+ Node c2 = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, node[0][0], node[0][1] ), s );
+ retNode = NodeManager::currentNM()->mkNode( kind::AND, c1, c2 );
+ }
+ }
+ if( node[0].getKind()==kind::SEP_EMP ){
+ retNode = node[1].eqNode( NodeManager::currentNM()->mkConst(EmptySet(node[1].getType().toType())) );
+ }
+ break;
+ }
+ case kind::SEP_PTO: {
+ break;
+ }
+ case kind::SEP_STAR: {
+ //flatten
+ std::vector< Node > s_children;
+ std::vector< Node > ns_children;
+ getStarChildren( node, s_children, ns_children );
+ if( !s_children.empty() ){
+ Node schild;
+ if( s_children.size()==1 ) {
+ schild = s_children[0];
+ }else{
+ schild = NodeManager::currentNM()->mkNode( kind::SEP_STAR, s_children );
+ }
+ ns_children.push_back( schild );
+ }
+ Assert( !ns_children.empty() );
+ if( ns_children.size()==1 ){
+ retNode = ns_children[0];
+ }else{
+ retNode = NodeManager::currentNM()->mkNode( kind::AND, ns_children );
+ }
+ break;
+ }
+ case kind::EQUAL:
+ case kind::IFF: {
+ if(node[0] == node[1]) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ else if (node[0].isConst() && node[1].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(false));
+ }
+ if (node[0] > node[1]) {
+ Node newNode = NodeManager::currentNM()->mkNode(node.getKind(), node[1], node[0]);
+ return RewriteResponse(REWRITE_DONE, newNode);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if( node!=retNode ){
+ Trace("sep-rewrite") << "Sep::rewrite : " << node << " -> " << retNode << std::endl;
+ }
+ return RewriteResponse(node==retNode ? REWRITE_DONE : REWRITE_AGAIN_FULL, retNode);
+}
+
+
+/*
+RewriteResponse TheorySepRewriter::preRewrite(TNode node) {
+ if( node.getKind()==kind::SEP_EMP ){
+ Trace("sep-prerewrite") << "Sep::preRewrite emp star " << std::endl;
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkNode( kind::SEP_EMP, NodeManager::currentNM()->mkConst( true ) ) );
+ }else{
+ Trace("sep-prerewrite") << "Sep::preRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+}
+*/
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/sep/theory_sep_rewriter.h b/src/theory/sep/theory_sep_rewriter.h
new file mode 100644
index 000000000..02adbebe5
--- /dev/null
+++ b/src/theory/sep/theory_sep_rewriter.h
@@ -0,0 +1,53 @@
+/********************* */
+/*! \file theory_sep_rewriter.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+
+class TheorySepRewriter {
+private:
+ static void getStarChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children );
+ static void getAndChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children );
+ static bool isSpatial( Node n, std::map< Node, bool >& visited );
+public:
+
+ static RewriteResponse postRewrite(TNode node);
+ static inline RewriteResponse preRewrite(TNode node) {
+ Trace("sep-prerewrite") << "Sep::preRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+
+ static inline void init() {}
+ static inline void shutdown() {}
+
+};/* class TheorySepRewriter */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H */
diff --git a/src/theory/sep/theory_sep_type_rules.h b/src/theory/sep/theory_sep_type_rules.h
new file mode 100644
index 000000000..7d4eb303e
--- /dev/null
+++ b/src/theory/sep/theory_sep_type_rules.h
@@ -0,0 +1,114 @@
+/********************* */
+/*! \file theory_sep_type_rules.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Typing and cardinality rules for the theory of sep
+ **
+ ** Typing and cardinality rules for the theory of sep.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H
+
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+class SepNilRefTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return TypeNode::fromType( n.getConst<NilRef>().getType() );
+ }
+};
+
+class SepEmpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::SEP_EMP);
+ return nodeManager->booleanType();
+ }
+};
+
+struct SepPtoTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::SEP_PTO);
+ if( check ) {
+ TypeNode refType = n[0].getType(check);
+ TypeNode ptType = n[1].getType(check);
+ }
+ return nodeManager->booleanType();
+ }
+};/* struct SepSelectTypeRule */
+
+struct SepStarTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_STAR);
+ if( check ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TypeNode ctype = n[i].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep star is not Boolean");
+ }
+ }
+ }
+ return btype;
+ }
+};/* struct SepStarTypeRule */
+
+struct SepWandTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_WAND);
+ if( check ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TypeNode ctype = n[i].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep magic wand is not Boolean");
+ }
+ }
+ }
+ return btype;
+ }
+};/* struct SepWandTypeRule */
+
+struct SepLabelTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_LABEL);
+ if( check ){
+ TypeNode ctype = n[0].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep label is not Boolean");
+ }
+ TypeNode stype = n[1].getType( check );
+ if( !stype.isSet() ){
+ throw TypeCheckingExceptionPrivate(n, "label of sep label is not a set");
+ }
+ }
+ return btype;
+ }
+};/* struct SepLabelTypeRule */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H */
diff --git a/src/theory/sets/kinds b/src/theory/sets/kinds
index 3fb73749d..c92eab4bd 100644
--- a/src/theory/sets/kinds
+++ b/src/theory/sets/kinds
@@ -64,6 +64,7 @@ typerule PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
typerule TRANSPOSE ::CVC4::theory::sets::RelTransposeTypeRule
typerule TCLOSURE ::CVC4::theory::sets::RelTransClosureTypeRule
+
construle UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index 217432670..37071eb2e 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -139,6 +139,20 @@ private:
*/
bool lemma(Node n, SetsLemmaTag t);
+ /** send out a lemma */
+ enum SetsLemmaTag {
+ SETS_LEMMA_DISEQUAL,
+ SETS_LEMMA_MEMBER,
+ SETS_LEMMA_GRAPH,
+ SETS_LEMMA_OTHER
+ };
+
+ /**
+ * returns true if a lemmas was generated
+ * returns false otherwise (found in cache)
+ */
+ bool lemma(Node n, SetsLemmaTag t);
+
class TermInfoManager {
TheorySetsPrivate& d_theory;
context::Context* d_context;
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index 92d6c9b6d..478dcbdb6 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -275,6 +275,7 @@ struct RelTransClosureTypeRule {
}
};/* struct RelTransClosureTypeRule */
+
struct SetsProperties {
inline static Cardinality computeCardinality(TypeNode type) {
Assert(type.getKind() == kind::SET_TYPE);
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index 53344dd6c..a665a02c1 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -39,6 +39,10 @@ RegExpOpr::RegExpOpr()
d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
}
+RegExpOpr::~RegExpOpr(){
+
+}
+
int RegExpOpr::gcd ( int a, int b ) {
int c;
while ( a != 0 ) {
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index c537553f2..075391370 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -99,6 +99,7 @@ private:
public:
RegExpOpr();
+ ~RegExpOpr();
bool checkConstRegExp( Node r );
void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index b3e1925ae..57344236e 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -28,6 +28,7 @@
#include "theory/strings/type_enumerator.h"
#include "theory/theory_model.h"
#include "theory/valuation.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4::context;
@@ -74,9 +75,11 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
d_preproc(u),
d_preproc_cache(u),
d_extf_infer_cache(c),
+ d_ee_disequalities(c),
d_congruent(c),
d_proxy_var(u),
d_proxy_var_to_length(u),
+ d_functionsTerms(c),
d_neg_ctn_eqlen(c),
d_neg_ctn_ulen(c),
d_neg_ctn_cached(u),
@@ -124,7 +127,9 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
}
TheoryStrings::~TheoryStrings() {
-
+ for( std::map< Node, EqcInfo* >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){
+ delete it->second;
+ }
}
Node TheoryStrings::getRepresentative( Node t ) {
@@ -467,18 +472,30 @@ void TheoryStrings::preRegisterTerm(TNode n) {
break;
}
default: {
- if( n.getType().isString() ) {
+ TypeNode tn = n.getType();
+ if( tn.isString() ) {
registerTerm( n, 0 );
// FMF
if( n.getKind() == kind::VARIABLE && options::stringFMF() ){
d_input_vars.insert(n);
}
- } else if (n.getType().isBoolean()) {
+ d_equalityEngine.addTerm(n);
+ } else if (tn.isBoolean()) {
// Get triggered for both equal and dis-equal
d_equalityEngine.addTriggerPredicate(n);
} else {
// Function applications/predicates
d_equalityEngine.addTerm(n);
+ if( options::stringExp() ){
+ //collect extended functions here: some may not be asserted to strings (such as those with return type Int),
+ // but we need to record them so they are treated properly
+ std::map< Node, bool > visited;
+ collectExtendedFuncTerms( n, visited );
+ }
+ }
+ //concat terms do not contribute to theory combination? TODO: verify
+ if( n.hasOperator() && kindToTheoryId( n.getKind() )==THEORY_STRINGS && n.getKind()!=kind::STRING_CONCAT ){
+ d_functionsTerms.push_back( n );
}
}
}
@@ -486,6 +503,7 @@ void TheoryStrings::preRegisterTerm(TNode n) {
}
Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
+ Trace("strings-exp-def") << "TheoryStrings::expandDefinition : " << node << std::endl;
return node;
}
@@ -740,53 +758,23 @@ void TheoryStrings::eqNotifyNewClass(TNode t){
/** called when two equivalance classes will merge */
void TheoryStrings::eqNotifyPreMerge(TNode t1, TNode t2){
- EqcInfo * e2 = getOrMakeEqcInfo(t2, false);
- 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 );
- }
- if( e2->d_cardinality_lem_k.get()>e1->d_cardinality_lem_k.get() ) {
- e1->d_cardinality_lem_k.set( e2->d_cardinality_lem_k );
- }
- if( !e2->d_normalized_length.get().isNull() ){
- e1->d_normalized_length.set( e2->d_normalized_length );
- }
+ EqcInfo * e2 = getOrMakeEqcInfo(t2, false);
+ 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( hasTerm( d_zero ) ){
- Node leqc;
- if( areEqual(d_zero, t1) ){
- leqc = t2;
- }else if( areEqual(d_zero, t2) ){
- leqc = t1;
- }
- if( !leqc.isNull() ){
- //scan equivalence class to see if we apply
- eq::EqClassIterator eqc_i = eq::EqClassIterator( leqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ){
- Node n = (*eqc_i);
- if( n.getKind()==kind::STRING_LENGTH ){
- if( !hasTerm( d_emptyString ) || !areEqual(n[0], d_emptyString ) ){
- //apply the rule length(n[0])==0 => n[0] == ""
- Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, n[0], d_emptyString );
- d_pending.push_back( eq );
- Node eq_exp = NodeManager::currentNM()->mkNode( kind::EQUAL, n, d_zero );
- d_pending_exp[eq] = eq_exp;
- Trace("strings-infer") << "Strings : Infer Empty : " << eq << " from " << eq_exp << std::endl;
- d_infer.push_back(eq);
- d_infer_exp.push_back(eq_exp);
- }
- }
- ++eqc_i;
- }
- }
+ if( !e2->d_length_term.get().isNull() ){
+ e1->d_length_term.set( e2->d_length_term );
+ }
+ if( e2->d_cardinality_lem_k.get()>e1->d_cardinality_lem_k.get() ) {
+ e1->d_cardinality_lem_k.set( e2->d_cardinality_lem_k );
}
- */
+ if( !e2->d_normalized_length.get().isNull() ){
+ e1->d_normalized_length.set( e2->d_normalized_length );
+ }
+ }
}
/** called when two equivalance classes have merged */
@@ -796,11 +784,106 @@ void TheoryStrings::eqNotifyPostMerge(TNode t1, TNode t2) {
/** called when two equivalance classes are disequal */
void TheoryStrings::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ if( t1.getType().isString() ){
+ //store disequalities between strings, may need to check if their lengths are equal/disequal
+ d_ee_disequalities.push_back( t1.eqNode( t2 ) );
+ }
+}
+void TheoryStrings::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth ) {
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !d_equalityEngine.areEqual( f1, f2 ) ){
+ Trace("strings-cg-debug") << "TheoryStrings::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
+ vector< pair<TNode, TNode> > currentPairs;
+ for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+ TNode x = f1[k];
+ TNode y = f2[k];
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !d_equalityEngine.areDisequal( x, y, false ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_STRINGS) && d_equalityEngine.isTriggerTerm(y, THEORY_STRINGS) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_STRINGS);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_STRINGS);
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
+ }
+ }
+ }
+ }
+ 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);
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1 );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
+ }
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
+ }
+ }
+ }
+ }
+ }
}
void TheoryStrings::computeCareGraph(){
- Theory::computeCareGraph();
+ //computing the care graph here is probably still necessary, due to operators that take non-string arguments TODO: verify
+ Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Build term indices..." << std::endl;
+ std::map< Node, quantifiers::TermArgTrie > index;
+ std::map< Node, unsigned > arity;
+ unsigned functionTerms = d_functionsTerms.size();
+ for (unsigned i = 0; i < functionTerms; ++ i) {
+ TNode f1 = d_functionsTerms[i];
+ Trace("strings-cg") << "...build for " << f1 << std::endl;
+ Node op = f1.getOperator();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_STRINGS ) ){
+ has_trigger_arg = true;
+ }
+ }
+ if( has_trigger_arg ){
+ index[op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = index.begin(); itii != index.end(); ++itii ){
+ Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Process index " << itii->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0 );
+ }
}
void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
@@ -1136,8 +1219,12 @@ void TheoryStrings::checkExtendedFuncsEval( int effort ) {
}else{
if( !areEqual( n, nrc ) ){
if( n.getType().isBoolean() ){
- d_extf_exp[n].push_back( nrc==d_true ? n.negate() : n );
- conc = d_false;
+ if( areEqual( n, nrc==d_true ? d_false : d_true ) ){
+ d_extf_exp[n].push_back( nrc==d_true ? n.negate() : n );
+ conc = d_false;
+ }else{
+ conc = nrc==d_true ? n : n.negate();
+ }
}else{
conc = n.eqNode( nrc );
}
@@ -1145,7 +1232,7 @@ void TheoryStrings::checkExtendedFuncsEval( int effort ) {
}
if( !conc.isNull() ){
Trace("strings-extf") << " resolve extf : " << nr << " -> " << nrc << std::endl;
- sendInference( d_extf_exp[n], conc, effort==0 ? "EXTF" : "EXTF-N", n.getType().isInteger() || d_extf_exp[n].empty() );
+ sendInference( d_extf_exp[n], conc, effort==0 ? "EXTF" : "EXTF-N", true );
if( d_conflict ){
Trace("strings-extf-debug") << " conflict, return." << std::endl;
return;
@@ -1745,9 +1832,9 @@ bool TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & n
}
nf.insert( nf.end(), normal_forms[nf_index].begin(), normal_forms[nf_index].end() );
nf_exp.insert( nf_exp.end(), normal_forms_exp[nf_index].begin(), normal_forms_exp[nf_index].end() );
- //if( eqc!=normal_form_src[nf_index] ){
- // nf_exp.push_back( eqc.eqNode( normal_form_src[nf_index] ) );
- //}
+ if( eqc!=normal_form_src[nf_index] ){
+ nf_exp.push_back( eqc.eqNode( normal_form_src[nf_index] ) );
+ }
Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
d_normal_forms_base[eqc] = normal_form_src[nf_index];
//*/
@@ -2639,23 +2726,17 @@ int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node
void TheoryStrings::addNormalFormPair( Node n1, Node n2 ){
if( !isNormalFormPair( n1, n2 ) ){
- //Assert( !isNormalFormPair( n1, n2 ) );
- NodeList* lst;
- NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
- if( nf_i == d_nf_pairs.end() ){
- if( d_nf_pairs.find( n2 )!=d_nf_pairs.end() ){
- addNormalFormPair( n2, n1 );
- return;
- }
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_nf_pairs.insertDataFromContextMemory( n1, lst );
- Trace("strings-nf") << "Create cache for " << n1 << std::endl;
- } else {
- lst = (*nf_i).second;
- }
- Trace("strings-nf") << "Add normal form pair : " << n1 << " " << n2 << std::endl;
- lst->push_back( n2 );
+ int index = 0;
+ NodeIntMap::const_iterator it = d_nf_pairs.find( n1 );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ }
+ d_nf_pairs[n1] = index + 1;
+ if( index<(int)d_nf_pairs_data[n1].size() ){
+ d_nf_pairs_data[n1][index] = n2;
+ }else{
+ d_nf_pairs_data[n1].push_back( n2 );
+ }
Assert( isNormalFormPair( n1, n2 ) );
} else {
Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
@@ -2668,15 +2749,14 @@ bool TheoryStrings::isNormalFormPair( Node n1, Node n2 ) {
}
bool TheoryStrings::isNormalFormPair2( Node n1, Node n2 ) {
- //Trace("strings-debug") << "is normal form pair. " << n1 << " " << n2 << std::endl;
- NodeList* lst;
- NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
- if( nf_i != d_nf_pairs.end() ) {
- lst = (*nf_i).second;
- for( NodeList::const_iterator i = lst->begin(); i != lst->end(); ++i ) {
- Node n = *i;
- if( n==n2 ) {
- return true;
+ //Trace("strings-debug") << "is normal form pair. " << n1 << " " << n2 << std::endl;
+ NodeIntMap::const_iterator it = d_nf_pairs.find( n1 );
+ if( it!=d_nf_pairs.end() ){
+ Assert( d_nf_pairs_data.find( n1 )!=d_nf_pairs_data.end() );
+ for( int i=0; i<(*it).second; i++ ){
+ Assert( i<(int)d_nf_pairs_data[n1].size() );
+ if( d_nf_pairs_data[n1][i]==n2 ){
+ return true;
}
}
}
@@ -2752,7 +2832,7 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
eq = eq.isNull() ? d_false : Rewriter::rewrite( eq );
if( eq!=d_true ){
if( Trace.isOn("strings-infer-debug") ){
- Trace("strings-infer-debug") << "infer : " << eq << " from: " << std::endl;
+ Trace("strings-infer-debug") << "By " << c << ", infer : " << eq << " from: " << std::endl;
for( unsigned i=0; i<exp.size(); i++ ){
Trace("strings-infer-debug") << " " << exp[i] << std::endl;
}
@@ -2761,8 +2841,8 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
}
//Trace("strings-infer-debug") << "as lemma : " << asLemma << std::endl;
}
- bool doSendLemma = ( asLemma || eq==d_false || eq.getKind()==kind::OR || options::stringInferAsLemmas() );
- if( doSendLemma ){
+ //check if we should send a lemma or an inference
+ if( asLemma || eq==d_false || eq.getKind()==kind::OR || !exp_n.empty() || options::stringInferAsLemmas() ){
Node eq_exp;
if( options::stringRExplainLemmas() ){
eq_exp = mkExplain( exp, exp_n );
@@ -2780,7 +2860,6 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
}
sendLemma( eq_exp, eq, c );
}else{
- Assert( exp_n.empty() );
sendInfer( mkAnd( exp ), eq, c );
}
}
@@ -3064,30 +3143,56 @@ void TheoryStrings::getConcatVec( Node n, std::vector< Node >& c ) {
void TheoryStrings::checkDeqNF() {
std::vector< std::vector< Node > > cols;
std::vector< Node > lts;
- separateByLength( d_strings_eqc, cols, lts );
- for( unsigned i=0; i<cols.size(); i++ ){
- if( cols[i].size()>1 && d_lemma_cache.empty() ){
- Trace("strings-solve") << "- Verify disequalities are processed for " << cols[i][0];
- printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
- Trace("strings-solve") << "... #eql = " << cols[i].size() << std::endl;
- //must ensure that normal forms are disequal
- for( unsigned j=0; j<cols[i].size(); j++ ){
- for( unsigned k=(j+1); k<cols[i].size(); k++ ){
- if( areDisequal( cols[i][j], cols[i][k] ) ){
- Assert( !d_conflict );
- //if( !areDisequal( cols[i][j], cols[i][k] ) ){
- // sendSplit( cols[i][j], cols[i][k], "D-NORM", true );
- // return;
- //}else{
- Trace("strings-solve") << "- Compare " << cols[i][j] << " ";
- printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
- Trace("strings-solve") << " against " << cols[i][k] << " ";
- printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
- Trace("strings-solve") << "..." << std::endl;
- if( processDeq( cols[i][j], cols[i][k] ) ){
- return;
+ std::map< Node, std::map< Node, bool > > processed;
+
+ //for each pair of disequal strings, must determine whether their lengths are equal or disequal
+ bool addedLSplit = false;
+ for( NodeList::const_iterator id = d_ee_disequalities.begin(); id != d_ee_disequalities.end(); ++id ) {
+ Node eq = *id;
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ n[i] = d_equalityEngine.getRepresentative( eq[i] );
+ }
+ if( processed[n[0]].find( n[1] )==processed[n[0]].end() ){
+ processed[n[0]][n[1]] = true;
+ Node lt[2];
+ for( unsigned i=0; i<2; i++ ){
+ EqcInfo* ei = getOrMakeEqcInfo( n[i], false );
+ lt[i] = ei ? ei->d_length_term : Node::null();
+ if( lt[i].isNull() ){
+ lt[i] = eq[i];
+ }
+ lt[i] = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt[i] );
+ }
+ if( !areEqual( lt[0], lt[1] ) && !areDisequal( lt[0], lt[1] ) ){
+ addedLSplit = true;
+ sendSplit( lt[0], lt[1], "DEQ-LENGTH-SP" );
+ }
+ }
+ }
+
+ if( !addedLSplit ){
+ separateByLength( d_strings_eqc, cols, lts );
+ for( unsigned i=0; i<cols.size(); i++ ){
+ if( cols[i].size()>1 && d_lemma_cache.empty() ){
+ Trace("strings-solve") << "- Verify disequalities are processed for " << cols[i][0] << ", normal form : ";
+ printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
+ Trace("strings-solve") << "... #eql = " << cols[i].size() << std::endl;
+ //must ensure that normal forms are disequal
+ for( unsigned j=0; j<cols[i].size(); j++ ){
+ for( unsigned k=(j+1); k<cols[i].size(); k++ ){
+ //for strings that are disequal, but have the same length
+ if( areDisequal( cols[i][j], cols[i][k] ) ){
+ Assert( !d_conflict );
+ Trace("strings-solve") << "- Compare " << cols[i][j] << " ";
+ printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
+ Trace("strings-solve") << " against " << cols[i][k] << " ";
+ printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ if( processDeq( cols[i][j], cols[i][k] ) ){
+ return;
+ }
}
- //}
}
}
}
@@ -3149,6 +3254,9 @@ void TheoryStrings::checkCardinality() {
//int cardinality = options::stringCharCardinality();
//Trace("strings-solve-debug2") << "get cardinality: " << cardinality << endl;
+ //AJR: this will create a partition of eqc, where each collection has length that are pairwise propagated to be equal.
+ // we do not require disequalities between the lengths of each collection, since we split on disequalities between lengths of string terms that are disequal (DEQ-LENGTH-SP).
+ // TODO: revisit this?
std::vector< std::vector< Node > > cols;
std::vector< Node > lts;
separateByLength( d_strings_eqc, cols, lts );
@@ -3159,54 +3267,51 @@ void TheoryStrings::checkCardinality() {
if( cols[i].size() > 1 ) {
// size > c^k
unsigned card_need = 1;
- double curr = (double)cols[i].size()-1;
+ double curr = (double)cols[i].size();
while( curr>d_card_size ){
curr = curr/(double)d_card_size;
card_need++;
}
+ Trace("strings-card") << "Need length " << card_need << " for this number of strings (where alphabet size is " << d_card_size << ")." << std::endl;
Node cmp = NodeManager::currentNM()->mkNode( kind::GEQ, lr, NodeManager::currentNM()->mkConst( Rational( card_need ) ) );
cmp = Rewriter::rewrite( cmp );
if( cmp!=d_true ){
unsigned int int_k = (unsigned int)card_need;
- bool allDisequal = true;
for( std::vector< Node >::iterator itr1 = cols[i].begin();
itr1 != cols[i].end(); ++itr1) {
for( std::vector< Node >::iterator itr2 = itr1 + 1;
itr2 != cols[i].end(); ++itr2) {
if(!areDisequal( *itr1, *itr2 )) {
- allDisequal = false;
// add split lemma
sendSplit( *itr1, *itr2, "CARD-SP" );
return;
}
}
}
- if( allDisequal ){
- EqcInfo* ei = getOrMakeEqcInfo( lr, true );
- Trace("strings-card") << "Previous cardinality used for " << lr << " is " << ((int)ei->d_cardinality_lem_k.get()-1) << std::endl;
- if( int_k+1 > ei->d_cardinality_lem_k.get() ){
- Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
- //add cardinality lemma
- Node dist = NodeManager::currentNM()->mkNode( kind::DISTINCT, cols[i] );
- std::vector< Node > vec_node;
- vec_node.push_back( dist );
- for( std::vector< Node >::iterator itr1 = cols[i].begin();
- itr1 != cols[i].end(); ++itr1) {
- Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr1 );
- if( len!=lr ) {
- Node len_eq_lr = len.eqNode(lr);
- vec_node.push_back( len_eq_lr );
- }
- }
- Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
- Node cons = NodeManager::currentNM()->mkNode( kind::GEQ, len, k_node );
- cons = Rewriter::rewrite( cons );
- ei->d_cardinality_lem_k.set( int_k+1 );
- if( cons!=d_true ){
- sendInference( d_empty_vec, vec_node, cons, "CARDINALITY", true );
- return;
+ EqcInfo* ei = getOrMakeEqcInfo( lr, true );
+ Trace("strings-card") << "Previous cardinality used for " << lr << " is " << ((int)ei->d_cardinality_lem_k.get()-1) << std::endl;
+ if( int_k+1 > ei->d_cardinality_lem_k.get() ){
+ Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
+ //add cardinality lemma
+ Node dist = NodeManager::currentNM()->mkNode( kind::DISTINCT, cols[i] );
+ std::vector< Node > vec_node;
+ vec_node.push_back( dist );
+ for( std::vector< Node >::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end(); ++itr1) {
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr1 );
+ if( len!=lr ) {
+ Node len_eq_lr = len.eqNode(lr);
+ vec_node.push_back( len_eq_lr );
}
}
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
+ Node cons = NodeManager::currentNM()->mkNode( kind::GEQ, len, k_node );
+ cons = Rewriter::rewrite( cons );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( cons!=d_true ){
+ sendInference( d_empty_vec, vec_node, cons, "CARDINALITY", true );
+ return;
+ }
}
}
}
@@ -3275,11 +3380,9 @@ void TheoryStrings::separateByLength(std::vector< Node >& n,
Assert( d_equalityEngine.getRepresentative(eqc)==eqc );
EqcInfo* ei = getOrMakeEqcInfo( eqc, false );
Node lt = ei ? ei->d_length_term : Node::null();
- Trace("ajr-temp") << "Length term for " << eqc << " is " << lt << std::endl;
if( !lt.isNull() ){
lt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
Node r = d_equalityEngine.getRepresentative( lt );
- Trace("ajr-temp") << "Length term rep for " << eqc << " is " << lt << std::endl;
if( eqc_to_leqc.find( r )==eqc_to_leqc.end() ){
eqc_to_leqc[r] = leqc_counter;
leqc_to_eqc[leqc_counter] = r;
@@ -3318,6 +3421,26 @@ void TheoryStrings::updateMpl( Node n, int b ) {
}
*/
+
+unsigned TheoryStrings::getNumMemberships( Node n, bool isPos ) {
+ if( isPos ){
+ NodeIntMap::const_iterator it = d_pos_memberships.find( n );
+ if( it!=d_pos_memberships.end() ){
+ return (*it).second;
+ }
+ }else{
+ NodeIntMap::const_iterator it = d_neg_memberships.find( n );
+ if( it!=d_neg_memberships.end() ){
+ return (*it).second;
+ }
+ }
+ return 0;
+}
+
+Node TheoryStrings::getMembership( Node n, bool isPos, unsigned i ) {
+ return isPos ? d_pos_memberships_data[n][i] : d_neg_memberships_data[n][i];
+}
+
//// Regular Expressions
Node TheoryStrings::mkRegExpAntec(Node atom, Node ant) {
if(d_regexp_ant.find(atom) == d_regexp_ant.end()) {
@@ -3395,10 +3518,8 @@ bool TheoryStrings::normalizePosMemberships(std::map< Node, std::vector< Node >
Trace("regexp-check") << "Normalizing Positive Memberships ... " << std::endl;
- for(NodeListMap::const_iterator itr_xr = d_pos_memberships.begin();
- itr_xr != d_pos_memberships.end(); ++itr_xr ) {
+ for( NodeIntMap::const_iterator itr_xr = d_pos_memberships.begin(); itr_xr != d_pos_memberships.end(); ++itr_xr ){
Node x = (*itr_xr).first;
- NodeList* lst = (*itr_xr).second;
Node nf_x = x;
std::vector< Node > nf_x_exp;
if(d_normal_forms.find( x ) != d_normal_forms.end()) {
@@ -3412,10 +3533,11 @@ bool TheoryStrings::normalizePosMemberships(std::map< Node, std::vector< Node >
std::vector< Node > vec_x;
std::vector< Node > vec_r;
- for(NodeList::const_iterator itr_lst = lst->begin();
- itr_lst != lst->end(); ++itr_lst) {
- Node r = *itr_lst;
- Node nf_r = normalizeRegexp((*lst)[0]);
+ unsigned n_pmem = (*itr_xr).second;
+ Assert( getNumMemberships( x, true )==n_pmem );
+ for( unsigned k=0; k<n_pmem; k++ ){
+ Node r = getMembership( x, true, k );
+ Node nf_r = normalizeRegexp( r ); //AJR: fixed (was normalizing mem #0 always)
Node memb = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, nf_x, nf_r);
if(d_processed_memberships.find(memb) == d_processed_memberships.end()) {
if(d_regexp_opr.checkConstRegExp(nf_r)) {
@@ -3645,46 +3767,43 @@ void TheoryStrings::checkMemberships() {
Trace("regexp-debug") << "Checking Memberships ... " << std::endl;
//if(options::stringEIT()) {
//TODO: Opt for normal forms
- for(NodeListMap::const_iterator itr_xr = d_pos_memberships.begin();
- itr_xr != d_pos_memberships.end(); ++itr_xr ) {
+ for( NodeIntMap::const_iterator itr_xr = d_pos_memberships.begin(); itr_xr != d_pos_memberships.end(); ++itr_xr ){
bool spflag = false;
Node x = (*itr_xr).first;
- NodeList* lst = (*itr_xr).second;
Trace("regexp-debug") << "Checking Memberships for " << x << std::endl;
if(d_inter_index.find(x) == d_inter_index.end()) {
d_inter_index[x] = 0;
}
int cur_inter_idx = d_inter_index[x];
- if(cur_inter_idx != (int)lst->size()) {
- if(lst->size() == 1) {
- d_inter_cache[x] = (*lst)[0];
+ unsigned n_pmem = (*itr_xr).second;
+ Assert( getNumMemberships( x, true )==n_pmem );
+ if( cur_inter_idx != (int)n_pmem ) {
+ if( n_pmem == 1) {
+ d_inter_cache[x] = getMembership( x, true, 0 );
d_inter_index[x] = 1;
Trace("regexp-debug") << "... only one choice " << std::endl;
- } else if(lst->size() > 1) {
+ } else if(n_pmem > 1) {
Node r;
if(d_inter_cache.find(x) != d_inter_cache.end()) {
r = d_inter_cache[x];
}
if(r.isNull()) {
- r = (*lst)[0];
+ r = getMembership( x, true, 0 );
cur_inter_idx = 1;
}
- NodeList::const_iterator itr_lst = lst->begin();
- for(int i=0; i<cur_inter_idx; i++) {
- ++itr_lst;
- }
- Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << lst->size() << std::endl;
- for(;itr_lst != lst->end(); ++itr_lst) {
- Node r2 = *itr_lst;
+
+ unsigned k_start = cur_inter_idx;
+ Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << n_pmem << std::endl;
+ for(unsigned k = k_start; k<n_pmem; k++) {
+ Node r2 = getMembership( x, true, k );
r = d_regexp_opr.intersect(r, r2, spflag);
if(spflag) {
break;
} else if(r == d_emptyRegexp) {
std::vector< Node > vec_nodes;
- ++itr_lst;
- for(NodeList::const_iterator itr2 = lst->begin();
- itr2 != itr_lst; ++itr2) {
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, *itr2);
+ for( unsigned kk=0; kk<=k; kk++ ){
+ Node rr = getMembership( x, true, kk );
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, rr);
vec_nodes.push_back( n );
}
Node conc;
@@ -3699,7 +3818,7 @@ void TheoryStrings::checkMemberships() {
//updates
if(!d_conflict && !spflag) {
d_inter_cache[x] = r;
- d_inter_index[x] = (int)lst->size();
+ d_inter_index[x] = (int)n_pmem;
}
}
}
@@ -4322,44 +4441,52 @@ void TheoryStrings::addMembership(Node assertion) {
Node x = atom[0];
Node r = atom[1];
if(polarity) {
- NodeList* lst;
- NodeListMap::iterator itr_xr = d_pos_memberships.find( x );
- if( itr_xr == d_pos_memberships.end() ){
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_pos_memberships.insertDataFromContextMemory( x, lst );
- } else {
- lst = (*itr_xr).second;
- }
- //check
- for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
- if( r == *itr ) {
- return;
+ int index = 0;
+ NodeIntMap::const_iterator it = d_pos_memberships.find( x );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ for( int k=0; k<index; k++ ){
+ if( k<(int)d_pos_memberships_data[x].size() ){
+ if( d_pos_memberships_data[x][k]==r ){
+ return;
+ }
+ }else{
+ break;
+ }
}
}
- lst->push_back( r );
+ d_pos_memberships[x] = index + 1;
+ if( index<(int)d_pos_memberships_data[x].size() ){
+ d_pos_memberships_data[x][index] = r;
+ }else{
+ d_pos_memberships_data[x].push_back( r );
+ }
} else if(!options::stringIgnNegMembership()) {
/*if(options::stringEIT() && d_regexp_opr.checkConstRegExp(r)) {
int rt;
Node r2 = d_regexp_opr.complement(r, rt);
Node a = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r2);
}*/
- NodeList* lst;
- NodeListMap::iterator itr_xr = d_neg_memberships.find( x );
- if( itr_xr == d_neg_memberships.end() ){
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_neg_memberships.insertDataFromContextMemory( x, lst );
- } else {
- lst = (*itr_xr).second;
- }
- //check
- for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
- if( r == *itr ) {
- return;
+ int index = 0;
+ NodeIntMap::const_iterator it = d_neg_memberships.find( x );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ for( int k=0; k<index; k++ ){
+ if( k<(int)d_neg_memberships_data[x].size() ){
+ if( d_neg_memberships_data[x][k]==r ){
+ return;
+ }
+ }else{
+ break;
+ }
}
}
- lst->push_back( r );
+ d_neg_memberships[x] = index + 1;
+ if( index<(int)d_neg_memberships_data[x].size() ){
+ d_neg_memberships_data[x][index] = r;
+ }else{
+ d_neg_memberships_data[x].push_back( r );
+ }
}
// old
if(polarity || !options::stringIgnNegMembership()) {
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index b9da524de..2deb09654 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -33,6 +33,11 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace strings {
/**
@@ -45,7 +50,6 @@ typedef expr::Attribute< StringsProxyVarAttributeId, bool > StringsProxyVarAttri
class TheoryStrings : public Theory {
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
@@ -160,7 +164,8 @@ private:
std::map< Node, std::vector< Node > > d_normal_forms_exp;
std::map< Node, std::map< Node, std::map< bool, int > > > d_normal_forms_exp_depend;
//map of pairs of terms that have the same normal form
- NodeListMap d_nf_pairs;
+ NodeIntMap d_nf_pairs;
+ std::map< Node, std::vector< Node > > d_nf_pairs_data;
void addNormalFormPair( Node n1, Node n2 );
bool isNormalFormPair( Node n1, Node n2 );
bool isNormalFormPair2( Node n1, Node n2 );
@@ -176,6 +181,8 @@ private:
// extended functions inferences cache
NodeSet d_extf_infer_cache;
std::vector< Node > d_empty_vec;
+ //
+ NodeList d_ee_disequalities;
private:
NodeSet d_congruent;
std::map< Node, Node > d_eqc_to_const;
@@ -236,6 +243,8 @@ private:
//maintain which concat terms have the length lemma instantiated
NodeNodeMap d_proxy_var;
NodeNodeMap d_proxy_var_to_length;
+ /** All the function terms that the theory has seen */
+ context::CDList<TNode> d_functionsTerms;
private:
//initial check
void checkInit();
@@ -304,6 +313,8 @@ private:
//cardinality check
void checkCardinality();
+private:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth );
public:
/** preregister term */
void preRegisterTerm(TNode n);
@@ -410,8 +421,12 @@ private:
NodeSet d_regexp_ucached;
NodeSet d_regexp_ccached;
// stored assertions
- NodeListMap d_pos_memberships;
- NodeListMap d_neg_memberships;
+ NodeIntMap d_pos_memberships;
+ std::map< Node, std::vector< Node > > d_pos_memberships_data;
+ NodeIntMap d_neg_memberships;
+ std::map< Node, std::vector< Node > > d_neg_memberships_data;
+ unsigned getNumMemberships( Node n, bool isPos );
+ Node getMembership( Node n, bool isPos, unsigned i );
// semi normal forms for symbolic expression
std::map< Node, Node > d_nf_regexps;
std::map< Node, std::vector< Node > > d_nf_regexps_exp;
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index a4f42bddd..ba811644a 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -33,6 +33,10 @@ StringsPreprocess::StringsPreprocess( context::UserContext* u ) : d_cache( u ){
d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
}
+StringsPreprocess::~StringsPreprocess(){
+
+}
+
/*
int StringsPreprocess::checkFixLenVar( Node t ) {
int ret = 2;
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
index 5bc9667ea..abc7b5a91 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -40,6 +40,7 @@ private:
Node simplify( Node t, std::vector< Node > &new_nodes );
public:
StringsPreprocess( context::UserContext* u );
+ ~StringsPreprocess();
Node decompose( Node t, std::vector< Node > &new_nodes );
void simplify(std::vector< Node > &vec_node);
diff --git a/src/theory/term_registration_visitor.cpp b/src/theory/term_registration_visitor.cpp
index 830e7f809..e758002fa 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -37,8 +37,12 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE /*||
- parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
+ parent.getKind() == kind::REWRITE_RULE ||
+ parent.getKind() == kind::SEP_STAR ||
+ parent.getKind() == kind::SEP_WAND ||
+ ( parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean() )
+ // parent.getKind() == kind::CARDINALITY_CONSTRAINT
+ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
@@ -64,14 +68,8 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -130,14 +128,8 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -189,8 +181,12 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE /*||
- parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
+ parent.getKind() == kind::REWRITE_RULE ||
+ parent.getKind() == kind::SEP_STAR ||
+ parent.getKind() == kind::SEP_WAND ||
+ ( parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean() )
+ // parent.getKind() == kind::CARDINALITY_CONSTRAINT
+ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
@@ -222,14 +218,8 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -244,14 +234,8 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -297,14 +281,8 @@ void SharedTermsVisitor::visit(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 382d4cf65..e8518b1f6 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -781,6 +781,14 @@ public:
assertions_iterator facts_end() const {
return d_facts.end();
}
+ /**
+ * Whether facts have been asserted to this theory.
+ *
+ * @return true iff facts have been asserted to this theory.
+ */
+ bool hasFacts() {
+ return !d_facts.empty();
+ }
typedef context::CDList<TNode>::const_iterator shared_terms_iterator;
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index f2231ff7a..881acdddd 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -26,6 +26,8 @@
#include "options/bv_options.h"
#include "options/options.h"
#include "options/quantifiers_options.h"
+#include "proof/cnf_proof.h"
+#include "proof/lemma_proof.h"
#include "proof/proof_manager.h"
#include "proof/theory_proof.h"
#include "smt/ite_removal.h"
@@ -53,6 +55,104 @@ using namespace CVC4::theory;
namespace CVC4 {
+inline void flattenAnd(Node n, std::vector<TNode>& out){
+ Assert(n.getKind() == kind::AND);
+ for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){
+ Node curr = *i;
+ if(curr.getKind() == kind::AND){
+ flattenAnd(curr, out);
+ }else{
+ out.push_back(curr);
+ }
+ }
+}
+
+inline Node flattenAnd(Node n){
+ std::vector<TNode> out;
+ flattenAnd(n, out);
+ return NodeManager::currentNM()->mkNode(kind::AND, out);
+}
+
+theory::LemmaStatus TheoryEngine::EngineOutputChannel::lemma(TNode lemma,
+ ProofRule rule,
+ bool removable,
+ bool preprocess,
+ bool sendAtoms)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
+ Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << ", preprocess = " << preprocess << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ PROOF({
+ // Theory lemmas have one step that proves the empty clause
+ proofRecipe = new LemmaProofRecipe;
+
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(d_theory, emptyNode);
+
+ Node rewritten;
+ if (lemma.getKind() == kind::OR) {
+ for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
+ rewritten = theory::Rewriter::rewrite(lemma[i]);
+ if (rewritten != lemma[i]) {
+ proofRecipe->addRewriteRule(lemma[i].negate(), rewritten.negate());
+ }
+ proofStep.addAssertion(lemma[i]);
+ proofRecipe->addBaseAssertion(rewritten);
+ }
+ } else {
+ rewritten = theory::Rewriter::rewrite(lemma);
+ if (rewritten != lemma) {
+ proofRecipe->addRewriteRule(lemma.negate(), rewritten.negate());
+ }
+ proofStep.addAssertion(lemma);
+ proofRecipe->addBaseAssertion(rewritten);
+ }
+ proofRecipe->addStep(proofStep);
+ });
+
+ theory::LemmaStatus result = d_engine->lemma(lemma,
+ rule,
+ false,
+ removable,
+ preprocess,
+ sendAtoms ? d_theory : theory::THEORY_LAST,
+ proofRecipe);
+ PROOF(delete proofRecipe;);
+ return result;
+}
+
+theory::LemmaStatus TheoryEngine::EngineOutputChannel::splitLemma(TNode lemma, bool removable)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
+ Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ Debug("pf::explain") << "TheoryEngine::EngineOutputChannel::splitLemma( " << lemma << " )" << std::endl;
+ theory::LemmaStatus result = d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory, proofRecipe);
+ return result;
+}
+
+bool TheoryEngine::EngineOutputChannel::propagate(TNode literal)
+ throw(AssertionException, UnsafeInterruptException) {
+ Debug("theory::propagate") << "EngineOutputChannel<" << d_theory << ">::propagate(" << literal << ")" << std::endl;
+ ++ d_statistics.propagations;
+ d_engine->d_outputChannelUsed = true;
+ return d_engine->propagate(literal, d_theory);
+}
+
+void TheoryEngine::EngineOutputChannel::conflict(TNode conflictNode, Proof* pf)
+ throw(AssertionException, UnsafeInterruptException) {
+ Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
+ Assert (pf == NULL); // Theory shouldn't be producing proofs yet
+ ++ d_statistics.conflicts;
+ d_engine->d_outputChannelUsed = true;
+ d_engine->conflict(conflictNode, d_theory);
+}
+
void TheoryEngine::finishInit() {
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
@@ -161,7 +261,9 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- PROOF (ProofManager::currentPM()->initTheoryProofEngine(); );
+#ifdef CVC4_PROOF
+ ProofManager::currentPM()->initTheoryProofEngine();
+#endif
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
@@ -416,18 +518,29 @@ void TheoryEngine::check(Theory::Effort effort) {
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
if( effort == Theory::EFFORT_FULL && ! d_inConflict && ! needCheck() ) {
- //d_theoryTable[THEORY_STRINGS]->check(Theory::EFFORT_LAST_CALL);
- if(d_logicInfo.isQuantified()) {
- // quantifiers engine must pass effort last call check
- d_quantEngine->check(Theory::EFFORT_LAST_CALL);
- // if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built
- } else if(options::produceModels()) {
- // must build model at this point
- d_curr_model_builder->buildModel(d_curr_model, true);
+ //calls to theories requiring the model go here
+ //FIXME: this should not be theory-specific
+ if(d_logicInfo.isTheoryEnabled(THEORY_SEP)) {
+ Assert( d_theoryTable[THEORY_SEP]!=NULL );
+ if( d_theoryTable[THEORY_SEP]->hasFacts() ){
+ // must build model at this point
+ d_curr_model_builder->buildModel(getModel(), false);
+ d_theoryTable[THEORY_SEP]->check(Theory::EFFORT_LAST_CALL);
+ }
}
- Trace("theory::assertions-model") << endl;
- if (Trace.isOn("theory::assertions-model")) {
- printAssertions("theory::assertions-model");
+ if( ! d_inConflict && ! needCheck() ){
+ if(d_logicInfo.isQuantified()) {
+ // quantifiers engine must pass effort last call check
+ d_quantEngine->check(Theory::EFFORT_LAST_CALL);
+ // if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built
+ } else if(options::produceModels()) {
+ // must build model at this point
+ d_curr_model_builder->buildModel(getModel(), true);
+ }
+ Trace("theory::assertions-model") << endl;
+ if (Trace.isOn("theory::assertions-model")) {
+ printAssertions("theory::assertions-model");
+ }
}
}
@@ -497,7 +610,10 @@ void TheoryEngine::combineTheories() {
// We need to split on it
Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
- lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory, carePair.theory);
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory, proofRecipe);
+
// This code is supposed to force preference to follow what the theory models already have
// but it doesn't seem to make a big difference - need to explore more -Clark
// if (true) {
@@ -963,7 +1079,7 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
- Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl;
Assert(toTheoryId != fromTheoryId);
if(toTheoryId != THEORY_SAT_SOLVER &&
@@ -1176,6 +1292,23 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
}
} else {
+ // We could be propagating a unit-clause lemma. In this case, we need to provide a
+ // recipe.
+ // TODO: Consider putting this someplace else? This is the only refence to the proof
+ // manager in this class.
+
+ PROOF({
+ LemmaProofRecipe proofRecipe;
+ proofRecipe.addBaseAssertion(literal);
+
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theory, emptyNode);
+ proofStep.addAssertion(literal);
+ proofRecipe.addStep(proofStep);
+
+ ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
+ });
+
// Just send off to the SAT solver
Assert(d_propEngine->isSatLiteral(literal));
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
@@ -1270,7 +1403,7 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
return conjunction;
}
-NodeTheoryPair TheoryEngine::getExplanationAndExplainer(TNode node) {
+Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) {
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
@@ -1278,32 +1411,90 @@ NodeTheoryPair TheoryEngine::getExplanationAndExplainer(TNode node) {
// If we're not in shared mode, explanations are simple
if (!d_logicInfo.isSharingEnabled()) {
+ Debug("theory::explain") << "TheoryEngine::getExplanation: sharing is NOT enabled. "
+ << " Responsible theory is: "
+ << theoryOf(atom)->getId() << std::endl;
+
Node explanation = theoryOf(atom)->explain(node);
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
- return NodeTheoryPair(explanation, theoryOf(atom)->getId());
+ PROOF({
+ if(proofRecipe) {
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theoryOf(atom)->getId(), emptyNode);
+ proofStep.addAssertion(node);
+ proofRecipe->addBaseAssertion(node);
+
+ if (explanation.getKind() == kind::AND) {
+ // If the explanation is a conjunction, the recipe for the corresponding lemma is
+ // the negation of its conjuncts.
+ Node flat = flattenAnd(explanation);
+ for (unsigned i = 0; i < flat.getNumChildren(); ++i) {
+ if (flat[i].isConst() && flat[i].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ if (flat[i].getKind() == kind::NOT &&
+ flat[i][0].isConst() && !flat[i][0].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ Debug("theory::explain") << "TheoryEngine::getExplanationAndRecipe: adding recipe assertion: "
+ << flat[i].negate() << std::endl;
+ proofStep.addAssertion(flat[i].negate());
+ proofRecipe->addBaseAssertion(flat[i].negate());
+ }
+ } else {
+ // The recipe for proving it is by negating it. "True" is not an acceptable reason.
+ if (!((explanation.isConst() && explanation.getConst<bool>()) ||
+ (explanation.getKind() == kind::NOT &&
+ explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
+ proofStep.addAssertion(explanation.negate());
+ proofRecipe->addBaseAssertion(explanation.negate());
+ }
+ }
+
+ proofRecipe->addStep(proofStep);
+ }
+ });
+
+ return explanation;
}
+ Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
+
// Initial thing to explain
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
Assert(d_propagationMap.find(toExplain) != d_propagationMap.end());
NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain];
+ Debug("theory::explain") << "TheoryEngine::getExplanation: explainer for node "
+ << nodeExplainerPair.node
+ << " is theory: " << nodeExplainerPair.theory << std::endl;
TheoryId explainer = nodeExplainerPair.theory;
// Create the workplace for explanations
std::vector<NodeTheoryPair> explanationVector;
explanationVector.push_back(d_propagationMap[toExplain]);
// Process the explanation
- getExplanation(explanationVector);
+ if (proofRecipe) {
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(explainer, emptyNode);
+ proofStep.addAssertion(node);
+ proofRecipe->addStep(proofStep);
+ proofRecipe->addBaseAssertion(node);
+ }
+
+ getExplanation(explanationVector, proofRecipe);
Node explanation = mkExplanation(explanationVector);
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
- return NodeTheoryPair(explanation, explainer);
+ return explanation;
}
Node TheoryEngine::getExplanation(TNode node) {
- return getExplanationAndExplainer(node).node;
+ LemmaProofRecipe *dontCareRecipe = NULL;
+ return getExplanationAndRecipe(node, dontCareRecipe);
}
struct AtomsCollect {
@@ -1406,7 +1597,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
bool removable,
bool preprocess,
theory::TheoryId atomsTo,
- theory::TheoryId ownerTheory) {
+ LemmaProofRecipe* proofRecipe) {
// For resource-limiting (also does a time check).
// spendResource();
@@ -1456,10 +1647,10 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, ownerTheory, node);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, proofRecipe, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, ownerTheory, node);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, proofRecipe, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
@@ -1493,22 +1684,69 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
<< CheckSatCommand(conflict.toExpr());
}
+ LemmaProofRecipe* proofRecipe = NULL;
+ PROOF({
+ proofRecipe = new LemmaProofRecipe;
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
+
+ if (conflict.getKind() == kind::AND) {
+ for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+ proofStep.addAssertion(conflict[i].negate());
+ }
+ } else {
+ proofStep.addAssertion(conflict.negate());
+ }
+
+ proofRecipe->addStep(proofStep);
+ });
+
// In the multiple-theories case, we need to reconstruct the conflict
if (d_logicInfo.isSharingEnabled()) {
// Create the workplace for explanations
std::vector<NodeTheoryPair> explanationVector;
explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
+
// Process the explanation
- getExplanation(explanationVector);
+ getExplanation(explanationVector, proofRecipe);
Node fullConflict = mkExplanation(explanationVector);
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST, theoryId);
+ lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST, proofRecipe);
+
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST, theoryId);
+ PROOF({
+ if (conflict.getKind() == kind::AND) {
+ // If the conflict is a conjunction, the corresponding lemma is derived by negating
+ // its conjuncts.
+ for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+ if (conflict[i].isConst() && conflict[i].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ if (conflict[i].getKind() == kind::NOT &&
+ conflict[i][0].isConst() && !conflict[i][0].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ proofRecipe->getStep(0)->addAssertion(conflict[i].negate());
+ proofRecipe->addBaseAssertion(conflict[i].negate());
+ }
+ } else {
+ proofRecipe->getStep(0)->addAssertion(conflict.negate());
+ proofRecipe->addBaseAssertion(conflict.negate());
+ }
+ });
+
+ lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST, proofRecipe);
}
+
+ PROOF({
+ delete proofRecipe;
+ proofRecipe = NULL;
+ });
}
void TheoryEngine::staticInitializeBVOptions(const std::vector<Node>& assertions) {
@@ -1558,15 +1796,9 @@ void TheoryEngine::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
Node TheoryEngine::ppSimpITE(TNode assertion)
{
- if(options::incrementalSolving()){
- // disabling the d_iteUtilities->simpITE(assertion) pass for incremental solving.
- // This is paranoia. We do not actually know of a bug coming from this.
- // TODO re-enable
+ if (!d_iteRemover.containsTermITE(assertion)) {
return assertion;
- } else if(!d_iteRemover.containsTermITE(assertion)){
- return assertion;
- }else{
-
+ } else {
Node result = d_iteUtilities->simpITE(assertion);
Node res_rewritten = Rewriter::rewrite(result);
@@ -1576,10 +1808,9 @@ Node TheoryEngine::ppSimpITE(TNode assertion)
Chat() << "ending simplifyWithCare()"
<< " post simplifyWithCare()" << postSimpWithCare.getId() << endl;
result = Rewriter::rewrite(postSimpWithCare);
- }else{
+ } else {
result = res_rewritten;
}
-
return result;
}
}
@@ -1667,19 +1898,21 @@ bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
return result;
}
-void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector)
-{
+void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) {
Assert(explanationVector.size() > 0);
unsigned i = 0; // Index of the current literal we are processing
unsigned j = 0; // Index of the last literal we are keeping
- while (i < explanationVector.size()) {
+ std::set<Node> inputAssertions;
+ PROOF(inputAssertions = proofRecipe->getStep(0)->getAssertions(););
+ while (i < explanationVector.size()) {
// Get the current literal to explain
NodeTheoryPair toExplain = explanationVector[i];
- Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
+ Debug("theory::explain") << "[i=" << i << "] TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
+
// If a true constant or a negation of a false constant we can ignore it
if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) {
@@ -1693,6 +1926,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// If from the SAT solver, keep it
if (toExplain.theory == THEORY_SAT_SOLVER) {
+ Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl;
explanationVector[j++] = explanationVector[i++];
continue;
}
@@ -1711,10 +1945,26 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// See if it was sent to the theory by another theory
PropagationMap::const_iterator find = d_propagationMap.find(toExplain);
if (find != d_propagationMap.end()) {
+ Debug("theory::explain") << "\tTerm was propagated by another theory (theory = "
+ << theoryOf((*find).second.theory)->getId() << ")" << std::endl;
// There is some propagation, check if its a timely one
if ((*find).second.timestamp < toExplain.timestamp) {
+ Debug("theory::explain") << "\tRelevant timetsamp, pushing "
+ << (*find).second.node << "to index = " << explanationVector.size() << std::endl;
explanationVector.push_back((*find).second);
- ++ i;
+ ++i;
+
+ PROOF({
+ if (toExplain.node != (*find).second.node) {
+ Debug("pf::explain") << "TheoryEngine::getExplanation: Rewrite alert! toAssert = " << toExplain.node
+ << ", toExplain = " << (*find).second.node << std::endl;
+
+ if (proofRecipe) {
+ proofRecipe->addRewriteRule(toExplain.node, (*find).second.node);
+ }
+ }
+ })
+
continue;
}
}
@@ -1723,21 +1973,61 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
Node explanation;
if (toExplain.theory == THEORY_BUILTIN) {
explanation = d_sharedTerms.explain(toExplain.node);
+ Debug("theory::explain") << "\tTerm was propagated by THEORY_BUILTIN. Explanation: " << explanation << std::endl;
} else {
explanation = theoryOf(toExplain.theory)->explain(toExplain.node);
+ Debug("theory::explain") << "\tTerm was propagated by owner theory: "
+ << theoryOf(toExplain.theory)->getId()
+ << ". Explanation: " << explanation << std::endl;
}
+
Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << endl;
Assert(explanation != toExplain.node, "wasn't sent to you, so why are you explaining it trivially");
// Mark the explanation
NodeTheoryPair newExplain(explanation, toExplain.theory, toExplain.timestamp);
explanationVector.push_back(newExplain);
+
++ i;
+
+ PROOF({
+ if (proofRecipe) {
+ // If we're expanding the target node of the explanation (this is the first expansion...),
+ // we don't want to add it as a separate proof step. It is already part of the assertions.
+ if (inputAssertions.find(toExplain.node) == inputAssertions.end()) {
+ LemmaProofRecipe::ProofStep proofStep(toExplain.theory, toExplain.node);
+ if (explanation.getKind() == kind::AND) {
+ Node flat = flattenAnd(explanation);
+ for (unsigned k = 0; k < flat.getNumChildren(); ++ k) {
+ // If a true constant or a negation of a false constant we can ignore it
+ if (! ((flat[k].isConst() && flat[k].getConst<bool>()) ||
+ (flat[k].getKind() == kind::NOT && flat[k][0].isConst() && !flat[k][0].getConst<bool>()))) {
+ proofStep.addAssertion(flat[k].negate());
+ }
+ }
+ } else {
+ if (! ((explanation.isConst() && explanation.getConst<bool>()) ||
+ (explanation.getKind() == kind::NOT && explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
+ proofStep.addAssertion(explanation.negate());
+ }
+ }
+ proofRecipe->addStep(proofStep);
+ }
+ }
+ });
}
// Keep only the relevant literals
explanationVector.resize(j);
-}
+ PROOF({
+ if (proofRecipe) {
+ // The remaining literals are the base of the proof
+ for (unsigned k = 0; k < explanationVector.size(); ++k) {
+ proofRecipe->addBaseAssertion(explanationVector[k].node.negate());
+ }
+ }
+ });
+}
void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
{
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index db94edd7c..53c4aac77 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -50,6 +50,7 @@
namespace CVC4 {
class ResourceManager;
+class LemmaProofRecipe;
/**
* A pair of a theory and a node. This is used to mark the flow of
@@ -270,46 +271,18 @@ class TheoryEngine {
}
}
- void conflict(TNode conflictNode, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException) {
- Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
- Assert(pf == NULL); // theory shouldn't be producing proofs yet
- ++ d_statistics.conflicts;
- d_engine->d_outputChannelUsed = true;
- d_engine->conflict(conflictNode, d_theory);
- }
+ void conflict(TNode conflictNode, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException);
- bool propagate(TNode literal) throw(AssertionException, UnsafeInterruptException) {
- Trace("theory::propagate") << "EngineOutputChannel<" << d_theory << ">::propagate(" << literal << ")" << std::endl;
- ++ d_statistics.propagations;
- d_engine->d_outputChannelUsed = true;
- return d_engine->propagate(literal, d_theory);
- }
+ bool propagate(TNode literal) throw(AssertionException, UnsafeInterruptException);
theory::LemmaStatus lemma(TNode lemma,
ProofRule rule,
bool removable = false,
bool preprocess = false,
bool sendAtoms = false)
- throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, rule, false, removable, preprocess, sendAtoms ? d_theory : theory::THEORY_LAST, d_theory);
- }
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException);
- /*theory::LemmaStatus preservedLemma(TNode lemma, bool removable = false, bool preprocess = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException, LogicException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::preservedLemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable, preprocess, d_theory);
- }*/
-
- theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::splitLemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory, d_theory);
- }
+ theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException);
void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
NodeManager* curr = NodeManager::currentNM();
@@ -456,7 +429,7 @@ class TheoryEngine {
bool removable,
bool preprocess,
theory::TheoryId atomsTo,
- theory::TheoryId ownerTheory);
+ LemmaProofRecipe* proofRecipe);
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
@@ -606,9 +579,10 @@ private:
* asking relevant theories to explain the propagations. Initially
* the explanation vector should contain only the element (node, theory)
* where the node is the one to be explained, and the theory is the
- * theory that sent the literal.
+ * theory that sent the literal. The lemmaProofRecipe will contain a list
+ * of the explanation steps required to produce the original node.
*/
- void getExplanation(std::vector<NodeTheoryPair>& explanationVector);
+ void getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* lemmaProofRecipe);
public:
@@ -730,7 +704,7 @@ public:
* Returns an explanation of the node propagated to the SAT solver and the theory
* that propagated it.
*/
- NodeTheoryPair getExplanationAndExplainer(TNode node);
+ Node getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe);
/**
* collect model info
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index fa7e497e2..f43a2aa7f 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -561,7 +561,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
TheoryModel* tm = (TheoryModel*)m;
// buildModel with fullModel = true should only be called once in any context
- Assert(!tm->d_modelBuilt);
+ Assert(!tm->isBuilt());
tm->d_modelBuilt = fullModel;
// Reset model
@@ -832,6 +832,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
Assert(!t.isBoolean() || (*i2).getKind() == kind::APPLY_UF);
Node n;
if (t.getCardinality().isInfinite()) {
+ // if (!t.isInterpretedFinite()) {
bool success;
do{
Trace("model-builder-debug") << "Enumerate term of type " << t << std::endl;
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index 6e4f77336..833b124eb 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -36,6 +36,7 @@ class TheoryModel : public Model
protected:
/** substitution map for this model */
SubstitutionMap d_substitutions;
+ context::CDO<bool> d_modelBuilt;
public:
TheoryModel(context::Context* c, std::string name, bool enableFuncModels);
virtual ~TheoryModel() throw();
@@ -51,7 +52,6 @@ public:
/** true/false nodes */
Node d_true;
Node d_false;
- context::CDO<bool> d_modelBuilt;
mutable std::hash_map<Node, Node, NodeHashFunction> d_modelCache;
protected:
@@ -62,6 +62,8 @@ protected:
*/
Node getModelValue(TNode n, bool hasBoundVars = false, bool useDontCares = false) const;
public:
+ /** is built */
+ bool isBuilt() { return d_modelBuilt.get(); }
/**
* Get value function. This should be called only after a ModelBuilder has called buildModel(...)
* on this model.
diff --git a/src/theory/type_enumerator.h b/src/theory/type_enumerator.h
index d1318aaa8..bcd7e695f 100644
--- a/src/theory/type_enumerator.h
+++ b/src/theory/type_enumerator.h
@@ -115,7 +115,7 @@ public:
// On Mac clang, there appears to be a code generation bug in an exception
// block here. For now, there doesn't appear a good workaround; just disable
// assertions on that setup.
-#if defined(CVC4_ASSERTIONS) && !(defined(__APPLE__) && defined(__clang__))
+#if defined(CVC4_ASSERTIONS) && !(defined(__clang__))
if(d_te->isFinished()) {
try {
**d_te;
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 9b429765e..25b12f75f 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -964,12 +964,9 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
std::vector<EqProof *> orderedChildren;
bool nullCongruenceFound = false;
for (unsigned i = 0; i < eqpc->d_children.size(); ++i) {
- if (eqpc->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE && eqpc->d_children[i]->d_node.isNull()) {
-
- // For now, assume there can only be one null congruence child
- Assert(!nullCongruenceFound);
+ if (eqpc->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE &&
+ eqpc->d_children[i]->d_node.isNull()) {
nullCongruenceFound = true;
-
Debug("pf::ee") << "Have congruence with empty d_node. Splitting..." << std::endl;
orderedChildren.insert(orderedChildren.begin(), eqpc->d_children[i]->d_children[0]);
orderedChildren.push_back(eqpc->d_children[i]->d_children[1]);
@@ -1192,6 +1189,9 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
getExplanation(childId, getEqualityNode(childId).getFind(), equalities, eqpcc);
if( eqpc ) {
eqpc->d_children.push_back( eqpcc );
+
+ Debug("pf::ee") << "MERGED_THROUGH_CONSTANTS. Dumping the child proof" << std::endl;
+ eqpc->debug_print("pf::ee", 1);
}
}
@@ -1605,6 +1605,7 @@ void EqualityEngine::propagate() {
}
void EqualityEngine::debugPrintGraph() const {
+ Debug("equality::graph") << std::endl << "Dumping graph" << std::endl;
for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++ nodeId) {
Debug("equality::graph") << d_nodes[nodeId] << " " << nodeId << "(" << getEqualityNode(nodeId).getFind() << "):";
@@ -1618,6 +1619,7 @@ void EqualityEngine::debugPrintGraph() const {
Debug("equality::graph") << std::endl;
}
+ Debug("equality::graph") << std::endl;
}
bool EqualityEngine::areEqual(TNode t1, TNode t2) const {
@@ -2209,9 +2211,15 @@ bool EqClassIterator::isFinished() const {
return d_current == null_id;
}
-void EqProof::debug_print( const char * c, unsigned tb ) const{
- for( unsigned i=0; i<tb; i++ ) { Debug( c ) << " "; }
- Debug( c ) << d_id << "(";
+void EqProof::debug_print(const char* c, unsigned tb, PrettyPrinter* prettyPrinter) const {
+ for(unsigned i=0; i<tb; i++) { Debug( c ) << " "; }
+
+ if (prettyPrinter)
+ Debug( c ) << prettyPrinter->printTag(d_id);
+ else
+ Debug( c ) << d_id;
+
+ Debug( c ) << "(";
if( !d_children.empty() || !d_node.isNull() ){
if( !d_node.isNull() ){
Debug( c ) << std::endl;
@@ -2221,7 +2229,7 @@ void EqProof::debug_print( const char * c, unsigned tb ) const{
for( unsigned i=0; i<d_children.size(); i++ ){
if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
Debug( c ) << std::endl;
- d_children[i]->debug_print( c, tb+1 );
+ d_children[i]->debug_print( c, tb+1, prettyPrinter );
}
}
Debug( c ) << ")" << std::endl;
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index f30f1e8a0..843e7ce7f 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -902,11 +902,17 @@ public:
class EqProof
{
public:
+ class PrettyPrinter {
+ public:
+ virtual ~PrettyPrinter() {}
+ virtual std::string printTag(unsigned tag) = 0;
+ };
+
EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY){}
unsigned d_id;
Node d_node;
std::vector< EqProof * > d_children;
- void debug_print( const char * c, unsigned tb = 0 ) const;
+ void debug_print(const char * c, unsigned tb = 0, PrettyPrinter* prettyPrinter = NULL) const;
};/* class EqProof */
} // Namespace eq
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 0c7bed773..ae935798e 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -26,6 +26,8 @@
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/quantifiers/term_database.h"
+#include "options/theory_options.h"
using namespace std;
@@ -431,100 +433,107 @@ void TheoryUF::addSharedTerm(TNode t) {
d_equalityEngine.addTriggerTerm(t, THEORY_UF);
}
-void TheoryUF::computeCareGraph() {
-
- if (d_sharedTerms.size() > 0) {
-
- vector< pair<TNode, TNode> > currentPairs;
-
- // Go through the function terms and see if there are any to split on
- unsigned functionTerms = d_functionsTerms.size();
- for (unsigned i = 0; i < functionTerms; ++ i) {
-
- TNode f1 = d_functionsTerms[i];
- Node op = f1.getOperator();
-
- for (unsigned j = i + 1; j < functionTerms; ++ j) {
-
- TNode f2 = d_functionsTerms[j];
-
- // If the operators are not the same, we can skip this pair
- if (f2.getOperator() != op) {
- continue;
- }
-
+//TODO: move quantifiers::TermArgTrie to src/theory/
+void TheoryUF::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth ){
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !d_equalityEngine.areEqual( f1, f2 ) ){
Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
-
- // If the terms are already known to be equal, we are also in good shape
- if (d_equalityEngine.areEqual(f1, f2)) {
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): equal, skipping" << std::endl;
- continue;
- }
-
- // We have two functions f(x1, ..., xn) and f(y1, ..., yn) no known to be equal
- // We split on the argument pairs that are are not known, unless there is some
- // argument pair that is already dis-equal.
- bool somePairIsDisequal = false;
- currentPairs.clear();
+ vector< pair<TNode, TNode> > currentPairs;
for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
-
TNode x = f1[k];
TNode y = f2[k];
-
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking arguments " << x << " and " << y << std::endl;
-
- if (d_equalityEngine.areDisequal(x, y, false)) {
- // Mark that there is a dis-equal pair and break
- somePairIsDisequal = true;
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): disequal, disregarding all" << std::endl;
- break;
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !d_equalityEngine.areDisequal( x, y, false ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_UF) && d_equalityEngine.isTriggerTerm(y, THEORY_UF) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
+ }
+ }
}
-
- if (d_equalityEngine.areEqual(x, y)) {
- // We don't need this one
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): equal" << std::endl;
- continue;
- }
-
- if (!d_equalityEngine.isTriggerTerm(x, THEORY_UF) || !d_equalityEngine.isTriggerTerm(y, THEORY_UF)) {
- // Not connected to shared terms, we don't care
- continue;
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
+ addCarePair(currentPairs[c].first, currentPairs[c].second);
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1 );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
-
- // Get representative trigger terms
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
-
- EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
- switch (eqStatusDomain) {
- case EQUALITY_FALSE_AND_PROPAGATED:
- case EQUALITY_FALSE:
- case EQUALITY_FALSE_IN_MODEL:
- somePairIsDisequal = true;
- continue;
- break;
- default:
- break;
- // nothing
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
-
- // Otherwise, we need to figure it out
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
- currentPairs.push_back(make_pair(x_shared, y_shared));
}
+ }
+ }
+ }
+}
- if (!somePairIsDisequal) {
- for (unsigned i = 0; i < currentPairs.size(); ++ i) {
- addCarePair(currentPairs[i].first, currentPairs[i].second);
- }
+void TheoryUF::computeCareGraph() {
+
+ if (d_sharedTerms.size() > 0) {
+ //use term indexing
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..." << std::endl;
+ std::map< Node, quantifiers::TermArgTrie > index;
+ std::map< Node, unsigned > arity;
+ unsigned functionTerms = d_functionsTerms.size();
+ for (unsigned i = 0; i < functionTerms; ++ i) {
+ TNode f1 = d_functionsTerms[i];
+ Node op = f1.getOperator();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_UF ) ){
+ has_trigger_arg = true;
}
}
+ if( has_trigger_arg ){
+ index[op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = index.begin(); itii != index.end(); ++itii ){
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index " << itii->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0 );
}
}
}/* TheoryUF::computeCareGraph() */
void TheoryUF::conflict(TNode a, TNode b) {
eq::EqProof* pf = d_proofsEnabled ? new eq::EqProof() : NULL;
+
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b),pf);
} else {
@@ -542,9 +551,9 @@ void TheoryUF::eqNotifyNewClass(TNode t) {
}
void TheoryUF::eqNotifyPreMerge(TNode t1, TNode t2) {
- if (getLogicInfo().isQuantified()) {
+ //if (getLogicInfo().isQuantified()) {
//getQuantifiersEngine()->getEfficientEMatcher()->merge( t1, t2 );
- }
+ //}
}
void TheoryUF::eqNotifyPostMerge(TNode t1, TNode t2) {
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index 42a804c09..3a83decec 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -32,6 +32,11 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace uf {
class UfTermDb;
@@ -204,6 +209,8 @@ public:
StrongSolverTheoryUF* getStrongSolver() {
return d_thss;
}
+private:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth );
};/* class TheoryUF */
}/* CVC4::theory::uf namespace */
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index ed28cc2fc..cda94e1c4 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -1670,6 +1670,12 @@ StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c,
}
}
+StrongSolverTheoryUF::~StrongSolverTheoryUF() {
+ for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ delete it->second;
+ }
+}
+
SortInference* StrongSolverTheoryUF::getSortInference() {
return d_th->getQuantifiersEngine()->getTheoryEngine()->getSortInference();
}
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 11f0664f3..4e4dbef83 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -414,7 +414,7 @@ private:
SubsortSymmetryBreaker* d_sym_break;
public:
StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
- ~StrongSolverTheoryUF() {}
+ ~StrongSolverTheoryUF();
/** get theory */
TheoryUF* getTheory() { return d_th; }
/** disequality propagator */
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index 165937c13..7e13668cd 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -87,6 +87,10 @@ Node Valuation::getModelValue(TNode var) {
return d_engine->getModelValue(var);
}
+TheoryModel* Valuation::getModel() {
+ return d_engine->getModel();
+}
+
Node Valuation::ensureLiteral(TNode n) {
return d_engine->ensureLiteral(n);
}
diff --git a/src/theory/valuation.h b/src/theory/valuation.h
index 4ecdecad0..54af14fdd 100644
--- a/src/theory/valuation.h
+++ b/src/theory/valuation.h
@@ -32,6 +32,7 @@ namespace theory {
class EntailmentCheckParameters;
class EntailmentCheckSideEffects;
+class TheoryModel;
/**
* The status of an equality in the current context.
@@ -106,6 +107,11 @@ public:
Node getModelValue(TNode var);
/**
+ * Returns pointer to model.
+ */
+ TheoryModel* getModel();
+
+ /**
* Ensure that the given node will have a designated SAT literal
* that is definitionally equal to it. The result of this function
* is a Node that can be queried via getSatValue().
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback