summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proofs/lfsc_checker/expr.cpp17
-rwxr-xr-xproofs/signatures/th_arrays.plf4
-rw-r--r--src/expr/expr_manager_template.cpp6
-rw-r--r--src/expr/expr_manager_template.h2
-rw-r--r--src/options/options_handler.cpp32
-rw-r--r--src/options/options_handler.h2
-rw-r--r--src/options/proof_options6
-rw-r--r--src/options/quantifiers_modes.h11
-rw-r--r--src/options/quantifiers_options23
-rw-r--r--src/options/strings_options12
-rw-r--r--src/printer/cvc/cvc_printer.cpp2
-rw-r--r--src/printer/smt2/smt2_printer.cpp17
-rw-r--r--src/proof/arith_proof.cpp6
-rw-r--r--src/proof/arith_proof.h2
-rw-r--r--src/proof/array_proof.cpp82
-rw-r--r--src/proof/array_proof.h2
-rw-r--r--src/proof/bitvector_proof.cpp80
-rw-r--r--src/proof/bitvector_proof.h8
-rw-r--r--src/proof/lemma_proof.cpp13
-rw-r--r--src/proof/lemma_proof.h7
-rw-r--r--src/proof/proof_manager.cpp306
-rw-r--r--src/proof/proof_manager.h29
-rw-r--r--src/proof/proof_utils.h3
-rw-r--r--src/proof/sat_proof.h5
-rw-r--r--src/proof/sat_proof_implementation.h29
-rw-r--r--src/proof/theory_proof.cpp94
-rw-r--r--src/proof/theory_proof.h22
-rw-r--r--src/proof/uf_proof.cpp6
-rw-r--r--src/proof/uf_proof.h2
-rw-r--r--src/prop/cnf_stream.cpp9
-rw-r--r--src/prop/cnf_stream.h8
-rw-r--r--src/prop/prop_engine.cpp3
-rw-r--r--src/prop/prop_engine.h3
-rw-r--r--src/prop/theory_proxy.cpp3
-rw-r--r--src/smt/dump.cpp5
-rw-r--r--src/smt/model.h5
-rw-r--r--src/smt/smt_engine.cpp27
-rw-r--r--src/theory/arrays/array_proof_reconstruction.cpp4
-rw-r--r--src/theory/bv/bv_subtheory_core.h1
-rw-r--r--src/theory/bv/theory_bv.cpp29
-rw-r--r--src/theory/bv/theory_bv.h4
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp8
-rw-r--r--src/theory/datatypes/theory_datatypes.h6
-rwxr-xr-xsrc/theory/quantifiers/bounded_integers.cpp63
-rwxr-xr-xsrc/theory/quantifiers/bounded_integers.h1
-rwxr-xr-xsrc/theory/quantifiers/ce_guided_single_inv.cpp40
-rwxr-xr-xsrc/theory/quantifiers/ce_guided_single_inv.h2
-rwxr-xr-xsrc/theory/quantifiers/ceg_instantiator.cpp13
-rwxr-xr-xsrc/theory/quantifiers/full_model_check.cpp2
-rwxr-xr-xsrc/theory/quantifiers/inst_match.cpp171
-rwxr-xr-xsrc/theory/quantifiers/inst_match.h53
-rwxr-xr-xsrc/theory/quantifiers/inst_match_generator.cpp26
-rwxr-xr-xsrc/theory/quantifiers/inst_match_generator.h5
-rwxr-xr-xsrc/theory/quantifiers/inst_strategy_e_matching.cpp29
-rwxr-xr-xsrc/theory/quantifiers/model_builder.cpp2
-rwxr-xr-xsrc/theory/quantifiers/model_engine.cpp2
-rwxr-xr-xsrc/theory/quantifiers/quantifiers_rewriter.cpp353
-rwxr-xr-xsrc/theory/quantifiers/quantifiers_rewriter.h15
-rwxr-xr-xsrc/theory/quantifiers/trigger.cpp10
-rwxr-xr-xsrc/theory/quantifiers/trigger.h1
-rw-r--r--src/theory/quantifiers_engine.cpp136
-rw-r--r--src/theory/quantifiers_engine.h8
-rw-r--r--src/theory/rep_set.cpp2
-rw-r--r--src/theory/sep/theory_sep.cpp215
-rw-r--r--src/theory/sep/theory_sep.h6
-rw-r--r--src/theory/sep/theory_sep_rewriter.cpp22
-rw-r--r--src/theory/strings/theory_strings.cpp2263
-rw-r--r--src/theory/strings/theory_strings.h164
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp348
-rw-r--r--src/theory/strings/theory_strings_preprocess.h22
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp112
-rw-r--r--src/theory/strings/theory_strings_rewriter.h6
-rw-r--r--src/theory/theory.cpp141
-rw-r--r--src/theory/theory.h67
-rw-r--r--src/theory/theory_engine.cpp193
-rw-r--r--src/theory/theory_engine.h13
-rw-r--r--src/theory/theory_model.cpp47
-rw-r--r--src/theory/theory_model.h13
-rw-r--r--src/theory/uf/equality_engine.cpp3
-rw-r--r--src/util/integer_cln_imp.cpp12
-rw-r--r--src/util/integer_cln_imp.h8
-rw-r--r--src/util/integer_gmp_imp.cpp8
-rw-r--r--src/util/integer_gmp_imp.h4
-rw-r--r--src/util/regexp.cpp11
-rw-r--r--src/util/regexp.h33
-rw-r--r--test/regress/regress0/quantifiers/Makefile.am5
-rw-r--r--test/regress/regress0/quantifiers/bi-artm-s.smt22
-rw-r--r--test/regress/regress0/quantifiers/bug749-rounding.smt211
-rw-r--r--test/regress/regress0/quantifiers/bug_743.smt2774
-rw-r--r--test/regress/regress0/quantifiers/quaternion_ds1_symm_0428.fof.smt249
-rw-r--r--test/regress/regress0/sep/Makefile.am5
-rw-r--r--test/regress/regress0/sep/dup-nemp.smt27
-rw-r--r--test/regress/regress0/sep/split-find-unsat.smt24
-rw-r--r--test/regress/regress0/sep/trees-1.smt241
-rw-r--r--test/regress/regress0/sep/wand-false.smt27
-rw-r--r--test/regress/regress0/sep/wand-nterm-simp2.smt23
-rwxr-xr-xtest/regress/regress0/sep/wand-simp-sat2.smt23
-rw-r--r--test/regress/regress0/sets/Makefile.am4
-rw-r--r--test/regress/regress0/sets/card3-ground.smt26
-rw-r--r--test/regress/regress0/sets/dt-simp-mem.smt29
-rw-r--r--test/regress/regress0/strings/Makefile.am14
-rw-r--r--test/regress/regress0/strings/cmu-5042-0707-2.smt215
-rw-r--r--test/regress/regress0/strings/cmu-dis-0707-3.smt224
-rw-r--r--test/regress/regress0/strings/cmu-disagree-0707-dd.smt222
-rw-r--r--test/regress/regress0/strings/cmu-inc-nlpp-071516.smt29
-rw-r--r--test/regress/regress0/strings/cmu-substr-rw.smt212
-rw-r--r--test/regress/regress0/strings/csp-prefix-exp-bug.smt210
-rw-r--r--test/regress/regress0/strings/gm-inc-071516-2.smt210
-rw-r--r--test/regress/regress0/strings/nf-ff-contains-abs.smt215
-rw-r--r--test/regress/regress0/strings/norn-dis-0707-3.smt226
110 files changed, 4697 insertions, 1980 deletions
diff --git a/proofs/lfsc_checker/expr.cpp b/proofs/lfsc_checker/expr.cpp
index 5cb774fbf..784a0ad2f 100644
--- a/proofs/lfsc_checker/expr.cpp
+++ b/proofs/lfsc_checker/expr.cpp
@@ -577,8 +577,21 @@ bool Expr::defeq(Expr *e) {
{
int counter = 0;
while( e1->kids[counter] ){
- if( !e2->kids[counter] || !e1->kids[counter]->defeq( e2->kids[counter] ) )
- return false;
+ if( e1->kids[counter]!=e2->kids[counter] ){
+ if( !e2->kids[counter] || !e1->kids[counter]->defeq( e2->kids[counter] ) )
+ return false;
+ //--- optimization : replace child with equivalent pointer if was defeq
+ if( e1->kids[counter]<e2->kids[counter] ){
+ e1->kids[counter]->dec();
+ e2->kids[counter]->inc();
+ e1->kids[counter] = e2->kids[counter];
+ }else{
+ e2->kids[counter]->dec();
+ e1->kids[counter]->inc();
+ e2->kids[counter] = e1->kids[counter];
+ }
+ }
+ //---
counter++;
}
return e2->kids[counter]==NULL;
diff --git a/proofs/signatures/th_arrays.plf b/proofs/signatures/th_arrays.plf
index b54a4ed5b..acfbd2f3b 100755
--- a/proofs/signatures/th_arrays.plf
+++ b/proofs/signatures/th_arrays.plf
@@ -32,6 +32,7 @@
(th_holds (= _
(apply _ _ (apply _ _ (read s1 s2) (apply _ _ (apply _ _ (apply _ _ (write s1 s2) t1) t2) t3)) t2) t3))))))))
+; read( a[i] = b, j ) == read( a, j ) if i != j
(declare row (! s1 sort
(! s2 sort
(! t2 (term s1)
@@ -42,6 +43,7 @@
(th_holds (= _ (apply _ _ (apply _ _ (read s1 s2) (apply _ _ (apply _ _ (apply _ _ (write s1 s2) t1) t2) t4)) t3)
(apply _ _ (apply _ _ (read s1 s2) t1) t3)))))))))))
+; i == j if read( a, j ) != read( a[i] = b, j )
(declare negativerow (! s1 sort
(! s2 sort
(! t2 (term s1)
@@ -60,4 +62,4 @@
(! u1 (! k (term s1)
(! u2 (th_holds (or (= _ t1 t2) (not (= _ (apply _ _ (apply _ _ (read s1 s2) t1) k) (apply _ _ (apply _ _ (read s1 s2) t2) k)))))
(holds cln)))
- (holds cln))))))) \ No newline at end of file
+ (holds cln)))))))
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 53e16751e..2dc3aebe5 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -75,7 +75,7 @@ ExprManager::ExprManager() :
for (unsigned i = 0; i < kind::LAST_KIND; ++ i) {
d_exprStatistics[i] = NULL;
}
- for (unsigned i = 0; i < LAST_TYPE; ++ i) {
+ for (unsigned i = 0; i <= LAST_TYPE; ++ i) {
d_exprStatisticsVars[i] = NULL;
}
#endif
@@ -84,7 +84,7 @@ ExprManager::ExprManager() :
ExprManager::ExprManager(const Options& options) :
d_nodeManager(new NodeManager(this, options)) {
#ifdef CVC4_STATISTICS_ON
- for (unsigned i = 0; i < LAST_TYPE; ++ i) {
+ for (unsigned i = 0; i <= LAST_TYPE; ++ i) {
d_exprStatisticsVars[i] = NULL;
}
for (unsigned i = 0; i < kind::LAST_KIND; ++ i) {
@@ -106,7 +106,7 @@ ExprManager::~ExprManager() throw() {
d_exprStatistics[i] = NULL;
}
}
- for (unsigned i = 0; i < LAST_TYPE; ++ i) {
+ for (unsigned i = 0; i <= LAST_TYPE; ++ i) {
if (d_exprStatisticsVars[i] != NULL) {
d_nodeManager->getStatisticsRegistry()->unregisterStat(d_exprStatisticsVars[i]);
delete d_exprStatisticsVars[i];
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index 31c911736..f30b720de 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -57,7 +57,7 @@ private:
NodeManager* d_nodeManager;
/** Counts of expressions and variables created of a given kind */
- IntStat* d_exprStatisticsVars[LAST_TYPE];
+ IntStat* d_exprStatisticsVars[LAST_TYPE + 1];
IntStat* d_exprStatistics[kind::LAST_KIND];
/**
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index 6a5f6cd39..8cd651da5 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -369,6 +369,19 @@ min-s-all \n\
+ Consider only minimal subterms that meet criteria for single triggers, all otherwise. \n\
\n\
";
+const std::string OptionsHandler::s_triggerActiveSelModeHelp = "\
+Trigger active selection modes currently supported by the --trigger-sel option:\n\
+\n\
+all \n\
++ Make all triggers active. \n\
+\n\
+min \n\
++ Activate triggers with minimal ground terms.\n\
+\n\
+max \n\
++ Activate triggers with maximal ground terms. \n\
+\n\
+";
const std::string OptionsHandler::s_prenexQuantModeHelp = "\
Prenex quantifiers modes currently supported by the --prenex-quant option:\n\
\n\
@@ -630,9 +643,7 @@ theory::quantifiers::UserPatMode OptionsHandler::stringToUserPatMode(std::string
}
theory::quantifiers::TriggerSelMode OptionsHandler::stringToTriggerSelMode(std::string option, std::string optarg) throw(OptionException) {
- if(optarg == "default") {
- return theory::quantifiers::TRIGGER_SEL_DEFAULT;
- } else if(optarg == "min") {
+ if(optarg == "default" || optarg == "min") {
return theory::quantifiers::TRIGGER_SEL_MIN;
} else if(optarg == "max") {
return theory::quantifiers::TRIGGER_SEL_MAX;
@@ -651,6 +662,21 @@ theory::quantifiers::TriggerSelMode OptionsHandler::stringToTriggerSelMode(std::
}
}
+theory::quantifiers::TriggerActiveSelMode OptionsHandler::stringToTriggerActiveSelMode(std::string option, std::string optarg) throw(OptionException) {
+ if(optarg == "default" || optarg == "all") {
+ return theory::quantifiers::TRIGGER_ACTIVE_SEL_ALL;
+ } else if(optarg == "min") {
+ return theory::quantifiers::TRIGGER_ACTIVE_SEL_MIN;
+ } else if(optarg == "max") {
+ return theory::quantifiers::TRIGGER_ACTIVE_SEL_MAX;
+ } else if(optarg == "help") {
+ puts(s_triggerActiveSelModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --trigger-active-sel: `") +
+ optarg + "'. Try --trigger-active-sel help.");
+ }
+}
theory::quantifiers::PrenexQuantMode OptionsHandler::stringToPrenexQuantMode(std::string option, std::string optarg) throw(OptionException) {
if(optarg == "default" ) {
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index 5db2887c0..e327b9c8e 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -94,6 +94,7 @@ public:
theory::quantifiers::QcfMode stringToQcfMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::UserPatMode stringToUserPatMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::TriggerSelMode stringToTriggerSelMode(std::string option, std::string optarg) throw(OptionException);
+ theory::quantifiers::TriggerActiveSelMode stringToTriggerActiveSelMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::PrenexQuantMode stringToPrenexQuantMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::CegqiFairMode stringToCegqiFairMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::TermDbMode stringToTermDbMode(std::string option, std::string optarg) throw(OptionException);
@@ -221,6 +222,7 @@ public:
static const std::string s_termDbModeHelp;
static const std::string s_theoryOfModeHelp;
static const std::string s_triggerSelModeHelp;
+ static const std::string s_triggerActiveSelModeHelp;
static const std::string s_ufssModeHelp;
static const std::string s_userPatModeHelp;
static const std::string s_errorSelectionRulesHelp;
diff --git a/src/options/proof_options b/src/options/proof_options
index a99d858bc..322ef5a9c 100644
--- a/src/options/proof_options
+++ b/src/options/proof_options
@@ -8,4 +8,10 @@ module PROOF "options/proof_options.h" Proof
option lfscLetification --lfsc-letification bool :default true
turns on global letification in LFSC proofs
+option aggressiveCoreMin --aggressive-core-min bool :default false
+ turns on aggressive unsat core minimization (experimental)
+
+option fewerPreprocessingHoles --fewer-preprocessing-holes bool :default false :read-write
+ try to eliminate preprocessing holes in proofs
+
endmodule
diff --git a/src/options/quantifiers_modes.h b/src/options/quantifiers_modes.h
index 65445be17..fe76f8798 100644
--- a/src/options/quantifiers_modes.h
+++ b/src/options/quantifiers_modes.h
@@ -101,8 +101,6 @@ enum UserPatMode {
};
enum TriggerSelMode {
- /** default for trigger selection */
- TRIGGER_SEL_DEFAULT,
/** only consider minimal terms for triggers */
TRIGGER_SEL_MIN,
/** only consider maximal terms for triggers */
@@ -115,6 +113,15 @@ enum TriggerSelMode {
TRIGGER_SEL_ALL,
};
+enum TriggerActiveSelMode {
+ /** always use all triggers */
+ TRIGGER_ACTIVE_SEL_ALL,
+ /** only use triggers with minimal # of ground terms */
+ TRIGGER_ACTIVE_SEL_MIN,
+ /** only use triggers with maximal # of ground terms */
+ TRIGGER_ACTIVE_SEL_MAX,
+};
+
enum CVC4_PUBLIC PrenexQuantMode {
/** default : prenex quantifiers without user patterns */
PRENEX_NO_USER_PAT,
diff --git a/src/options/quantifiers_options b/src/options/quantifiers_options
index 4d228bbad..7536d385d 100644
--- a/src/options/quantifiers_options
+++ b/src/options/quantifiers_options
@@ -26,6 +26,8 @@ option prenexQuant --prenex-quant=MODE CVC4::theory::quantifiers::PrenexQuantMod
# forall y. P( c, y )
option varElimQuant --var-elim-quant bool :default true
enable simple variable elimination for quantified formulas
+option varIneqElimQuant --var-ineq-elim-quant bool :default true
+ enable variable elimination based on infinite projection of unbound arithmetic variables
option dtVarExpandQuant --dt-var-exp-quant bool :default true
expand datatype variables bound to one constructor in quantifiers
#ite lift mode for quantified formulas
@@ -50,8 +52,6 @@ option aggressiveMiniscopeQuant --ag-miniscope-quant bool :default false
perform aggressive miniscoping for quantifiers
option elimTautQuant --elim-taut-quant bool :default true
eliminate tautological disjuncts of quantified formulas
-option purifyQuant --purify-quant bool :default false
- purify quantified formulas
option elimExtArithQuant --elim-ext-arith-quant bool :default true
eliminate extended arithmetic symbols in quantified formulas
option condRewriteQuant --cond-rewrite-quant bool :default true
@@ -89,8 +89,10 @@ option multiTriggerWhenSingle --multi-trigger-when-single bool :default false
select multi triggers when single triggers exist
option multiTriggerPriority --multi-trigger-priority bool :default false
only try multi triggers if single triggers give no instantiations
-option triggerSelMode --trigger-sel CVC4::theory::quantifiers::TriggerSelMode :default CVC4::theory::quantifiers::TRIGGER_SEL_DEFAULT :read-write :include "options/quantifiers_modes.h" :handler stringToTriggerSelMode
+option triggerSelMode --trigger-sel CVC4::theory::quantifiers::TriggerSelMode :default CVC4::theory::quantifiers::TRIGGER_SEL_MIN :read-write :include "options/quantifiers_modes.h" :handler stringToTriggerSelMode
selection mode for triggers
+option triggerActiveSelMode --trigger-active-sel CVC4::theory::quantifiers::TriggerActiveSelMode :default CVC4::theory::quantifiers::TRIGGER_ACTIVE_SEL_ALL :read-write :include "options/quantifiers_modes.h" :handler stringToTriggerActiveSelMode
+ selection mode to activate triggers
option userPatternsQuant --user-pat=MODE CVC4::theory::quantifiers::UserPatMode :default CVC4::theory::quantifiers::USER_PAT_MODE_TRUST :read-write :include "options/quantifiers_modes.h" :handler stringToUserPatMode
policy for handling user-provided patterns for quantifier instantiation
option incrementTriggers --increment-triggers bool :default true
@@ -160,8 +162,10 @@ option fmfFmcSimple --fmf-fmc-simple bool :default true
simple models in full model check for finite model finding
option fmfBoundInt fmf-bound-int --fmf-bound-int bool :default false :read-write
finite model finding on bounded integer quantification
-option fmfBoundIntLazy --fmf-bound-int-lazy bool :default false :read-write
- enforce bounds for bounded integer quantification lazily via use of proxy variables
+option fmfBound fmf-bound --fmf-bound bool :default false :read-write
+ finite model finding on bounded quantification
+option fmfBoundLazy --fmf-bound-lazy bool :default false :read-write
+ enforce bounds for bounded quantification lazily via use of proxy variables
### conflict-based instantiation options
@@ -239,6 +243,10 @@ option cegqiSingleInvPartial --cegqi-si-partial bool :default false
combined techniques for synthesis conjectures that are partially single invocation
option cegqiSingleInvReconstruct --cegqi-si-reconstruct bool :default true
reconstruct solutions for single invocation conjectures in original grammar
+option cegqiSolMinCore --cegqi-si-sol-min-core bool :default false
+ minimize solutions for single invocation conjectures based on unsat core
+option cegqiSolMinInst --cegqi-si-sol-min-inst bool :default true
+ minimize individual instantiations for single invocation conjectures based on unsat core
option cegqiSingleInvReconstructConst --cegqi-si-reconstruct-const bool :default true
include constants when reconstruct solutions for single invocation conjectures in original grammar
option cegqiSingleInvAbort --cegqi-si-abort bool :default false
@@ -325,4 +333,9 @@ option quantAntiSkolem --quant-anti-skolem bool :read-write :default false
option quantEqualityEngine --quant-ee bool :default false
maintain congrunce closure over universal equalities
+### proof options
+
+option trackInstLemmas --track-inst-lemmas bool :default true
+ when proof is enabled, track instantiation lemmas (for proofs, unsat cores, qe and synthesis minimization)
+
endmodule
diff --git a/src/options/strings_options b/src/options/strings_options
index 5c991a1bb..6dd7030a1 100644
--- a/src/options/strings_options
+++ b/src/options/strings_options
@@ -38,9 +38,7 @@ option stringIgnNegMembership strings-inm --strings-inm bool :default false
# the cardinality of the characters used by the theory of strings, default 128 (for standard ASCII) or 256 (for extended ASCII)
option stringLazyPreproc strings-lazy-pp --strings-lazy-pp bool :default true
- perform string preprocessing lazily upon assertion
-option stringLazyPreproc2 strings-lazy-pp2 --strings-lazy-pp2 bool :default true
- perform string preprocessing lazily upon failure to reduce
+ perform string preprocessing lazily
option stringLenGeqZ strings-len-geqz --strings-len-geqz bool :default false
strings length greater than zero lemmas
@@ -65,6 +63,14 @@ option stringRExplainLemmas strings-rexplain-lemmas --strings-rexplain-lemmas bo
regression explanations for string lemmas
option stringMinPrefixExplain strings-min-prefix-explain --strings-min-prefix-explain bool :default true
minimize explanations for prefix of normal forms in strings
+option stringGuessModel strings-guess-model --strings-guess-model bool :default false
+ use model guessing to avoid string extended function reductions
+option stringUfReduct strings-uf-reduct --strings-uf-reduct bool :default false
+ use uninterpreted functions when applying extended function reductions
+option stringBinaryCsp strings-binary-csp --strings-binary-csp bool :default false
+ use binary search when splitting strings
+option stringLenPropCsp strings-lprop-csp --strings-lprop-csp bool :default false
+ do length propagation based on constant splits
endmodule
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 8bd222ca7..84c8eecf5 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -726,7 +726,7 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
case kind::BITVECTOR_SIGN_EXTEND:
out << "SX(";
toStream(out, n[0], depth, types, false);
- out << ", " << n.getOperator().getConst<BitVectorSignExtend>() << ')';
+ out << ", " << BitVectorType(n.getType().toType()).getSize() << ')';
return;
break;
case kind::BITVECTOR_ROTATE_LEFT:
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 4006a9e08..c9dc814f2 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -1069,6 +1069,23 @@ void Smt2Printer::toStream(std::ostream& out, const UnsatCore& core, const std::
void Smt2Printer::toStream(std::ostream& out, const Model& m) const throw() {
+ //print the model comments
+ std::stringstream c;
+ m.getComments( c );
+ std::string ln;
+ while( std::getline( c, ln ) ){
+ out << "; " << ln << std::endl;
+ }
+ //print the heap model, if it exists
+ Expr h, neq;
+ if( m.getHeapModel( h, neq ) ){
+ // description of the heap+what nil is equal to fully describes model
+ out << "(heap" << endl;
+ out << h << endl;
+ out << neq << endl;
+ out << ")" << std::endl;
+ }
+ //print the model
out << "(model" << endl;
this->Printer::toStream(out, m);
out << ")" << endl;
diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp
index 4864cbf46..4e813d646 100644
--- a/src/proof/arith_proof.cpp
+++ b/src/proof/arith_proof.cpp
@@ -804,9 +804,9 @@ void LFSCArithProof::printOwnedSort(Type type, std::ostream& os) {
if (type.isInteger() && d_realMode) {
// If in "real mode", don't use type Int for, e.g., equality.
- os << "Real ";
+ os << "Real";
} else {
- os << type << " ";
+ os << type;
}
}
@@ -830,7 +830,7 @@ void LFSCArithProof::printDeferredDeclarations(std::ostream& os, std::ostream& p
// Nothing to do here at this point.
}
-void LFSCArithProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCArithProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
// Nothing to do here at this point.
}
diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h
index d980654c4..126e89ed2 100644
--- a/src/proof/arith_proof.h
+++ b/src/proof/arith_proof.h
@@ -74,7 +74,7 @@ public:
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren);
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
};
diff --git a/src/proof/array_proof.cpp b/src/proof/array_proof.cpp
index 484bc70c8..32a7c247d 100644
--- a/src/proof/array_proof.cpp
+++ b/src/proof/array_proof.cpp
@@ -305,7 +305,8 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
out << " ";
ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out,
n1[0].toExpr(),
- n1[1].toExpr());
+ n1[1].toExpr(),
+ map);
}
out << "))" << std::endl;
@@ -585,7 +586,8 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out,
n[0].toExpr(),
- n[1].toExpr());
+ n[1].toExpr(),
+ map);
return pf->d_node;
}
@@ -637,6 +639,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
// we look at the node after the equality sequence. If it needs a, we go for a=a; and if it needs
// b, we go for b=b. If there is no following node, we look at the goal of the transitivity proof,
// and use it to determine which option we need.
+
if(n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) {
if (((n1[0] == n2[0]) && (n1[1] == n2[1])) || ((n1[0] == n2[1]) && (n1[1] == n2[0]))) {
// We are in a sequence of identical equalities
@@ -900,7 +903,6 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
// inner index != outer index
// t3 is the outer index
-
Assert(pf->d_children.size() == 1);
std::stringstream ss;
Node subproof = toStreamRecLFSC(ss, tp, pf->d_children[0], tb + 1, map);
@@ -915,22 +917,76 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
tp->printTerm(t4.toExpr(), out, map);
out << " ";
+
Debug("pf::array") << "pf->d_children[0]->d_node is: " << pf->d_children[0]->d_node
<< ". t3 is: " << t3 << std::endl
<< "subproof is: " << subproof << std::endl;
Debug("pf::array") << "Subproof is: " << ss.str() << std::endl;
- if (subproof[0][1] == t3) {
- Debug("pf::array") << "Dont need symmetry!" << std::endl;
- out << ss.str();
+ // The subproof needs to show that t2 != t3. This can either be a direct disequality,
+ // or, if (wlog) t2 is constant, it can show that t3 is equal to another constant.
+ if (subproof.getKind() == kind::NOT) {
+ // The subproof is for t2 != t3 (or t3 != t2)
+ if (subproof[0][1] == t3) {
+ Debug("pf::array") << "Dont need symmetry!" << std::endl;
+ out << ss.str();
+ } else {
+ Debug("pf::array") << "Need symmetry!" << std::endl;
+ out << "(negsymm _ _ _ " << ss.str() << ")";
+ }
} else {
- Debug("pf::array") << "Need symmetry!" << std::endl;
- out << "(negsymm _ _ _ " << ss.str() << ")";
+ // Either t2 or t3 is a constant.
+ Assert(subproof.getKind() == kind::EQUAL);
+ Assert(subproof[0].isConst() || subproof[1].isConst());
+ Assert(t2.isConst() || t3.isConst());
+ Assert(!(t2.isConst() && t3.isConst()));
+
+ bool t2IsConst = t2.isConst();
+ if (subproof[0].isConst()) {
+ if (t2IsConst) {
+ // (t3 == subproof[1]) == subproof[0] != t2
+ // goal is t2 != t3
+ // subproof already shows constant = t3
+ Assert(t3 == subproof[1]);
+ out << "(negtrans _ _ _ _ ";
+ tp->printConstantDisequalityProof(out, t2.toExpr(), subproof[0].toExpr(), map);
+ out << " ";
+ out << ss.str();
+ out << ")";
+ } else {
+ Assert(t2 == subproof[1]);
+ out << "(negsymm _ _ _ ";
+ out << "(negtrans _ _ _ _ ";
+ tp->printConstantDisequalityProof(out, t3.toExpr(), subproof[0].toExpr(), map);
+ out << " ";
+ out << ss.str();
+ out << "))";
+ }
+ } else {
+ if (t2IsConst) {
+ // (t3 == subproof[0]) == subproof[1] != t2
+ // goal is t2 != t3
+ // subproof already shows constant = t3
+ Assert(t3 == subproof[0]);
+ out << "(negtrans _ _ _ _ ";
+ tp->printConstantDisequalityProof(out, t2.toExpr(), subproof[1].toExpr(), map);
+ out << " ";
+ out << "(symm _ _ _ " << ss.str() << ")";
+ out << ")";
+ } else {
+ Assert(t2 == subproof[0]);
+ out << "(negsymm _ _ _ ";
+ out << "(negtrans _ _ _ _ ";
+ tp->printConstantDisequalityProof(out, t3.toExpr(), subproof[1].toExpr(), map);
+ out << " ";
+ out << "(symm _ _ _ " << ss.str() << ")";
+ out << "))";
+ }
+ }
}
out << ")";
-
return ret;
} else {
Debug("pf::array") << "In the case of NEGATIVE ROW" << std::endl;
@@ -1215,7 +1271,7 @@ void LFSCArrayProof::printOwnedSort(Type type, std::ostream& os) {
printSort(array_type.getConstituentType(), os);
os << ")";
} else {
- os << type <<" ";
+ os << type;
}
}
@@ -1268,6 +1324,7 @@ void LFSCArrayProof::printTermDeclarations(std::ostream& os, std::ostream& paren
printSort(array_type.getConstituentType(), os);
os << "))\n";
+ paren << ")";
} else {
Assert(term.isVariable());
if (ProofManager::getSkolemizationManager()->isSkolem(*it)) {
@@ -1277,10 +1334,9 @@ void LFSCArrayProof::printTermDeclarations(std::ostream& os, std::ostream& paren
os << "(% " << ProofManager::sanitize(term) << " ";
os << "(term ";
os << term.getType() << ")\n";
+ paren << ")";
}
}
-
- paren << ")";
}
Debug("pf::array") << "Declaring terms done!" << std::endl;
@@ -1326,7 +1382,7 @@ void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& p
}
}
-void LFSCArrayProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCArrayProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
// Nothing to do here at this point.
}
diff --git a/src/proof/array_proof.h b/src/proof/array_proof.h
index 69e62dbf3..61f168a16 100644
--- a/src/proof/array_proof.h
+++ b/src/proof/array_proof.h
@@ -124,7 +124,7 @@ public:
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren);
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
};
diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp
index f19e45920..8c6af5c34 100644
--- a/src/proof/bitvector_proof.cpp
+++ b/src/proof/bitvector_proof.cpp
@@ -16,6 +16,7 @@
**/
#include "options/bv_options.h"
+#include "options/proof_options.h"
#include "proof/array_proof.h"
#include "proof/bitvector_proof.h"
#include "proof/clause_id.h"
@@ -41,6 +42,7 @@ BitVectorProof::BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proo
, d_resolutionProof(NULL)
, d_cnfProof(NULL)
, d_bitblaster(NULL)
+ , d_useConstantLetification(false)
{}
void BitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver) {
@@ -117,6 +119,14 @@ void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) {
void BitVectorProof::registerTerm(Expr term) {
Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )" << std::endl;
+ if (options::lfscLetification() && term.isConst()) {
+ if (d_constantLetMap.find(term) == d_constantLetMap.end()) {
+ std::ostringstream name;
+ name << "letBvc" << d_constantLetMap.size();
+ d_constantLetMap[term] = name.str();
+ }
+ }
+
d_usedBB.insert(term);
if (Theory::isLeafOf(term, theory::THEORY_BV) &&
@@ -384,16 +394,21 @@ void LFSCBitVectorProof::printBitOf(Expr term, std::ostream& os, const ProofLetM
void LFSCBitVectorProof::printConstant(Expr term, std::ostream& os) {
Assert (term.isConst());
- os <<"(a_bv " << utils::getSize(term)<<" ";
- std::ostringstream paren;
- int size = utils::getSize(term);
- for (int i = size - 1; i >= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
- paren << ")";
+ os << "(a_bv " << utils::getSize(term) << " ";
+
+ if (d_useConstantLetification) {
+ os << d_constantLetMap[term] << ")";
+ } else {
+ std::ostringstream paren;
+ int size = utils::getSize(term);
+ for (int i = size - 1; i >= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
+ paren << ")";
+ }
+ os << " bvn)";
+ os << paren.str();
}
- os << " bvn)";
- os << paren.str();
}
void LFSCBitVectorProof::printOperatorNary(Expr term, std::ostream& os, const ProofLetMap& map) {
@@ -464,7 +479,7 @@ void LFSCBitVectorProof::printOwnedSort(Type type, std::ostream& os) {
Debug("pf::bv") << std::endl << "(pf::bv) LFSCBitVectorProof::printOwnedSort( " << type << " )" << std::endl;
Assert (type.isBitVector());
unsigned width = utils::getSize(type);
- os << "(BitVec "<<width<<")";
+ os << "(BitVec " << width << ")";
}
void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
@@ -653,10 +668,29 @@ void LFSCBitVectorProof::printTermDeclarations(std::ostream& os, std::ostream& p
}
void LFSCBitVectorProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
+ if (options::lfscLetification()) {
+ os << std::endl << ";; BV const letification\n" << std::endl;
+ std::map<Expr,std::string>::const_iterator it;
+ for (it = d_constantLetMap.begin(); it != d_constantLetMap.end(); ++it) {
+ os << "\n(@ " << it->second << " ";
+ std::ostringstream localParen;
+ int size = utils::getSize(it->first);
+ for (int i = size - 1; i >= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(it->first, i) ? "b1" : "b0") << " ";
+ localParen << ")";
+ }
+ os << "bvn";
+ os << localParen.str();
+ paren << ")";
+ }
+ os << std::endl;
+
+ d_useConstantLetification = true;
+ }
}
-void LFSCBitVectorProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCBitVectorProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
// Print "trust" statements to bind complex bv variables to their associated terms
ExprToString::const_iterator it = d_assignedAliases.begin();
@@ -673,8 +707,7 @@ void LFSCBitVectorProof::printAliasingDeclarations(std::ostream& os, std::ostrea
os << "(trust_f ";
os << "(= (BitVec " << utils::getSize(it->first) << ") ";
os << "(a_var_bv " << utils::getSize(it->first) << " " << it->second << ") ";
- ProofLetMap emptyMap;
- d_proofEngine->printBoundTerm(it->first, os, emptyMap);
+ d_proofEngine->printBoundTerm(it->first, os, globalLetMap);
os << ")) ";
os << "(\\ "<< d_aliasToBindDeclaration[it->second] << "\n";
paren << "))";
@@ -701,15 +734,20 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
os << "(bv_bbl_const "<< utils::getSize(term) <<" _ ";
std::ostringstream paren;
int size = utils::getSize(term);
- for (int i = size - 1; i>= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
- paren << ")";
+ if (d_useConstantLetification) {
+ os << d_constantLetMap[term] << ")";
+ } else {
+ for (int i = size - 1; i>= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
+ paren << ")";
+ }
+ os << " bvn)";
+ os << paren.str();
}
- os << " bvn)";
- os << paren.str();
return;
}
+
case kind::BITVECTOR_AND :
case kind::BITVECTOR_OR :
case kind::BITVECTOR_XOR :
@@ -1016,7 +1054,7 @@ bool LFSCBitVectorProof::hasAlias(Expr expr) {
return d_assignedAliases.find(expr) != d_assignedAliases.end();
}
-void LFSCBitVectorProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+void LFSCBitVectorProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
Assert (c1.isConst());
Assert (c2.isConst());
Assert (utils::getSize(c1) == utils::getSize(c2));
diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h
index a52292ec9..6b952e35c 100644
--- a/src/proof/bitvector_proof.h
+++ b/src/proof/bitvector_proof.h
@@ -81,6 +81,10 @@ protected:
bool d_isAssumptionConflict;
theory::bv::TBitblaster<Node>* d_bitblaster;
std::string getBBTermName(Expr expr);
+
+ std::map<Expr,std::string> d_constantLetMap;
+ bool d_useConstantLetification;
+
public:
BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine);
@@ -148,12 +152,12 @@ public:
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren);
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
virtual void printBitblasting(std::ostream& os, std::ostream& paren);
virtual void printResolutionProof(std::ostream& os, std::ostream& paren, ProofLetMap& letMap);
void calculateAtomsInBitblastingProof();
const std::set<Node>* getAtomsInBitblastingProof();
- void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2);
+ void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap);
void printRewriteProof(std::ostream& os, const Node &n1, const Node &n2);
};
diff --git a/src/proof/lemma_proof.cpp b/src/proof/lemma_proof.cpp
index a12a516cf..3a962f987 100644
--- a/src/proof/lemma_proof.cpp
+++ b/src/proof/lemma_proof.cpp
@@ -65,6 +65,10 @@ void LemmaProofRecipe::dump(const char *tag) const {
Debug(tag) << std::endl << "[Simple lemma]" << std::endl << std::endl;
}
+ if (d_originalLemma != Node()) {
+ Debug(tag) << std::endl << "Original lemma: " << d_originalLemma << std::endl << std::endl;
+ }
+
unsigned count = 1;
Debug(tag) << "Base assertions:" << std::endl;
for (std::set<Node>::iterator baseIt = d_baseAssertions.begin();
@@ -190,4 +194,13 @@ unsigned LemmaProofRecipe::getNumSteps() const {
return d_proofSteps.size();
}
+void LemmaProofRecipe::setOriginalLemma(Node lemma) {
+ d_originalLemma = lemma;
+}
+
+Node LemmaProofRecipe::getOriginalLemma() const {
+ return d_originalLemma;
+}
+
+
} /* namespace CVC4 */
diff --git a/src/proof/lemma_proof.h b/src/proof/lemma_proof.h
index e96ff5337..9c838cee7 100644
--- a/src/proof/lemma_proof.h
+++ b/src/proof/lemma_proof.h
@@ -51,6 +51,10 @@ public:
bool wasRewritten(Node assertion) const;
Node getExplanation(Node assertion) const;
+ //* Original lemma */
+ void setOriginalLemma(Node lemma);
+ Node getOriginalLemma() const;
+
//* Proof Steps */
void addStep(ProofStep& proofStep);
const ProofStep* getStep(unsigned index) const;
@@ -72,6 +76,9 @@ private:
//* A map from assertions to their rewritten explanations (toAssert --> toExplain) */
std::map<Node, Node> d_assertionToExplanation;
+
+ //* The original lemma, as asserted by the owner theory solver */
+ Node d_originalLemma;
};
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index d155630e5..1c9bb0ff0 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -41,6 +41,15 @@
namespace CVC4 {
+std::string nodeSetToString(const std::set<Node>& nodes) {
+ std::ostringstream os;
+ std::set<Node>::const_iterator it;
+ for (it = nodes.begin(); it != nodes.end(); ++it) {
+ os << *it << " ";
+ }
+ return os.str();
+}
+
std::string append(const std::string& str, uint64_t num) {
std::ostringstream os;
os << str << num;
@@ -202,6 +211,10 @@ std::string ProofManager::getLitName(prop::SatLiteral lit,
std::string ProofManager::getPreprocessedAssertionName(Node node,
const std::string& prefix) {
+ if (currentPM()->d_assertionFilters.find(node) != currentPM()->d_assertionFilters.end()) {
+ return currentPM()->d_assertionFilters[node];
+ }
+
node = node.getKind() == kind::BITVECTOR_EAGER_ATOM ? node[0] : node;
return append(prefix+".PA", node.getId());
}
@@ -209,6 +222,9 @@ std::string ProofManager::getAssertionName(Node node,
const std::string& prefix) {
return append(prefix+".A", node.getId());
}
+std::string ProofManager::getInputFormulaName(const Expr& expr) {
+ return currentPM()->d_inputFormulaToName[expr];
+}
std::string ProofManager::getAtomName(TNode atom,
const std::string& prefix) {
@@ -243,7 +259,7 @@ std::string ProofManager::sanitize(TNode node) {
return name;
}
-void ProofManager::traceDeps(TNode n) {
+void ProofManager::traceDeps(TNode n, ExprSet* coreAssertions) {
Debug("cores") << "trace deps " << n << std::endl;
if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
(n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
@@ -252,7 +268,7 @@ void ProofManager::traceDeps(TNode n) {
if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
// originating formula was in core set
Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
- d_outputCoreFormulas.insert(n.toExpr());
+ coreAssertions->insert(n.toExpr());
} else {
Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
if(d_deps.find(n) == d_deps.end()) {
@@ -263,7 +279,7 @@ void ProofManager::traceDeps(TNode n) {
for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
if( !(*i).isNull() ){
- traceDeps(*i);
+ traceDeps(*i, coreAssertions);
}
}
}
@@ -271,7 +287,7 @@ void ProofManager::traceDeps(TNode n) {
void ProofManager::traceUnsatCore() {
Assert (options::unsatCores());
- d_satProof->constructProof();
+ constructSatProof();
IdToSatClause used_lemmas;
IdToSatClause used_inputs;
d_satProof->collectClausesUsed(used_inputs,
@@ -287,14 +303,157 @@ void ProofManager::traceUnsatCore() {
rule == RULE_GIVEN) {
// trace dependences back to actual assertions
// (this adds them to the unsat core)
- traceDeps(node);
+ traceDeps(node, &d_outputCoreFormulas);
+ }
+ }
+}
+
+bool ProofManager::unsatCoreAvailable() const {
+ return d_satProof->derivedEmptyClause();
+}
+
+void ProofManager::constructSatProof() {
+ if (!d_satProof->proofConstructed()) {
+ d_satProof->constructProof();
+ }
+}
+
+void ProofManager::getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas) {
+ Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
+ Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
+
+ constructSatProof();
+
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_satProof->collectClausesUsed(used_inputs, used_lemmas);
+
+ IdToSatClause::const_iterator it;
+ std::set<Node> seen;
+
+ Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl;
+ for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
+ std::set<Node> lemma = satClauseToNodeSet(it->second);
+ Debug("pf::lemmasUnsatCore") << nodeSetToString(lemma);
+
+ // TODO: we should be able to drop the "haveProofRecipe" check.
+ // however, there are some rewrite issues with the arith solver, resulting
+ // in non-registered recipes. For now we assume no one is requesting arith lemmas.
+ LemmaProofRecipe recipe;
+ if (!getCnfProof()->haveProofRecipe(lemma)) {
+ Debug("pf::lemmasUnsatCore") << "\t[no recipe]" << std::endl;
+ continue;
+ }
+
+ recipe = getCnfProof()->getProofRecipe(lemma);
+ Debug("pf::lemmasUnsatCore") << "\t[owner = " << recipe.getTheory()
+ << ", original = " << recipe.getOriginalLemma() << "]" << std::endl;
+ if (recipe.simpleLemma() && recipe.getTheory() == theory && seen.find(recipe.getOriginalLemma()) == seen.end()) {
+ lemmas.push_back(recipe.getOriginalLemma());
+ seen.insert(recipe.getOriginalLemma());
+ }
+ }
+}
+
+std::set<Node> ProofManager::satClauseToNodeSet(prop::SatClause* clause) {
+ std::set<Node> result;
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Node node = getCnfProof()->getAtom(lit.getSatVariable());
+ Expr atom = node.toExpr();
+ if (atom != utils::mkTrue())
+ result.insert(lit.isNegated() ? node.notNode() : node);
+ }
+
+ return result;
+}
+
+Node ProofManager::getWeakestImplicantInUnsatCore(Node lemma) {
+ Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
+ Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
+
+ // If we're doing aggressive minimization, work on all lemmas, not just conjunctions.
+ if (!options::aggressiveCoreMin() && (lemma.getKind() != kind::AND))
+ return lemma;
+
+ constructSatProof();
+
+ NodeBuilder<> builder(kind::AND);
+
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_satProof->collectClausesUsed(used_inputs, used_lemmas);
+
+ IdToSatClause::const_iterator it;
+ std::set<Node>::iterator lemmaIt;
+
+ if (!options::aggressiveCoreMin()) {
+ for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
+ std::set<Node> currentLemma = satClauseToNodeSet(it->second);
+
+ // TODO: we should be able to drop the "haveProofRecipe" check.
+ // however, there are some rewrite issues with the arith solver, resulting
+ // in non-registered recipes. For now we assume no one is requesting arith lemmas.
+ LemmaProofRecipe recipe;
+ if (!getCnfProof()->haveProofRecipe(currentLemma))
+ continue;
+
+ recipe = getCnfProof()->getProofRecipe(currentLemma);
+ if (recipe.getOriginalLemma() == lemma) {
+ for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
+ builder << *lemmaIt;
+
+ // Check that each conjunct appears in the original lemma.
+ bool found = false;
+ for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
+ if (lemma[i] == *lemmaIt)
+ found = true;
+ }
+
+ if (!found)
+ return lemma;
+ }
+ }
+ }
+ } else {
+ // Aggressive mode
+ for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
+ std::set<Node> currentLemma = satClauseToNodeSet(it->second);
+
+ // TODO: we should be able to drop the "haveProofRecipe" check.
+ // however, there are some rewrite issues with the arith solver, resulting
+ // in non-registered recipes. For now we assume no one is requesting arith lemmas.
+ LemmaProofRecipe recipe;
+ if (!getCnfProof()->haveProofRecipe(currentLemma))
+ continue;
+
+ recipe = getCnfProof()->getProofRecipe(currentLemma);
+ if (recipe.getOriginalLemma() == lemma) {
+ NodeBuilder<> disjunction(kind::OR);
+ for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
+ disjunction << *lemmaIt;
+ }
+
+ Node conjunct = (disjunction.getNumChildren() == 1) ? disjunction[0] : disjunction;
+ builder << conjunct;
+ }
}
}
+
+ AlwaysAssert(builder.getNumChildren() != 0);
+
+ if (builder.getNumChildren() == 1)
+ return builder[0];
+
+ return builder;
}
void ProofManager::addAssertion(Expr formula) {
Debug("proof:pm") << "assert: " << formula << std::endl;
d_inputFormulas.insert(formula);
+ std::ostringstream name;
+ name << "A" << d_inputFormulaToName.size();
+ d_inputFormulaToName[formula] = name.str();
}
void ProofManager::addCoreAssertion(Expr formula) {
@@ -319,6 +478,10 @@ void ProofManager::addUnsatCore(Expr formula) {
d_outputCoreFormulas.insert(formula);
}
+void ProofManager::addAssertionFilter(const Node& node, const std::string& rewritten) {
+ d_assertionFilters[node] = rewritten;
+}
+
void ProofManager::setLogic(const LogicInfo& logic) {
d_logic = logic;
}
@@ -343,6 +506,7 @@ void LFSCProof::toStream(std::ostream& out) {
Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER);
+ Assert(!d_satProof->proofConstructed());
d_satProof->constructProof();
// collecting leaf clauses in resolution proof
@@ -446,6 +610,7 @@ void LFSCProof::toStream(std::ostream& out) {
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
out << "(check\n";
+ paren << ")";
out << " ;; Declarations\n";
// declare the theory atoms
@@ -468,23 +633,22 @@ void LFSCProof::toStream(std::ostream& out) {
Debug("pf::pm") << std::endl << "LFSCProof::toStream: print assertions DONE" << std::endl;
out << "(: (holds cln)\n\n";
+ paren << ")";
// Have the theory proofs print deferred declarations, e.g. for skolem variables.
out << " ;; Printing deferred declarations \n\n";
d_theoryProof->printDeferredDeclarations(out, paren);
+ out << "\n ;; Printing the global let map";
d_theoryProof->finalizeBvConflicts(used_lemmas, out);
ProofManager::getBitVectorProof()->calculateAtomsInBitblastingProof();
-
- out << "\n ;; Printing the global let map \n";
-
ProofLetMap globalLetMap;
if (options::lfscLetification()) {
ProofManager::currentPM()->printGlobalLetMap(atoms, globalLetMap, out, paren);
}
out << " ;; Printing aliasing declarations \n\n";
- d_theoryProof->printAliasingDeclarations(out, paren);
+ d_theoryProof->printAliasingDeclarations(out, paren, globalLetMap);
out << " ;; Rewrites for Lemmas \n";
d_theoryProof->printLemmaRewrites(rewrites, out, paren);
@@ -511,20 +675,15 @@ void LFSCProof::toStream(std::ostream& out) {
Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl;
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) {
- // print actual resolution proof
- // d_satProof->printResolutions(out, paren);
ProofManager::getBitVectorProof()->getSatProof()->printResolutionEmptyClause(out, paren);
- paren <<")))\n;;";
- out << paren.str();
- out << "\n";
} else {
// print actual resolution proof
d_satProof->printResolutions(out, paren);
d_satProof->printResolutionEmptyClause(out, paren);
- paren <<")))\n;;";
- out << paren.str();
- out << "\n";
}
+
+ out << paren.str();
+ out << "\n;;\n";
}
void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
@@ -537,21 +696,118 @@ void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl;
- for (; it != end; ++it) {
- os << "(th_let_pf _ ";
+ if (options::fewerPreprocessingHoles()) {
+ // Check for assertions that did not get rewritten, and update the printing filter.
+ checkUnrewrittenAssertion(assertions);
+
+ // For the remaining assertions, bind them to input assertions.
+ for (; it != end; ++it) {
+ // Rewrite preprocessing step if it cannot be eliminated
+ if (!ProofManager::currentPM()->have_input_assertion((*it).toExpr())) {
+ os << "(th_let_pf _ (trust_f (iff ";
+
+ Expr inputAssertion;
+
+ if (((*it).isConst() && *it == NodeManager::currentNM()->mkConst<bool>(true)) ||
+ ((*it).getKind() == kind::NOT && (*it)[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
+ inputAssertion = NodeManager::currentNM()->mkConst<bool>(true).toExpr();
+ } else {
+ // Figure out which input assertion led to this assertion
+ ExprSet inputAssertions;
+ ProofManager::currentPM()->traceDeps(*it, &inputAssertions);
+
+ Debug("pf::pm") << "Original assertions for " << *it << " are: " << std::endl;
+
+ ProofManager::assertions_iterator assertionIt;
+ for (assertionIt = inputAssertions.begin(); assertionIt != inputAssertions.end(); ++assertionIt) {
+ Debug("pf::pm") << "\t" << *assertionIt << std::endl;
+ }
+
+ if (inputAssertions.size() == 0) {
+ Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
+ // For now just use the first assertion...
+ inputAssertion = *(ProofManager::currentPM()->begin_assertions());
+ } else {
+ if (inputAssertions.size() != 1) {
+ Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Attention: more than one original assertion was found. Picking just one." << std::endl;
+ }
+ inputAssertion = *inputAssertions.begin();
+ }
+ }
+
+ if (!ProofManager::currentPM()->have_input_assertion(inputAssertion)) {
+ // The thing returned by traceDeps does not appear in the input assertions...
+ Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
+ // For now just use the first assertion...
+ inputAssertion = *(ProofManager::currentPM()->begin_assertions());
+ }
+
+ Debug("pf::pm") << "Original assertion for " << *it
+ << " is: "
+ << inputAssertion
+ << ", AKA "
+ << ProofManager::currentPM()->getInputFormulaName(inputAssertion)
+ << std::endl;
+
+ ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm(inputAssertion, os, globalLetMap);
+ os << " ";
+ ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it).toExpr(), os, globalLetMap);
+
+ os << "))";
+ os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
+ paren << "))";
+
+ std::ostringstream rewritten;
+
+ rewritten << "(or_elim_1 _ _ ";
+ rewritten << "(not_not_intro _ ";
+ rewritten << ProofManager::currentPM()->getInputFormulaName(inputAssertion);
+ rewritten << ") (iff_elim_1 _ _ ";
+ rewritten << ProofManager::getPreprocessedAssertionName(*it, "");
+ rewritten << "))";
+
+ ProofManager::currentPM()->addAssertionFilter(*it, rewritten.str());
+ }
+ }
+ } else {
+ for (; it != end; ++it) {
+ os << "(th_let_pf _ ";
- //TODO
- os << "(trust_f ";
- ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it).toExpr(), os, globalLetMap);
- os << ") ";
+ //TODO
+ os << "(trust_f ";
+ ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it).toExpr(), os, globalLetMap);
+ os << ") ";
- os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
- paren << "))";
+ os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
+ paren << "))";
+ }
}
os << "\n";
}
+void LFSCProof::checkUnrewrittenAssertion(const NodeSet& rewrites) {
+ Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion starting" << std::endl;
+
+ NodeSet::const_iterator rewrite;
+ for (rewrite = rewrites.begin(); rewrite != rewrites.end(); ++rewrite) {
+ Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: handling " << *rewrite << std::endl;
+ if (ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr())) {
+ Assert(ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr()));
+ Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion was NOT rewritten!" << std::endl
+ << "\tAdding filter: "
+ << ProofManager::getPreprocessedAssertionName(*rewrite, "")
+ << " --> "
+ << ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr())
+ << std::endl;
+ ProofManager::currentPM()->addAssertionFilter(*rewrite,
+ ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr()));
+ } else {
+ Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion WAS rewritten! " << *rewrite << std::endl;
+ }
+ }
+}
+
//---from Morgan---
bool ProofManager::hasOp(TNode n) const {
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index 14793f380..fa7224d72 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -21,13 +21,11 @@
#include <iosfwd>
#include <map>
-#include "proof/proof.h"
-#include "proof/proof_utils.h"
-#include "proof/skolemization_manager.h"
-#include "util/proof.h"
#include "expr/node.h"
#include "proof/clause_id.h"
#include "proof/proof.h"
+#include "proof/proof_utils.h"
+#include "proof/skolemization_manager.h"
#include "theory/logic_info.h"
#include "theory/substitutions.h"
#include "util/proof.h"
@@ -147,6 +145,7 @@ class ProofManager {
// information that will need to be shared across proofs
ExprSet d_inputFormulas;
+ std::map<Expr, std::string> d_inputFormulaToName;
ExprSet d_inputCoreFormulas;
ExprSet d_outputCoreFormulas;
@@ -158,12 +157,11 @@ class ProofManager {
ProofFormat d_format; // used for now only in debug builds
NodeToNodes d_deps;
- // trace dependences back to unsat core
- void traceDeps(TNode n);
std::set<Type> d_printedTypes;
std::map<std::string, std::string> d_rewriteFilters;
+ std::map<Node, std::string> d_assertionFilters;
std::vector<RewriteLogEntry> d_rewriteLog;
@@ -204,6 +202,9 @@ public:
}
assertions_iterator end_assertions() const { return d_inputFormulas.end(); }
size_t num_assertions() const { return d_inputFormulas.size(); }
+ bool have_input_assertion(const Expr& assertion) {
+ return d_inputFormulas.find(assertion) != d_inputFormulas.end();
+ }
//---from Morgan---
Node mkOp(TNode n);
@@ -222,6 +223,7 @@ public:
static std::string getLearntClauseName(ClauseId id, const std::string& prefix = "");
static std::string getPreprocessedAssertionName(Node node, const std::string& prefix = "");
static std::string getAssertionName(Node node, const std::string& prefix = "");
+ static std::string getInputFormulaName(const Expr& expr);
static std::string getVarName(prop::SatVariable var, const std::string& prefix = "");
static std::string getAtomName(prop::SatVariable var, const std::string& prefix = "");
@@ -241,11 +243,17 @@ public:
void addDependence(TNode n, TNode dep);
void addUnsatCore(Expr formula);
+ // trace dependences back to unsat core
+ void traceDeps(TNode n, ExprSet* coreAssertions);
void traceUnsatCore();
assertions_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); }
assertions_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); }
size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
+ bool unsatCoreAvailable() const;
+ void getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas);
+ Node getWeakestImplicantInUnsatCore(Node lemma);
+
int nextId() { return d_nextId++; }
void setLogic(const LogicInfo& logic);
@@ -258,6 +266,8 @@ public:
void addRewriteFilter(const std::string &original, const std::string &substitute);
void clearRewriteFilters();
+ void addAssertionFilter(const Node& node, const std::string& rewritten);
+
static void registerRewrite(unsigned ruleId, Node original, Node result);
static void clearRewriteLog();
@@ -268,6 +278,10 @@ public:
ProofLetMap& letMap,
std::ostream& out,
std::ostringstream& paren);
+
+private:
+ void constructSatProof();
+ std::set<Node> satClauseToNodeSet(prop::SatClause* clause);
};/* class ProofManager */
class LFSCProof : public Proof {
@@ -281,6 +295,9 @@ class LFSCProof : public Proof {
std::ostream& os,
std::ostream& paren,
ProofLetMap& globalLetMap);
+
+ void checkUnrewrittenAssertion(const NodeSet& assertions);
+
public:
LFSCProof(SmtEngine* smtEngine,
LFSCCoreSatProof* sat,
diff --git a/src/proof/proof_utils.h b/src/proof/proof_utils.h
index 546d419fc..b172217d8 100644
--- a/src/proof/proof_utils.h
+++ b/src/proof/proof_utils.h
@@ -33,7 +33,8 @@ typedef std::pair<Node, Node> NodePair;
typedef std::set<NodePair> NodePairSet;
-struct ProofLetCount {
+class ProofLetCount {
+public:
static unsigned counter;
static void resetCounter() { counter = 0; }
static unsigned newId() { return ++counter; }
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index bda8094be..52e059e95 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -198,7 +198,9 @@ class TSatProof {
*/
void constructProof(ClauseId id);
void constructProof() { constructProof(d_emptyClauseId); }
+ bool proofConstructed() const;
void collectClauses(ClauseId id);
+ bool derivedEmptyClause() const;
prop::SatClause* buildClause(ClauseId id);
virtual void printResolution(ClauseId id, std::ostream& out,
@@ -354,7 +356,7 @@ class TSatProof {
IdToSatClause d_seenInputs;
IdToSatClause d_seenLemmas;
- private:
+ private:
__gnu_cxx::hash_map<ClauseId, int> d_glueMap;
struct Statistics {
IntStat d_numLearnedClauses;
@@ -369,6 +371,7 @@ class TSatProof {
~Statistics();
};
+ bool d_satProofConstructed;
Statistics d_statistics;
}; /* class TSatProof */
diff --git a/src/proof/sat_proof_implementation.h b/src/proof/sat_proof_implementation.h
index 1e01e4dce..603559da1 100644
--- a/src/proof/sat_proof_implementation.h
+++ b/src/proof/sat_proof_implementation.h
@@ -224,6 +224,7 @@ TSatProof<Solver>::TSatProof(Solver* solver, const std::string& name,
d_seenLearnt(),
d_seenInputs(),
d_seenLemmas(),
+ d_satProofConstructed(false),
d_statistics(name) {
d_proxy = new ProofProxy<Solver>(this);
}
@@ -957,10 +958,16 @@ void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
template <class Solver>
void TSatProof<Solver>::constructProof(ClauseId conflict) {
+ d_satProofConstructed = true;
collectClauses(conflict);
}
template <class Solver>
+bool TSatProof<Solver>::proofConstructed() const {
+ return d_satProofConstructed;
+}
+
+template <class Solver>
std::string TSatProof<Solver>::clauseName(ClauseId id) {
std::ostringstream os;
if (isInputClause(id)) {
@@ -998,6 +1005,11 @@ prop::SatClause* TSatProof<Solver>::buildClause(ClauseId id) {
}
template <class Solver>
+bool TSatProof<Solver>::derivedEmptyClause() const {
+ return hasResolutionChain(d_emptyClauseId);
+}
+
+template <class Solver>
void TSatProof<Solver>::collectClauses(ClauseId id) {
if (d_seenInputs.find(id) != d_seenInputs.end() ||
d_seenLemmas.find(id) != d_seenLemmas.end() ||
@@ -1080,33 +1092,34 @@ TSatProof<Solver>::Statistics::~Statistics() {
template <class Solver>
void LFSCSatProof<Solver>::printResolution(ClauseId id, std::ostream& out,
std::ostream& paren) {
- out << "(satlem_simplify _ _ _ ";
+ out << "(satlem_simplify _ _ _";
+ paren << ")";
const ResChain<Solver>& res = this->getResolutionChain(id);
const typename ResChain<Solver>::ResSteps& steps = res.getSteps();
for (int i = steps.size() - 1; i >= 0; i--) {
- out << "(";
- out << (steps[i].sign ? "R" : "Q") << " _ _ ";
+ out << " (";
+ out << (steps[i].sign ? "R" : "Q") << " _ _";
}
ClauseId start_id = res.getStart();
- out << this->clauseName(start_id) << " ";
+ out << " " << this->clauseName(start_id);
for (unsigned i = 0; i < steps.size(); i++) {
prop::SatVariable v =
prop::MinisatSatSolver::toSatVariable(var(steps[i].lit));
- out << this->clauseName(steps[i].id) << " "
+ out << " " << this->clauseName(steps[i].id) << " "
<< ProofManager::getVarName(v, this->d_name) << ")";
}
if (id == this->d_emptyClauseId) {
- out <<"(\\ empty empty)";
+ out <<" (\\ empty empty)";
return;
}
- out << "(\\ " << this->clauseName(id) << "\n"; // bind to lemma name
- paren << "))"; // closing parethesis for lemma binding and satlem
+ out << " (\\ " << this->clauseName(id) << "\n"; // bind to lemma name
+ paren << ")";
}
/// LFSCSatProof class
diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp
index d12b561a6..1912dbada 100644
--- a/src/proof/theory_proof.cpp
+++ b/src/proof/theory_proof.cpp
@@ -126,26 +126,26 @@ void TheoryProofEngine::markTermForFutureRegistration(Expr term, theory::TheoryI
d_exprToTheoryIds[term].insert(id);
}
-void TheoryProofEngine::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+void TheoryProofEngine::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
Assert(c1.isConst());
Assert(c2.isConst());
Assert(theory::Theory::theoryOf(c1) == theory::Theory::theoryOf(c2));
- getTheoryProof(theory::Theory::theoryOf(c1))->printConstantDisequalityProof(os, c1, c2);
+ getTheoryProof(theory::Theory::theoryOf(c1))->printConstantDisequalityProof(os, c1, c2, globalLetMap);
}
void TheoryProofEngine::registerTerm(Expr term) {
- Debug("pf::tp") << "TheoryProofEngine::registerTerm: registering term: " << term << std::endl;
+ Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering term: " << term << std::endl;
if (d_registrationCache.count(term)) {
return;
}
- Debug("pf::tp") << "TheoryProofEngine::registerTerm: registering NEW term: " << term << std::endl;
+ Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering NEW term: " << term << std::endl;
theory::TheoryId theory_id = theory::Theory::theoryOf(term);
- Debug("pf::tp") << "Term's theory( " << term << " ) = " << theory_id << std::endl;
+ Debug("pf::tp::register") << "Term's theory( " << term << " ) = " << theory_id << std::endl;
// don't need to register boolean terms
if (theory_id == theory::THEORY_BUILTIN ||
@@ -165,7 +165,7 @@ void TheoryProofEngine::registerTerm(Expr term) {
// A special case: the array theory needs to know of every skolem, even if
// it belongs to another theory (e.g., a BV skolem)
if (ProofManager::getSkolemizationManager()->isSkolem(term) && theory_id != theory::THEORY_ARRAY) {
- Debug("pf::tp") << "TheoryProofEngine::registerTerm: Special case: registering a non-array skolem: " << term << std::endl;
+ Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering a non-array skolem: " << term << std::endl;
getTheoryProof(theory::THEORY_ARRAY)->registerTerm(term);
}
@@ -321,15 +321,12 @@ void LFSCTheoryProofEngine::registerTermsFromAssertions() {
void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& paren) {
Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions called" << std::endl << std::endl;
- unsigned counter = 0;
ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
for (; it != end; ++it) {
Debug("pf::tp") << "printAssertions: assertion is: " << *it << std::endl;
- std::ostringstream name;
- name << "A" << counter++;
- os << "(% " << name.str() << " (th_holds ";
+ os << "(% " << ProofManager::currentPM()->getInputFormulaName(*it) << " (th_holds ";
// Assertions appear before the global let map, so we use a dummpMap to avoid letification here.
ProofLetMap dummyMap;
@@ -406,13 +403,13 @@ void LFSCTheoryProofEngine::printDeferredDeclarations(std::ostream& os, std::ost
}
}
-void LFSCTheoryProofEngine::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCTheoryProofEngine::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
Debug("pf::tp") << "LFSCTheoryProofEngine::printAliasingDeclarations called" << std::endl;
TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
TheoryProofTable::const_iterator end = d_theoryProofTable.end();
for (; it != end; ++it) {
- it->second->printAliasingDeclarations(os, paren);
+ it->second->printAliasingDeclarations(os, paren, globalLetMap);
}
}
@@ -632,15 +629,27 @@ void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
clause_expr[k] = missingAssertion->toExpr();
std::ostringstream rewritten;
- rewritten << "(or_elim_1 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_1 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
+
+ if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) {
+ rewritten << "(or_elim_2 _ _ ";
+ rewritten << "(not_not_intro _ ";
+ rewritten << pm->getLitName(explanation);
+ rewritten << ") (iff_elim_2 _ _ ";
+ rewritten << d_assertionToRewrite[missingAssertion->negate()];
+ rewritten << "))";
+ }
+ else {
+ rewritten << "(or_elim_1 _ _ ";
+ rewritten << "(not_not_intro _ ";
+ rewritten << pm->getLitName(explanation);
+ rewritten << ") (iff_elim_1 _ _ ";
+ rewritten << d_assertionToRewrite[missingAssertion->negate()];
+ rewritten << "))";
+ }
Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
<< pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
+ << ", explanation = " << explanation
<< std::endl << std::endl;
pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
@@ -742,15 +751,27 @@ void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
currentClauseExpr[k] = missingAssertion->toExpr();
std::ostringstream rewritten;
- rewritten << "(or_elim_1 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_1 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
+
+ if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) {
+ rewritten << "(or_elim_2 _ _ ";
+ rewritten << "(not_not_intro _ ";
+ rewritten << pm->getLitName(explanation);
+ rewritten << ") (iff_elim_2 _ _ ";
+ rewritten << d_assertionToRewrite[missingAssertion->negate()];
+ rewritten << "))";
+ }
+ else {
+ rewritten << "(or_elim_1 _ _ ";
+ rewritten << "(not_not_intro _ ";
+ rewritten << pm->getLitName(explanation);
+ rewritten << ") (iff_elim_1 _ _ ";
+ rewritten << d_assertionToRewrite[missingAssertion->negate()];
+ rewritten << "))";
+ }
Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
<< pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
+ << "explanation = " << explanation
<< std::endl << std::endl;
pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
@@ -837,6 +858,7 @@ void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const Pro
os << "(";
os << "= ";
printSort(term[0].getType(), os);
+ os << " ";
printBoundTerm(term[0], os, map);
os << " ";
printBoundTerm(term[1], os, map);
@@ -850,6 +872,7 @@ void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const Pro
if (term.getNumChildren() == 2) {
os << "(not (= ";
printSort(term[0].getType(), os);
+ os << " ";
printBoundTerm(term[0], os, map);
os << " ";
printBoundTerm(term[1], os, map);
@@ -865,6 +888,7 @@ void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const Pro
if ((i != 0) || (j != 1)) {
os << "(not (= ";
printSort(term[0].getType(), os);
+ os << " ";
printBoundTerm(term[i], os, map);
os << " ";
printBoundTerm(term[j], os, map);
@@ -872,6 +896,7 @@ void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const Pro
} else {
os << "(not (= ";
printSort(term[0].getType(), os);
+ os << " ";
printBoundTerm(term[0], os, map);
os << " ";
printBoundTerm(term[1], os, map);
@@ -968,13 +993,6 @@ void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
Assert(!oc.d_lemma.isNull());
Trace("pf::tp") << "; ++ but got lemma: " << oc.d_lemma << std::endl;
- // Original, as in Liana's branch
- // Trace("pf::tp") << "; asserting " << oc.d_lemma[1].negate() << std::endl;
- // th->assertFact(oc.d_lemma[1].negate(), false);
- // th->check(theory::Theory::EFFORT_FULL);
-
- // Altered version, to handle OR lemmas
-
if (oc.d_lemma.getKind() == kind::OR) {
Debug("pf::tp") << "OR lemma. Negating each child separately" << std::endl;
for (unsigned i = 0; i < oc.d_lemma.getNumChildren(); ++i) {
@@ -1063,7 +1081,7 @@ void LFSCBooleanProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLe
}
// The let map should already have the current expression.
- ProofLetMap::const_iterator it = map.find(term);
+ ProofLetMap::const_iterator it = map.find(currentExpression.toExpr());
if (it != map.end()) {
unsigned id = it->second.id;
unsigned count = it->second.count;
@@ -1144,25 +1162,25 @@ void LFSCBooleanProof::printDeferredDeclarations(std::ostream& os, std::ostream&
// Nothing to do here at this point.
}
-void LFSCBooleanProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCBooleanProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
// Nothing to do here at this point.
}
void LFSCBooleanProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
std::ostream& os,
- std::ostream& paren) {
+ std::ostream& paren,
+ const ProofLetMap& map) {
Unreachable("No boolean lemmas yet!");
}
-void TheoryProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+void TheoryProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
// By default, we just print a trust statement. Specific theories can implement
// better proofs.
- ProofLetMap emptyMap;
os << "(trust_f (not (= _ ";
- d_proofEngine->printBoundTerm(c1, os, emptyMap);
+ d_proofEngine->printBoundTerm(c1, os, globalLetMap);
os << " ";
- d_proofEngine->printBoundTerm(c2, os, emptyMap);
+ d_proofEngine->printBoundTerm(c2, os, globalLetMap);
os << ")))";
}
diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h
index 5907f9bd5..34248f7eb 100644
--- a/src/proof/theory_proof.h
+++ b/src/proof/theory_proof.h
@@ -109,7 +109,7 @@ public:
* @param os
* @param paren closing parenthesis
*/
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren) = 0;
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0;
/**
* Print proofs of all the theory lemmas (must prove
@@ -149,7 +149,7 @@ public:
void markTermForFutureRegistration(Expr term, theory::TheoryId id);
- void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2);
+ void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap);
virtual void treatBoolsAsFormulas(bool value) {};
@@ -173,7 +173,7 @@ public:
virtual void printAssertions(std::ostream& os, std::ostream& paren);
virtual void printLemmaRewrites(NodePairSet& rewrites, std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
virtual void printTheoryLemmas(const IdToSatClause& lemmas,
std::ostream& os,
std::ostream& paren,
@@ -205,7 +205,7 @@ public:
{}
virtual ~TheoryProof() {};
/**
- * Print a term belonging some theory, not neccessarily this one.
+ * Print a term belonging some theory, not necessarily this one.
*
* @param term expresion representing term
* @param os output stream
@@ -216,7 +216,7 @@ public:
/**
* Print a term belonging to THIS theory.
*
- * @param term expresion representing term
+ * @param term expression representing term
* @param os output stream
*/
virtual void printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) = 0;
@@ -274,7 +274,7 @@ public:
* @param os
* @param paren
*/
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren) = 0;
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0;
/**
* Register a term of this theory that appears in the proof.
*
@@ -286,7 +286,7 @@ public:
*
* @param term
*/
- virtual void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2);
+ virtual void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap);
/**
* Print a proof for the equivalence of n1 and n2.
*
@@ -308,11 +308,11 @@ public:
virtual void printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) = 0;
virtual void printOwnedSort(Type type, std::ostream& os) = 0;
- virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) = 0;
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) = 0;
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren) = 0;
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren) = 0;
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0;
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren) = 0;
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0;
};
class LFSCBooleanProof : public BooleanProof {
@@ -322,11 +322,11 @@ public:
{}
virtual void printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map);
virtual void printOwnedSort(Type type, std::ostream& os);
- virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map);
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren);
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
void treatBoolsAsFormulas(bool value) {
d_treatBoolsAsFormulas = value;
diff --git a/src/proof/uf_proof.cpp b/src/proof/uf_proof.cpp
index 139ce5ed2..27f351102 100644
--- a/src/proof/uf_proof.cpp
+++ b/src/proof/uf_proof.cpp
@@ -264,7 +264,7 @@ Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::E
out << ss.str();
out << " ";
- ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out, n1[0].toExpr(), n1[1].toExpr());
+ ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out, n1[0].toExpr(), n1[1].toExpr(), map);
out << "))" << std::endl;
}
@@ -733,7 +733,7 @@ void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) {
Debug("pf::uf") << std::endl << "(pf::uf) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl;
Assert (type.isSort());
- os << type <<" ";
+ os << type;
}
void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
@@ -797,7 +797,7 @@ void LFSCUFProof::printDeferredDeclarations(std::ostream& os, std::ostream& pare
// Nothing to do here at this point.
}
-void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
// Nothing to do here at this point.
}
diff --git a/src/proof/uf_proof.h b/src/proof/uf_proof.h
index 444b602dc..ff0f9a879 100644
--- a/src/proof/uf_proof.h
+++ b/src/proof/uf_proof.h
@@ -70,7 +70,7 @@ public:
virtual void printSortDeclarations(std::ostream& os, std::ostream& paren);
virtual void printTermDeclarations(std::ostream& os, std::ostream& paren);
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap);
};
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index eda736b8a..f2401041e 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -678,8 +678,7 @@ void TseitinCnfStream::convertAndAssert(TNode node,
bool removable,
bool negated,
ProofRule proof_id,
- TNode from,
- LemmaProofRecipe* proofRecipe) {
+ TNode from) {
Debug("cnf") << "convertAndAssert(" << node
<< ", removable = " << (removable ? "true" : "false")
<< ", negated = " << (negated ? "true" : "false") << ")" << endl;
@@ -689,12 +688,6 @@ void TseitinCnfStream::convertAndAssert(TNode node,
Node assertion = negated ? node.notNode() : (Node)node;
Node from_assertion = negated? from.notNode() : (Node) from;
- if (proofRecipe) {
- Debug("pf::sat") << "TseitinCnfStream::convertAndAssert: setting proof recipe" << std::endl;
- proofRecipe->dump("pf::sat");
- d_cnfProof->setProofRecipe(proofRecipe);
- }
-
if (proof_id != RULE_INVALID) {
d_cnfProof->pushCurrentAssertion(from.isNull() ? assertion : from_assertion);
d_cnfProof->registerAssertion(from.isNull() ? assertion : from_assertion, proof_id);
diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h
index 6cc10d878..661108dd0 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -37,8 +37,6 @@
namespace CVC4 {
-class LemmaProofRecipe;
-
namespace prop {
class PropEngine;
@@ -210,9 +208,8 @@ public:
* @param node node to convert and assert
* @param removable whether the sat solver can choose to remove the clauses
* @param negated whether we are asserting the node negated
- * @param proofRecipe contains the proof recipe for proving this node
*/
- virtual void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null(), LemmaProofRecipe* proofRecipe = NULL) = 0;
+ virtual void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null()) = 0;
/**
* Get the node that is represented by the given SatLiteral.
@@ -282,8 +279,7 @@ public:
* @param negated true if negated
*/
void convertAndAssert(TNode node, bool removable,
- bool negated, ProofRule rule, TNode from = TNode::null(),
- LemmaProofRecipe* proofRecipe = NULL);
+ bool negated, ProofRule rule, TNode from = TNode::null());
/**
* Constructs the stream to use the given sat solver.
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index eb607e901..6cdf17f30 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -132,13 +132,12 @@ void PropEngine::assertFormula(TNode node) {
void PropEngine::assertLemma(TNode node, bool negated,
bool removable,
ProofRule rule,
- LemmaProofRecipe* proofRecipe,
TNode from) {
//Assert(d_inCheckSat, "Sat solver should be in solve()!");
Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl;
// Assert as (possibly) removable
- d_cnfStream->convertAndAssert(node, removable, negated, rule, from, proofRecipe);
+ d_cnfStream->convertAndAssert(node, removable, negated, rule, from);
}
void PropEngine::requirePhase(TNode n, bool phase) {
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index c02015931..f966def26 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -37,7 +37,6 @@ namespace CVC4 {
class ResourceManager;
class DecisionEngine;
class TheoryEngine;
-class LemmaProofRecipe;
namespace theory {
class TheoryRegistrar;
@@ -135,7 +134,7 @@ public:
* @param removable whether this lemma can be quietly removed based
* on an activity heuristic (or not)
*/
- void assertLemma(TNode node, bool negated, bool removable, ProofRule rule, LemmaProofRecipe* proofRecipe, TNode from = TNode::null());
+ void assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from = TNode::null());
/**
* If ever n is decided upon, it must be in the given phase. This
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 6e8f1fbbf..5f5eac733 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -181,8 +181,7 @@ void TheoryProxy::notifyRestart() {
Debug("shared") << "=) " << asNode << std::endl;
}
- LemmaProofRecipe* noProofRecipe = NULL;
- d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID, noProofRecipe);
+ d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID);
} else {
Debug("shared") << "=(" << asNode << std::endl;
}
diff --git a/src/smt/dump.cpp b/src/smt/dump.cpp
index eee7b901a..dc1ef792d 100644
--- a/src/smt/dump.cpp
+++ b/src/smt/dump.cpp
@@ -32,7 +32,9 @@ std::ostream* DumpC::getStreamPointer() { return ::CVC4::DumpOutChannel.getStrea
void DumpC::setDumpFromString(const std::string& optarg) {
#ifdef CVC4_DUMPING
- char* optargPtr = strdup(optarg.c_str());
+ // Make a copy of optarg for strtok_r to use.
+ std::string optargCopy = optarg;
+ char* optargPtr = const_cast<char*>(optargCopy.c_str());
char* tokstr = optargPtr;
char* toksave;
while((optargPtr = strtok_r(tokstr, ",", &toksave)) != NULL) {
@@ -130,7 +132,6 @@ void DumpC::setDumpFromString(const std::string& optarg) {
}
}
}
- free(optargPtr);
#else /* CVC4_DUMPING */
throw OptionException("The dumping feature was disabled in this build of CVC4.");
#endif /* CVC4_DUMPING */
diff --git a/src/smt/model.h b/src/smt/model.h
index 768cb3e6a..fd31655f4 100644
--- a/src/smt/model.h
+++ b/src/smt/model.h
@@ -58,7 +58,6 @@ public:
const SmtEngine* getSmtEngine() const { return &d_smt; }
/** get the input name (file name, etc.) this model is associated to */
std::string getInputName() const { return d_inputName; }
-
public:
/** Check whether this expr is a don't-care in the model */
virtual bool isDontCare(Expr expr) const { return false; }
@@ -66,6 +65,10 @@ public:
virtual Expr getValue(Expr expr) const = 0;
/** get cardinality for sort */
virtual Cardinality getCardinality(Type t) const = 0;
+ /** print comments */
+ virtual void getComments(std::ostream& out) const {}
+ /** get heap model (for separation logic) */
+ virtual bool getHeapModel( Expr& h, Expr& ne ) const { return false; }
};/* class Model */
class ModelBuilder {
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 08495c936..32c44d224 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -57,6 +57,7 @@
#include "options/open_ostream.h"
#include "options/option_exception.h"
#include "options/printer_options.h"
+#include "options/proof_options.h"
#include "options/prop_options.h"
#include "options/quantifiers_options.h"
#include "options/set_language.h"
@@ -92,9 +93,9 @@
#include "theory/quantifiers/fun_def_process.h"
#include "theory/quantifiers/macros.h"
#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/sep/theory_sep.h"
#include "theory/sort_inference.h"
#include "theory/strings/theory_strings.h"
-#include "theory/sep/theory_sep.h"
#include "theory/substitutions.h"
#include "theory/theory_engine.h"
#include "theory/theory_model.h"
@@ -1349,8 +1350,8 @@ void SmtEngine::setDefaults() {
Trace("smt") << "turning on quantifier logic, for strings-exp"
<< std::endl;
}
- if(! options::fmfBoundInt.wasSetByUser()) {
- options::fmfBoundInt.set( true );
+ if(! options::fmfBound.wasSetByUser()) {
+ options::fmfBound.set( true );
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
if(! options::fmfInstEngine.wasSetByUser()) {
@@ -1752,12 +1753,13 @@ void SmtEngine::setDefaults() {
options::cbqi.set(false);
}
- if(options::fmfBoundIntLazy.wasSetByUser() && options::fmfBoundIntLazy()) {
- options::fmfBoundInt.set( true );
+ if( ( options::fmfBoundLazy.wasSetByUser() && options::fmfBoundLazy() ) ||
+ ( options::fmfBoundInt.wasSetByUser() && options::fmfBoundInt() ) ) {
+ options::fmfBound.set( true );
}
//now have determined whether fmfBoundInt is on/off
//apply fmfBoundInt options
- if( options::fmfBoundInt() ){
+ if( options::fmfBound() ){
//must have finite model finding on
options::finiteModelFind.set( true );
if( ! options::mbqiMode.wasSetByUser() ||
@@ -3986,15 +3988,6 @@ void SmtEnginePrivate::processAssertions() {
dumpAssertions("post-bv-to-bool", d_assertions);
Trace("smt") << "POST bvToBool" << endl;
}
- if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
- Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-strings-preprocess" << endl;
- dumpAssertions("pre-strings-pp", d_assertions);
- if( !options::stringLazyPreproc() ){
- ((theory::strings::TheoryStrings*)d_smt.d_theoryEngine->theoryOf(THEORY_STRINGS))->getPreprocess()->simplify( d_assertions.ref() );
- }
- Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-strings-preprocess" << endl;
- dumpAssertions("post-strings-pp", d_assertions);
- }
if( d_smt.d_logic.isTheoryEnabled(THEORY_SEP) ) {
//separation logic solver needs to register the entire input
((theory::sep::TheorySep*)d_smt.d_theoryEngine->theoryOf(THEORY_SEP))->processAssertions( d_assertions.ref() );
@@ -4292,8 +4285,10 @@ void SmtEnginePrivate::addFormula(TNode n, bool inUnsatCore, bool inInput)
PROOF(
if( inInput ){
// n is an input assertion
- if (inUnsatCore || options::dumpUnsatCores() || options::checkUnsatCores())
+ if (inUnsatCore || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
+
ProofManager::currentPM()->addCoreAssertion(n.toExpr());
+ }
}else{
// n is the result of an unknown preprocessing step, add it to dependency map to null
ProofManager::currentPM()->addDependence(n, Node::null());
diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp
index 6dfd14157..8dd7fe782 100644
--- a/src/theory/arrays/array_proof_reconstruction.cpp
+++ b/src/theory/arrays/array_proof_reconstruction.cpp
@@ -60,7 +60,7 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a,
// or ((a[i]:=t)[k] == a[k]) because (i != k).
if (proof) {
- if (a.getNumChildren() == 2) {
+ if (a.getKind() == kind::SELECT) {
// This is the case of ((a[i]:=t)[k] == a[k]) because (i != k).
// The edge is ((a[i]:=t)[k], a[k]), or (a[k], (a[i]:=t)[k]). This flag should be
@@ -156,7 +156,7 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a,
proof->d_children.push_back(childProof);
} else {
- // This is the case of (i == k) because ((a[i]:=t)[k] != a[k]),
+ // This is the case of (i == k) because ((a[i]:=t)[k] != a[k]),
Node indexOne = a;
Node indexTwo = b;
diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h
index 643093327..93a938cc0 100644
--- a/src/theory/bv/bv_subtheory_core.h
+++ b/src/theory/bv/bv_subtheory_core.h
@@ -117,6 +117,7 @@ public:
bool hasTerm(TNode node) const { return d_equalityEngine.hasTerm(node); }
void addTermToEqualityEngine(TNode node) { d_equalityEngine.addTerm(node); }
void enableSlicer();
+ eq::EqualityEngine * getEqualityEngine() { return &d_equalityEngine; }
};
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index fec93e033..f0981044b 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -495,7 +495,36 @@ void TheoryBV::propagate(Effort e) {
}
}
+eq::EqualityEngine * TheoryBV::getEqualityEngine() {
+ return NULL;
+}
+bool TheoryBV::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
+#if 0
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if( core ){
+ //get the constant equivalence classes
+ bool retVal = false;
+ for( unsigned i=0; i<vars.size(); i++ ){
+ Node n = vars[i];
+ if( core->getEqualityEngine()->hasTerm( n ) ){
+ Node nr = core->getEqualityEngine()->getRepresenative( n );
+ if( nr.isConst() ){
+ subs.push_back( nr );
+ exp[n].push_back( n.eqNode( nr ) );
+ retVal = true;
+ }else{
+ subs.push_back( n );
+ }
+ }
+ }
+ //return true if the substitution is non-trivial
+ return retVal;
+ }
+#endif
+ return false;
+}
+
Theory::PPAssertStatus TheoryBV::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
switch(in.getKind()) {
case kind::EQUAL:
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index ba2a4fc2a..0709ca427 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -79,6 +79,10 @@ public:
std::string identify() const { return std::string("TheoryBV"); }
+ /** equality engine */
+ eq::EqualityEngine * getEqualityEngine();
+ bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp );
+
PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
void enableCoreTheorySlicer();
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index a2f995935..59b9f1d96 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -865,6 +865,11 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
}
//d_consEqc[t1] = true;
}
+ //AJR: do this?
+ //else if( cons2.isConst() ){
+ // //prefer the constant
+ // eqc1->d_constructor = cons2;
+ //}
//d_consEqc[t2] = false;
}
}else{
@@ -2090,6 +2095,9 @@ TNode TheoryDatatypes::getRepresentative( TNode a ){
}
}
+bool TheoryDatatypes::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
+ return false;
+}
void TheoryDatatypes::printModelDebug( const char* c ){
if(! (Trace.isOn(c))) {
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 5722e7822..49c45590c 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -266,6 +266,9 @@ public:
void collectModelInfo( TheoryModel* m, bool fullModel );
void shutdown() { }
std::string identify() const { return std::string("TheoryDatatypes"); }
+ /** equality engine */
+ eq::EqualityEngine * getEqualityEngine() { return &d_equalityEngine; }
+ bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp );
/** debug print */
void printModelDebug( const char* c );
/** entailment check */
@@ -313,9 +316,6 @@ private:
bool areEqual( TNode a, TNode b );
bool areDisequal( TNode a, TNode b );
TNode getRepresentative( TNode a );
-public:
- /** get equality engine */
- eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
};/* class TheoryDatatypes */
}/* CVC4::theory::datatypes namespace */
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index 7184624da..54853ceaf 100755
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -20,6 +20,7 @@
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/quant_util.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/theory_engine.h"
using namespace CVC4;
using namespace std;
@@ -30,7 +31,7 @@ using namespace CVC4::kind;
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() ){
+ if( options::fmfBoundLazy() ){
d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
}else{
d_proxy_range = r;
@@ -232,14 +233,12 @@ void BoundedIntegers::processLiteral( Node q, Node lit, bool pol,
}
}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;
}
@@ -330,6 +329,7 @@ void BoundedIntegers::registerQuantifier( Node f ) {
setBoundedVar( f, v, BOUND_SET_MEMBER );
setBoundVar = true;
d_setm_range[f][v] = bound_lit_map[0][v][1];
+ d_setm_range_lit[f][v] = bound_lit_map[0][v];
Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl;
}
if( setBoundVar ){
@@ -515,6 +515,63 @@ Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
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;
+ //map to term model
+ if( sr.getKind()!=EMPTYSET ){
+ std::map< Node, Node > val_to_term;
+ while( sr.getKind()==UNION ){
+ Assert( sr[1].getKind()==kind::SINGLETON );
+ val_to_term[ sr[1][0] ] = sr[1][0];
+ sr = sr[0];
+ }
+ Assert( sr.getKind()==kind::SINGLETON );
+ val_to_term[ sr[0] ] = sr[0];
+ //must look back at assertions, not term database (theory of sets introduces extraneous terms internally)
+ Theory* theory = d_quantEngine->getTheoryEngine()->theoryOf( THEORY_SETS );
+ if( theory ){
+ context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
+ for( unsigned i = 0; it != it_end; ++ it, ++i ){
+ Node lit = (*it).assertion;
+ if( lit.getKind()==kind::MEMBER ){
+ Node vr = d_quantEngine->getModel()->getCurrentModelValue( lit[0] );
+ Trace("bound-int-rsi-debug") << "....membership for " << lit << " ==> " << vr << std::endl;
+ Trace("bound-int-rsi-debug") << " " << (val_to_term.find( vr )!=val_to_term.end()) << " " << d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) << std::endl;
+ if( val_to_term.find( vr )!=val_to_term.end() ){
+ if( d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) ){
+ Trace("bound-int-rsi") << " Map value to term : " << vr << " -> " << lit[0] << std::endl;
+ val_to_term[ vr ] = lit[0];
+ }
+ }
+ }
+ }
+ }
+ //rebuild value
+ Node nsr;
+ for( std::map< Node, Node >::iterator it = val_to_term.begin(); it != val_to_term.end(); ++it ){
+ Node nv = NodeManager::currentNM()->mkNode( kind::SINGLETON, it->second );
+ if( nsr.isNull() ){
+ nsr = nv;
+ }else{
+ nsr = NodeManager::currentNM()->mkNode( kind::UNION, nsr, nv );
+ }
+ }
+ Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl;
+ return nsr;
+
+ /*
+ Node lit = d_setm_range_lit[q][v];
+ Trace("bound-int-rsi-debug") << "Bounded from lit " << lit << std::endl;
+ Node f = d_quantEngine->getTermDatabase()->getMatchOperator( lit );
+ TermArgTrie * ta = d_quantEngine->getTermDatabase()->getTermArgTrie( f );
+ if( ta ){
+ Trace("bound-int-rsi-debug") << "Got term index for " << f << std::endl;
+ for( std::map< TNode, TermArgTrie >::iterator it = ta->d_data.begin(); it != ta->d_data.end(); ++it ){
+
+ }
+
+ }
+ */
+ }
+
}
return sr;
}
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
index ab4bcba96..c3fb05641 100755
--- a/src/theory/quantifiers/bounded_integers.h
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -60,6 +60,7 @@ private:
std::map< Node, std::map< Node, Node > > d_nground_range;
//set membership range
std::map< Node, std::map< Node, Node > > d_setm_range;
+ std::map< Node, std::map< Node, Node > > d_setm_range_lit;
void hasFreeVar( Node f, Node n );
void process( Node f, Node n, bool pol,
std::map< Node, unsigned >& bound_lit_type_map,
diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp
index 3177739ac..981abea94 100755
--- a/src/theory/quantifiers/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv.cpp
@@ -658,17 +658,22 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
}
}
-Node CegConjectureSingleInv::constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index ) {
+Node CegConjectureSingleInv::constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index, std::map< Node, Node >& weak_imp ) {
Assert( index<d_inst.size() );
Assert( i<d_inst[index].size() );
unsigned uindex = indices[index];
- if( index==d_inst.size()-1 ){
+ if( index==indices.size()-1 ){
return d_inst[uindex][i];
}else{
Node cond = d_lemmas_produced[uindex];
+ //weaken based on unsat core
+ std::map< Node, Node >::iterator itw = weak_imp.find( cond );
+ if( itw!=weak_imp.end() ){
+ cond = itw->second;
+ }
cond = TermDb::simpleNegate( cond );
Node ite1 = d_inst[uindex][i];
- Node ite2 = constructSolution( indices, i, index+1 );
+ Node ite2 = constructSolution( indices, i, index+1, weak_imp );
return NodeManager::currentNM()->mkNode( ITE, cond, ite1, ite2 );
}
}
@@ -753,12 +758,35 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int&
//construct the solution
Trace("csi-sol") << "Sort solution return values " << sol_index << std::endl;
+ bool useUnsatCore = false;
+ std::vector< Node > active_lemmas;
+ //minimize based on unsat core, if possible
+ std::map< Node, Node > weak_imp;
+ if( options::cegqiSolMinCore() ){
+ if( options::cegqiSolMinInst() ){
+ if( d_qe->getUnsatCoreLemmas( active_lemmas, weak_imp ) ){
+ useUnsatCore = true;
+ }
+ }else{
+ if( d_qe->getUnsatCoreLemmas( active_lemmas ) ){
+ useUnsatCore = true;
+ }
+ }
+ }
Assert( d_lemmas_produced.size()==d_inst.size() );
std::vector< unsigned > indices;
for( unsigned i=0; i<d_lemmas_produced.size(); i++ ){
- Assert( sol_index<d_inst[i].size() );
- indices.push_back( i );
+ bool incl = true;
+ if( useUnsatCore ){
+ incl = std::find( active_lemmas.begin(), active_lemmas.end(), d_lemmas_produced[i] )!=active_lemmas.end();
+ }
+ if( incl ){
+ Assert( sol_index<d_inst[i].size() );
+ indices.push_back( i );
+ }
}
+ Trace("csi-sol") << "...included " << indices.size() << " / " << d_lemmas_produced.size() << " instantiations." << std::endl;
+ Assert( !indices.empty() );
//sort indices based on heuristic : currently, do all constant returns first (leads to simpler conditions)
// TODO : to minimize solution size, put the largest term last
sortSiInstanceIndices ssii;
@@ -766,7 +794,7 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int&
ssii.d_i = sol_index;
std::sort( indices.begin(), indices.end(), ssii );
Trace("csi-sol") << "Construct solution" << std::endl;
- s = constructSolution( indices, sol_index, 0 );
+ s = constructSolution( indices, sol_index, 0, weak_imp );
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() );
}
diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h
index 4d2f9a0e5..feadeca39 100755
--- a/src/theory/quantifiers/ce_guided_single_inv.h
+++ b/src/theory/quantifiers/ce_guided_single_inv.h
@@ -74,7 +74,7 @@ private:
std::map< Node, std::vector< Node > >& teq,
Node n, std::vector< Node >& conj );
//constructing solution
- Node constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index );
+ Node constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index, std::map< Node, Node >& weak_imp );
Node postProcessSolution( Node n );
private:
//list of skolems for each argument of programs
diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp
index cd263e90c..0fe4b98c7 100755
--- a/src/theory/quantifiers/ceg_instantiator.cpp
+++ b/src/theory/quantifiers/ceg_instantiator.cpp
@@ -749,6 +749,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
Trace("cbqi-inst") << pv_coeff << " * ";
}
Trace("cbqi-inst") << pv << " -> " << n << std::endl;
+ Assert( n.getType().isSubtypeOf( pv.getType() ) );
}
//must ensure variables have been computed for n
computeProgVars( n );
@@ -772,6 +773,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
std::vector< Node > new_has_coeff;
Trace("cbqi-inst-debug2") << "Applying substitutions..." << std::endl;
for( unsigned j=0; j<sf.d_subs.size(); j++ ){
+ Trace("cbqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl;
Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() );
if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
prev_subs[j] = sf.d_subs[j];
@@ -1629,10 +1631,11 @@ int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, No
real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) );
}
}
- for( unsigned t=0; t<2; t++ ){
- if( !vts_coeff[t].isNull() ){
- vts_coeff[t] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[t] ) );
- }
+ //remove delta TODO: check this
+ vts_coeff[1] = Node::null();
+ //multiply inf
+ if( !vts_coeff[0].isNull() ){
+ vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) );
}
realPart = real_part.empty() ? d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) );
Assert( d_out->isEligibleForInstantiation( realPart ) );
@@ -1645,7 +1648,7 @@ int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, No
int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1;
val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS,
NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ),
- NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) );
+ NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) ); //TODO: round up for upper bounds?
Trace("cbqi-inst-debug") << "result : " << val << std::endl;
Assert( val.getType().isInteger() );
}
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index a0665cb7f..be608aeaa 100755
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -668,7 +668,7 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f,
}
}
if( addInst ){
- if( options::fmfBoundInt() ){
+ if( options::fmfBound() ){
std::vector< Node > cond;
cond.push_back(d_quant_cond[f]);
cond.insert( cond.end(), inst.begin(), inst.end() );
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index 8818175db..7e5424d9c 100755
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
@@ -199,31 +199,90 @@ bool InstMatchTrie::removeInstMatch( QuantifiersEngine* qe, Node q, std::vector<
}
}
-void InstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms ) const {
+bool InstMatchTrie::recordInstLemma( Node q, std::vector< Node >& m, Node lem, ImtIndexOrder* imtio, int index ){
+ if( index==(int)q[0].getNumChildren() || ( imtio && index==(int)imtio->d_order.size() ) ){
+ setInstLemma( lem );
+ return true;
+ }else{
+ int i_index = imtio ? imtio->d_order[index] : index;
+ std::map< Node, InstMatchTrie >::iterator it = d_data.find( m[i_index] );
+ if( it!=d_data.end() ){
+ return it->second.recordInstLemma( q, m, lem, imtio, index+1 );
+ }else{
+ return false;
+ }
+ }
+}
+
+void InstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms, bool& firstTime, bool useActive, std::vector< Node >& active ) const {
if( terms.size()==q[0].getNumChildren() ){
- out << " ( ";
- for( unsigned i=0; i<terms.size(); i++ ){
- if( i>0 ){ out << ", ";}
- out << terms[i];
+ bool print;
+ if( useActive ){
+ if( hasInstLemma() ){
+ Node lem = getInstLemma();
+ print = std::find( active.begin(), active.end(), lem )!=active.end();
+ }else{
+ print = false;
+ }
+ }else{
+ print = true;
+ }
+ if( print ){
+ if( firstTime ){
+ out << "(instantiation " << q << std::endl;
+ firstTime = false;
+ }
+ out << " ( ";
+ for( unsigned i=0; i<terms.size(); i++ ){
+ if( i>0 ){ out << ", ";}
+ out << terms[i];
+ }
+ out << " )" << std::endl;
}
- out << " )" << std::endl;
}else{
for( std::map< Node, InstMatchTrie >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
terms.push_back( it->first );
- it->second.print( out, q, terms );
+ it->second.print( out, q, terms, firstTime, useActive, active );
terms.pop_back();
}
}
}
-void InstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const {
+void InstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) const {
if( terms.size()==q[0].getNumChildren() ){
- //insts.push_back( q[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() ) );
- insts.push_back( qe->getInstantiation( q, terms, true ) );
+ if( useActive ){
+ if( hasInstLemma() ){
+ Node lem = getInstLemma();
+ if( std::find( active.begin(), active.end(), lem )!=active.end() ){
+ insts.push_back( lem );
+ }
+ }
+ }else{
+ insts.push_back( qe->getInstantiation( q, terms, true ) );
+ }
}else{
for( std::map< Node, InstMatchTrie >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
terms.push_back( it->first );
- it->second.getInstantiations( insts, q, terms, qe );
+ it->second.getInstantiations( insts, q, terms, qe, useActive, active );
+ terms.pop_back();
+ }
+ }
+}
+
+void InstMatchTrie::getExplanationForInstLemmas( Node q, std::vector< Node >& terms, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const {
+ if( terms.size()==q[0].getNumChildren() ){
+ if( hasInstLemma() ){
+ Node lem = getInstLemma();
+ if( std::find( lems.begin(), lems.end(), lem )!=lems.end() ){
+ quant[lem] = q;
+ tvec[lem].clear();
+ tvec[lem].insert( tvec[lem].end(), terms.begin(), terms.end() );
+ }
+ }
+ }else{
+ for( std::map< Node, InstMatchTrie >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ terms.push_back( it->first );
+ it->second.getExplanationForInstLemmas( q, terms, lems, quant, tvec );
terms.pop_back();
}
}
@@ -301,8 +360,7 @@ bool CDInstMatchTrie::removeInstMatch( QuantifiersEngine* qe, Node q, std::vecto
return false;
}
}else{
- Node n = m[index];
- std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( n );
+ std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( m[index] );
if( it!=d_data.end() ){
return it->second->removeInstMatch( qe, q, m, index+1 );
}else{
@@ -311,34 +369,99 @@ bool CDInstMatchTrie::removeInstMatch( QuantifiersEngine* qe, Node q, std::vecto
}
}
-void CDInstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms ) const{
+bool CDInstMatchTrie::recordInstLemma( Node q, std::vector< Node >& m, Node lem, int index ) {
+ if( index==(int)q[0].getNumChildren() ){
+ if( d_valid.get() ){
+ setInstLemma( lem );
+ return true;
+ }else{
+ return false;
+ }
+ }else{
+ std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( m[index] );
+ if( it!=d_data.end() ){
+ return it->second->recordInstLemma( q, m, lem, index+1 );
+ }else{
+ return false;
+ }
+ }
+}
+
+void CDInstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms, bool& firstTime, bool useActive, std::vector< Node >& active ) const{
if( d_valid.get() ){
if( terms.size()==q[0].getNumChildren() ){
- out << " ( ";
- for( unsigned i=0; i<terms.size(); i++ ){
- if( i>0 ) out << ", ";
- out << terms[i];
+ bool print;
+ if( useActive ){
+ if( hasInstLemma() ){
+ Node lem = getInstLemma();
+ print = std::find( active.begin(), active.end(), lem )!=active.end();
+ }else{
+ print = false;
+ }
+ }else{
+ print = true;
+ }
+ if( print ){
+ if( firstTime ){
+ out << "(instantiation " << q << std::endl;
+ firstTime = false;
+ }
+ out << " ( ";
+ for( unsigned i=0; i<terms.size(); i++ ){
+ if( i>0 ) out << " ";
+ out << terms[i];
+ }
+ out << " )" << std::endl;
}
- out << " )" << std::endl;
}else{
for( std::map< Node, CDInstMatchTrie* >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
terms.push_back( it->first );
- it->second->print( out, q, terms );
+ it->second->print( out, q, terms, firstTime, useActive, active );
terms.pop_back();
}
}
}
}
-void CDInstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const{
+void CDInstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) const{
if( d_valid.get() ){
if( terms.size()==q[0].getNumChildren() ){
- //insts.push_back( q[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() ) );
- insts.push_back( qe->getInstantiation( q, terms, true ) );
+ if( useActive ){
+ if( hasInstLemma() ){
+ Node lem;
+ if( std::find( active.begin(), active.end(), lem )!=active.end() ){
+ insts.push_back( lem );
+ }
+ }
+ }else{
+ insts.push_back( qe->getInstantiation( q, terms, true ) );
+ }
+ }else{
+ for( std::map< Node, CDInstMatchTrie* >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ terms.push_back( it->first );
+ it->second->getInstantiations( insts, q, terms, qe, useActive, active );
+ terms.pop_back();
+ }
+ }
+ }
+}
+
+
+void CDInstMatchTrie::getExplanationForInstLemmas( Node q, std::vector< Node >& terms, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const {
+ if( d_valid.get() ){
+ if( terms.size()==q[0].getNumChildren() ){
+ if( hasInstLemma() ){
+ Node lem;
+ if( std::find( lems.begin(), lems.end(), lem )!=lems.end() ){
+ quant[lem] = q;
+ tvec[lem].clear();
+ tvec[lem].insert( tvec[lem].end(), terms.begin(), terms.end() );
+ }
+ }
}else{
for( std::map< Node, CDInstMatchTrie* >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){
terms.push_back( it->first );
- it->second->getInstantiations( insts, q, terms, qe );
+ it->second->getExplanationForInstLemmas( q, terms, lems, quant, tvec );
terms.pop_back();
}
}
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index ad287c1a3..68446922f 100755
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
@@ -96,12 +96,19 @@ public:
public:
std::vector< int > d_order;
};/* class InstMatchTrie ImtIndexOrder */
-
/** the data */
std::map< Node, InstMatchTrie > d_data;
private:
- void print( std::ostream& out, Node q, std::vector< TNode >& terms ) const;
- void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const;
+ void print( std::ostream& out, Node q, std::vector< TNode >& terms, bool& firstTime, bool useActive, std::vector< Node >& active ) const;
+ void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) const;
+ void getExplanationForInstLemmas( Node q, std::vector< Node >& terms, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const;
+private:
+ void setInstLemma( Node n ){
+ d_data.clear();
+ d_data[n].clear();
+ }
+ bool hasInstLemma() const { return !d_data.empty(); }
+ Node getInstLemma() const { return d_data.begin()->first; }
public:
InstMatchTrie(){}
~InstMatchTrie(){}
@@ -129,14 +136,19 @@ public:
bool addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, bool modEq = false,
ImtIndexOrder* imtio = NULL, bool onlyExist = false, int index = 0 );
bool removeInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, ImtIndexOrder* imtio = NULL, int index = 0 );
- void print( std::ostream& out, Node q ) const{
+ bool recordInstLemma( Node q, std::vector< Node >& m, Node lem, ImtIndexOrder* imtio = NULL, int index = 0 );
+ void print( std::ostream& out, Node q, bool& firstTime, bool useActive, std::vector< Node >& active ) const{
std::vector< TNode > terms;
- print( out, q, terms );
+ print( out, q, terms, firstTime, useActive, active );
}
- void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe ) {
+ void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) {
std::vector< Node > terms;
- getInstantiations( insts, q, terms, qe );
+ getInstantiations( insts, q, terms, qe, useActive, active );
}
+ void getExplanationForInstLemmas( Node q, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const {
+ std::vector< Node > terms;
+ getExplanationForInstLemmas( q, terms, lems, quant, tvec );
+ }
void clear() { d_data.clear(); }
};/* class InstMatchTrie */
@@ -147,9 +159,17 @@ private:
std::map< Node, CDInstMatchTrie* > d_data;
/** is valid */
context::CDO< bool > d_valid;
-
- void print( std::ostream& out, Node q, std::vector< TNode >& terms ) const;
- void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const;
+private:
+ void print( std::ostream& out, Node q, std::vector< TNode >& terms, bool& firstTime, bool useActive, std::vector< Node >& active ) const;
+ void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) const;
+ void getExplanationForInstLemmas( Node q, std::vector< Node >& terms, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const;
+private:
+ void setInstLemma( Node n ){
+ d_data.clear();
+ d_data[n] = NULL;
+ }
+ bool hasInstLemma() const { return !d_data.empty(); }
+ Node getInstLemma() const { return d_data.begin()->first; }
public:
CDInstMatchTrie( context::Context* c ) : d_valid( c, false ){}
~CDInstMatchTrie();
@@ -177,14 +197,19 @@ public:
bool addInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, context::Context* c, bool modEq = false,
int index = 0, bool onlyExist = false );
bool removeInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, int index = 0 );
- void print( std::ostream& out, Node q ) const{
+ bool recordInstLemma( Node q, std::vector< Node >& m, Node lem, int index = 0 );
+ void print( std::ostream& out, Node q, bool& firstTime, bool useActive, std::vector< Node >& active ) const{
std::vector< TNode > terms;
- print( out, q, terms );
+ print( out, q, terms, firstTime, useActive, active );
}
- void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe ) {
+ void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe, bool useActive, std::vector< Node >& active ) {
std::vector< Node > terms;
- getInstantiations( insts, q, terms, qe );
+ getInstantiations( insts, q, terms, qe, useActive, active );
}
+ void getExplanationForInstLemmas( Node q, std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) const {
+ std::vector< Node > terms;
+ getExplanationForInstLemmas( q, terms, lems, quant, tvec );
+ }
};/* class CDInstMatchTrie */
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index 2d3bf76f6..b3df9ca5d 100755
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -65,6 +65,24 @@ void InstMatchGenerator::setActiveAdd(bool val){
}
}
+int InstMatchGenerator::getActiveScore( QuantifiersEngine * qe ) {
+ if( Trigger::isAtomicTrigger( d_match_pattern ) ){
+ Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+ unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
+ Trace("trigger-active-sel-debug") << "Number of ground terms for " << f << " is " << ngt << std::endl;
+ return ngt;
+ }else if( d_match_pattern.getKind()==INST_CONSTANT ){
+ TypeNode tn = d_match_pattern.getType();
+ unsigned ngtt = qe->getTermDatabase()->getNumTypeGroundTerms( tn );
+ Trace("trigger-active-sel-debug") << "Number of ground terms for " << tn << " is " << ngtt << std::endl;
+ return ngtt;
+// }else if( d_match_pattern_getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
+
+ }else{
+ return -1;
+ }
+}
+
void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){
if( !d_pattern.isNull() ){
Trace("inst-match-gen") << "Initialize, pattern term is " << d_pattern << std::endl;
@@ -837,6 +855,14 @@ int InstMatchGeneratorSimple::addTerm( Node q, Node t, QuantifiersEngine* qe ){
return qe->addInstantiation( q, m ) ? 1 : 0;
}
+int InstMatchGeneratorSimple::getActiveScore( QuantifiersEngine * qe ) {
+ Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+ unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
+ Trace("trigger-active-sel-debug") << "Number of ground terms for (simple) " << f << " is " << ngt << std::endl;
+ return ngt;
+}
+
+
}/* CVC4::theory::inst namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index 096774c51..65c5a1427 100755
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -46,6 +46,8 @@ public:
virtual int addTerm( Node q, Node t, QuantifiersEngine* qe ) { return 0; }
/** set active add */
virtual void setActiveAdd( bool val ) {}
+ /** get active score */
+ virtual int getActiveScore( QuantifiersEngine * qe ) { return 0; }
};/* class IMGenerator */
class CandidateGenerator;
@@ -116,6 +118,7 @@ public:
bool d_active_add;
void setActiveAdd( bool val );
+ int getActiveScore( QuantifiersEngine * qe );
static InstMatchGenerator* mkInstMatchGenerator( Node q, Node pat, QuantifiersEngine* qe );
static InstMatchGenerator* mkInstMatchGenerator( Node q, std::vector< Node >& pats, QuantifiersEngine* qe );
@@ -239,6 +242,8 @@ public:
int addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe );
/** add ground term t, possibly add instantiations */
int addTerm( Node q, Node t, QuantifiersEngine* qe );
+ /** get active score */
+ int getActiveScore( QuantifiersEngine * qe );
};/* class InstMatchGeneratorSimple */
}
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index efd765c86..49e0a698f 100755
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -149,11 +149,7 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){
InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe ) : InstStrategy( qe ){
//how to select trigger terms
- if( options::triggerSelMode()==quantifiers::TRIGGER_SEL_DEFAULT ){
- d_tr_strategy = quantifiers::TRIGGER_SEL_MIN;
- }else{
- d_tr_strategy = options::triggerSelMode();
- }
+ d_tr_strategy = options::triggerSelMode();
//whether to select new triggers during the search
if( options::incrementTriggers() ){
d_regenerate_frequency = 3;
@@ -211,6 +207,29 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
// d_processed_trigger.clear();
// d_quantEngine->getEqualityQuery()->setLiberal( true );
//}
+ if( options::triggerActiveSelMode()!=TRIGGER_ACTIVE_SEL_ALL ){
+ int max_score = -1;
+ Trigger * max_trigger = NULL;
+ for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[0][f].begin(); itt != d_auto_gen_trigger[0][f].end(); ++itt ){
+ int score = itt->first->getActiveScore();
+ if( options::triggerActiveSelMode()==TRIGGER_ACTIVE_SEL_MIN ){
+ if( score>=0 && ( score<max_score || max_score<0 ) ){
+ max_score = score;
+ max_trigger = itt->first;
+ }
+ }else{
+ if( score>max_score ){
+ max_score = score;
+ max_trigger = itt->first;
+ }
+ }
+ d_auto_gen_trigger[0][f][itt->first] = false;
+ }
+ if( max_trigger!=NULL ){
+ d_auto_gen_trigger[0][f][max_trigger] = true;
+ }
+ }
+
bool hasInst = false;
for( unsigned r=0; r<2; r++ ){
for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[r][f].begin(); itt != d_auto_gen_trigger[r][f].end(); ++itt ){
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 10a5ae41b..7bbe06108 100755
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -45,7 +45,7 @@ bool QModelBuilder::isQuantifierActive( Node f ) {
bool QModelBuilder::optUseModel() {
- return options::mbqiMode()!=MBQI_NONE || options::fmfBoundInt();
+ return options::mbqiMode()!=MBQI_NONE || options::fmfBound();
}
void QModelBuilder::debugModel( FirstOrderModel* fm ){
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index 5d575969f..7658f2b6b 100755
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -121,7 +121,7 @@ void ModelEngine::registerQuantifier( Node f ){
if( !tn.isSort() ){
if( !tn.getCardinality().isFinite() ){
if( tn.isInteger() ){
- if( !options::fmfBoundInt() ){
+ if( !options::fmfBound() ){
canHandle = false;
}
}else{
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 68f824c57..963889a85 100755
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -85,48 +85,6 @@ bool QuantifiersRewriter::isCube( Node n ){
}
}
-int QuantifiersRewriter::getPurifyId( Node n ){
- if( !TermDb::hasBoundVarAttr( n ) ){
- return 0;
- }else if( inst::Trigger::isAtomicTriggerKind( n.getKind() ) ){
- return 1;
- }else if( TermDb::isBoolConnective( n.getKind() ) || n.getKind()==EQUAL || n.getKind()==BOUND_VARIABLE ){
- return 0;
- }else{
- return -1;
- }
-}
-
-int QuantifiersRewriter::getPurifyIdLit2( Node n, std::map< Node, int >& visited ) {
- std::map< Node, int >::iterator it = visited.find( n );
- if( visited.find( n )==visited.end() ){
- int ret = 0;
- if( TermDb::hasBoundVarAttr( n ) ){
- ret = getPurifyId( n );
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- int cid = getPurifyIdLit2( n[i], visited );
- if( cid!=0 ){
- if( ret==0 ){
- ret = cid;
- }else if( cid!=ret ){
- ret = -2;
- break;
- }
- }
- }
- }
- visited[n] = ret;
- return ret;
- }else{
- return it->second;
- }
-}
-
-int QuantifiersRewriter::getPurifyIdLit( Node n ) {
- std::map< Node, int > visited;
- return getPurifyIdLit2( n, visited );
-}
-
void QuantifiersRewriter::addNodeToOrBuilder( Node n, NodeBuilder<>& t ){
if( n.getKind()==OR ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
@@ -202,6 +160,9 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
children.push_back( body[1] );
+ if( body.getNumChildren()==3 ){
+ children.push_back( body[2] );
+ }
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
@@ -881,29 +842,53 @@ Node QuantifiersRewriter::computeCondSplit( Node body, QAttributes& qa ){
return body;
}
-bool QuantifiersRewriter::isVariableElim( Node v, Node s, std::map< Node, std::vector< int > >& var_parent ) {
+bool QuantifiersRewriter::isVariableElim( Node v, Node s ) {
if( TermDb::containsTerm( s, v ) || !s.getType().isSubtypeOf( v.getType() ) ){
return false;
}else{
- if( !var_parent.empty() ){
- std::map< Node, std::vector< int > >::iterator it = var_parent.find( v );
- if( it!=var_parent.end() ){
- Assert( !it->second.empty() );
- int id = getPurifyId( s );
- return it->second.size()==1 && it->second[0]==id;
+ return true;
+ }
+}
+
+void QuantifiersRewriter::isVariableBoundElig( Node n, std::map< Node, int >& exclude, std::map< Node, std::map< int, bool > >& visited, bool hasPol, bool pol,
+ std::map< Node, bool >& elig_vars ) {
+ int vindex = hasPol ? ( pol ? 1 : -1 ) : 0;
+ if( visited[n].find( vindex )==visited[n].end() ){
+ visited[n][vindex] = true;
+ if( elig_vars.find( n )!=elig_vars.end() ){
+ //variable contained in a place apart from bounds, no longer eligible for elimination
+ elig_vars.erase( n );
+ Trace("var-elim-ineq-debug") << "...found occurrence of " << n << ", mark ineligible" << std::endl;
+ }else{
+ if( hasPol ){
+ std::map< Node, int >::iterator itx = exclude.find( n );
+ if( itx!=exclude.end() && itx->second==vindex ){
+ //already processed this literal
+ return;
+ }
+ }
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, j, hasPol, pol, newHasPol, newPol );
+ isVariableBoundElig( n[j], exclude, visited, newHasPol, newPol, elig_vars );
+ if( elig_vars.empty() ){
+ break;
+ }
}
}
- return true;
+ }else{
+ //already visited
}
}
bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vector< Node >& args, std::vector< Node >& vars, std::vector< Node >& subs,
- std::map< Node, std::vector< int > >& var_parent ) {
- if( lit.getKind()==EQUAL && pol ){
+ std::map< Node, std::map< bool, std::map< Node, bool > > >& num_bounds ) {
+ if( lit.getKind()==EQUAL && pol && options::varElimQuant() ){
for( unsigned i=0; i<2; i++ ){
std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit[i] );
if( ita!=args.end() ){
- if( isVariableElim( lit[i], lit[1-i], var_parent ) ){
+ if( isVariableElim( lit[i], lit[1-i] ) ){
Trace("var-elim-quant") << "Variable eliminate based on equality : " << lit[i] << " -> " << lit[1-i] << std::endl;
vars.push_back( lit[i] );
subs.push_back( lit[1-i] );
@@ -912,28 +897,7 @@ bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vecto
}
}
}
- //for arithmetic, solve the equality
- if( lit[0].getType().isReal() ){
- std::map< Node, Node > msum;
- if( QuantArith::getMonomialSumLit( lit, msum ) ){
- for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
- std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), itm->first );
- if( ita!=args.end() ){
- Node veq_c;
- Node val;
- int ires = QuantArith::isolate( itm->first, msum, veq_c, val, EQUAL );
- if( ires!=0 && veq_c.isNull() && isVariableElim( itm->first, val, var_parent ) ){
- Trace("var-elim-quant") << "Variable eliminate based on solved equality : " << itm->first << " -> " << val << std::endl;
- vars.push_back( itm->first );
- subs.push_back( val );
- args.erase( ita );
- return true;
- }
- }
- }
- }
- }
- }else if( lit.getKind()==APPLY_TESTER && pol && lit[0].getKind()==BOUND_VARIABLE ){
+ }else if( lit.getKind()==APPLY_TESTER && pol && lit[0].getKind()==BOUND_VARIABLE && options::dtVarExpandQuant() ){
Trace("var-elim-dt") << "Expand datatype variable based on : " << lit << std::endl;
std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit[0] );
if( ita!=args.end() ){
@@ -957,7 +921,7 @@ bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vecto
args.insert( args.end(), newVars.begin(), newVars.end() );
return true;
}
- }else if( lit.getKind()==BOUND_VARIABLE ){
+ }else if( lit.getKind()==BOUND_VARIABLE && options::varElimQuant() ){
std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
if( ita!=args.end() ){
Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
@@ -967,24 +931,76 @@ bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vecto
return true;
}
}
+ if( ( lit.getKind()==EQUAL && lit[0].getType().isReal() && pol ) || ( ( lit.getKind()==GEQ || lit.getKind()==GT ) && options::varIneqElimQuant() ) ){
+ //for arithmetic, solve the (in)equality
+ std::map< Node, Node > msum;
+ if( QuantArith::getMonomialSumLit( lit, msum ) ){
+ for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
+ if( !itm->first.isNull() ){
+ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), itm->first );
+ if( ita!=args.end() ){
+ if( lit.getKind()==EQUAL ){
+ Assert( pol );
+ Node veq_c;
+ Node val;
+ int ires = QuantArith::isolate( itm->first, msum, veq_c, val, EQUAL );
+ if( ires!=0 && veq_c.isNull() && isVariableElim( itm->first, val ) ){
+ Trace("var-elim-quant") << "Variable eliminate based on solved equality : " << itm->first << " -> " << val << std::endl;
+ vars.push_back( itm->first );
+ subs.push_back( val );
+ args.erase( ita );
+ return true;
+ }
+ }else{
+ Assert( lit.getKind()==GEQ || lit.getKind()==GT );
+ //store that this literal is upper/lower bound for itm->first
+ Node veq_c;
+ Node val;
+ int ires = QuantArith::isolate( itm->first, msum, veq_c, val, lit.getKind() );
+ if( ires!=0 && veq_c.isNull() ){
+ bool is_upper = pol!=( ires==1 );
+ Trace("var-elim-ineq-debug") << lit << " is a " << ( is_upper ? "upper" : "lower" ) << " bound for " << itm->first << std::endl;
+ Trace("var-elim-ineq-debug") << " pol/ires = " << pol << " " << ires << std::endl;
+ num_bounds[itm->first][is_upper][lit] = pol;
+ }else{
+ Trace("var-elim-ineq-debug") << "...ineligible " << itm->first << " since it cannot be solved for (" << ires << ", " << veq_c << ")." << std::endl;
+ num_bounds[itm->first][true].clear();
+ num_bounds[itm->first][false].clear();
+ }
+ }
+ }else{
+ if( lit.getKind()==GEQ || lit.getKind()==GT ){
+ //compute variables in itm->first, these are not eligible for elimination
+ std::vector< Node > bvs;
+ TermDb::getBoundVars( itm->first, bvs );
+ for( unsigned j=0; j<bvs.size(); j++ ){
+ Trace("var-elim-ineq-debug") << "...ineligible " << bvs[j] << " since it is contained in monomial." << std::endl;
+ num_bounds[bvs[j]][true].clear();
+ num_bounds[bvs[j]][false].clear();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
return false;
}
-Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent ){
+Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa ){
Trace("var-elim-quant-debug") << "Compute var elimination for " << body << std::endl;
+ std::map< Node, std::map< bool, std::map< Node, bool > > > num_bounds;
QuantPhaseReq qpr( body );
std::vector< Node > vars;
std::vector< Node > subs;
for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){
- //Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl;
- if( ( it->first.getKind()==EQUAL && it->second && options::varElimQuant() ) ||
- ( it->first.getKind()==APPLY_TESTER && it->second && it->first[0].getKind()==BOUND_VARIABLE && options::dtVarExpandQuant() ) ||
- ( it->first.getKind()==BOUND_VARIABLE && options::varElimQuant() ) ){
- if( computeVariableElimLit( it->first, it->second, args, vars, subs, var_parent ) ){
- break;
- }
+ Trace("var-elim-quant-debug") << " phase req : " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl;
+ if( computeVariableElimLit( it->first, it->second, args, vars, subs, num_bounds ) ){
+ break;
}
}
+
if( !vars.empty() ){
Trace("var-elim-quant-debug") << "VE " << vars.size() << "/" << args.size() << std::endl;
//remake with eliminated nodes
@@ -994,21 +1010,65 @@ Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >
qa.d_ipl = qa.d_ipl.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
}
Trace("var-elim-quant") << "Return " << body << std::endl;
+ }else{
+ //collect all variables that have only upper/lower bounds
+ std::map< Node, bool > elig_vars;
+ for( std::map< Node, std::map< bool, std::map< Node, bool > > >::iterator it = num_bounds.begin(); it != num_bounds.end(); ++it ){
+ if( it->second.find( true )==it->second.end() ){
+ Trace("var-elim-ineq-debug") << "Variable " << it->first << " has only lower bounds." << std::endl;
+ elig_vars[it->first] = false;
+ }else if( it->second.find( false )==it->second.end() ){
+ Trace("var-elim-ineq-debug") << "Variable " << it->first << " has only upper bounds." << std::endl;
+ elig_vars[it->first] = true;
+ }
+ }
+ if( !elig_vars.empty() ){
+ std::vector< Node > inactive_vars;
+ std::map< Node, std::map< int, bool > > visited;
+ std::map< Node, int > exclude;
+ for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){
+ if( it->first.getKind()==GEQ || it->first.getKind()==GT ){
+ exclude[ it->first ] = it->second ? -1 : 1;
+ Trace("var-elim-ineq-debug") << "...exclude " << it->first << " at polarity " << exclude[ it->first ] << std::endl;
+ }
+ }
+ //traverse the body, invalidate variables if they occur in places other than the bounds they occur in
+ isVariableBoundElig( body, exclude, visited, true, true, elig_vars );
+
+ if( !elig_vars.empty() ){
+ if( !qa.d_ipl.isNull() ){
+ isVariableBoundElig( qa.d_ipl, exclude, visited, false, true, elig_vars );
+ }
+ for( std::map< Node, bool >::iterator itev = elig_vars.begin(); itev != elig_vars.end(); ++itev ){
+ Node v = itev->first;
+ Trace("var-elim-ineq-debug") << v << " is eligible for elimination." << std::endl;
+ //do substitution corresponding to infinite projection, all literals involving unbounded variable go to true/false
+ std::vector< Node > terms;
+ std::vector< Node > subs;
+ for( std::map< Node, bool >::iterator itb = num_bounds[v][elig_vars[v]].begin(); itb != num_bounds[v][elig_vars[v]].end(); ++itb ){
+ Trace("var-elim-ineq-debug") << " subs : " << itb->first << " -> " << itb->second << std::endl;
+ terms.push_back( itb->first );
+ subs.push_back( NodeManager::currentNM()->mkConst( itb->second ) );
+ }
+ body = body.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
+ Trace("var-elim-ineq-debug") << "Return " << body << std::endl;
+ //eliminate from args
+ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), v );
+ Assert( ita!=args.end() );
+ args.erase( ita );
+ }
+ }
+ }
}
return body;
}
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){
- //the parent id's for each variable, if using purifyQuant
- std::map< Node, std::vector< int > > var_parent;
- if( options::purifyQuant() ){
- body = computePurify( body, args, var_parent );
- }
if( options::varElimQuant() || options::dtVarExpandQuant() ){
Node prev;
do{
prev = body;
- body = computeVarElimination2( body, args, qa, var_parent );
+ body = computeVarElimination2( body, args, qa );
}while( prev!=body && !args.empty() );
}
return body;
@@ -1355,9 +1415,7 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q
}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_PURIFY_EXPAND ){
- return options::purifyQuant() && is_std;
+ return ( options::varElimQuant() || options::dtVarExpandQuant() ) && is_std;
}else{
return false;
}
@@ -1391,14 +1449,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_PURIFY_EXPAND ){
- std::vector< Node > conj;
- computePurifyExpand( n, conj, args, qa );
- if( !conj.empty() ){
- return conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj );
- }else{
- return f;
- }
}
Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
if( f[1]==n && args.size()==f[0].getNumChildren() ){
@@ -1630,104 +1680,3 @@ Node QuantifiersRewriter::preprocess( Node n, bool isInst ) {
return n;
}
-Node QuantifiersRewriter::computePurify2( Node body, std::vector< Node >& args, std::map< Node, Node >& visited, std::map< Node, Node >& var_to_term,
- std::map< Node, std::vector< int > >& var_parent, int parentId ){
- std::map< Node, Node >::iterator it = visited.find( body );
- if( it!=visited.end() ){
- return it->second;
- }else{
- Node ret = body;
- if( body.getNumChildren()>0 && body.getKind()!=FORALL && TermDb::hasBoundVarAttr( ret ) ){
- std::vector< Node > children;
- bool childrenChanged = false;
- int id = getPurifyId( body );
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- Node bi;
- if( body.getKind()==EQUAL && i==1 ){
- int cid = getPurifyId( children[0] );
- bi = computePurify2( body[i], args, visited, var_to_term, var_parent, cid );
- if( children[0].getKind()==BOUND_VARIABLE ){
- cid = getPurifyId( bi );
- if( cid!=0 && std::find( var_parent[children[0]].begin(), var_parent[children[0]].end(), cid )==var_parent[children[0]].end() ){
- var_parent[children[0]].push_back( id );
- }
- }
- }else{
- bi = computePurify2( body[i], args, visited, var_to_term, var_parent, id );
- }
- childrenChanged = childrenChanged || bi!=body[i];
- children.push_back( bi );
- if( id!=0 && bi.getKind()==BOUND_VARIABLE ){
- if( std::find( var_parent[bi].begin(), var_parent[bi].end(), id )==var_parent[bi].end() ){
- var_parent[bi].push_back( id );
- }
- }
- }
- if( childrenChanged ){
- if( body.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.insert( children.begin(), body.getOperator() );
- }
- ret = NodeManager::currentNM()->mkNode( body.getKind(), children );
- }
- if( parentId!=0 && parentId!=id ){
- Node v = NodeManager::currentNM()->mkBoundVar( ret.getType() );
- var_to_term[v] = Rewriter::rewrite( v.eqNode( ret ) );
- ret = v;
- args.push_back( v );
- }
- }
- visited[body] = ret;
- return ret;
- }
-}
-
-Node QuantifiersRewriter::computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent ) {
- std::map< Node, Node > visited;
- std::map< Node, Node > var_to_term;
- Node pbody = computePurify2( body, args, visited, var_to_term, var_parent, 0 );
- if( pbody==body ){
- return body;
- }else{
- Trace("quantifiers-rewrite-purify") << "Purify : " << body << std::endl;
- Trace("quantifiers-rewrite-purify") << " Got : " << pbody << std::endl;
- for( std::map< Node, Node >::iterator it = var_to_term.begin(); it != var_to_term.end(); ++it ){
- Trace("quantifiers-rewrite-purify") << " " << it->first << " : " << it->second << std::endl;
- }
- Trace("quantifiers-rewrite-purify") << "Variable parents : " << std::endl;
- for( std::map< Node, std::vector< int > >::iterator it = var_parent.begin(); it != var_parent.end(); ++it ){
- Trace("quantifiers-rewrite-purify") << " " << it->first << " -> ";
- for( unsigned i=0; i<it->second.size(); i++ ){
- Trace("quantifiers-rewrite-purify") << it->second[i] << " ";
- }
- Trace("quantifiers-rewrite-purify") << std::endl;
- }
- Trace("quantifiers-rewrite-purify") << std::endl;
- std::vector< Node > disj;
- for( std::map< Node, Node >::iterator it = var_to_term.begin(); it != var_to_term.end(); ++it ){
- disj.push_back( it->second.negate() );
- }
- Node res;
- if( disj.empty() ){
- res = pbody;
- }else{
- disj.push_back( pbody );
- res = NodeManager::currentNM()->mkNode( OR, disj );
- }
- Trace("quantifiers-rewrite-purify") << "Constructed : " << res << std::endl << std::endl;
- return res;
- }
-}
-
-void QuantifiersRewriter::computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa ) {
- if( body.getKind()==OR ){
- Trace("quantifiers-rewrite-purify-exp") << "Purify expansion : " << body << std::endl;
- std::map< int, std::vector< Node > > disj;
- std::map< int, std::vector< Node > > fvs;
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- int pid CVC4_UNUSED = getPurifyIdLit( body[i] );
- }
- //mark as an attribute
- //Node attr = NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, body );
- }
-}
-
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index 776517109..60dc8ab10 100755
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -35,8 +35,6 @@ public:
static bool isClause( Node n );
static bool isLiteral( Node n );
static bool isCube( Node n );
- 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 );
@@ -49,12 +47,12 @@ private:
std::vector< Node >& new_vars, std::vector< Node >& new_conds );
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 );
+ static bool isVariableElim( Node v, Node s );
+ static void isVariableBoundElig( Node n, std::map< Node, int >& exclude, std::map< Node, std::map< int, bool > >& visited, bool hasPol, bool pol,
+ std::map< Node, bool >& elig_vars );
static bool computeVariableElimLit( Node n, bool pol, std::vector< Node >& args, std::vector< Node >& var, std::vector< Node >& subs,
- std::map< Node, std::vector< int > >& var_parent );
- static Node computePurify2( Node body, std::vector< Node >& args, std::map< Node, Node >& visited, std::map< Node, Node >& var_to_term,
- std::map< Node, std::vector< int > >& var_parent, int parentId );
- static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent );
+ std::map< Node, std::map< bool, std::map< Node, bool > > >& num_bounds );
+ static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa );
private:
static Node computeElimSymbols( Node body );
static Node computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa );
@@ -65,8 +63,6 @@ private:
static Node computePrenex( Node body, std::vector< Node >& args, bool pol );
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 );
private:
enum{
COMPUTE_ELIM_SYMBOLS = 0,
@@ -76,7 +72,6 @@ private:
COMPUTE_PRENEX,
COMPUTE_VAR_ELIMINATION,
COMPUTE_COND_SPLIT,
- COMPUTE_PURIFY_EXPAND,
//COMPUTE_FLATTEN_ARGS_UF,
//COMPUTE_CNF,
COMPUTE_LAST
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index ee091919d..2faed3af0 100755
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -386,9 +386,9 @@ bool Trigger::isCbqiKind( Kind k ) {
bool Trigger::isSimpleTrigger( Node n ){
Node t = n.getKind()==NOT ? n[0] : n;
- if( n.getKind()==IFF || n.getKind()==EQUAL ){
- if( !quantifiers::TermDb::hasInstConstAttr( n[1] ) ){
- t = n[0];
+ if( t.getKind()==IFF || t.getKind()==EQUAL ){
+ if( !quantifiers::TermDb::hasInstConstAttr( t[1] ) ){
+ t = t[0];
}
}
if( isAtomicTrigger( t ) ){
@@ -742,6 +742,10 @@ InstMatchGenerator* Trigger::getInstMatchGenerator( Node q, Node n ) {
}
}
+int Trigger::getActiveScore() {
+ return d_mg->getActiveScore( d_quantEngine );
+}
+
Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){
if( nodes.empty() ){
return d_tr.empty() ? NULL : d_tr[0];
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index a3da4d398..6d7bf1f4d 100755
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -134,6 +134,7 @@ class Trigger {
}
Trace(c) << " )";
}
+ int getActiveScore();
private:
/** trigger constructor */
Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes );
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index d81efe1da..c08fee712 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -98,7 +98,7 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
//the model object
if( options::mbqiMode()==quantifiers::MBQI_FMC ||
- options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBoundInt() ||
+ options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBound() ||
options::mbqiMode()==quantifiers::MBQI_TRUST ){
d_model = new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc" );
}else if( options::mbqiMode()==quantifiers::MBQI_ABS ){
@@ -129,6 +129,8 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
d_fs = NULL;
d_rel_dom = NULL;
d_builder = NULL;
+
+ d_trackInstLemmas = options::proof() && options::trackInstLemmas();
d_total_inst_count_debug = 0;
//allow theory combination to go first, once initially
@@ -224,9 +226,14 @@ void QuantifiersEngine::finishInit(){
}
}
}
+ if( options::ceGuidedInst() ){
+ d_ceg_inst = new quantifiers::CegInstantiation( this, c );
+ d_modules.push_back( d_ceg_inst );
+ needsBuilder = true;
+ }
//finite model finding
if( options::finiteModelFind() ){
- if( options::fmfBoundInt() ){
+ if( options::fmfBound() ){
d_bint = new quantifiers::BoundedIntegers( c, this );
d_modules.push_back( d_bint );
}
@@ -238,11 +245,6 @@ void QuantifiersEngine::finishInit(){
d_rr_engine = new quantifiers::RewriteEngine( c, this );
d_modules.push_back(d_rr_engine);
}
- if( options::ceGuidedInst() ){
- d_ceg_inst = new quantifiers::CegInstantiation( this, c );
- d_modules.push_back( d_ceg_inst );
- needsBuilder = true;
- }
if( options::ltePartialInst() ){
d_lte_part_inst = new quantifiers::LtePartialInst( this, c );
d_modules.push_back( d_lte_part_inst );
@@ -280,9 +282,9 @@ void QuantifiersEngine::finishInit(){
}
if( needsBuilder ){
- Trace("quant-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
+ Trace("quant-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBound() << std::endl;
if( options::mbqiMode()==quantifiers::MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ||
- options::mbqiMode()==quantifiers::MBQI_TRUST || options::fmfBoundInt() ){
+ options::mbqiMode()==quantifiers::MBQI_TRUST || options::fmfBound() ){
Trace("quant-engine-debug") << "...make fmc builder." << std::endl;
d_builder = new quantifiers::fmcheck::FullModelChecker( c, this );
}else if( options::mbqiMode()==quantifiers::MBQI_ABS ){
@@ -719,7 +721,7 @@ void QuantifiersEngine::propagate( Theory::Effort level ){
}
Node QuantifiersEngine::getNextDecisionRequest(){
- for( int i=0; i<(int)d_modules.size(); i++ ){
+ for( unsigned i=0; i<d_modules.size(); i++ ){
Node n = d_modules[i]->getNextDecisionRequest();
if( !n.isNull() ){
return n;
@@ -1168,6 +1170,16 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
}
}
}
+ if( d_trackInstLemmas ){
+ bool recorded;
+ if( options::incrementalSolving() ){
+ recorded = d_c_inst_match_trie[q]->recordInstLemma( q, terms, lem );
+ }else{
+ recorded = d_inst_match_trie[q].recordInstLemma( q, terms, lem );
+ }
+ Trace("inst-add-debug") << "...was recorded : " << recorded << std::endl;
+ Assert( recorded );
+ }
Trace("inst-add-debug") << " --> Success." << std::endl;
++(d_statistics.d_instantiations);
return true;
@@ -1229,7 +1241,7 @@ bool QuantifiersEngine::getInstWhenNeedsCheck( Theory::Effort e ) {
if( e==Theory::EFFORT_LAST_CALL ){
//with bounded integers, skip every other last call,
// since matching loops may occur with infinite quantification
- if( d_ierCounter_lc%2==0 && options::fmfBoundInt() ){
+ if( d_ierCounter_lc%2==0 && options::fmfBound() ){
performCheck = false;
}
}
@@ -1273,36 +1285,106 @@ void QuantifiersEngine::flushLemmas(){
}
}
+bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas ) {
+ //only if unsat core available
+ bool isUnsatCoreAvailable = false;
+ if( options::proof() ){
+ isUnsatCoreAvailable = ProofManager::currentPM()->unsatCoreAvailable();
+ }
+ if( isUnsatCoreAvailable ){
+ Trace("inst-unsat-core") << "Get instantiations in unsat core..." << std::endl;
+ ProofManager::currentPM()->getLemmasInUnsatCore(theory::THEORY_QUANTIFIERS, active_lemmas);
+ if( Trace.isOn("inst-unsat-core") ){
+ Trace("inst-unsat-core") << "Quantifiers lemmas in unsat core: " << std::endl;
+ for (unsigned i = 0; i < active_lemmas.size(); ++i) {
+ Trace("inst-unsat-core") << " " << active_lemmas[i] << std::endl;
+ }
+ Trace("inst-unsat-core") << std::endl;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas, std::map< Node, Node >& weak_imp ) {
+ if( getUnsatCoreLemmas( active_lemmas ) ){
+ for (unsigned i = 0; i < active_lemmas.size(); ++i) {
+ Node n = ProofManager::currentPM()->getWeakestImplicantInUnsatCore(active_lemmas[i]);
+ if( n!=active_lemmas[i] ){
+ Trace("inst-unsat-core") << " weaken : " << active_lemmas[i] << " -> " << n << std::endl;
+ }
+ weak_imp[active_lemmas[i]] = n;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void QuantifiersEngine::getExplanationForInstLemmas( std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec ) {
+ if( d_trackInstLemmas ){
+ if( options::incrementalSolving() ){
+ for( std::map< Node, inst::CDInstMatchTrie* >::iterator it = d_c_inst_match_trie.begin(); it != d_c_inst_match_trie.end(); ++it ){
+ it->second->getExplanationForInstLemmas( it->first, lems, quant, tvec );
+ }
+ }else{
+ for( std::map< Node, inst::InstMatchTrie >::iterator it = d_inst_match_trie.begin(); it != d_inst_match_trie.end(); ++it ){
+ it->second.getExplanationForInstLemmas( it->first, lems, quant, tvec );
+ }
+ }
+#ifdef CVC4_ASSERTIONS
+ for( unsigned j=0; j<lems.size(); j++ ){
+ Assert( quant.find( lems[j] )!=quant.end() );
+ Assert( tvec.find( lems[j] )!=tvec.end() );
+ }
+#endif
+ }else{
+ Assert( false );
+ }
+}
+
void QuantifiersEngine::printInstantiations( std::ostream& out ) {
+ bool useUnsatCore = false;
+ std::vector< Node > active_lemmas;
+ if( d_trackInstLemmas && getUnsatCoreLemmas( active_lemmas ) ){
+ useUnsatCore = true;
+ }
+
bool printed = false;
for( BoolMap::iterator it = d_skolemized.begin(); it != d_skolemized.end(); ++it ){
Node q = (*it).first;
printed = true;
- out << "Skolem constants of " << q << " : " << std::endl;
+ out << "(skolem " << q << std::endl;
out << " ( ";
for( unsigned i=0; i<d_term_db->d_skolem_constants[q].size(); i++ ){
- if( i>0 ){ out << ", "; }
+ if( i>0 ){ out << " "; }
out << d_term_db->d_skolem_constants[q][i];
}
out << " )" << std::endl;
- out << std::endl;
+ out << ")" << std::endl;
}
if( options::incrementalSolving() ){
for( std::map< Node, inst::CDInstMatchTrie* >::iterator it = d_c_inst_match_trie.begin(); it != d_c_inst_match_trie.end(); ++it ){
- printed = true;
- out << "Instantiations of " << it->first << " : " << std::endl;
- it->second->print( out, it->first );
+ bool firstTime = true;
+ it->second->print( out, it->first, firstTime, useUnsatCore, active_lemmas );
+ if( !firstTime ){
+ out << ")" << std::endl;
+ }
+ printed = printed || !firstTime;
}
}else{
for( std::map< Node, inst::InstMatchTrie >::iterator it = d_inst_match_trie.begin(); it != d_inst_match_trie.end(); ++it ){
- printed = true;
- out << "Instantiations of " << it->first << " : " << std::endl;
- it->second.print( out, it->first );
- out << std::endl;
+ bool firstTime = true;
+ it->second.print( out, it->first, firstTime, useUnsatCore, active_lemmas );
+ if( !firstTime ){
+ out << ")" << std::endl;
+ }
+ printed = printed || !firstTime;
}
}
if( !printed ){
- out << "No instantiations." << std::endl;
+ out << "No instantiations" << std::endl;
}
}
@@ -1315,13 +1397,19 @@ void QuantifiersEngine::printSynthSolution( std::ostream& out ) {
}
void QuantifiersEngine::getInstantiations( std::map< Node, std::vector< Node > >& insts ) {
+ bool useUnsatCore = false;
+ std::vector< Node > active_lemmas;
+ if( d_trackInstLemmas && getUnsatCoreLemmas( active_lemmas ) ){
+ useUnsatCore = true;
+ }
+
if( options::incrementalSolving() ){
for( std::map< Node, inst::CDInstMatchTrie* >::iterator it = d_c_inst_match_trie.begin(); it != d_c_inst_match_trie.end(); ++it ){
- it->second->getInstantiations( insts[it->first], it->first, this );
+ it->second->getInstantiations( insts[it->first], it->first, this, useUnsatCore, active_lemmas );
}
}else{
for( std::map< Node, inst::InstMatchTrie >::iterator it = d_inst_match_trie.begin(); it != d_inst_match_trie.end(); ++it ){
- it->second.getInstantiations( insts[it->first], it->first, this );
+ it->second.getInstantiations( insts[it->first], it->first, this, useUnsatCore, active_lemmas );
}
}
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 1f4a04218..08ca0564b 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -143,6 +143,9 @@ private:
quantifiers::QuantAntiSkolem * d_anti_skolem;
/** quantifiers instantiation propagtor */
quantifiers::InstPropagator * d_inst_prop;
+private:
+ /** whether we are tracking instantiation lemmas */
+ bool d_trackInstLemmas;
public: //effort levels
enum {
QEFFORT_CONFLICT,
@@ -363,6 +366,11 @@ public:
void printSynthSolution( std::ostream& out );
/** get instantiations */
void getInstantiations( std::map< Node, std::vector< Node > >& insts );
+ /** get unsat core lemmas */
+ bool getUnsatCoreLemmas( std::vector< Node >& active_lemmas );
+ bool getUnsatCoreLemmas( std::vector< Node >& active_lemmas, std::map< Node, Node >& weak_imp );
+ /** get inst for lemmas */
+ void getExplanationForInstLemmas( std::vector< Node >& lems, std::map< Node, Node >& quant, std::map< Node, std::vector< Node > >& tvec );
/** statistics class */
class Statistics {
public:
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index 184553ba7..86bcb2cac 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -366,12 +366,12 @@ int RepSetIterator::resetIndex( int i, bool initial ) {
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];
}
+ Assert( srv.getKind()==kind::SINGLETON );
d_setm_bounds[v].push_back( srv[0] );
d_domain[v].push_back( d_setm_bounds[v].size() );
}else{
diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp
index 836a04afa..dcba4c379 100644
--- a/src/theory/sep/theory_sep.cpp
+++ b/src/theory/sep/theory_sep.cpp
@@ -93,6 +93,7 @@ Node TheorySep::ppRewrite(TNode term) {
//must process assertions at preprocess so that quantified assertions are processed properly
void TheorySep::processAssertions( std::vector< Node >& assertions ) {
+ d_pp_nils.clear();
std::map< Node, bool > visited;
for( unsigned i=0; i<assertions.size(); i++ ){
processAssertion( assertions[i], visited );
@@ -102,7 +103,11 @@ void TheorySep::processAssertions( std::vector< Node >& assertions ) {
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 ){
+ if( n.getKind()==kind::SEP_NIL ){
+ if( std::find( d_pp_nils.begin(), d_pp_nils.end(), n )==d_pp_nils.end() ){
+ d_pp_nils.push_back( n );
+ }
+ }else if( n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_EMP ){
//get the reference type (will compute d_type_references)
int card = 0;
TypeNode tn = getReferenceType( n, card );
@@ -170,7 +175,7 @@ void TheorySep::preRegisterTermRec(TNode t, std::map< TNode, bool >& visited ) {
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;
+ setNilRef( tn, t );
}else{
Node nr = it->second;
Trace("sep-prereg") << "...reference is " << nr << "." << std::endl;
@@ -271,32 +276,71 @@ void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel )
{
// Send the equality engine information to the model
m->assertEqualityEngine( &d_equalityEngine );
+
+}
+
+void TheorySep::postProcessModel(TheoryModel* m) {
+ Trace("sep-model") << "Printing model for TheorySep..." << std::endl;
- 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;
+ std::vector< Node > sep_children;
+ Node m_neq;
+ Node m_heap;
+ for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){
+ //should only be constructing for one heap type
+ Assert( m_heap.isNull() );
+ Assert( d_loc_to_data_type.find( it->first )!=d_loc_to_data_type.end() );
+ Trace("sep-model") << "Model for heap, type = " << it->first << " with data type " << d_loc_to_data_type[it->first] << " : " << std::endl;
+ TypeEnumerator te_range( d_loc_to_data_type[it->first] );
+ //m->d_comment_str << "Model for heap, type = " << it->first << " : " << std::endl;
+ computeLabelModel( it->second, d_tmodel );
+ if( d_label_model[it->second].d_heap_locs_model.empty() ){
+ Trace("sep-model") << " [empty]" << std::endl;
+ //m->d_comment_str << " [empty]" << std::endl;
+ }else{
+ for( unsigned j=0; j<d_label_model[it->second].d_heap_locs_model.size(); j++ ){
+ Assert( d_label_model[it->second].d_heap_locs_model[j].getKind()==kind::SINGLETON );
+ std::vector< Node > pto_children;
+ Node l = d_label_model[it->second].d_heap_locs_model[j][0];
+ Assert( l.isConst() );
+ pto_children.push_back( l );
+ Trace("sep-model") << " " << l << " -> ";
+ //m->d_comment_str << " " << l << " -> ";
+ if( d_pto_model[l].isNull() ){
+ Trace("sep-model") << "_";
+ //m->d_comment_str << "_";
+ pto_children.push_back( *te_range );
+ }else{
+ Trace("sep-model") << d_pto_model[l];
+ //m->d_comment_str << d_pto_model[l];
+ Node vpto = d_valuation.getModel()->getRepresentative( d_pto_model[l] );
+ Assert( vpto.isConst() );
+ pto_children.push_back( vpto );
}
+ Trace("sep-model") << std::endl;
+ //m->d_comment_str << std::endl;
+ sep_children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_PTO, pto_children ) );
}
- 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;
}
+ Node nil = getNilRef( it->first );
+ Node vnil = d_valuation.getModel()->getRepresentative( nil );
+ m_neq = NodeManager::currentNM()->mkNode( nil.getType().isBoolean() ? kind::IFF : kind::EQUAL, nil, vnil );
+ Trace("sep-model") << "sep.nil = " << vnil << std::endl;
+ Trace("sep-model") << std::endl;
+ //m->d_comment_str << "sep.nil = " << vnil << std::endl;
+ //m->d_comment_str << std::endl;
+ if( sep_children.empty() ){
+ TypeEnumerator te_domain( it->first );
+ m_heap = NodeManager::currentNM()->mkNode( kind::SEP_EMP, *te_domain );
+ }else if( sep_children.size()==1 ){
+ m_heap = sep_children[0];
+ }else{
+ m_heap = NodeManager::currentNM()->mkNode( kind::SEP_STAR, sep_children );
+ }
+ m->setHeapModel( m_heap, m_neq );
+ //m->d_comment_str << m->d_sep_heap << std::endl;
+ //m->d_comment_str << m->d_sep_nil_eq << std::endl;
}
+ Trace("sep-model") << "Finished printing model for TheorySep." << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
@@ -307,6 +351,13 @@ void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel )
void TheorySep::presolve() {
Trace("sep-pp") << "Presolving" << std::endl;
//TODO: cleanup if incremental?
+
+ //we must preregister all instances of sep.nil to ensure they are made equal
+ for( unsigned i=0; i<d_pp_nils.size(); i++ ){
+ std::map< TNode, bool > visited;
+ preRegisterTermRec( d_pp_nils[i], visited );
+ }
+ d_pp_nils.clear();
}
@@ -445,6 +496,11 @@ void TheorySep::check(Effort e) {
Node ilem = s.eqNode( empSet );
Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl;
c_lems.push_back( ilem );
+ //nil does not occur in labels[0]
+ Node nr = getNilRef( tn );
+ Node nrlem = NodeManager::currentNM()->mkNode( kind::MEMBER, nr, labels[0] ).negate();
+ Trace("sep-lemma") << "Sep::Lemma: sep.nil not in wand antecedant heap : " << nrlem << std::endl;
+ d_out->lemma( nrlem );
}
//send out definitional lemmas for introduced sets
for( unsigned j=0; j<c_lems.size(); j++ ){
@@ -458,8 +514,9 @@ void TheorySep::check(Effort e) {
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 );
+ //not needed anymore: semantics of sep.nil is enforced globally
+ //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 );
@@ -702,33 +759,19 @@ void TheorySep::check(Effort e) {
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 );
- }
- }
+ //new refinement
+ //instantiate the label
+ 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{
- //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 = Rewriter::rewrite( inst );
+ if( inst==( polarity ? d_true : d_false ) ){
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() );
}
+ conc.push_back( polarity ? inst : inst.negate() );
}
if( inst_success ){
std::vector< Node > lemc;
@@ -737,11 +780,12 @@ void TheorySep::check(Effort e) {
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() ){
+ 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;
@@ -773,6 +817,10 @@ void TheorySep::check(Effort e) {
}
+bool TheorySep::needsCheckLastEffort() {
+ return hasFacts();
+}
+
Node TheorySep::getNextDecisionRequest() {
for( unsigned i=0; i<d_neg_guards.size(); i++ ){
Node g = d_neg_guards[i];
@@ -897,6 +945,9 @@ TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n,
Trace("sep-type-debug") << "visit : " << n << " : " << atom << " " << index << std::endl;
visited[n] = -1;
if( n.getKind()==kind::SEP_PTO ){
+ //TODO: when THEORY_SETS supports mixed Int/Real sets
+ //TypeNode tn1 = n[0].getType().getBaseType();
+ //TypeNode tn2 = n[1].getType().getBaseType();
TypeNode tn1 = n[0].getType();
TypeNode tn2 = n[1].getType();
if( quantifiers::TermDb::hasBoundVarAttr( n[0] ) ){
@@ -908,6 +959,13 @@ TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n,
}
std::map< TypeNode, TypeNode >::iterator itt = d_loc_to_data_type.find( tn1 );
if( itt==d_loc_to_data_type.end() ){
+ if( !d_loc_to_data_type.empty() ){
+ TypeNode te1 = d_loc_to_data_type.begin()->first;
+ std::stringstream ss;
+ ss << "ERROR: specifying heap constraints for two different types : " << tn1 << " -> " << tn2 << " and " << te1 << " -> " << d_loc_to_data_type[te1] << std::endl;
+ throw LogicException(ss.str());
+ Assert( false );
+ }
Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl;
d_loc_to_data_type[tn1] = tn2;
}else{
@@ -984,7 +1042,7 @@ Node TheorySep::getBaseLabel( TypeNode tn ) {
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, "" );
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "base label" );
d_base_label[tn] = n_lbl;
//make reference bound
Trace("sep") << "Make reference bound label for " << tn << std::endl;
@@ -1021,6 +1079,13 @@ Node TheorySep::getBaseLabel( TypeNode tn ) {
//slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_base_label[tn], d_reference_bound_max[tn] );
//Trace("sep-lemma") << "Sep::Lemma: base reference bound for " << tn << " : " << slem << std::endl;
//d_out->lemma( slem );
+
+ //assert that nil ref is not in base label
+ Node nr = getNilRef( tn );
+ Node nrlem = NodeManager::currentNM()->mkNode( kind::MEMBER, nr, n_lbl ).negate();
+ Trace("sep-lemma") << "Sep::Lemma: sep.nil not in base label " << tn << " : " << nrlem << std::endl;
+ d_out->lemma( nrlem );
+
return n_lbl;
}else{
return it->second;
@@ -1031,13 +1096,18 @@ 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;
+ setNilRef( tn, nil );
return nil;
}else{
return it->second;
}
}
+void TheorySep::setNilRef( TypeNode tn, Node n ) {
+ Assert( n.getType()==tn );
+ d_nil_ref[tn] = n;
+}
+
Node TheorySep::mkUnion( TypeNode tn, std::vector< Node >& locs ) {
Node u;
if( locs.empty() ){
@@ -1067,7 +1137,7 @@ Node TheorySep::getLabel( Node atom, int child, Node lbl ) {
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, "" );
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "sep label" );
d_label_map[atom][lbl][child] = n_lbl;
d_label_map_parent[n_lbl] = lbl;
return n_lbl;
@@ -1149,11 +1219,40 @@ Node TheorySep::instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std:
return Node::null();
}
}
+ Node empSet = NodeManager::currentNM()->mkConst(EmptySet(rtn.toType()));
if( n.getKind()==kind::SEP_STAR ){
+ //disjoint contraints
+ Node vsu;
+ std::vector< Node > vs;
+ 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;
+ Node lbl_mval = d_label_model[sub_lbl].getValue( rtn );
+ for( unsigned j=0; j<vs.size(); j++ ){
+ children.push_back( NodeManager::currentNM()->mkNode( kind::INTERSECTION, lbl_mval, vs[j] ).eqNode( empSet ) );
+ }
+ vs.push_back( lbl_mval );
+ if( vsu.isNull() ){
+ vsu = lbl_mval;
+ }else{
+ vsu = NodeManager::currentNM()->mkNode( kind::UNION, vsu, lbl_mval );
+ }
+ }
+ children.push_back( vsu.eqNode( lbl ) );
+
+ //return the lemma
Assert( children.size()>1 );
return NodeManager::currentNM()->mkNode( kind::AND, children );
}else{
- return NodeManager::currentNM()->mkNode( kind::OR, children[0].negate(), children[1] );
+ std::vector< Node > wchildren;
+ //disjoint constraints
+ Node sub_lbl_0 = d_label_map[n][lbl][0];
+ Node lbl_mval_0 = d_label_model[sub_lbl_0].getValue( rtn );
+ wchildren.push_back( NodeManager::currentNM()->mkNode( kind::INTERSECTION, lbl_mval_0, lbl ).eqNode( empSet ).negate() );
+
+ //return the lemma
+ wchildren.push_back( children[0].negate() );
+ wchildren.push_back( children[1] );
+ return NodeManager::currentNM()->mkNode( kind::OR, wchildren );
}
}else{
//nested star/wand, label it and return
@@ -1266,8 +1365,12 @@ void TheorySep::computeLabelModel( Node lbl, std::map< Node, Node >& tmodel ) {
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 );
+ if( v_val.getKind()==kind::SINGLETON ){
+ d_label_model[lbl].d_heap_locs_model.push_back( v_val );
+ }else{
+ throw Exception("Could not establish value of heap in model.");
+ Assert( false );
+ }
}
//end hack
for( unsigned j=0; j<d_label_model[lbl].d_heap_locs_model.size(); j++ ){
diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h
index 852a36721..29e7a008c 100644
--- a/src/theory/sep/theory_sep.h
+++ b/src/theory/sep/theory_sep.h
@@ -50,6 +50,8 @@ class TheorySep : public Theory {
/** True node for predicates = false */
Node d_false;
+
+ std::vector< Node > d_pp_nils;
Node mkAnd( std::vector< TNode >& assumptions );
@@ -106,6 +108,7 @@ class TheorySep : public Theory {
public:
void collectModelInfo(TheoryModel* m, bool fullModel);
+ void postProcessModel(TheoryModel* m);
/////////////////////////////////////////////////////////////////////////////
// NOTIFICATIONS
@@ -126,6 +129,8 @@ class TheorySep : public Theory {
void check(Effort e);
+ bool needsCheckLastEffort();
+
private:
// NotifyClass: template helper class for d_equalityEngine - handles call-back from congruence closure module
@@ -243,6 +248,7 @@ class TheorySep : public Theory {
//get the base label for the spatial assertion
Node getBaseLabel( TypeNode tn );
Node getNilRef( TypeNode tn );
+ void setNilRef( TypeNode tn, Node n );
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 );
diff --git a/src/theory/sep/theory_sep_rewriter.cpp b/src/theory/sep/theory_sep_rewriter.cpp
index d58c2c13d..3e74bd61e 100644
--- a/src/theory/sep/theory_sep_rewriter.cpp
+++ b/src/theory/sep/theory_sep_rewriter.cpp
@@ -24,6 +24,7 @@ namespace sep {
void TheorySepRewriter::getStarChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children ){
Assert( n.getKind()==kind::SEP_STAR );
+ Node tr = NodeManager::currentNM()->mkConst( true );
for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( n[i].getKind()==kind::SEP_EMP ){
s_children.push_back( n[i] );
@@ -36,26 +37,19 @@ void TheorySepRewriter::getStarChildren( Node n, std::vector< Node >& 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( std::find( s_children.begin(), s_children.end(), tr )==s_children.end() ){
+ to_add = tr;
}
+ }else if( temp_s_children.size()==1 ){
+ to_add = temp_s_children[0];
+ }else{
+ to_add = NodeManager::currentNM()->mkNode( kind::AND, temp_s_children );
}
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() ){
+ }else if( to_add.getKind()!=kind::SEP_EMP || s_children.empty() ){ //remove sep emp
s_children.push_back( to_add );
}
}
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 57344236e..7caa1cbb1 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -37,7 +37,7 @@ namespace CVC4 {
namespace theory {
namespace strings {
-Node TheoryStrings::TermIndex::add( Node n, unsigned index, TheoryStrings* t, Node er, std::vector< Node >& c ) {
+Node TheoryStrings::TermIndex::add( TNode n, unsigned index, TheoryStrings* t, Node er, std::vector< Node >& c ) {
if( index==n.getNumChildren() ){
if( d_data.isNull() ){
d_data = n;
@@ -45,7 +45,7 @@ Node TheoryStrings::TermIndex::add( Node n, unsigned index, TheoryStrings* t, No
return d_data;
}else{
Assert( index<n.getNumChildren() );
- Node nir = t->getRepresentative( n[index] );
+ TNode nir = t->getRepresentative( n[index] );
//if it is empty, and doing CONCAT, ignore
if( nir==er && n.getKind()==kind::STRING_CONCAT ){
return add( n, index+1, t, er, c );
@@ -69,21 +69,20 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
d_infer_exp(c),
d_nf_pairs(c),
d_loop_antec(u),
- d_length_intro_vars(u),
d_pregistered_terms_cache(u),
d_registered_terms_cache(u),
+ d_length_lemma_terms_cache(u),
+ d_skolem_ne_reg_cache(u),
d_preproc(u),
d_preproc_cache(u),
d_extf_infer_cache(c),
+ d_extf_infer_cache_u(u),
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),
- d_ext_func_terms(c),
+ d_has_extf(c, false ),
d_regexp_memberships(c),
d_regexp_ucached(u),
d_regexp_ccached(c),
@@ -98,15 +97,28 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
d_cardinality_lits(u),
d_curr_cardinality(c, 0)
{
+ d_extt = new ExtTheory( this );
+ d_extt->addFunctionKind( kind::STRING_SUBSTR );
+ d_extt->addFunctionKind( kind::STRING_STRIDOF );
+ d_extt->addFunctionKind( kind::STRING_ITOS );
+ d_extt->addFunctionKind( kind::STRING_U16TOS );
+ d_extt->addFunctionKind( kind::STRING_U32TOS );
+ d_extt->addFunctionKind( kind::STRING_STOI );
+ d_extt->addFunctionKind( kind::STRING_STOU16 );
+ d_extt->addFunctionKind( kind::STRING_STOU32 );
+ d_extt->addFunctionKind( kind::STRING_STRREPL );
+ d_extt->addFunctionKind( kind::STRING_STRCTN );
+ d_extt->addFunctionKind( kind::STRING_IN_REGEXP );
+
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
- d_equalityEngine.addFunctionKind(kind::STRING_STRCTN);
- d_equalityEngine.addFunctionKind(kind::STRING_SUBSTR);
- d_equalityEngine.addFunctionKind(kind::STRING_ITOS);
- d_equalityEngine.addFunctionKind(kind::STRING_STOI);
if( options::stringLazyPreproc() ){
+ d_equalityEngine.addFunctionKind(kind::STRING_STRCTN);
+ d_equalityEngine.addFunctionKind(kind::STRING_SUBSTR);
+ d_equalityEngine.addFunctionKind(kind::STRING_ITOS);
+ d_equalityEngine.addFunctionKind(kind::STRING_STOI);
d_equalityEngine.addFunctionKind(kind::STRING_U16TOS);
d_equalityEngine.addFunctionKind(kind::STRING_STOU16);
d_equalityEngine.addFunctionKind(kind::STRING_U32TOS);
@@ -130,6 +142,7 @@ TheoryStrings::~TheoryStrings() {
for( std::map< Node, EqcInfo* >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){
delete it->second;
}
+ delete d_extt;
}
Node TheoryStrings::getRepresentative( Node t ) {
@@ -157,28 +170,16 @@ bool TheoryStrings::areEqual( Node a, Node b ){
bool TheoryStrings::areDisequal( Node a, Node b ){
if( a==b ){
return false;
- } else {
- if( a.getType().isString() ) {
- for( unsigned i=0; i<2; i++ ) {
- Node ac = a.getKind()==kind::STRING_CONCAT ? a[i==0 ? 0 : a.getNumChildren()-1] : a;
- Node bc = b.getKind()==kind::STRING_CONCAT ? b[i==0 ? 0 : b.getNumChildren()-1] : b;
- if( ac.isConst() && bc.isConst() ){
- CVC4::String as = ac.getConst<String>();
- CVC4::String bs = bc.getConst<String>();
- int slen = as.size() > bs.size() ? bs.size() : as.size();
- bool flag = i == 1 ? as.rstrncmp(bs, slen): as.strncmp(bs, slen);
- if(!flag) {
- return true;
- }
- }
- }
- }
+ }else{
if( hasTerm( a ) && hasTerm( b ) ) {
- if( d_equalityEngine.areDisequal( a, b, false ) ){
- return true;
- }
+ Node ar = d_equalityEngine.getRepresentative( a );
+ Node br = d_equalityEngine.getRepresentative( b );
+ return ( ar!=br && ar.isConst() && br.isConst() ) || d_equalityEngine.areDisequal( ar, br, false );
+ }else{
+ Node ar = getRepresentative( a );
+ Node br = getRepresentative( b );
+ return ar!=br && ar.isConst() && br.isConst();
}
- return false;
}
}
@@ -286,6 +287,50 @@ Node TheoryStrings::explain( TNode literal ){
}
}
+bool TheoryStrings::getCurrentSubstitution( int effort, std::vector< Node >& vars,
+ std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
+ Trace("strings-subs") << "getCurrentSubstitution, effort = " << effort << std::endl;
+ for( unsigned i=0; i<vars.size(); i++ ){
+ Node n = vars[i];
+ Trace("strings-subs") << " get subs for " << n << "..." << std::endl;
+ if( effort>=3 ){
+ //model values
+ Node mv = d_valuation.getModel()->getRepresentative( n );
+ Trace("strings-subs") << " model val : " << mv << std::endl;
+ subs.push_back( mv );
+ }else{
+ Node nr = getRepresentative( n );
+ std::map< Node, Node >::iterator itc = d_eqc_to_const.find( nr );
+ if( itc!=d_eqc_to_const.end() ){
+ //constant equivalence classes
+ Trace("strings-subs") << " constant eqc : " << d_eqc_to_const_exp[nr] << " " << d_eqc_to_const_base[nr] << " " << nr << std::endl;
+ subs.push_back( itc->second );
+ if( !d_eqc_to_const_exp[nr].isNull() ){
+ exp[n].push_back( d_eqc_to_const_exp[nr] );
+ }
+ if( !d_eqc_to_const_base[nr].isNull() ){
+ addToExplanation( n, d_eqc_to_const_base[nr], exp[n] );
+ }
+ }else if( effort>=1 && effort<3 && n.getType().isString() ){
+ //normal forms
+ Node ns = getNormalString( d_normal_forms_base[nr], exp[n] );
+ subs.push_back( ns );
+ Trace("strings-subs") << " normal eqc : " << ns << " " << d_normal_forms_base[nr] << " " << nr << std::endl;
+ if( !d_normal_forms_base[nr].isNull() ) {
+ addToExplanation( n, d_normal_forms_base[nr], exp[n] );
+ }
+ }else{
+ //representative?
+ //Trace("strings-subs") << " representative : " << nr << std::endl;
+ //addToExplanation( n, nr, exp[n] );
+ //subs.push_back( nr );
+ subs.push_back( n );
+ }
+ }
+ }
+ return true;
+}
+
/////////////////////////////////////////////////////////////////////////////
// NOTIFICATIONS
/////////////////////////////////////////////////////////////////////////////
@@ -509,7 +554,7 @@ Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
void TheoryStrings::check(Effort e) {
- if (done() && !fullEffort(e)) {
+ if (done() && e<EFFORT_FULL) {
return;
}
@@ -528,7 +573,7 @@ void TheoryStrings::check(Effort e) {
preRegisterTerm( d_emptyString );
}
- // Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
+ // Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
Trace("strings-check") << "Theory of strings, check : " << e << std::endl;
while ( !done() && !d_conflict ) {
// Get all the assertions
@@ -539,11 +584,6 @@ void TheoryStrings::check(Effort e) {
polarity = fact.getKind() != kind::NOT;
atom = polarity ? fact : fact[0];
- //run preprocess on memberships
- if( options::stringLazyPreproc() ){
- checkReduction( atom, polarity ? 1 : -1, 0 );
- doPendingLemmas();
- }
//assert pending fact
assertPendingFact( atom, polarity, fact );
}
@@ -590,7 +630,7 @@ void TheoryStrings::check(Effort e) {
checkInit();
Trace("strings-process") << "Done check init, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
if( !hasProcessed() ){
- checkExtendedFuncsEval();
+ checkExtfEval();
Trace("strings-process") << "Done check extended functions eval, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
if( !hasProcessed() ){
checkFlatForms();
@@ -604,11 +644,17 @@ void TheoryStrings::check(Effort e) {
Trace("strings-process") << "Done check lengths, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
}
if( !hasProcessed() ){
- checkExtendedFuncs();
- Trace("strings-process") << "Done check extended functions, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
+ if( options::stringExp() && !options::stringGuessModel() ){
+ checkExtfReductions( 2 );
+ Trace("strings-process") << "Done check extended functions reduction 2, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
+ }
if( !hasProcessed() ){
- checkCardinality();
- Trace("strings-process") << "Done check cardinality, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
+ checkMemberships();
+ Trace("strings-process") << "Done check memberships, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
+ if( !hasProcessed() ){
+ checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
+ }
}
}
}
@@ -623,19 +669,38 @@ void TheoryStrings::check(Effort e) {
}while( !d_conflict && !addedLemma && addedFact );
Trace("strings-check") << "Theory of strings done full effort check " << addedLemma << " " << d_conflict << std::endl;
+ }else if( e==EFFORT_LAST_CALL ){
+ Assert( !hasProcessed() );
+ Trace("strings-check") << "Theory of strings last call effort check " << std::endl;
+ checkExtfEval( 3 );
+ checkExtfReductions( 2 );
+ doPendingFacts();
+ doPendingLemmas();
+ Trace("strings-process") << "Done check extended functions reduction 2, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
Assert( d_pending.empty() );
Assert( d_lemma_cache.empty() );
}
-void TheoryStrings::checkExtfReduction( int effort ) {
- Trace("strings-process-debug") << "Checking preprocess at effort " << effort << ", #to process=" << d_ext_func_terms.size() << "..." << std::endl;
- for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
- Trace("strings-process-debug2") << (*it).first << ", active=" << !(*it).second << std::endl;
- if( (*it).second ){
- Node n = (*it).first;
- checkReduction( n, d_extf_pol[n], effort );
+bool TheoryStrings::needsCheckLastEffort() {
+ if( options::stringGuessModel() ){
+ return d_has_extf.get();
+ }else{
+ return false;
+ }
+}
+
+void TheoryStrings::checkExtfReductions( int effort ) {
+ std::vector< Node > extf;
+ d_extt->getActive( extf );
+ for( unsigned i=0; i<extf.size(); i++ ){
+ Node n = extf[i];
+ if( d_extf_info_tmp[n].d_model_active ){
+ Assert( d_extf_info_tmp.find( n )!=d_extf_info_tmp.end() );
+ if( checkExtfReduction( n, d_extf_info_tmp[n].d_pol, effort ) ){
+ d_extt->markReduced( n );
+ }
if( hasProcessed() ){
return;
}
@@ -643,65 +708,85 @@ void TheoryStrings::checkExtfReduction( int effort ) {
}
}
-void TheoryStrings::checkReduction( Node atom, int pol, int effort ) {
+bool TheoryStrings::checkExtfReduction( Node atom, int pol, int effort ) {
//determine the effort level to process the extf at
// 0 - at assertion time, 1+ - after no other reduction is applicable
int r_effort = -1;
- if( atom.getKind()==kind::STRING_IN_REGEXP ){
- if( pol==1 && atom[1].getKind()==kind::REGEXP_RANGE ){
- r_effort = 0;
- }
- }else if( atom.getKind()==kind::STRING_STRCTN ){
+ if( atom.getKind()==kind::STRING_STRCTN ){
if( pol==1 ){
r_effort = 1;
+ }else{
+ Assert( pol==-1 );
+ if( effort==2 ){
+ Node x = atom[0];
+ Node s = atom[1];
+ std::vector< Node > lexp;
+ Node lenx = getLength( x, lexp );
+ Node lens = getLength( s, lexp );
+ if( areEqual( lenx, lens ) ){
+ Trace("strings-extf-debug") << " resolve extf : " << atom << " based on equal lengths disequality." << std::endl;
+ //we can reduce to disequality when lengths are equal
+ if( !areDisequal( x, s ) ){
+ lexp.push_back( lenx.eqNode(lens) );
+ lexp.push_back( atom.negate() );
+ Node xneqs = x.eqNode(s).negate();
+ sendInference( lexp, xneqs, "NEG-CTN-EQL", true );
+ }
+ return true;
+ }else if( !areDisequal( lenx, lens ) ){
+ //split on their lenths
+ sendSplit( lenx, lens, "NEG-CTN-SP" );
+ }else{
+ r_effort = 2;
+ }
+ }
}
}else{
if( options::stringLazyPreproc() ){
if( atom.getKind()==kind::STRING_SUBSTR ){
- r_effort = options::stringLazyPreproc2() ? 1 : 0;
- }else{
- r_effort = options::stringLazyPreproc2() ? 2 : 0;
+ r_effort = 1;
+ }else if( atom.getKind()!=kind::STRING_IN_REGEXP ){
+ r_effort = 2;
}
}
}
if( effort==r_effort ){
- if( d_preproc_cache.find( atom )==d_preproc_cache.end() ){
- d_preproc_cache[ atom ] = true;
- Trace("strings-process-debug") << "Process reduction for " << atom << std::endl;
- if( atom.getKind()==kind::STRING_IN_REGEXP ){
- if( atom[1].getKind()==kind::REGEXP_RANGE ){
- Node eq = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, atom[0]));
- std::vector< Node > exp_vec;
- exp_vec.push_back( atom );
- sendInference( d_empty_vec, exp_vec, eq, "RE-Range-Len", true );
- }
- }else if( atom.getKind()==kind::STRING_STRCTN ){
+ Node c_atom = pol==-1 ? atom.negate() : atom;
+ if( d_preproc_cache.find( c_atom )==d_preproc_cache.end() ){
+ d_preproc_cache[ c_atom ] = true;
+ Trace("strings-process-debug") << "Process reduction for " << atom << ", pol = " << pol << std::endl;
+ if( atom.getKind()==kind::STRING_STRCTN && pol==1 ){
Node x = atom[0];
Node s = atom[1];
- //would have already reduced by now
- Assert( !areEqual( s, d_emptyString ) && !areEqual( s, x ) );
+ //positive contains reduces to a equality
Node sk1 = mkSkolemCached( x, s, sk_id_ctn_pre, "sc1" );
Node sk2 = mkSkolemCached( x, s, sk_id_ctn_post, "sc2" );
Node eq = Rewriter::rewrite( x.eqNode( mkConcat( sk1, s, sk2 ) ) );
std::vector< Node > exp_vec;
exp_vec.push_back( atom );
sendInference( d_empty_vec, exp_vec, eq, "POS-CTN", true );
+ //we've reduced this atom
+ Trace("strings-extf-debug") << " resolve extf : " << atom << " based on positive contain reduction." << std::endl;
+ return true;
}else{
- // for STRING_SUBSTR,
+ // for STRING_SUBSTR, STRING_STRCTN with pol=-1,
// STRING_STRIDOF, STRING_ITOS, STRING_U16TOS, STRING_U32TOS, STRING_STOI, STRING_STOU16, STRING_STOU32, STRING_STRREPL
std::vector< Node > new_nodes;
- Node res = d_preproc.decompose( atom, new_nodes );
- Assert( res==atom );
- if( !new_nodes.empty() ){
- Node nnlem = new_nodes.size()==1 ? new_nodes[0] : NodeManager::currentNM()->mkNode( kind::AND, new_nodes );
- nnlem = Rewriter::rewrite( nnlem );
- Trace("strings-red-lemma") << "Reduction_" << effort << " lemma : " << nnlem << std::endl;
- Trace("strings-red-lemma") << "...from " << atom << std::endl;
- sendInference( d_empty_vec, nnlem, "Reduction", true );
- }
+ Node res = d_preproc.simplify( atom, new_nodes );
+ Assert( res!=atom );
+ new_nodes.push_back( NodeManager::currentNM()->mkNode( res.getType().isBoolean() ? kind::IFF : kind::EQUAL, res, atom ) );
+ Node nnlem = new_nodes.size()==1 ? new_nodes[0] : NodeManager::currentNM()->mkNode( kind::AND, new_nodes );
+ nnlem = Rewriter::rewrite( nnlem );
+ Trace("strings-red-lemma") << "Reduction_" << effort << " lemma : " << nnlem << std::endl;
+ Trace("strings-red-lemma") << "...from " << atom << std::endl;
+ sendInference( d_empty_vec, nnlem, "Reduction", true );
+ //we've reduced this atom
+ Trace("strings-extf-debug") << " resolve extf : " << atom << " based on reduction." << std::endl;
+ return true;
}
}
}
+ return false;
}
TheoryStrings::EqcInfo::EqcInfo( context::Context* c ) : d_const_term(c), d_length_term(c), d_cardinality_lem_k(c), d_normalized_length(c) {
@@ -900,13 +985,21 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
d_equalityEngine.assertEquality( atom, polarity, exp );
Trace("strings-pending-debug") << " Finished assert equality" << std::endl;
} else {
- if( atom.getKind()==kind::STRING_IN_REGEXP ) {
- if( d_ext_func_terms.find( atom )==d_ext_func_terms.end() ){
- Trace("strings-extf-debug") << "Found extended function (membership) : " << atom << std::endl;
- d_ext_func_terms[atom] = true;
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ //process extf
+ if( atom.getKind()==kind::STRING_IN_REGEXP ){
+ d_extt->registerTerm( atom );
+ if( polarity && atom[1].getKind()==kind::REGEXP_RANGE ){
+ if( d_extf_infer_cache_u.find( atom )==d_extf_infer_cache_u.end() ){
+ d_extf_infer_cache_u.insert( atom );
+ //length of first argument is one
+ Node conc = d_one.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, atom[0] ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, atom.negate(), conc );
+ Trace("strings-lemma") << "Strings::Lemma RE-Range-Len : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
}
}
- d_equalityEngine.assertPredicate( atom, polarity, exp );
}
Trace("strings-pending-debug") << " Now collect terms" << std::endl;
//collect extended function terms in the atom
@@ -994,15 +1087,15 @@ void TheoryStrings::checkInit() {
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
while( !eqc_i.isFinished() ) {
Node n = *eqc_i;
- if( tn.isInteger() ){
+ if( n.isConst() ){
+ d_eqc_to_const[eqc] = n;
+ d_eqc_to_const_base[eqc] = n;
+ d_eqc_to_const_exp[eqc] = Node::null();
+ }else if( tn.isInteger() ){
if( n.getKind()==kind::STRING_LENGTH ){
Node nr = getRepresentative( n[0] );
d_eqc_to_len_term[nr] = n[0];
}
- }else if( n.isConst() ){
- d_eqc_to_const[eqc] = n;
- d_eqc_to_const_base[eqc] = n;
- d_eqc_to_const_exp[eqc] = Node::null();
}else if( n.getNumChildren()>0 ){
Kind k = n.getKind();
if( k!=kind::EQUAL ){
@@ -1039,16 +1132,8 @@ void TheoryStrings::checkInit() {
//infer the equality
sendInference( exp, n.eqNode( nc ), "I_Norm" );
}else{
- //update the extf map : only process if neither has been reduced
- NodeBoolMap::const_iterator it = d_ext_func_terms.find( n );
- if( it!=d_ext_func_terms.end() ){
- if( d_ext_func_terms.find( nc )==d_ext_func_terms.end() ){
- d_ext_func_terms[nc] = (*it).second;
- }else{
- d_ext_func_terms[nc] = d_ext_func_terms[nc] && (*it).second;
- }
- d_ext_func_terms[n] = false;
- }
+ //mark as congruent : only process if neither has been reduced
+ d_extt->markCongruent( nc, n );
}
//this node is congruent to another one, we can ignore it
Trace("strings-process-debug") << " congruent term : " << n << std::endl;
@@ -1122,77 +1207,121 @@ void TheoryStrings::checkInit() {
}
}
-void TheoryStrings::checkExtendedFuncsEval( int effort ) {
- Trace("strings-extf-list") << "Active extended functions, effort=" << effort << " : " << std::endl;
- if( effort==0 ){
- d_extf_vars.clear();
- }
- d_extf_pol.clear();
- d_extf_exp.clear();
- d_extf_info.clear();
- Trace("strings-extf-debug") << "Checking " << d_ext_func_terms.size() << " extended functions." << std::endl;
- for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
- if( (*it).second ){
- Node n = (*it).first;
- d_extf_pol[n] = 0;
- if( n.getType().isBoolean() ){
- if( areEqual( n, d_true ) ){
- d_extf_pol[n] = 1;
- }else if( areEqual( n, d_false ) ){
- d_extf_pol[n] = -1;
- }
- }
- Trace("strings-extf-debug") << "Check extf " << n << ", pol = " << d_extf_pol[n] << "..." << std::endl;
- if( effort==0 ){
- std::map< Node, bool > visited;
- collectVars( n, d_extf_vars[n], visited );
+void TheoryStrings::checkConstantEquivalenceClasses( TermIndex* ti, std::vector< Node >& vecc ) {
+ Node n = ti->d_data;
+ if( !n.isNull() ){
+ //construct the constant
+ Node c = mkConcat( vecc );
+ if( !areEqual( n, c ) ){
+ Trace("strings-debug") << "Constant eqc : " << c << " for " << n << std::endl;
+ Trace("strings-debug") << " ";
+ for( unsigned i=0; i<vecc.size(); i++ ){
+ Trace("strings-debug") << vecc[i] << " ";
}
- //build up a best current substitution for the variables in the term, exp is explanation for substitution
- std::vector< Node > var;
- std::vector< Node > sub;
- for( std::map< Node, std::vector< Node > >::iterator itv = d_extf_vars[n].begin(); itv != d_extf_vars[n].end(); ++itv ){
- Node nr = itv->first;
- std::map< Node, Node >::iterator itc = d_eqc_to_const.find( nr );
- Node s;
- Node b;
- Node e;
- if( itc!=d_eqc_to_const.end() ){
- b = d_eqc_to_const_base[nr];
- s = itc->second;
- e = d_eqc_to_const_exp[nr];
- }else if( effort>0 ){
- b = d_normal_forms_base[nr];
- std::vector< Node > expt;
- s = getNormalString( b, expt );
- e = mkAnd( expt );
+ Trace("strings-debug") << std::endl;
+ unsigned count = 0;
+ unsigned countc = 0;
+ std::vector< Node > exp;
+ while( count<n.getNumChildren() ){
+ while( count<n.getNumChildren() && areEqual( n[count], d_emptyString ) ){
+ addToExplanation( n[count], d_emptyString, exp );
+ count++;
}
- if( !s.isNull() ){
- bool added = false;
- for( unsigned i=0; i<itv->second.size(); i++ ){
- if( itv->second[i]!=s ){
- var.push_back( itv->second[i] );
- sub.push_back( s );
- addToExplanation( itv->second[i], b, d_extf_exp[n] );
- Trace("strings-extf-debug") << " " << itv->second[i] << " --> " << s << std::endl;
- added = true;
- }
+ if( count<n.getNumChildren() ){
+ Trace("strings-debug") << "...explain " << n[count] << " " << vecc[countc] << std::endl;
+ if( !areEqual( n[count], vecc[countc] ) ){
+ Node nrr = getRepresentative( n[count] );
+ Assert( !d_eqc_to_const_exp[nrr].isNull() );
+ addToExplanation( n[count], d_eqc_to_const_base[nrr], exp );
+ exp.push_back( d_eqc_to_const_exp[nrr] );
+ }else{
+ addToExplanation( n[count], vecc[countc], exp );
}
- if( added ){
- addToExplanation( e, d_extf_exp[n] );
+ countc++;
+ count++;
+ }
+ }
+ //exp contains an explanation of n==c
+ Assert( countc==vecc.size() );
+ if( hasTerm( c ) ){
+ sendInference( exp, n.eqNode( c ), "I_CONST_MERGE" );
+ return;
+ }else if( !hasProcessed() ){
+ Node nr = getRepresentative( n );
+ std::map< Node, Node >::iterator it = d_eqc_to_const.find( nr );
+ if( it==d_eqc_to_const.end() ){
+ Trace("strings-debug") << "Set eqc const " << n << " to " << c << std::endl;
+ d_eqc_to_const[nr] = c;
+ d_eqc_to_const_base[nr] = n;
+ d_eqc_to_const_exp[nr] = mkAnd( exp );
+ }else if( c!=it->second ){
+ //conflict
+ Trace("strings-debug") << "Conflict, other constant was " << it->second << ", this constant was " << c << std::endl;
+ if( d_eqc_to_const_exp[nr].isNull() ){
+ // n==c ^ n == c' => false
+ addToExplanation( n, it->second, exp );
+ }else{
+ // n==c ^ n == d_eqc_to_const_base[nr] == c' => false
+ exp.push_back( d_eqc_to_const_exp[nr] );
+ addToExplanation( n, d_eqc_to_const_base[nr], exp );
}
+ sendInference( exp, d_false, "I_CONST_CONFLICT" );
+ return;
+ }else{
+ Trace("strings-debug") << "Duplicate constant." << std::endl;
}
}
- Node to_reduce;
- if( !var.empty() ){
- Node nr = n.substitute( var.begin(), var.end(), sub.begin(), sub.end() );
- Node nrc = Rewriter::rewrite( nr );
- if( nrc.isConst() ){
- //mark as reduced
- d_ext_func_terms[n] = false;
+ }
+ }
+ for( std::map< TNode, TermIndex >::iterator it = ti->d_children.begin(); it != ti->d_children.end(); ++it ){
+ std::map< Node, Node >::iterator itc = d_eqc_to_const.find( it->first );
+ if( itc!=d_eqc_to_const.end() ){
+ vecc.push_back( itc->second );
+ checkConstantEquivalenceClasses( &it->second, vecc );
+ vecc.pop_back();
+ if( hasProcessed() ){
+ break;
+ }
+ }
+ }
+}
+
+void TheoryStrings::checkExtfEval( int effort ) {
+ Trace("strings-extf-list") << "Active extended functions, effort=" << effort << " : " << std::endl;
+ d_extf_info_tmp.clear();
+ bool has_nreduce = false;
+ std::vector< Node > terms;
+ std::vector< Node > sterms;
+ std::vector< std::vector< Node > > exp;
+ d_extt->getInferences( effort, terms, sterms, exp );
+ for( unsigned i=0; i<terms.size(); i++ ){
+ Node n = terms[i];
+ Node sn = sterms[i];
+ //setup information about extf
+ d_extf_info_tmp[n].init();
+ std::map< Node, ExtfInfoTmp >::iterator itit = d_extf_info_tmp.find( n );
+ if( n.getType().isBoolean() ){
+ if( areEqual( n, d_true ) ){
+ itit->second.d_pol = 1;
+ }else if( areEqual( n, d_false ) ){
+ itit->second.d_pol = -1;
+ }
+ }
+ Trace("strings-extf-debug") << "Check extf " << n << " == " << sn << ", pol = " << itit->second.d_pol << ", effort=" << effort << "..." << std::endl;
+ //do the inference
+ Node to_reduce;
+ if( n!=sn ){
+ itit->second.d_exp.insert( itit->second.d_exp.end(), exp[i].begin(), exp[i].end() );
+ // inference is rewriting the substituted node
+ Node nrc = Rewriter::rewrite( sn );
+ //if rewrites to a constant, then do the inference and mark as reduced
+ if( nrc.isConst() ){
+ if( effort<3 ){
+ d_extt->markReduced( n );
Trace("strings-extf-debug") << " resolvable by evaluation..." << std::endl;
std::vector< Node > exps;
Trace("strings-extf-debug") << " get symbolic definition..." << std::endl;
- Node nrs = getSymbolicDefinition( nr, exps );
+ Node nrs = getSymbolicDefinition( sn, exps );
if( !nrs.isNull() ){
Trace("strings-extf-debug") << " rewrite " << nrs << "..." << std::endl;
nrs = Rewriter::rewrite( nrs );
@@ -1214,13 +1343,13 @@ void TheoryStrings::checkExtendedFuncsEval( int effort ) {
}else{
conc = nrs.eqNode( nrc );
}
- d_extf_exp[n].clear();
+ itit->second.d_exp.clear();
}
}else{
if( !areEqual( n, nrc ) ){
if( n.getType().isBoolean() ){
if( areEqual( n, nrc==d_true ? d_false : d_true ) ){
- d_extf_exp[n].push_back( nrc==d_true ? n.negate() : n );
+ itit->second.d_exp.push_back( nrc==d_true ? n.negate() : n );
conc = d_false;
}else{
conc = nrc==d_true ? n : n.negate();
@@ -1231,85 +1360,102 @@ 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", true );
+ Trace("strings-extf") << " resolve extf : " << sn << " -> " << nrc << std::endl;
+ sendInference( itit->second.d_exp, conc, effort==0 ? "EXTF" : "EXTF-N", true );
if( d_conflict ){
Trace("strings-extf-debug") << " conflict, return." << std::endl;
return;
}
}
- }else if( ( nrc.getKind()==kind::OR && d_extf_pol[n]==-1 ) || ( nrc.getKind()==kind::AND && d_extf_pol[n]==1 ) ){
- //infer the consequence of each
- d_ext_func_terms[n] = false;
- d_extf_exp[n].push_back( d_extf_pol[n]==-1 ? n.negate() : n );
- Trace("strings-extf-debug") << " decomposable..." << std::endl;
- Trace("strings-extf") << " resolve extf : " << nr << " -> " << nrc << ", pol = " << d_extf_pol[n] << std::endl;
- for( unsigned i=0; i<nrc.getNumChildren(); i++ ){
- sendInference( d_extf_exp[n], d_extf_pol[n]==-1 ? nrc[i].negate() : nrc[i], effort==0 ? "EXTF_d" : "EXTF_d-N" );
- }
}else{
- to_reduce = nrc;
+ //check if it is already equal, if so, mark as reduced. Otherwise, do nothing.
+ if( areEqual( n, nrc ) ){
+ Trace("strings-extf") << " resolved extf, since satisfied by model: " << n << std::endl;
+ itit->second.d_model_active = false;
+ }
+ }
+ //if it reduces to a conjunction, infer each and reduce
+ }else if( ( nrc.getKind()==kind::OR && itit->second.d_pol==-1 ) || ( nrc.getKind()==kind::AND && itit->second.d_pol==1 ) ){
+ Assert( effort<3 );
+ d_extt->markReduced( n );
+ itit->second.d_exp.push_back( itit->second.d_pol==-1 ? n.negate() : n );
+ Trace("strings-extf-debug") << " decomposable..." << std::endl;
+ Trace("strings-extf") << " resolve extf : " << sn << " -> " << nrc << ", pol = " << itit->second.d_pol << std::endl;
+ for( unsigned i=0; i<nrc.getNumChildren(); i++ ){
+ sendInference( itit->second.d_exp, itit->second.d_pol==-1 ? nrc[i].negate() : nrc[i], effort==0 ? "EXTF_d" : "EXTF_d-N" );
}
}else{
- to_reduce = n;
+ to_reduce = nrc;
+ }
+ }else{
+ to_reduce = sterms[i];
+ }
+ //if not reduced
+ if( !to_reduce.isNull() ){
+ Assert( effort<3 );
+ if( effort==1 ){
+ Trace("strings-extf") << " cannot rewrite extf : " << to_reduce << std::endl;
}
- if( !to_reduce.isNull() ){
- if( effort==1 ){
- Trace("strings-extf") << " cannot rewrite extf : " << to_reduce << std::endl;
+ checkExtfInference( n, to_reduce, itit->second, effort );
+ if( Trace.isOn("strings-extf-list") ){
+ Trace("strings-extf-list") << " * " << to_reduce;
+ if( itit->second.d_pol!=0 ){
+ Trace("strings-extf-list") << ", pol = " << itit->second.d_pol;
}
- checkExtfInference( n, to_reduce, effort );
- if( Trace.isOn("strings-extf-list") ){
- Trace("strings-extf-list") << " * " << to_reduce;
- if( d_extf_pol[n]!=0 ){
- Trace("strings-extf-list") << ", pol = " << d_extf_pol[n];
- }
- if( n!=to_reduce ){
- Trace("strings-extf-list") << ", from " << n;
- }
- Trace("strings-extf-list") << std::endl;
+ if( n!=to_reduce ){
+ Trace("strings-extf-list") << ", from " << n;
}
+ Trace("strings-extf-list") << std::endl;
+ }
+ if( d_extt->isActive( n ) && itit->second.d_model_active ){
+ has_nreduce = true;
}
- }else{
- Trace("strings-extf-debug") << " already reduced " << (*it).first << std::endl;
}
}
+ d_has_extf = has_nreduce;
}
-void TheoryStrings::checkExtfInference( Node n, Node nr, int effort ){
- int n_pol = d_extf_pol[n];
- if( n_pol!=0 ){
+void TheoryStrings::checkExtfInference( Node n, Node nr, ExtfInfoTmp& in, int effort ){
+ //make additional inferences that do not contribute to the reduction of n, but may help show a refutation
+ if( in.d_pol!=0 ){
//add original to explanation
- d_extf_exp[n].push_back( n_pol==1 ? n : n.negate() );
+ in.d_exp.push_back( in.d_pol==1 ? n : n.negate() );
+
+ //d_extf_infer_cache stores whether we have made the inferences associated with a node n,
+ // this may need to be generalized if multiple inferences apply
+
if( nr.getKind()==kind::STRING_STRCTN ){
- if( ( n_pol==1 && nr[1].getKind()==kind::STRING_CONCAT ) || ( n_pol==-1 && nr[0].getKind()==kind::STRING_CONCAT ) ){
+ if( ( in.d_pol==1 && nr[1].getKind()==kind::STRING_CONCAT ) || ( in.d_pol==-1 && nr[0].getKind()==kind::STRING_CONCAT ) ){
if( d_extf_infer_cache.find( nr )==d_extf_infer_cache.end() ){
d_extf_infer_cache.insert( nr );
+
//one argument does (not) contain each of the components of the other argument
- int index = n_pol==1 ? 1 : 0;
+ int index = in.d_pol==1 ? 1 : 0;
std::vector< Node > children;
children.push_back( nr[0] );
children.push_back( nr[1] );
- //Node exp_n = mkAnd( d_extf_exp[n] );
+ //Node exp_n = mkAnd( exp );
for( unsigned i=0; i<nr[index].getNumChildren(); i++ ){
children[index] = nr[index][i];
Node conc = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, children );
//can mark as reduced, since model for n => model for conc
- d_ext_func_terms[conc] = false;
- sendInference( d_extf_exp[n], n_pol==1 ? conc : conc.negate(), "CTN_Decompose" );
+ d_extt->markReduced( conc );
+ sendInference( in.d_exp, in.d_pol==1 ? conc : conc.negate(), "CTN_Decompose" );
}
+
}
}else{
//store this (reduced) assertion
//Assert( effort==0 || nr[0]==getRepresentative( nr[0] ) );
- bool pol = n_pol==1;
- if( std::find( d_extf_info[nr[0]].d_ctn[pol].begin(), d_extf_info[nr[0]].d_ctn[pol].end(), nr[1] )==d_extf_info[nr[0]].d_ctn[pol].end() ){
+ bool pol = in.d_pol==1;
+ if( std::find( d_extf_info_tmp[nr[0]].d_ctn[pol].begin(), d_extf_info_tmp[nr[0]].d_ctn[pol].end(), nr[1] )==d_extf_info_tmp[nr[0]].d_ctn[pol].end() ){
Trace("strings-extf-debug") << " store contains info : " << nr[0] << " " << pol << " " << nr[1] << std::endl;
- d_extf_info[nr[0]].d_ctn[pol].push_back( nr[1] );
- d_extf_info[nr[0]].d_ctn_from[pol].push_back( n );
+ d_extf_info_tmp[nr[0]].d_ctn[pol].push_back( nr[1] );
+ d_extf_info_tmp[nr[0]].d_ctn_from[pol].push_back( n );
//transitive closure for contains
bool opol = !pol;
- for( unsigned i=0; i<d_extf_info[nr[0]].d_ctn[opol].size(); i++ ){
- Node onr = d_extf_info[nr[0]].d_ctn[opol][i];
+ for( unsigned i=0; i<d_extf_info_tmp[nr[0]].d_ctn[opol].size(); i++ ){
+ Node onr = d_extf_info_tmp[nr[0]].d_ctn[opol][i];
Node conc = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, pol ? nr[1] : onr, pol ? onr : nr[1] );
conc = Rewriter::rewrite( conc );
bool do_infer = false;
@@ -1320,24 +1466,24 @@ void TheoryStrings::checkExtfInference( Node n, Node nr, int effort ){
}
if( do_infer ){
conc = conc.negate();
- std::vector< Node > exp;
- exp.insert( exp.end(), d_extf_exp[n].begin(), d_extf_exp[n].end() );
- Node ofrom = d_extf_info[nr[0]].d_ctn_from[opol][i];
- Assert( d_extf_exp.find( ofrom )!=d_extf_exp.end() );
- exp.insert( exp.end(), d_extf_exp[ofrom].begin(), d_extf_exp[ofrom].end() );
- sendInference( exp, conc, "CTN_Trans" );
+ std::vector< Node > exp_c;
+ exp_c.insert( exp_c.end(), in.d_exp.begin(), in.d_exp.end() );
+ Node ofrom = d_extf_info_tmp[nr[0]].d_ctn_from[opol][i];
+ Assert( d_extf_info_tmp.find( ofrom )!=d_extf_info_tmp.end() );
+ exp_c.insert( exp_c.end(), d_extf_info_tmp[ofrom].d_exp.begin(), d_extf_info_tmp[ofrom].d_exp.end() );
+ sendInference( exp_c, conc, "CTN_Trans" );
}
}
}else{
Trace("strings-extf-debug") << " redundant." << std::endl;
- d_ext_func_terms[n] = false;
+ d_extt->markReduced( n );
}
}
}
}
}
-void TheoryStrings::collectVars( Node n, std::map< Node, std::vector< Node > >& vars, std::map< Node, bool >& visited ) {
+void TheoryStrings::collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited ) {
if( !n.isConst() ){
if( visited.find( n )==visited.end() ){
visited[n] = true;
@@ -1346,8 +1492,9 @@ void TheoryStrings::collectVars( Node n, std::map< Node, std::vector< Node > >&
collectVars( n[i], vars, visited );
}
}else{
- Node nr = getRepresentative( n );
- vars[nr].push_back( n );
+ //Node nr = getRepresentative( n );
+ //vars[nr].push_back( n );
+ vars.push_back( n );
}
}
}
@@ -1387,6 +1534,14 @@ Node TheoryStrings::getSymbolicDefinition( Node n, std::vector< Node >& exp ) {
}
}
+Node TheoryStrings::getConstantEqc( Node eqc ) {
+ std::map< Node, Node >::iterator it = d_eqc_to_const.find( eqc );
+ if( it!=d_eqc_to_const.end() ){
+ return it->second;
+ }else{
+ return Node::null();
+ }
+}
void TheoryStrings::debugPrintFlatForms( const char * tc ){
for( unsigned k=0; k<d_strings_eqc.size(); k++ ){
@@ -1429,6 +1584,31 @@ void TheoryStrings::debugPrintFlatForms( const char * tc ){
Trace( tc ) << std::endl;
}
+void TheoryStrings::debugPrintNormalForms( const char * tc ) {
+}
+
+struct sortConstLength {
+ std::map< Node, unsigned > d_const_length;
+ bool operator() (Node i, Node j) {
+ std::map< Node, unsigned >::iterator it_i = d_const_length.find( i );
+ std::map< Node, unsigned >::iterator it_j = d_const_length.find( j );
+ if( it_i==d_const_length.end() ){
+ if( it_j==d_const_length.end() ){
+ return i<j;
+ }else{
+ return false;
+ }
+ }else{
+ if( it_j==d_const_length.end() ){
+ return true;
+ }else{
+ return it_i->second<it_j->second;
+ }
+ }
+ }
+};
+
+
void TheoryStrings::checkFlatForms() {
//first check for cycles, while building ordering of equivalence classes
d_eqc.clear();
@@ -1439,6 +1619,17 @@ void TheoryStrings::checkFlatForms() {
std::vector< Node > eqc;
eqc.insert( eqc.end(), d_strings_eqc.begin(), d_strings_eqc.end() );
d_strings_eqc.clear();
+ if( options::stringBinaryCsp() ){
+ //sort: process smallest constants first (necessary if doing binary splits)
+ sortConstLength scl;
+ for( unsigned i=0; i<eqc.size(); i++ ){
+ std::map< Node, Node >::iterator itc = d_eqc_to_const.find( eqc[i] );
+ if( itc!=d_eqc_to_const.end() ){
+ scl.d_const_length[eqc[i]] = itc->second.getConst<String>().size();
+ }
+ }
+ std::sort( eqc.begin(), eqc.end(), scl );
+ }
for( unsigned i=0; i<eqc.size(); i++ ){
std::vector< Node > curr;
std::vector< Node > exp;
@@ -1454,14 +1645,50 @@ void TheoryStrings::checkFlatForms() {
Trace("strings-ff") << "Flat forms : " << std::endl;
debugPrintFlatForms( "strings-ff" );
}
+
//inferences without recursively expanding flat forms
+
+ //(1) approximate equality by containment, infer conflicts
for( unsigned k=0; k<d_strings_eqc.size(); k++ ){
Node eqc = d_strings_eqc[k];
- Node c;
- std::map< Node, Node >::iterator itc = d_eqc_to_const.find( eqc );
- if( itc!=d_eqc_to_const.end() ){
- c = itc->second; //use?
+ Node c = getConstantEqc( eqc );
+ if( !c.isNull() ){
+ //if equivalence class is constant, all component constants in flat forms must be contained in it, in order
+ std::map< Node, std::vector< Node > >::iterator it = d_eqc.find( eqc );
+ if( it!=d_eqc.end() ){
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ int firstc, lastc;
+ if( !TheoryStringsRewriter::canConstantContainList( c, d_flat_form[n], firstc, lastc ) ){
+ Trace("strings-ff-debug") << "Flat form for " << n << " cannot be contained in constant " << c << std::endl;
+ Trace("strings-ff-debug") << " indices = " << firstc << "/" << lastc << std::endl;
+ //conflict, explanation is n = base ^ base = c ^ relevant porition of ( n = f[n] )
+ std::vector< Node > exp;
+ Assert( d_eqc_to_const_base.find( eqc )!=d_eqc_to_const_base.end() );
+ addToExplanation( n, d_eqc_to_const_base[eqc], exp );
+ Assert( d_eqc_to_const_exp.find( eqc )!=d_eqc_to_const_exp.end() );
+ if( !d_eqc_to_const_exp[eqc].isNull() ){
+ exp.push_back( d_eqc_to_const_exp[eqc] );
+ }
+ for( int e=firstc; e<=lastc; e++ ){
+ if( d_flat_form[n][e].isConst() ){
+ Assert( e>=0 && e<(int)d_flat_form_index[n].size() );
+ Assert( d_flat_form_index[n][e]>=0 && d_flat_form_index[n][e]<(int)n.getNumChildren() );
+ addToExplanation( d_flat_form[n][e], n[d_flat_form_index[n][e]], exp );
+ }
+ }
+ Node conc = d_false;
+ sendInference( exp, conc, "F_NCTN" );
+ return;
+ }
+ }
+ }
}
+ }
+
+ //(2) scan lists, unification to infer conflicts and equalities
+ for( unsigned k=0; k<d_strings_eqc.size(); k++ ){
+ Node eqc = d_strings_eqc[k];
std::map< Node, std::vector< Node > >::iterator it = d_eqc.find( eqc );
if( it!=d_eqc.end() && it->second.size()>1 ){
//iterate over start index
@@ -1503,7 +1730,7 @@ void TheoryStrings::checkFlatForms() {
}
}else{
Node curr = d_flat_form[a][count];
- Node curr_c = d_eqc_to_const[curr];
+ Node curr_c = getConstantEqc( curr );
Node ac = a[d_flat_form_index[a][count]];
std::vector< Node > lexp;
Node lcurr = getLength( ac, lexp );
@@ -1529,7 +1756,7 @@ void TheoryStrings::checkFlatForms() {
Node bc = b[d_flat_form_index[b][count]];
inelig.push_back( b );
Assert( !areEqual( curr, cc ) );
- Node cc_c = d_eqc_to_const[cc];
+ Node cc_c = getConstantEqc( cc );
if( !curr_c.isNull() && !cc_c.isNull() ){
//check for constant conflict
int index;
@@ -1582,7 +1809,13 @@ void TheoryStrings::checkFlatForms() {
//explain why other components up to now are empty
for( unsigned t=0; t<2; t++ ){
Node c = t==0 ? a : b;
- int jj = t==0 ? d_flat_form_index[a][count] : ( inf_type==2 ? ( r==0 ? c.getNumChildren() : -1 ) : d_flat_form_index[b][count] );
+ int jj;
+ if( inf_type==3 || ( t==1 && inf_type==2 ) ){
+ //explain all the empty components for F_EndpointEq, all for the short end for F_EndpointEmp
+ jj = r==0 ? c.getNumChildren() : -1;
+ }else{
+ jj = t==0 ? d_flat_form_index[a][count] : d_flat_form_index[b][count];
+ }
if( r==0 ){
for( int j=0; j<jj; j++ ){
if( areEqual( c[j], d_emptyString ) ){
@@ -1597,10 +1830,9 @@ void TheoryStrings::checkFlatForms() {
}
}
}
- //if( exp_n.empty() ){
- sendInference( exp, conc, inf_type==0? "F_Const" : ( inf_type==1 ? "F_LengthEq" : ( inf_type==2 ? "F_Endpoint" : "F_EndpointEq" ) ) );
- //}else{
- //}
+ //notice that F_EndpointEmp is not typically applied, since strict prefix equality ( a.b = a ) where a,b non-empty
+ // is conflicting by arithmetic len(a.b)=len(a)+len(b)!=len(a) when len(b)!=0.
+ sendInference( exp, conc, inf_type==0 ? "F_Const" : ( inf_type==1 ? "F_Unify" : ( inf_type==2 ? "F_EndpointEmp" : "F_EndpointEq" ) ) );
if( d_conflict ){
return;
}else{
@@ -1621,7 +1853,7 @@ void TheoryStrings::checkFlatForms() {
if( !hasProcessed() ){
// simple extended func reduction
Trace("strings-process") << "Check extended function reduction effort=1..." << std::endl;
- checkExtfReduction( 1 );
+ checkExtfReductions( 1 );
Trace("strings-process") << "Done check extended function reduction" << std::endl;
}
}
@@ -1720,41 +1952,43 @@ void TheoryStrings::checkNormalForms(){
d_normal_forms.clear();
d_normal_forms_exp.clear();
std::map< Node, Node > nf_to_eqc;
+ std::map< Node, Node > eqc_to_nf;
std::map< Node, Node > eqc_to_exp;
for( unsigned i=0; i<d_strings_eqc.size(); i++ ) {
Node eqc = d_strings_eqc[i];
Trace("strings-process-debug") << "- Verify normal forms are the same for " << eqc << std::endl;
- std::vector< Node > nf;
- std::vector< Node > nf_exp;
- normalizeEquivalenceClass( eqc, nf, nf_exp );
+ normalizeEquivalenceClass( eqc );
Trace("strings-debug") << "Finished normalizing eqc..." << std::endl;
if( hasProcessed() ){
return;
}else{
- Node nf_term = mkConcat( nf );
- if( nf_to_eqc.find( nf_term )!=nf_to_eqc.end() ) {
- //Trace("strings-debug") << "Merge because of normal form : " << eqc << " and " << nf_to_eqc[nf_term] << " both have normal form " << nf_term << std::endl;
+ Node nf_term = mkConcat( d_normal_forms[eqc] );
+ std::map< Node, Node >::iterator itn = nf_to_eqc.find( nf_term );
+ if( itn!=nf_to_eqc.end() ){
//two equivalence classes have same normal form, merge
- nf_exp.push_back( eqc_to_exp[nf_to_eqc[nf_term]] );
- Node eq = eqc.eqNode( nf_to_eqc[nf_term] );
+ std::vector< Node > nf_exp;
+ nf_exp.push_back( mkAnd( d_normal_forms_exp[eqc] ) );
+ nf_exp.push_back( eqc_to_exp[itn->second] );
+ Node eq = d_normal_forms_base[eqc].eqNode( d_normal_forms_base[itn->second] );
sendInference( nf_exp, eq, "Normal_Form" );
} else {
nf_to_eqc[nf_term] = eqc;
- eqc_to_exp[eqc] = mkAnd( nf_exp );
+ eqc_to_nf[eqc] = nf_term;
+ eqc_to_exp[eqc] = mkAnd( d_normal_forms_exp[eqc] );
}
}
Trace("strings-process-debug") << "Done verifying normal forms are the same for " << eqc << std::endl;
}
-
- if(Trace.isOn("strings-nf")) {
- Trace("strings-nf") << "**** Normal forms are : " << std::endl;
- for( std::map< Node, Node >::iterator it = nf_to_eqc.begin(); it != nf_to_eqc.end(); ++it ){
- Trace("strings-nf") << " N[" << it->second << "] = " << it->first << std::endl;
- }
- Trace("strings-nf") << std::endl;
- }
if( !hasProcessed() ){
- checkExtendedFuncsEval( 1 );
+ if(Trace.isOn("strings-nf")) {
+ Trace("strings-nf") << "**** Normal forms are : " << std::endl;
+ for( std::map< Node, Node >::iterator it = eqc_to_exp.begin(); it != eqc_to_exp.end(); ++it ){
+ Trace("strings-nf") << " N[" << it->first << "] (base " << d_normal_forms_base[it->first] << ") = " << eqc_to_nf[it->first] << std::endl;
+ Trace("strings-nf") << " exp: " << it->second << std::endl;
+ }
+ Trace("strings-nf") << std::endl;
+ }
+ checkExtfEval( 1 );
Trace("strings-process-debug") << "Done check extended functions re-eval, addedFact = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
if( !hasProcessed() ){
if( !options::stringEagerLen() ){
@@ -1772,97 +2006,78 @@ void TheoryStrings::checkNormalForms(){
}
}
-//nf_exp is conjunction
-bool TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & nf, std::vector< Node > & nf_exp ) {
+//compute d_normal_forms_(base,exp,exp_depend)[eqc]
+void TheoryStrings::normalizeEquivalenceClass( Node eqc ) {
Trace("strings-process-debug") << "Process equivalence class " << eqc << std::endl;
if( areEqual( eqc, d_emptyString ) ) {
+#ifdef CVC4_ASSERTIONS
for( unsigned j=0; j<d_eqc[eqc].size(); j++ ){
Node n = d_eqc[eqc][j];
for( unsigned i=0; i<n.getNumChildren(); i++ ){
Assert( areEqual( n[i], d_emptyString ) );
}
}
+#endif
//do nothing
Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : empty." << std::endl;
d_normal_forms_base[eqc] = d_emptyString;
d_normal_forms[eqc].clear();
d_normal_forms_exp[eqc].clear();
- return true;
} else {
- bool result;
- if( d_normal_forms.find(eqc)==d_normal_forms.end() ){
- //phi => t = s1 * ... * sn
- // normal form for each non-variable term in this eqc (s1...sn)
- std::vector< std::vector< Node > > normal_forms;
- // explanation for each normal form (phi)
- std::vector< std::vector< Node > > normal_forms_exp;
- // dependency information
- std::vector< std::map< Node, std::map< bool, int > > > normal_forms_exp_depend;
- // record terms for each normal form (t)
- std::vector< Node > normal_form_src;
- //Get Normal Forms
- result = getNormalForms(eqc, normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend);
- if( hasProcessed() ){
- return true;
- }else if( result ){
- if( processNEqc(normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend) ){
- return true;
- }
- }
- //construct the normal form
- if( normal_forms.empty() ){
- Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
- getConcatVec( eqc, nf );
- d_normal_forms_base[eqc] = eqc;
- }else{
- int nf_index = 0;
- //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() );
- //Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
- //d_normal_forms_base[eqc] = normal_form_src[nf_index];
- ///*
- std::vector< Node >::iterator itn = std::find( normal_form_src.begin(), normal_form_src.end(), eqc );
- if( itn!=normal_form_src.end() ){
- nf_index = itn - normal_form_src.begin();
- Trace("strings-solve-debug2") << "take normal form " << nf_index << std::endl;
- Assert( normal_form_src[nf_index]==eqc );
- }else{
- //just take the first normal form
- Trace("strings-solve-debug2") << "take the first normal form" << std::endl;
- }
- 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] ) );
- }
- Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
- d_normal_forms_base[eqc] = normal_form_src[nf_index];
- //*/
- //track dependencies
- for( unsigned i=0; i<normal_forms_exp[nf_index].size(); i++ ){
- Node exp = normal_forms_exp[nf_index][i];
- for( unsigned r=0; r<2; r++ ){
- d_normal_forms_exp_depend[eqc][exp][r==0] = normal_forms_exp_depend[nf_index][exp][r==0];
- }
- }
- }
-
- d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), nf.begin(), nf.end() );
- d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), nf_exp.begin(), nf_exp.end() );
-
- Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : returned, size = " << nf.size() << std::endl;
+ Assert( d_normal_forms.find(eqc)==d_normal_forms.end() );
+ //phi => t = s1 * ... * sn
+ // normal form for each non-variable term in this eqc (s1...sn)
+ std::vector< std::vector< Node > > normal_forms;
+ // explanation for each normal form (phi)
+ std::vector< std::vector< Node > > normal_forms_exp;
+ // dependency information
+ std::vector< std::map< Node, std::map< bool, int > > > normal_forms_exp_depend;
+ // record terms for each normal form (t)
+ std::vector< Node > normal_form_src;
+ // get normal forms
+ getNormalForms(eqc, normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend);
+ if( hasProcessed() ){
+ return;
+ }
+ // process the normal forms
+ processNEqc( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend );
+ if( hasProcessed() ){
+ return;
+ }
+ //debugPrintNormalForms( "strings-solve", eqc, normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend );
+
+ //construct the normal form
+ Assert( !normal_forms.empty() );
+
+ int nf_index = 0;
+ std::vector< Node >::iterator itn = std::find( normal_form_src.begin(), normal_form_src.end(), eqc );
+ if( itn!=normal_form_src.end() ){
+ nf_index = itn - normal_form_src.begin();
+ Trace("strings-solve-debug2") << "take normal form " << nf_index << std::endl;
+ Assert( normal_form_src[nf_index]==eqc );
}else{
- Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : already computed, size = " << d_normal_forms[eqc].size() << std::endl;
- nf.insert( nf.end(), d_normal_forms[eqc].begin(), d_normal_forms[eqc].end() );
- nf_exp.insert( nf_exp.end(), d_normal_forms_exp[eqc].begin(), d_normal_forms_exp[eqc].end() );
- result = true;
+ //just take the first normal form
+ Trace("strings-solve-debug2") << "take the first normal form" << std::endl;
+ }
+ d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), normal_forms[nf_index].begin(), normal_forms[nf_index].end() );
+ d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), normal_forms_exp[nf_index].begin(), normal_forms_exp[nf_index].end() );
+ Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
+ d_normal_forms_base[eqc] = normal_form_src[nf_index];
+ //track dependencies
+ for( unsigned i=0; i<normal_forms_exp[nf_index].size(); i++ ){
+ Node exp = normal_forms_exp[nf_index][i];
+ for( unsigned r=0; r<2; r++ ){
+ d_normal_forms_exp_depend[eqc][exp][r==0] = normal_forms_exp_depend[nf_index][exp][r==0];
+ }
}
- return result;
+ Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : returned, size = " << d_normal_forms[eqc].size() << std::endl;
}
}
-bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+void TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ) {
+ //constant for equivalence class
+ Node eqc_non_c = eqc;
Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
while( !eqc_i.isFinished() ){
@@ -1915,8 +2130,9 @@ bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node >
}
}
}
- if( nr!=n[i] ){
- Node eq = n[i].eqNode( nr );
+ if( d_normal_forms_base[nr]!=n[i] ){
+ Assert( d_normal_forms_base.find( nr )!=d_normal_forms_base.end() );
+ Node eq = n[i].eqNode( d_normal_forms_base[nr] );
nf_exp_n.push_back( eq );
//track depends
nf_exp_depend_n[eq][false] = orig_size;
@@ -1950,25 +2166,25 @@ bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node >
//this was redundant: combination of self + empty string(s)
Node nn = nf_n.size()==0 ? d_emptyString : nf_n[0];
Assert( areEqual( nn, eqc ) );
- //Assert( areEqual( nf_n[0], eqc ) );
- /*
- if( !areEqual( nn, eqc ) ){
- std::vector< Node > ant;
- ant.insert( ant.end(), nf_exp_n.begin(), nf_exp_n.end() );
- ant.push_back( n.eqNode( eqc ) );
- Node conc = Rewriter::rewrite( nn.eqNode( eqc ) );
- sendInference( ant, conc, "CYCLE-T" );
- return true;
- }
- */
}
+ }else{
+ eqc_non_c = n;
}
}
++eqc_i;
}
- if(Trace.isOn("strings-solve")) {
- if( !normal_forms.empty() ) {
+ if( normal_forms.empty() ) {
+ Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
+ //do not choose a concat here use "eqc_non_c" (in this case they have non-trivial explanation why they normalize to self)
+ std::vector< Node > eqc_non_c_nf;
+ getConcatVec( eqc_non_c, eqc_non_c_nf );
+ normal_forms.push_back( eqc_non_c_nf );
+ normal_form_src.push_back( eqc_non_c );
+ normal_forms_exp.push_back( std::vector< Node >() );
+ normal_forms_exp_depend.push_back( std::map< Node, std::map< bool, int > >() );
+ }else{
+ if(Trace.isOn("strings-solve")) {
Trace("strings-solve") << "--- Normal forms for equivlance class " << eqc << " : " << std::endl;
for( unsigned i=0; i<normal_forms.size(); i++ ) {
Trace("strings-solve") << "#" << i << " (from " << normal_form_src[i] << ") : ";
@@ -2003,263 +2219,173 @@ bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node >
} else {
Trace("strings-solve") << "--- Single normal form for equivalence class " << eqc << std::endl;
}
+
+ //if equivalence class is constant, approximate as containment, infer conflicts
+ Node c = getConstantEqc( eqc );
+ if( !c.isNull() ){
+ Trace("strings-solve") << "Eqc is constant " << c << std::endl;
+ for( unsigned i=0; i<normal_forms.size(); i++ ) {
+ int firstc, lastc;
+ if( !TheoryStringsRewriter::canConstantContainList( c, normal_forms[i], firstc, lastc ) ){
+ Node n = normal_form_src[i];
+ //conflict
+ Trace("strings-solve") << "Normal form for " << n << " cannot be contained in constant " << c << std::endl;
+ //conflict, explanation is n = base ^ base = c ^ relevant porition of ( n = N[n] )
+ std::vector< Node > exp;
+ Assert( d_eqc_to_const_base.find( eqc )!=d_eqc_to_const_base.end() );
+ addToExplanation( n, d_eqc_to_const_base[eqc], exp );
+ Assert( d_eqc_to_const_exp.find( eqc )!=d_eqc_to_const_exp.end() );
+ if( !d_eqc_to_const_exp[eqc].isNull() ){
+ exp.push_back( d_eqc_to_const_exp[eqc] );
+ }
+ //TODO: this can be minimized based on firstc/lastc, normal_forms_exp_depend
+ exp.insert( exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
+ Node conc = d_false;
+ sendInference( exp, conc, "N_NCTN" );
+ }
+ }
+ }
}
- return true;
}
-void TheoryStrings::getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
- std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j, int index, bool isRev, std::vector< Node >& curr_exp ) {
+void TheoryStrings::getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+ unsigned i, int index, bool isRev, std::vector< Node >& curr_exp ) {
if( index==-1 || !options::stringMinPrefixExplain() ){
curr_exp.insert(curr_exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
- curr_exp.insert(curr_exp.end(), normal_forms_exp[j].begin(), normal_forms_exp[j].end() );
}else{
- Trace("strings-explain-prefix") << "Get explanation for prefix " << index << " of normal forms " << i << " and " << j << ", reverse = " << isRev << std::endl;
- for( unsigned r=0; r<2; r++ ){
- int tindex = r==0 ? i : j;
- for( unsigned k=0; k<normal_forms_exp[tindex].size(); k++ ){
- Node exp = normal_forms_exp[tindex][k];
- int dep = normal_forms_exp_depend[tindex][exp][isRev];
- if( dep<=index ){
- curr_exp.push_back( exp );
- Trace("strings-explain-prefix-debug") << " include : " << exp << std::endl;
- }else{
- Trace("strings-explain-prefix-debug") << " exclude : " << exp << std::endl;
- }
+ for( unsigned k=0; k<normal_forms_exp[i].size(); k++ ){
+ Node exp = normal_forms_exp[i][k];
+ int dep = normal_forms_exp_depend[i][exp][isRev];
+ if( dep<=index ){
+ curr_exp.push_back( exp );
+ Trace("strings-explain-prefix-debug") << " include : " << exp << std::endl;
+ }else{
+ Trace("strings-explain-prefix-debug") << " exclude : " << exp << std::endl;
}
}
- Trace("strings-explain-prefix") << "Included " << curr_exp.size() << " / " << ( normal_forms_exp[i].size() + normal_forms_exp[j].size() ) << std::endl;
}
- if( normal_form_src[i]!=normal_form_src[j] ){
- curr_exp.push_back( normal_form_src[i].eqNode( normal_form_src[j] ) );
+}
+
+void TheoryStrings::getExplanationVectorForPrefixEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+ unsigned i, unsigned j, int index_i, int index_j, bool isRev, std::vector< Node >& curr_exp ) {
+ Trace("strings-explain-prefix") << "Get explanation for prefix " << index_i << ", " << index_j << " of normal forms " << i << " and " << j << ", reverse = " << isRev << std::endl;
+ for( unsigned r=0; r<2; r++ ){
+ getExplanationVectorForPrefix( normal_forms_exp, normal_forms_exp_depend, r==0 ? i : j, r==0 ? index_i : index_j, isRev, curr_exp );
}
+ Trace("strings-explain-prefix") << "Included " << curr_exp.size() << " / " << ( normal_forms_exp[i].size() + normal_forms_exp[j].size() ) << std::endl;
+ addToExplanation( normal_form_src[i], normal_form_src[j], curr_exp );
}
-bool TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
- std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ) {
- bool flag_lb = false;
- std::vector< Node > c_lb_exp;
- int c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index;
+
+void TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ){
+ //the possible inferences
+ std::vector< InferInfo > pinfer;
+ // loop over all pairs
for(unsigned i=0; i<normal_forms.size()-1; i++) {
//unify each normalform[j] with normal_forms[i]
for(unsigned j=i+1; j<normal_forms.size(); j++ ) {
+ //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality, add to pinfer if not
Trace("strings-solve") << "Strings: Process normal form #" << i << " against #" << j << "..." << std::endl;
if( isNormalFormPair( normal_form_src[i], normal_form_src[j] ) ) {
Trace("strings-solve") << "Strings: Already cached." << std::endl;
}else{
//process the reverse direction first (check for easy conflicts and inferences)
- if( processReverseNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j ) ){
- return true;
+ unsigned rindex = 0;
+ processReverseNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, rindex, 0, pinfer );
+ if( hasProcessed() ){
+ return;
+ }else if( !pinfer.empty() && pinfer.back().d_id==1 ){
+ break;
}
+ //AJR: for less aggressive endpoint inference
+ //rindex = 0;
- //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality
unsigned index = 0;
- bool success;
- do{
- //simple check
- if( processSimpleNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false ) ){
- //added a lemma, return
- return true;
- }
-
- success = false;
- //if we are at the end
- if(index==normal_forms[i].size() || index==normal_forms[j].size() ) {
- Assert( index==normal_forms[i].size() && index==normal_forms[j].size() );
- //we're done
- //addNormalFormPair( normal_form_src[i], normal_form_src[j] );
- } else {
- std::vector< Node > lexp;
- Node length_term_i = getLength( normal_forms[i][index], lexp );
- Node length_term_j = getLength( normal_forms[j][index], lexp );
- //check length(normal_forms[i][index]) == length(normal_forms[j][index])
- if( !areDisequal(length_term_i, length_term_j) && !areEqual(length_term_i, length_term_j) &&
- normal_forms[i][index].getKind()!=kind::CONST_STRING && normal_forms[j][index].getKind()!=kind::CONST_STRING ) {
- //length terms are equal, merge equivalence classes if not already done so
- Node length_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j );
- Trace("strings-solve-debug") << "Non-simple Case 1 : string lengths neither equal nor disequal" << std::endl;
- //try to make the lengths equal via splitting on demand
- sendSplit( length_term_i, length_term_j, "Len-Split(Diseq)" );
- length_eq = Rewriter::rewrite( length_eq );
- d_pending_req_phase[ length_eq ] = true;
- return true;
- } else {
- Trace("strings-solve-debug") << "Non-simple Case 2 : must compare strings" << std::endl;
- int loop_in_i = -1;
- int loop_in_j = -1;
- if( detectLoop(normal_forms, i, j, index, loop_in_i, loop_in_j) ){
- if( !flag_lb ){
- c_i = i;
- c_j = j;
- c_loop_n_index = loop_in_i!=-1 ? i : j;
- c_other_n_index = loop_in_i!=-1 ? j : i;
- c_loop_index = loop_in_i!=-1 ? loop_in_i : loop_in_j;
- c_index = index;
-
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, false, c_lb_exp );
-
- if(options::stringLB() == 0) {
- flag_lb = true;
- } else {
- if(processLoop(c_lb_exp, normal_forms, normal_form_src, c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index)) {
- return true;
- }
- }
- }
- } else {
- Node conc;
- std::vector< Node > antec;
- Trace("strings-solve-debug") << "No loops detected." << std::endl;
- if( normal_forms[i][index].getKind() == kind::CONST_STRING || normal_forms[j][index].getKind() == kind::CONST_STRING) {
- unsigned const_k = normal_forms[i][index].getKind() == kind::CONST_STRING ? i : j;
- unsigned nconst_k = normal_forms[i][index].getKind() == kind::CONST_STRING ? j : i;
- Node const_str = normal_forms[const_k][index];
- Node other_str = normal_forms[nconst_k][index];
- Assert( other_str.getKind()!=kind::CONST_STRING, "Other string is not constant." );
- Assert( other_str.getKind()!=kind::STRING_CONCAT, "Other string is not CONCAT." );
- if( !d_equalityEngine.areDisequal(other_str, d_emptyString, true) ) {
- sendSplit( other_str, d_emptyString, "Len-Split(CST)" );
- } else {
- Assert(areDisequal(other_str, d_emptyString), "CST Split on empty Var");
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false, antec );
- Node xnz = other_str.eqNode(d_emptyString).negate();
- antec.push_back( xnz );
- Node conc;
- if( normal_forms[nconst_k].size() > index + 1 && normal_forms[nconst_k][index + 1].isConst() ) {
- CVC4::String stra = const_str.getConst<String>();
- CVC4::String strb = normal_forms[nconst_k][index + 1].getConst<String>();
- CVC4::String stra1 = stra.substr(1);
- size_t p = stra.size() - stra1.overlap(strb);
- size_t p2 = stra1.find(strb);
- p = p2==std::string::npos? p : ( p>p2+1? p2+1 : p );
- Node prea = p==stra.size()? const_str : NodeManager::currentNM()->mkConst(stra.substr(0, p));
- Node sk = mkSkolemCached( other_str, prea, sk_id_c_spt, "c_spt" );
- conc = other_str.eqNode( mkConcat(prea, sk) );
- Trace("strings-csp") << "Const Split: " << prea << " is removed from " << stra << " due to " << strb << std::endl;
- } else {
- // normal v/c split
- Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
- NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
- Node sk = mkSkolemCached( other_str, firstChar, sk_id_vc_spt, "c_spt" );
- conc = other_str.eqNode( mkConcat(firstChar, sk) );
- Trace("strings-csp") << "Const Split: " << firstChar << " is removed from " << const_str << " (normal) " << std::endl;
- }
-
- conc = Rewriter::rewrite( conc );
- sendInference( antec, conc, "S-Split(CST-P)", true );
- }
- return true;
- } else {
- std::vector< Node > antec_new_lits;
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false, antec );
-
- Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
- if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
- antec.push_back( ldeq );
- }else{
- antec_new_lits.push_back(ldeq);
- }
-
- //x!=e /\ y!=e
- for(unsigned xory=0; xory<2; xory++) {
- Node x = xory==0 ? normal_forms[i][index] : normal_forms[j][index];
- Node xgtz = x.eqNode( d_emptyString ).negate();
- if( d_equalityEngine.areDisequal( x, d_emptyString, true ) ) {
- antec.push_back( xgtz );
- } else {
- antec_new_lits.push_back( xgtz );
- }
- }
- Node sk = mkSkolemCached( normal_forms[i][index], normal_forms[j][index], sk_id_v_spt, "v_spt", 1 );
- Node eq1 = normal_forms[i][index].eqNode( mkConcat(normal_forms[j][index], sk) );
- Node eq2 = normal_forms[j][index].eqNode( mkConcat(normal_forms[i][index], sk) );
- if( options::stringCheckEntailLen() ){
- //check entailment
- for( unsigned e=0; e<2; e++ ){
- Node lt1 = e==0 ? length_term_i : length_term_j;
- Node lt2 = e==0 ? length_term_j : length_term_i;
- Node ent_lit = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::GT, lt1, lt2 ) );
- std::pair<bool, Node> et = d_valuation.entailmentCheck(THEORY_OF_TYPE_BASED, ent_lit );
- if( et.first ){
- Trace("strings-entail") << "Strings entailment : " << ent_lit << " is entailed in the current context." << std::endl;
- Trace("strings-entail") << " explanation was : " << et.second << std::endl;
- conc = e==0 ? eq1 : eq2;
- antec_new_lits.push_back( et.second );
- break;
- }
- }
- }
- if( conc.isNull() ){
- conc = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 ));
- }
-
-
- sendInference( antec, antec_new_lits, conc, "S-Split(VAR)", true );
- //++(d_statistics.d_eq_splits);
- return true;
- }
- }
- }
- }
- } while(success);
+ processSimpleNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false, rindex, pinfer );
+ if( hasProcessed() ){
+ return;
+ }else if( !pinfer.empty() && pinfer.back().d_id==1 ){
+ break;
+ }
}
}
- if(!flag_lb) {
- return false;
- }
}
- if(flag_lb) {
- if(processLoop(c_lb_exp, normal_forms, normal_form_src, c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index)) {
- return true;
+ if( !pinfer.empty() ){
+ //now, determine which of the possible inferences we want to add
+ int use_index = -1;
+ Trace("strings-solve") << "Possible inferences (" << pinfer.size() << ") : " << std::endl;
+ unsigned min_id = 9;
+ unsigned max_index = 0;
+ for( unsigned i=0; i<pinfer.size(); i++ ){
+ Trace("strings-solve") << "From " << pinfer[i].d_i << " / " << pinfer[i].d_j << " (rev=" << pinfer[i].d_rev << ") : ";
+ Trace("strings-solve") << pinfer[i].d_conc << " by " << pinfer[i].getId() << std::endl;
+ if( use_index==-1 || pinfer[i].d_id<min_id || ( pinfer[i].d_id==min_id && pinfer[i].d_index>max_index ) ){
+ min_id = pinfer[i].d_id;
+ max_index = pinfer[i].d_index;
+ use_index = i;
+ }
+ }
+ //send the inference
+ sendInference( pinfer[use_index].d_ant, pinfer[use_index].d_antn, pinfer[use_index].d_conc, pinfer[use_index].getId(), pinfer[use_index].sendAsLemma() );
+ for( std::map< int, std::vector< Node > >::iterator it = pinfer[use_index].d_new_skolem.begin(); it != pinfer[use_index].d_new_skolem.end(); ++it ){
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ if( it->first==0 ){
+ sendLengthLemma( it->second[i] );
+ }else if( it->first==1 ){
+ registerNonEmptySkolem( it->second[i] );
+ }
+ }
}
}
+}
- return false;
+bool TheoryStrings::InferInfo::sendAsLemma() {
+ return true;
}
-bool TheoryStrings::processReverseNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+void TheoryStrings::processReverseNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j ) {
+ unsigned i, unsigned j, unsigned& index, unsigned rproc, std::vector< InferInfo >& pinfer ) {
//reverse normal form of i, j
std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
- unsigned index = 0;
- bool ret = processSimpleNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, true );
+ processSimpleNEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, true, rproc, pinfer );
//reverse normal form of i, j
std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
-
- return ret;
}
-bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+//rproc is the # is the size of suffix that is identical
+void TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j, unsigned& index, bool isRev ) {
+ unsigned i, unsigned j, unsigned& index, bool isRev, unsigned rproc, std::vector< InferInfo >& pinfer ) {
+ Assert( rproc<=normal_forms[i].size() && rproc<=normal_forms[j].size() );
bool success;
do {
success = false;
//if we are at the end
- if(index==normal_forms[i].size() || index==normal_forms[j].size() ) {
- if( index==normal_forms[i].size() && index==normal_forms[j].size() ) {
+ if( index==(normal_forms[i].size()-rproc) || index==(normal_forms[j].size()-rproc) ){
+ if( index==(normal_forms[i].size()-rproc) && index==(normal_forms[j].size()-rproc) ){
//we're done
- } else {
+ }else{
//the remainder must be empty
- unsigned k = index==normal_forms[i].size() ? j : i;
+ unsigned k = index==(normal_forms[i].size()-rproc) ? j : i;
unsigned index_k = index;
//Node eq_exp = mkAnd( curr_exp );
std::vector< Node > curr_exp;
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, isRev, curr_exp );
- while(!d_conflict && index_k<normal_forms[k].size()) {
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, curr_exp );
+ while( !d_conflict && index_k<(normal_forms[k].size()-rproc) ){
//can infer that this string must be empty
Node eq = normal_forms[k][index_k].eqNode( d_emptyString );
//Trace("strings-lemma") << "Strings: Infer " << eq << " from " << eq_exp << std::endl;
Assert( !areEqual( d_emptyString, normal_forms[k][index_k] ) );
- sendInference( curr_exp, eq, "EQ_Endpoint" );
+ sendInference( curr_exp, eq, "N_EndpointEmp" );
index_k++;
}
- return true;
}
}else{
Trace("strings-solve-debug") << "Process " << normal_forms[i][index] << " ... " << normal_forms[j][index] << std::endl;
@@ -2279,23 +2405,22 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
//eq = Rewriter::rewrite( eq );
Node length_eq = length_term_i.eqNode( length_term_j );
//temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, isRev, temp_exp );
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, temp_exp );
temp_exp.push_back(length_eq);
- sendInference( temp_exp, eq, "LengthEq" );
- return true;
- }else if( ( normal_forms[i][index].getKind()!=kind::CONST_STRING && index==normal_forms[i].size()-1 ) ||
- ( normal_forms[j][index].getKind()!=kind::CONST_STRING && index==normal_forms[j].size()-1 ) ){
+ sendInference( temp_exp, eq, "N_Unify" );
+ return;
+ }else if( ( normal_forms[i][index].getKind()!=kind::CONST_STRING && index==normal_forms[i].size()-rproc-1 ) ||
+ ( normal_forms[j][index].getKind()!=kind::CONST_STRING && index==normal_forms[j].size()-rproc-1 ) ){
Trace("strings-solve-debug") << "Simple Case 3 : at endpoint" << std::endl;
- Node conc;
std::vector< Node > antec;
//antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, isRev, antec );
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, antec );
std::vector< Node > eqn;
for( unsigned r=0; r<2; r++ ) {
int index_k = index;
int k = r==0 ? i : j;
std::vector< Node > eqnc;
- for( unsigned index_l=index_k; index_l<normal_forms[k].size(); index_l++ ) {
+ for( unsigned index_l=index_k; index_l<(normal_forms[k].size()-rproc); index_l++ ) {
if(isRev) {
eqnc.insert(eqnc.begin(), normal_forms[k][index_l] );
} else {
@@ -2304,18 +2429,17 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
}
eqn.push_back( mkConcat( eqnc ) );
}
- if( !areEqual( eqn[0], eqn[1] ) ) {
- conc = eqn[0].eqNode( eqn[1] );
- sendInference( antec, conc, "ENDPOINT", true );
- return true;
+ if( !areEqual( eqn[0], eqn[1] ) ){
+ sendInference( antec, eqn[0].eqNode( eqn[1] ), "N_EndpointEq", true );
+ return;
}else{
Assert( normal_forms[i].size()==normal_forms[j].size() );
- index = normal_forms[i].size();
+ index = normal_forms[i].size()-rproc;
}
- } else if( normal_forms[i][index].isConst() && normal_forms[j][index].isConst() ){
+ }else if( normal_forms[i][index].isConst() && normal_forms[j][index].isConst() ){
Node const_str = normal_forms[i][index];
Node other_str = normal_forms[j][index];
- Trace("strings-solve-debug") << "Simple Case 3 : Const Split : " << const_str << " vs " << other_str << std::endl;
+ Trace("strings-solve-debug") << "Simple Case 3 : Const Split : " << const_str << " vs " << other_str << " at index " << index << ", isRev = " << isRev << std::endl;
unsigned len_short = const_str.getConst<String>().size() <= other_str.getConst<String>().size() ? const_str.getConst<String>().size() : other_str.getConst<String>().size();
bool isSameFix = isRev ? const_str.getConst<String>().rstrncmp(other_str.getConst<String>(), len_short): const_str.getConst<String>().strncmp(other_str.getConst<String>(), len_short);
if( isSameFix ) {
@@ -2323,12 +2447,24 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
//k is the index of the string that is shorter
int k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? i : j;
int l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? j : i;
- if(isRev) {
+ //update the nf exp dependencies
+ //notice this is not critical for soundness: not doing the below incrementing will only lead to overapproximating when antecedants are required in explanations
+ for( std::map< Node, std::map< bool, int > >::iterator itnd = normal_forms_exp_depend[l].begin(); itnd != normal_forms_exp_depend[l].end(); ++itnd ){
+ for( std::map< bool, int >::iterator itnd2 = itnd->second.begin(); itnd2 != itnd->second.end(); ++itnd2 ){
+ //see if this can be incremented: it can if it is not relevant to the current index
+ Assert( itnd2->second>=0 && itnd2->second<=(int)normal_forms[l].size() );
+ bool increment = (itnd2->first==isRev) ? itnd2->second>(int)index : ( (int)normal_forms[l].size()-1-itnd2->second )<(int)index;
+ if( increment ){
+ normal_forms_exp_depend[l][itnd->first][itnd2->first] = itnd2->second + 1;
+ }
+ }
+ }
+ if( isRev ){
int new_len = normal_forms[l][index].getConst<String>().size() - len_short;
Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index].getConst<String>().substr(0, new_len) );
Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index] << " into " << normal_forms[k][index] << ", " << remainderStr << std::endl;
normal_forms[l].insert( normal_forms[l].begin()+index + 1, remainderStr );
- } else {
+ }else{
Node remainderStr = NodeManager::currentNM()->mkConst(normal_forms[l][index].getConst<String>().substr(len_short));
Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index] << " into " << normal_forms[k][index] << ", " << remainderStr << std::endl;
normal_forms[l].insert( normal_forms[l].begin()+index + 1, remainderStr );
@@ -2336,29 +2472,231 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
normal_forms[l][index] = normal_forms[k][index];
index++;
success = true;
- } else {
+ }else{
+ //conflict
std::vector< Node > antec;
- //curr_exp is conflict
- //antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
- getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, isRev, antec );
- sendInference( antec, d_false, "Const Conflict", true );
- return true;
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, antec );
+ sendInference( antec, d_false, "N_Const", true );
+ return;
+ }
+ }else{
+ //construct the candidate inference "info"
+ InferInfo info;
+ info.d_index = index;
+ //for debugging
+ info.d_i = i;
+ info.d_j = j;
+ info.d_rev = isRev;
+ bool info_valid = false;
+ Assert( index<normal_forms[i].size()-rproc && index<normal_forms[j].size()-rproc );
+ std::vector< Node > lexp;
+ Node length_term_i = getLength( normal_forms[i][index], lexp );
+ Node length_term_j = getLength( normal_forms[j][index], lexp );
+ //split on equality between string lengths (note that splitting on equality between strings is worse since it is harder to process)
+ if( !areDisequal( length_term_i, length_term_j ) && !areEqual( length_term_i, length_term_j ) &&
+ normal_forms[i][index].getKind()!=kind::CONST_STRING && normal_forms[j][index].getKind()!=kind::CONST_STRING ){ //AJR: remove the latter 2 conditions?
+ Trace("strings-solve-debug") << "Non-simple Case 1 : string lengths neither equal nor disequal" << std::endl;
+ //try to make the lengths equal via splitting on demand
+ Node length_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j );
+ length_eq = Rewriter::rewrite( length_eq );
+ //set info
+ info.d_conc = NodeManager::currentNM()->mkNode( kind::OR, length_eq, length_eq.negate() );
+ info.d_pending_phase[ length_eq ] = true;
+ info.d_id = 3;
+ info_valid = true;
+ }else{
+ Trace("strings-solve-debug") << "Non-simple Case 2 : must compare strings" << std::endl;
+ int loop_in_i = -1;
+ int loop_in_j = -1;
+ if( detectLoop( normal_forms, i, j, index, loop_in_i, loop_in_j, rproc ) ){
+ if( !isRev ){ //FIXME
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, info.d_ant );
+ //set info
+ if( processLoop( normal_forms, normal_form_src, i, j, loop_in_i!=-1 ? i : j, loop_in_i!=-1 ? j : i, loop_in_i!=-1 ? loop_in_i : loop_in_j, index, info ) ){
+ info_valid = true;
+ }
+ }
+ }else{
+ //AJR: length entailment here?
+ if( normal_forms[i][index].getKind() == kind::CONST_STRING || normal_forms[j][index].getKind() == kind::CONST_STRING ){
+ unsigned const_k = normal_forms[i][index].getKind() == kind::CONST_STRING ? i : j;
+ unsigned nconst_k = normal_forms[i][index].getKind() == kind::CONST_STRING ? j : i;
+ Node other_str = normal_forms[nconst_k][index];
+ Assert( other_str.getKind()!=kind::CONST_STRING, "Other string is not constant." );
+ Assert( other_str.getKind()!=kind::STRING_CONCAT, "Other string is not CONCAT." );
+ if( !d_equalityEngine.areDisequal( other_str, d_emptyString, true ) ){
+ Node eq = other_str.eqNode( d_emptyString );
+ //set info
+ info.d_conc = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
+ info.d_id = 4;
+ info_valid = true;
+ }else{
+ if( !isRev ){ //FIXME
+ Node xnz = other_str.eqNode( d_emptyString ).negate();
+ unsigned index_nc_k = index+1;
+ //Node next_const_str = TheoryStringsRewriter::collectConstantStringAt( normal_forms[nconst_k], index_nc_k, false );
+ unsigned start_index_nc_k = index+1;
+ Node next_const_str = TheoryStringsRewriter::getNextConstantAt( normal_forms[nconst_k], start_index_nc_k, index_nc_k, false );
+ if( !next_const_str.isNull() ) {
+ unsigned index_c_k = index;
+ Node const_str = TheoryStringsRewriter::collectConstantStringAt( normal_forms[const_k], index_c_k, false );
+ Assert( !const_str.isNull() );
+ CVC4::String stra = const_str.getConst<String>();
+ CVC4::String strb = next_const_str.getConst<String>();
+ //since non-empty, we start with charecter #1
+ size_t p;
+ if( isRev ){
+ CVC4::String stra1 = stra.prefix( stra.size()-1 );
+ p = stra.size() - stra1.roverlap(strb);
+ Trace("strings-csp-debug") << "Compute roverlap : " << const_str << " " << next_const_str << std::endl;
+ size_t p2 = stra1.rfind(strb);
+ p = p2==std::string::npos ? p : ( p>p2+1? p2+1 : p );
+ Trace("strings-csp-debug") << "overlap : " << stra1 << " " << strb << " returned " << p << " " << p2 << " " << (p2==std::string::npos) << std::endl;
+ }else{
+ CVC4::String stra1 = stra.substr( 1 );
+ p = stra.size() - stra1.overlap(strb);
+ Trace("strings-csp-debug") << "Compute overlap : " << const_str << " " << next_const_str << std::endl;
+ size_t p2 = stra1.find(strb);
+ p = p2==std::string::npos ? p : ( p>p2+1? p2+1 : p );
+ Trace("strings-csp-debug") << "overlap : " << stra1 << " " << strb << " returned " << p << " " << p2 << " " << (p2==std::string::npos) << std::endl;
+ }
+ if( p>1 ){
+ if( start_index_nc_k==index+1 ){
+ info.d_ant.push_back( xnz );
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend,
+ const_k, nconst_k, index_c_k, index_nc_k, isRev, info.d_ant );
+ Node prea = p==stra.size() ? const_str : NodeManager::currentNM()->mkConst( isRev ? stra.suffix( p ) : stra.prefix( p ) );
+ Node sk = mkSkolemCached( other_str, prea, isRev ? sk_id_c_spt_rev : sk_id_c_spt, "c_spt", -1 );
+ Trace("strings-csp") << "Const Split: " << prea << " is removed from " << stra << " due to " << strb << ", p=" << p << std::endl;
+ //set info
+ info.d_conc = other_str.eqNode( isRev ? mkConcat( sk, prea ) : mkConcat(prea, sk) );
+ info.d_new_skolem[0].push_back( sk );
+ info.d_id = 1;
+ info_valid = true;
+ }
+ /* FIXME for isRev, speculative
+ else if( options::stringLenPropCsp() ){
+ //propagate length constraint
+ std::vector< Node > cc;
+ for( unsigned i=index; i<start_index_nc_k; i++ ){
+ cc.push_back( normal_forms[nconst_k][i] );
+ }
+ Node lt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, mkConcat( cc ) );
+ conc = NodeManager::currentNM()->mkNode( kind::GEQ, lt, NodeManager::currentNM()->mkConst( Rational(p) ) );
+ sendInference( ant, conc, "S-Split(CSP-P)-lprop", true );
+ }
+ */
+ }
+ }
+ if( !info_valid ){
+ info.d_ant.push_back( xnz );
+ Node const_str = normal_forms[const_k][index];
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, info.d_ant );
+ CVC4::String stra = const_str.getConst<String>();
+ if( options::stringBinaryCsp() && stra.size()>3 ){
+ //split string in half
+ Node c_firstHalf = NodeManager::currentNM()->mkConst( isRev ? stra.substr( stra.size()/2 ) : stra.substr(0, stra.size()/2 ) );
+ Node sk = mkSkolemCached( other_str, c_firstHalf , isRev ? sk_id_vc_bin_spt_rev : sk_id_vc_bin_spt, "cb_spt", -1 );
+ Trace("strings-csp") << "Const Split: " << c_firstHalf << " is removed from " << const_str << " (binary) " << std::endl;
+ info.d_conc = NodeManager::currentNM()->mkNode( kind::OR, other_str.eqNode( isRev ? mkConcat( sk, c_firstHalf ) : mkConcat( c_firstHalf, sk ) ),
+ NodeManager::currentNM()->mkNode( kind::AND,
+ sk.eqNode( d_emptyString ).negate(),
+ c_firstHalf.eqNode( isRev ? mkConcat( sk, other_str ) : mkConcat( other_str, sk ) ) ) );
+ info.d_new_skolem[0].push_back( sk );
+ info.d_id = 5;
+ info_valid = true;
+ }else{
+ // normal v/c split
+ Node firstChar = stra.size() == 1 ? const_str : NodeManager::currentNM()->mkConst( isRev ? stra.suffix( 1 ) : stra.prefix( 1 ) );
+ Node sk = mkSkolemCached( other_str, firstChar, isRev ? sk_id_vc_spt_rev : sk_id_vc_spt, "c_spt", -1 );
+ Trace("strings-csp") << "Const Split: " << firstChar << " is removed from " << const_str << " (serial) " << std::endl;
+ info.d_conc = other_str.eqNode( isRev ? mkConcat( sk, firstChar ) : mkConcat(firstChar, sk) );
+ info.d_new_skolem[0].push_back( sk );
+ info.d_id = 6;
+ info_valid = true;
+ }
+ }
+ }
+ }
+ }else{
+ int lentTestSuccess = -1;
+ Node lentTestExp;
+ if( options::stringCheckEntailLen() ){
+ //check entailment
+ for( unsigned e=0; e<2; e++ ){
+ Node t = e==0 ? normal_forms[i][index] : normal_forms[j][index];
+ //do not infer constants are larger than variables
+ if( t.getKind()!=kind::CONST_STRING ){
+ Node lt1 = e==0 ? length_term_i : length_term_j;
+ Node lt2 = e==0 ? length_term_j : length_term_i;
+ Node ent_lit = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::GT, lt1, lt2 ) );
+ std::pair<bool, Node> et = d_valuation.entailmentCheck( THEORY_OF_TYPE_BASED, ent_lit );
+ if( et.first ){
+ Trace("strings-entail") << "Strings entailment : " << ent_lit << " is entailed in the current context." << std::endl;
+ Trace("strings-entail") << " explanation was : " << et.second << std::endl;
+ lentTestSuccess = e;
+ lentTestExp = et.second;
+ break;
+ }
+ }
+ }
+ }
+
+ getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, info.d_ant );
+ //x!=e /\ y!=e
+ for(unsigned xory=0; xory<2; xory++) {
+ Node x = xory==0 ? normal_forms[i][index] : normal_forms[j][index];
+ Node xgtz = x.eqNode( d_emptyString ).negate();
+ if( d_equalityEngine.areDisequal( x, d_emptyString, true ) ) {
+ info.d_ant.push_back( xgtz );
+ } else {
+ info.d_antn.push_back( xgtz );
+ }
+ }
+ Node sk = mkSkolemCached( normal_forms[i][index], normal_forms[j][index], isRev ? sk_id_v_spt_rev : sk_id_v_spt, "v_spt", -1 );
+ //must add length requirement
+ info.d_new_skolem[1].push_back( sk );
+ Node eq1 = normal_forms[i][index].eqNode( isRev ? mkConcat(sk, normal_forms[j][index]) : mkConcat(normal_forms[j][index], sk) );
+ Node eq2 = normal_forms[j][index].eqNode( isRev ? mkConcat(sk, normal_forms[i][index]) : mkConcat(normal_forms[i][index], sk) );
+
+ if( lentTestSuccess!=-1 ){
+ info.d_antn.push_back( lentTestExp );
+ info.d_conc = lentTestSuccess==0 ? eq1 : eq2;
+ info.d_id = 2;
+ info_valid = true;
+ }else{
+ Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
+ if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
+ info.d_ant.push_back( ldeq );
+ }else{
+ info.d_antn.push_back(ldeq);
+ }
+ //set info
+ info.d_conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ info.d_id = 7;
+ info_valid = true;
+ }
+ }
+ }
+ }
+ if( info_valid ){
+ pinfer.push_back( info );
+ Assert( !success );
}
}
}
}
}while( success );
- return false;
}
-bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms, int i, int j, int index, int &loop_in_i, int &loop_in_j) {
+bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms, int i, int j, int index, int &loop_in_i, int &loop_in_j, unsigned rproc ){
int has_loop[2] = { -1, -1 };
if( options::stringLB() != 2 ) {
for( unsigned r=0; r<2; r++ ) {
int n_index = (r==0 ? i : j);
int other_n_index = (r==0 ? j : i);
if( normal_forms[other_n_index][index].getKind() != kind::CONST_STRING ) {
- for( unsigned lp = index+1; lp<normal_forms[n_index].size(); lp++ ){
+ for( unsigned lp = index+1; lp<normal_forms[n_index].size()-rproc; lp++ ){
if( normal_forms[n_index][lp]==normal_forms[other_n_index][index] ){
has_loop[r] = lp;
break;
@@ -2372,13 +2710,14 @@ bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms
loop_in_j = has_loop[1];
return true;
} else {
+ Trace("strings-solve-debug") << "No loops detected." << std::endl;
return false;
}
}
//xs(zy)=t(yz)xr
-bool TheoryStrings::processLoop( std::vector< Node > &antec, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
- int i, int j, int loop_n_index, int other_n_index, int loop_index, int index) {
+bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ int i, int j, int loop_n_index, int other_n_index, int loop_index, int index, InferInfo& info ){
if( options::stringAbortLoop() ){
Message() << "Looping word equation encountered." << std::endl;
exit( 1 );
@@ -2417,11 +2756,11 @@ bool TheoryStrings::processLoop( std::vector< Node > &antec, std::vector< std::v
//Trace("strings-loop") << "Lemma Cache: " << normal_form_src[i] << " vs " << normal_form_src[j] << std::endl;
//TODO: can be more general
- if( s_zy.isConst() && r.isConst() && r != d_emptyString) {
+ if( s_zy.isConst() && r.isConst() && r!=d_emptyString) {
int c;
bool flag = true;
if(s_zy.getConst<String>().tailcmp( r.getConst<String>(), c ) ) {
- if(c >= 0) {
+ if( c>=0) {
s_zy = NodeManager::currentNM()->mkConst( s_zy.getConst<String>().substr(0, c) );
r = d_emptyString;
vec_r.clear();
@@ -2429,29 +2768,37 @@ bool TheoryStrings::processLoop( std::vector< Node > &antec, std::vector< std::v
flag = false;
}
}
- if(flag) {
+ if( flag ){
Trace("strings-loop") << "Strings::Loop: tails are different." << std::endl;
- sendInference( antec, conc, "Loop Conflict", true );
- return true;
+ sendInference( info.d_ant, conc, "Loop Conflict", true );
+ return false;
}
}
//require that x is non-empty
+ Node split_eq;
if( !areDisequal( normal_forms[loop_n_index][loop_index], d_emptyString ) ){
//try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
- sendSplit( normal_forms[loop_n_index][loop_index], d_emptyString, "Len-Split(Loop-X)" );
- } else if( !areDisequal( t_yz, d_emptyString ) && t_yz.getKind()!=kind::CONST_STRING ) {
+ split_eq = normal_forms[loop_n_index][loop_index].eqNode( d_emptyString );
+ }else if( !areDisequal( t_yz, d_emptyString ) && t_yz.getKind()!=kind::CONST_STRING ) {
//try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
- sendSplit( t_yz, d_emptyString, "Len-Split(Loop-YZ)" );
- } else {
+ split_eq = t_yz.eqNode( d_emptyString );
+ }
+ if( !split_eq.isNull() ){
+ info.d_conc = NodeManager::currentNM()->mkNode( kind::OR, split_eq, split_eq.negate() );
+ info.d_id = 4;
+ return true;
+ }else{
//need to break
- antec.push_back( normal_forms[loop_n_index][loop_index].eqNode( d_emptyString ).negate() );
+ info.d_ant.push_back( normal_forms[loop_n_index][loop_index].eqNode( d_emptyString ).negate() );
if( t_yz.getKind()!=kind::CONST_STRING ) {
- antec.push_back( t_yz.eqNode( d_emptyString ).negate() );
+ info.d_ant.push_back( t_yz.eqNode( d_emptyString ).negate() );
}
- Node ant = mkExplain( antec );
- if(d_loop_antec.find(ant) == d_loop_antec.end()) {
- d_loop_antec.insert(ant);
+ Node ant = mkExplain( info.d_ant );
+ if( d_loop_antec.find( ant ) == d_loop_antec.end() ){
+ d_loop_antec.insert( ant );
+ info.d_ant.clear();
+ info.d_antn.push_back( ant );
Node str_in_re;
if( s_zy == t_yz &&
@@ -2531,26 +2878,23 @@ bool TheoryStrings::processLoop( std::vector< Node > &antec, std::vector< std::v
//we will be done
addNormalFormPair( normal_form_src[i], normal_form_src[j] );
if( options::stringProcessLoop() ){
- sendLemma( ant, conc, "F-LOOP" );
- ++(d_statistics.d_loop_lemmas);
+ info.d_conc = conc;
+ info.d_id = 8;
+ return true;
}else{
d_out->setIncomplete();
- return false;
}
-
- } else {
+ }else{
Trace("strings-loop") << "Strings::Loop: loop lemma for " << ant << " has already added." << std::endl;
addNormalFormPair( normal_form_src[i], normal_form_src[j] );
- return false;
}
}
- return true;
}
- return true;
+ return false;
}
//return true for lemma, false if we succeed
-bool TheoryStrings::processDeq( Node ni, Node nj ) {
+void TheoryStrings::processDeq( Node ni, Node nj ) {
//Assert( areDisequal( ni, nj ) );
if( d_normal_forms[ni].size()>1 || d_normal_forms[nj].size()>1 ){
std::vector< Node > nfi;
@@ -2560,7 +2904,7 @@ bool TheoryStrings::processDeq( Node ni, Node nj ) {
int revRet = processReverseDeq( nfi, nfj, ni, nj );
if( revRet!=0 ){
- return revRet==-1;
+ return;
}
nfi.clear();
@@ -2572,47 +2916,88 @@ bool TheoryStrings::processDeq( Node ni, Node nj ) {
while( index<nfi.size() || index<nfj.size() ){
int ret = processSimpleDeq( nfi, nfj, ni, nj, index, false );
if( ret!=0 ) {
- return ret==-1;
- } else {
+ return;
+ }else{
Assert( index<nfi.size() && index<nfj.size() );
Node i = nfi[index];
Node j = nfj[index];
Trace("strings-solve-debug") << "...Processing(DEQ) " << i << " " << j << std::endl;
- if( !areEqual( i, j ) ) {
+ if( !areEqual( i, j ) ){
Assert( i.getKind()!=kind::CONST_STRING || j.getKind()!=kind::CONST_STRING );
std::vector< Node > lexp;
Node li = getLength( i, lexp );
Node lj = getLength( j, lexp );
- if( areDisequal(li, lj) ){
- //if( i.getKind()==kind::CONST_STRING || j.getKind()==kind::CONST_STRING ){
-
- Trace("strings-solve") << "Non-Simple Case 1 : add lemma " << std::endl;
- //must add lemma
- std::vector< Node > antec;
- std::vector< Node > antec_new_lits;
- antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
- antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
- //check disequal
- if( areDisequal( ni, nj ) ){
- antec.push_back( ni.eqNode( nj ).negate() );
+ if( areDisequal( li, lj ) ){
+ if( i.getKind()==kind::CONST_STRING || j.getKind()==kind::CONST_STRING ){
+ //check if empty
+ Node const_k = i.getKind() == kind::CONST_STRING ? i : j;
+ Node nconst_k = i.getKind() == kind::CONST_STRING ? j : i;
+ Node lnck = i.getKind() == kind::CONST_STRING ? lj : li;
+ if( !d_equalityEngine.areDisequal( nconst_k, d_emptyString, true ) ){
+ Node eq = nconst_k.eqNode( d_emptyString );
+ Node conc = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
+ sendInference( d_empty_vec, conc, "D-DISL-Emp-Split" );
+ return;
+ }else{
+ //split on first character
+ CVC4::String str = const_k.getConst<String>();
+ Node firstChar = str.size() == 1 ? const_k : NodeManager::currentNM()->mkConst( str.prefix( 1 ) );
+ if( areEqual( lnck, d_one ) ){
+ if( areDisequal( firstChar, nconst_k ) ){
+ return;
+ }else if( !areEqual( firstChar, nconst_k ) ){
+ //splitting on demand : try to make them disequal
+ Node eq = firstChar.eqNode( nconst_k );
+ sendSplit( firstChar, nconst_k, "S-Split(DEQL-Const)" );
+ eq = Rewriter::rewrite( eq );
+ d_pending_req_phase[ eq ] = false;
+ return;
+ }
+ }else{
+ Node sk = mkSkolemCached( nconst_k, firstChar, sk_id_dc_spt, "dc_spt", 2 );
+ Node skr = mkSkolemCached( nconst_k, firstChar, sk_id_dc_spt_rem, "dc_spt_rem", -1 );
+ Node eq1 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, skr ) );
+ eq1 = Rewriter::rewrite( eq1 );
+ Node eq2 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, firstChar, skr ) );
+ std::vector< Node > antec;
+ antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ antec.push_back( nconst_k.eqNode( d_emptyString ).negate() );
+ sendInference( antec, NodeManager::currentNM()->mkNode( kind::OR,
+ NodeManager::currentNM()->mkNode( kind::AND, eq1, sk.eqNode( firstChar ).negate() ), eq2 ), "D-DISL-CSplit" );
+ d_pending_req_phase[ eq1 ] = true;
+ return;
+ }
+ }
}else{
- antec_new_lits.push_back( ni.eqNode( nj ).negate() );
+ Trace("strings-solve") << "Non-Simple Case 1 : add lemma " << std::endl;
+ //must add lemma
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ //check disequal
+ if( areDisequal( ni, nj ) ){
+ antec.push_back( ni.eqNode( nj ).negate() );
+ }else{
+ antec_new_lits.push_back( ni.eqNode( nj ).negate() );
+ }
+ antec_new_lits.push_back( li.eqNode( lj ).negate() );
+ std::vector< Node > conc;
+ Node sk1 = mkSkolemCached( i, j, sk_id_deq_x, "x_dsplit" );
+ Node sk2 = mkSkolemCached( i, j, sk_id_deq_y, "y_dsplit" );
+ Node sk3 = mkSkolemCached( i, j, sk_id_deq_z, "z_dsplit", 1 );
+ //Node nemp = sk3.eqNode(d_emptyString).negate();
+ //conc.push_back(nemp);
+ Node lsk1 = mkLength( sk1 );
+ conc.push_back( lsk1.eqNode( li ) );
+ Node lsk2 = mkLength( sk2 );
+ conc.push_back( lsk2.eqNode( lj ) );
+ conc.push_back( NodeManager::currentNM()->mkNode( kind::OR, j.eqNode( mkConcat( sk1, sk3 ) ), i.eqNode( mkConcat( sk2, sk3 ) ) ) );
+ sendInference( antec, antec_new_lits, NodeManager::currentNM()->mkNode( kind::AND, conc ), "D-DISL-Split" );
+ ++(d_statistics.d_deq_splits);
+ return;
}
- antec_new_lits.push_back( li.eqNode( lj ).negate() );
- std::vector< Node > conc;
- Node sk1 = mkSkolemCached( i, j, sk_id_deq_x, "x_dsplit" );
- Node sk2 = mkSkolemCached( i, j, sk_id_deq_y, "y_dsplit" );
- Node sk3 = mkSkolemCached( i, j, sk_id_deq_z, "z_dsplit", 1 );
- //Node nemp = sk3.eqNode(d_emptyString).negate();
- //conc.push_back(nemp);
- Node lsk1 = mkLength( sk1 );
- conc.push_back( lsk1.eqNode( li ) );
- Node lsk2 = mkLength( sk2 );
- conc.push_back( lsk2.eqNode( lj ) );
- conc.push_back( NodeManager::currentNM()->mkNode( kind::OR, j.eqNode( mkConcat( sk1, sk3 ) ), i.eqNode( mkConcat( sk2, sk3 ) ) ) );
- sendInference( antec, antec_new_lits, NodeManager::currentNM()->mkNode( kind::AND, conc ), "D-DISL-Split" );
- ++(d_statistics.d_deq_splits);
- return true;
}else if( areEqual( li, lj ) ){
Assert( !areDisequal( i, j ) );
//splitting on demand : try to make them disequal
@@ -2620,14 +3005,14 @@ bool TheoryStrings::processDeq( Node ni, Node nj ) {
sendSplit( i, j, "S-Split(DEQL)" );
eq = Rewriter::rewrite( eq );
d_pending_req_phase[ eq ] = false;
- return true;
+ return;
}else{
//splitting on demand : try to make lengths equal
Node eq = li.eqNode( lj );
sendSplit( li, lj, "D-Split" );
eq = Rewriter::rewrite( eq );
d_pending_req_phase[ eq ] = true;
- return true;
+ return;
}
}
index++;
@@ -2635,7 +3020,6 @@ bool TheoryStrings::processDeq( Node ni, Node nj ) {
}
Assert( false );
}
- return false;
}
int TheoryStrings::processReverseDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj ) {
@@ -2653,9 +3037,19 @@ int TheoryStrings::processReverseDeq( std::vector< Node >& nfi, std::vector< Nod
return ret;
}
-int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev ) {
+int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev ){
+ //see if one side is constant, if so, we can approximate as containment
+ for( unsigned i=0; i<2; i++ ){
+ Node c = getConstantEqc( i==0 ? ni : nj );
+ if( !c.isNull() ){
+ int findex, lindex;
+ if( !TheoryStringsRewriter::canConstantContainList( c, i==0 ? nfj : nfi, findex, lindex ) ){
+ return 1;
+ }
+ }
+ }
while( index<nfi.size() || index<nfj.size() ) {
- if( index>=nfi.size() || index>=nfj.size() ) {
+ if( index>=nfi.size() || index>=nfj.size() ){
Trace("strings-solve-debug") << "Disequality normalize empty" << std::endl;
std::vector< Node > ant;
//we have a conflict : because the lengths are equal, the remainder needs to be empty, which will lead to a conflict
@@ -2673,7 +3067,7 @@ int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node
conc = Rewriter::rewrite( conc );
sendInference( ant, conc, "Disequality Normalize Empty", true);
return -1;
- } else {
+ }else{
Node i = nfi[index];
Node j = nfj[index];
Trace("strings-solve-debug") << "...Processing(QED) " << i << " " << j << std::endl;
@@ -2687,12 +3081,12 @@ int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node
Node nk = i.getConst<String>().size() < j.getConst<String>().size() ? i : j;
Node nl = i.getConst<String>().size() < j.getConst<String>().size() ? j : i;
Node remainderStr;
- if(isRev) {
+ if( isRev ){
int new_len = nl.getConst<String>().size() - len_short;
remainderStr = NodeManager::currentNM()->mkConst( nl.getConst<String>().substr(0, new_len) );
Trace("strings-solve-debug-test") << "Rev. Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
} else {
- remainderStr = NodeManager::currentNM()->mkConst( j.getConst<String>().substr(len_short) );
+ remainderStr = NodeManager::currentNM()->mkConst( nl.getConst<String>().substr( len_short ) );
Trace("strings-solve-debug-test") << "Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
}
if( i.getConst<String>().size() < j.getConst<String>().size() ) {
@@ -2702,18 +3096,18 @@ int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node
nfi.insert( nfi.begin() + index + 1, remainderStr );
nfi[index] = nfj[index];
}
- } else {
+ }else{
return 1;
}
- } else {
+ }else{
std::vector< Node > lexp;
Node li = getLength( i, lexp );
Node lj = getLength( j, lexp );
- if( areEqual( li, lj ) && areDisequal( i, j ) ) {
+ if( areEqual( li, lj ) && areDisequal( i, j ) ){
Trace("strings-solve") << "Simple Case 2 : found equal length disequal sub strings " << i << " " << j << std::endl;
//we are done: D-Remove
return 1;
- } else {
+ }else{
return 0;
}
}
@@ -2781,14 +3175,24 @@ void TheoryStrings::registerTerm( Node n, int effort ) {
if(n.getType().isString()) {
//register length information:
// for variables, split on empty vs positive length
- // for concat/const, introduce proxy var and state length relation
+ // for concat/const/replace, introduce proxy var and state length relation
+ Node lsum;
+ bool processed = false;
if( n.getKind()!=kind::STRING_CONCAT && n.getKind()!=kind::CONST_STRING ) {
- if( d_length_intro_vars.find(n)==d_length_intro_vars.end() ) {
- sendLengthLemma( n );
- ++(d_statistics.d_splits);
+ if( d_length_lemma_terms_cache.find( n )==d_length_lemma_terms_cache.end() ){
+ Node lsumb = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n );
+ lsum = Rewriter::rewrite( lsumb );
+ // can register length term if it does not rewrite
+ if( lsum==lsumb ){
+ sendLengthLemma( n );
+ processed = true;
+ }
+ }else{
+ processed = true;
}
- } else {
- Node sk = mkSkolemS("lsym", 2);
+ }
+ if( !processed ){
+ Node sk = mkSkolemS( "lsym", -1 );
StringsProxyVarAttribute spva;
sk.setAttribute(spva,true);
Node eq = Rewriter::rewrite( sk.eqNode(n) );
@@ -2797,8 +3201,7 @@ void TheoryStrings::registerTerm( Node n, int effort ) {
Trace("strings-assert") << "(assert " << eq << ")" << std::endl;
d_out->lemma(eq);
Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
- Node lsum;
- if( n.getKind() == kind::STRING_CONCAT ) {
+ if( n.getKind()==kind::STRING_CONCAT ){
std::vector<Node> node_vec;
for( unsigned i=0; i<n.getNumChildren(); i++ ) {
if( n[i].getAttribute(StringsProxyVarAttribute()) ){
@@ -2810,16 +3213,18 @@ void TheoryStrings::registerTerm( Node n, int effort ) {
}
}
lsum = NodeManager::currentNM()->mkNode( kind::PLUS, node_vec );
- } else if( n.getKind() == kind::CONST_STRING ) {
+ lsum = Rewriter::rewrite( lsum );
+ }else if( n.getKind()==kind::CONST_STRING ){
lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
}
- lsum = Rewriter::rewrite( lsum );
+ Assert( !lsum.isNull() );
d_proxy_var_to_length[sk] = lsum;
Node ceq = Rewriter::rewrite( skl.eqNode( lsum ) );
Trace("strings-lemma") << "Strings::Lemma LENGTH : " << ceq << std::endl;
Trace("strings-lemma-debug") << " prerewrite : " << skl.eqNode( lsum ) << std::endl;
Trace("strings-assert") << "(assert " << ceq << ")" << std::endl;
d_out->lemma(ceq);
+
}
} else {
AlwaysAssert(false, "String Terms only in registerTerm.");
@@ -3035,15 +3440,27 @@ Node TheoryStrings::mkSkolemCached( Node a, Node b, int id, const char * c, int
}
}
-//isLenSplit: 0-yes, 1-no, 2-ignore
+//isLenSplit: -1-ignore, 0-no restriction, 1-greater than one, 2-one
Node TheoryStrings::mkSkolemS( const char *c, int isLenSplit ) {
Node n = NodeManager::currentNM()->mkSkolem( c, NodeManager::currentNM()->stringType(), "string sko" );
- d_length_intro_vars.insert(n);
+ d_length_lemma_terms_cache.insert( n );
++(d_statistics.d_new_skolems);
- if(isLenSplit == 0) {
+ if( isLenSplit==0 ){
sendLengthLemma( n );
- ++(d_statistics.d_splits);
- } else if(isLenSplit == 1) {
+ } else if( isLenSplit == 1 ){
+ registerNonEmptySkolem( n );
+ }else if( isLenSplit==2 ){
+ Node len_one = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n ).eqNode( d_one );
+ Trace("strings-lemma") << "Strings::Lemma SK-ONE : " << len_one << std::endl;
+ Trace("strings-assert") << "(assert " << len_one << ")" << std::endl;
+ d_out->lemma( len_one );
+ }
+ return n;
+}
+
+void TheoryStrings::registerNonEmptySkolem( Node n ) {
+ if( d_skolem_ne_reg_cache.find( n )==d_skolem_ne_reg_cache.end() ){
+ d_skolem_ne_reg_cache.insert( n );
d_equalityEngine.assertEquality(n.eqNode(d_emptyString), false, d_true);
Node len_n_gt_z = NodeManager::currentNM()->mkNode(kind::GT,
NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, n), d_zero);
@@ -3051,7 +3468,6 @@ Node TheoryStrings::mkSkolemS( const char *c, int isLenSplit ) {
Trace("strings-assert") << "(assert " << len_n_gt_z << ")" << std::endl;
d_out->lemma(len_n_gt_z);
}
- return n;
}
Node TheoryStrings::mkExplain( std::vector< Node >& a ) {
@@ -3146,7 +3562,6 @@ void TheoryStrings::checkDeqNF() {
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];
@@ -3165,13 +3580,12 @@ void TheoryStrings::checkDeqNF() {
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 ){
+ if( !hasProcessed() ){
separateByLength( d_strings_eqc, cols, lts );
for( unsigned i=0; i<cols.size(); i++ ){
if( cols[i].size()>1 && d_lemma_cache.empty() ){
@@ -3189,7 +3603,8 @@ void TheoryStrings::checkDeqNF() {
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] ) ){
+ processDeq( cols[i][j], cols[i][k] );
+ if( hasProcessed() ){
return;
}
}
@@ -3212,14 +3627,24 @@ void TheoryStrings::checkLengthsEqc() {
Node llt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
//now, check if length normalization has occurred
if( ei->d_normalized_length.get().isNull() ) {
+ Node nf = mkConcat( d_normal_forms[d_strings_eqc[i]] );
+ if( Trace.isOn("strings-process-debug") ){
+ Trace("strings-process-debug") << " normal form is " << nf << " from base " << d_normal_forms_base[d_strings_eqc[i]] << std::endl;
+ Trace("strings-process-debug") << " normal form exp is: " << std::endl;
+ for( unsigned j=0; j<d_normal_forms_exp[d_strings_eqc[i]].size(); j++ ){
+ Trace("strings-process-debug") << " " << d_normal_forms_exp[d_strings_eqc[i]][j] << std::endl;
+ }
+ }
+
//if not, add the lemma
std::vector< Node > ant;
ant.insert( ant.end(), d_normal_forms_exp[d_strings_eqc[i]].begin(), d_normal_forms_exp[d_strings_eqc[i]].end() );
ant.push_back( d_normal_forms_base[d_strings_eqc[i]].eqNode( lt ) );
- Node lc = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, mkConcat( d_normal_forms[d_strings_eqc[i]] ) );
- lc = Rewriter::rewrite( lc );
- Node eq = llt.eqNode( lc );
- if( llt!=lc ){
+ Node lc = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, nf );
+ Node lcr = Rewriter::rewrite( lc );
+ Trace("strings-process-debug") << "Rewrote length " << lc << " to " << lcr << std::endl;
+ Node eq = llt.eqNode( lcr );
+ if( llt!=lcr ){
ei->d_normalized_length.set( eq );
sendInference( ant, eq, "LEN-NORM", true );
}
@@ -3330,44 +3755,6 @@ void TheoryStrings::getEquivalenceClasses( std::vector< Node >& eqcs ) {
}
}
-void TheoryStrings::getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp ) {
- if( n!=d_emptyString ) {
- if( n.getKind()==kind::STRING_CONCAT ) {
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- getFinalNormalForm( n[i], nf, exp );
- }
- } else {
- Trace("strings-debug") << "Get final normal form " << n << std::endl;
- Assert( d_equalityEngine.hasTerm( n ) );
- Node nr = d_equalityEngine.getRepresentative( n );
- EqcInfo *eqc_n = getOrMakeEqcInfo( nr, false );
- Node nc = eqc_n ? eqc_n->d_const_term.get() : Node::null();
- if( !nc.isNull() ) {
- nf.push_back( nc );
- if( n!=nc ) {
- exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nc ) );
- }
- } else {
- Assert( d_normal_forms.find( nr )!=d_normal_forms.end() );
- if( d_normal_forms[nr][0]==nr ) {
- Assert( d_normal_forms[nr].size()==1 );
- nf.push_back( nr );
- if( n!=nr ) {
- exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nr ) );
- }
- } else {
- for( unsigned i=0; i<d_normal_forms[nr].size(); i++ ) {
- Assert( d_normal_forms[nr][i]!=nr );
- getFinalNormalForm( d_normal_forms[nr][i], nf, exp );
- }
- exp.insert( exp.end(), d_normal_forms_exp[nr].begin(), d_normal_forms_exp[nr].end() );
- }
- }
- Trace("strings-ind-nf") << "The final normal form of " << n << " is " << nf << std::endl;
- }
- }
-}
-
void TheoryStrings::separateByLength(std::vector< Node >& n,
std::vector< std::vector< Node > >& cols,
std::vector< Node >& lts ) {
@@ -3409,17 +3796,139 @@ void TheoryStrings::printConcat( std::vector< Node >& n, const char * c ) {
}
-//// Measurements
-/*
-void TheoryStrings::updateMpl( Node n, int b ) {
- if(d_mpl.find(n) == d_mpl.end()) {
- //d_curr_cardinality.get();
- d_mpl[n] = b;
- } else if(b < d_mpl[n]) {
- d_mpl[n] = b;
+
+//// Finite Model Finding
+
+Node TheoryStrings::getNextDecisionRequest() {
+ if( options::stringFMF() && !d_conflict ){
+ Node in_var_lsum = d_input_var_lsum.get();
+ //Trace("strings-fmf-debug") << "Strings::FMF: Assertion Level = " << d_valuation.getAssertionLevel() << std::endl;
+ //initialize the term we will minimize
+ if( in_var_lsum.isNull() && !d_input_vars.empty() ){
+ Trace("strings-fmf-debug") << "Input variables: ";
+ std::vector< Node > ll;
+ for(NodeSet::key_iterator itr = d_input_vars.key_begin();
+ itr != d_input_vars.key_end(); ++itr) {
+ Trace("strings-fmf-debug") << " " << (*itr) ;
+ ll.push_back( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr ) );
+ }
+ Trace("strings-fmf-debug") << std::endl;
+ in_var_lsum = ll.size()==1 ? ll[0] : NodeManager::currentNM()->mkNode( kind::PLUS, ll );
+ in_var_lsum = Rewriter::rewrite( in_var_lsum );
+ d_input_var_lsum.set( in_var_lsum );
+ }
+ if( !in_var_lsum.isNull() ){
+ //Trace("strings-fmf") << "Get next decision request." << std::endl;
+ //check if we need to decide on something
+ int decideCard = d_curr_cardinality.get();
+ if( d_cardinality_lits.find( decideCard )!=d_cardinality_lits.end() ){
+ bool value;
+ Node cnode = d_cardinality_lits[ d_curr_cardinality.get() ];
+ if( d_valuation.hasSatValue( cnode, value ) ) {
+ if( !value ){
+ d_curr_cardinality.set( d_curr_cardinality.get() + 1 );
+ decideCard = d_curr_cardinality.get();
+ Trace("strings-fmf-debug") << "Has false SAT value, increment and decide." << std::endl;
+ }else{
+ decideCard = -1;
+ Trace("strings-fmf-debug") << "Has true SAT value, do not decide." << std::endl;
+ }
+ }else{
+ Trace("strings-fmf-debug") << "No SAT value, decide." << std::endl;
+ }
+ }
+ if( decideCard!=-1 ){
+ if( d_cardinality_lits.find( decideCard )==d_cardinality_lits.end() ){
+ Node lit = NodeManager::currentNM()->mkNode( kind::LEQ, in_var_lsum, NodeManager::currentNM()->mkConst( Rational( decideCard ) ) );
+ lit = Rewriter::rewrite( lit );
+ d_cardinality_lits[decideCard] = lit;
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
+ Trace("strings-fmf") << "Strings::FMF: Add decision lemma " << lem << ", decideCard = " << decideCard << std::endl;
+ d_out->lemma( lem );
+ d_out->requirePhase( lit, true );
+ }
+ Node lit = d_cardinality_lits[ decideCard ];
+ Trace("strings-fmf") << "Strings::FMF: Decide positive on " << lit << std::endl;
+ return lit;
+ }
+ }
+ }
+ return Node::null();
+}
+
+Node TheoryStrings::ppRewrite(TNode atom) {
+ Trace("strings-ppr") << "TheoryStrings::ppRewrite " << atom << std::endl;
+ if( !options::stringLazyPreproc() ){
+ //eager preprocess here
+ std::vector< Node > new_nodes;
+ Node ret = d_preproc.processAssertion( atom, new_nodes );
+ if( ret!=atom ){
+ Trace("strings-ppr") << " rewrote " << atom << " -> " << ret << ", with " << new_nodes.size() << " lemmas." << std::endl;
+ for( unsigned i=0; i<new_nodes.size(); i++ ){
+ Trace("strings-ppr") << " lemma : " << new_nodes[i] << std::endl;
+ d_out->lemma( new_nodes[i] );
+ }
+ return ret;
+ }else{
+ Assert( new_nodes.empty() );
+ }
+ }
+ return atom;
+}
+
+void TheoryStrings::collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ d_extt->registerTerm( n );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectExtendedFuncTerms( n[i], visited );
+ }
}
}
-*/
+
+// Stats
+TheoryStrings::Statistics::Statistics():
+ d_splits("TheoryStrings::NumOfSplitOnDemands", 0),
+ d_eq_splits("TheoryStrings::NumOfEqSplits", 0),
+ d_deq_splits("TheoryStrings::NumOfDiseqSplits", 0),
+ d_loop_lemmas("TheoryStrings::NumOfLoops", 0),
+ d_new_skolems("TheoryStrings::NumOfNewSkolems", 0)
+{
+ smtStatisticsRegistry()->registerStat(&d_splits);
+ smtStatisticsRegistry()->registerStat(&d_eq_splits);
+ smtStatisticsRegistry()->registerStat(&d_deq_splits);
+ smtStatisticsRegistry()->registerStat(&d_loop_lemmas);
+ smtStatisticsRegistry()->registerStat(&d_new_skolems);
+}
+
+TheoryStrings::Statistics::~Statistics(){
+ smtStatisticsRegistry()->unregisterStat(&d_splits);
+ smtStatisticsRegistry()->unregisterStat(&d_eq_splits);
+ smtStatisticsRegistry()->unregisterStat(&d_deq_splits);
+ smtStatisticsRegistry()->unregisterStat(&d_loop_lemmas);
+ smtStatisticsRegistry()->unregisterStat(&d_new_skolems);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//// Regular Expressions
unsigned TheoryStrings::getNumMemberships( Node n, bool isPos ) {
@@ -3441,7 +3950,6 @@ 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()) {
return Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, ant, atom) );
@@ -3749,7 +4257,7 @@ bool TheoryStrings::checkMemberships2() {
} else {
//TODO: split
}
- */
+ */
}
Assert(false); //TODO:tmp
}
@@ -3759,6 +4267,18 @@ bool TheoryStrings::checkMemberships2() {
}
void TheoryStrings::checkMemberships() {
+ //add the memberships
+ std::vector< Node > mems;
+ d_extt->getActive( mems, kind::STRING_IN_REGEXP );
+ for( unsigned i=0; i<mems.size(); i++ ){
+ Node n = mems[i];
+ Assert( d_extf_info_tmp.find( n )!=d_extf_info_tmp.end() );
+ Assert( d_extf_info_tmp[n].d_pol==1 || d_extf_info_tmp[n].d_pol==-1 );
+ bool pol = d_extf_info_tmp[n].d_pol==1;
+ Trace("strings-process-debug") << " add membership : " << n << ", pol = " << pol << std::endl;
+ addMembership( pol ? n : n.negate() );
+ }
+
bool addedLemma = false;
bool changed = false;
std::vector< Node > processed;
@@ -3840,7 +4360,8 @@ void TheoryStrings::checkMemberships() {
Node r = atom[1];
std::vector< Node > rnfexp;
- if(options::stringOpt1()) {
+ //if(options::stringOpt1()) {
+ if(true){
if(!x.isConst()) {
x = getNormalString( x, rnfexp);
changed = true;
@@ -3947,7 +4468,7 @@ void TheoryStrings::checkMemberships() {
antec = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, antec, mkExplain(rnfexp)) );
Node conc = nvec.size()==1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
conc = Rewriter::rewrite(conc);
- sendLemma( antec, conc, "REGEXP" );
+ sendLemma( antec, conc, "REGEXP_Unfold" );
addedLemma = true;
if(changed) {
cprocessed.push_back( assertion );
@@ -3955,7 +4476,7 @@ void TheoryStrings::checkMemberships() {
processed.push_back( assertion );
}
//d_regexp_ucached[assertion] = true;
- } else {
+ }else{
Trace("strings-regexp") << "Unroll/simplify membership of non-atomic term " << xr << " = ";
for( unsigned j=0; j<d_normal_forms[xr].size(); j++ ){
Trace("strings-regexp") << d_normal_forms[xr][j] << " ";
@@ -4075,14 +4596,7 @@ void TheoryStrings::checkMemberships() {
bool TheoryStrings::checkPDerivative(Node x, Node r, Node atom, bool &addedLemma,
std::vector< Node > &processed, std::vector< Node > &cprocessed, std::vector< Node > &nf_exp) {
- /*if(d_opt_regexp_gcd) {
- if(d_membership_length.find(atom) == d_membership_length.end()) {
- addedLemma = addMembershipLength(atom);
- d_membership_length[atom] = true;
- } else {
- Trace("strings-regexp") << "Membership length is already added." << std::endl;
- }
- }*/
+
Node antnf = mkExplain(nf_exp);
if(areEqual(x, d_emptyString)) {
@@ -4141,204 +4655,6 @@ bool TheoryStrings::checkPDerivative(Node x, Node r, Node atom, bool &addedLemma
return true;
}
-void TheoryStrings::checkConstantEquivalenceClasses( TermIndex* ti, std::vector< Node >& vecc ) {
- Node n = ti->d_data;
- if( !n.isNull() ){
- //construct the constant
- Node c = mkConcat( vecc );
- if( !areEqual( n, c ) ){
- Trace("strings-debug") << "Constant eqc : " << c << " for " << n << std::endl;
- Trace("strings-debug") << " ";
- for( unsigned i=0; i<vecc.size(); i++ ){
- Trace("strings-debug") << vecc[i] << " ";
- }
- Trace("strings-debug") << std::endl;
- unsigned count = 0;
- unsigned countc = 0;
- std::vector< Node > exp;
- while( count<n.getNumChildren() ){
- while( count<n.getNumChildren() && areEqual( n[count], d_emptyString ) ){
- addToExplanation( n[count], d_emptyString, exp );
- count++;
- }
- if( count<n.getNumChildren() ){
- Trace("strings-debug") << "...explain " << n[count] << " " << vecc[countc] << std::endl;
- if( !areEqual( n[count], vecc[countc] ) ){
- Node nrr = getRepresentative( n[count] );
- Assert( !d_eqc_to_const_exp[nrr].isNull() );
- addToExplanation( n[count], d_eqc_to_const_base[nrr], exp );
- exp.push_back( d_eqc_to_const_exp[nrr] );
- }else{
- addToExplanation( n[count], vecc[countc], exp );
- }
- countc++;
- count++;
- }
- }
- //exp contains an explanation of n==c
- Assert( countc==vecc.size() );
- if( hasTerm( c ) ){
- sendInference( exp, n.eqNode( c ), "I_CONST_MERGE" );
- return;
- }else if( !hasProcessed() ){
- Node nr = getRepresentative( n );
- std::map< Node, Node >::iterator it = d_eqc_to_const.find( nr );
- if( it==d_eqc_to_const.end() ){
- Trace("strings-debug") << "Set eqc const " << n << " to " << c << std::endl;
- d_eqc_to_const[nr] = c;
- d_eqc_to_const_base[nr] = n;
- d_eqc_to_const_exp[nr] = mkAnd( exp );
- }else if( c!=it->second ){
- //conflict
- Trace("strings-debug") << "Conflict, other constant was " << it->second << ", this constant was " << c << std::endl;
- if( d_eqc_to_const_exp[nr].isNull() ){
- // n==c ^ n == c' => false
- addToExplanation( n, it->second, exp );
- }else{
- // n==c ^ n == d_eqc_to_const_base[nr] == c' => false
- exp.push_back( d_eqc_to_const_exp[nr] );
- addToExplanation( n, d_eqc_to_const_base[nr], exp );
- }
- sendInference( exp, d_false, "I_CONST_CONFLICT" );
- return;
- }else{
- Trace("strings-debug") << "Duplicate constant." << std::endl;
- }
- }
- }
- }
- for( std::map< Node, TermIndex >::iterator it = ti->d_children.begin(); it != ti->d_children.end(); ++it ){
- std::map< Node, Node >::iterator itc = d_eqc_to_const.find( it->first );
- if( itc!=d_eqc_to_const.end() ){
- vecc.push_back( itc->second );
- checkConstantEquivalenceClasses( &it->second, vecc );
- vecc.pop_back();
- if( hasProcessed() ){
- break;
- }
- }
- }
-}
-
-void TheoryStrings::checkExtendedFuncs() {
- if( options::stringExp() ){
- checkExtfReduction( 2 );
- }
- if( !hasProcessed() ){
- //collect all remaining extended functions
- std::vector< Node > pnContains;
- std::map< bool, std::vector< Node > > pnMem;
- for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
- if( (*it).second ){
- Node n = (*it).first;
- if( n.getKind()==kind::STRING_STRCTN ) {
- if( d_extf_pol[n]!=1 ){
- Assert( d_extf_pol[n]==-1 );
- pnContains.push_back( n );
- }
- }else if( n.getKind()==kind::STRING_IN_REGEXP ) {
- bool pol = d_extf_pol[n]==1;
- Assert( d_extf_pol[n]==1 || d_extf_pol[n]==-1 );
- pnMem[pol].push_back( n );
- }
- }
- }
- Trace("strings-process-debug") << "Checking negative contains..." << std::endl;
- checkNegContains( pnContains );
- Trace("strings-process-debug") << "Done check negative contain constraints, addedLemma = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
- if( !hasProcessed() ) {
- Trace("strings-process") << "Adding memberships..." << std::endl;
- //add all non-evaluated memberships
- for( std::map< bool, std::vector< Node > >::iterator it=pnMem.begin(); it != pnMem.end(); ++it ){
- for( unsigned i=0; i<it->second.size(); i++ ){
- Trace("strings-process-debug") << " add membership : " << it->second[i] << ", pol = " << it->first << std::endl;
- addMembership( it->first ? it->second[i] : it->second[i].negate() );
- }
- }
- Trace("strings-process") << "Checking memberships..." << std::endl;
- checkMemberships();
- Trace("strings-process") << "Done check memberships, addedLemma = " << !d_pending.empty() << " " << !d_lemma_cache.empty() << ", d_conflict = " << d_conflict << std::endl;
- }
- }
-}
-
-void TheoryStrings::checkNegContains( std::vector< Node >& negContains ) {
- for( unsigned i=0; i<negContains.size(); i++ ){
- Node atom = negContains[i];
- Trace("strings-ctn") << "We have negative contain assertion : (not " << atom << " )" << std::endl;
- //should have already reduced these things by now
- Assert( !areEqual( atom[1], d_emptyString ) );
- Assert( !areEqual( atom[1], atom[0] ) );
- }
- //check for lemmas
- if(options::stringExp()) {
- for( unsigned i=0; i<negContains.size(); i++ ){
- Node atom = negContains[i];
- Node x = atom[0];
- Node s = atom[1];
- std::vector< Node > lexp;
- Node lenx = getLength( x, lexp );
- Node lens = getLength( s, lexp );
- if( areEqual(lenx, lens) ){
- if(d_neg_ctn_eqlen.find(atom) == d_neg_ctn_eqlen.end()) {
- lexp.push_back( lenx.eqNode(lens) );
- lexp.push_back( atom.negate() );
- Node xneqs = x.eqNode(s).negate();
- d_neg_ctn_eqlen.insert( atom );
- sendInference( lexp, xneqs, "NEG-CTN-EQL", true );
- }
- }else if( !areDisequal( lenx, lens ) ){
- if(d_neg_ctn_ulen.find(atom) == d_neg_ctn_ulen.end()) {
- lenx = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x);
- lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- d_neg_ctn_ulen.insert( atom );
- sendSplit( lenx, lens, "NEG-CTN-SP" );
- }
- }else{
- if(d_neg_ctn_cached.find(atom) == d_neg_ctn_cached.end()) {
- lenx = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x);
- lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
- NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::MINUS, lenx, lens ), b1 ) ) );
- Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, x, NodeManager::currentNM()->mkNode( kind::PLUS, b1, b2 ), d_one);
- Node s5 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, s, b2, d_one);
-
- Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);//, s1, s3, s4, s6);
-
- std::vector< Node > vec_nodes;
- Node cc = NodeManager::currentNM()->mkNode( kind::GEQ, b2, d_zero );
- vec_nodes.push_back(cc);
- cc = NodeManager::currentNM()->mkNode( kind::GT, lens, b2 );
- vec_nodes.push_back(cc);
-
- cc = s2.eqNode(s5).negate();
- vec_nodes.push_back(cc);
-
- Node conc = NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- conc = NodeManager::currentNM()->mkNode( kind::EXISTS, b2v, conc );
- conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
- conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
- Node xlss = NodeManager::currentNM()->mkNode( kind::GT, lens, lenx );
- conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::OR, xlss, conc ) );
-
- d_neg_ctn_cached.insert( atom );
- std::vector< Node > exp;
- exp.push_back( atom.negate() );
- sendInference( d_empty_vec, exp, conc, "NEG-CTN-BRK", true );
- //d_pending_req_phase[xlss] = true;
- }
- }
- }
- } else {
- if( !negContains.empty() ){
- throw LogicException("Strings Incomplete (due to Negative Contain) by default, try --strings-exp option.");
- }
- }
-}
-
CVC4::String TheoryStrings::getHeadConst( Node x ) {
if( x.isConst() ) {
return x.getConst< String >();
@@ -4353,27 +4669,6 @@ CVC4::String TheoryStrings::getHeadConst( Node x ) {
}
}
-bool TheoryStrings::addMembershipLength(Node atom) {
- //Node x = atom[0];
- //Node r = atom[1];
-
- /*std::vector< int > co;
- co.push_back(0);
- for(unsigned int k=0; k<lts.size(); ++k) {
- if(lts[k].isConst() && lts[k].getType().isInteger()) {
- int len = lts[k].getConst<Rational>().getNumerator().toUnsignedInt();
- co[0] += cols[k].size() * len;
- } else {
- co.push_back( cols[k].size() );
- }
- }
- int g_co = co[0];
- for(unsigned k=1; k<co.size(); ++k) {
- g_co = gcd(g_co, co[k]);
- }*/
- return false;
-}
-
bool TheoryStrings::deriveRegExp( Node x, Node r, Node ant ) {
// TODO cstr in vre
Assert(x != d_emptyString);
@@ -4494,7 +4789,7 @@ void TheoryStrings::addMembership(Node assertion) {
}
}
-Node TheoryStrings::getNormalString( Node x, std::vector<Node> &nf_exp ){
+Node TheoryStrings::getNormalString( Node x, std::vector< Node >& nf_exp ){
if( !x.isConst() ){
Node xr = getRepresentative( x );
if( d_normal_forms.find( xr ) != d_normal_forms.end() ){
@@ -4570,111 +4865,9 @@ Node TheoryStrings::getNormalSymRegExp(Node r, std::vector<Node> &nf_exp) {
//return Node::null();
}
}
-
return ret;
}
-//// Finite Model Finding
-
-Node TheoryStrings::getNextDecisionRequest() {
- if( options::stringFMF() && !d_conflict ){
- Node in_var_lsum = d_input_var_lsum.get();
- //Trace("strings-fmf-debug") << "Strings::FMF: Assertion Level = " << d_valuation.getAssertionLevel() << std::endl;
- //initialize the term we will minimize
- if( in_var_lsum.isNull() && !d_input_vars.empty() ){
- Trace("strings-fmf-debug") << "Input variables: ";
- std::vector< Node > ll;
- for(NodeSet::key_iterator itr = d_input_vars.key_begin();
- itr != d_input_vars.key_end(); ++itr) {
- Trace("strings-fmf-debug") << " " << (*itr) ;
- ll.push_back( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr ) );
- }
- Trace("strings-fmf-debug") << std::endl;
- in_var_lsum = ll.size()==1 ? ll[0] : NodeManager::currentNM()->mkNode( kind::PLUS, ll );
- in_var_lsum = Rewriter::rewrite( in_var_lsum );
- d_input_var_lsum.set( in_var_lsum );
- }
- if( !in_var_lsum.isNull() ){
- //Trace("strings-fmf") << "Get next decision request." << std::endl;
- //check if we need to decide on something
- int decideCard = d_curr_cardinality.get();
- if( d_cardinality_lits.find( decideCard )!=d_cardinality_lits.end() ){
- bool value;
- Node cnode = d_cardinality_lits[ d_curr_cardinality.get() ];
- if( d_valuation.hasSatValue( cnode, value ) ) {
- if( !value ){
- d_curr_cardinality.set( d_curr_cardinality.get() + 1 );
- decideCard = d_curr_cardinality.get();
- Trace("strings-fmf-debug") << "Has false SAT value, increment and decide." << std::endl;
- }else{
- decideCard = -1;
- Trace("strings-fmf-debug") << "Has true SAT value, do not decide." << std::endl;
- }
- }else{
- Trace("strings-fmf-debug") << "No SAT value, decide." << std::endl;
- }
- }
- if( decideCard!=-1 ){
- if( d_cardinality_lits.find( decideCard )==d_cardinality_lits.end() ){
- Node lit = NodeManager::currentNM()->mkNode( kind::LEQ, in_var_lsum, NodeManager::currentNM()->mkConst( Rational( decideCard ) ) );
- lit = Rewriter::rewrite( lit );
- d_cardinality_lits[decideCard] = lit;
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
- Trace("strings-fmf") << "Strings::FMF: Add decision lemma " << lem << ", decideCard = " << decideCard << std::endl;
- d_out->lemma( lem );
- d_out->requirePhase( lit, true );
- }
- Node lit = d_cardinality_lits[ decideCard ];
- Trace("strings-fmf") << "Strings::FMF: Decide positive on " << lit << std::endl;
- return lit;
- }
- }
- }
-
- return Node::null();
-}
-
-void TheoryStrings::collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited ) {
- if( visited.find( n )==visited.end() ){
- visited[n] = true;
- if( n.getKind()==kind::STRING_SUBSTR || n.getKind()==kind::STRING_STRIDOF ||
- n.getKind() == kind::STRING_ITOS || n.getKind() == kind::STRING_U16TOS || n.getKind() == kind::STRING_U32TOS ||
- n.getKind() == kind::STRING_STOI || n.getKind() == kind::STRING_STOU16 || n.getKind() == kind::STRING_STOU32 ||
- n.getKind() == kind::STRING_STRREPL || n.getKind() == kind::STRING_STRCTN ){
- if( d_ext_func_terms.find( n )==d_ext_func_terms.end() ){
- Trace("strings-extf-debug2") << "Found extended function : " << n << std::endl;
- d_ext_func_terms[n] = true;
- }
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectExtendedFuncTerms( n[i], visited );
- }
- }
-}
-
-// Stats
-TheoryStrings::Statistics::Statistics():
- d_splits("TheoryStrings::NumOfSplitOnDemands", 0),
- d_eq_splits("TheoryStrings::NumOfEqSplits", 0),
- d_deq_splits("TheoryStrings::NumOfDiseqSplits", 0),
- d_loop_lemmas("TheoryStrings::NumOfLoops", 0),
- d_new_skolems("TheoryStrings::NumOfNewSkolems", 0)
-{
- smtStatisticsRegistry()->registerStat(&d_splits);
- smtStatisticsRegistry()->registerStat(&d_eq_splits);
- smtStatisticsRegistry()->registerStat(&d_deq_splits);
- smtStatisticsRegistry()->registerStat(&d_loop_lemmas);
- smtStatisticsRegistry()->registerStat(&d_new_skolems);
-}
-
-TheoryStrings::Statistics::~Statistics(){
- smtStatisticsRegistry()->unregisterStat(&d_splits);
- smtStatisticsRegistry()->unregisterStat(&d_eq_splits);
- smtStatisticsRegistry()->unregisterStat(&d_deq_splits);
- smtStatisticsRegistry()->unregisterStat(&d_loop_lemmas);
- smtStatisticsRegistry()->unregisterStat(&d_new_skolems);
-}
-
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index 2deb09654..fe72bd8e7 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -70,8 +70,9 @@ public:
bool propagate(TNode literal);
void explain( TNode literal, std::vector<TNode>& assumptions );
Node explain( TNode literal );
-
-
+ eq::EqualityEngine * getEqualityEngine() { return &d_equalityEngine; }
+ bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp );
+
// NotifyClass for equality engine
class NotifyClass : public eq::EqualityEngineNotify {
TheoryStrings& d_str;
@@ -171,15 +172,17 @@ private:
bool isNormalFormPair2( Node n1, Node n2 );
// loop ant
NodeSet d_loop_antec;
- NodeSet d_length_intro_vars;
// preReg cache
NodeSet d_pregistered_terms_cache;
NodeSet d_registered_terms_cache;
+ NodeSet d_length_lemma_terms_cache;
+ NodeSet d_skolem_ne_reg_cache;
// preprocess cache
StringsPreprocess d_preproc;
NodeBoolMap d_preproc_cache;
// extended functions inferences cache
NodeSet d_extf_infer_cache;
+ NodeSet d_extf_infer_cache_u;
std::vector< Node > d_empty_vec;
//
NodeList d_ee_disequalities;
@@ -188,14 +191,16 @@ private:
std::map< Node, Node > d_eqc_to_const;
std::map< Node, Node > d_eqc_to_const_base;
std::map< Node, Node > d_eqc_to_const_exp;
+ Node getConstantEqc( Node eqc );
+
std::map< Node, Node > d_eqc_to_len_term;
std::vector< Node > d_strings_eqc;
Node d_emptyString_r;
class TermIndex {
public:
Node d_data;
- std::map< Node, TermIndex > d_children;
- Node add( Node n, unsigned index, TheoryStrings* t, Node er, std::vector< Node >& c );
+ std::map< TNode, TermIndex > d_children;
+ Node add( TNode n, unsigned index, TheoryStrings* t, Node er, std::vector< Node >& c );
void clear(){ d_children.clear(); }
};
std::map< Kind, TermIndex > d_term_index;
@@ -205,6 +210,7 @@ private:
std::map< Node, std::vector< int > > d_flat_form_index;
void debugPrintFlatForms( const char * tc );
+ void debugPrintNormalForms( const char * tc );
/////////////////////////////////////////////////////////////////////////////
// MODEL GENERATION
/////////////////////////////////////////////////////////////////////////////
@@ -246,51 +252,107 @@ private:
/** All the function terms that the theory has seen */
context::CDList<TNode> d_functionsTerms;
private:
+ //any non-reduced extended functions exist
+ context::CDO< bool > d_has_extf;
+ // static information about extf
+ class ExtfInfo {
+ public:
+ //all variables in this term
+ std::vector< Node > d_vars;
+ };
+ // non-static information about extf
+ class ExtfInfoTmp {
+ public:
+ void init(){
+ d_pol = 0;
+ d_model_active = true;
+ }
+ // list of terms that something (does not) contain and their explanation
+ std::map< bool, std::vector< Node > > d_ctn;
+ std::map< bool, std::vector< Node > > d_ctn_from;
+ //polarity
+ int d_pol;
+ //explanation
+ std::vector< Node > d_exp;
+ //reps -> list of variables
+ //std::map< Node, std::vector< Node > > d_rep_vars;
+ //false if it is reduced in the model
+ bool d_model_active;
+ };
+ std::map< Node, ExtfInfoTmp > d_extf_info_tmp;
+ //collect extended operator terms
+ void collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited );
+private:
+ class InferInfo {
+ public:
+ unsigned d_i;
+ unsigned d_j;
+ bool d_rev;
+ std::vector< Node > d_ant;
+ std::vector< Node > d_antn;
+ std::map< int, std::vector< Node > > d_new_skolem;
+ Node d_conc;
+ unsigned d_id;
+ std::map< Node, bool > d_pending_phase;
+ unsigned d_index;
+ const char * getId() {
+ switch( d_id ){
+ case 1:return "S-Split(CST-P)-prop";break;
+ case 2:return "S-Split(VAR)-prop";break;
+ case 3:return "Len-Split(Len)";break;
+ case 4:return "Len-Split(Emp)";break;
+ case 5:return "S-Split(CST-P)-binary";break;
+ case 6:return "S-Split(CST-P)";break;
+ case 7:return "S-Split(VAR)";break;
+ case 8:return "F-Loop";break;
+ default:break;
+ }
+ return "";
+ }
+ bool sendAsLemma();
+ };
//initial check
void checkInit();
void checkConstantEquivalenceClasses( TermIndex* ti, std::vector< Node >& vecc );
//extended functions evaluation check
- void checkExtendedFuncsEval( int effort = 0 );
- void checkExtfInference( Node n, Node nr, int effort );
- void collectVars( Node n, std::map< Node, std::vector< Node > >& vars, std::map< Node, bool >& visited );
+ void checkExtfEval( int effort = 0 );
+ void checkExtfInference( Node n, Node nr, ExtfInfoTmp& in, int effort );
+ void collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited );
Node getSymbolicDefinition( Node n, std::vector< Node >& exp );
//check extf reduction
- void checkExtfReduction( int effort );
- void checkReduction( Node atom, int pol, int effort );
+ void checkExtfReductions( int effort );
+ bool checkExtfReduction( Node atom, int pol, int effort );
//flat forms check
void checkFlatForms();
Node checkCycles( Node eqc, std::vector< Node >& curr, std::vector< Node >& exp );
//normal forms check
void checkNormalForms();
- bool normalizeEquivalenceClass( Node n, std::vector< Node > & nf, std::vector< Node > & nf_exp );
- bool getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
- std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend);
- bool detectLoop(std::vector< std::vector< Node > > &normal_forms,
- int i, int j, int index, int &loop_in_i, int &loop_in_j);
- bool processLoop(std::vector< Node > &antec,
- std::vector< std::vector< Node > > &normal_forms,
- std::vector< Node > &normal_form_src,
- int i, int j, int loop_n_index, int other_n_index,
- int loop_index, int index);
- bool processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ void normalizeEquivalenceClass( Node n );
+ void getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend );
+ bool detectLoop( std::vector< std::vector< Node > > &normal_forms, int i, int j, int index, int &loop_in_i, int &loop_in_j, unsigned rproc );
+ bool processLoop( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ int i, int j, int loop_n_index, int other_n_index,int loop_index, int index, InferInfo& info );
+ void processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend );
- bool processReverseNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ void processReverseNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j );
- bool processSimpleNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ unsigned i, unsigned j, unsigned& index, unsigned rproc, std::vector< InferInfo >& pinfer );
+ void processSimpleNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j, unsigned& index, bool isRev );
- bool processDeq( Node n1, Node n2 );
+ unsigned i, unsigned j, unsigned& index, bool isRev, unsigned rproc, std::vector< InferInfo >& pinfer );
+ void processDeq( Node n1, Node n2 );
int processReverseDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj );
int processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev );
void checkDeqNF();
-
- void getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
- std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
- unsigned i, unsigned j, int index, bool isRev, std::vector< Node >& curr_exp );
+ void getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+ unsigned i, int index, bool isRev, std::vector< Node >& curr_exp );
+ void getExplanationVectorForPrefixEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+ std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+ unsigned i, unsigned j, int index_i, int index_j, bool isRev, std::vector< Node >& curr_exp );
+
+ Node collectConstantStringAt( std::vector< Node >& vec, int& index, bool isRev );
- //check for extended functions
- void checkExtendedFuncs();
//check membership constraints
Node mkRegExpAntec(Node atom, Node ant);
Node normalizeRegexp(Node r);
@@ -322,6 +384,8 @@ public:
Node expandDefinition(LogicRequest &logicRequest, Node n);
/** Check at effort e */
void check(Effort e);
+ /** needs check last effort */
+ bool needsCheckLastEffort();
/** Conflict when merging two constants */
void conflict(TNode a, TNode b);
/** called when a new equivalence class is created */
@@ -364,9 +428,16 @@ protected:
enum {
sk_id_c_spt,
sk_id_vc_spt,
- sk_id_v_spt,
+ sk_id_vc_bin_spt,
+ sk_id_v_spt,
+ sk_id_c_spt_rev,
+ sk_id_vc_spt_rev,
+ sk_id_vc_bin_spt_rev,
+ sk_id_v_spt_rev,
sk_id_ctn_pre,
sk_id_ctn_post,
+ sk_id_dc_spt,
+ sk_id_dc_spt_rem,
sk_id_deq_x,
sk_id_deq_y,
sk_id_deq_z,
@@ -374,6 +445,7 @@ protected:
std::map< Node, std::map< Node, std::map< int, Node > > > d_skolem_cache;
Node mkSkolemCached( Node a, Node b, int id, const char * c, int isLenSplit = 0 );
inline Node mkSkolemS(const char * c, int isLenSplit = 0);
+ void registerNonEmptySkolem( Node sk );
//inline Node mkSkolemI(const char * c);
/** mkExplain **/
Node mkExplain( std::vector< Node >& a );
@@ -385,34 +457,12 @@ protected:
//get equivalence classes
void getEquivalenceClasses( std::vector< Node >& eqcs );
- //get final normal form
- void getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp );
//separate into collections with equal length
void separateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& col, std::vector< Node >& lts );
void printConcat( std::vector< Node >& n, const char * c );
void inferSubstitutionProxyVars( Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< Node >& unproc );
-private:
-
- // Special String Functions
- NodeSet d_neg_ctn_eqlen;
- NodeSet d_neg_ctn_ulen;
- NodeSet d_neg_ctn_cached;
- //extended string terms and whether they have been reduced
- NodeBoolMap d_ext_func_terms;
- std::map< Node, std::map< Node, std::vector< Node > > > d_extf_vars;
- // list of terms that something (does not) contain and their explanation
- class ExtfInfo {
- public:
- std::map< bool, std::vector< Node > > d_ctn;
- std::map< bool, std::vector< Node > > d_ctn_from;
- };
- std::map< Node, int > d_extf_pol;
- std::map< Node, std::vector< Node > > d_extf_exp;
- std::map< Node, ExtfInfo > d_extf_info;
- //collect extended operator terms
- void collectExtendedFuncTerms( Node n, std::map< Node, bool >& visited );
// Symbolic Regular Expression
private:
@@ -444,7 +494,6 @@ private:
CVC4::String getHeadConst( Node x );
bool deriveRegExp( Node x, Node r, Node ant );
- bool addMembershipLength(Node atom);
void addMembership(Node assertion);
Node getNormalString(Node x, std::vector<Node> &nf_exp);
Node getNormalSymRegExp(Node r, std::vector<Node> &nf_exp);
@@ -459,7 +508,8 @@ private:
public:
//for finite model finding
Node getNextDecisionRequest();
-
+ //ppRewrite
+ Node ppRewrite(TNode atom);
public:
/** statistics class */
class Statistics {
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index ba811644a..a697dad75 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -28,89 +28,58 @@ namespace CVC4 {
namespace theory {
namespace strings {
-StringsPreprocess::StringsPreprocess( context::UserContext* u ) : d_cache( u ){
+StringsPreprocess::StringsPreprocess( context::UserContext* u ){
//Constants
d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
}
StringsPreprocess::~StringsPreprocess(){
}
-/*
-int StringsPreprocess::checkFixLenVar( Node t ) {
- int ret = 2;
- if(t.getKind() == kind::EQUAL) {
- if(t[0].getType().isInteger() && t[0].isConst() && t[1].getKind() == kind::STRING_LENGTH) {
- if(t[1][0].getKind() == kind::VARIABLE) {
- ret = 0;
- }
- } else if(t[1].getType().isInteger() && t[1].isConst() && t[0].getKind() == kind::STRING_LENGTH) {
- if(t[0][0].getKind() == kind::VARIABLE) {
- ret = 1;
- }
- }
- }
- if(ret != 2) {
- unsigned len = t[ret].getConst<Rational>().getNumerator().toUnsignedInt();
- if(len < 2) {
- ret = 2;
+Node StringsPreprocess::getUfForNode( Kind k, Node n, unsigned id ) {
+ std::map< unsigned, Node >::iterator it = d_uf[k].find( id );
+ if( it==d_uf[k].end() ){
+ std::vector< TypeNode > types;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ types.push_back( n[i].getType() );
}
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, n.getType() );
+ Node f = NodeManager::currentNM()->mkSkolem( "sop", typ, "op created for string op" );
+ d_uf[k][id] = f;
+ return f;
+ }else{
+ return it->second;
}
- if(!options::stringExp()) {
- ret = 2;
- }
- return ret;
}
-*/
-Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
- NodeNodeMap::const_iterator i = d_cache.find(t);
- if(i != d_cache.end()) {
- return (*i).second.isNull() ? t : (*i).second;
+
+//pro: congruence possible, con: introduces UF/requires theory combination
+// currently hurts performance
+//TODO: for all skolems below
+Node StringsPreprocess::getUfAppForNode( Kind k, Node n, unsigned id ) {
+ std::vector< Node > children;
+ children.push_back( getUfForNode( k, n, id ) );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ children.push_back( n[i] );
}
+ return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children );
+}
- Trace("strings-preprocess") << "StringsPreprocess::simplify: " << t << std::endl;
+//returns an n such that t can be replaced by n, under the assumption of lemmas in new_nodes
+
+Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
+ unsigned prev_new_nodes = new_nodes.size();
+ Trace("strings-preprocess-debug") << "StringsPreprocess::simplify: " << t << std::endl;
Node retNode = t;
- /*int c_id = checkFixLenVar(t);
- if( c_id != 2 ) {
- int v_id = 1 - c_id;
- int len = t[c_id].getConst<Rational>().getNumerator().toUnsignedInt();
- if(len > 1) {
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- std::vector< Node > vec;
- for(int i=0; i<len; i++) {
- Node num = NodeManager::currentNM()->mkConst( ::CVC4::Rational(i) );
- //Node sk = NodeManager::currentNM()->mkNode(kind::STRING_CHARAT, t[v_id][0], num);
- Node sk = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, t[v_id][0], num, one);
- vec.push_back(sk);
- Node cc = one.eqNode(NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk ));
- new_nodes.push_back( cc );
- }
- Node lem = t[v_id][0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, vec ) );
- lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, t, lem );
- new_nodes.push_back( lem );
- d_cache[t] = t;
- retNode = t;
- }
- } else */
if( t.getKind() == kind::STRING_SUBSTR ) {
- /*
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ),
- NodeManager::currentNM()->mkNode( kind::PLUS, t[1], t[2] ) );
- Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, t[1], d_zero);
- Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GT, t[2], d_zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
- Node sk1 = NodeManager::currentNM()->mkSkolem( "ss1", NodeManager::currentNM()->stringType(), "created for charat/substr" );
- Node sk3 = NodeManager::currentNM()->mkSkolem( "ss3", NodeManager::currentNM()->stringType(), "created for charat/substr" );
- Node x_eq_123 = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, t, sk3 ) );
- Node len_sk1_eq_i = t[1].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
- Node lenc = t[2].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t ) );
- Node lemma = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
- NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i, lenc ),
- t.eqNode(NodeManager::currentNM()->mkConst( ::CVC4::String("") )) ));
- */
+ Node skt;
+ if( options::stringUfReduct() ){
+ skt = getUfAppForNode( kind::STRING_SUBSTR, t );
+ }else{
+ skt = NodeManager::currentNM()->mkSkolem( "sst", NodeManager::currentNM()->stringType(), "created for substr" );
+ }
Node t12 = NodeManager::currentNM()->mkNode( kind::PLUS, t[1], t[2] );
Node lt0 = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] );
//start point is greater than or equal zero
@@ -120,10 +89,10 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
//length is positive
Node c3 = NodeManager::currentNM()->mkNode( kind::GT, t[2], d_zero );
Node cond = NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3 );
-
+
Node sk1 = NodeManager::currentNM()->mkSkolem( "ss1", NodeManager::currentNM()->stringType(), "created for substr" );
Node sk2 = NodeManager::currentNM()->mkSkolem( "ss2", NodeManager::currentNM()->stringType(), "created for substr" );
- Node b11 = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, t, sk2 ) );
+ Node b11 = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, skt, sk2 ) );
//length of first skolem is second argument
Node b12 = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ).eqNode( t[1] );
//length of second skolem is abs difference between end point and end of string
@@ -132,34 +101,38 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
NodeManager::currentNM()->mkNode( kind::MINUS, lt0, t12 ), d_zero ) );
Node b1 = NodeManager::currentNM()->mkNode( kind::AND, b11, b12, b13 );
- Node b2 = t.eqNode( NodeManager::currentNM()->mkConst( ::CVC4::String("") ) );
-
- Node lemma = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond, b1, b2 ) );
+ Node b2 = skt.eqNode( NodeManager::currentNM()->mkConst( ::CVC4::String("") ) );
+ Node lemma = NodeManager::currentNM()->mkNode( kind::ITE, cond, b1, b2 );
new_nodes.push_back( lemma );
- d_cache[t] = t;
+ retNode = skt;
} else if( t.getKind() == kind::STRING_STRIDOF ) {
Node sk2 = NodeManager::currentNM()->mkSkolem( "io2", NodeManager::currentNM()->stringType(), "created for indexof" );
Node sk3 = NodeManager::currentNM()->mkSkolem( "io3", NodeManager::currentNM()->stringType(), "created for indexof" );
Node sk4 = NodeManager::currentNM()->mkSkolem( "io4", NodeManager::currentNM()->stringType(), "created for indexof" );
- Node skk = NodeManager::currentNM()->mkSkolem( "iok", NodeManager::currentNM()->integerType(), "created for indexof" );
+ Node skk;
+ if( options::stringUfReduct() ){
+ skk = getUfAppForNode( kind::STRING_STRIDOF, t );
+ }else{
+ skk = NodeManager::currentNM()->mkSkolem( "iok", NodeManager::currentNM()->integerType(), "created for indexof" );
+ }
Node st = NodeManager::currentNM()->mkNode( kind::STRING_SUBSTR, t[0], t[2], NodeManager::currentNM()->mkNode( kind::MINUS, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ), t[2] ) );
Node eq = st.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk2, sk3, sk4 ) );
new_nodes.push_back( eq );
Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
Node krange = NodeManager::currentNM()->mkNode( kind::GEQ, skk, negone );
new_nodes.push_back( krange );
- krange = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::GT, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ), skk) );
+ krange = NodeManager::currentNM()->mkNode( kind::GT, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ), skk);
new_nodes.push_back( krange );
- krange = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::GT, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] ), d_zero) );
+ krange = NodeManager::currentNM()->mkNode( kind::GT, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] ), d_zero);
new_nodes.push_back( krange );
- Node start_valid = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::GEQ, t[2], d_zero) );
+ Node start_valid = NodeManager::currentNM()->mkNode( kind::GEQ, t[2], d_zero);
//str.len(s1) < y + str.len(s2)
- Node c1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::GT,
- NodeManager::currentNM()->mkNode( kind::PLUS, t[2], NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] )),
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] )));
+ Node c1 = NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::PLUS, t[2], NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] )),
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ));
//~contain(t234, s2)
- Node c3 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, st, t[1] ).negate());
+ Node c3 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, st, t[1] ).negate();
//left
Node left = NodeManager::currentNM()->mkNode( kind::OR, c1, c3, start_valid.negate() );
//t3 = s2
@@ -176,23 +149,22 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node c6 = skk.eqNode( NodeManager::currentNM()->mkNode( kind::PLUS, t[2],
NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 )) );
//right
- Node right = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::AND, c4, c5, c6, start_valid ));
+ Node right = NodeManager::currentNM()->mkNode( kind::AND, c4, c5, c6, start_valid );
Node cond = skk.eqNode( negone );
Node rr = NodeManager::currentNM()->mkNode( kind::ITE, cond, left, right );
new_nodes.push_back( rr );
- if( options::stringLazyPreproc() ){
- new_nodes.push_back( t.eqNode( skk ) );
- d_cache[t] = Node::null();
- }else{
- d_cache[t] = skk;
- retNode = skk;
- }
+ retNode = skk;
} else if( t.getKind() == kind::STRING_ITOS || t.getKind() == kind::STRING_U16TOS || t.getKind() == kind::STRING_U32TOS ) {
//Node num = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE,
// NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero),
// t[0], NodeManager::currentNM()->mkNode(kind::UMINUS, t[0])));
Node num = t[0];
- Node pret = NodeManager::currentNM()->mkNode(kind::STRING_ITOS, num);
+ Node pret;
+ if( options::stringUfReduct() ){
+ pret = NodeManager::currentNM()->mkNode(kind::STRING_ITOS, num);
+ }else{
+ pret = NodeManager::currentNM()->mkSkolem( "itost", NodeManager::currentNM()->stringType(), "created for itos" );
+ }
Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, pret);
Node nonneg = NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero);
@@ -214,8 +186,8 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
//non-neg
Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
- NodeManager::currentNM()->mkNode( kind::GT, lenp, b1 ) ) );
+ Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
+ NodeManager::currentNM()->mkNode( kind::GT, lenp, b1 ) );
Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
Node nine = NodeManager::currentNM()->mkConst( ::CVC4::Rational(9) );
Node ten = NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) );
@@ -284,7 +256,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
svec.push_back(cc1);svec.push_back(cc2);
svec.push_back(cc21);
svec.push_back(cc3);svec.push_back(cc4);svec.push_back(cc5);
- Node conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, svec) );
+ Node conc = NodeManager::currentNM()->mkNode(kind::AND, svec);
conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, nonneg, conc );
@@ -295,20 +267,17 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
t.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
NodeManager::currentNM()->mkConst(::CVC4::String("-")), pret))));
new_nodes.push_back( conc );*/
- if( options::stringLazyPreproc() && t!=pret ){
- new_nodes.push_back( t.eqNode( pret ) );
- d_cache[t] = Node::null();
- }else{
- d_cache[t] = pret;
- retNode = pret;
- }
- //don't rewrite processed
- if(t != pret) {
- d_cache[pret] = pret;
- }
+ retNode = pret;
} else if( t.getKind() == kind::STRING_STOI || t.getKind() == kind::STRING_STOU16 || t.getKind() == kind::STRING_STOU32 ) {
Node str = t[0];
- Node pret = NodeManager::currentNM()->mkNode(kind::STRING_STOI, str);
+ Node pret;
+ if( options::stringUfReduct() ){
+ pret = getUfAppForNode( kind::STRING_STOI, t );
+ }else{
+ pret = NodeManager::currentNM()->mkSkolem( "stoit", NodeManager::currentNM()->integerType(), "created for stoi" );
+ }
+ //Node pret = NodeManager::currentNM()->mkNode(kind::STRING_STOI, str);
+ //Node pret = getUfAppForNode( kind::STRING_STOI, t );
Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, str);
Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
@@ -363,7 +332,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
g = z2.eqNode( NodeManager::currentNM()->mkConst(::CVC4::String(stmp)) ).negate();
vec_n.push_back(g);
}
- Node cc2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, vec_n));
+ Node cc2 = NodeManager::currentNM()->mkNode(kind::AND, vec_n);
//cc3
Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);
@@ -397,7 +366,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
ufMx)));
vec_c3b.push_back(c3cc);
c3cc = NodeManager::currentNM()->mkNode(kind::AND, vec_c3b);
- c3cc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::IMPLIES, g2, c3cc) );
+ c3cc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g2, c3cc);
c3cc = NodeManager::currentNM()->mkNode(kind::FORALL, b2v, c3cc);
vec_c3.push_back(c3cc);
//unbound
@@ -411,16 +380,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node conc = NodeManager::currentNM()->mkNode(kind::ITE, pret.eqNode(negone),
NodeManager::currentNM()->mkNode(kind::OR, cc1, cc2), cc3);
new_nodes.push_back( conc );
- if( options::stringLazyPreproc() && t!=pret ){
- new_nodes.push_back( t.eqNode( pret ) );
- d_cache[t] = Node::null();
- }else{
- d_cache[t] = pret;
- retNode = pret;
- }
- if(t != pret) {
- d_cache[pret] = pret;
- }
+ retNode = pret;
} else if( t.getKind() == kind::STRING_STRREPL ) {
Node x = t[0];
Node y = t[1];
@@ -429,6 +389,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node sk2 = NodeManager::currentNM()->mkSkolem( "rp2", t[0].getType(), "created for replace" );
Node skw = NodeManager::currentNM()->mkSkolem( "rpw", t[0].getType(), "created for replace" );
Node cond = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, x, y );
+ cond = NodeManager::currentNM()->mkNode( kind::AND, cond, NodeManager::currentNM()->mkNode(kind::GT, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, y), d_zero) );
Node c1 = x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, y, sk2 ) );
Node c2 = skw.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, z, sk2 ) );
Node c3 = NodeManager::currentNM()->mkNode(kind::STRING_STRCTN,
@@ -437,98 +398,107 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
NodeManager::currentNM()->mkNode(kind::MINUS,
NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, y),
NodeManager::currentNM()->mkConst(::CVC4::Rational(1))))), y).negate();
- Node rr = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
- NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3),
- skw.eqNode(x) ) );
- new_nodes.push_back( rr );
- rr = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::GT, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, y), d_zero) );
+ Node rr = NodeManager::currentNM()->mkNode( kind::ITE, cond,
+ NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3),
+ skw.eqNode(x) );
new_nodes.push_back( rr );
- if( options::stringLazyPreproc() ){
- new_nodes.push_back( t.eqNode( skw ) );
- d_cache[t] = Node::null();
- }else{
- d_cache[t] = skw;
- retNode = skw;
- }
- } else{
- d_cache[t] = Node::null();
+ retNode = skw;
+ } else if( t.getKind() == kind::STRING_STRCTN ){
+ Node x = t[0];
+ Node s = t[1];
+ //negative contains reduces to existential
+ Node lenx = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x);
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
+ Node body = NodeManager::currentNM()->mkNode( kind::AND,
+ NodeManager::currentNM()->mkNode( kind::LEQ, d_zero, b1 ),
+ NodeManager::currentNM()->mkNode( kind::LEQ, b1, NodeManager::currentNM()->mkNode( kind::MINUS, lenx, lens ) ),
+ NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, x, b1, lens), s )
+ );
+ retNode = NodeManager::currentNM()->mkNode( kind::EXISTS, b1v, body );
}
- /*if( t.getNumChildren()>0 ) {
- std::vector< Node > cc;
- if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
- cc.push_back(t.getOperator());
- }
- bool changed = false;
- for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node tn = simplify( t[i], new_nodes );
- cc.push_back( tn );
- changed = changed || tn!=t[i];
- }
- if(changed) {
- Node n = NodeManager::currentNM()->mkNode( t.getKind(), cc );
- d_cache[t] = n;
- retNode = n;
- } else {
- d_cache[t] = Node::null();
- retNode = t;
- }
- }*/
if( t!=retNode ){
- Trace("strings-preprocess-debug") << "StringsPreprocess::simplify: " << t << " -> " << retNode << std::endl;
+ Trace("strings-preprocess") << "StringsPreprocess::simplify: " << t << " -> " << retNode << std::endl;
if(!new_nodes.empty()) {
- Trace("strings-preprocess-debug") << " ... new nodes (" << new_nodes.size() << "):\n";
- for(unsigned int i=0; i<new_nodes.size(); ++i) {
- Trace("strings-preprocess-debug") << "\t" << new_nodes[i] << "\n";
+ Trace("strings-preprocess") << " ... new nodes (" << (new_nodes.size()-prev_new_nodes) << "):" << std::endl;
+ for(unsigned int i=prev_new_nodes; i<new_nodes.size(); ++i) {
+ Trace("strings-preprocess") << " " << new_nodes[i] << std::endl;
}
}
}
return retNode;
}
-Node StringsPreprocess::decompose(Node t, std::vector< Node > & new_nodes) {
- NodeNodeMap::const_iterator i = d_cache.find(t);
- if(i != d_cache.end()) {
- return (*i).second.isNull() ? t : (*i).second;
- }
-
- unsigned num = t.getNumChildren();
- if(num == 0) {
- return simplify(t, new_nodes);
+Node StringsPreprocess::simplifyRec( Node t, std::vector< Node > & new_nodes, std::map< Node, Node >& visited ){
+ std::map< Node, Node >::iterator it = visited.find(t);
+ if( it!=visited.end() ){
+ return it->second;
}else{
- bool changed = false;
- std::vector< Node > cc;
- if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
- cc.push_back(t.getOperator());
- }
- for(unsigned i=0; i<t.getNumChildren(); i++) {
- Node s = decompose(t[i], new_nodes);
- cc.push_back( s );
- if(s != t[i]) {
- changed = true;
+ Node retNode;
+ if( t.getNumChildren()==0 ){
+ retNode = simplify( t, new_nodes );
+ }else if( t.getKind()!=kind::FORALL ){
+ bool changed = false;
+ std::vector< Node > cc;
+ if( t.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ cc.push_back( t.getOperator() );
}
+ for(unsigned i=0; i<t.getNumChildren(); i++) {
+ Node s = simplifyRec( t[i], new_nodes, visited );
+ cc.push_back( s );
+ if( s!=t[i] ) {
+ changed = true;
+ }
+ }
+ Node tmp = t;
+ if( changed ){
+ tmp = NodeManager::currentNM()->mkNode( t.getKind(), cc );
+ }
+ retNode = simplify( tmp, new_nodes );
}
- if(changed) {
- Node tmp = NodeManager::currentNM()->mkNode( t.getKind(), cc );
- return simplify(tmp, new_nodes);
- } else {
- return simplify(t, new_nodes);
- }
+ visited[t] = retNode;
+ return retNode;
+ }
+}
+
+Node StringsPreprocess::processAssertion( Node n, std::vector< Node > &new_nodes ) {
+ std::map< Node, Node > visited;
+ std::vector< Node > new_nodes_curr;
+ Node ret = simplifyRec( n, new_nodes_curr, visited );
+ while( !new_nodes_curr.empty() ){
+ Node curr = new_nodes_curr.back();
+ new_nodes_curr.pop_back();
+ std::vector< Node > new_nodes_tmp;
+ curr = simplifyRec( curr, new_nodes_tmp, visited );
+ new_nodes_curr.insert( new_nodes_curr.end(), new_nodes_tmp.begin(), new_nodes_tmp.end() );
+ new_nodes.push_back( curr );
}
+ return ret;
}
-void StringsPreprocess::simplify(std::vector< Node > &vec_node) {
+void StringsPreprocess::processAssertions( std::vector< Node > &vec_node ){
+ std::map< Node, Node > visited;
for( unsigned i=0; i<vec_node.size(); i++ ){
+ Trace("strings-preprocess-debug") << "Preprocessing assertion " << vec_node[i] << std::endl;
+ //preprocess until fixed point
std::vector< Node > new_nodes;
- Node curr = decompose( vec_node[i], new_nodes );
- if( !new_nodes.empty() ){
- new_nodes.insert( new_nodes.begin(), curr );
- curr = NodeManager::currentNM()->mkNode( kind::AND, new_nodes );
+ std::vector< Node > new_nodes_curr;
+ new_nodes_curr.push_back( vec_node[i] );
+ while( !new_nodes_curr.empty() ){
+ Node curr = new_nodes_curr.back();
+ new_nodes_curr.pop_back();
+ std::vector< Node > new_nodes_tmp;
+ curr = simplifyRec( curr, new_nodes_tmp, visited );
+ new_nodes_curr.insert( new_nodes_curr.end(), new_nodes_tmp.begin(), new_nodes_tmp.end() );
+ new_nodes.push_back( curr );
}
- if( curr!=vec_node[i] ){
- curr = Rewriter::rewrite( curr );
- PROOF( ProofManager::currentPM()->addDependence(curr, vec_node[i]); );
- vec_node[i] = curr;
+ Node res = new_nodes.size()==1 ? new_nodes[0] : NodeManager::currentNM()->mkNode( kind::AND, new_nodes );
+ if( res!=vec_node[i] ){
+ res = Rewriter::rewrite( res );
+ PROOF( ProofManager::currentPM()->addDependence( res, vec_node[i] ); );
+ vec_node[i] = res;
}
}
}
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
index abc7b5a91..faaeb53c3 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -31,19 +31,25 @@ namespace theory {
namespace strings {
class StringsPreprocess {
- typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
- NodeNodeMap d_cache;
//Constants
Node d_zero;
-private:
- //int checkFixLenVar( Node t );
- Node simplify( Node t, std::vector< Node > &new_nodes );
+ Node d_one;
+ //mapping from kinds to UF
+ std::map< Kind, std::map< unsigned, Node > > d_uf;
+ //get UF for node
+ Node getUfForNode( Kind k, Node n, unsigned id = 0 );
+ Node getUfAppForNode( Kind k, Node n, unsigned id = 0 );
+ //recursive simplify
+ Node simplifyRec( Node t, std::vector< Node > &new_nodes, std::map< Node, Node >& visited );
public:
StringsPreprocess( context::UserContext* u );
~StringsPreprocess();
-
- Node decompose( Node t, std::vector< Node > &new_nodes );
- void simplify(std::vector< Node > &vec_node);
+ //returns a node that is equivalent to t under assumptions in new_nodes
+ Node simplify( Node t, std::vector< Node > &new_nodes );
+ //process assertion: guarentees to remove all extf
+ Node processAssertion( Node n, std::vector< Node > &new_nodes );
+ //proces assertions: guarentees to remove all extf, rewrite in place
+ void processAssertions( std::vector< Node > &vec_node );
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 75243b84d..92b18eed0 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -1026,22 +1026,22 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
retNode = NodeManager::currentNM()->mkNode(kind::EQUAL, leftNode, rightNode);
}
} else if(node.getKind() == kind::STRING_LENGTH) {
- if(node[0].isConst()) {
+ if( node[0].isConst() ){
retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( node[0].getConst<String>().size() ) );
- } else if(node[0].getKind() == kind::STRING_CONCAT) {
+ }else if( node[0].getKind() == kind::STRING_CONCAT ){
Node tmpNode = rewriteConcatString(node[0]);
if(tmpNode.isConst()) {
retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode.getConst<String>().size() ) );
- } else if(tmpNode.getKind() == kind::STRING_SUBSTR) {
+ //} else if(tmpNode.getKind() == kind::STRING_SUBSTR) {
//retNode = tmpNode[2];
- } else {
+ }else if( tmpNode.getKind()==kind::STRING_CONCAT ){
// it has to be string concat
std::vector<Node> node_vec;
for(unsigned int i=0; i<tmpNode.getNumChildren(); ++i) {
if(tmpNode[i].isConst()) {
node_vec.push_back( NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode[i].getConst<String>().size() ) ) );
- } else if(tmpNode[i].getKind() == kind::STRING_SUBSTR) {
- node_vec.push_back( tmpNode[i][2] );
+ //} else if(tmpNode[i].getKind() == kind::STRING_SUBSTR) {
+ // node_vec.push_back( tmpNode[i][2] );
} else {
node_vec.push_back( NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, tmpNode[i]) );
}
@@ -1055,8 +1055,6 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
}
}
}
- //else if(node[0].getKind() == kind::STRING_SUBSTR) {
- //retNode = node[0][2];
}else if( node.getKind() == kind::STRING_CHARAT ){
Node one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
retNode = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, node[0], node[1], one);
@@ -1502,22 +1500,12 @@ Node TheoryStringsRewriter::rewriteContains( Node node ) {
}
}
}else if( node[0].isConst() ){
- CVC4::String t = node[0].getConst<String>();
- if( t.size()==0 ){
+ if( node[0].getConst<String>().size()==0 ){
return NodeManager::currentNM()->mkNode( kind::EQUAL, node[0], node[1] );
}else if( node[1].getKind()==kind::STRING_CONCAT ){
- //must find constant components in order
- size_t pos = 0;
- for(unsigned i=0; i<node[1].getNumChildren(); i++) {
- if( node[1][i].isConst() ){
- CVC4::String s = node[1][i].getConst<String>();
- size_t new_pos = t.find(s,pos);
- if( new_pos==std::string::npos ) {
- return NodeManager::currentNM()->mkConst( false );
- }else{
- pos = new_pos + s.size();
- }
- }
+ int firstc, lastc;
+ if( !canConstantContainConcat( node[0], node[1], firstc, lastc ) ){
+ return NodeManager::currentNM()->mkConst( false );
}
}
}
@@ -1710,3 +1698,83 @@ Node TheoryStringsRewriter::splitConstant( Node a, Node b, int& index, bool isRe
return Node::null();
}
}
+
+bool TheoryStringsRewriter::canConstantContainConcat( Node c, Node n, int& firstc, int& lastc ) {
+ Assert( c.isConst() );
+ CVC4::String t = c.getConst<String>();
+ Assert( n.getKind()==kind::STRING_CONCAT );
+ //must find constant components in order
+ size_t pos = 0;
+ firstc = -1;
+ lastc = -1;
+ for(unsigned i=0; i<n.getNumChildren(); i++) {
+ if( n[i].isConst() ){
+ firstc = firstc==-1 ? i : firstc;
+ lastc = i;
+ CVC4::String s = n[i].getConst<String>();
+ size_t new_pos = t.find(s,pos);
+ if( new_pos==std::string::npos ) {
+ return false;
+ }else{
+ pos = new_pos + s.size();
+ }
+ }
+ }
+ return true;
+}
+
+bool TheoryStringsRewriter::canConstantContainList( Node c, std::vector< Node >& l, int& firstc, int& lastc ) {
+ Assert( c.isConst() );
+ CVC4::String t = c.getConst<String>();
+ //must find constant components in order
+ size_t pos = 0;
+ firstc = -1;
+ lastc = -1;
+ for(unsigned i=0; i<l.size(); i++) {
+ if( l[i].isConst() ){
+ firstc = firstc==-1 ? i : firstc;
+ lastc = i;
+ CVC4::String s = l[i].getConst<String>();
+ size_t new_pos = t.find(s,pos);
+ if( new_pos==std::string::npos ) {
+ return false;
+ }else{
+ pos = new_pos + s.size();
+ }
+ }
+ }
+ return true;
+}
+
+Node TheoryStringsRewriter::getNextConstantAt( std::vector< Node >& vec, unsigned& start_index, unsigned& end_index, bool isRev ) {
+ while( vec.size()>start_index && !vec[ start_index ].isConst() ){
+ //return Node::null();
+ start_index++;
+ }
+ if( start_index<vec.size() ){
+ end_index = start_index;
+ return collectConstantStringAt( vec, end_index, isRev );
+ }else{
+ return Node::null();
+ }
+}
+
+Node TheoryStringsRewriter::collectConstantStringAt( std::vector< Node >& vec, unsigned& end_index, bool isRev ) {
+ std::vector< Node > c;
+ while( vec.size()>end_index && vec[ end_index ].isConst() ){
+ c.push_back( vec[ end_index ] );
+ end_index++;
+ //break;
+ }
+ if( !c.empty() ){
+ if( isRev ){
+ std::reverse( c.begin(), c.end() );
+ }
+ Node cc = Rewriter::rewrite( mkConcat( kind::STRING_CONCAT, c ) );
+ Assert( cc.isConst() );
+ return cc;
+ }else{
+ return Node::null();
+ }
+}
+
diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h
index 59588eda2..e166bfaeb 100644
--- a/src/theory/strings/theory_strings_rewriter.h
+++ b/src/theory/strings/theory_strings_rewriter.h
@@ -61,6 +61,12 @@ public:
static void getConcat( Node n, std::vector< Node >& c );
static Node mkConcat( Kind k, std::vector< Node >& c );
static Node splitConstant( Node a, Node b, int& index, bool isRev );
+ /** return true if constant c can contain the concat n/list l in order
+ firstc/lastc store which indices were used */
+ static bool canConstantContainConcat( Node c, Node n, int& firstc, int& lastc );
+ static bool canConstantContainList( Node c, std::vector< Node >& l, int& firstc, int& lastc );
+ static Node getNextConstantAt( std::vector< Node >& vec, unsigned& start_index, unsigned& end_index, bool isRev );
+ static Node collectConstantStringAt( std::vector< Node >& vec, unsigned& end_index, bool isRev );
};/* class TheoryStringsRewriter */
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index 7e2b6df55..7fa74df6a 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -66,6 +66,7 @@ Theory::Theory(TheoryId id, context::Context* satContext,
, d_sharedTermsIndex(satContext, 0)
, d_careGraph(NULL)
, d_quantEngine(NULL)
+ , d_extt(NULL)
, d_checkTime(getFullInstanceName() + "::checkTime")
, d_computeCareGraphTime(getFullInstanceName() + "::computeCareGraphTime")
, d_sharedTerms(satContext)
@@ -311,5 +312,145 @@ TheoryId EntailmentCheckSideEffects::getTheoryId() const {
EntailmentCheckSideEffects::~EntailmentCheckSideEffects() {
}
+
+ExtTheory::ExtTheory( Theory * p ) : d_parent( p ),
+d_ext_func_terms( p->getSatContext() ), d_has_extf( p->getSatContext() ){
+
+}
+
+void ExtTheory::collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited ) {
+ if( !n.isConst() ){
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getNumChildren()>0 ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectVars( n[i], vars, visited );
+ }
+ }else{
+ vars.push_back( n );
+ }
+ }
+ }
+}
+
+//do inferences
+void ExtTheory::getInferences( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp ) {
+ //all variables we need to find a substitution for
+ std::vector< Node > vars;
+ std::vector< Node > sub;
+ std::map< Node, std::vector< Node > > expc;
+ Trace("extt-debug") << "Checking " << d_ext_func_terms.size() << " extended functions." << std::endl;
+ for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
+ //if not already reduced
+ if( (*it).second ){
+ Node n = (*it).first;
+ terms.push_back( n );
+ std::map< Node, ExtfInfo >::iterator iti = d_extf_info.find( n );
+ Assert( iti!=d_extf_info.end() );
+ for( unsigned i=0; i<iti->second.d_vars.size(); i++ ){
+ if( std::find( vars.begin(), vars.end(), iti->second.d_vars[i] )==vars.end() ){
+ vars.push_back( iti->second.d_vars[i] );
+ }
+ }
+ }
+ }
+ Trace("extt-debug") << "..." << terms.size() << " unreduced." << std::endl;
+ if( !terms.empty() ){
+ //get the current substitution
+ if( d_parent->getCurrentSubstitution( effort, vars, sub, expc ) ){
+ for( unsigned i=0; i<terms.size(); i++ ){
+ //do substitution, rewrite
+ Node n = terms[i];
+ Node ns = n.substitute( vars.begin(), vars.end(), sub.begin(), sub.end() );
+ std::vector< Node > expn;
+ if( ns!=n ){
+ //build explanation: explanation vars = sub for each vars in FV( n )
+ std::map< Node, ExtfInfo >::iterator iti = d_extf_info.find( n );
+ Assert( iti!=d_extf_info.end() );
+ for( unsigned j=0; j<iti->second.d_vars.size(); j++ ){
+ Node v = iti->second.d_vars[j];
+ std::map< Node, std::vector< Node > >::iterator itx = expc.find( v );
+ if( itx!=expc.end() ){
+ for( unsigned k=0; k<itx->second.size(); k++ ){
+ if( std::find( expn.begin(), expn.end(), itx->second[k] )==expn.end() ){
+ expn.push_back( itx->second[k] );
+ }
+ }
+ }
+ }
+ }
+ Trace("extt-debug") << " have " << n << " == " << ns << ", exp size=" << expn.size() << "." << std::endl;
+ //add to vector
+ sterms.push_back( ns );
+ exp.push_back( expn );
+ }
+ }else{
+ for( unsigned i=0; i<terms.size(); i++ ){
+ sterms.push_back( terms[i] );
+ }
+ }
+ }
+}
+
+//register term
+void ExtTheory::registerTerm( Node n ) {
+ if( d_extf_kind.find( n.getKind() )!=d_extf_kind.end() ){
+ if( d_ext_func_terms.find( n )==d_ext_func_terms.end() ){
+ Trace("extt-debug") << "Found extended function : " << n << " in " << d_parent->getId() << std::endl;
+ d_ext_func_terms[n] = true;
+ d_has_extf = true;
+ std::map< Node, bool > visited;
+ collectVars( n, d_extf_info[n].d_vars, visited );
+ }
+ }
+}
+
+//mark reduced
+void ExtTheory::markReduced( Node n ) {
+ d_ext_func_terms[n] = false;
+ //TODO update has_extf
+}
+
+//mark congruent
+void ExtTheory::markCongruent( Node a, Node b ) {
+ NodeBoolMap::const_iterator it = d_ext_func_terms.find( b );
+ if( it!=d_ext_func_terms.end() ){
+ if( d_ext_func_terms.find( a )==d_ext_func_terms.end() ){
+ d_ext_func_terms[a] = (*it).second;
+ }else{
+ d_ext_func_terms[a] = d_ext_func_terms[a] && (*it).second;
+ }
+ d_ext_func_terms[b] = false;
+ }
+}
+
+//is active
+bool ExtTheory::isActive( Node n ) {
+ NodeBoolMap::const_iterator it = d_ext_func_terms.find( n );
+ if( it!=d_ext_func_terms.end() ){
+ return (*it).second;
+ }else{
+ return false;
+ }
+}
+//get active
+void ExtTheory::getActive( std::vector< Node >& active ) {
+ for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
+ //if not already reduced
+ if( (*it).second ){
+ active.push_back( (*it).first );
+ }
+ }
+}
+
+void ExtTheory::getActive( std::vector< Node >& active, Kind k ) {
+ for( NodeBoolMap::iterator it = d_ext_func_terms.begin(); it != d_ext_func_terms.end(); ++it ){
+ //if not already reduced
+ if( (*it).second && (*it).first.getKind()==k ){
+ active.push_back( (*it).first );
+ }
+ }
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index e8518b1f6..ede06fd2d 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -48,6 +48,7 @@ namespace theory {
class QuantifiersEngine;
class TheoryModel;
class SubstitutionMap;
+class ExtTheory;
class EntailmentCheckParameters;
class EntailmentCheckSideEffects;
@@ -201,6 +202,9 @@ private:
protected:
+ /** extended theory */
+ ExtTheory * d_extt;
+
// === STATISTICS ===
/** time spent in check calls */
TimerStat d_checkTime;
@@ -565,7 +569,11 @@ public:
* - or call get() until done() is true.
*/
virtual void check(Effort level = EFFORT_FULL) { }
-
+
+ /**
+ * Needs last effort check?
+ */
+ virtual bool needsCheckLastEffort() { return false; }
/**
* T-propagate new literal assignments in the current context.
*/
@@ -589,7 +597,9 @@ public:
* class.
*/
virtual void collectModelInfo( TheoryModel* m, bool fullModel ){ }
-
+ /** if theories want to do something with model after building, do it here */
+ virtual void postProcessModel( TheoryModel* m ){ }
+
/**
* Return a decision request, if the theory has one, or the NULL node
* otherwise.
@@ -875,6 +885,16 @@ public:
*/
virtual std::pair<bool, Node> entailmentCheck(TNode lit, const EntailmentCheckParameters* params = NULL, EntailmentCheckSideEffects* out = NULL);
+ /* equality engine */
+ virtual eq::EqualityEngine * getEqualityEngine() { return NULL; }
+
+ /* get current substitution at an effort
+ * input : vars
+ * output : subs, exp
+ * where ( exp[vars[i]] => vars[i] = subs[i] ) holds for all i
+ */
+ virtual bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) { return false; }
+
/**
* Turn on proof-production mode.
*/
@@ -944,6 +964,49 @@ public:
virtual ~EntailmentCheckSideEffects();
};/* class EntailmentCheckSideEffects */
+
+class ExtTheory {
+ friend class Theory;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+protected:
+ Theory * d_parent;
+ //extended string terms, map to whether they are active
+ NodeBoolMap d_ext_func_terms;
+ //any non-reduced extended functions exist
+ context::CDO< bool > d_has_extf;
+ //extf kind
+ std::map< Kind, bool > d_extf_kind;
+ //information for extf
+ class ExtfInfo {
+ public:
+ //all variables in this term
+ std::vector< Node > d_vars;
+ };
+ std::map< Node, ExtfInfo > d_extf_info;
+ //collect variables
+ void collectVars( Node n, std::vector< Node >& vars, std::map< Node, bool >& visited );
+public:
+ ExtTheory( Theory * p );
+ virtual ~ExtTheory(){}
+ //add extf kind
+ void addFunctionKind( Kind k ) { d_extf_kind[k] = true; }
+ //do inferences
+ // input : effort
+ // output : terms, sterms, exp, where ( exp[i] => terms[i] = sterms[i] ) for all i
+ void getInferences( int effort, std::vector< Node >& terms, std::vector< Node >& sterms, std::vector< std::vector< Node > >& exp );
+ //register term
+ void registerTerm( Node n );
+ //mark reduced
+ void markReduced( Node n );
+ //mark congruent
+ void markCongruent( Node a, Node b );
+ //is active
+ bool isActive( Node n );
+ //get active
+ void getActive( std::vector< Node >& active );
+ void getActive( std::vector< Node >& active, Kind k );
+};
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 881acdddd..94281156f 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -83,33 +83,8 @@ theory::LemmaStatus TheoryEngine::EngineOutputChannel::lemma(TNode lemma,
++ 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);
+ registerLemmaRecipe(lemma, lemma, preprocess, d_theory);
});
theory::LemmaStatus result = d_engine->lemma(lemma,
@@ -117,22 +92,101 @@ theory::LemmaStatus TheoryEngine::EngineOutputChannel::lemma(TNode lemma,
false,
removable,
preprocess,
- sendAtoms ? d_theory : theory::THEORY_LAST,
- proofRecipe);
- PROOF(delete proofRecipe;);
+ sendAtoms ? d_theory : theory::THEORY_LAST);
return result;
}
+void TheoryEngine::EngineOutputChannel::registerLemmaRecipe(Node lemma, Node originalLemma, bool preprocess, theory::TheoryId theoryId) {
+ // During CNF conversion, conjunctions will be broken down into
+ // multiple lemmas. In order for the recipes to match, we have to do
+ // the same here.
+ NodeManager* nm = NodeManager::currentNM();
+
+ if (preprocess)
+ lemma = d_engine->preprocess(lemma);
+
+ bool negated = (lemma.getKind() == kind::NOT);
+ Node nnLemma = negated ? lemma[0] : lemma;
+
+ switch (nnLemma.getKind()) {
+
+ case kind::AND:
+ if (!negated) {
+ for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
+ registerLemmaRecipe(nnLemma[i], originalLemma, false, theoryId);
+ } else {
+ NodeBuilder<> builder(kind::OR);
+ for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
+ builder << nnLemma[i].negate();
+
+ Node disjunction = (builder.getNumChildren() == 1) ? builder[0] : builder;
+ registerLemmaRecipe(disjunction, originalLemma, false, theoryId);
+ }
+ break;
+
+ case kind::IFF:
+ if (!negated) {
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[1].negate()), originalLemma, false, theoryId);
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1]), originalLemma, false, theoryId);
+ } else {
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[1]), originalLemma, false, theoryId);
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1].negate()), originalLemma, false, theoryId);
+ }
+ break;
+
+ case kind::ITE:
+ if (!negated) {
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1]), originalLemma, false, theoryId);
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[2]), originalLemma, false, theoryId);
+ } else {
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1].negate()), originalLemma, false, theoryId);
+ registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[2].negate()), originalLemma, false, theoryId);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Theory lemmas have one step that proves the empty clause
+ LemmaProofRecipe proofRecipe;
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
+
+ // Remember the original lemma, so we can report this later when asked to
+ proofRecipe.setOriginalLemma(originalLemma);
+
+ // Record the assertions and rewrites
+ 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);
+ ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
+}
+
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);
+ theory::LemmaStatus result = d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory);
return result;
}
@@ -157,6 +211,14 @@ void TheoryEngine::finishInit() {
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
+ //initialize the model
+ if( d_logicInfo.isQuantified() ) {
+ d_curr_model = d_quantEngine->getModel();
+ } else {
+ d_curr_model = new theory::TheoryModel(d_userContext, "DefaultModel", true);
+ d_aloc_curr_model = true;
+ }
+
if (d_logicInfo.isQuantified()) {
d_quantEngine->finishInit();
Assert(d_masterEqualityEngine == 0);
@@ -217,6 +279,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_masterEENotify(*this),
d_quantEngine(NULL),
d_curr_model(NULL),
+ d_aloc_curr_model(false),
d_curr_model_builder(NULL),
d_ppCache(),
d_possiblePropagations(context),
@@ -254,7 +317,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
}
// build model information if applicable
- d_curr_model = new theory::TheoryModel(userContext, "DefaultModel", true);
d_curr_model_builder = new theory::TheoryEngineModelBuilder(this);
smtStatisticsRegistry()->registerStat(&d_combineTheoriesTime);
@@ -281,7 +343,9 @@ TheoryEngine::~TheoryEngine() {
}
delete d_curr_model_builder;
- delete d_curr_model;
+ if( d_aloc_curr_model ){
+ delete d_curr_model;
+ }
delete d_quantEngine;
@@ -518,24 +582,30 @@ 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() ) {
- //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);
+ //checks for theories requiring the model go at last call
+ bool builtModel = false;
+ for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
+ if( theoryId!=THEORY_QUANTIFIERS ){
+ Theory* theory = d_theoryTable[theoryId];
+ if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
+ if( theory->needsCheckLastEffort() ){
+ if( !builtModel ){
+ builtModel = true;
+ d_curr_model_builder->buildModel(d_curr_model, false);
+ }
+ theory->check(Theory::EFFORT_LAST_CALL);
+ }
+ }
}
}
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
+ // if returning incomplete or SAT, we have ensured that d_curr_model has been built with fullModel=true
} else if(options::produceModels()) {
// must build model at this point
- d_curr_model_builder->buildModel(getModel(), true);
+ d_curr_model_builder->buildModel(d_curr_model, true);
}
Trace("theory::assertions-model") << endl;
if (Trace.isOn("theory::assertions-model")) {
@@ -611,8 +681,7 @@ void TheoryEngine::combineTheories() {
// We need to split on it
Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
- LemmaProofRecipe* proofRecipe = NULL;
- lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory, proofRecipe);
+ lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory);
// 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
@@ -780,16 +849,18 @@ void TheoryEngine::collectModelInfo( theory::TheoryModel* m, bool fullModel ){
}
}
+void TheoryEngine::postProcessModel( theory::TheoryModel* m ){
+ for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
+ if(d_logicInfo.isTheoryEnabled(theoryId)) {
+ Trace("model-builder-debug") << " PostProcessModel on theory: " << theoryId << endl;
+ d_theoryTable[theoryId]->postProcessModel( m );
+ }
+ }
+}
+
/* get model */
TheoryModel* TheoryEngine::getModel() {
- Debug("model") << "TheoryEngine::getModel()" << endl;
- if( d_logicInfo.isQuantified() ) {
- Debug("model") << "Get model from quantifiers engine." << endl;
- return d_quantEngine->getModel();
- } else {
- Debug("model") << "Get default model." << endl;
- return d_curr_model;
- }
+ return d_curr_model;
}
bool TheoryEngine::presolve() {
@@ -1596,8 +1667,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
bool negated,
bool removable,
bool preprocess,
- theory::TheoryId atomsTo,
- LemmaProofRecipe* proofRecipe) {
+ theory::TheoryId atomsTo) {
// For resource-limiting (also does a time check).
// spendResource();
@@ -1647,10 +1717,10 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, proofRecipe, node);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, proofRecipe, node);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
@@ -1709,10 +1779,11 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
// Process the explanation
getExplanation(explanationVector, proofRecipe);
+ PROOF(ProofManager::getCnfProof()->setProofRecipe(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, proofRecipe);
+ lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
} else {
// When only one theory, the conflict should need no processing
@@ -1738,9 +1809,11 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
proofRecipe->getStep(0)->addAssertion(conflict.negate());
proofRecipe->addBaseAssertion(conflict.negate());
}
+
+ ProofManager::getCnfProof()->setProofRecipe(proofRecipe);
});
- lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST, proofRecipe);
+ lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
}
PROOF({
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index 53c4aac77..9316066a5 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -183,6 +183,7 @@ class TheoryEngine {
* Default model object
*/
theory::TheoryModel* d_curr_model;
+ bool d_aloc_curr_model;
/**
* Model builder object
*/
@@ -321,6 +322,13 @@ class TheoryEngine {
void handleUserAttribute( const char* attr, theory::Theory* t ){
d_engine->handleUserAttribute( attr, t );
}
+
+ private:
+
+ /**
+ * A helper function for registering lemma recipes with the proof engine
+ */
+ void registerLemmaRecipe(Node lemma, Node originalLemma, bool preprocess, theory::TheoryId theoryId);
};/* class TheoryEngine::EngineOutputChannel */
/**
@@ -428,8 +436,7 @@ class TheoryEngine {
bool negated,
bool removable,
bool preprocess,
- theory::TheoryId atomsTo,
- LemmaProofRecipe* proofRecipe);
+ theory::TheoryId atomsTo);
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
@@ -710,6 +717,8 @@ public:
* collect model info
*/
void collectModelInfo( theory::TheoryModel* m, bool fullModel );
+ /** post process model */
+ void postProcessModel( theory::TheoryModel* m );
/**
* Get the current model
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index f43a2aa7f..3cdaeb106 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -56,6 +56,9 @@ TheoryModel::~TheoryModel() throw() {
void TheoryModel::reset(){
d_modelCache.clear();
+ d_comment_str.clear();
+ d_sep_heap = Node::null();
+ d_sep_nil_eq = Node::null();
d_reps.clear();
d_rep_set.clear();
d_uf_terms.clear();
@@ -64,6 +67,26 @@ void TheoryModel::reset(){
d_eeContext->push();
}
+void TheoryModel::getComments(std::ostream& out) const {
+ Trace("model-builder") << "get comments..." << std::endl;
+ out << d_comment_str.str();
+}
+
+void TheoryModel::setHeapModel( Node h, Node neq ) {
+ d_sep_heap = h;
+ d_sep_nil_eq = neq;
+}
+
+bool TheoryModel::getHeapModel( Expr& h, Expr& neq ) const {
+ if( d_sep_heap.isNull() || d_sep_nil_eq.isNull() ){
+ return false;
+ }else{
+ h = d_sep_heap.toExpr();
+ neq = d_sep_nil_eq.toExpr();
+ return true;
+ }
+}
+
Node TheoryModel::getValue(TNode n, bool useDontCares) const {
//apply substitutions
Node nn = d_substitutions.apply(n);
@@ -352,6 +375,11 @@ void TheoryModel::assertEqualityEngine(const eq::EqualityEngine* ee, set<Node>*
} else {
if (first) {
rep = (*eqc_i);
+ //add the term (this is specifically for the case of singleton equivalence classes)
+ if( !rep.getType().isRegExp() ){
+ d_equalityEngine->addTerm( rep );
+ Trace("model-builder-debug") << "Add term to ee within assertEqualityEngine: " << rep << std::endl;
+ }
first = false;
}
else {
@@ -651,7 +679,8 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
// Assign representative for this EC
if (!const_rep.isNull()) {
// Theories should not specify a rep if there is already a constant in the EC
- Assert(rep.isNull() || rep == const_rep);
+ //AJR: I believe this assertion is too strict, eqc with asserted reps may merge with constant eqc
+ //Assert(rep.isNull() || rep == const_rep);
assignConstantRep( tm, constantReps, eqc, const_rep, fullModel );
typeConstSet.add(eqct.getBaseType(), const_rep);
}
@@ -789,14 +818,16 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
//get properties of this type
bool isCorecursive = false;
- bool isUSortFiniteRestricted = false;
if( t.isDatatype() ){
const Datatype& dt = ((DatatypeType)(t).toType()).getDatatype();
isCorecursive = dt.isCodatatype() && ( !dt.isFinite() || dt.isRecursiveSingleton() );
}
+#ifdef CVC4_ASSERTIONS
+ bool isUSortFiniteRestricted = false;
if( options::finiteModelFind() ){
isUSortFiniteRestricted = !t.isSort() && involvesUSort( t );
}
+#endif
set<Node>* repSet = typeRepSet.getSet(t);
TypeNode tb = t.getBaseType();
@@ -841,8 +872,8 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
Assert( !n.isNull() );
success = true;
Trace("model-builder-debug") << "Check if excluded : " << n << std::endl;
- if( isUSortFiniteRestricted ){
#ifdef CVC4_ASSERTIONS
+ if( isUSortFiniteRestricted ){
//must not involve uninterpreted constants beyond cardinality bound (which assumed to coincide with #eqc)
//this is just an assertion now, since TypeEnumeratorProperties should ensure that only legal values are enumerated wrt this constraint.
std::map< Node, bool > visited;
@@ -851,8 +882,8 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
Trace("model-builder") << "Excluded value for " << t << " : " << n << " due to out of range uninterpreted constant." << std::endl;
}
Assert( success );
-#endif
}
+#endif
if( success && isCorecursive ){
if (repSet != NULL && !repSet->empty()) {
// in the case of codatatypes, check if it is in the set of values that we cannot assign
@@ -937,6 +968,12 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
//modelBuilder-specific initialization
processBuildModel( tm, fullModel );
+ // Do post-processing of model from the theories (used for THEORY_SEP to construct heap model)
+ if( fullModel ){
+ Trace("model-builder") << "TheoryEngineModelBuilder: Post-process model..." << std::endl;
+ d_te->postProcessModel(tm);
+ }
+
#ifdef CVC4_ASSERTIONS
if (fullModel) {
// Check that every term evaluates to its representative in the model
@@ -1015,7 +1052,7 @@ Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, std::map< Node
retNode = NodeManager::currentNM()->mkNode( r.getKind(), children );
if (childrenConst) {
retNode = Rewriter::rewrite(retNode);
- Assert(retNode.getKind()==kind::APPLY_UF || retNode.getKind()==kind::REGEXP_RANGE || retNode.isConst());
+ Assert(retNode.getKind()==kind::APPLY_UF || retNode.getType().isRegExp() || retNode.isConst());
}
}
d_normalizedCache[r] = retNode;
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index 833b124eb..7157433f9 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -53,7 +53,18 @@ public:
Node d_true;
Node d_false;
mutable std::hash_map<Node, Node, NodeHashFunction> d_modelCache;
-
+public:
+ /** comment stream to include in printing */
+ std::stringstream d_comment_str;
+ /** get comments */
+ void getComments(std::ostream& out) const;
+private:
+ /** information for separation logic */
+ Node d_sep_heap;
+ Node d_sep_nil_eq;
+public:
+ void setHeapModel( Node h, Node neq );
+ bool getHeapModel( Expr& h, Expr& neq ) const;
protected:
/** reset the model */
virtual void reset();
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 25b12f75f..09d348584 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -393,7 +393,7 @@ const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const
void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid) {
- Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << "), pid = " << pid << std::endl;
+ Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << "), reason = " << reason << ", pid = " << pid << std::endl;
if (d_done) {
return;
@@ -1204,7 +1204,6 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << d_name << "::eq::getExplanation(): adding: "
<< reason << std::endl;
Debug("equality") << d_name << "::eq::getExplanation(): reason type = " << reasonType << std::endl;
-
Node a = d_nodes[currentNode];
Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()];
diff --git a/src/util/integer_cln_imp.cpp b/src/util/integer_cln_imp.cpp
index 0064f2904..aa6cb03af 100644
--- a/src/util/integer_cln_imp.cpp
+++ b/src/util/integer_cln_imp.cpp
@@ -40,6 +40,10 @@ signed long Integer::s_slowSignedIntMax = (signed long) std::numeric_limits<sig
unsigned int Integer::s_fastUnsignedIntMax = (1<<29)-1;
unsigned long Integer::s_slowUnsignedIntMax = (unsigned long) std::numeric_limits<unsigned int>::max();
+unsigned long Integer::s_signedLongMin = std::numeric_limits<signed long>::min();
+unsigned long Integer::s_signedLongMax = std::numeric_limits<signed long>::max();
+unsigned long Integer::s_unsignedLongMax = std::numeric_limits<unsigned long>::max();
+
Integer Integer::oneExtend(uint32_t size, uint32_t amount) const {
DebugCheckArgument((*this) < Integer(1).multiplyByPow2(size), size);
cln::cl_byte range(amount, size);
@@ -133,4 +137,12 @@ unsigned int Integer::getUnsignedInt() const {
return cln::cl_I_to_uint(d_value);
}
+bool Integer::fitsSignedLong() const {
+ return d_value <= s_signedLongMax && d_value >= s_signedLongMin;
+}
+
+bool Integer::fitsUnsignedLong() const {
+ return sgn() >= 0 && d_value <= s_unsignedLongMax;
+}
+
} /* namespace CVC4 */
diff --git a/src/util/integer_cln_imp.h b/src/util/integer_cln_imp.h
index 177fc02cf..6bfebbaf1 100644
--- a/src/util/integer_cln_imp.h
+++ b/src/util/integer_cln_imp.h
@@ -66,7 +66,9 @@ private:
static signed long s_slowSignedIntMax; /* std::numeric_limits<signed int>::max() */
static signed long s_slowSignedIntMin; /* std::numeric_limits<signed int>::min() */
static unsigned long s_slowUnsignedIntMax; /* std::numeric_limits<unsigned int>::max() */
-
+ static unsigned long s_signedLongMin;
+ static unsigned long s_signedLongMax;
+ static unsigned long s_unsignedLongMax;
public:
/** Constructs a rational with the value 0. */
@@ -425,6 +427,10 @@ public:
unsigned int getUnsignedInt() const;
+ bool fitsSignedLong() const;
+
+ bool fitsUnsignedLong() const;
+
long getLong() const {
// ensure there isn't overflow
CheckArgument(d_value <= std::numeric_limits<long>::max(), this,
diff --git a/src/util/integer_gmp_imp.cpp b/src/util/integer_gmp_imp.cpp
index d165dbec3..e0472ac4c 100644
--- a/src/util/integer_gmp_imp.cpp
+++ b/src/util/integer_gmp_imp.cpp
@@ -73,6 +73,14 @@ unsigned int Integer::getUnsignedInt() const {
return (unsigned int) d_value.get_ui();
}
+bool Integer::fitsSignedLong() const {
+ return d_value.fits_slong_p();
+}
+
+bool Integer::fitsUnsignedLong() const {
+ return d_value.fits_ulong_p();
+}
+
Integer Integer::oneExtend(uint32_t size, uint32_t amount) const {
// check that the size is accurate
DebugCheckArgument((*this) < Integer(1).multiplyByPow2(size), size);
diff --git a/src/util/integer_gmp_imp.h b/src/util/integer_gmp_imp.h
index 0c5665e38..3a95c6b85 100644
--- a/src/util/integer_gmp_imp.h
+++ b/src/util/integer_gmp_imp.h
@@ -411,6 +411,10 @@ public:
unsigned int getUnsignedInt() const;
+ bool fitsSignedLong() const;
+
+ bool fitsUnsignedLong() const;
+
long getLong() const {
long si = d_value.get_si();
// ensure there wasn't overflow
diff --git a/src/util/regexp.cpp b/src/util/regexp.cpp
index d211aaf1b..a6f0de4b3 100644
--- a/src/util/regexp.cpp
+++ b/src/util/regexp.cpp
@@ -110,6 +110,17 @@ std::size_t String::overlap(String &y) const {
}
return i;
}
+std::size_t String::roverlap(String &y) const {
+ std::size_t i = d_str.size() < y.size() ? d_str.size() : y.size();
+ for(; i>0; i--) {
+ String s = prefix(i);
+ String p = y.suffix(i);
+ if(s == p) {
+ return i;
+ }
+ }
+ return i;
+}
std::string String::toString() const {
std::string str;
diff --git a/src/util/regexp.h b/src/util/regexp.h
index 2cfcbc4e4..06766e046 100644
--- a/src/util/regexp.h
+++ b/src/util/regexp.h
@@ -239,24 +239,25 @@ public:
if(d_str.size() < y.d_str.size() + start) return std::string::npos;
if(y.d_str.size() == 0) return start;
if(d_str.size() == 0) return std::string::npos;
- std::size_t ret = std::string::npos;
- /*for(std::size_t i = start; i <= d_str.size() - y.d_str.size(); i++) {
- if(d_str[i] == y.d_str[0]) {
- std::size_t j=0;
- for(; j<y.d_str.size(); j++) {
- if(d_str[i+j] != y.d_str[j]) break;
- }
- if(j == y.d_str.size()) {
- ret = i;
- break;
- }
- }
- }*/
std::vector<unsigned>::const_iterator itr = std::search(d_str.begin() + start, d_str.end(), y.d_str.begin(), y.d_str.end());
if(itr != d_str.end()) {
- ret = itr - d_str.begin();
+ return itr - d_str.begin();
+ }else{
+ return std::string::npos;
+ }
+ }
+
+ std::size_t rfind( String &y, const std::size_t start = 0) {
+ std::reverse( d_str.begin(), d_str.end() );
+ std::reverse( y.d_str.begin(), y.d_str.end() );
+ std::size_t f = find( y, start );
+ std::reverse( d_str.begin(), d_str.end() );
+ std::reverse( y.d_str.begin(), y.d_str.end() );
+ if( f==std::string::npos ){
+ return std::string::npos;
+ }else{
+ return f;
}
- return ret;
}
String replace(const String &s, const String &t) const {
@@ -295,6 +296,8 @@ public:
}
// if y=y1...yn and overlap returns m, then this is x1...y1...ym
std::size_t overlap(String &y) const;
+ // if y=y1...yn and overlap returns m, then this is y(n+1-m)...yn...xk
+ std::size_t roverlap(String &y) const;
bool isNumber() const {
if(d_str.size() == 0) return false;
diff --git a/test/regress/regress0/quantifiers/Makefile.am b/test/regress/regress0/quantifiers/Makefile.am
index 4c657adf1..6608ae22d 100644
--- a/test/regress/regress0/quantifiers/Makefile.am
+++ b/test/regress/regress0/quantifiers/Makefile.am
@@ -83,7 +83,10 @@ TESTS = \
partial-trigger.smt2 \
inst-max-level-segf.smt2 \
small-bug1-fixpoint-3.smt2 \
- z3.620661-no-fv-trigger.smt2
+ z3.620661-no-fv-trigger.smt2 \
+ bug_743.smt2 \
+ quaternion_ds1_symm_0428.fof.smt2 \
+ bug749-rounding.smt2
# regression can be solved with --finite-model-find --fmf-inst-engine
diff --git a/test/regress/regress0/quantifiers/bi-artm-s.smt2 b/test/regress/regress0/quantifiers/bi-artm-s.smt2
index 5fb7522e9..b97c339fc 100644
--- a/test/regress/regress0/quantifiers/bi-artm-s.smt2
+++ b/test/regress/regress0/quantifiers/bi-artm-s.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --fmf-bound-int-lazy
+; COMMAND-LINE: --fmf-bound-lazy
; EXPECT: unsat
(set-option :incremental "false")
(set-info :status unsat)
diff --git a/test/regress/regress0/quantifiers/bug749-rounding.smt2 b/test/regress/regress0/quantifiers/bug749-rounding.smt2
new file mode 100644
index 000000000..5fea8d4ff
--- /dev/null
+++ b/test/regress/regress0/quantifiers/bug749-rounding.smt2
@@ -0,0 +1,11 @@
+; COMMAND-LINE: --var-ineq-elim-quant
+; EXPECT: unknown
+(set-logic UFLIRA)
+
+(declare-fun round2 (Real) Int)
+
+(assert (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (round2 x) i)) ))
+(assert (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (round2 x))) ))
+
+
+(check-sat)
diff --git a/test/regress/regress0/quantifiers/bug_743.smt2 b/test/regress/regress0/quantifiers/bug_743.smt2
new file mode 100644
index 000000000..4e3ee0c96
--- /dev/null
+++ b/test/regress/regress0/quantifiers/bug_743.smt2
@@ -0,0 +1,774 @@
+;; produced by cvc4_14.drv ;;
+(set-logic AUFBVDTNIRA)
+(set-info :source |VC generated by SPARK 2014|)
+(set-info :smt-lib-version 2.0)
+(set-info :category industrial)
+(set-info :status unsat)
+;;; generated by SMT-LIB2 driver
+;;; SMT-LIB2 driver: bit-vectors, common part
+;;; SMT-LIB2: integer arithmetic
+(declare-datatypes () ((tuple0 (Tuple0))))
+(declare-sort us_private 0)
+
+(declare-fun us_null_ext__ () us_private)
+
+(declare-sort us_type_of_heap 0)
+
+(declare-datatypes ()
+((us_type_of_heap__ref
+ (mk___type_of_heap__ref (us_type_of_heap__content us_type_of_heap)))))
+(declare-sort us_image 0)
+
+(declare-datatypes () ((int__ref (mk_int__ref (int__content Int)))))
+(declare-datatypes () ((bool__ref (mk_bool__ref (bool__content Bool)))))
+(declare-datatypes () ((real__ref (mk_real__ref (real__content Real)))))
+(declare-datatypes ()
+((us_private__ref (mk___private__ref (us_private__content us_private)))))
+(define-fun int__ref___projection ((a int__ref)) Int (int__content a))
+
+(define-fun bool__ref___projection ((a bool__ref)) Bool (bool__content a))
+
+(define-fun real__ref___projection ((a real__ref)) Real (real__content a))
+
+(define-fun us_private__ref___projection ((a us_private__ref)) us_private
+ (us_private__content a))
+
+(declare-fun us_compatible_tags (Int Int) Bool)
+
+;; __compatible_tags_refl
+ (assert (forall ((tag Int)) (us_compatible_tags tag tag)))
+
+(define-fun to_int1 ((b Bool)) Int (ite (= b true) 1 0))
+
+(define-fun of_int ((i Int)) Bool (ite (= i 0) false true))
+
+(define-fun in_range ((x Int)) Bool (or (= x 0) (= x 1)))
+
+(declare-fun attr__ATTRIBUTE_IMAGE (Bool) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE (us_image) Bool)
+
+(declare-sort integer 0)
+
+(define-fun in_range1 ((x Int)) Bool (and (<= (- 2147483648) x)
+ (<= x 2147483647)))
+
+(define-fun bool_eq ((x Int) (y Int)) Bool (ite (= x y) true false))
+
+(declare-fun attr__ATTRIBUTE_IMAGE1 (Int) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check1 (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE1 (us_image) Int)
+
+(declare-fun to_rep (integer) Int)
+
+(declare-fun of_rep (Int) integer)
+
+(declare-fun user_eq (integer integer) Bool)
+
+(declare-fun dummy () integer)
+
+;; inversion_axiom
+ (assert
+ (forall ((x integer)) (! (= (of_rep (to_rep x)) x) :pattern ((to_rep x))
+)))
+
+;; range_axiom
+ (assert
+ (forall ((x integer)) (! (in_range1 (to_rep x)) :pattern ((to_rep x))
+)))
+
+;; coerce_axiom
+ (assert
+ (forall ((x Int))
+ (! (=> (in_range1 x) (= (to_rep (of_rep x)) x)) :pattern ((to_rep
+ (of_rep x)))
+)))
+
+(declare-datatypes ()
+((integer__ref (mk_integer__ref (integer__content integer)))))
+(define-fun integer__ref___projection ((a integer__ref)) integer
+(integer__content
+ a))
+
+(declare-sort natural 0)
+
+(define-fun in_range2 ((x Int)) Bool (and (<= 0 x) (<= x 2147483647)))
+
+(define-fun bool_eq1 ((x Int) (y Int)) Bool (ite (= x y) true false))
+
+(declare-fun attr__ATTRIBUTE_IMAGE2 (Int) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check2 (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE2 (us_image) Int)
+
+(declare-fun to_rep1 (natural) Int)
+
+(declare-fun of_rep1 (Int) natural)
+
+(declare-fun user_eq1 (natural natural) Bool)
+
+(declare-fun dummy1 () natural)
+
+;; inversion_axiom
+ (assert
+ (forall ((x natural))
+ (! (= (of_rep1 (to_rep1 x)) x) :pattern ((to_rep1 x)) )))
+
+;; range_axiom
+ (assert
+ (forall ((x natural)) (! (in_range2 (to_rep1 x)) :pattern ((to_rep1 x))
+)))
+
+;; coerce_axiom
+ (assert
+ (forall ((x Int))
+ (! (=> (in_range2 x) (= (to_rep1 (of_rep1 x)) x)) :pattern ((to_rep1
+ (of_rep1
+x))) )))
+
+(declare-datatypes ()
+((natural__ref (mk_natural__ref (natural__content natural)))))
+(define-fun natural__ref___projection ((a natural__ref)) natural
+(natural__content
+ a))
+
+(define-fun dynamic_invariant ((temp___expr_33 Int) (temp___is_init_30
+Bool)
+ (temp___do_constant_31 Bool)
+ (temp___do_toplevel_32 Bool)) Bool (=>
+ (or (= temp___is_init_30 true)
+ (<= 0 2147483647)) (in_range2
+ temp___expr_33)))
+
+(declare-sort index 0)
+
+(define-fun in_range3 ((x Int)) Bool (and (<= 1 x) (<= x 100)))
+
+(define-fun bool_eq2 ((x Int) (y Int)) Bool (ite (= x y) true false))
+
+(declare-fun attr__ATTRIBUTE_IMAGE3 (Int) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check3 (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE3 (us_image) Int)
+
+(declare-fun to_rep2 (index) Int)
+
+(declare-fun of_rep2 (Int) index)
+
+(declare-fun user_eq2 (index index) Bool)
+
+(declare-fun dummy2 () index)
+
+;; inversion_axiom
+ (assert
+ (forall ((x index))
+ (! (= (of_rep2 (to_rep2 x)) x) :pattern ((to_rep2 x)) )))
+
+;; range_axiom
+ (assert
+ (forall ((x index)) (! (in_range3 (to_rep2 x)) :pattern ((to_rep2 x))
+)))
+
+;; coerce_axiom
+ (assert
+ (forall ((x Int))
+ (! (=> (in_range3 x) (= (to_rep2 (of_rep2 x)) x)) :pattern ((to_rep2
+ (of_rep2
+x))) )))
+
+(declare-datatypes () ((index__ref (mk_index__ref (index__content
+index)))))
+(define-fun index__ref___projection ((a index__ref)) index (index__content
+a))
+
+(define-fun dynamic_invariant1 ((temp___expr_144 Int)
+ (temp___is_init_141 Bool) (temp___do_constant_142 Bool)
+ (temp___do_toplevel_143 Bool)) Bool (=>
+ (or (= temp___is_init_141 true)
+ (<= 1 100)) (in_range3
+ temp___expr_144)))
+
+(declare-datatypes ()
+((map__ref (mk_map__ref (map__content (Array Int natural))))))
+(declare-fun bool_eq3 ((Array Int natural) Int Int (Array Int natural) Int
+ Int) Bool)
+
+;; T__ada_array___equal_def
+ (assert
+ (forall ((a (Array Int natural)))
+ (forall ((af Int))
+ (forall ((al Int))
+ (forall ((b (Array Int natural)))
+ (forall ((bf Int))
+ (forall ((bl Int))
+ (! (=
+ (and (ite (<= af al) (= (+ (- al af) 1) (+ (- bl bf) 1)) (< bl bf))
+ (forall ((i Int))
+ (! (=> (and (<= af i) (<= i al))
+ (= (select a i) (select b (+ (- bf af) i)))) :pattern ((select a
+i)) )))
+ (= (bool_eq3 a af al b bf bl) true)) :pattern ((bool_eq3 a af al b bf
+ bl)) ))))))))
+
+(declare-fun slide ((Array Int natural) Int Int) (Array Int natural))
+
+;; slide_eq
+ (assert
+ (forall ((a (Array Int natural)))
+ (forall ((first Int))
+ (! (= (slide a first first) a) :pattern ((slide a first first)) ))))
+
+;; slide_def
+ (assert
+ (forall ((a (Array Int natural)))
+ (forall ((old_first Int))
+ (forall ((new_first Int))
+ (forall ((i Int))
+ (! (= (select (slide a old_first new_first) i) (select a (- i (-
+new_first old_first)))) :pattern ((select
+ (slide a old_first new_first) i)) ))))))
+
+(declare-fun concat1 ((Array Int natural) Int Int (Array Int natural) Int
+ Int) (Array Int natural))
+
+;; concat_def
+ (assert
+ (forall ((a (Array Int natural)) (b (Array Int natural)))
+ (forall ((a_first Int) (a_last Int) (b_first Int) (b_last Int))
+ (forall ((i Int))
+ (! (and
+ (=> (and (<= a_first i) (<= i a_last))
+ (= (select (concat1 a a_first a_last b b_first b_last) i) (select a
+i)))
+ (=> (< a_last i)
+ (= (select (concat1 a a_first a_last b b_first b_last) i) (select b
+(+ (- i a_last) (- b_first 1)))))) :pattern ((select
+ (concat1 a a_first a_last b b_first b_last) i)) )))))
+
+(declare-fun singleton (natural Int) (Array Int natural))
+
+;; singleton_def
+ (assert
+ (forall ((v natural))
+ (forall ((i Int))
+ (! (= (select (singleton v i) i) v) :pattern ((select (singleton v i)
+i)) ))))
+
+(declare-fun compare ((Array Int natural) Int Int (Array Int natural) Int
+ Int) Int)
+
+;; compare_def
+ (assert
+ (forall ((a (Array Int natural)) (b (Array Int natural)))
+ (forall ((a_first Int) (a_last Int) (b_first Int) (b_last Int))
+ (! (and
+ (= (= (compare a a_first a_last b b_first b_last) 0)
+ (= (bool_eq3 a a_first a_last b b_first b_last) true))
+ (and
+ (= (< (compare a a_first a_last b b_first b_last) 0)
+ (exists ((i Int) (j Int))
+ (and (<= i a_last)
+ (and (< j b_last)
+ (and (= (bool_eq3 a a_first i b b_first j) true)
+ (or (= i a_last)
+ (and (< i a_last)
+ (< (to_rep1 (select a (+ i 1))) (to_rep1 (select b (+ j 1)))))))))))
+ (= (< 0 (compare a a_first a_last b b_first b_last))
+ (exists ((i Int) (j Int))
+ (and (<= i b_last)
+ (and (< j a_last)
+ (and (= (bool_eq3 a a_first j b b_first i) true)
+ (or (= i b_last)
+ (and (< i b_last)
+ (< (to_rep1 (select b (+ i 1))) (to_rep1 (select a (+ j
+1))))))))))))) :pattern (
+ (compare a a_first a_last b b_first b_last)) ))))
+
+(declare-sort t 0)
+
+(declare-fun first (t) integer)
+
+(declare-fun last (t) integer)
+
+(declare-fun mk (Int Int) t)
+
+;; mk_def
+ (assert
+ (forall ((f Int) (l Int))
+ (! (=> (in_range1 f)
+ (=> (in_range1 l)
+ (and (= (to_rep (first (mk f l))) f) (= (to_rep (last (mk f l)))
+l)))) :pattern (
+ (mk f l)) )))
+
+(define-fun dynamic_property ((range_first Int) (range_last Int) (low Int)
+ (high Int)) Bool (and (in_range1 low)
+ (and (in_range1 high)
+ (=> (<= low high) (and (in_range3 low) (in_range3
+high))))))
+
+(declare-datatypes () ((us_t (mk___t (elts (Array Int natural))(rt t)))))
+(define-fun to_array ((a us_t)) (Array Int natural) (elts a))
+
+(define-fun of_array ((a (Array Int natural)) (f Int)
+ (l Int)) us_t (mk___t a (mk f l)))
+
+(define-fun first1 ((a us_t)) Int (to_rep (first (rt a))))
+
+(define-fun last1 ((a us_t)) Int (to_rep (last (rt a))))
+
+(define-fun length ((a us_t)) Int (ite (<= (first1 a) (last1 a))
+ (+ (- (last1 a) (first1 a)) 1) 0))
+
+(declare-fun value__size () Int)
+
+(declare-fun object__size ((Array Int natural)) Int)
+
+(declare-fun value__component__size () Int)
+
+(declare-fun object__component__size ((Array Int natural)) Int)
+
+(declare-fun value__alignment () Int)
+
+(declare-fun object__alignment ((Array Int natural)) Int)
+
+;; value__size_axiom
+ (assert (<= 0 value__size))
+
+;; object__size_axiom
+ (assert (forall ((a (Array Int natural))) (<= 0 (object__size a))))
+
+;; value__component__size_axiom
+ (assert (<= 0 value__component__size))
+
+;; object__component__size_axiom
+ (assert
+ (forall ((a (Array Int natural))) (<= 0 (object__component__size a))))
+
+;; value__alignment_axiom
+ (assert (<= 0 value__alignment))
+
+;; object__alignment_axiom
+ (assert (forall ((a (Array Int natural))) (<= 0 (object__alignment a))))
+
+(define-fun bool_eq4 ((x us_t)
+ (y us_t)) Bool (bool_eq3 (elts x) (to_rep (first (rt x)))
+ (to_rep (last (rt x))) (elts y) (to_rep (first (rt y)))
+ (to_rep (last (rt y)))))
+
+(declare-fun user_eq3 (us_t us_t) Bool)
+
+(declare-fun dummy3 () us_t)
+
+(declare-datatypes ()
+((nat_array__ref (mk_nat_array__ref (nat_array__content us_t)))))
+(define-fun nat_array__ref___projection ((a nat_array__ref)) us_t
+(nat_array__content
+ a))
+
+(define-fun dynamic_invariant2 ((temp___expr_150 us_t)
+ (temp___is_init_147 Bool) (temp___do_constant_148 Bool)
+ (temp___do_toplevel_149 Bool)) Bool (=>
+ (not (= temp___do_constant_148
+true))
+ (dynamic_property 1 100
+ (first1 temp___expr_150)
+ (last1 temp___expr_150))))
+
+(declare-fun remove_last (us_t) us_t)
+
+(declare-fun first2 () Int)
+
+(declare-fun last2 () Int)
+
+(define-fun dynamic_property1 ((first_int Int) (last_int Int)
+ (x Int)) Bool (and (<= first_int x) (<= x last_int)))
+
+(define-fun bool_eq5 ((x Int) (y Int)) Bool (ite (= x y) true false))
+
+(declare-fun attr__ATTRIBUTE_IMAGE4 (Int) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check4 (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE4 (us_image) Int)
+
+(declare-fun user_eq4 (integer integer) Bool)
+
+(declare-fun dummy4 () integer)
+
+(declare-datatypes () ((t15s__ref (mk_t15s__ref (t15s__content
+integer)))))
+(define-fun t15s__ref___projection ((a t15s__ref)) integer (t15s__content
+a))
+
+(declare-sort t1 0)
+
+(declare-fun first3 (t1) integer)
+
+(declare-fun last3 (t1) integer)
+
+(declare-fun mk1 (Int Int) t1)
+
+;; mk_def
+ (assert
+ (forall ((f Int) (l Int))
+ (! (=> (in_range1 f)
+ (=> (in_range1 l)
+ (and (= (to_rep (first3 (mk1 f l))) f) (= (to_rep (last3 (mk1 f l)))
+l)))) :pattern (
+ (mk1 f l)) )))
+
+(define-fun dynamic_property2 ((range_first Int) (range_last Int) (low
+Int)
+ (high Int)) Bool (and (in_range1 low)
+ (and (in_range1 high)
+ (=> (<= low high)
+ (and (dynamic_property1 range_first range_last low)
+ (dynamic_property1 range_first range_last high))))))
+
+(declare-datatypes ()
+((us_t1 (mk___t1 (elts1 (Array Int natural))(rt1 t1)))))
+(define-fun to_array1 ((a us_t1)) (Array Int natural) (elts1 a))
+
+(define-fun of_array1 ((a (Array Int natural)) (f Int)
+ (l Int)) us_t1 (mk___t1 a (mk1 f l)))
+
+(define-fun first4 ((a us_t1)) Int (to_rep (first3 (rt1 a))))
+
+(define-fun last4 ((a us_t1)) Int (to_rep (last3 (rt1 a))))
+
+(define-fun length1 ((a us_t1)) Int (ite (<= (first4 a) (last4 a))
+ (+ (- (last4 a) (first4 a)) 1) 0))
+
+(declare-fun value__size1 () Int)
+
+(declare-fun object__size1 ((Array Int natural)) Int)
+
+(declare-fun value__component__size1 () Int)
+
+(declare-fun object__component__size1 ((Array Int natural)) Int)
+
+(declare-fun value__alignment1 () Int)
+
+(declare-fun object__alignment1 ((Array Int natural)) Int)
+
+;; value__size_axiom
+ (assert (<= 0 value__size1))
+
+;; object__size_axiom
+ (assert (forall ((a (Array Int natural))) (<= 0 (object__size1 a))))
+
+;; value__component__size_axiom
+ (assert (<= 0 value__component__size1))
+
+;; object__component__size_axiom
+ (assert
+ (forall ((a (Array Int natural))) (<= 0 (object__component__size1 a))))
+
+;; value__alignment_axiom
+ (assert (<= 0 value__alignment1))
+
+;; object__alignment_axiom
+ (assert (forall ((a (Array Int natural))) (<= 0 (object__alignment1
+a))))
+
+(define-fun bool_eq6 ((x us_t1)
+ (y us_t1)) Bool (bool_eq3 (elts1 x) (to_rep (first3 (rt1 x)))
+ (to_rep (last3 (rt1 x))) (elts1 y)
+ (to_rep (first3 (rt1 y))) (to_rep (last3 (rt1 y)))))
+
+(declare-fun user_eq5 (us_t1 us_t1) Bool)
+
+(declare-fun dummy5 () us_t1)
+
+(declare-datatypes () ((t16s__ref (mk_t16s__ref (t16s__content us_t1)))))
+(define-fun t16s__ref___projection ((a t16s__ref)) us_t1 (t16s__content
+a))
+
+;; remove_last__post_axiom
+ (assert
+ (forall ((a us_t))
+ (! (=> (and (dynamic_invariant2 a true true true) (< 0 (length a)))
+ (dynamic_invariant2 (remove_last a) true false true)) :pattern (
+ (remove_last a)) )))
+
+;; remove_last__def_axiom
+ (assert
+ (forall ((a us_t))
+ (! (=> (dynamic_invariant2 a true true true)
+ (= (remove_last a) (let ((temp___163 (let ((temp___162 (- (last1 a)
+1)))
+ (let ((temp___161 (first1 a)))
+ (of_array1 (to_array a)
+temp___161
+ temp___162)))))
+ (of_array (to_array1 temp___163) (first4
+temp___163)
+ (last4 temp___163))))) :pattern ((remove_last a))
+)))
+
+(declare-fun occ (us_t Int) Int)
+
+(declare-sort nb_occ 0)
+
+(define-fun in_range4 ((x Int)) Bool (and (<= 0 x) (<= x 100)))
+
+(define-fun bool_eq7 ((x Int) (y Int)) Bool (ite (= x y) true false))
+
+(declare-fun attr__ATTRIBUTE_IMAGE5 (Int) us_image)
+
+(declare-fun attr__ATTRIBUTE_VALUE__pre_check5 (us_image) Bool)
+
+(declare-fun attr__ATTRIBUTE_VALUE5 (us_image) Int)
+
+(declare-fun to_rep3 (nb_occ) Int)
+
+(declare-fun of_rep3 (Int) nb_occ)
+
+(declare-fun user_eq6 (nb_occ nb_occ) Bool)
+
+(declare-fun dummy6 () nb_occ)
+
+;; inversion_axiom
+ (assert
+ (forall ((x nb_occ))
+ (! (= (of_rep3 (to_rep3 x)) x) :pattern ((to_rep3 x)) )))
+
+;; range_axiom
+ (assert
+ (forall ((x nb_occ)) (! (in_range4 (to_rep3 x)) :pattern ((to_rep3 x))
+)))
+
+;; coerce_axiom
+ (assert
+ (forall ((x Int))
+ (! (=> (in_range4 x) (= (to_rep3 (of_rep3 x)) x)) :pattern ((to_rep3
+ (of_rep3
+x))) )))
+
+(declare-datatypes ()
+((nb_occ__ref (mk_nb_occ__ref (nb_occ__content nb_occ)))))
+(define-fun nb_occ__ref___projection ((a nb_occ__ref)) nb_occ
+(nb_occ__content
+ a))
+
+(define-fun dynamic_invariant3 ((temp___expr_155 Int)
+ (temp___is_init_152 Bool) (temp___do_constant_153 Bool)
+ (temp___do_toplevel_154 Bool)) Bool (=>
+ (or (= temp___is_init_152 true)
+ (<= 0 100)) (in_range4
+ temp___expr_155)))
+
+(declare-fun occ_def (us_t Int) Int)
+
+;; occ__post_axiom
+ (assert
+ (forall ((a us_t))
+ (forall ((e Int))
+ (! (=> (and (dynamic_invariant2 a true true true) (in_range2 e))
+ (let ((result (occ a e)))
+ (and (<= result (length a)) (dynamic_invariant3 result true false
+true)))) :pattern (
+ (occ a e)) ))))
+
+;; occ__def_axiom
+ (assert
+ (forall ((a us_t))
+ (forall ((e Int))
+ (! (=> (and (dynamic_invariant2 a true true true) (in_range2 e))
+ (= (occ a e) (occ_def a e))) :pattern ((occ a e)) ))))
+
+(declare-fun is_set (us_t Int Int us_t) Bool)
+
+;; is_set__def_axiom
+ (assert
+ (forall ((a us_t) (r us_t))
+ (forall ((i Int) (v Int))
+ (! (= (= (is_set a i v r) true)
+ (and
+ (and (and (= (first1 r) (first1 a)) (= (last1 r) (last1 a)))
+ (= (to_rep1 (select (to_array r) i)) v))
+ (forall ((j Int))
+ (=> (and (<= (first1 a) j) (<= j (last1 a)))
+ (=> (not (= i j))
+ (= (to_rep1 (select (to_array r) j)) (to_rep1 (select (to_array a)
+j)))))))) :pattern (
+ (is_set a i v r)) ))))
+
+(declare-fun a () us_t)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS () Int)
+
+(declare-fun i () Int)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS1 () Int)
+
+(declare-fun v () Int)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS2 () Int)
+
+(declare-fun e () Int)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS3 () Int)
+
+(declare-fun r () us_t)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS4 () Int)
+
+(declare-fun b__first () integer)
+
+(declare-fun b__last () integer)
+
+(declare-fun attr__ATTRIBUTE_ADDRESS5 () Int)
+
+(define-fun dynamic_invariant4 ((temp___expr_15 Int) (temp___is_init_12
+Bool)
+ (temp___do_constant_13 Bool)
+ (temp___do_toplevel_14 Bool)) Bool (=>
+ (or (= temp___is_init_12 true)
+ (<= (- 2147483648) 2147483647))
+ (in_range1 temp___expr_15)))
+
+;; occ_def__def_axiom
+ (assert
+ (forall ((a1 us_t))
+ (forall ((e1 Int))
+ (! (=> (and (dynamic_invariant2 a1 true true true) (in_range2 e1))
+ (= (occ_def a1 e1) (ite (= (length a1) 0) 0
+ (ite (= (to_rep1 (select (to_array a1) (last1
+a1))) e1)
+ (+ (occ_def (remove_last a1) e1) 1)
+ (occ_def (remove_last a1) e1))))) :pattern
+((occ_def
+ a1
+e1)) ))))
+
+(declare-fun b () (Array Int natural))
+
+(declare-fun perm__occ_set__b__assume () (Array Int natural))
+
+(declare-fun perm__occ_set__b__assume1 () t)
+
+(declare-fun o () natural)
+
+(declare-fun o1 () Int)
+
+(declare-fun o2 () (Array Int natural))
+
+(declare-fun o3 () (Array Int natural))
+
+(declare-fun o4 () t)
+
+(declare-fun result () (Array Int natural))
+
+(declare-fun b1 () (Array Int natural))
+
+(declare-fun result1 () (Array Int natural))
+
+(declare-fun b2 () (Array Int natural))
+
+(define-fun o5 () us_t (mk___t o3 o4))
+
+(define-fun perm__occ_set__b__assume2 () us_t (mk___t
+ perm__occ_set__b__assume
+ perm__occ_set__b__assume1))
+
+;; H
+ (assert (dynamic_invariant2 a true false true))
+
+;; H
+ (assert (in_range3 i))
+
+;; H
+ (assert (in_range2 v))
+
+;; H
+ (assert (in_range2 e))
+
+;; H
+ (assert (dynamic_invariant2 r true false true))
+
+;; H
+ (assert
+ (and (and (<= (to_rep (first (rt a))) i) (<= i (to_rep (last (rt a)))))
+ (= (is_set a i v r) true)))
+
+;; H
+ (assert
+ (and (= perm__occ_set__b__assume2 (remove_last a))
+ (and (dynamic_invariant2 perm__occ_set__b__assume2 true false true)
+ (and (= (elts a) perm__occ_set__b__assume)
+ (= (mk
+ (to_rep
+ (first3 (mk1 (to_rep (first (rt a))) (- (to_rep (last (rt a))) 1))))
+ (to_rep
+ (last3 (mk1 (to_rep (first (rt a))) (- (to_rep (last (rt a))) 1)))))
+ perm__occ_set__b__assume1)))))
+
+;; H
+ (assert (= (mk_map__ref result) (mk_map__ref b)))
+
+;; H
+ (assert (= b1 perm__occ_set__b__assume))
+
+;; H
+ (assert (= (to_rep b__first) (to_rep (first
+perm__occ_set__b__assume1))))
+
+;; H
+ (assert (= (to_rep b__last) (to_rep (last perm__occ_set__b__assume1))))
+
+;; H
+ (assert (dynamic_property 1 100 (to_rep b__first) (to_rep b__last)))
+
+;; H
+ (assert (not (= (length a) 0)))
+
+;; H
+ (assert (not (= i (to_rep (last (rt a))))))
+
+;; H
+ (assert (= (to_rep1 o) v))
+
+;; H
+ (assert (and (<= (to_rep b__first) i) (<= i (to_rep b__last))))
+
+;; H
+ (assert (= o1 i))
+
+;; H
+ (assert (= o2 (store b1 o1 o)))
+
+;; H
+ (assert (= b1 result1))
+
+;; H
+ (assert (= b2 o2))
+
+;; H
+ (assert
+ (and (= o5 (remove_last r))
+ (and (dynamic_invariant2 o5 true false true)
+ (and (= (elts r) o3)
+ (= (mk
+ (to_rep
+ (first3 (mk1 (to_rep (first (rt r))) (- (to_rep (last (rt r))) 1))))
+ (to_rep
+ (last3 (mk1 (to_rep (first (rt r))) (- (to_rep (last (rt r))) 1)))))
+ o4)))))
+
+(assert
+;; WP_parameter_def
+ ;; File "perm.ads", line 21, characters 0-0
+ (not
+ (= (bool_eq3 o3 (to_rep (first o4)) (to_rep (last o4)) b2
+ (to_rep (first (mk (to_rep b__first) (to_rep b__last))))
+ (to_rep (last (mk (to_rep b__first) (to_rep b__last))))) true)))
+(check-sat)
+
diff --git a/test/regress/regress0/quantifiers/quaternion_ds1_symm_0428.fof.smt2 b/test/regress/regress0/quantifiers/quaternion_ds1_symm_0428.fof.smt2
new file mode 100644
index 000000000..9b0216e58
--- /dev/null
+++ b/test/regress/regress0/quantifiers/quaternion_ds1_symm_0428.fof.smt2
@@ -0,0 +1,49 @@
+; COMMAND-LINE: --full-saturate-quant
+; EXPECT: unsat
+(set-logic AUFLIRA)
+(set-info :status unsat)
+(declare-fun def () Real)
+(declare-fun h_ds1_filter () (Array Int (Array Int Real)))
+(declare-fun id_ds1_filter () (Array Int (Array Int Real)))
+(declare-fun pminus_ds1_filter () (Array Int (Array Int Real)))
+(declare-fun pv5 () Int)
+(declare-fun q_ds1_filter () (Array Int (Array Int Real)))
+(declare-fun r_ds1_filter () (Array Int (Array Int Real)))
+(declare-fun use () Real)
+(declare-fun uniform_int_rnd (Int Int) Int)
+(declare-fun abs_ (Real) Real)
+(declare-fun log (Real) Real)
+(declare-fun exp (Real) Real)
+(declare-fun cos (Real) Real)
+(declare-fun sin (Real) Real)
+(declare-fun sqrt (Real) Real)
+(declare-fun divide (Real Real) Real)
+(declare-fun cond (Int Real Real) Real)
+(declare-fun tptp_term_equal (Real Real) Int)
+(declare-fun tptp_term_equals (Real Real) Int)
+(declare-fun tptp_term_and (Real Real) Int)
+(declare-fun sum (Int Int Real) Real)
+(declare-fun dim (Int Int) Int)
+(declare-fun trans ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
+(declare-fun inv ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
+(declare-fun tptp_mmul ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
+(declare-fun tptp_madd ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
+(declare-fun tptp_msub ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
+(declare-fun tptp_const_array1 (Int Real) (Array Int Real))
+(declare-fun tptp_const_array2 (Int Int Real) (Array Int (Array Int Real)))
+(assert (forall ((?X_0 Int) (?C_1 Int)) (=> (>= ?X_0 0) (<= (uniform_int_rnd ?C_1 ?X_0) ?X_0))))
+(assert (forall ((?X_2 Int) (?C_3 Int)) (=> (>= ?X_2 0) (>= (uniform_int_rnd ?C_3 ?X_2) 0))))
+(assert (forall ((?I_4 Int) (?L_5 Int) (?U_6 Int) (?Val_7 Real)) (=> (and (<= ?L_5 ?I_4) (<= ?I_4 ?U_6)) (= (select (tptp_const_array1 (dim ?L_5 ?U_6) ?Val_7) ?I_4) ?Val_7))))
+(assert (forall ((?I_8 Int) (?L1_9 Int) (?U1_10 Int) (?J_11 Int) (?L2_12 Int) (?U2_13 Int) (?Val_14 Real)) (=> (and (and (and (<= ?L1_9 ?I_8) (<= ?I_8 ?U1_10)) (<= ?L2_12 ?J_11)) (<= ?J_11 ?U2_13)) (= (select (select (tptp_const_array2 (dim ?L1_9 ?U1_10) (dim ?L2_12 ?U2_13) ?Val_14) ?I_8) ?J_11) ?Val_14))))
+(assert (forall ((?I0_15 Int) (?J0_16 Int) (?A_17 (Array Int (Array Int Real))) (?B_18 (Array Int (Array Int Real))) (?N_19 Int)) (let ((?v_0 (tptp_mmul ?A_17 (tptp_mmul ?B_18 (trans ?A_17))))) (=> (and (and (and (and (>= ?I0_15 0) (<= ?I0_15 ?N_19)) (>= ?J0_16 0)) (<= ?J0_16 ?N_19)) (= (select (select ?B_18 ?I0_15) ?J0_16) (select (select ?B_18 ?J0_16) ?I0_15))) (= (select (select ?v_0 ?I0_15) ?J0_16) (select (select ?v_0 ?J0_16) ?I0_15))))))
+(assert (forall ((?I0_20 Int) (?J0_21 Int) (?I_22 Int) (?J_23 Int) (?A_24 (Array Int (Array Int Real))) (?B_25 (Array Int (Array Int Real))) (?N_26 Int) (?M_27 Int)) (let ((?v_0 (tptp_mmul ?A_24 (tptp_mmul ?B_25 (trans ?A_24))))) (=> (and (and (and (and (and (and (and (and (>= ?I0_20 0) (<= ?I0_20 ?N_26)) (>= ?J0_21 0)) (<= ?J0_21 ?N_26)) (>= ?I_22 0)) (<= ?I_22 ?M_27)) (>= ?J_23 0)) (<= ?J_23 ?M_27)) (= (select (select ?B_25 ?I_22) ?J_23) (select (select ?B_25 ?J_23) ?I_22))) (= (select (select ?v_0 ?I0_20) ?J0_21) (select (select ?v_0 ?J0_21) ?I0_20))))))
+(assert (forall ((?I_28 Int) (?J_29 Int) (?A_30 (Array Int (Array Int Real))) (?B_31 (Array Int (Array Int Real))) (?N_32 Int)) (let ((?v_0 (tptp_madd ?A_30 ?B_31))) (=> (and (and (and (and (and (>= ?I_28 0) (<= ?I_28 ?N_32)) (>= ?J_29 0)) (<= ?J_29 ?N_32)) (= (select (select ?A_30 ?I_28) ?J_29) (select (select ?A_30 ?J_29) ?I_28))) (= (select (select ?B_31 ?I_28) ?J_29) (select (select ?B_31 ?J_29) ?I_28))) (= (select (select ?v_0 ?I_28) ?J_29) (select (select ?v_0 ?J_29) ?I_28))))))
+(assert (forall ((?I_33 Int) (?J_34 Int) (?A_35 (Array Int (Array Int Real))) (?B_36 (Array Int (Array Int Real))) (?N_37 Int)) (let ((?v_0 (tptp_msub ?A_35 ?B_36))) (=> (and (and (and (and (and (>= ?I_33 0) (<= ?I_33 ?N_37)) (>= ?J_34 0)) (<= ?J_34 ?N_37)) (= (select (select ?A_35 ?I_33) ?J_34) (select (select ?A_35 ?J_34) ?I_33))) (= (select (select ?B_36 ?I_33) ?J_34) (select (select ?B_36 ?J_34) ?I_33))) (= (select (select ?v_0 ?I_33) ?J_34) (select (select ?v_0 ?J_34) ?I_33))))))
+(assert (forall ((?I_38 Int) (?J_39 Int) (?A_40 (Array Int (Array Int Real))) (?N_41 Int)) (let ((?v_0 (trans ?A_40))) (=> (and (and (and (and (>= ?I_38 0) (<= ?I_38 ?N_41)) (>= ?J_39 0)) (<= ?J_39 ?N_41)) (= (select (select ?A_40 ?I_38) ?J_39) (select (select ?A_40 ?J_39) ?I_38))) (= (select (select ?v_0 ?I_38) ?J_39) (select (select ?v_0 ?J_39) ?I_38))))))
+(assert (forall ((?I_42 Int) (?J_43 Int) (?A_44 (Array Int (Array Int Real))) (?N_45 Int)) (let ((?v_0 (inv ?A_44))) (=> (and (and (and (and (>= ?I_42 0) (<= ?I_42 ?N_45)) (>= ?J_43 0)) (<= ?J_43 ?N_45)) (= (select (select ?A_44 ?I_42) ?J_43) (select (select ?A_44 ?J_43) ?I_42))) (= (select (select ?v_0 ?I_42) ?J_43) (select (select ?v_0 ?J_43) ?I_42))))))
+(assert (forall ((?I0_46 Int) (?J0_47 Int) (?I_48 Int) (?J_49 Int) (?A_50 (Array Int (Array Int Real))) (?B_51 (Array Int (Array Int Real))) (?C_52 (Array Int (Array Int Real))) (?D_53 (Array Int (Array Int Real))) (?E_54 (Array Int (Array Int Real))) (?F_55 (Array Int (Array Int Real))) (?N_56 Int) (?M_57 Int)) (let ((?v_0 (tptp_madd ?A_50 (tptp_mmul ?B_51 (tptp_mmul (tptp_madd (tptp_mmul ?C_52 (tptp_mmul ?D_53 (trans ?C_52))) (tptp_mmul ?E_54 (tptp_mmul ?F_55 (trans ?E_54)))) (trans ?B_51)))))) (=> (and (and (and (and (and (and (and (and (and (and (>= ?I0_46 0) (<= ?I0_46 ?N_56)) (>= ?J0_47 0)) (<= ?J0_47 ?N_56)) (>= ?I_48 0)) (<= ?I_48 ?M_57)) (>= ?J_49 0)) (<= ?J_49 ?M_57)) (= (select (select ?D_53 ?I_48) ?J_49) (select (select ?D_53 ?J_49) ?I_48))) (= (select (select ?A_50 ?I0_46) ?J0_47) (select (select ?A_50 ?J0_47) ?I0_46))) (= (select (select ?F_55 ?I0_46) ?J0_47) (select (select ?F_55 ?J0_47) ?I0_46))) (= (select (select ?v_0 ?I0_46) ?J0_47) (select (select ?v_0 ?J0_47) ?I0_46))))))
+(assert (forall ((?Body_58 Real)) (= (sum 0 (- 1) ?Body_58) 0.0)))
+(assert (not (= def use)))
+(assert (not (=> (and (and (and (and (and (and (>= pv5 0) (<= pv5 998)) (> pv5 0)) (forall ((?A_59 Int) (?B_60 Int)) (=> (and (and (and (>= ?A_59 0) (>= ?B_60 0)) (<= ?A_59 5)) (<= ?B_60 5)) (= (select (select q_ds1_filter ?A_59) ?B_60) (select (select q_ds1_filter ?B_60) ?A_59))))) (forall ((?C_61 Int) (?D_62 Int)) (=> (and (and (and (>= ?C_61 0) (>= ?D_62 0)) (<= ?C_61 2)) (<= ?D_62 2)) (= (select (select r_ds1_filter ?C_61) ?D_62) (select (select r_ds1_filter ?D_62) ?C_61))))) (forall ((?E_63 Int) (?F_64 Int)) (=> (and (and (and (>= ?E_63 0) (>= ?F_64 0)) (<= ?E_63 5)) (<= ?F_64 5)) (= (select (select pminus_ds1_filter ?E_63) ?F_64) (select (select pminus_ds1_filter ?F_64) ?E_63))))) (forall ((?G_65 Int)) (=> (and (>= ?G_65 0) (<= ?G_65 5)) (forall ((?H_66 Int)) (=> (and (>= ?H_66 0) (<= ?H_66 5)) (= (select (select id_ds1_filter ?G_65) ?H_66) (select (select id_ds1_filter ?H_66) ?G_65))))))) (forall ((?I_67 Int) (?J_68 Int)) (let ((?v_0 (trans h_ds1_filter))) (let ((?v_1 (tptp_mmul pminus_ds1_filter (tptp_mmul ?v_0 (inv (tptp_madd r_ds1_filter (tptp_mmul h_ds1_filter (tptp_mmul pminus_ds1_filter ?v_0)))))))) (let ((?v_2 (tptp_mmul ?v_1 (tptp_mmul r_ds1_filter (trans ?v_1))))) (=> (and (and (and (>= ?I_67 0) (>= ?J_68 0)) (<= ?I_67 5)) (<= ?J_68 5)) (= (select (select ?v_2 ?I_67) ?J_68) (select (select ?v_2 ?J_68) ?I_67))))))))))
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/sep/Makefile.am b/test/regress/regress0/sep/Makefile.am
index 9d2abaa18..6078bfa19 100644
--- a/test/regress/regress0/sep/Makefile.am
+++ b/test/regress/regress0/sep/Makefile.am
@@ -53,7 +53,10 @@ TESTS = \
dispose-list-4-init.smt2 \
wand-0526-sat.smt2 \
quant_wand.smt2 \
- fmf-nemp-2.smt2
+ fmf-nemp-2.smt2 \
+ trees-1.smt2 \
+ wand-false.smt2 \
+ dup-nemp.smt2
FAILING_TESTS =
diff --git a/test/regress/regress0/sep/dup-nemp.smt2 b/test/regress/regress0/sep/dup-nemp.smt2
new file mode 100644
index 000000000..009561128
--- /dev/null
+++ b/test/regress/regress0/sep/dup-nemp.smt2
@@ -0,0 +1,7 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+(declare-sort Loc 0)
+(declare-const l Loc)
+(assert (sep (not (emp l)) (not (emp l))))
+(assert (pto l l))
+(check-sat)
diff --git a/test/regress/regress0/sep/split-find-unsat.smt2 b/test/regress/regress0/sep/split-find-unsat.smt2
index 54530cbf4..1731174fa 100644
--- a/test/regress/regress0/sep/split-find-unsat.smt2
+++ b/test/regress/regress0/sep/split-find-unsat.smt2
@@ -1,7 +1,7 @@
; COMMAND-LINE: --no-check-models
-; EXPECT: sat
+; EXPECT: unsat
(set-logic ALL_SUPPORTED)
-(set-info :status sat)
+(set-info :status unsat)
(declare-const x Int)
(declare-const y Int)
diff --git a/test/regress/regress0/sep/trees-1.smt2 b/test/regress/regress0/sep/trees-1.smt2
new file mode 100644
index 000000000..88e875f70
--- /dev/null
+++ b/test/regress/regress0/sep/trees-1.smt2
@@ -0,0 +1,41 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+
+(declare-sort Loc 0)
+(declare-const loc0 Loc)
+
+(declare-datatypes () ((Node (node (data Int) (left Loc) (right Loc)))))
+
+(declare-const dv Int)
+(declare-const v Loc)
+
+(declare-const dl Int)
+(declare-const l Loc)
+(declare-const dr Int)
+(declare-const r Loc)
+
+(define-fun ten-tree0 ((x Loc) (d Int)) Bool
+(or (and (emp loc0) (= x (as sep.nil Loc))) (and (sep (pto x (node d l r)) (and (emp loc0) (= l (as sep.nil Loc))) (and (emp loc0) (= r (as sep.nil Loc)))) (= dl (- d 10)) (= dr (+ d 10)))))
+
+(declare-const dy Int)
+(declare-const y Loc)
+(declare-const dz Int)
+(declare-const z Loc)
+
+(define-fun ord-tree0 ((x Loc) (d Int)) Bool
+(or (and (emp loc0) (= x (as sep.nil Loc))) (and (sep (pto x (node d y z)) (and (emp loc0) (= y (as sep.nil Loc))) (and (emp loc0) (= z (as sep.nil Loc)))) (<= dy d) (<= d dz))))
+
+;------- f -------
+(assert (= y (as sep.nil Loc)))
+(assert (= z (as sep.nil Loc)))
+
+(assert (= dy dv))
+(assert (= dz (+ dv 10)))
+;-----------------
+
+(assert (not (= v (as sep.nil Loc))))
+
+(assert (ten-tree0 v dv))
+(assert (not (ord-tree0 v dv)))
+
+(check-sat)
diff --git a/test/regress/regress0/sep/wand-false.smt2 b/test/regress/regress0/sep/wand-false.smt2
new file mode 100644
index 000000000..642c0a8aa
--- /dev/null
+++ b/test/regress/regress0/sep/wand-false.smt2
@@ -0,0 +1,7 @@
+; COMMAND-LINE: --no-check-models
+; EXPECT: sat
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-fun x () Int)
+(assert (wand (pto x x) false))
+(check-sat)
diff --git a/test/regress/regress0/sep/wand-nterm-simp2.smt2 b/test/regress/regress0/sep/wand-nterm-simp2.smt2
index 69305e95c..c317e8736 100644
--- a/test/regress/regress0/sep/wand-nterm-simp2.smt2
+++ b/test/regress/regress0/sep/wand-nterm-simp2.smt2
@@ -1,6 +1,7 @@
; COMMAND-LINE: --no-check-models
-; EXPECT: unsat
+; EXPECT: sat
(set-logic ALL_SUPPORTED)
+(set-info :status sat)
(declare-fun x () Int)
(assert (wand (pto x 1) (emp x)))
(check-sat)
diff --git a/test/regress/regress0/sep/wand-simp-sat2.smt2 b/test/regress/regress0/sep/wand-simp-sat2.smt2
index ebc115fdd..059e91317 100755
--- a/test/regress/regress0/sep/wand-simp-sat2.smt2
+++ b/test/regress/regress0/sep/wand-simp-sat2.smt2
@@ -1,6 +1,7 @@
; COMMAND-LINE: --no-check-models
-; EXPECT: unsat
+; EXPECT: sat
(set-logic ALL_SUPPORTED)
+(set-info :status sat)
(declare-fun x () Int)
(assert (wand (pto x 1) (pto x 3)))
(check-sat)
diff --git a/test/regress/regress0/sets/Makefile.am b/test/regress/regress0/sets/Makefile.am
index 5069d061e..4e1806aba 100644
--- a/test/regress/regress0/sets/Makefile.am
+++ b/test/regress/regress0/sets/Makefile.am
@@ -62,7 +62,9 @@ TESTS = \
union-1a.smt2 \
union-1b-flip.smt2 \
union-1b.smt2 \
- union-2.smt2
+ union-2.smt2 \
+ dt-simp-mem.smt2 \
+ card3-ground.smt2
EXTRA_DIST = $(TESTS)
diff --git a/test/regress/regress0/sets/card3-ground.smt2 b/test/regress/regress0/sets/card3-ground.smt2
new file mode 100644
index 000000000..54a9a5cfc
--- /dev/null
+++ b/test/regress/regress0/sets/card3-ground.smt2
@@ -0,0 +1,6 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-fun S () (Set Int))
+(assert (>= (card S) 3))
+(assert (not (member 1 S)))
+(check-sat)
diff --git a/test/regress/regress0/sets/dt-simp-mem.smt2 b/test/regress/regress0/sets/dt-simp-mem.smt2
new file mode 100644
index 000000000..a38544aa2
--- /dev/null
+++ b/test/regress/regress0/sets/dt-simp-mem.smt2
@@ -0,0 +1,9 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-datatypes () ((D (A (a Int)))))
+(declare-fun x1 () D)
+(declare-fun S () (Set D))
+(declare-fun P (D) Bool)
+(assert (member x1 S))
+(assert (=> (member (A 0) S) (P x1)))
+(check-sat)
diff --git a/test/regress/regress0/strings/Makefile.am b/test/regress/regress0/strings/Makefile.am
index 477d336e6..2e4fd4e1c 100644
--- a/test/regress/regress0/strings/Makefile.am
+++ b/test/regress/regress0/strings/Makefile.am
@@ -67,7 +67,6 @@ TESTS = \
bug612.smt2 \
bug615.smt2 \
kaluza-fl.smt2 \
- norn-ab.smt2 \
idof-rewrites.smt2 \
bug682.smt2 \
bug686dd.smt2 \
@@ -78,7 +77,15 @@ TESTS = \
norn-31.smt2 \
strings-native-simple.cvc \
cmu-2db2-extf-reg.smt2 \
- norn-nel-bug-052116.smt2
+ norn-nel-bug-052116.smt2 \
+ cmu-disagree-0707-dd.smt2 \
+ cmu-5042-0707-2.smt2 \
+ cmu-dis-0707-3.smt2 \
+ nf-ff-contains-abs.smt2 \
+ csp-prefix-exp-bug.smt2 \
+ cmu-substr-rw.smt2 \
+ gm-inc-071516-2.smt2 \
+ cmu-inc-nlpp-071516.smt2
FAILING_TESTS =
@@ -87,6 +94,9 @@ EXTRA_DIST = $(TESTS)
# and make sure to distribute it
EXTRA_DIST +=
+#norn-dis-0707-3.smt2
+#norn-ab.smt2
+
# synonyms for "check"
.PHONY: regress regress0 test
regress regress0 test: check
diff --git a/test/regress/regress0/strings/cmu-5042-0707-2.smt2 b/test/regress/regress0/strings/cmu-5042-0707-2.smt2
new file mode 100644
index 000000000..637142dfb
--- /dev/null
+++ b/test/regress/regress0/strings/cmu-5042-0707-2.smt2
@@ -0,0 +1,15 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :strings-exp true)
+
+(declare-fun key2 () String)
+(declare-fun key1 () String)
+
+(assert
+(and
+(not
+(str.contains (str.++ (str.replace (str.substr key2 0 (- (+ (str.indexof key2 "X" 0) 1) 0)) "X" "x") (str.++ (str.replace (str.substr (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) 0 (- (+ (str.indexof (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) "X" 0) 1) 0)) "X" "x") (str.substr (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) (+ (str.indexof (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) "X" 0) 1) (- (str.len (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1)))) (+ (str.indexof (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) "X" 0) 1))))) "Z"))
+(str.contains (str.substr key2 (+ (str.indexof key2 "X" 0) 1) (- (str.len key2) (+ (str.indexof key2 "X" 0) 1))) "X")))
+
+(check-sat)
+
diff --git a/test/regress/regress0/strings/cmu-dis-0707-3.smt2 b/test/regress/regress0/strings/cmu-dis-0707-3.smt2
new file mode 100644
index 000000000..209cbb3f9
--- /dev/null
+++ b/test/regress/regress0/strings/cmu-dis-0707-3.smt2
@@ -0,0 +1,24 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :strings-exp true)
+(declare-fun value () String)
+(declare-fun name () String)
+(assert (not (not (not (= (ite (str.contains value "?") 1 0) 0)))))
+(assert (not (not (= (ite (str.contains value "#") 1 0) 0))))
+(assert (not (not (= (ite (= (str.substr value 0 (- 2 0)) "//") 1 0) 0))))
+(assert (not (not (= (ite (> (str.indexof value ":" 0) 0) 1 0) 0))))
+(assert (not (= (ite (not (= (str.len value) 0)) 1 0) 0)))
+(assert (not (not (= (ite (str.contains value "'") 1 0) 0))))
+(assert (not (not (= (ite (str.contains value "\"") 1 0) 0))))
+(assert (not (not (= (ite (str.contains value ">") 1 0) 0))))
+(assert (not (not (= (ite (str.contains value "<") 1 0) 0))))
+(assert (not (not (= (ite (str.contains value "&") 1 0) 0))))
+(assert (not (not (= (ite (str.contains name "'") 1 0) 0))))
+(assert (not (not (= (ite (str.contains name "\"") 1 0) 0))))
+(assert (not (not (= (ite (str.contains name ">") 1 0) 0))))
+(assert (not (not (= (ite (str.contains name "<") 1 0) 0))))
+(assert (not (not (= (ite (str.contains name "&") 1 0) 0))))
+(assert (not (= (ite (not (= value "")) 1 0) 0)))
+(assert (not (= (ite (str.contains value "javascript:alert(1);") 1 0) 0)))
+(assert (not (not (= (ite (str.contains name "javascript:alert(1);") 1 0) 0))))
+(check-sat)
diff --git a/test/regress/regress0/strings/cmu-disagree-0707-dd.smt2 b/test/regress/regress0/strings/cmu-disagree-0707-dd.smt2
new file mode 100644
index 000000000..c44dfa396
--- /dev/null
+++ b/test/regress/regress0/strings/cmu-disagree-0707-dd.smt2
@@ -0,0 +1,22 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :strings-exp true)
+
+(declare-fun url () String)
+
+(assert
+(and
+(and
+(and
+(and
+
+(= (str.len (str.substr (str.substr url (str.indexof url "#" 2) (- (str.len url) (str.indexof url "#" 2))) (+ (str.indexof (str.substr url (str.indexof url "#" 2) (- (str.len url) (str.indexof url "#" 2))) "#" 0) 1) (- (str.len (str.substr url (str.indexof url "#" 2) (- (str.len url) (str.indexof url "#" 2)))) (+ (str.indexof (str.substr url (str.indexof url "#" 2) (- (str.len url) (str.indexof url "#" 2))) "#" 0) 1)))) 0)
+
+(not (= (str.substr url 0 (- (str.indexof url ":" 0) 0)) "http")))
+(> (str.indexof url ":" 0) 0))
+(>= (- (str.indexof url "#" 2) 2) 0))
+(>= (str.indexof url ":" 0) 0))
+)
+
+(check-sat)
+
diff --git a/test/regress/regress0/strings/cmu-inc-nlpp-071516.smt2 b/test/regress/regress0/strings/cmu-inc-nlpp-071516.smt2
new file mode 100644
index 000000000..1208ca169
--- /dev/null
+++ b/test/regress/regress0/strings/cmu-inc-nlpp-071516.smt2
@@ -0,0 +1,9 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+(set-option :strings-exp true)
+
+(declare-fun url () String)
+
+(assert (and (and (and (and (and (and (and (and (and (and (and (and (and (and (and (not (not (= (ite (> (str.indexof url ":" 0) 0) 1 0) 0))) (not (= (ite (str.contains url "javascript:alert(1);") 1 0) 0))) (not (not (= (ite (= (str.len url) 0) 1 0) 0)))) (not (not (= (ite (= (str.at url 0) " ") 1 0) 0)))) (not (not (= (ite (= (str.at url 0) "\t") 1 0) 0)))) (not (not (= (ite (= (str.at url 0) "\n") 1 0) 0)))) (not (not (= (ite (= (str.at url 0) "\r") 1 0) 0)))) (not (not (= (ite (= (str.at url 0) "\v") 1 0) 0)))) (not (not (= (ite (= (str.at url 0) "\f") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) " ") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) "\t") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) "\n") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) "\r") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) "\v") 1 0) 0)))) (not (not (= (ite (= (str.at url (- (str.len url) 1)) "\f") 1 0) 0)))) (not (= (ite (str.prefixof "javascript:alert(1);" url) 1 0) 0))))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/cmu-substr-rw.smt2 b/test/regress/regress0/strings/cmu-substr-rw.smt2
new file mode 100644
index 000000000..20bf979dd
--- /dev/null
+++ b/test/regress/regress0/strings/cmu-substr-rw.smt2
@@ -0,0 +1,12 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :strings-exp true)
+;(set-option :produce-models true)
+;(set-option :rewrite-divk true)
+
+(declare-fun uri () String)
+
+(assert (and (and (and (and (and (and (and (and (and (and (and (and (not (not (= (ite (= (str.len (str.substr (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1))) 0 (- 2 0))) 2) 1 0) 0))) (not (not (= (ite (str.contains (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1))) "%") 1 0) 0)))) (not (not (= (ite (= (str.len (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1)))) 0) 1 0) 0)))) (not (= (ite (str.contains uri "%") 1 0) 0))) (not (not (= (ite (= (str.len uri) 0) 1 0) 0)))) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)) (>= 0 0)) (>= (- 2 0) 0)) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)))
+
+(check-sat)
+
diff --git a/test/regress/regress0/strings/csp-prefix-exp-bug.smt2 b/test/regress/regress0/strings/csp-prefix-exp-bug.smt2
new file mode 100644
index 000000000..c2fb4175c
--- /dev/null
+++ b/test/regress/regress0/strings/csp-prefix-exp-bug.smt2
@@ -0,0 +1,10 @@
+(set-logic QF_S)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+
+(assert (= (str.len x) 1))
+(assert (= (str.++ x y "b" z) "aaaba"))
+(check-sat)
diff --git a/test/regress/regress0/strings/gm-inc-071516-2.smt2 b/test/regress/regress0/strings/gm-inc-071516-2.smt2
new file mode 100644
index 000000000..1650190f8
--- /dev/null
+++ b/test/regress/regress0/strings/gm-inc-071516-2.smt2
@@ -0,0 +1,10 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+(set-option :strings-exp true)
+
+(declare-fun value2 () String)
+(declare-fun key2 () String)
+
+(assert (and (and (and (and (and (and (not (not (= (ite (str.contains value2 "=") 1 0) 0))) (not (not (= (ite (= (str.len value2) 0) 1 0) 0)))) (not (= (ite (not (= (str.indexof value2 "=" 0) (- 1))) 1 0) 0))) (not (not (= (ite (str.contains value2 ",") 1 0) 0)))) (not (not (= (ite (= (str.len value2) 0) 1 0) 0)))) (not (= (ite (= key2 "cache-control") 1 0) 0))) (not (= (ite (= key2 "cache-control") 1 0) 0))))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/nf-ff-contains-abs.smt2 b/test/regress/regress0/strings/nf-ff-contains-abs.smt2
new file mode 100644
index 000000000..eb6792666
--- /dev/null
+++ b/test/regress/regress0/strings/nf-ff-contains-abs.smt2
@@ -0,0 +1,15 @@
+(set-logic QF_S)
+(set-info :status unsat)
+(declare-fun a () String)
+(declare-fun b () String)
+(declare-fun c () String)
+(declare-fun d () String)
+(declare-fun e () String)
+(declare-fun f () String)
+(declare-fun g () String)
+(assert (= (str.++ "abc" a "def" b "gg" c) (str.++ e g f)))
+(assert (or (= a "a") (= a "aaa")))
+(assert (or (= b "b") (= b "bbb")))
+(assert (or (= c "c") (= c "ccc")))
+(assert (or (= g (str.++ ";" d)) (= g (str.++ d ";"))))
+(check-sat)
diff --git a/test/regress/regress0/strings/norn-dis-0707-3.smt2 b/test/regress/regress0/strings/norn-dis-0707-3.smt2
new file mode 100644
index 000000000..bc0f877ad
--- /dev/null
+++ b/test/regress/regress0/strings/norn-dis-0707-3.smt2
@@ -0,0 +1,26 @@
+(set-logic QF_S)
+(set-info :status sat)
+(set-option :strings-exp true)
+
+(declare-fun var_0 () String)
+(declare-fun var_1 () String)
+(declare-fun var_2 () String)
+(declare-fun var_3 () String)
+(declare-fun var_4 () String)
+(declare-fun var_5 () String)
+(declare-fun var_6 () String)
+(declare-fun var_7 () String)
+(declare-fun var_8 () String)
+(declare-fun var_9 () String)
+(declare-fun var_10 () String)
+(declare-fun var_11 () String)
+(declare-fun var_12 () String)
+
+(assert (str.in.re (str.++ var_8 "z" var_9 ) (re.++ (re.* (re.union (str.to.re "a") (re.++ (str.to.re "b") (re.++ (re.* (re.union (str.to.re "b") (str.to.re "a"))) (str.to.re "z"))))) (re.++ (str.to.re "b") (re.* (re.union (str.to.re "b") (str.to.re "a")))))))
+(assert (str.in.re (str.++ var_8 "z" var_9 ) (re.++ (re.* (re.union (re.union (str.to.re "z") (str.to.re "a")) (re.++ (str.to.re "b") (re.++ (re.* (str.to.re "b")) (re.union (str.to.re "z") (str.to.re "a")))))) (re.++ (str.to.re "b") (re.* (str.to.re "b"))))))
+(assert (str.in.re (str.++ var_8 "z" var_9 ) (re.++ (re.* (re.union (str.to.re "a") (re.++ (str.to.re "b") (re.++ (re.* (re.union (str.to.re "z") (str.to.re "a"))) (str.to.re "b"))))) (re.++ (str.to.re "b") (re.* (re.union (str.to.re "z") (str.to.re "a")))))))
+(assert (str.in.re (str.++ var_8 "z" var_9 ) (re.* (re.++ (re.union (str.to.re "b") (str.to.re "a")) (re.++ (re.* (str.to.re "a")) (re.union (str.to.re "z") (str.to.re "b")))))))
+(assert (str.in.re var_9 (re.* (re.range "a" "u"))))
+(assert (str.in.re var_8 (re.* (re.range "a" "u"))))
+(assert (not (str.in.re (str.++ "b" var_8 "z" "b" var_9 ) (re.++ (re.* (re.++ (str.to.re "b") (str.to.re "z"))) (str.to.re "b")))))
+(check-sat)
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback