summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaulMeng <pmtruth@hotmail.com>2016-07-05 13:56:53 -0400
committerPaulMeng <pmtruth@hotmail.com>2016-07-05 13:56:53 -0400
commit36a0d1d948f201471596e092136c5a00103f78af (patch)
tree7a9b0d79074da1cb0c1cbed986584d50792a30e9 /src
parent66525e81928d0d025dbcc197ab3ef772eac31103 (diff)
parenta58abbe71fb1fc07129ff9c7568ac544145fb57c (diff)
Merge branch 'master' of https://github.com/CVC4/CVC4.git
Conflicts: proofs/signatures/Makefile.am src/Makefile.am src/expr/datatype.cpp src/options/datatypes_options src/options/options_template.cpp src/options/quantifiers_options src/proof/arith_proof.cpp src/proof/arith_proof.h src/proof/array_proof.cpp src/proof/array_proof.h src/proof/bitvector_proof.cpp src/proof/bitvector_proof.h src/proof/cnf_proof.cpp src/proof/cnf_proof.h src/proof/proof_manager.cpp src/proof/proof_manager.h src/proof/sat_proof.h src/proof/sat_proof_implementation.h src/proof/skolemization_manager.h src/proof/theory_proof.cpp src/proof/theory_proof.h src/proof/uf_proof.cpp src/proof/uf_proof.h src/prop/cnf_stream.cpp src/prop/cnf_stream.h src/prop/minisat/core/Solver.cc src/prop/prop_engine.cpp src/prop/prop_engine.h src/prop/theory_proxy.cpp src/smt/smt_engine.cpp src/smt/smt_engine_check_proof.cpp src/theory/arrays/array_proof_reconstruction.cpp src/theory/arrays/theory_arrays.cpp src/theory/bv/eager_bitblaster.cpp src/theory/bv/lazy_bitblaster.cpp src/theory/datatypes/theory_datatypes.cpp src/theory/quantifiers/alpha_equivalence.cpp src/theory/quantifiers/candidate_generator.cpp src/theory/quantifiers/candidate_generator.h src/theory/quantifiers/ce_guided_single_inv.cpp src/theory/quantifiers/ceg_instantiator.cpp src/theory/quantifiers/conjecture_generator.cpp src/theory/quantifiers/equality_infer.cpp src/theory/quantifiers/equality_infer.h src/theory/quantifiers/inst_match_generator.cpp src/theory/quantifiers/inst_propagator.cpp src/theory/quantifiers/inst_propagator.h src/theory/quantifiers/inst_strategy_e_matching.cpp src/theory/quantifiers/inst_strategy_e_matching.h src/theory/quantifiers/instantiation_engine.cpp src/theory/quantifiers/model_builder.cpp src/theory/quantifiers/model_engine.cpp src/theory/quantifiers/quant_conflict_find.cpp src/theory/quantifiers/quant_conflict_find.h src/theory/quantifiers/quant_split.cpp src/theory/quantifiers/quant_util.cpp src/theory/quantifiers/quantifiers_rewriter.cpp src/theory/quantifiers/quantifiers_rewriter.h src/theory/quantifiers/term_database.cpp src/theory/quantifiers/term_database.h src/theory/quantifiers/trigger.cpp src/theory/quantifiers/trigger.h src/theory/quantifiers_engine.cpp src/theory/quantifiers_engine.h src/theory/sets/kinds src/theory/sets/theory_sets_private.cpp src/theory/sets/theory_sets_private.h src/theory/sets/theory_sets_rewriter.cpp src/theory/sets/theory_sets_type_rules.h src/theory/strings/theory_strings.cpp src/theory/strings/theory_strings.h src/theory/theory_engine.cpp src/theory/theory_engine.h src/theory/uf/equality_engine.cpp test/regress/regress0/fmf/Makefile.am test/regress/regress0/quantifiers/Makefile.am test/regress/regress0/strings/Makefile.am test/regress/regress0/sygus/Makefile.am test/regress/regress0/sygus/max2-univ.sy
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am20
-rw-r--r--src/Makefile.theories2
-rw-r--r--src/base/configuration.cpp4
-rw-r--r--src/base/configuration.h2
-rw-r--r--src/base/configuration_private.h6
-rw-r--r--src/context/cdhashmap.h20
-rw-r--r--src/expr/Makefile.am2
-rw-r--r--src/expr/datatype.cpp18
-rw-r--r--src/expr/datatype.h7
-rw-r--r--src/expr/expr_manager_template.cpp7
-rw-r--r--src/expr/expr_manager_template.h8
-rw-r--r--src/expr/node_manager.cpp14
-rw-r--r--src/expr/node_manager.h6
-rw-r--r--src/expr/sepconst.cpp29
-rw-r--r--src/expr/sepconst.h72
-rw-r--r--src/expr/type_node.cpp21
-rw-r--r--src/expr/type_node.h7
-rw-r--r--src/main/interactive_shell.cpp1
-rw-r--r--src/main/portfolio_util.cpp6
-rw-r--r--src/options/Makefile.am15
-rw-r--r--src/options/bv_bitblast_mode.cpp15
-rw-r--r--src/options/bv_bitblast_mode.h7
-rw-r--r--src/options/bv_options3
-rw-r--r--src/options/datatypes_options2
-rw-r--r--src/options/options_handler.cpp140
-rw-r--r--src/options/options_handler.h8
-rw-r--r--src/options/options_template.cpp6
-rw-r--r--src/options/proof_options3
-rw-r--r--src/options/quantifiers_modes.cpp11
-rw-r--r--src/options/quantifiers_modes.h23
-rw-r--r--src/options/quantifiers_options29
-rw-r--r--src/options/sep_options20
-rw-r--r--src/parser/cvc/Cvc.g5
-rw-r--r--src/parser/smt2/Smt2.g26
-rw-r--r--src/parser/smt2/smt2.cpp24
-rw-r--r--src/parser/smt2/smt2.h4
-rw-r--r--src/printer/smt2/smt2_printer.cpp74
-rw-r--r--src/proof/arith_proof.cpp16
-rw-r--r--src/proof/arith_proof.h9
-rw-r--r--src/proof/array_proof.cpp192
-rw-r--r--src/proof/array_proof.h42
-rw-r--r--src/proof/bitvector_proof.cpp568
-rw-r--r--src/proof/bitvector_proof.h42
-rw-r--r--src/proof/cnf_proof.cpp137
-rw-r--r--src/proof/cnf_proof.h43
-rw-r--r--src/proof/lemma_proof.cpp193
-rw-r--r--src/proof/lemma_proof.h79
-rw-r--r--src/proof/proof_manager.cpp209
-rw-r--r--src/proof/proof_manager.h48
-rw-r--r--src/proof/proof_output_channel.cpp82
-rw-r--r--src/proof/proof_output_channel.h50
-rw-r--r--src/proof/proof_utils.cpp52
-rw-r--r--src/proof/proof_utils.h105
-rw-r--r--src/proof/sat_proof.h410
-rw-r--r--src/proof/sat_proof_implementation.h635
-rw-r--r--src/proof/skolemization_manager.h1
-rw-r--r--src/proof/theory_proof.cpp748
-rw-r--r--src/proof/theory_proof.h157
-rw-r--r--src/proof/uf_proof.cpp119
-rw-r--r--src/proof/uf_proof.h10
-rw-r--r--src/prop/bvminisat/bvminisat.h4
-rw-r--r--src/prop/cnf_stream.cpp23
-rw-r--r--src/prop/cnf_stream.h21
-rw-r--r--src/prop/cryptominisat.cpp230
-rw-r--r--src/prop/cryptominisat.h138
-rw-r--r--src/prop/minisat/core/Solver.cc32
-rw-r--r--src/prop/minisat/minisat.cpp16
-rw-r--r--src/prop/minisat/minisat.h3
-rw-r--r--src/prop/prop_engine.cpp4
-rw-r--r--src/prop/prop_engine.h3
-rw-r--r--src/prop/sat_solver.h9
-rw-r--r--src/prop/sat_solver_factory.cpp7
-rw-r--r--src/prop/sat_solver_factory.h2
-rw-r--r--src/prop/theory_proxy.cpp33
-rw-r--r--src/smt/boolean_terms.cpp34
-rw-r--r--src/smt/smt_engine.cpp229
-rw-r--r--src/smt/smt_engine_check_proof.cpp23
-rw-r--r--src/smt/smt_engine_scope.h1
-rw-r--r--src/theory/arrays/array_proof_reconstruction.cpp51
-rw-r--r--src/theory/arrays/theory_arrays.cpp5
-rw-r--r--src/theory/bv/abstraction.cpp352
-rw-r--r--src/theory/bv/abstraction.h90
-rw-r--r--src/theory/bv/aig_bitblaster.cpp26
-rw-r--r--src/theory/bv/bitblaster_template.h8
-rw-r--r--src/theory/bv/bv_subtheory_algebraic.cpp3
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp37
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h6
-rw-r--r--src/theory/bv/eager_bitblaster.cpp25
-rw-r--r--src/theory/bv/lazy_bitblaster.cpp2
-rw-r--r--src/theory/bv/theory_bv.cpp184
-rw-r--r--src/theory/bv/theory_bv.h47
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h4
-rw-r--r--src/theory/datatypes/datatypes_sygus.cpp283
-rw-r--r--src/theory/datatypes/kinds2
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp337
-rw-r--r--src/theory/datatypes/theory_datatypes.h20
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h3
-rw-r--r--src/theory/datatypes/type_enumerator.cpp2
-rw-r--r--src/theory/datatypes/type_enumerator.h2
-rw-r--r--src/theory/logic_info.cpp11
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/alpha_equivalence.cpp25
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/alpha_equivalence.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ambqi_builder.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ambqi_builder.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/anti_skolem.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/anti_skolem.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/bounded_integers.cpp365
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/bounded_integers.h61
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/candidate_generator.cpp10
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/candidate_generator.h16
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_instantiation.cpp182
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_instantiation.h5
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv.cpp305
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_ei.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_ei.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_sol.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ce_guided_single_inv_sol.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ceg_instantiator.cpp48
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/ceg_instantiator.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/conjecture_generator.cpp13
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/conjecture_generator.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/equality_infer.cpp49
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/equality_infer.h8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/first_order_model.cpp4
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/first_order_model.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/full_model_check.cpp15
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/full_model_check.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_engine.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_process.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/fun_def_process.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match_generator.cpp43
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_match_generator.h12
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_propagator.cpp476
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_propagator.h28
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_cbqi.cpp10
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_cbqi.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_e_matching.cpp145
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/inst_strategy_e_matching.h8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/instantiation_engine.cpp6
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/instantiation_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/kinds0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/local_theory_ext.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/local_theory_ext.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/macros.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/macros.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_builder.cpp43
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_builder.h11
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_engine.cpp56
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/model_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.cpp592
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.h26
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_equality_engine.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_equality_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_split.cpp6
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_split.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_util.cpp15
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_util.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_attributes.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_attributes.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_rewriter.cpp518
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quantifiers_rewriter.h9
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/rewrite_engine.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/rewrite_engine.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/symmetry_breaking.cpp0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/symmetry_breaking.h2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/term_database.cpp455
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/term_database.h54
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers.cpp7
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/theory_quantifiers_type_rules.h0
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/trigger.cpp169
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/trigger.h19
-rw-r--r--src/theory/quantifiers_engine.cpp107
-rw-r--r--src/theory/quantifiers_engine.h8
-rw-r--r--src/theory/rep_set.cpp283
-rw-r--r--src/theory/rep_set.h55
-rw-r--r--src/theory/sep/kinds37
-rw-r--r--src/theory/sep/theory_sep.cpp1534
-rw-r--r--src/theory/sep/theory_sep.h294
-rw-r--r--src/theory/sep/theory_sep_rewriter.cpp184
-rw-r--r--src/theory/sep/theory_sep_rewriter.h53
-rw-r--r--src/theory/sep/theory_sep_type_rules.h114
-rw-r--r--src/theory/sets/kinds1
-rw-r--r--src/theory/sets/theory_sets_private.h14
-rw-r--r--src/theory/sets/theory_sets_type_rules.h1
-rw-r--r--src/theory/strings/regexp_operation.cpp4
-rw-r--r--src/theory/strings/regexp_operation.h1
-rw-r--r--src/theory/strings/theory_strings.cpp511
-rw-r--r--src/theory/strings/theory_strings.h23
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp4
-rw-r--r--src/theory/strings/theory_strings_preprocess.h1
-rw-r--r--src/theory/term_registration_visitor.cpp56
-rw-r--r--src/theory/theory.h8
-rw-r--r--src/theory/theory_engine.cpp372
-rw-r--r--src/theory/theory_engine.h46
-rw-r--r--src/theory/theory_model.cpp3
-rw-r--r--src/theory/theory_model.h4
-rw-r--r--src/theory/type_enumerator.h2
-rw-r--r--src/theory/uf/equality_engine.cpp26
-rw-r--r--src/theory/uf/equality_engine.h8
-rw-r--r--src/theory/uf/theory_uf.cpp167
-rw-r--r--src/theory/uf/theory_uf.h7
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp6
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h2
-rw-r--r--src/theory/valuation.cpp4
-rw-r--r--src/theory/valuation.h6
-rw-r--r--src/util/bitvector.h17
-rw-r--r--src/util/proof.h8
214 files changed, 10632 insertions, 4087 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3ffda9f28..0e3f4823b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,10 +96,14 @@ libcvc4_la_SOURCES = \
proof/skolemization_manager.h \
proof/theory_proof.cpp \
proof/theory_proof.h \
+ proof/lemma_proof.cpp \
+ proof/lemma_proof.h \
proof/uf_proof.cpp \
proof/uf_proof.h \
proof/unsat_core.cpp \
proof/unsat_core.h \
+ proof/proof_output_channel.cpp \
+ proof/proof_output_channel.h \
prop/cnf_stream.cpp \
prop/cnf_stream.h \
prop/prop_engine.cpp \
@@ -109,6 +113,8 @@ libcvc4_la_SOURCES = \
prop/sat_solver_factory.cpp \
prop/sat_solver_factory.h \
prop/sat_solver_types.h \
+ prop/cryptominisat.h \
+ prop/cryptominisat.cpp \
prop/theory_proxy.cpp \
prop/theory_proxy.h \
smt/boolean_terms.cpp \
@@ -443,7 +449,12 @@ libcvc4_la_SOURCES = \
theory/fp/theory_fp.cpp \
theory/fp/theory_fp_rewriter.h \
theory/fp/theory_fp_rewriter.cpp \
- theory/fp/theory_fp_type_rules.h
+ theory/fp/theory_fp_type_rules.h \
+ theory/sep/theory_sep.h \
+ theory/sep/theory_sep.cpp \
+ theory/sep/theory_sep_rewriter.h \
+ theory/sep/theory_sep_rewriter.cpp \
+ theory/sep/theory_sep_type_rules.h
nodist_libcvc4_la_SOURCES = \
theory/rewriter_tables.h \
@@ -477,6 +488,12 @@ libcvc4_la_LIBADD += $(ABC_LIBS)
libcvc4_la_LDFLAGS += $(ABC_LDFLAGS)
endif
+if CVC4_USE_CRYPTOMINISAT
+libcvc4_la_LIBADD += $(CRYPTOMINISAT_LIBS)
+libcvc4_la_LDFLAGS += $(CRYPTOMINISAT_LDFLAGS)
+endif
+
+
BUILT_SOURCES = \
theory/rewriter_tables.h \
theory/theory_traits.h \
@@ -526,6 +543,7 @@ EXTRA_DIST = \
theory/mktheorytraits \
theory/quantifiers/kinds \
theory/rewriter_tables_template.h \
+ theory/sep/kinds \
theory/sets/kinds \
theory/strings/kinds \
theory/theory_traits_template.h \
diff --git a/src/Makefile.theories b/src/Makefile.theories
index 8b5cef4d5..003128a3c 100644
--- a/src/Makefile.theories
+++ b/src/Makefile.theories
@@ -1,3 +1,3 @@
-THEORIES = builtin booleans uf arith bv fp arrays datatypes sets strings quantifiers idl
+THEORIES = builtin booleans uf arith bv fp arrays datatypes sets sep strings quantifiers idl
diff --git a/src/base/configuration.cpp b/src/base/configuration.cpp
index ce8967a18..db19469fd 100644
--- a/src/base/configuration.cpp
+++ b/src/base/configuration.cpp
@@ -134,6 +134,10 @@ bool Configuration::isBuiltWithAbc() {
return IS_ABC_BUILD;
}
+bool Configuration::isBuiltWithCryptominisat() {
+ return IS_CRYPTOMINISAT_BUILD;
+}
+
bool Configuration::isBuiltWithReadline() {
return IS_READLINE_BUILD;
}
diff --git a/src/base/configuration.h b/src/base/configuration.h
index 498337c4c..5d499174f 100644
--- a/src/base/configuration.h
+++ b/src/base/configuration.h
@@ -93,6 +93,8 @@ public:
static bool isBuiltWithAbc();
+ static bool isBuiltWithCryptominisat();
+
static bool isBuiltWithReadline();
static bool isBuiltWithCudd();
diff --git a/src/base/configuration_private.h b/src/base/configuration_private.h
index 74ce00bdf..f0ef1a795 100644
--- a/src/base/configuration_private.h
+++ b/src/base/configuration_private.h
@@ -114,6 +114,12 @@ namespace CVC4 {
# define IS_ABC_BUILD false
#endif /* CVC4_USE_ABC */
+#if CVC4_USE_CRYPTOMINISAT
+# define IS_CRYPTOMINISAT_BUILD true
+#else /* CVC4_USE_CRYPTOMINISAT */
+# define IS_CRYPTOMINISAT_BUILD false
+#endif /* CVC4_USE_CRYPTOMINISAT */
+
#ifdef HAVE_LIBREADLINE
# define IS_READLINE_BUILD true
#else /* HAVE_LIBREADLINE */
diff --git a/src/context/cdhashmap.h b/src/context/cdhashmap.h
index d080da333..884234eb8 100644
--- a/src/context/cdhashmap.h
+++ b/src/context/cdhashmap.h
@@ -163,7 +163,7 @@ class CDOhash_map : public ContextObj {
d_data = p->d_data;
}
}
- // Explicitly call destructors fro the key and the date as they will not
+ // Explicitly call destructors for the key and the date as they will not
// otherwise get called.
p->d_key.~Key();
p->d_data.~Data();
@@ -478,18 +478,13 @@ public:
typename table_type::iterator i = d_map.find(k);
if(i != d_map.end()) {
Debug("gc") << "key " << k << " obliterated" << std::endl;
- // We can't call ->deleteSelf() here, because it calls the
- // ContextObj destructor, which calls CDOhash_map::destroy(), which
- // restore()'s, which puts the CDOhash_map on the trash, which causes
- // a double-delete.
- (*i).second->~Element();
- // Writing ...->~CDOhash_map() in the above is legal (?) but breaks
- // g++ 4.1, though later versions have no problem.
+ // Restore this object to level 0. If it was inserted after level 0,
+ // nothing else to do as restore will put it in the trash.
+ (*i).second->destroy();
+ // Check if object was inserted at level 0: in that case, still have
+ // to do some work.
typename table_type::iterator j = d_map.find(k);
- // This if() succeeds for objects inserted when in the
- // zero-scope: they were never save()'d there, so restore()
- // never gets a NULL map and so they leak.
if(j != d_map.end()) {
Element* elt = (*j).second;
if(d_first == elt) {
@@ -505,9 +500,8 @@ public:
}
d_map.erase(j);//FIXME multithreading
Debug("gc") << "key " << k << " obliterated zero-scope: " << elt << std::endl;
- // was already destructed, so don't call ->deleteSelf()
if(!elt->d_noTrash) {
- ::operator delete(elt);
+ elt->deleteSelf();
}
}
}
diff --git a/src/expr/Makefile.am b/src/expr/Makefile.am
index c04de4421..9dcbc3b4b 100644
--- a/src/expr/Makefile.am
+++ b/src/expr/Makefile.am
@@ -40,6 +40,8 @@ libexpr_la_SOURCES = \
pickle_data.h \
pickler.cpp \
pickler.h \
+ sepconst.cpp \
+ sepconst.h \
symbol_table.cpp \
symbol_table.h \
type.cpp \
diff --git a/src/expr/datatype.cpp b/src/expr/datatype.cpp
index d14ac26d4..12cab48cc 100644
--- a/src/expr/datatype.cpp
+++ b/src/expr/datatype.cpp
@@ -297,7 +297,7 @@ bool Datatype::isFinite() const throw(IllegalArgumentException) {
return true;
}
-bool Datatype::isUFinite() const throw(IllegalArgumentException) {
+bool Datatype::isInterpretedFinite() const throw(IllegalArgumentException) {
PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
// we're using some internals, so we have to set up this library context
ExprManagerScope ems(d_self);
@@ -310,7 +310,7 @@ bool Datatype::isUFinite() const throw(IllegalArgumentException) {
self.setAttribute(DatatypeUFiniteComputedAttr(), true);
self.setAttribute(DatatypeUFiniteAttr(), false);
for(const_iterator i = begin(), i_end = end(); i != i_end; ++i) {
- if(! (*i).isUFinite()) {
+ if(! (*i).isInterpretedFinite()) {
return false;
}
}
@@ -850,7 +850,7 @@ bool DatatypeConstructor::isFinite() const throw(IllegalArgumentException) {
return true;
}
-bool DatatypeConstructor::isUFinite() const throw(IllegalArgumentException) {
+bool DatatypeConstructor::isInterpretedFinite() const throw(IllegalArgumentException) {
PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
// we're using some internals, so we have to set up this library context
ExprManagerScope ems(d_constructor);
@@ -861,16 +861,8 @@ bool DatatypeConstructor::isUFinite() const throw(IllegalArgumentException) {
}
bool success = true;
for(const_iterator i = begin(), i_end = end(); i != i_end; ++i) {
- Type t = (*i).getRangeType();
- if( t.isDatatype() ){
- const Datatype& dt = ((DatatypeType)t).getDatatype();
- if( !dt.isUFinite() ){
- success = false;
- }
- }else if(!t.isSort() && !t.getCardinality().isFinite()) {
- success = false;
- }
- if(!success ){
+ TypeNode t = TypeNode::fromType( (*i).getRangeType() );
+ if(!t.isInterpretedFinite()) {
self.setAttribute(DatatypeUFiniteComputedAttr(), true);
self.setAttribute(DatatypeUFiniteAttr(), false);
return false;
diff --git a/src/expr/datatype.h b/src/expr/datatype.h
index 1197b4a3b..a0c9cbe6b 100644
--- a/src/expr/datatype.h
+++ b/src/expr/datatype.h
@@ -342,7 +342,7 @@ public:
* uninterpreted sorts are finite. This function can
* only be called for resolved constructors.
*/
- bool isUFinite() const throw(IllegalArgumentException);
+ bool isInterpretedFinite() const throw(IllegalArgumentException);
/**
* Returns true iff this Datatype constructor has already been
@@ -613,6 +613,9 @@ public:
/** get the record representation for this datatype */
inline Record * getRecord() const;
+ /** get the record representation for this datatype */
+ inline Record * getRecord() const;
+
/**
* Return the cardinality of this datatype (the sum of the
* cardinalities of its constructors). The Datatype must be
@@ -634,7 +637,7 @@ public:
* datatype is not well-founded, this function returns false. The
* Datatype must be resolved or an exception is thrown.
*/
- bool isUFinite() const throw(IllegalArgumentException);
+ bool isInterpretedFinite() const throw(IllegalArgumentException);
/**
* Return true iff this datatype is well-founded (there exist ground
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 84f674d2b..53e16751e 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -30,7 +30,7 @@ ${includes}
// compiler directs the user to the template file instead of the
// generated one. We don't want the user to modify the generated one,
// since it'll get overwritten on a later build.
-#line 33 "${template}"
+#line 34 "${template}"
#ifdef CVC4_STATISTICS_ON
#define INC_STAT(kind) \
@@ -941,6 +941,11 @@ Expr ExprManager::mkBoundVar(Type type) {
return Expr(this, d_nodeManager->mkBoundVarPtr(*type.d_typeNode));
}
+Expr ExprManager::mkSepNil(Type type) {
+ NodeManagerScope nms(d_nodeManager);
+ return Expr(this, d_nodeManager->mkSepNilPtr(*type.d_typeNode));
+}
+
Expr ExprManager::mkAssociative(Kind kind,
const std::vector<Expr>& children) {
PrettyCheckArgument(
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index 04f2f4289..9c4e554e1 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -124,6 +124,9 @@ public:
/** Get the type for regular expressions. */
RegExpType regExpType() const;
+ /** Get the type for regular expressions. */
+ RegExpType regExpType() const;
+
/** Get the type for reals. */
RealType realType() const;
@@ -545,6 +548,11 @@ public:
* @param type the type for the new bound variable
*/
Expr mkBoundVar(Type type);
+
+ /**
+ * Create a (nameless) new nil reference for separation logic of type
+ */
+ Expr mkSepNil(Type type);
/** Get a reference to the statistics registry for this ExprManager */
Statistics getStatistics() const throw();
diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp
index 0809a0331..d2ac7e2a1 100644
--- a/src/expr/node_manager.cpp
+++ b/src/expr/node_manager.cpp
@@ -681,6 +681,20 @@ Node NodeManager::mkInstConstant(const TypeNode& type) {
return n;
}
+Node NodeManager::mkSepNil(const TypeNode& type) {
+ Node n = NodeBuilder<0>(this, kind::SEP_NIL);
+ n.setAttribute(TypeAttr(), type);
+ n.setAttribute(TypeCheckedAttr(), true);
+ return n;
+}
+
+Node* NodeManager::mkSepNilPtr(const TypeNode& type) {
+ Node* n = NodeBuilder<0>(this, kind::SEP_NIL).constructNodePtr();
+ setAttribute(*n, TypeAttr(), type);
+ setAttribute(*n, TypeCheckedAttr(), true);
+ return n;
+}
+
Node NodeManager::mkAbstractValue(const TypeNode& type) {
Node n = mkConst(AbstractValue(++d_abstractValueCount));
n.setAttribute(TypeAttr(), type);
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 7d2b13e4c..dcd7005f8 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -332,7 +332,7 @@ class NodeManager {
/** Create a variable with the given type. */
Node mkVar(const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
Node* mkVarPtr(const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
-
+
public:
explicit NodeManager(ExprManager* exprManager);
@@ -486,6 +486,10 @@ public:
/** Create a instantiation constant with the given type. */
Node mkInstConstant(const TypeNode& type);
+
+ /** Create nil reference for separation logic with the given type. */
+ Node mkSepNil(const TypeNode& type);
+ Node* mkSepNilPtr(const TypeNode& type);
/** Make a new abstract value with the given type. */
Node mkAbstractValue(const TypeNode& type);
diff --git a/src/expr/sepconst.cpp b/src/expr/sepconst.cpp
new file mode 100644
index 000000000..7646b90d3
--- /dev/null
+++ b/src/expr/sepconst.cpp
@@ -0,0 +1,29 @@
+/********************* */
+/*! \file sepconst.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "expr/sepconst.h"
+#include <iostream>
+
+using namespace std;
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, const NilRef& asa) {
+ return out << "(nil " << asa.getType() << ")";
+}
+
+}/* CVC4 namespace */
diff --git a/src/expr/sepconst.h b/src/expr/sepconst.h
new file mode 100644
index 000000000..9f86c7efc
--- /dev/null
+++ b/src/expr/sepconst.h
@@ -0,0 +1,72 @@
+/********************* */
+/*! \file sepconst.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#pragma once
+
+namespace CVC4 {
+ // messy; Expr needs NilRef (because it's the payload of a
+ // CONSTANT-kinded expression), and NilRef needs Expr.
+ class CVC4_PUBLIC NilRef;
+ //class CVC4_PUBLIC EmpStar;
+}/* CVC4 namespace */
+
+#include "expr/expr.h"
+#include "expr/type.h"
+#include <iostream>
+
+namespace CVC4 {
+
+class CVC4_PUBLIC NilRef {
+ const Type d_type;
+ NilRef() { }
+public:
+ NilRef(Type refType):d_type(refType) { }
+
+ ~NilRef() throw() {
+ }
+ Type getType() const { return d_type; }
+ bool operator==(const NilRef& es) const throw() {
+ return d_type == es.d_type;
+ }
+ bool operator!=(const NilRef& es) const throw() {
+ return !(*this == es);
+ }
+ bool operator<(const NilRef& es) const throw() {
+ return d_type < es.d_type;
+ }
+ bool operator<=(const NilRef& es) const throw() {
+ return d_type <= es.d_type;
+ }
+ bool operator>(const NilRef& es) const throw() {
+ return !(*this <= es);
+ }
+ bool operator>=(const NilRef& es) const throw() {
+ return !(*this < es);
+ }
+};/* class NilRef */
+
+std::ostream& operator<<(std::ostream& out, const NilRef& es) CVC4_PUBLIC;
+
+struct CVC4_PUBLIC NilRefHashFunction {
+ inline size_t operator()(const NilRef& es) const {
+ return TypeHashFunction()(es.getType());
+ }
+};/* struct NilRefHashFunction */
+
+}/* CVC4 namespace */
diff --git a/src/expr/type_node.cpp b/src/expr/type_node.cpp
index 5d672e6ac..dc2370bea 100644
--- a/src/expr/type_node.cpp
+++ b/src/expr/type_node.cpp
@@ -21,6 +21,7 @@
#include "expr/type_properties.h"
#include "options/base_options.h"
#include "options/expr_options.h"
+#include "options/quantifiers_options.h"
using namespace std;
@@ -64,6 +65,26 @@ Cardinality TypeNode::getCardinality() const {
return kind::getCardinality(*this);
}
+bool TypeNode::isInterpretedFinite() const {
+ if( getCardinality().isFinite() ){
+ return true;
+ }else{
+ if( options::finiteModelFind() ){
+ if( isSort() ){
+ return true;
+ }else if( isDatatype() || isParametricDatatype() ){
+ const Datatype& dt = getDatatype();
+ return dt.isInterpretedFinite();
+ }else if( isArray() ){
+ return getArrayIndexType().isInterpretedFinite() && getArrayConstituentType().isInterpretedFinite();
+ }else if( isSet() ) {
+ return getSetElementType().isInterpretedFinite();
+ }
+ }
+ return false;
+ }
+}
+
bool TypeNode::isWellFounded() const {
return kind::isWellFounded(*this);
}
diff --git a/src/expr/type_node.h b/src/expr/type_node.h
index cfb61a085..46fdaa143 100644
--- a/src/expr/type_node.h
+++ b/src/expr/type_node.h
@@ -419,6 +419,13 @@ public:
* @return a finite or infinite cardinality
*/
Cardinality getCardinality() const;
+
+ /**
+ * Is this type interpreted as being finite.
+ * If finite model finding is enabled, this assumes all uninterpreted sorts
+ * are interpreted as finite.
+ */
+ bool isInterpretedFinite() const;
/**
* Returns whether this type is well-founded.
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
index e11f82a40..334373642 100644
--- a/src/main/interactive_shell.cpp
+++ b/src/main/interactive_shell.cpp
@@ -172,6 +172,7 @@ InteractiveShell::~InteractiveShell() {
<< ": " << strerror(err) << std::endl;
}
#endif /* HAVE_LIBREADLINE */
+ delete d_parser;
}
Command* InteractiveShell::readCommand() throw (UnsafeInterruptException) {
diff --git a/src/main/portfolio_util.cpp b/src/main/portfolio_util.cpp
index 03827a917..8e38eb528 100644
--- a/src/main/portfolio_util.cpp
+++ b/src/main/portfolio_util.cpp
@@ -98,12 +98,6 @@ void parseThreadSpecificOptions(OptionsList& threadOptions, const Options& opts)
ss << optid << ": " << e.getMessage();
throw OptionException(ss.str());
}
- if(optind != targc) {
- stringstream ss;
- ss << "unused argument `" << targv[optind]
- << "' in thread configuration " << optid << " !";
- throw OptionException(ss.str());
- }
if(tOpts.getThreads() != numThreads ||
tOpts.getThreadArgv() != opts.getThreadArgv()) {
stringstream ss;
diff --git a/src/options/Makefile.am b/src/options/Makefile.am
index 643932781..1eb84b45f 100644
--- a/src/options/Makefile.am
+++ b/src/options/Makefile.am
@@ -10,7 +10,7 @@
# Step 4: Generate X_options.h from X_options.sed
# Step 5: Generate X_options.cpp from X_options.sed.
# This stage also waits for X_options.h as otherwise it cannot compile.
-#
+#
OPTIONS_SRC_FILES = \
arith_options \
@@ -30,6 +30,7 @@ OPTIONS_SRC_FILES = \
proof_options \
prop_options \
quantifiers_options \
+ sep_options \
sets_options \
smt_options \
strings_options \
@@ -54,6 +55,7 @@ OPTIONS_TEMPS = \
proof_options.tmp \
prop_options.tmp \
quantifiers_options.tmp \
+ sep_options.tmp \
sets_options.tmp \
smt_options.tmp \
strings_options.tmp \
@@ -78,6 +80,7 @@ OPTIONS_OPTIONS_FILES = \
proof_options.options \
prop_options.options \
quantifiers_options.options \
+ sep_options.options \
sets_options.options \
smt_options.options \
strings_options.options \
@@ -102,6 +105,7 @@ OPTIONS_SEDS = \
proof_options.sed \
prop_options.sed \
quantifiers_options.sed \
+ sep_options.sed \
sets_options.sed \
smt_options.sed \
strings_options.sed \
@@ -126,6 +130,7 @@ OPTIONS_HEADS = \
proof_options.h \
prop_options.h \
quantifiers_options.h \
+ sep_options.h \
sets_options.h \
smt_options.h \
strings_options.h \
@@ -150,6 +155,7 @@ OPTIONS_CPPS = \
proof_options.cpp \
prop_options.cpp \
quantifiers_options.cpp \
+ sep_options.cpp \
sets_options.cpp \
smt_options.cpp \
strings_options.cpp \
@@ -295,14 +301,14 @@ options_holder_template.h options_template.cpp options_get_option_template.cpp o
# Make sure the implicit rules never mistake X_options for the -o file for a
# CPP file.
-arith_options arrays_options base_options booleans_options builtin_options bv_options datatypes_options decision_options expr_options fp_options idl_options main_options parser_options printer_options proof_options prop_options quantifiers_options sets_options smt_options strings_options theory_options uf_options:;
+arith_options arrays_options base_options booleans_options builtin_options bv_options datatypes_options decision_options expr_options fp_options idl_options main_options parser_options printer_options proof_options prop_options quantifiers_options sep_options sets_options smt_options strings_options theory_options uf_options:;
# These are phony to force them to be made everytime.
-.PHONY: arith_options.tmp arrays_options.tmp base_options.tmp booleans_options.tmp builtin_options.tmp bv_options.tmp datatypes_options.tmp decision_options.tmp expr_options.tmp fp_options.tmp idl_options.tmp main_options.tmp parser_options.tmp printer_options.tmp proof_options.tmp prop_options.tmp quantifiers_options.tmp sets_options.tmp smt_options.tmp strings_options.tmp theory_options.tmp uf_options.tmp
+.PHONY: arith_options.tmp arrays_options.tmp base_options.tmp booleans_options.tmp builtin_options.tmp bv_options.tmp datatypes_options.tmp decision_options.tmp expr_options.tmp fp_options.tmp idl_options.tmp main_options.tmp parser_options.tmp printer_options.tmp proof_options.tmp prop_options.tmp quantifiers_options.tmp sep_options.tmp sets_options.tmp smt_options.tmp strings_options.tmp theory_options.tmp uf_options.tmp
# Make is happier being listed explictly. Not sure why.
-arith_options.tmp arrays_options.tmp base_options.tmp booleans_options.tmp builtin_options.tmp bv_options.tmp datatypes_options.tmp decision_options.tmp expr_options.tmp fp_options.tmp idl_options.tmp main_options.tmp parser_options.tmp printer_options.tmp proof_options.tmp prop_options.tmp quantifiers_options.tmp sets_options.tmp smt_options.tmp strings_options.tmp theory_options.tmp uf_options.tmp:
+arith_options.tmp arrays_options.tmp base_options.tmp booleans_options.tmp builtin_options.tmp bv_options.tmp datatypes_options.tmp decision_options.tmp expr_options.tmp fp_options.tmp idl_options.tmp main_options.tmp parser_options.tmp printer_options.tmp proof_options.tmp prop_options.tmp quantifiers_options.tmp sep_options.tmp sets_options.tmp smt_options.tmp strings_options.tmp theory_options.tmp uf_options.tmp:
echo "$@" "$(@:.tmp=)"
$(AM_V_GEN)(cp "@srcdir@/$(@:.tmp=)" "$@" || true)
#TIM:
@@ -424,4 +430,3 @@ $(DOCUMENTATION_FILES) : % : %_template %_template.sed mkoptions summary.sed
# directories that are cleaned first. Without this rule, "distclean"
# fails.
%.Plo:; $(MKDIR_P) "$(dir $@)" && : > "$@"
-
diff --git a/src/options/bv_bitblast_mode.cpp b/src/options/bv_bitblast_mode.cpp
index 9cf47fe33..f331345f7 100644
--- a/src/options/bv_bitblast_mode.cpp
+++ b/src/options/bv_bitblast_mode.cpp
@@ -53,4 +53,19 @@ std::ostream& operator<<(std::ostream& out, theory::bv::BvSlicerMode mode) {
return out;
}
+std::ostream& operator<<(std::ostream& out, theory::bv::SatSolverMode solver) {
+ switch(solver) {
+ case theory::bv::SAT_SOLVER_MINISAT:
+ out << "SAT_SOLVER_MINISAT";
+ break;
+ case theory::bv::SAT_SOLVER_CRYPTOMINISAT:
+ out << "SAT_SOLVER_CRYPTOMINISAT";
+ break;
+ default:
+ out << "SatSolverMode:UNKNOWN![" << unsigned(solver) << "]";
+ }
+
+ return out;
+}
+
}/* CVC4 namespace */
diff --git a/src/options/bv_bitblast_mode.h b/src/options/bv_bitblast_mode.h
index 4c8c4f626..3a6474104 100644
--- a/src/options/bv_bitblast_mode.h
+++ b/src/options/bv_bitblast_mode.h
@@ -60,12 +60,19 @@ enum BvSlicerMode {
};/* enum BvSlicerMode */
+/** Enumeration of sat solvers that can be used. */
+enum SatSolverMode {
+ SAT_SOLVER_MINISAT,
+ SAT_SOLVER_CRYPTOMINISAT,
+};/* enum SatSolver */
+
}/* CVC4::theory::bv namespace */
}/* CVC4::theory namespace */
std::ostream& operator<<(std::ostream& out, theory::bv::BitblastMode mode);
std::ostream& operator<<(std::ostream& out, theory::bv::BvSlicerMode mode);
+std::ostream& operator<<(std::ostream& out, theory::bv::SatSolverMode mode);
}/* CVC4 namespace */
diff --git a/src/options/bv_options b/src/options/bv_options
index 8edc809e3..2e6fa2e7a 100644
--- a/src/options/bv_options
+++ b/src/options/bv_options
@@ -7,6 +7,9 @@ module BV "options/bv_options.h" Bitvector theory
# Option to set the bit-blasting mode (lazy, eager)
+expert-option bvSatSolver bv-sat-solver --bv-sat-solver=MODE CVC4::theory::bv::SatSolverMode :predicate satSolverEnabledBuild :handler stringToSatSolver :default CVC4::theory::bv::SAT_SOLVER_MINISAT :read-write :include "options/bv_bitblast_mode.h"
+ choose which sat solver to use, see --bv-sat-solver=help
+
option bitblastMode bitblast --bitblast=MODE CVC4::theory::bv::BitblastMode :handler stringToBitblastMode :default CVC4::theory::bv::BITBLAST_MODE_LAZY :read-write :include "options/bv_bitblast_mode.h"
choose bitblasting mode, see --bitblast=help
diff --git a/src/options/datatypes_options b/src/options/datatypes_options
index e9578f8d7..bb92b4e05 100644
--- a/src/options/datatypes_options
+++ b/src/options/datatypes_options
@@ -27,5 +27,7 @@ option dtInferAsLemmas --dt-infer-as-lemmas bool :default false
always send lemmas out instead of making internal inferences
#option dtRExplainLemmas --dt-rexplain-lemmas bool :default true
# regression explanations for datatype lemmas
+option dtBlastSplits --dt-blast-splits bool :default false
+ when applicable, blast splitting lemmas for all variables at once
endmodule
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index a2809bd67..6a5f6cd39 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -254,15 +254,21 @@ last-call\n\
const std::string OptionsHandler::s_literalMatchHelp = "\
Literal match modes currently supported by the --literal-match option:\n\
\n\
-none (default)\n\
+none \n\
+ Do not use literal matching.\n\
\n\
-predicate\n\
-+ Consider the phase requirements of predicate literals when applying heuristic\n\
- quantifier instantiation. For example, the trigger P( x ) in the quantified \n\
- formula forall( x ). ( P( x ) V ~Q( x ) ) will only be matched with ground\n\
- terms P( t ) where P( t ) is in the equivalence class of false, and likewise\n\
- Q( x ) with Q( s ) where Q( s ) is in the equivalence class of true.\n\
+use (default)\n\
++ Consider phase requirements of triggers conservatively. For example, the\n\
+ trigger P( x ) in forall( x ). ( P( x ) V ~Q( x ) ) will not be matched with\n\
+ terms in the equivalence class of true, and likewise Q( x ) will not be matched\n\
+ terms in the equivalence class of false. Extends to equality.\n\
+\n\
+agg-predicate \n\
++ Consider phase requirements aggressively for predicates. In the above example,\n\
+ only match P( x ) with terms that are in the equivalence class of false.\n\
+\n\
+agg \n\
++ Consider the phase requirements aggressively for all triggers.\n\
\n\
";
@@ -384,7 +390,7 @@ uf-dt-size \n\
+ Enforce fairness using an uninterpreted function for datatypes size.\n\
\n\
default | dt-size \n\
-+ Default, enforce fairness using size theory operator.\n\
++ Default, enforce fairness using size operator.\n\
\n\
dt-height-bound \n\
+ Enforce fairness by height bound predicate.\n\
@@ -419,6 +425,24 @@ all \n\
\n\
";
+const std::string OptionsHandler::s_cegqiSingleInvHelp = "\
+Modes for single invocation techniques, supported by --cegqi-si:\n\
+\n\
+none \n\
++ Do not use single invocation techniques.\n\
+\n\
+use (default) \n\
++ Use single invocation techniques only if grammar is not restrictive.\n\
+\n\
+all-abort \n\
++ Always use single invocation techniques, abort if solution reconstruction will likely fail,\
+ for instance, when the grammar does not have ITE and solution requires it.\n\
+\n\
+all \n\
++ Always use single invocation techniques. \n\
+\n\
+";
+
const std::string OptionsHandler::s_sygusInvTemplHelp = "\
Template modes for sygus invariant synthesis, supported by --sygus-inv-templ:\n\
\n\
@@ -506,10 +530,12 @@ void OptionsHandler::checkInstWhenMode(std::string option, theory::quantifiers::
theory::quantifiers::LiteralMatchMode OptionsHandler::stringToLiteralMatchMode(std::string option, std::string optarg) throw(OptionException) {
if(optarg == "none") {
return theory::quantifiers::LITERAL_MATCH_NONE;
- } else if(optarg == "predicate") {
- return theory::quantifiers::LITERAL_MATCH_PREDICATE;
- } else if(optarg == "equality") {
- return theory::quantifiers::LITERAL_MATCH_EQUALITY;
+ } else if(optarg == "use") {
+ return theory::quantifiers::LITERAL_MATCH_USE;
+ } else if(optarg == "agg-predicate") {
+ return theory::quantifiers::LITERAL_MATCH_AGG_PREDICATE;
+ } else if(optarg == "agg") {
+ return theory::quantifiers::LITERAL_MATCH_AGG;
} else if(optarg == "help") {
puts(s_literalMatchHelp.c_str());
exit(1);
@@ -520,9 +546,7 @@ theory::quantifiers::LiteralMatchMode OptionsHandler::stringToLiteralMatchMode(s
}
void OptionsHandler::checkLiteralMatchMode(std::string option, theory::quantifiers::LiteralMatchMode mode) throw(OptionException) {
- if(mode == theory::quantifiers::LITERAL_MATCH_EQUALITY) {
- throw OptionException(std::string("Mode equality for ") + option + " is not supported in this release.");
- }
+
}
theory::quantifiers::MbqiMode OptionsHandler::stringToMbqiMode(std::string option, std::string optarg) throw(OptionException) {
@@ -651,6 +675,8 @@ theory::quantifiers::CegqiFairMode OptionsHandler::stringToCegqiFairMode(std::st
return theory::quantifiers::CEGQI_FAIR_DT_SIZE;
} else if(optarg == "dt-height-bound" ){
return theory::quantifiers::CEGQI_FAIR_DT_HEIGHT_PRED;
+ //} else if(optarg == "dt-size-bound" ){
+ // return theory::quantifiers::CEGQI_FAIR_DT_SIZE_PRED;
} else if(optarg == "none") {
return theory::quantifiers::CEGQI_FAIR_NONE;
} else if(optarg == "help") {
@@ -692,6 +718,24 @@ theory::quantifiers::IteLiftQuantMode OptionsHandler::stringToIteLiftQuantMode(s
}
}
+theory::quantifiers::CegqiSingleInvMode OptionsHandler::stringToCegqiSingleInvMode(std::string option, std::string optarg) throw(OptionException) {
+ if(optarg == "none" ) {
+ return theory::quantifiers::CEGQI_SI_MODE_NONE;
+ } else if(optarg == "use" || optarg == "default") {
+ return theory::quantifiers::CEGQI_SI_MODE_USE;
+ } else if(optarg == "all-abort") {
+ return theory::quantifiers::CEGQI_SI_MODE_ALL_ABORT;
+ } else if(optarg == "all") {
+ return theory::quantifiers::CEGQI_SI_MODE_ALL;
+ } else if(optarg == "help") {
+ puts(s_cegqiSingleInvHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --cegqi-si: `") +
+ optarg + "'. Try --cegqi-si help.");
+ }
+}
+
theory::quantifiers::SygusInvTemplMode OptionsHandler::stringToSygusInvTemplMode(std::string option, std::string optarg) throw(OptionException) {
if(optarg == "none" ) {
return theory::quantifiers::SYGUS_INV_TEMPL_MODE_NONE;
@@ -777,6 +821,72 @@ void OptionsHandler::abcEnabledBuild(std::string option, std::string value) thro
#endif /* CVC4_USE_ABC */
}
+void OptionsHandler::satSolverEnabledBuild(std::string option,
+ bool value) throw(OptionException) {
+#ifndef CVC4_USE_CRYPTOMINISAT
+ if(value) {
+ std::stringstream ss;
+ ss << "option `" << option << "' requires an cryptominisat-enabled build of CVC4; this binary was not built with cryptominisat support";
+ throw OptionException(ss.str());
+ }
+#endif /* CVC4_USE_CRYPTOMINISAT */
+}
+
+void OptionsHandler::satSolverEnabledBuild(std::string option,
+ std::string value) throw(OptionException) {
+#ifndef CVC4_USE_CRYPTOMINISAT
+ if(!value.empty()) {
+ std::stringstream ss;
+ ss << "option `" << option << "' requires an cryptominisat-enabled build of CVC4; this binary was not built with cryptominisat support";
+ throw OptionException(ss.str());
+ }
+#endif /* CVC4_USE_CRYPTOMINISAT */
+}
+
+const std::string OptionsHandler::s_bvSatSolverHelp = "\
+Sat solvers currently supported by the --bv-sat-solver option:\n\
+\n\
+minisat (default)\n\
+\n\
+cryptominisat\n\
+";
+
+theory::bv::SatSolverMode OptionsHandler::stringToSatSolver(std::string option,
+ std::string optarg) throw(OptionException) {
+ if(optarg == "minisat") {
+ return theory::bv::SAT_SOLVER_MINISAT;
+ } else if(optarg == "cryptominisat") {
+
+ if (options::incrementalSolving() &&
+ options::incrementalSolving.wasSetByUser()) {
+ throw OptionException(std::string("Cryptominsat does not support incremental mode. \n\
+ Try --bv-sat-solver=minisat"));
+ }
+
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY &&
+ options::bitblastMode.wasSetByUser()) {
+ throw OptionException(std::string("Cryptominsat does not support lazy bit-blsating. \n\
+ Try --bv-sat-solver=minisat"));
+ }
+ if (!options::bitvectorToBool.wasSetByUser()) {
+ options::bitvectorToBool.set(true);
+ }
+
+ // if (!options::bvAbstraction.wasSetByUser() &&
+ // !options::skolemizeArguments.wasSetByUser()) {
+ // options::bvAbstraction.set(true);
+ // options::skolemizeArguments.set(true);
+ // }
+ return theory::bv::SAT_SOLVER_CRYPTOMINISAT;
+ } else if(optarg == "help") {
+ puts(s_bvSatSolverHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --bv-sat-solver: `") +
+ optarg + "'. Try --bv-sat-solver=help.");
+ }
+}
+
const std::string OptionsHandler::s_bitblastingModeHelp = "\
Bit-blasting modes currently supported by the --bitblast option:\n\
\n\
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index baa6cea96..5db2887c0 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -98,6 +98,7 @@ public:
theory::quantifiers::CegqiFairMode stringToCegqiFairMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::TermDbMode stringToTermDbMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::IteLiftQuantMode stringToIteLiftQuantMode(std::string option, std::string optarg) throw(OptionException);
+ theory::quantifiers::CegqiSingleInvMode stringToCegqiSingleInvMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::SygusInvTemplMode stringToSygusInvTemplMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::MacrosQuantMode stringToMacrosQuantMode(std::string option, std::string optarg) throw(OptionException);
theory::quantifiers::QuantDSplitMode stringToQuantDSplitMode(std::string option, std::string optarg) throw(OptionException);
@@ -106,10 +107,15 @@ public:
// theory/bv/options_handlers.h
void abcEnabledBuild(std::string option, bool value) throw(OptionException);
void abcEnabledBuild(std::string option, std::string value) throw(OptionException);
+ void satSolverEnabledBuild(std::string option, bool value) throw(OptionException);
+ void satSolverEnabledBuild(std::string option, std::string optarg) throw(OptionException);
+
theory::bv::BitblastMode stringToBitblastMode(std::string option, std::string optarg) throw(OptionException);
theory::bv::BvSlicerMode stringToBvSlicerMode(std::string option, std::string optarg) throw(OptionException);
void setBitblastAig(std::string option, bool arg) throw(OptionException);
+ theory::bv::SatSolverMode stringToSatSolver(std::string option, std::string optarg) throw(OptionException);
+
// theory/booleans/options_handlers.h
theory::booleans::BooleanTermConversionMode stringToBooleanTermConversionMode(std::string option, std::string optarg) throw(OptionException);
@@ -192,6 +198,7 @@ public:
/* Help strings */
static const std::string s_bitblastingModeHelp;
+ static const std::string s_bvSatSolverHelp;
static const std::string s_booleanTermConversionModeHelp;
static const std::string s_bvSlicerModeHelp;
static const std::string s_cegqiFairModeHelp;
@@ -209,6 +216,7 @@ public:
static const std::string s_qcfModeHelp;
static const std::string s_qcfWhenModeHelp;
static const std::string s_simplificationHelp;
+ static const std::string s_cegqiSingleInvHelp;
static const std::string s_sygusInvTemplHelp;
static const std::string s_termDbModeHelp;
static const std::string s_theoryOfModeHelp;
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index f029dfd17..694d46d31 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -720,7 +720,7 @@ void Options::parseOptionsRecursive(Options* options,
switch(c) {
${all_modules_option_handlers}
-#line 722 "${template}"
+#line 724 "${template}"
case ':':
// This can be a long or short option, and the way to get at the
@@ -798,7 +798,7 @@ std::string Options::suggestCommandLineOptions(const std::string& optionName) th
static const char* smtOptions[] = {
${all_modules_smt_options},
-#line 800 "${template}"
+#line 802 "${template}"
NULL
};/* smtOptions[] */
@@ -820,7 +820,7 @@ std::vector< std::vector<std::string> > Options::getOptions() const throw() {
${all_modules_get_options}
-#line 762 "${template}"
+#line 824 "${template}"
return opts;
}
diff --git a/src/options/proof_options b/src/options/proof_options
index 7feb00b0d..a99d858bc 100644
--- a/src/options/proof_options
+++ b/src/options/proof_options
@@ -5,4 +5,7 @@
module PROOF "options/proof_options.h" Proof
+option lfscLetification --lfsc-letification bool :default true
+ turns on global letification in LFSC proofs
+
endmodule
diff --git a/src/options/quantifiers_modes.cpp b/src/options/quantifiers_modes.cpp
index a58120974..e2cd78de5 100644
--- a/src/options/quantifiers_modes.cpp
+++ b/src/options/quantifiers_modes.cpp
@@ -46,11 +46,14 @@ std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMod
case theory::quantifiers::LITERAL_MATCH_NONE:
out << "LITERAL_MATCH_NONE";
break;
- case theory::quantifiers::LITERAL_MATCH_PREDICATE:
- out << "LITERAL_MATCH_PREDICATE";
+ case theory::quantifiers::LITERAL_MATCH_USE:
+ out << "LITERAL_MATCH_USE";
break;
- case theory::quantifiers::LITERAL_MATCH_EQUALITY:
- out << "LITERAL_MATCH_EQUALITY";
+ case theory::quantifiers::LITERAL_MATCH_AGG_PREDICATE:
+ out << "LITERAL_MATCH_AGG_PREDICATE";
+ break;
+ case theory::quantifiers::LITERAL_MATCH_AGG:
+ out << "LITERAL_MATCH_AGG";
break;
default:
out << "LiteralMatchMode!UNKNOWN";
diff --git a/src/options/quantifiers_modes.h b/src/options/quantifiers_modes.h
index 5749da972..65445be17 100644
--- a/src/options/quantifiers_modes.h
+++ b/src/options/quantifiers_modes.h
@@ -44,10 +44,12 @@ enum InstWhenMode {
enum LiteralMatchMode {
/** Do not consider polarity of patterns */
LITERAL_MATCH_NONE,
- /** Consider polarity of boolean predicates only */
- LITERAL_MATCH_PREDICATE,
- /** Consider polarity of boolean predicates, as well as equalities */
- LITERAL_MATCH_EQUALITY,
+ /** Conservatively consider polarity of patterns */
+ LITERAL_MATCH_USE,
+ /** Aggressively consider polarity of Boolean predicates */
+ LITERAL_MATCH_AGG_PREDICATE,
+ /** Aggressively consider polarity of all terms */
+ LITERAL_MATCH_AGG,
};
enum MbqiMode {
@@ -129,6 +131,8 @@ enum CegqiFairMode {
CEGQI_FAIR_DT_SIZE,
/** enforce fairness by datatypes height bound */
CEGQI_FAIR_DT_HEIGHT_PRED,
+ /** enforce fairness by datatypes size bound */
+ CEGQI_FAIR_DT_SIZE_PRED,
/** do not use fair strategy for CEGQI */
CEGQI_FAIR_NONE,
};
@@ -149,6 +153,17 @@ enum IteLiftQuantMode {
ITE_LIFT_QUANT_MODE_ALL,
};
+enum CegqiSingleInvMode {
+ /** do not use single invocation techniques */
+ CEGQI_SI_MODE_NONE,
+ /** use single invocation techniques */
+ CEGQI_SI_MODE_USE,
+ /** always use single invocation techniques, abort if solution reconstruction will fail */
+ CEGQI_SI_MODE_ALL_ABORT,
+ /** always use single invocation techniques */
+ CEGQI_SI_MODE_ALL,
+};
+
enum SygusInvTemplMode {
/** synthesize I( x ) */
SYGUS_INV_TEMPL_MODE_NONE,
diff --git a/src/options/quantifiers_options b/src/options/quantifiers_options
index 74b3011a6..4d228bbad 100644
--- a/src/options/quantifiers_options
+++ b/src/options/quantifiers_options
@@ -54,6 +54,8 @@ 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
+ conditional rewriting of quantified formulas
#### E-matching options
@@ -109,6 +111,8 @@ option instLevelInputOnly --inst-level-input-only bool :default true
only input terms are assigned instantiation level zero
option quantRepMode --quant-rep-mode=MODE CVC4::theory::quantifiers::QuantRepMode :default CVC4::theory::quantifiers::QUANT_REP_MODE_FIRST :read-write :include "options/quantifiers_modes.h" :handler stringToQuantRepMode
selection mode for representatives in quantifiers engine
+option instRelevantCond --inst-rlv-cond bool :default false
+ add relevancy conditions for instantiations
option eagerInstQuant --eager-inst-quant bool :default false
apply quantifier instantiation eagerly
@@ -120,7 +124,7 @@ option fullSaturateQuantRd --full-saturate-quant-rd bool :default true
option fullSaturateInst --fs-inst bool :default false
interleave full saturate instantiation with other techniques
-option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_NONE :include "options/quantifiers_modes.h" :handler stringToLiteralMatchMode :predicate checkLiteralMatchMode
+option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_USE :include "options/quantifiers_modes.h" :handler stringToLiteralMatchMode :predicate checkLiteralMatchMode
choose literal matching mode
### finite model finding options
@@ -144,7 +148,7 @@ option fmfOneInstPerRound --mbqi-one-inst-per-round bool :read-write :default fa
option fmfOneQuantPerRound --mbqi-one-quant-per-round bool :default false
only add instantiations for one quantifier per round for mbqi
-option fmfInstEngine --fmf-inst-engine bool :default false
+option fmfInstEngine --fmf-inst-engine bool :default false :read-write
use instantiation engine in conjunction with finite model finding
option fmfInstGen --fmf-inst-gen bool :default true
enable Inst-Gen instantiation techniques for finite model finding
@@ -171,13 +175,23 @@ option qcfTConstraint --qcf-tconstraint bool :read-write :default false
enable entailment checks for t-constraints in qcf algorithm
option qcfAllConflict --qcf-all-conflict bool :read-write :default false
add all available conflicting instances during conflict-based instantiation
+option qcfNestedConflict --qcf-nested-conflict bool :default false
+ consider conflicts for nested quantifiers
+option qcfVoExp --qcf-vo-exp bool :default false
+ qcf experimental variable ordering
+
+
option instNoEntail --inst-no-entail bool :read-write :default true
do not consider instances of quantified formulas that are currently entailed
-option instPropagate --inst-propagate bool :read-write :default false
+option instPropagate --inst-prop bool :read-write :default false
internal propagation for instantiations for selecting relevant instances
+option qcfEagerTest --qcf-eager-test bool :default true
+ optimization, test qcf instances eagerly
+option qcfSkipRd --qcf-skip-rd bool :default false
+ optimization, skip instances based on possibly irrelevant portions of quantified formulas
### rewrite rules options
option quantRewriteRules --rewrite-rules bool :default false
@@ -219,8 +233,8 @@ option ceGuidedInst --cegqi bool :default false :read-write
counterexample-guided quantifier instantiation
option ceGuidedInstFair --cegqi-fair=MODE CVC4::theory::quantifiers::CegqiFairMode :default CVC4::theory::quantifiers::CEGQI_FAIR_DT_SIZE :include "options/quantifiers_modes.h" :handler stringToCegqiFairMode
if and how to apply fairness for cegqi
-option cegqiSingleInv --cegqi-si bool :default false :read-write
- process single invocation synthesis conjectures
+option cegqiSingleInvMode --cegqi-si=MODE CVC4::theory::quantifiers::CegqiSingleInvMode :default CVC4::theory::quantifiers::CEGQI_SI_MODE_NONE :include "options/quantifiers_modes.h" :handler stringToCegqiSingleInvMode :read-write
+ mode for processing single invocation synthesis conjectures
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
@@ -229,8 +243,6 @@ option cegqiSingleInvReconstructConst --cegqi-si-reconstruct-const bool :default
include constants when reconstruct solutions for single invocation conjectures in original grammar
option cegqiSingleInvAbort --cegqi-si-abort bool :default false
abort if synthesis conjecture is not single invocation
-option cegqiSingleInvMultiInstAbort --cegqi-si-multi-inst-abort bool :default false
- abort if synthesis conjecture is single invocation with no ITE in grammar and multiple instantiations are tried
option sygusNormalForm --sygus-nf bool :default true
only search for sygus builtin terms that are in normal form
@@ -248,6 +260,9 @@ option sygusNormalFormGlobalContent --sygus-nf-sym-content bool :default true
option sygusInvTemplMode --sygus-inv-templ=MODE CVC4::theory::quantifiers::SygusInvTemplMode :default CVC4::theory::quantifiers::SYGUS_INV_TEMPL_MODE_NONE :include "options/quantifiers_modes.h" :handler stringToSygusInvTemplMode
template mode for sygus invariant synthesis
+option sygusDirectEval --sygus-direct-eval bool :default true
+ direct unfolding of evaluation functions
+
# approach applied to general quantified formulas
option cbqiSplx --cbqi-splx bool :read-write :default false
turns on old implementation of counterexample-based quantifier instantiation
diff --git a/src/options/sep_options b/src/options/sep_options
new file mode 100644
index 000000000..043355bda
--- /dev/null
+++ b/src/options/sep_options
@@ -0,0 +1,20 @@
+#
+# Option specification file for CVC4
+# See src/options/base_options for a description of this file format
+#
+
+module SEP "options/sep_options.h" Sep
+
+option sepCheckNeg --sep-check-neg bool :default true
+ check negated spatial assertions
+
+option sepExp --sep-exp bool :default false
+ experimental flag for sep
+option sepMinimalRefine --sep-min-refine bool :default false
+ only add refinement lemmas for minimal (innermost) assertions
+option sepPreciseBound --sep-prec-bound bool :default false
+ calculate precise bounds for labels
+option sepDisequalC --sep-deq-c bool :default true
+ assume cardinality elements are distinct
+
+endmodule
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index c497fcd0d..e6d7f9d86 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -931,7 +931,10 @@ toplevelDeclaration[CVC4::Command*& cmd]
* A bound variable declaration.
*/
boundVarDecl[std::vector<std::string>& ids, CVC4::Type& t]
- : identifierList[ids,CHECK_NONE,SYM_VARIABLE] COLON declareVariables[*(Command**)NULL,t,ids,false]
+@init {
+ Command* local_cmd = NULL;
+}
+ : identifierList[ids,CHECK_NONE,SYM_VARIABLE] COLON declareVariables[local_cmd,t,ids,false]
;
/**
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 38163c579..29d3e45b6 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -749,7 +749,7 @@ sygusCommand returns [CVC4::Command* cmd = NULL]
$cmd = new EmptyCommand();
}
| /* check-synth */
- CHECK_SYNTH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ CHECK_SYNTH_TOK { PARSER_STATE->checkThatLogicIsSet();PARSER_STATE->defineSygusFuns(); }
{ Expr sygusVar = EXPR_MANAGER->mkVar("sygus", EXPR_MANAGER->booleanType());
Expr sygusAttr = EXPR_MANAGER->mkExpr(kind::INST_PATTERN_LIST, EXPR_MANAGER->mkExpr(kind::INST_ATTRIBUTE, sygusVar));
std::vector<Expr> bodyv;
@@ -760,7 +760,9 @@ sygusCommand returns [CVC4::Command* cmd = NULL]
body = EXPR_MANAGER->mkExpr(kind::EXISTS, EXPR_MANAGER->mkExpr(kind::BOUND_VAR_LIST, PARSER_STATE->getSygusVars()), body);
Debug("parser-sygus") << "...constructed exists " << body << std::endl;
}
- body = EXPR_MANAGER->mkExpr(kind::FORALL, EXPR_MANAGER->mkExpr(kind::BOUND_VAR_LIST, PARSER_STATE->getSygusFunSymbols()), body, sygusAttr);
+ if( !PARSER_STATE->getSygusFunSymbols().empty() ){
+ body = EXPR_MANAGER->mkExpr(kind::FORALL, EXPR_MANAGER->mkExpr(kind::BOUND_VAR_LIST, PARSER_STATE->getSygusFunSymbols()), body, sygusAttr);
+ }
Debug("parser-sygus") << "...constructed forall " << body << std::endl;
Command* c = new SetUserAttributeCommand("sygus", sygusVar);
c->setMuted(true);
@@ -791,6 +793,7 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
std::string sname;
std::vector< Expr > let_vars;
bool readingLet = false;
+ std::string s;
}
: LPAREN_TOK
//read operator
@@ -799,6 +802,8 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
//since we enforce satisfaction completeness, immediately convert to total version
if( k==CVC4::kind::BITVECTOR_UDIV ){
k = CVC4::kind::BITVECTOR_UDIV_TOTAL;
+ }else if( k==CVC4::kind::BITVECTOR_UREM ){
+ k = CVC4::kind::BITVECTOR_UREM_TOTAL;
}
sgt.d_name = kind::kindToString(k);
sgt.d_gterm_type = SygusGTerm::gterm_op;
@@ -834,6 +839,8 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
k = PARSER_STATE->getOperatorKind(name);
if( k==CVC4::kind::BITVECTOR_UDIV ){
k = CVC4::kind::BITVECTOR_UDIV_TOTAL;
+ }else if( k==CVC4::kind::BITVECTOR_UREM ){
+ k = CVC4::kind::BITVECTOR_UREM_TOTAL;
}
sgt.d_name = kind::kindToString(k);
sgt.d_gterm_type = SygusGTerm::gterm_op;
@@ -890,6 +897,12 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
sgt.d_name = AntlrInput::tokenText($BINARY_LITERAL);
sgt.d_gterm_type = SygusGTerm::gterm_op;
}
+ | str[s,false]
+ { Debug("parser-sygus") << "Sygus grammar " << fun << " : string literal \"" << s << "\"" << std::endl;
+ sgt.d_expr = MK_CONST( ::CVC4::String(s) );
+ sgt.d_name = s;
+ sgt.d_gterm_type = SygusGTerm::gterm_op;
+ }
| symbol[name,CHECK_NONE,SYM_VARIABLE] ( SYGUS_ENUM_CONS_TOK symbol[name2,CHECK_NONE,SYM_VARIABLE] { readEnum = true; } )?
{ if( readEnum ){
name = name + "__Enum__" + name2;
@@ -1594,6 +1607,10 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
Debug("parser") << "Empty set encountered: " << f << " "
<< f2 << " " << type << std::endl;
expr = MK_CONST( ::CVC4::EmptySet(type) );
+ } else if(f.getKind() == CVC4::kind::SEP_NIL_REF) {
+ //We don't want the nil reference to be a constant: for instance, it could be of type Int but is not a const rational.
+ //However, the expression has 0 children. So we convert to a SEP_NIL variable.
+ expr = EXPR_MANAGER->mkSepNil(type);
} else {
if(f.getType() != type) {
PARSER_STATE->parseError("Type ascription not satisfied.");
@@ -1898,6 +1915,8 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
| EMPTYSET_TOK
{ expr = MK_CONST( ::CVC4::EmptySet(Type())); }
+ | NILREF_TOK
+ { expr = MK_CONST( ::CVC4::NilRef(Type())); }
// NOTE: Theory constants go here
;
@@ -2633,6 +2652,7 @@ FMFCARDVAL_TOK : 'fmf.card.val';
INST_CLOSURE_TOK : 'inst-closure';
EMPTYSET_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS) }? 'emptyset';
+NILREF_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SEP) }? 'sep.nil';
// Other set theory operators are not
// tokenized and handled directly when
// processing a term
@@ -2773,7 +2793,7 @@ STRING_LITERAL_2_0
* will be part of the token text. Use the str[] parser rule instead.
*/
STRING_LITERAL_2_5
- : { PARSER_STATE->v2_5() }?=>
+ : { PARSER_STATE->v2_5() || PARSER_STATE->sygus() }?=>
'"' (~('"') | '""')* '"'
;
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index 463adcb54..9f3c43f09 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -166,6 +166,16 @@ void Smt2::addFloatingPointOperators() {
Parser::addOperator(kind::FLOATINGPOINT_TO_SBV);
}
+void Smt2::addSepOperators() {
+ addOperator(kind::SEP_STAR, "sep");
+ addOperator(kind::SEP_PTO, "pto");
+ addOperator(kind::SEP_WAND, "wand");
+ addOperator(kind::SEP_EMP, "emp");
+ Parser::addOperator(kind::SEP_STAR);
+ Parser::addOperator(kind::SEP_PTO);
+ Parser::addOperator(kind::SEP_WAND);
+ Parser::addOperator(kind::SEP_EMP);
+}
void Smt2::addTheory(Theory theory) {
switch(theory) {
@@ -258,7 +268,11 @@ void Smt2::addTheory(Theory theory) {
defineType("Float128", getExprManager()->mkFloatingPointType(15, 113));
addFloatingPointOperators();
break;
-
+
+ case THEORY_SEP:
+ addSepOperators();
+ break;
+
default:
std::stringstream ss;
ss << "internal error: unsupported theory " << theory;
@@ -311,6 +325,8 @@ bool Smt2::isTheoryEnabled(Theory theory) const {
return d_logic.isTheoryEnabled(theory::THEORY_UF);
case THEORY_FP:
return d_logic.isTheoryEnabled(theory::THEORY_FP);
+ case THEORY_SEP:
+ return d_logic.isTheoryEnabled(theory::THEORY_SEP);
default:
std::stringstream ss;
ss << "internal error: unsupported theory " << theory;
@@ -354,6 +370,8 @@ void Smt2::setLogic(std::string name) {
name = "UFLIRA";
} else if(name == "BV") {
name = "UFBV";
+ } else if(name == "SLIA") {
+ name = "UFSLIA";
} else if(name == "ALL_SUPPORTED") {
//no change
} else {
@@ -417,6 +435,10 @@ void Smt2::setLogic(std::string name) {
addTheory(THEORY_FP);
}
+ if (d_logic.isTheoryEnabled(theory::THEORY_SEP)) {
+ addTheory(THEORY_SEP);
+ }
+
}/* Smt2::setLogic() */
void Smt2::setInfo(const std::string& flag, const SExpr& sexpr) {
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 1ae2c9dd7..b99e142ba 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -51,7 +51,8 @@ public:
THEORY_SETS,
THEORY_STRINGS,
THEORY_UF,
- THEORY_FP
+ THEORY_FP,
+ THEORY_SEP
};
private:
@@ -344,6 +345,7 @@ private:
void addFloatingPointOperators();
+ void addSepOperators();
};/* class Smt2 */
}/* CVC4::parser namespace */
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 9d61e5ef8..4006a9e08 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -117,21 +117,26 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
// variable
if(n.isVar()) {
- string s;
- if(n.getAttribute(expr::VarNameAttr(), s)) {
- out << maybeQuoteSymbol(s);
- } else {
- if(n.getKind() == kind::VARIABLE) {
- out << "var_";
+ if( n.getKind() == kind::SEP_NIL ){
+ out << "(as sep.nil " << n.getType() << ")";
+ return;
+ }else{
+ string s;
+ if(n.getAttribute(expr::VarNameAttr(), s)) {
+ out << maybeQuoteSymbol(s);
} else {
- out << n.getKind() << '_';
+ if(n.getKind() == kind::VARIABLE) {
+ out << "var_";
+ } else {
+ out << n.getKind() << '_';
+ }
+ out << n.getId();
+ }
+ if(types) {
+ // print the whole type, but not *its* type
+ out << ":";
+ n.getType().toStream(out, language::output::LANG_SMTLIB_V2_5);
}
- out << n.getId();
- }
- if(types) {
- // print the whole type, but not *its* type
- out << ":";
- n.getType().toStream(out, language::output::LANG_SMTLIB_V2_5);
}
return;
@@ -291,7 +296,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::EMPTYSET:
out << "(as emptyset " << n.getConst<EmptySet>().getType() << ")";
break;
-
+
default:
// fall back on whatever operator<< does on underlying type; we
// might luck out and be SMT-LIB v2 compliant
@@ -318,7 +323,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
}
return;
}
-
+
bool stillNeedToPrintParams = true;
bool forceBinary = false; // force N-ary to binary when outputing children
// operator
@@ -585,6 +590,12 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::APPLY_SELECTOR_TOTAL:
case kind::PARAMETRIC_DATATYPE:
break;
+
+ //separation
+ case kind::SEP_EMP:
+ case kind::SEP_PTO:
+ case kind::SEP_STAR:
+ case kind::SEP_WAND:out << smtKindString(k) << " "; break;
// quantifiers
case kind::FORALL:
@@ -834,6 +845,39 @@ static string smtKindString(Kind k) throw() {
case kind::FLOATINGPOINT_TO_SBV: return "fp.to_sbv";
case kind::FLOATINGPOINT_TO_REAL: return "fp.to_real";
+ //string theory
+ case kind::STRING_CONCAT: return "str.++";
+ case kind::STRING_LENGTH: return "str.len";
+ case kind::STRING_SUBSTR: return "str.substr" ;
+ case kind::STRING_STRCTN: return "str.contains" ;
+ case kind::STRING_CHARAT: return "str.at" ;
+ case kind::STRING_STRIDOF: return "str.indexof" ;
+ case kind::STRING_STRREPL: return "str.replace" ;
+ case kind::STRING_PREFIX: return "str.prefixof" ;
+ case kind::STRING_SUFFIX: return "str.suffixof" ;
+ case kind::STRING_ITOS: return "int.to.str" ;
+ case kind::STRING_STOI: return "str.to.int" ;
+ case kind::STRING_U16TOS: return "u16.to.str" ;
+ case kind::STRING_STOU16: return "str.to.u16" ;
+ case kind::STRING_U32TOS: return "u32.to.str" ;
+ case kind::STRING_STOU32: return "str.to.u32" ;
+ case kind::STRING_IN_REGEXP: return "str.in.re";
+ case kind::STRING_TO_REGEXP: return "str.to.re";
+ case kind::REGEXP_CONCAT: return "re.++";
+ case kind::REGEXP_UNION: return "re.union";
+ case kind::REGEXP_INTER: return "re.inter";
+ case kind::REGEXP_STAR: return "re.*";
+ case kind::REGEXP_PLUS: return "re.+";
+ case kind::REGEXP_OPT: return "re.opt";
+ case kind::REGEXP_RANGE: return "re.range";
+ case kind::REGEXP_LOOP: return "re.loop";
+
+ //sep theory
+ case kind::SEP_STAR: return "sep";
+ case kind::SEP_PTO: return "pto";
+ case kind::SEP_WAND: return "wand";
+ case kind::SEP_EMP: return "emp";
+
default:
; /* fall through */
}
diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp
index a1287b667..4864cbf46 100644
--- a/src/proof/arith_proof.cpp
+++ b/src/proof/arith_proof.cpp
@@ -69,18 +69,18 @@ inline static bool match(TNode n1, TNode n2) {
void ProofArith::toStream(std::ostream& out) {
Trace("theory-proof-debug") << "; Print Arith proof..." << std::endl;
//AJR : carry this further?
- LetMap map;
+ ProofLetMap map;
toStreamLFSC(out, ProofManager::getArithProof(), d_proof, map);
}
-void ProofArith::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map) {
+void ProofArith::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const ProofLetMap& map) {
Debug("lfsc-arith") << "Printing arith proof in LFSC : " << std::endl;
pf->debug_print("lfsc-arith");
Debug("lfsc-arith") << std::endl;
toStreamRecLFSC( out, tp, pf, 0, map );
}
-Node ProofArith::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map) {
+Node ProofArith::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const ProofLetMap& map) {
Debug("pf::arith") << std::endl << std::endl << "toStreamRecLFSC called. tb = " << tb << " . proof:" << std::endl;
pf->debug_print("pf::arith");
Debug("pf::arith") << std::endl;
@@ -643,7 +643,7 @@ void ArithProof::registerTerm(Expr term) {
}
}
-void LFSCArithProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCArithProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
Debug("pf::arith") << "Arith print term: " << term << ". Kind: " << term.getKind()
<< ". Type: " << term.getType()
<< ". Number of children: " << term.getNumChildren() << std::endl;
@@ -810,14 +810,14 @@ void LFSCArithProof::printOwnedSort(Type type, std::ostream& os) {
}
}
-void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
os << " ;; Arith Theory Lemma \n;;";
for (unsigned i = 0; i < lemma.size(); ++i) {
os << lemma[i] <<" ";
}
os <<"\n";
//os << " (clausify_false trust)";
- ArithProof::printTheoryLemmaProof( lemma, os, paren );
+ ArithProof::printTheoryLemmaProof(lemma, os, paren, map);
}
void LFSCArithProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
@@ -830,4 +830,8 @@ 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) {
+ // Nothing to do here at this point.
+}
+
} /* CVC4 namespace */
diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h
index 788e4bd86..d980654c4 100644
--- a/src/proof/arith_proof.h
+++ b/src/proof/arith_proof.h
@@ -29,13 +29,13 @@ namespace CVC4 {
//proof object outputted by TheoryArith
class ProofArith : public Proof {
private:
- static Node toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map);
+ static Node toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const ProofLetMap& map);
public:
ProofArith( theory::eq::EqProof * pf ) : d_proof( pf ) {}
//it is simply an equality engine proof
theory::eq::EqProof * d_proof;
void toStream(std::ostream& out);
- static void toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map);
+ static void toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const ProofLetMap& map);
};
@@ -68,12 +68,13 @@ public:
LFSCArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* proofEngine)
: ArithProof(arith, proofEngine)
{}
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map);
+ 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);
};
diff --git a/src/proof/array_proof.cpp b/src/proof/array_proof.cpp
index 8aba8dce9..484bc70c8 100644
--- a/src/proof/array_proof.cpp
+++ b/src/proof/array_proof.cpp
@@ -81,27 +81,45 @@ inline static bool match(TNode n1, TNode n2) {
void ProofArray::setRowMergeTag(unsigned tag) {
d_reasonRow = tag;
+ d_proofPrinter.d_row = tag;
}
void ProofArray::setRow1MergeTag(unsigned tag) {
d_reasonRow1 = tag;
+ d_proofPrinter.d_row1 = tag;
}
void ProofArray::setExtMergeTag(unsigned tag) {
d_reasonExt = tag;
+ d_proofPrinter.d_ext = tag;
+}
+
+unsigned ProofArray::getRowMergeTag() const {
+ return d_reasonRow;
+}
+
+unsigned ProofArray::getRow1MergeTag() const {
+ return d_reasonRow1;
+}
+
+unsigned ProofArray::getExtMergeTag() const {
+ return d_reasonExt;
}
void ProofArray::toStream(std::ostream& out) {
+ ProofLetMap map;
+ toStream(out, map);
+}
+
+void ProofArray::toStream(std::ostream& out, const ProofLetMap& map) {
Trace("pf::array") << "; Print Array proof..." << std::endl;
- //AJR : carry this further?
- LetMap map;
toStreamLFSC(out, ProofManager::getArrayProof(), d_proof, map);
Debug("pf::array") << "; Print Array proof done!" << std::endl;
}
-void ProofArray::toStreamLFSC(std::ostream& out, TheoryProof* tp, theory::eq::EqProof* pf, const LetMap& map) {
+void ProofArray::toStreamLFSC(std::ostream& out, TheoryProof* tp, theory::eq::EqProof* pf, const ProofLetMap& map) {
Debug("pf::array") << "Printing array proof in LFSC : " << std::endl;
- pf->debug_print("pf::array");
+ pf->debug_print("pf::array", 0, &d_proofPrinter);
Debug("pf::array") << std::endl;
toStreamRecLFSC( out, tp, pf, 0, map );
Debug("pf::array") << "Printing array proof in LFSC DONE" << std::endl;
@@ -111,10 +129,10 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
TheoryProof* tp,
theory::eq::EqProof* pf,
unsigned tb,
- const LetMap& map) {
+ const ProofLetMap& map) {
Debug("pf::array") << std::endl << std::endl << "toStreamRecLFSC called. tb = " << tb << " . proof:" << std::endl;
- pf->debug_print("pf::array");
+ pf->debug_print("pf::array", 0, &d_proofPrinter);
Debug("pf::array") << std::endl;
if(tb == 0) {
@@ -150,7 +168,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
pf->d_children[i + count]->d_node.isNull();
++count) {
Debug("pf::array") << "Found a congruence: " << std::endl;
- pf->d_children[i+count]->debug_print("pf::array");
+ pf->d_children[i+count]->debug_print("pf::array", 0, &d_proofPrinter);
congruenceClosures.push_back(pf->d_children[i+count]);
}
@@ -220,48 +238,48 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
++i;
}
}
- Assert(neg >= 0);
+
+ bool disequalityFound = (neg >= 0);
+ if (!disequalityFound) {
+ Debug("pf::array") << "A disequality was NOT found. UNSAT due to merged constants" << std::endl;
+ Debug("pf::array") << "Proof for: " << pf->d_node << std::endl;
+ Assert(pf->d_node.getKind() == kind::EQUAL);
+ Assert(pf->d_node.getNumChildren() == 2);
+ Assert (pf->d_node[0].isConst() && pf->d_node[1].isConst());
+ }
Node n1;
std::stringstream ss, ss2;
//Assert(subTrans.d_children.size() == pf->d_children.size() - 1);
Debug("mgdx") << "\nsubtrans has " << subTrans.d_children.size() << " children\n";
- if(pf->d_children.size() > 2) {
+ if(!disequalityFound || pf->d_children.size() > 2) {
n1 = toStreamRecLFSC(ss, tp, &subTrans, 1, map);
} else {
n1 = toStreamRecLFSC(ss, tp, subTrans.d_children[0], 1, map);
Debug("mgdx") << "\nsubTrans unique child " << subTrans.d_children[0]->d_id << " was proven\ngot: " << n1 << std::endl;
}
- Node n2 = pf->d_children[neg]->d_node;
- Assert(n2.getKind() == kind::NOT);
- Debug("mgdx") << "\nhave proven: " << n1 << std::endl;
- Debug("mgdx") << "n2 is " << n2 << std::endl;
- Debug("mgdx") << "n2->d_id is " << pf->d_children[neg]->d_id << std::endl;
- Debug("mgdx") << "n2[0] is " << n2[0] << std::endl;
+ out << "(clausify_false (contra _ ";
- if (n2[0].getNumChildren() > 0) { Debug("mgdx") << "\nn2[0]: " << n2[0][0] << std::endl; }
- if (n1.getNumChildren() > 1) { Debug("mgdx") << "n1[1]: " << n1[1] << std::endl; }
+ if (disequalityFound) {
+ Node n2 = pf->d_children[neg]->d_node;
+ Assert(n2.getKind() == kind::NOT);
+ Debug("mgdx") << "\nhave proven: " << n1 << std::endl;
+ Debug("mgdx") << "n2 is " << n2 << std::endl;
+ Debug("mgdx") << "n2->d_id is " << pf->d_children[neg]->d_id << std::endl;
+ Debug("mgdx") << "n2[0] is " << n2[0] << std::endl;
- if (pf->d_children[neg]->d_id == d_reasonExt) {
- // The negative node was created by an EXT rule; e.g. it is a[k]!=b[k], due to a!=b.
-
- // (clausify_false (contra _ .gl2 (or_elim_1 _ _ .gl1 FIXME))))))) (\ .glemc6
-
- out << "(clausify_false (contra _ ";
- out << ss.str();
+ if (n2[0].getNumChildren() > 0) { Debug("mgdx") << "\nn2[0]: " << n2[0][0] << std::endl; }
+ if (n1.getNumChildren() > 1) { Debug("mgdx") << "n1[1]: " << n1[1] << std::endl; }
- toStreamRecLFSC(ss2, tp, pf->d_children[neg], 1, map);
-
- out << " ";
- out << ss2.str();
- out << "))";
-
- } else {
- // The negative node is, e.g., a pure equality
- out << "(clausify_false (contra _ ";
-
- if(n2[0].getKind() == kind::APPLY_UF) {
+ if ((pf->d_children[neg]->d_id == d_reasonExt) ||
+ (pf->d_children[neg]->d_id == theory::eq::MERGED_THROUGH_TRANS)) {
+ // Ext case: The negative node was created by an EXT rule; e.g. it is a[k]!=b[k], due to a!=b.
+ out << ss.str();
+ out << " ";
+ toStreamRecLFSC(ss2, tp, pf->d_children[neg], 1, map);
+ out << ss2.str();
+ } else if (n2[0].getKind() == kind::APPLY_UF) {
out << "(trans _ _ _ _ ";
out << "(symm _ _ _ ";
out << ss.str();
@@ -276,16 +294,27 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Debug("pf::array") << "ArrayProof::toStream: getLitName( " << n2[0] << " ) = " <<
ProofManager::getLitName(n2[0]) << std::endl;
- out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
+ out << " " << ProofManager::getLitName(n2[0]);
}
+ } else {
+ Node n2 = pf->d_node;
+ Assert(n2.getKind() == kind::EQUAL);
+ Assert((n1[0] == n2[0] && n1[1] == n2[1]) || (n1[1] == n2[0] && n1[0] == n2[1]));
+
+ out << ss.str();
+ out << " ";
+ ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out,
+ n1[0].toExpr(),
+ n1[1].toExpr());
}
+ out << "))" << std::endl;
return Node();
}
if (pf->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE) {
Debug("mgd") << "\nok, looking at congruence:\n";
- pf->debug_print("mgd");
+ pf->debug_print("mgd", 0, &d_proofPrinter);
std::stack<const theory::eq::EqProof*> stk;
for(const theory::eq::EqProof* pf2 = pf; pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE; pf2 = pf2->d_children[0]) {
Assert(!pf2->d_node.isNull());
@@ -315,7 +344,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Debug("mgd") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n";
- pf2->debug_print("mgd");
+ pf2->debug_print("mgd", 0, &d_proofPrinter);
// Temp
Debug("mgd") << "n1 is a proof for: " << pf2->d_children[0]->d_node << ". It is: " << n1 << std::endl;
Debug("mgd") << "n2 is a proof for: " << pf2->d_children[1]->d_node << ". It is: " << n2 << std::endl;
@@ -332,7 +361,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Debug("mgd") << "SIDE IS 1\n";
if(!match(pf2->d_node, n1[1])) {
Debug("mgd") << "IN BAD CASE, our first subproof is\n";
- pf2->d_children[0]->debug_print("mgd");
+ pf2->d_children[0]->debug_print("mgd", 0, &d_proofPrinter);
}
Assert(match(pf2->d_node, n1[1]));
side = 1;
@@ -546,6 +575,20 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
return pf->d_node;
}
+ else if (pf->d_id == theory::eq::MERGED_THROUGH_CONSTANTS) {
+ Debug("pf::array") << "Proof for: " << pf->d_node << std::endl;
+ Assert(pf->d_node.getKind() == kind::NOT);
+ Node n = pf->d_node[0];
+ Assert(n.getKind() == kind::EQUAL);
+ Assert(n.getNumChildren() == 2);
+ Assert(n[0].isConst() && n[1].isConst());
+
+ ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out,
+ n[0].toExpr(),
+ n[1].toExpr());
+ return pf->d_node;
+ }
+
else if (pf->d_id == theory::eq::MERGED_THROUGH_TRANS) {
bool firstNeg = false;
bool secondNeg = false;
@@ -554,7 +597,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Assert(pf->d_children.size() >= 2);
std::stringstream ss;
Debug("mgd") << "\ndoing trans proof[[\n";
- pf->debug_print("mgd");
+ pf->debug_print("mgd", 0, &d_proofPrinter);
Debug("mgd") << "\n";
Node n1 = toStreamRecLFSC(ss, tp, pf->d_children[0], tb + 1, map);
Debug("mgd") << "\ndoing trans proof, got n1 " << n1 << "\n";
@@ -772,7 +815,7 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
Warning() << "0 proves " << n1 << "\n";
Warning() << "1 proves " << n2 << "\n\n";
- pf->debug_print("mgdx",0);
+ pf->debug_print("mgdx", 0, &d_proofPrinter);
//toStreamRec(Warning.getStream(), pf, 0);
Warning() << "\n\n";
Unreachable();
@@ -931,6 +974,9 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
t4 = pf->d_children[0]->d_node[0][side][0][2];
ret = pf->d_node;
+ // The order of indices needs to match; we might have to swap t1 and t2 and then apply symmetry.
+ bool swap = (t2 == pf->d_children[0]->d_node[0][side][0][1]);
+
Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\nt4 " << t4 << "\n";
Assert(pf->d_children.size() == 1);
@@ -939,28 +985,31 @@ Node ProofArray::toStreamRecLFSC(std::ostream& out,
Debug("pf::array") << "Subproof is: " << ss.str() << std::endl;
+ if (swap) {
+ out << "(symm _ _ _ ";
+ }
+
out << "(negativerow _ _ ";
- tp->printTerm(t1.toExpr(), out, map);
+ tp->printTerm(swap ? t2.toExpr() : t1.toExpr(), out, map);
out << " ";
- tp->printTerm(t2.toExpr(), out, map);
+ tp->printTerm(swap ? t1.toExpr() : t2.toExpr(), out, map);
out << " ";
tp->printTerm(t3.toExpr(), out, map);
out << " ";
tp->printTerm(t4.toExpr(), out, map);
out << " ";
-
- // 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() << ")";
- // }
+ if (side != 0) {
+ out << "(negsymm _ _ _ " << ss.str() << ")";
+ } else {
+ out << ss.str();
+ }
out << ")";
- // Unreachable();
+ if (swap) {
+ out << ") ";
+ }
return ret;
}
@@ -1071,13 +1120,12 @@ void ArrayProof::registerTerm(Expr term) {
}
std::string ArrayProof::skolemToLiteral(Expr skolem) {
+ Debug("pf::array") << "ArrayProof::skolemToLiteral( " << skolem << ")" << std::endl;
Assert(d_skolemToLiteral.find(skolem) != d_skolemToLiteral.end());
return d_skolemToLiteral[skolem];
}
-void LFSCArrayProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) {
- Debug("pf::array") << std::endl << "(pf::array) LFSCArrayProof::printOwnedTerm: term = " << term << std::endl;
-
+void LFSCArrayProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
Assert (theory::Theory::theoryOf(term) == theory::THEORY_ARRAY);
if (theory::Theory::theoryOf(term) != theory::THEORY_ARRAY) {
@@ -1154,23 +1202,35 @@ void LFSCArrayProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& m
void LFSCArrayProof::printOwnedSort(Type type, std::ostream& os) {
Debug("pf::array") << std::endl << "(pf::array) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl;
Assert (type.isArray() || type.isSort());
- os << type <<" ";
+ if (type.isArray()){
+ ArrayType array_type(type);
+
+ Debug("pf::array") << "LFSCArrayProof::printOwnedSort: type is an array. Index type: "
+ << array_type.getIndexType()
+ << ", element type: " << array_type.getConstituentType() << std::endl;
+
+ os << "(Array ";
+ printSort(array_type.getIndexType(), os);
+ os << " ";
+ printSort(array_type.getConstituentType(), os);
+ os << ")";
+ } else {
+ os << type <<" ";
+ }
}
-void LFSCArrayProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+void LFSCArrayProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
os << " ;; Array Theory Lemma \n;;";
for (unsigned i = 0; i < lemma.size(); ++i) {
os << lemma[i] <<" ";
}
os <<"\n";
//os << " (clausify_false trust)";
- ArrayProof::printTheoryLemmaProof(lemma, os, paren);
+ ArrayProof::printTheoryLemmaProof(lemma, os, paren, map);
}
void LFSCArrayProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
// declaring the sorts
- Debug("pf::array") << "Arrays declaring sorts..." << std::endl;
-
for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) {
if (!ProofManager::currentPM()->wasPrinted(*it)) {
os << "(% " << *it << " sort\n";
@@ -1229,6 +1289,7 @@ void LFSCArrayProof::printTermDeclarations(std::ostream& os, std::ostream& paren
void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
Debug("pf::array") << "Array: print deferred declarations called" << std::endl;
+ unsigned count = 1;
for (ExprSet::const_iterator it = d_skolemDeclarations.begin(); it != d_skolemDeclarations.end(); ++it) {
Expr term = *it;
Node equality = ProofManager::getSkolemizationManager()->getDisequality(*it);
@@ -1237,7 +1298,7 @@ void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& p
<< "It is a witness for: " << equality << std::endl;
std::ostringstream newSkolemLiteral;
- newSkolemLiteral << ".sl" << d_skolemToLiteral.size();
+ newSkolemLiteral << ".sl" << count++;
std::string skolemLiteral = newSkolemLiteral.str();
d_skolemToLiteral[*it] = skolemLiteral;
@@ -1250,14 +1311,13 @@ void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& p
Node array_one = equality[0][0];
Node array_two = equality[0][1];
- LetMap map;
-
+ ProofLetMap map;
os << "(ext _ _ ";
printTerm(array_one.toExpr(), os, map);
os << " ";
printTerm(array_two.toExpr(), os, map);
os << " (\\ ";
- printTerm(*it, os, map);
+ os << ProofManager::sanitize(*it);
os << " (\\ ";
os << skolemLiteral.c_str();
os << "\n";
@@ -1266,4 +1326,8 @@ void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& p
}
}
+void LFSCArrayProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+ // Nothing to do here at this point.
+}
+
} /* CVC4 namespace */
diff --git a/src/proof/array_proof.h b/src/proof/array_proof.h
index fb25c9433..69e62dbf3 100644
--- a/src/proof/array_proof.h
+++ b/src/proof/array_proof.h
@@ -30,10 +30,36 @@ namespace CVC4 {
//proof object outputted by TheoryARRAY
class ProofArray : public Proof {
private:
+ class ArrayProofPrinter : public theory::eq::EqProof::PrettyPrinter {
+ public:
+ ArrayProofPrinter() : d_row(0), d_row1(0), d_ext(0) {
+ }
+
+ std::string printTag(unsigned tag) {
+ if (tag == theory::eq::MERGED_THROUGH_CONGRUENCE) return "Congruence";
+ if (tag == theory::eq::MERGED_THROUGH_EQUALITY) return "Pure Equality";
+ if (tag == theory::eq::MERGED_THROUGH_REFLEXIVITY) return "Reflexivity";
+ if (tag == theory::eq::MERGED_THROUGH_CONSTANTS) return "Constants";
+ if (tag == theory::eq::MERGED_THROUGH_TRANS) return "Transitivity";
+
+ if (tag == d_row) return "Read Over Write";
+ if (tag == d_row1) return "Read Over Write (1)";
+ if (tag == d_ext) return "Extensionality";
+
+ std::ostringstream result;
+ result << tag;
+ return result.str();
+ }
+
+ unsigned d_row;
+ unsigned d_row1;
+ unsigned d_ext;
+ };
+
Node toStreamRecLFSC(std::ostream& out, TheoryProof* tp,
theory::eq::EqProof* pf,
unsigned tb,
- const LetMap& map);
+ const ProofLetMap& map);
/** Merge tag for ROW applications */
unsigned d_reasonRow;
@@ -41,18 +67,25 @@ private:
unsigned d_reasonRow1;
/** Merge tag for EXT applications */
unsigned d_reasonExt;
+
+ ArrayProofPrinter d_proofPrinter;
public:
ProofArray(theory::eq::EqProof* pf) : d_proof(pf) {}
//it is simply an equality engine proof
theory::eq::EqProof *d_proof;
void toStream(std::ostream& out);
- void toStreamLFSC(std::ostream& out, TheoryProof* tp, theory::eq::EqProof* pf, const LetMap& map);
+ void toStream(std::ostream& out, const ProofLetMap& map);
+ void toStreamLFSC(std::ostream& out, TheoryProof* tp, theory::eq::EqProof* pf, const ProofLetMap& map);
void registerSkolem(Node equality, Node skolem);
void setRowMergeTag(unsigned tag);
void setRow1MergeTag(unsigned tag);
void setExtMergeTag(unsigned tag);
+
+ unsigned getRowMergeTag() const;
+ unsigned getRow1MergeTag() const;
+ unsigned getExtMergeTag() const;
};
namespace theory {
@@ -85,12 +118,13 @@ public:
: ArrayProof(arrays, proofEngine)
{}
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map);
+ 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);
};
diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp
index b63782226..f19e45920 100644
--- a/src/proof/bitvector_proof.cpp
+++ b/src/proof/bitvector_proof.cpp
@@ -15,14 +15,17 @@
**/
-#include "proof/bitvector_proof.h"
#include "options/bv_options.h"
+#include "proof/array_proof.h"
+#include "proof/bitvector_proof.h"
#include "proof/clause_id.h"
+#include "proof/proof_output_channel.h"
#include "proof/proof_utils.h"
#include "proof/sat_proof_implementation.h"
#include "prop/bvminisat/bvminisat.h"
#include "theory/bv/bitblaster_template.h"
#include "theory/bv/theory_bv.h"
+#include "theory/bv/theory_bv_rewrite_rules.h"
using namespace CVC4::theory;
using namespace CVC4::theory::bv;
@@ -80,20 +83,40 @@ BVSatProof* BitVectorProof::getSatProof() {
}
void BitVectorProof::registerTermBB(Expr term) {
+ Debug("pf::bv") << "BitVectorProof::registerTermBB( " << term << " )" << std::endl;
+
if (d_seenBBTerms.find(term) != d_seenBBTerms.end())
return;
d_seenBBTerms.insert(term);
d_bbTerms.push_back(term);
+
+ // If this term gets used in the final proof, we will want to register it. However,
+ // we don't know this at this point; and when the theory proof engine sees it, if it belongs
+ // to another theory, it won't register it with this proof. So, we need to tell the
+ // engine to inform us.
+
+ if (theory::Theory::theoryOf(term) != theory::THEORY_BV) {
+ Debug("pf::bv") << "\tMarking term " << term << " for future BV registration" << std::endl;
+ d_proofEngine->markTermForFutureRegistration(term, theory::THEORY_BV);
+ }
}
void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) {
+ Debug("pf::bv") << "BitVectorProof::registerAtomBB( " << atom << ", " << atom_bb << " )" << std::endl;
+
Expr def = atom.iffExpr(atom_bb);
- d_bbAtoms.insert(std::make_pair(atom, def));
+ d_bbAtoms.insert(std::make_pair(atom, def));
registerTerm(atom);
+
+ // Register the atom's terms for bitblasting
+ registerTermBB(atom[0]);
+ registerTermBB(atom[1]);
}
void BitVectorProof::registerTerm(Expr term) {
+ Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )" << std::endl;
+
d_usedBB.insert(term);
if (Theory::isLeafOf(term, theory::THEORY_BV) &&
@@ -101,6 +124,11 @@ void BitVectorProof::registerTerm(Expr term) {
d_declarations.insert(term);
}
+ Debug("pf::bv") << "Going to register children: " << std::endl;
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ Debug("pf::bv") << "\t" << term[i] << std::endl;
+ }
+
// don't care about parametric operators for bv?
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
d_proofEngine->registerTerm(term[i]);
@@ -108,6 +136,7 @@ void BitVectorProof::registerTerm(Expr term) {
}
std::string BitVectorProof::getBBTermName(Expr expr) {
+ Debug("pf::bv") << "BitVectorProof::getBBTermName( " << expr << " ) = bt" << expr.getId() << std::endl;
std::ostringstream os;
os << "bt"<< expr.getId();
return os.str();
@@ -122,6 +151,8 @@ void BitVectorProof::startBVConflict(CVC4::BVMinisat::Solver::TLit lit) {
}
void BitVectorProof::endBVConflict(const CVC4::BVMinisat::Solver::TLitVec& confl) {
+ Debug("pf::bv") << "BitVectorProof::endBVConflict called" << std::endl;
+
std::vector<Expr> expr_confl;
for (int i = 0; i < confl.size(); ++i) {
prop::SatLiteral lit = prop::BVMinisatSatSolver::toSatLiteral(confl[i]);
@@ -129,6 +160,7 @@ void BitVectorProof::endBVConflict(const CVC4::BVMinisat::Solver::TLitVec& confl
Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
expr_confl.push_back(expr_lit);
}
+
Expr conflict = utils::mkSortedExpr(kind::OR, expr_confl);
Debug("pf::bv") << "Make conflict for " << conflict << std::endl;
@@ -144,30 +176,104 @@ void BitVectorProof::endBVConflict(const CVC4::BVMinisat::Solver::TLitVec& confl
ClauseId clause_id = d_resolutionProof->registerAssumptionConflict(confl);
d_bbConflictMap[conflict] = clause_id;
d_resolutionProof->endResChain(clause_id);
- Debug("pf::bv") << "BitVectorProof::endBVConflict id"<<clause_id<< " => " << conflict << "\n";
+ Debug("pf::bv") << "BitVectorProof::endBVConflict id" <<clause_id<< " => " << conflict << "\n";
d_isAssumptionConflict = false;
}
void BitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts) {
+
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
Debug("pf::bv") << "Construct full proof." << std::endl;
d_resolutionProof->constructProof();
return;
}
- for(unsigned i = 0; i < conflicts.size(); ++i) {
+
+ for (unsigned i = 0; i < conflicts.size(); ++i) {
Expr confl = conflicts[i];
- Debug("pf::bv") << "Finalize conflict " << confl << std::endl;
- //Assert (d_bbConflictMap.find(confl) != d_bbConflictMap.end());
- if(d_bbConflictMap.find(confl) != d_bbConflictMap.end()){
+ Debug("pf::bv") << "Finalize conflict #" << i << ": " << confl << std::endl;
+
+ // Special case: if the conflict has a (true) or a (not false) in it, it is trivial...
+ bool ignoreConflict = false;
+ if ((confl.isConst() && confl.getConst<bool>()) ||
+ (confl.getKind() == kind::NOT && confl[0].isConst() && !confl[0].getConst<bool>())) {
+ ignoreConflict = true;
+ } else if (confl.getKind() == kind::OR) {
+ for (unsigned k = 0; k < confl.getNumChildren(); ++k) {
+ if ((confl[k].isConst() && confl[k].getConst<bool>()) ||
+ (confl[k].getKind() == kind::NOT && confl[k][0].isConst() && !confl[k][0].getConst<bool>())) {
+ ignoreConflict = true;
+ }
+ }
+ }
+ if (ignoreConflict) {
+ Debug("pf::bv") << "Ignoring conflict due to (true) or (not false)" << std::endl;
+ continue;
+ }
+
+ if (d_bbConflictMap.find(confl) != d_bbConflictMap.end()) {
ClauseId id = d_bbConflictMap[confl];
d_resolutionProof->collectClauses(id);
- }else{
- Debug("pf::bv") << "Do not collect clauses for " << confl << std::endl;
+ } else {
+ // There is no exact match for our conflict, but maybe it is a subset of another conflict
+ ExprToClauseId::const_iterator it;
+ bool matchFound = false;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) {
+ Expr possibleMatch = it->first;
+ if (possibleMatch.getKind() != kind::OR) {
+ // This is a single-node conflict. If this node is in the conflict we're trying to prove,
+ // we have a match.
+ for (unsigned k = 0; k < confl.getNumChildren(); ++k) {
+ if (confl[k] == possibleMatch) {
+ matchFound = true;
+ d_resolutionProof->collectClauses(it->second);
+ break;
+ }
+ }
+ } else {
+ if (possibleMatch.getNumChildren() > confl.getNumChildren())
+ continue;
+
+ unsigned k = 0;
+ bool matching = true;
+ for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j) {
+ // j is the index in possibleMatch
+ // k is the index in confl
+ while (k < confl.getNumChildren() && confl[k] != possibleMatch[j]) {
+ ++k;
+ }
+ if (k == confl.getNumChildren()) {
+ // We couldn't find a match for possibleMatch[j], so not a match
+ matching = false;
+ break;
+ }
+ }
+
+ if (matching) {
+ Debug("pf::bv") << "Collecting info from a sub-conflict" << std::endl;
+ d_resolutionProof->collectClauses(it->second);
+ matchFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!matchFound) {
+ Debug("pf::bv") << "Do not collect clauses for " << confl << std::endl
+ << "Dumping existing conflicts:" << std::endl;
+
+ i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) {
+ ++i;
+ Debug("pf::bv") << "\tConflict #" << i << ": " << it->first << std::endl;
+ }
+
+ Unreachable();
+ }
}
}
}
-void LFSCBitVectorProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
Debug("pf::bv") << std::endl << "(pf::bv) LFSCBitVectorProof::printOwnedTerm( " << term << " ), theory is: "
<< Theory::theoryOf(term) << std::endl;
@@ -238,17 +344,31 @@ void LFSCBitVectorProof::printOwnedTerm(Expr term, std::ostream& os, const LetMa
printBitOf(term, os, map);
return;
}
- case kind::VARIABLE:
+
+ case kind::VARIABLE: {
+ os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")";
+ return;
+ }
+
case kind::SKOLEM: {
- os << "(a_var_bv " << utils::getSize(term)<<" " << ProofManager::sanitize(term) <<")";
+
+ // TODO: we need to distinguish between "real" skolems (e.g. from array) and "fake" skolems,
+ // like ITE terms. Is there a more elegant way?
+
+ if (ProofManager::getSkolemizationManager()->isSkolem(term)) {
+ os << ProofManager::sanitize(term);
+ } else {
+ os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")";
+ }
return;
}
+
default:
Unreachable();
}
}
-void LFSCBitVectorProof::printBitOf(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printBitOf(Expr term, std::ostream& os, const ProofLetMap& map) {
Assert (term.getKind() == kind::BITVECTOR_BITOF);
unsigned bit = term.getOperator().getConst<BitVectorBitOf>().bitIndex;
Expr var = term[0];
@@ -258,14 +378,7 @@ void LFSCBitVectorProof::printBitOf(Expr term, std::ostream& os, const LetMap& m
<< ", var = " << var << std::endl;
os << "(bitof ";
- if (var.getKind() == kind::VARIABLE || var.getKind() == kind::SKOLEM) {
- // If var is "simple", we can just sanitize and print
- os << ProofManager::sanitize(var);
- } else {
- // If var is "complex", it can belong to another theory. Therefore, dispatch again.
- d_proofEngine->printBoundTerm(var, os, map);
- }
-
+ os << d_exprToVariableName[var];
os << " " << bit << ")";
}
@@ -283,7 +396,7 @@ void LFSCBitVectorProof::printConstant(Expr term, std::ostream& os) {
os << paren.str();
}
-void LFSCBitVectorProof::printOperatorNary(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printOperatorNary(Expr term, std::ostream& os, const ProofLetMap& map) {
std::string op = utils::toLFSCKind(term.getKind());
std::ostringstream paren;
std::string holes = term.getKind() == kind::BITVECTOR_CONCAT ? "_ _ " : "";
@@ -301,7 +414,7 @@ void LFSCBitVectorProof::printOperatorNary(Expr term, std::ostream& os, const Le
}
}
-void LFSCBitVectorProof::printOperatorUnary(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printOperatorUnary(Expr term, std::ostream& os, const ProofLetMap& map) {
os <<"(";
os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term) <<" ";
os << " ";
@@ -309,7 +422,7 @@ void LFSCBitVectorProof::printOperatorUnary(Expr term, std::ostream& os, const L
os <<")";
}
-void LFSCBitVectorProof::printPredicate(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printPredicate(Expr term, std::ostream& os, const ProofLetMap& map) {
os <<"(";
os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term[0]) <<" ";
os << " ";
@@ -319,7 +432,7 @@ void LFSCBitVectorProof::printPredicate(Expr term, std::ostream& os, const LetMa
os <<")";
}
-void LFSCBitVectorProof::printOperatorParametric(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBitVectorProof::printOperatorParametric(Expr term, std::ostream& os, const ProofLetMap& map) {
os <<"(";
os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term) <<" ";
os <<" ";
@@ -349,14 +462,16 @@ void LFSCBitVectorProof::printOperatorParametric(Expr term, std::ostream& os, co
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<<")";
}
-void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
+ Debug("pf::bv") << "(pf::bv) LFSCBitVectorProof::printTheoryLemmaProof called" << std::endl;
Expr conflict = utils::mkSortedExpr(kind::OR, lemma);
+ Debug("pf::bv") << "\tconflict = " << conflict << std::endl;
+
if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end()) {
std::ostringstream lemma_paren;
for (unsigned i = 0; i < lemma.size(); ++i) {
@@ -377,7 +492,7 @@ void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::os
// print corresponding literal in bv sat solver
prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
os << pm->getAtomName(bb_var, "bb");
- os <<"(\\unit"<<bb_var<<"\n";
+ os <<"(\\ unit"<<bb_var<<"\n";
lemma_paren <<")";
}
Expr lem = utils::mkOr(lemma);
@@ -386,11 +501,134 @@ void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::os
d_resolutionProof->printAssumptionsResolution(lemma_id, os, lemma_paren);
os <<lemma_paren.str();
} else {
- Unreachable(); // If we were to reach here, we would crash because BV replay is currently not supported
- // in TheoryProof::printTheoryLemmaProof()
- Debug("pf::bv") << std::endl << "; Print non-bitblast theory conflict " << conflict << std::endl;
- BitVectorProof::printTheoryLemmaProof( lemma, os, paren );
+ Debug("pf::bv") << "Found a non-recorded conflict. Looking for a matching sub-conflict..."
+ << std::endl;
+
+ bool matching;
+
+ ExprToClauseId::const_iterator it;
+ unsigned i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) {
+ // Our conflict is sorted, and the records are also sorted.
+ ++i;
+ Expr possibleMatch = it->first;
+
+ if (possibleMatch.getKind() != kind::OR) {
+ // This is a single-node conflict. If this node is in the conflict we're trying to prove,
+ // we have a match.
+ matching = false;
+
+ for (unsigned k = 0; k < conflict.getNumChildren(); ++k) {
+ if (conflict[k] == possibleMatch) {
+ matching = true;
+ break;
+ }
+ }
+ } else {
+ if (possibleMatch.getNumChildren() > conflict.getNumChildren())
+ continue;
+
+ unsigned k = 0;
+
+ matching = true;
+ for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j) {
+ // j is the index in possibleMatch
+ // k is the index in conflict
+ while (k < conflict.getNumChildren() && conflict[k] != possibleMatch[j]) {
+ ++k;
+ }
+ if (k == conflict.getNumChildren()) {
+ // We couldn't find a match for possibleMatch[j], so not a match
+ matching = false;
+ break;
+ }
+ }
+ }
+
+ if (matching) {
+ Debug("pf::bv") << "Found a match with conflict #" << i << ": " << std::endl << possibleMatch << std::endl;
+ // The rest is just a copy of the usual handling, if a precise match is found.
+ // We only use the literals that appear in the matching conflict, though, and not in the
+ // original lemma - as these may not have even been bit blasted!
+ std::ostringstream lemma_paren;
+
+ if (possibleMatch.getKind() == kind::OR) {
+ for (unsigned i = 0; i < possibleMatch.getNumChildren(); ++i) {
+ Expr lit = possibleMatch[i];
+
+ if (lit.getKind() == kind::NOT) {
+ os << "(intro_assump_t _ _ _ ";
+ } else {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren <<")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os <<" ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os <<"(\\ unit"<<bb_var<<"\n";
+ lemma_paren <<")";
+ }
+ } else {
+ // The conflict only consists of one node, either positive or negative.
+ Expr lit = possibleMatch;
+ if (lit.getKind() == kind::NOT) {
+ os << "(intro_assump_t _ _ _ ";
+ } else {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren <<")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os <<" ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os <<"(\\ unit"<<bb_var<<"\n";
+ lemma_paren <<")";
+ }
+
+ ClauseId lemma_id = it->second;
+ d_resolutionProof->printAssumptionsResolution(lemma_id, os, lemma_paren);
+ os <<lemma_paren.str();
+
+ return;
+ }
+ }
+
+ // We failed to find a matching sub conflict. The last hope is that the
+ // conflict has a FALSE assertion in it; this can happen in some corner cases,
+ // where the FALSE is the result of a rewrite.
+
+ for (unsigned i = 0; i < lemma.size(); ++i) {
+ if (lemma[i].getKind() == kind::NOT && lemma[i][0] == utils::mkFalse()) {
+ Debug("pf::bv") << "Lemma has a (not false) literal" << std::endl;
+ os << "(clausify_false ";
+ os << ProofManager::getLitName(lemma[i]);
+ os << ")";
+ return;
+ }
+ }
+
+ Debug("pf::bv") << "Failed to find a matching sub-conflict..." << std::endl
+ << "Dumping existing conflicts:" << std::endl;
+
+ i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) {
+ ++i;
+ Debug("pf::bv") << "\tConflict #" << i << ": " << it->first << std::endl;
+ }
+
+ Unreachable();
}
}
@@ -402,7 +640,14 @@ void LFSCBitVectorProof::printTermDeclarations(std::ostream& os, std::ostream& p
ExprSet::const_iterator it = d_declarations.begin();
ExprSet::const_iterator end = d_declarations.end();
for (; it != end; ++it) {
- os << "(% " << ProofManager::sanitize(*it) <<" var_bv\n";
+ if ((it->isVariable() || it->isConst()) && !ProofManager::getSkolemizationManager()->isSkolem(*it)) {
+ d_exprToVariableName[*it] = ProofManager::sanitize(*it);
+ } else {
+ std::string newAlias = assignAlias(*it);
+ d_exprToVariableName[*it] = newAlias;
+ }
+
+ os << "(% " << d_exprToVariableName[*it] <<" var_bv" << "\n";
paren <<")";
}
}
@@ -411,15 +656,43 @@ void LFSCBitVectorProof::printDeferredDeclarations(std::ostream& os, std::ostrea
// Nothing to do here at this point.
}
+void LFSCBitVectorProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+ // Print "trust" statements to bind complex bv variables to their associated terms
+
+ ExprToString::const_iterator it = d_assignedAliases.begin();
+ ExprToString::const_iterator end = d_assignedAliases.end();
+
+ for (; it != end; ++it) {
+ Debug("pf::bv") << "Printing aliasing declaration for: " << *it << std::endl;
+ std::stringstream declaration;
+ declaration << ".fbvd" << d_aliasToBindDeclaration.size();
+ d_aliasToBindDeclaration[it->second] = declaration.str();
+
+ os << "(th_let_pf _ ";
+
+ 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);
+ os << ")) ";
+ os << "(\\ "<< d_aliasToBindDeclaration[it->second] << "\n";
+ paren << "))";
+ }
+
+ os << "\n";
+}
+
void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
// TODO: once we have the operator elimination rules remove those that we
// eliminated
Assert (term.getType().isBitVector());
Kind kind = term.getKind();
- if (Theory::isLeafOf(term, theory::THEORY_BV) &&
- !term.isConst()) {
- os << "(bv_bbl_var "<<utils::getSize(term) << " " << ProofManager::sanitize(term) <<" _ )";
+ if (Theory::isLeafOf(term, theory::THEORY_BV) && !term.isConst()) {
+ // A term is a leaf if it has no children, or if it belongs to another theory
+ os << "(bv_bbl_var " << utils::getSize(term) << " " << d_exprToVariableName[term];
+ os << " _)";
return;
}
@@ -448,14 +721,18 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
case kind::BITVECTOR_PLUS :
case kind::BITVECTOR_SUB :
case kind::BITVECTOR_CONCAT : {
- for (unsigned i =0; i < term.getNumChildren() - 1; ++i) {
+ Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl;
+
+ for (int i = term.getNumChildren() - 1; i > 0; --i) {
os <<"(bv_bbl_"<< utils::toLFSCKind(kind);
+
if (kind == kind::BITVECTOR_CONCAT) {
- os << " " << utils::getSize(term) <<" _ ";
+ os << " " << utils::getSize(term) << " _";
}
- os <<" _ _ _ _ _ _ ";
+ os << " _ _ _ _ _ _ ";
}
- os << getBBTermName(term[0]) <<" ";
+
+ os << getBBTermName(term[0]) << " ";
for (unsigned i = 1; i < term.getNumChildren(); ++i) {
os << getBBTermName(term[i]);
@@ -463,22 +740,25 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
}
return;
}
+
case kind::BITVECTOR_NEG :
case kind::BITVECTOR_NOT :
case kind::BITVECTOR_ROTATE_LEFT :
case kind::BITVECTOR_ROTATE_RIGHT : {
- os <<"(bv_bbl_"<<utils::toLFSCKind(kind);
- os <<" _ _ _ _ ";
+ os << "(bv_bbl_"<<utils::toLFSCKind(kind);
+ os << " _ _ _ _ ";
os << getBBTermName(term[0]);
- os <<")";
+ os << ")";
return;
}
case kind::BITVECTOR_EXTRACT : {
- os <<"(bv_bbl_"<<utils::toLFSCKind(kind) <<" ";
- os << utils::getSize(term) << " ";
+ os <<"(bv_bbl_"<<utils::toLFSCKind(kind);
+
+ os << " " << utils::getSize(term) << " ";
os << utils::getExtractHigh(term) << " ";
os << utils::getExtractLow(term) << " ";
os << " _ _ _ _ ";
+
os << getBBTermName(term[0]);
os <<")";
return;
@@ -486,8 +766,8 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
case kind::BITVECTOR_REPEAT :
case kind::BITVECTOR_ZERO_EXTEND :
case kind::BITVECTOR_SIGN_EXTEND : {
- os <<"(bv_bbl_"<<utils::toLFSCKind(kind) <<" ";
- os << utils::getSize(term) <<" ";
+ os << "(bv_bbl_" << utils::toLFSCKind(kind) << " ";
+ os << utils::getSize(term) << " ";
if (term.getKind() == kind::BITVECTOR_REPEAT) {
unsigned amount = term.getOperator().getConst<BitVectorRepeat>().repeatAmount;
os << amount;
@@ -501,6 +781,7 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
unsigned amount = term.getOperator().getConst<BitVectorZeroExtend>().zeroExtendAmount;
os << amount;
}
+
os <<" _ _ _ _ ";
os << getBBTermName(term[0]);
os <<")";
@@ -516,7 +797,7 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
case kind::BITVECTOR_SHL :
case kind::BITVECTOR_LSHR :
case kind::BITVECTOR_ASHR : {
- // these are terms for which bit-blasting is not supported yet
+ // these are terms for which bit-blasting is not supported yet
std::ostringstream paren;
os <<"(trust_bblast_term _ ";
paren <<")";
@@ -539,7 +820,7 @@ void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
}
}
-void LFSCBitVectorProof::printAtomBitblasting(Expr atom, std::ostream& os) {
+void LFSCBitVectorProof::printAtomBitblasting(Expr atom, std::ostream& os, bool swap) {
Kind kind = atom.getKind();
switch(kind) {
case kind::BITVECTOR_ULT :
@@ -550,11 +831,19 @@ void LFSCBitVectorProof::printAtomBitblasting(Expr atom, std::ostream& os) {
case kind::BITVECTOR_SLE :
case kind::BITVECTOR_SGT :
case kind::BITVECTOR_SGE :
- case kind::EQUAL:
- {
- os <<"(bv_bbl_" << utils::toLFSCKind(atom.getKind());
+ case kind::EQUAL: {
+ Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl;
+
+ os << "(bv_bbl_" << utils::toLFSCKind(atom.getKind());
+
+ if (swap) {os << "_swap";}
+
os << " _ _ _ _ _ _ ";
- os << getBBTermName(atom[0])<<" " << getBBTermName(atom[1]) <<")";
+ os << getBBTermName(atom[0]);
+ os << " ";
+ os << getBBTermName(atom[1]);
+ os << ")";
+
return;
}
default:
@@ -562,19 +851,62 @@ void LFSCBitVectorProof::printAtomBitblasting(Expr atom, std::ostream& os) {
}
}
+void LFSCBitVectorProof::printAtomBitblastingToFalse(Expr atom, std::ostream& os) {
+ Assert(atom.getKind() == kind::EQUAL);
+
+ os << "(bv_bbl_=_false";
+ os << " _ _ _ _ _ _ ";
+ os << getBBTermName(atom[0]);
+
+ os << " ";
+
+ os << getBBTermName(atom[1]);
+
+ os << ")";
+}
void LFSCBitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren) {
// bit-blast terms
+ {
+ Debug("pf::bv") << "LFSCBitVectorProof::printBitblasting: the bitblasted terms are: " << std::endl;
+ std::vector<Expr>::const_iterator it = d_bbTerms.begin();
+ std::vector<Expr>::const_iterator end = d_bbTerms.end();
+
+ Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER);
+
+ for (; it != end; ++it) {
+ if (d_usedBB.find(*it) == d_usedBB.end()) {
+ Debug("pf::bv") << "\t" << *it << "\t(UNUSED)" << std::endl;
+ } else {
+ Debug("pf::bv") << "\t" << *it << std::endl;
+ }
+ }
+
+ Debug("pf::bv") << std::endl;
+ }
+
std::vector<Expr>::const_iterator it = d_bbTerms.begin();
std::vector<Expr>::const_iterator end = d_bbTerms.end();
for (; it != end; ++it) {
if (d_usedBB.find(*it) == d_usedBB.end() &&
options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER)
continue;
- os <<"(decl_bblast _ _ _ ";
- printTermBitblasting(*it, os);
- os << "(\\ "<< getBBTermName(*it);
- paren <<"\n))";
+
+ // Is this term has an alias, we inject it through the decl_bblast statement
+ if (hasAlias(*it)) {
+ os << "(decl_bblast_with_alias _ _ _ _ ";
+ printTermBitblasting(*it, os);
+ os << " " << d_aliasToBindDeclaration[d_assignedAliases[*it]] << " ";
+ os << "(\\ "<< getBBTermName(*it);
+ os << "\n";
+ paren <<"))";
+ } else {
+ os << "(decl_bblast _ _ _ ";
+ printTermBitblasting(*it, os);
+ os << "(\\ "<< getBBTermName(*it);
+ os << "\n";
+ paren <<"))";
+ }
}
// bit-blast atoms
ExprToExpr::const_iterator ait = d_bbAtoms.begin();
@@ -589,7 +921,35 @@ void LFSCBitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren)
bool val = ait->first.getConst<bool>();
os << "(iff_symm " << (val ? "true" : "false" ) << ")";
} else {
- printAtomBitblasting(ait->first, os);
+ Assert(ait->first == ait->second[0]);
+
+ bool swap = false;
+ if (ait->first.getKind() == kind::EQUAL) {
+ Expr bitwiseEquivalence = ait->second[1];
+ if ((bitwiseEquivalence.getKind() == kind::CONST_BOOLEAN) && !bitwiseEquivalence.getConst<bool>()) {
+ printAtomBitblastingToFalse(ait->first, os);
+ } else {
+ if (bitwiseEquivalence.getKind() != kind::AND) {
+ // Just one bit
+ if (bitwiseEquivalence.getNumChildren() > 0 && bitwiseEquivalence[0].getKind() == kind::BITVECTOR_BITOF) {
+ swap = (ait->first[1] == bitwiseEquivalence[0][0]);
+ }
+ } else {
+ // Multiple bits
+ if (bitwiseEquivalence[0].getNumChildren() > 0 &&
+ bitwiseEquivalence[0][0].getKind() == kind::BITVECTOR_BITOF) {
+ swap = (ait->first[1] == bitwiseEquivalence[0][0][0]);
+ } else if (bitwiseEquivalence[0].getNumChildren() > 0 &&
+ bitwiseEquivalence[0][1].getKind() == kind::BITVECTOR_BITOF) {
+ swap = (ait->first[0] == bitwiseEquivalence[0][1][0]);
+ }
+ }
+
+ printAtomBitblasting(ait->first, os, swap);
+ }
+ } else {
+ printAtomBitblasting(ait->first, os, swap);
+ }
}
os <<"(\\ " << ProofManager::getPreprocessedAssertionName(ait->second) <<"\n";
@@ -597,34 +957,102 @@ void LFSCBitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren)
}
}
-void LFSCBitVectorProof::printResolutionProof(std::ostream& os,
- std::ostream& paren) {
- // collect the input clauses used
+void LFSCBitVectorProof::calculateAtomsInBitblastingProof() {
+ // Collect the input clauses used
IdToSatClause used_lemmas;
IdToSatClause used_inputs;
- d_resolutionProof->collectClausesUsed(used_inputs,
- used_lemmas);
- Assert (used_lemmas.empty());
+ d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
+ d_cnfProof->collectAtomsForClauses(used_inputs, d_atomsInBitblastingProof);
+ Assert(used_lemmas.empty());
+}
+
+const std::set<Node>* LFSCBitVectorProof::getAtomsInBitblastingProof() {
+ return &d_atomsInBitblastingProof;
+}
+void LFSCBitVectorProof::printResolutionProof(std::ostream& os,
+ std::ostream& paren,
+ ProofLetMap& letMap) {
// print mapping between theory atoms and internal SAT variables
- os << ";; BB atom mapping\n";
+ os << std::endl << ";; BB atom mapping\n" << std::endl;
- NodeSet atoms;
- d_cnfProof->collectAtomsForClauses(used_inputs,atoms);
+ std::set<Node>::iterator atomIt;
+ Debug("pf::bv") << std::endl << "BV Dumping atoms from inputs: " << std::endl << std::endl;
+ for (atomIt = d_atomsInBitblastingProof.begin(); atomIt != d_atomsInBitblastingProof.end(); ++atomIt) {
+ Debug("pf::bv") << "\tAtom: " << *atomIt << std::endl;
+ }
+ Debug("pf::bv") << std::endl;
// first print bit-blasting
printBitblasting(os, paren);
// print CNF conversion proof for bit-blasted facts
- d_cnfProof->printAtomMapping(atoms, os, paren);
- os << ";; Bit-blasting definitional clauses \n";
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
+
+ d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap);
+ os << std::endl << ";; Bit-blasting definitional clauses \n" << std::endl;
for (IdToSatClause::iterator it = used_inputs.begin();
it != used_inputs.end(); ++it) {
d_cnfProof->printCnfProofForClause(it->first, it->second, os, paren);
}
- os << ";; Bit-blasting learned clauses \n";
+ os << std::endl << " ;; Bit-blasting learned clauses \n" << std::endl;
d_resolutionProof->printResolutions(os, paren);
}
+std::string LFSCBitVectorProof::assignAlias(Expr expr) {
+ Assert(d_exprToVariableName.find(expr) == d_exprToVariableName.end());
+
+ std::stringstream ss;
+ ss << "fbv" << d_assignedAliases.size();
+ Debug("pf::bv") << "assignAlias( " << expr << ") = " << ss.str() << std::endl;
+ d_assignedAliases[expr] = ss.str();
+ return ss.str();
+}
+
+bool LFSCBitVectorProof::hasAlias(Expr expr) {
+ return d_assignedAliases.find(expr) != d_assignedAliases.end();
+}
+
+void LFSCBitVectorProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+ Assert (c1.isConst());
+ Assert (c2.isConst());
+ Assert (utils::getSize(c1) == utils::getSize(c2));
+
+ os << "(bv_disequal_constants " << utils::getSize(c1) << " ";
+
+ std::ostringstream paren;
+
+ for (int i = utils::getSize(c1) - 1; i >= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(c1, i) ? "b1" : "b0") << " ";
+ paren << ")";
+ }
+ os << "bvn";
+ os << paren.str();
+
+ os << " ";
+
+ for (int i = utils::getSize(c2) - 1; i >= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(c2, i) ? "b1" : "b0") << " ";
+
+ }
+ os << "bvn";
+ os << paren.str();
+
+ os << ")";
+}
+
+void LFSCBitVectorProof::printRewriteProof(std::ostream& os, const Node &n1, const Node &n2) {
+ ProofLetMap emptyMap;
+ os << "(rr_bv_default ";
+ d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap);
+ os << " ";
+ d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap);
+ os << ")";
+}
+
} /* namespace CVC4 */
diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h
index 4a1f4015d..a52292ec9 100644
--- a/src/proof/bitvector_proof.h
+++ b/src/proof/bitvector_proof.h
@@ -60,6 +60,7 @@ typedef __gnu_cxx::hash_set<Expr, ExprHashFunction> ExprSet;
typedef __gnu_cxx::hash_map<Expr, ClauseId, ExprHashFunction> ExprToClauseId;
typedef __gnu_cxx::hash_map<Expr, unsigned, ExprHashFunction> ExprToId;
typedef __gnu_cxx::hash_map<Expr, Expr, ExprHashFunction> ExprToExpr;
+typedef __gnu_cxx::hash_map<Expr, std::string, ExprHashFunction> ExprToString;
class BitVectorProof : public TheoryProof {
protected:
@@ -108,35 +109,52 @@ public:
virtual void registerTerm(Expr term);
virtual void printTermBitblasting(Expr term, std::ostream& os) = 0;
- virtual void printAtomBitblasting(Expr term, std::ostream& os) = 0;
+ virtual void printAtomBitblasting(Expr term, std::ostream& os, bool swap) = 0;
+ virtual void printAtomBitblastingToFalse(Expr term, std::ostream& os) = 0;
virtual void printBitblasting(std::ostream& os, std::ostream& paren) = 0;
- virtual void printResolutionProof(std::ostream& os, std::ostream& paren) = 0;
-
+ virtual void printResolutionProof(std::ostream& os, std::ostream& paren, ProofLetMap& letMap) = 0;
+ virtual const std::set<Node>* getAtomsInBitblastingProof() = 0;
+ virtual void calculateAtomsInBitblastingProof() = 0;
};
class LFSCBitVectorProof: public BitVectorProof {
void printConstant(Expr term, std::ostream& os);
- void printOperatorNary(Expr term, std::ostream& os, const LetMap& map);
- void printOperatorUnary(Expr term, std::ostream& os, const LetMap& map);
- void printPredicate(Expr term, std::ostream& os, const LetMap& map);
- void printOperatorParametric(Expr term, std::ostream& os, const LetMap& map);
- void printBitOf(Expr term, std::ostream& os, const LetMap& map);
+ void printOperatorNary(Expr term, std::ostream& os, const ProofLetMap& map);
+ void printOperatorUnary(Expr term, std::ostream& os, const ProofLetMap& map);
+ void printPredicate(Expr term, std::ostream& os, const ProofLetMap& map);
+ void printOperatorParametric(Expr term, std::ostream& os, const ProofLetMap& map);
+ void printBitOf(Expr term, std::ostream& os, const ProofLetMap& map);
+
+ ExprToString d_exprToVariableName;
+ ExprToString d_assignedAliases;
+ std::map<std::string, std::string> d_aliasToBindDeclaration;
+ std::string assignAlias(Expr expr);
+ bool hasAlias(Expr expr);
+
+ std::set<Node> d_atomsInBitblastingProof;
+
public:
LFSCBitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
:BitVectorProof(bv, proofEngine)
{}
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map);
virtual void printOwnedSort(Type type, std::ostream& os);
virtual void printTermBitblasting(Expr term, std::ostream& os);
- virtual void printAtomBitblasting(Expr term, std::ostream& os);
- virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ virtual void printAtomBitblasting(Expr term, std::ostream& os, bool swap);
+ virtual void printAtomBitblastingToFalse(Expr term, std::ostream& os);
+ 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 printBitblasting(std::ostream& os, std::ostream& paren);
- virtual void printResolutionProof(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 printRewriteProof(std::ostream& os, const Node &n1, const Node &n2);
};
}/* CVC4 namespace */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 19e9cbac9..b58ade35e 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -19,6 +19,7 @@
#include "proof/clause_id.h"
#include "proof/proof_manager.h"
+#include "proof/proof_utils.h"
#include "proof/theory_proof.h"
#include "prop/cnf_stream.h"
#include "prop/minisat/minisat.h"
@@ -32,7 +33,6 @@ CnfProof::CnfProof(prop::CnfStream* stream,
: d_cnfStream(stream)
, d_clauseToAssertion(ctx)
, d_assertionToProofRule(ctx)
- , d_clauseIdToOwnerTheory(ctx)
, d_currentAssertionStack()
, d_currentDefinitionStack()
, d_clauseToDefinition(ctx)
@@ -103,7 +103,6 @@ void CnfProof::registerConvertedClause(ClauseId clause, bool explanation) {
setClauseAssertion(clause, current_assertion);
setClauseDefinition(clause, current_expr);
- registerExplanationLemma(clause);
}
void CnfProof::setClauseAssertion(ClauseId clause, Node expr) {
@@ -143,16 +142,15 @@ void CnfProof::registerAssertion(Node assertion, ProofRule reason) {
d_assertionToProofRule.insert(assertion, reason);
}
-void CnfProof::registerExplanationLemma(ClauseId clauseId) {
- d_clauseIdToOwnerTheory.insert(clauseId, getExplainerTheory());
+LemmaProofRecipe CnfProof::getProofRecipe(const std::set<Node> &lemma) {
+ Assert(d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end());
+ return d_lemmaToProofRecipe[lemma];
}
-theory::TheoryId CnfProof::getOwnerTheory(ClauseId clause) {
- Assert(d_clauseIdToOwnerTheory.find(clause) != d_clauseIdToOwnerTheory.end());
- return d_clauseIdToOwnerTheory[clause];
+bool CnfProof::haveProofRecipe(const std::set<Node> &lemma) {
+ return d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end();
}
-
void CnfProof::setCnfDependence(Node from, Node to) {
Debug("proof:cnf") << "CnfProof::setCnfDependence "
<< "from " << from << std::endl
@@ -183,12 +181,10 @@ Node CnfProof::getCurrentAssertion() {
return d_currentAssertionStack.back();
}
-void CnfProof::setExplainerTheory(theory::TheoryId theory) {
- d_explainerTheory = theory;
-}
-
-theory::TheoryId CnfProof::getExplainerTheory() {
- return d_explainerTheory;
+void CnfProof::setProofRecipe(LemmaProofRecipe* proofRecipe) {
+ Assert(proofRecipe);
+ Assert(proofRecipe->getNumSteps() > 0);
+ d_lemmaToProofRecipe[proofRecipe->getBaseAssertions()] = *proofRecipe;
}
void CnfProof::pushCurrentDefinition(Node definition) {
@@ -212,22 +208,19 @@ Node CnfProof::getCurrentDefinition() {
return d_currentDefinitionStack.back();
}
-
Node CnfProof::getAtom(prop::SatVariable var) {
prop::SatLiteral lit (var);
Node node = d_cnfStream->getNode(lit);
return node;
}
-
void CnfProof::collectAtoms(const prop::SatClause* clause,
- NodeSet& atoms) {
+ std::set<Node>& atoms) {
for (unsigned i = 0; i < clause->size(); ++i) {
prop::SatLiteral lit = clause->operator[](i);
prop::SatVariable var = lit.getSatVariable();
TNode atom = getAtom(var);
if (atoms.find(atom) == atoms.end()) {
- Assert (atoms.find(atom) == atoms.end());
atoms.insert(atom);
}
}
@@ -237,14 +230,75 @@ prop::SatLiteral CnfProof::getLiteral(TNode atom) {
return d_cnfStream->getLiteral(atom);
}
+bool CnfProof::hasLiteral(TNode atom) {
+ return d_cnfStream->hasLiteral(atom);
+}
+
+void CnfProof::ensureLiteral(TNode atom, bool noPreregistration) {
+ d_cnfStream->ensureLiteral(atom, noPreregistration);
+}
+
void CnfProof::collectAtomsForClauses(const IdToSatClause& clauses,
- NodeSet& atom_map) {
+ std::set<Node>& atoms) {
IdToSatClause::const_iterator it = clauses.begin();
for (; it != clauses.end(); ++it) {
const prop::SatClause* clause = it->second;
- collectAtoms(clause, atom_map);
+ collectAtoms(clause, atoms);
}
+}
+
+void CnfProof::collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses,
+ std::set<Node>& atoms,
+ NodePairSet& rewrites) {
+ IdToSatClause::const_iterator it = lemmaClauses.begin();
+ for (; it != lemmaClauses.end(); ++it) {
+ const prop::SatClause* clause = it->second;
+
+ // TODO: just calculate the map from ID to recipe once,
+ // instead of redoing this over and over again
+ std::vector<Expr> clause_expr;
+ std::set<Node> clause_expr_nodes;
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Node node = getAtom(lit.getSatVariable());
+ Expr atom = node.toExpr();
+ if (atom.isConst()) {
+ Assert (atom == utils::mkTrue());
+ continue;
+ }
+ clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node);
+ }
+
+ LemmaProofRecipe recipe = getProofRecipe(clause_expr_nodes);
+
+ for (unsigned i = 0; i < recipe.getNumSteps(); ++i) {
+ const LemmaProofRecipe::ProofStep* proofStep = recipe.getStep(i);
+ Node atom = proofStep->getLiteral();
+
+ if (atom == Node()) {
+ // The last proof step always has the empty node as its target...
+ continue;
+ }
+
+ if (atom.getKind() == kind::NOT) {
+ atom = atom[0];
+ }
+
+ atoms.insert(atom);
+ }
+
+ LemmaProofRecipe::RewriteIterator rewriteIt;
+ for (rewriteIt = recipe.rewriteBegin(); rewriteIt != recipe.rewriteEnd(); ++rewriteIt) {
+ rewrites.insert(NodePair(rewriteIt->first, rewriteIt->second));
+ // The unrewritten terms also need to have literals, so insert them into atoms
+ Node rewritten = rewriteIt->first;
+ if (rewritten.getKind() == kind::NOT) {
+ rewritten = rewritten[0];
+ }
+ atoms.insert(rewritten);
+ }
+ }
}
void CnfProof::collectAssertionsForClauses(const IdToSatClause& clauses,
@@ -263,13 +317,13 @@ void CnfProof::collectAssertionsForClauses(const IdToSatClause& clauses,
}
}
-void LFSCCnfProof::printAtomMapping(const NodeSet& atoms,
+void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms,
std::ostream& os,
std::ostream& paren) {
- NodeSet::const_iterator it = atoms.begin();
- NodeSet::const_iterator end = atoms.end();
+ std::set<Node>::const_iterator it = atoms.begin();
+ std::set<Node>::const_iterator end = atoms.end();
- for (;it != end; ++it) {
+ for (;it != end; ++it) {
os << "(decl_atom ";
Node atom = *it;
prop::SatVariable var = getLiteral(atom).getSatVariable();
@@ -277,8 +331,30 @@ void LFSCCnfProof::printAtomMapping(const NodeSet& atoms,
LFSCTheoryProofEngine* pe = (LFSCTheoryProofEngine*)ProofManager::currentPM()->getTheoryProofEngine();
pe->printLetTerm(atom.toExpr(), os);
- os << " (\\ " << ProofManager::getVarName(var, d_name)
- << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
+ os << " (\\ " << ProofManager::getVarName(var, d_name);
+ os << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
+ paren << ")))";
+ }
+}
+
+void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms,
+ std::ostream& os,
+ std::ostream& paren,
+ ProofLetMap &letMap) {
+ std::set<Node>::const_iterator it = atoms.begin();
+ std::set<Node>::const_iterator end = atoms.end();
+
+ for (;it != end; ++it) {
+ os << "(decl_atom ";
+ Node atom = *it;
+ prop::SatVariable var = getLiteral(atom).getSatVariable();
+ //FIXME hideous
+ LFSCTheoryProofEngine* pe = (LFSCTheoryProofEngine*)ProofManager::currentPM()->getTheoryProofEngine();
+ // pe->printLetTerm(atom.toExpr(), os);
+ pe->printBoundTerm(atom.toExpr(), os, letMap);
+
+ os << " (\\ " << ProofManager::getVarName(var, d_name);
+ os << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
paren << ")))";
}
}
@@ -304,6 +380,9 @@ void LFSCCnfProof::printCnfProofForClause(ClauseId id,
const prop::SatClause* clause,
std::ostream& os,
std::ostream& paren) {
+ Debug("cnf-pf") << std::endl << std::endl << "LFSCCnfProof::printCnfProofForClause( " << id << " ) starting "
+ << std::endl;
+
os << "(satlem _ _ ";
std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
@@ -336,6 +415,10 @@ void LFSCCnfProof::printCnfProofForClause(ClauseId id,
// and prints the proof of the top-level formula
bool is_input = printProofTopLevel(base_assertion, os_base);
+ if (is_input) {
+ Debug("cnf-pf") << std::endl << "; base assertion is input. proof: " << os_base.str() << std::endl;
+ }
+
//get base assertion with polarity
bool base_pol = base_assertion.getKind()!=kind::NOT;
base_assertion = base_assertion.getKind()==kind::NOT ? base_assertion[0] : base_assertion;
@@ -564,6 +647,7 @@ void LFSCCnfProof::printCnfProofForClause(ClauseId id,
if( !pols[0] || num_nots_1==1 ){
os_base_n << "(not_not_intro _ " << ProofManager::getLitName(lit1, d_name) << ") ";
}else{
+ Trace("cnf-pf-debug") << "CALLING getlitname" << std::endl;
os_base_n << ProofManager::getLitName(lit1, d_name) << " ";
}
Assert( elimNum!=0 );
@@ -662,6 +746,7 @@ void LFSCCnfProof::printCnfProofForClause(ClauseId id,
os << ")" << clause_paren.str()
<< " (\\ " << ProofManager::getInputClauseName(id, d_name) << "\n";
+
paren << "))";
}
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index a21cb1c0e..788526b80 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -27,6 +27,7 @@
#include "context/cdhashmap.h"
#include "proof/clause_id.h"
+#include "proof/lemma_proof.h"
#include "proof/sat_proof.h"
#include "util/proof.h"
@@ -43,7 +44,9 @@ typedef __gnu_cxx::hash_set<ClauseId> ClauseIdSet;
typedef context::CDHashMap<ClauseId, Node> ClauseIdToNode;
typedef context::CDHashMap<Node, ProofRule, NodeHashFunction> NodeToProofRule;
-typedef context::CDHashMap<ClauseId, theory::TheoryId> ClauseIdToTheory;
+typedef std::map<std::set<Node>, LemmaProofRecipe> LemmaToRecipe;
+typedef std::pair<Node, Node> NodePair;
+typedef std::set<NodePair> NodePairSet;
class CnfProof {
protected:
@@ -55,11 +58,8 @@ protected:
/** Map from assertion to reason for adding assertion **/
NodeToProofRule d_assertionToProofRule;
- /** Map from assertion to the theory that added this assertion **/
- ClauseIdToTheory d_clauseIdToOwnerTheory;
-
- /** The last theory to explain a lemma **/
- theory::TheoryId d_explainerTheory;
+ /** Map from lemma to the recipe for proving it **/
+ LemmaToRecipe d_lemmaToProofRecipe;
/** Top of stack is assertion currently being converted to CNF **/
std::vector<Node> d_currentAssertionStack;
@@ -91,10 +91,16 @@ public:
Node getAtom(prop::SatVariable var);
prop::SatLiteral getLiteral(TNode node);
+ bool hasLiteral(TNode node);
+ void ensureLiteral(TNode node, bool noPreregistration = false);
+
void collectAtoms(const prop::SatClause* clause,
- NodeSet& atoms);
+ std::set<Node>& atoms);
void collectAtomsForClauses(const IdToSatClause& clauses,
- NodeSet& atoms);
+ std::set<Node>& atoms);
+ void collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses,
+ std::set<Node>& atoms,
+ NodePairSet& rewrites);
void collectAssertionsForClauses(const IdToSatClause& clauses,
NodeSet& assertions);
@@ -121,11 +127,9 @@ public:
void popCurrentDefinition();
Node getCurrentDefinition();
- void setExplainerTheory(theory::TheoryId theory);
- theory::TheoryId getExplainerTheory();
- theory::TheoryId getOwnerTheory(ClauseId clause);
-
- void registerExplanationLemma(ClauseId clauseId);
+ void setProofRecipe(LemmaProofRecipe* proofRecipe);
+ LemmaProofRecipe getProofRecipe(const std::set<Node> &lemma);
+ bool haveProofRecipe(const std::set<Node> &lemma);
// accessors for the leaf assertions that are being converted to CNF
bool isAssertion(Node node);
@@ -134,9 +138,13 @@ public:
Node getAssertionForClause(ClauseId clause);
/** Virtual methods for printing things **/
- virtual void printAtomMapping(const NodeSet& atoms,
+ virtual void printAtomMapping(const std::set<Node>& atoms,
std::ostream& os,
std::ostream& paren) = 0;
+ virtual void printAtomMapping(const std::set<Node>& atoms,
+ std::ostream& os,
+ std::ostream& paren,
+ ProofLetMap &letMap) = 0;
virtual void printClause(const prop::SatClause& clause,
std::ostream& os,
@@ -161,10 +169,15 @@ public:
{}
~LFSCCnfProof() {}
- void printAtomMapping(const NodeSet& atoms,
+ void printAtomMapping(const std::set<Node>& atoms,
std::ostream& os,
std::ostream& paren);
+ void printAtomMapping(const std::set<Node>& atoms,
+ std::ostream& os,
+ std::ostream& paren,
+ ProofLetMap &letMap);
+
void printClause(const prop::SatClause& clause,
std::ostream& os,
std::ostream& paren);
diff --git a/src/proof/lemma_proof.cpp b/src/proof/lemma_proof.cpp
new file mode 100644
index 000000000..a12a516cf
--- /dev/null
+++ b/src/proof/lemma_proof.cpp
@@ -0,0 +1,193 @@
+/********************* */
+/*! \file lemma_proof.h
+** \verbatim
+**
+** \brief A class for recoding the steps required in order to prove a theory lemma.
+**
+** A class for recoding the steps required in order to prove a theory lemma.
+**
+**/
+
+#include "proof/lemma_proof.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+
+LemmaProofRecipe::ProofStep::ProofStep(theory::TheoryId theory, Node literalToProve) :
+ d_theory(theory), d_literalToProve(literalToProve) {
+}
+
+theory::TheoryId LemmaProofRecipe::ProofStep::getTheory() const {
+ return d_theory;
+}
+
+Node LemmaProofRecipe::ProofStep::getLiteral() const {
+ return d_literalToProve;
+}
+
+void LemmaProofRecipe::ProofStep::addAssertion(const Node& assertion) {
+ d_assertions.insert(assertion);
+}
+
+std::set<Node> LemmaProofRecipe::ProofStep::getAssertions() const {
+ return d_assertions;
+}
+
+void LemmaProofRecipe::addStep(ProofStep& proofStep) {
+ std::list<ProofStep>::iterator existingFirstStep = d_proofSteps.begin();
+ d_proofSteps.push_front(proofStep);
+}
+
+std::set<Node> LemmaProofRecipe::getMissingAssertionsForStep(unsigned index) const {
+ Assert(index < d_proofSteps.size());
+
+ std::set<Node> existingAssertions = getBaseAssertions();
+
+ std::list<ProofStep>::const_iterator step = d_proofSteps.begin();
+ while (index != 0) {
+ existingAssertions.insert(step->getLiteral().negate());
+ ++step;
+ --index;
+ }
+
+ std::set<Node> neededAssertions = step->getAssertions();
+
+ std::set<Node> result;
+ std::set_difference(neededAssertions.begin(), neededAssertions.end(),
+ existingAssertions.begin(), existingAssertions.end(),
+ std::inserter(result, result.begin()));
+ return result;
+}
+
+void LemmaProofRecipe::dump(const char *tag) const {
+
+ if (d_proofSteps.size() == 1) {
+ Debug(tag) << std::endl << "[Simple lemma]" << std::endl << std::endl;
+ }
+
+ unsigned count = 1;
+ Debug(tag) << "Base assertions:" << std::endl;
+ for (std::set<Node>::iterator baseIt = d_baseAssertions.begin();
+ baseIt != d_baseAssertions.end();
+ ++baseIt) {
+ Debug(tag) << "\t#" << count << ": " << "\t" << *baseIt << std::endl;
+ ++count;
+ }
+
+ Debug(tag) << std::endl << std::endl << "Proof steps:" << std::endl;
+
+ count = 1;
+ for (std::list<ProofStep>::const_iterator step = d_proofSteps.begin(); step != d_proofSteps.end(); ++step) {
+ Debug(tag) << "\tStep #" << count << ": " << "\t[" << step->getTheory() << "] ";
+ if (step->getLiteral() == Node()) {
+ Debug(tag) << "Contradiction";
+ } else {
+ Debug(tag) << step->getLiteral();
+ }
+
+ Debug(tag) << std::endl;
+
+ std::set<Node> missingAssertions = getMissingAssertionsForStep(count - 1);
+ for (std::set<Node>::const_iterator it = missingAssertions.begin(); it != missingAssertions.end(); ++it) {
+ Debug(tag) << "\t\t\tMissing assertion for step: " << *it << std::endl;
+ }
+
+ Debug(tag) << std::endl;
+ ++count;
+ }
+
+ if (!d_assertionToExplanation.empty()) {
+ Debug(tag) << std::endl << "Rewrites used:" << std::endl;
+ count = 1;
+ for (std::map<Node, Node>::const_iterator rewrite = d_assertionToExplanation.begin();
+ rewrite != d_assertionToExplanation.end();
+ ++rewrite) {
+ Debug(tag) << "\tRewrite #" << count << ":" << std::endl
+ << "\t\t" << rewrite->first
+ << std::endl << "\t\trewritten into" << std::endl
+ << "\t\t" << rewrite->second
+ << std::endl << std::endl;
+ ++count;
+ }
+ }
+}
+
+void LemmaProofRecipe::addBaseAssertion(Node baseAssertion) {
+ d_baseAssertions.insert(baseAssertion);
+}
+
+std::set<Node> LemmaProofRecipe::getBaseAssertions() const {
+ return d_baseAssertions;
+}
+
+theory::TheoryId LemmaProofRecipe::getTheory() const {
+ Assert(d_proofSteps.size() > 0);
+ return d_proofSteps.back().getTheory();
+}
+
+void LemmaProofRecipe::addRewriteRule(Node assertion, Node explanation) {
+ if (d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end()) {
+ Assert(d_assertionToExplanation[assertion] == explanation);
+ }
+
+ d_assertionToExplanation[assertion] = explanation;
+}
+
+bool LemmaProofRecipe::wasRewritten(Node assertion) const {
+ return d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end();
+}
+
+Node LemmaProofRecipe::getExplanation(Node assertion) const {
+ Assert(d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end());
+ return d_assertionToExplanation.find(assertion)->second;
+}
+
+LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteBegin() const {
+ return d_assertionToExplanation.begin();
+}
+
+LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteEnd() const {
+ return d_assertionToExplanation.end();
+}
+
+bool LemmaProofRecipe::operator<(const LemmaProofRecipe& other) const {
+ return d_baseAssertions < other.d_baseAssertions;
+ }
+
+bool LemmaProofRecipe::simpleLemma() const {
+ return d_proofSteps.size() == 1;
+}
+
+bool LemmaProofRecipe::compositeLemma() const {
+ return !simpleLemma();
+}
+
+const LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) const {
+ Assert(index < d_proofSteps.size());
+
+ std::list<ProofStep>::const_iterator it = d_proofSteps.begin();
+ while (index != 0) {
+ ++it;
+ --index;
+ }
+
+ return &(*it);
+}
+
+LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) {
+ Assert(index < d_proofSteps.size());
+
+ std::list<ProofStep>::iterator it = d_proofSteps.begin();
+ while (index != 0) {
+ ++it;
+ --index;
+ }
+
+ return &(*it);
+}
+
+unsigned LemmaProofRecipe::getNumSteps() const {
+ return d_proofSteps.size();
+}
+
+} /* namespace CVC4 */
diff --git a/src/proof/lemma_proof.h b/src/proof/lemma_proof.h
new file mode 100644
index 000000000..e96ff5337
--- /dev/null
+++ b/src/proof/lemma_proof.h
@@ -0,0 +1,79 @@
+/********************* */
+/*! \file lemma_proof.h
+** \verbatim
+**
+** \brief A class for recoding the steps required in order to prove a theory lemma.
+**
+** A class for recoding the steps required in order to prove a theory lemma.
+**
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__LEMMA_PROOF_H
+#define __CVC4__LEMMA_PROOF_H
+
+#include "expr/expr.h"
+#include "proof/clause_id.h"
+#include "prop/sat_solver_types.h"
+#include "util/proof.h"
+#include "expr/node.h"
+
+namespace CVC4 {
+
+class LemmaProofRecipe {
+public:
+ class ProofStep {
+ public:
+ ProofStep(theory::TheoryId theory, Node literalToProve);
+ theory::TheoryId getTheory() const;
+ Node getLiteral() const;
+ void addAssertion(const Node& assertion);
+ std::set<Node> getAssertions() const;
+
+ private:
+ theory::TheoryId d_theory;
+ Node d_literalToProve;
+ std::set<Node> d_assertions;
+ };
+
+ //* The lemma assertions and owner */
+ void addBaseAssertion(Node baseAssertion);
+ std::set<Node> getBaseAssertions() const;
+ theory::TheoryId getTheory() const;
+
+ //* Rewrite rules */
+ typedef std::map<Node, Node>::const_iterator RewriteIterator;
+ RewriteIterator rewriteBegin() const;
+ RewriteIterator rewriteEnd() const;
+
+ void addRewriteRule(Node assertion, Node explanation);
+ bool wasRewritten(Node assertion) const;
+ Node getExplanation(Node assertion) const;
+
+ //* Proof Steps */
+ void addStep(ProofStep& proofStep);
+ const ProofStep* getStep(unsigned index) const;
+ ProofStep* getStep(unsigned index);
+ unsigned getNumSteps() const;
+ std::set<Node> getMissingAssertionsForStep(unsigned index) const;
+ bool simpleLemma() const;
+ bool compositeLemma() const;
+
+ void dump(const char *tag) const;
+ bool operator<(const LemmaProofRecipe& other) const;
+
+private:
+ //* The list of assertions for this lemma */
+ std::set<Node> d_baseAssertions;
+
+ //* The various steps needed to derive the empty clause */
+ std::list<ProofStep> d_proofSteps;
+
+ //* A map from assertions to their rewritten explanations (toAssert --> toExplain) */
+ std::map<Node, Node> d_assertionToExplanation;
+};
+
+} /* CVC4 namespace */
+
+#endif /* __CVC4__LEMMA_PROOF_H */
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index a3689d746..d155630e5 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -20,6 +20,7 @@
#include "base/cvc4_assert.h"
#include "context/context.h"
#include "options/bv_options.h"
+#include "options/proof_options.h"
#include "proof/bitvector_proof.h"
#include "proof/clause_id.h"
#include "proof/cnf_proof.h"
@@ -61,10 +62,10 @@ ProofManager::ProofManager(ProofFormat format):
}
ProofManager::~ProofManager() {
- delete d_satProof;
- delete d_cnfProof;
- delete d_theoryProof;
- delete d_fullProof;
+ if (d_satProof) delete d_satProof;
+ if (d_cnfProof) delete d_cnfProof;
+ if (d_theoryProof) delete d_theoryProof;
+ if (d_fullProof) delete d_fullProof;
}
ProofManager* ProofManager::currentPM() {
@@ -95,7 +96,6 @@ CnfProof* ProofManager::getCnfProof() {
}
TheoryProofEngine* ProofManager::getTheoryProofEngine() {
- Assert (options::proof());
Assert (currentPM()->d_theoryProof != NULL);
return currentPM()->d_theoryProof;
}
@@ -200,7 +200,6 @@ std::string ProofManager::getLitName(prop::SatLiteral lit,
return append(prefix+".l", lit.toInt());
}
-
std::string ProofManager::getPreprocessedAssertionName(Node node,
const std::string& prefix) {
node = node.getKind() == kind::BITVECTOR_EAGER_ATOM ? node[0] : node;
@@ -217,9 +216,15 @@ std::string ProofManager::getAtomName(TNode atom,
Assert(!lit.isNegated());
return getAtomName(lit.getSatVariable(), prefix);
}
+
std::string ProofManager::getLitName(TNode lit,
const std::string& prefix) {
- return getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix);
+ std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix);
+ if (currentPM()->d_rewriteFilters.find(litName) != currentPM()->d_rewriteFilters.end()) {
+ return currentPM()->d_rewriteFilters[litName];
+ }
+
+ return litName;
}
std::string ProofManager::sanitize(TNode node) {
@@ -330,7 +335,14 @@ LFSCProof::LFSCProof(SmtEngine* smtEngine,
, d_smtEngine(smtEngine)
{}
+void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) {
+ Unreachable();
+}
+
void LFSCProof::toStream(std::ostream& out) {
+
+ Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER);
+
d_satProof->constructProof();
// collecting leaf clauses in resolution proof
@@ -384,8 +396,37 @@ void LFSCProof::toStream(std::ostream& out) {
for (it3 = used_assertions.begin(); it3 != used_assertions.end(); ++it3)
Debug("pf::pm") << "\t assertion = " << *it3 << std::endl;
- NodeSet atoms;
+ std::set<Node> atoms;
+ NodePairSet rewrites;
// collects the atoms in the clauses
+ d_cnfProof->collectAtomsAndRewritesForLemmas(used_lemmas, atoms, rewrites);
+
+ if (!rewrites.empty()) {
+ Debug("pf::pm") << std::endl << "Rewrites used in lemmas: " << std::endl;
+ NodePairSet::const_iterator rewriteIt;
+ for (rewriteIt = rewrites.begin(); rewriteIt != rewrites.end(); ++rewriteIt) {
+ Debug("pf::pm") << "\t" << rewriteIt->first << " --> " << rewriteIt->second << std::endl;
+ }
+ Debug("pf::pm") << std::endl << "Rewrite printing done" << std::endl;
+ } else {
+ Debug("pf::pm") << "No rewrites in lemmas found" << std::endl;
+ }
+
+ // The derived/unrewritten atoms may not have CNF literals required later on.
+ // If they don't, add them.
+ std::set<Node>::const_iterator it;
+ for (it = atoms.begin(); it != atoms.end(); ++it) {
+ Debug("pf::pm") << "Ensure literal for atom: " << *it << std::endl;
+ if (!d_cnfProof->hasLiteral(*it)) {
+ // For arithmetic: these literals are not normalized, causing an error in Arith.
+ if (theory::Theory::theoryOf(*it) == theory::THEORY_ARITH) {
+ d_cnfProof->ensureLiteral(*it, true); // This disables preregistration with the theory solver.
+ } else {
+ d_cnfProof->ensureLiteral(*it); // Normal method, with theory solver preregisteration.
+ }
+ }
+ }
+
d_cnfProof->collectAtomsForClauses(used_inputs, atoms);
d_cnfProof->collectAtomsForClauses(used_lemmas, atoms);
@@ -393,38 +434,23 @@ void LFSCProof::toStream(std::ostream& out) {
for (NodeSet::const_iterator it = used_assertions.begin();
it != used_assertions.end(); ++it) {
utils::collectAtoms(*it, atoms);
+ // utils::collectAtoms(*it, newAtoms);
}
- NodeSet::iterator atomIt;
- Debug("pf::pm") << std::endl << "Dumping atoms from lemmas, inputs and assertions: " << std::endl << std::endl;
+ std::set<Node>::iterator atomIt;
+ Debug("pf::pm") << std::endl << "Dumping atoms from lemmas, inputs and assertions: "
+ << std::endl << std::endl;
for (atomIt = atoms.begin(); atomIt != atoms.end(); ++atomIt) {
Debug("pf::pm") << "\tAtom: " << *atomIt << std::endl;
-
- if (Debug.isOn("proof:pm")) {
- // std::cout << NodeManager::currentNM();
- Debug("proof:pm") << "LFSCProof::Used assertions: "<< std::endl;
- for(NodeSet::const_iterator it = used_assertions.begin(); it != used_assertions.end(); ++it) {
- Debug("proof:pm") << " " << *it << std::endl;
- }
-
- Debug("proof:pm") << "LFSCProof::Used atoms: "<< std::endl;
- for(NodeSet::const_iterator it = atoms.begin(); it != atoms.end(); ++it) {
- Debug("proof:pm") << " " << *it << std::endl;
- }
- }
}
-
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
out << "(check\n";
out << " ;; Declarations\n";
// declare the theory atoms
- NodeSet::const_iterator it = atoms.begin();
- NodeSet::const_iterator end = atoms.end();
-
Debug("pf::pm") << "LFSCProof::toStream: registering terms:" << std::endl;
- for(; it != end; ++it) {
+ for(it = atoms.begin(); it != atoms.end(); ++it) {
Debug("pf::pm") << "\tTerm: " << (*it).toExpr() << std::endl;
d_theoryProof->registerTerm((*it).toExpr());
}
@@ -444,15 +470,31 @@ void LFSCProof::toStream(std::ostream& out) {
out << "(: (holds cln)\n\n";
// Have the theory proofs print deferred declarations, e.g. for skolem variables.
- out << " ;; Printing deferred declarations \n";
+ out << " ;; Printing deferred declarations \n\n";
d_theoryProof->printDeferredDeclarations(out, paren);
+ 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);
+
+ out << " ;; Rewrites for Lemmas \n";
+ d_theoryProof->printLemmaRewrites(rewrites, out, paren);
+
// print trust that input assertions are their preprocessed form
- printPreprocessedAssertions(used_assertions, out, paren);
+ printPreprocessedAssertions(used_assertions, out, paren, globalLetMap);
// print mapping between theory atoms and internal SAT variables
out << ";; Printing mapping from preprocessed assertions into atoms \n";
- d_cnfProof->printAtomMapping(atoms, out, paren);
+ d_cnfProof->printAtomMapping(atoms, out, paren, globalLetMap);
Debug("pf::pm") << std::endl << "Printing cnf proof for clauses" << std::endl;
@@ -464,12 +506,8 @@ void LFSCProof::toStream(std::ostream& out) {
Debug("pf::pm") << std::endl << "Printing cnf proof for clauses DONE" << std::endl;
- // FIXME: for now assume all theory lemmas are in CNF form so
- // distinguish between them and inputs
- // print theory lemmas for resolution proof
-
Debug("pf::pm") << "Proof manager: printing theory lemmas" << std::endl;
- d_theoryProof->printTheoryLemmas(used_lemmas, out, paren);
+ d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap);
Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl;
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) {
@@ -491,22 +529,24 @@ void LFSCProof::toStream(std::ostream& out) {
void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
std::ostream& os,
- std::ostream& paren) {
+ std::ostream& paren,
+ ProofLetMap& globalLetMap) {
os << "\n ;; In the preprocessor we trust \n";
NodeSet::const_iterator it = assertions.begin();
NodeSet::const_iterator end = assertions.end();
+ Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl;
+
for (; it != end; ++it) {
os << "(th_let_pf _ ";
//TODO
os << "(trust_f ";
- ProofManager::currentPM()->getTheoryProofEngine()->printLetTerm((*it).toExpr(), os);
+ ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it).toExpr(), os, globalLetMap);
os << ") ";
os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
paren << "))";
-
}
os << "\n";
@@ -568,6 +608,14 @@ void ProofManager::markPrinted(const Type& type) {
d_printedTypes.insert(type);
}
+void ProofManager::addRewriteFilter(const std::string &original, const std::string &substitute) {
+ d_rewriteFilters[original] = substitute;
+}
+
+void ProofManager::clearRewriteFilters() {
+ d_rewriteFilters.clear();
+}
+
std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k) {
switch(k) {
case RULE_GIVEN:
@@ -607,5 +655,88 @@ std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k) {
return out;
}
+void ProofManager::registerRewrite(unsigned ruleId, Node original, Node result){
+ Assert (currentPM()->d_theoryProof != NULL);
+ currentPM()->d_rewriteLog.push_back(RewriteLogEntry(ruleId, original, result));
+}
+
+void ProofManager::clearRewriteLog() {
+ Assert (currentPM()->d_theoryProof != NULL);
+ currentPM()->d_rewriteLog.clear();
+}
+
+std::vector<RewriteLogEntry> ProofManager::getRewriteLog() {
+ return currentPM()->d_rewriteLog;
+}
+
+void ProofManager::dumpRewriteLog() const {
+ Debug("pf::rr") << "Dumpign rewrite log:" << std::endl;
+
+ for (unsigned i = 0; i < d_rewriteLog.size(); ++i) {
+ Debug("pf::rr") << "\tRule " << d_rewriteLog[i].getRuleId()
+ << ": "
+ << d_rewriteLog[i].getOriginal()
+ << " --> "
+ << d_rewriteLog[i].getResult() << std::endl;
+ }
+}
+
+void bind(Expr term, ProofLetMap& map, Bindings& letOrder) {
+ ProofLetMap::iterator it = map.find(term);
+ if (it != map.end())
+ return;
+
+ for (unsigned i = 0; i < term.getNumChildren(); ++i)
+ bind(term[i], map, letOrder);
+
+ // Special case: chain operators. If we have and(a,b,c), it will be prineted as and(a,and(b,c)).
+ // The subterm and(b,c) may repeat elsewhere, so we need to bind it, too.
+ Kind k = term.getKind();
+ if (((k == kind::OR) || (k == kind::AND)) && term.getNumChildren() > 2) {
+ Node currentExpression = term[term.getNumChildren() - 1];
+ for (int i = term.getNumChildren() - 2; i >= 0; --i) {
+ NodeBuilder<> builder(k);
+ builder << term[i];
+ builder << currentExpression.toExpr();
+ currentExpression = builder;
+ bind(currentExpression.toExpr(), map, letOrder);
+ }
+ } else {
+ unsigned newId = ProofLetCount::newId();
+ ProofLetCount letCount(newId);
+ map[term] = letCount;
+ letOrder.push_back(LetOrderElement(term, newId));
+ }
+}
+
+void ProofManager::printGlobalLetMap(std::set<Node>& atoms,
+ ProofLetMap& letMap,
+ std::ostream& out,
+ std::ostringstream& paren) {
+ Bindings letOrder;
+ std::set<Node>::const_iterator atom;
+ for (atom = atoms.begin(); atom != atoms.end(); ++atom) {
+ bind(atom->toExpr(), letMap, letOrder);
+ }
+
+ // TODO: give each theory a chance to add atoms. For now, just query BV directly...
+ const std::set<Node>* additionalAtoms = ProofManager::getBitVectorProof()->getAtomsInBitblastingProof();
+ for (atom = additionalAtoms->begin(); atom != additionalAtoms->end(); ++atom) {
+ bind(atom->toExpr(), letMap, letOrder);
+ }
+
+ for (unsigned i = 0; i < letOrder.size(); ++i) {
+ Expr currentExpr = letOrder[i].expr;
+ unsigned letId = letOrder[i].id;
+ ProofLetMap::iterator it = letMap.find(currentExpr);
+ Assert(it != letMap.end());
+ out << "\n(@ let" << letId << " ";
+ d_theoryProof->printBoundTerm(currentExpr, out, letMap);
+ paren << ")";
+ it->second.increment();
+ }
+
+ out << std::endl << std::endl;
+}
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index c74aac237..14793f380 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -22,6 +22,7 @@
#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"
@@ -34,6 +35,8 @@
namespace CVC4 {
+class SmtGlobals;
+
// forward declarations
namespace Minisat {
class Solver;
@@ -113,6 +116,30 @@ enum ProofRule {
RULE_ARRAYS_ROW, /* arrays, read-over-write */
};/* enum ProofRules */
+class RewriteLogEntry {
+public:
+ RewriteLogEntry(unsigned ruleId, Node original, Node result)
+ : d_ruleId(ruleId), d_original(original), d_result(result) {
+ }
+
+ unsigned getRuleId() const {
+ return d_ruleId;
+ }
+
+ Node getOriginal() const {
+ return d_original;
+ }
+
+ Node getResult() const {
+ return d_result;
+ }
+
+private:
+ unsigned d_ruleId;
+ Node d_original;
+ Node d_result;
+};
+
class ProofManager {
CoreSatProof* d_satProof;
CnfProof* d_cnfProof;
@@ -136,6 +163,10 @@ class ProofManager {
std::set<Type> d_printedTypes;
+ std::map<std::string, std::string> d_rewriteFilters;
+
+ std::vector<RewriteLogEntry> d_rewriteLog;
+
protected:
LogicInfo d_logic;
@@ -224,6 +255,19 @@ public:
void markPrinted(const Type& type);
bool wasPrinted(const Type& type) const;
+ void addRewriteFilter(const std::string &original, const std::string &substitute);
+ void clearRewriteFilters();
+
+ static void registerRewrite(unsigned ruleId, Node original, Node result);
+ static void clearRewriteLog();
+
+ std::vector<RewriteLogEntry> getRewriteLog();
+ void dumpRewriteLog() const;
+
+ void printGlobalLetMap(std::set<Node>& atoms,
+ ProofLetMap& letMap,
+ std::ostream& out,
+ std::ostringstream& paren);
};/* class ProofManager */
class LFSCProof : public Proof {
@@ -235,13 +279,15 @@ class LFSCProof : public Proof {
// FIXME: hack until we get preprocessing
void printPreprocessedAssertions(const NodeSet& assertions,
std::ostream& os,
- std::ostream& paren);
+ std::ostream& paren,
+ ProofLetMap& globalLetMap);
public:
LFSCProof(SmtEngine* smtEngine,
LFSCCoreSatProof* sat,
LFSCCnfProof* cnf,
LFSCTheoryProofEngine* theory);
virtual void toStream(std::ostream& out);
+ virtual void toStream(std::ostream& out, const ProofLetMap& map);
virtual ~LFSCProof() {}
};/* class LFSCProof */
diff --git a/src/proof/proof_output_channel.cpp b/src/proof/proof_output_channel.cpp
new file mode 100644
index 000000000..6d729db1f
--- /dev/null
+++ b/src/proof/proof_output_channel.cpp
@@ -0,0 +1,82 @@
+/********************* */
+/*! \file proof_output_channel.cpp
+** \verbatim
+** \brief [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "base/cvc4_assert.h"
+#include "proof_output_channel.h"
+#include "theory/term_registration_visitor.h"
+#include "theory/valuation.h"
+
+namespace CVC4 {
+
+ProofOutputChannel::ProofOutputChannel() : d_conflict(), d_proof(NULL) {}
+
+void ProofOutputChannel::conflict(TNode n, Proof* pf) throw() {
+ Trace("pf::tp") << "ProofOutputChannel: CONFLICT: " << n << std::endl;
+ Assert(d_conflict.isNull());
+ Assert(!n.isNull());
+ d_conflict = n;
+ Assert(pf != NULL);
+ d_proof = pf;
+}
+
+bool ProofOutputChannel::propagate(TNode x) throw() {
+ Trace("pf::tp") << "ProofOutputChannel: got a propagation: " << x << std::endl;
+ d_propagations.insert(x);
+ return true;
+}
+
+theory::LemmaStatus ProofOutputChannel::lemma(TNode n, ProofRule rule, bool, bool, bool) throw() {
+ Trace("pf::tp") << "ProofOutputChannel: new lemma: " << n << std::endl;
+ d_lemma = n;
+ return theory::LemmaStatus(TNode::null(), 0);
+}
+
+theory::LemmaStatus ProofOutputChannel::splitLemma(TNode, bool) throw() {
+ AlwaysAssert(false);
+ return theory::LemmaStatus(TNode::null(), 0);
+}
+
+void ProofOutputChannel::requirePhase(TNode n, bool b) throw() {
+ Debug("pf::tp") << "ProofOutputChannel::requirePhase called" << std::endl;
+ Trace("pf::tp") << "requirePhase " << n << " " << b << std::endl;
+}
+
+bool ProofOutputChannel::flipDecision() throw() {
+ Debug("pf::tp") << "ProofOutputChannel::flipDecision called" << std::endl;
+ AlwaysAssert(false);
+ return false;
+}
+
+void ProofOutputChannel::setIncomplete() throw() {
+ Debug("pf::tp") << "ProofOutputChannel::setIncomplete called" << std::endl;
+ AlwaysAssert(false);
+}
+
+
+MyPreRegisterVisitor::MyPreRegisterVisitor(theory::Theory* theory)
+ : d_theory(theory)
+ , d_visited() {
+}
+
+bool MyPreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
+ return d_visited.find(current) != d_visited.end();
+}
+
+void MyPreRegisterVisitor::visit(TNode current, TNode parent) {
+ d_theory->preRegisterTerm(current);
+ d_visited.insert(current);
+}
+
+void MyPreRegisterVisitor::start(TNode node) {
+}
+
+void MyPreRegisterVisitor::done(TNode node) {
+}
+
+} /* namespace CVC4 */
diff --git a/src/proof/proof_output_channel.h b/src/proof/proof_output_channel.h
new file mode 100644
index 000000000..b85af5fb5
--- /dev/null
+++ b/src/proof/proof_output_channel.h
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file proof_output_channel.h
+ ** \verbatim
+ **
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PROOF_OUTPUT_CHANNEL_H
+#define __CVC4__PROOF_OUTPUT_CHANNEL_H
+
+#include "theory/output_channel.h"
+
+namespace CVC4 {
+
+class ProofOutputChannel : public theory::OutputChannel {
+public:
+ Node d_conflict;
+ Proof* d_proof;
+ Node d_lemma;
+ std::set<Node> d_propagations;
+
+ ProofOutputChannel();
+
+ virtual ~ProofOutputChannel() throw() {}
+
+ void conflict(TNode n, Proof* pf) throw();
+ bool propagate(TNode x) throw();
+ theory::LemmaStatus lemma(TNode n, ProofRule rule, bool, bool, bool) throw();
+ theory::LemmaStatus splitLemma(TNode, bool) throw();
+ void requirePhase(TNode n, bool b) throw();
+ bool flipDecision() throw();
+ void setIncomplete() throw();
+};/* class ProofOutputChannel */
+
+class MyPreRegisterVisitor {
+ theory::Theory* d_theory;
+ __gnu_cxx::hash_set<TNode, TNodeHashFunction> d_visited;
+public:
+ typedef void return_type;
+ MyPreRegisterVisitor(theory::Theory* theory);
+ bool alreadyVisited(TNode current, TNode parent);
+ void visit(TNode current, TNode parent);
+ void start(TNode node);
+ void done(TNode node);
+}; /* class MyPreRegisterVisitor */
+
+} /* CVC4 namespace */
+
+#endif /* __CVC4__PROOF_OUTPUT_CHANNEL_H */
diff --git a/src/proof/proof_utils.cpp b/src/proof/proof_utils.cpp
index 5b04c281d..fe0d42242 100644
--- a/src/proof/proof_utils.cpp
+++ b/src/proof/proof_utils.cpp
@@ -21,14 +21,14 @@
namespace CVC4 {
namespace utils {
-void collectAtoms(TNode node, CVC4::NodeSet& seen) {
+void collectAtoms(TNode node, std::set<Node>& seen) {
if (seen.find(node) != seen.end())
return;
if (theory::Theory::theoryOf(node) != theory::THEORY_BOOL || node.isVar()) {
seen.insert(node);
return;
}
-
+
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
collectAtoms(node[i], seen);
}
@@ -47,23 +47,23 @@ std::string toLFSCKind(Kind kind) {
// bit-vector kinds
case kind::BITVECTOR_AND :
- return "bvand";
+ return "bvand";
case kind::BITVECTOR_OR :
- return "bvor";
+ return "bvor";
case kind::BITVECTOR_XOR :
- return "bvxor";
+ return "bvxor";
case kind::BITVECTOR_NAND :
- return "bvnand";
+ return "bvnand";
case kind::BITVECTOR_NOR :
- return "bvnor";
+ return "bvnor";
case kind::BITVECTOR_XNOR :
- return "bvxnor";
+ return "bvxnor";
case kind::BITVECTOR_COMP :
- return "bvcomp";
+ return "bvcomp";
case kind::BITVECTOR_MULT :
return "bvmul";
case kind::BITVECTOR_PLUS :
- return "bvadd";
+ return "bvadd";
case kind::BITVECTOR_SUB :
return "bvsub";
case kind::BITVECTOR_UDIV :
@@ -71,49 +71,49 @@ std::string toLFSCKind(Kind kind) {
return "bvudiv";
case kind::BITVECTOR_UREM :
case kind::BITVECTOR_UREM_TOTAL :
- return "bvurem";
+ return "bvurem";
case kind::BITVECTOR_SDIV :
- return "bvsdiv";
+ return "bvsdiv";
case kind::BITVECTOR_SREM :
return "bvsrem";
case kind::BITVECTOR_SMOD :
- return "bvsmod";
+ return "bvsmod";
case kind::BITVECTOR_SHL :
- return "bvshl";
+ return "bvshl";
case kind::BITVECTOR_LSHR :
return "bvlshr";
case kind::BITVECTOR_ASHR :
return "bvashr";
case kind::BITVECTOR_CONCAT :
- return "concat";
+ return "concat";
case kind::BITVECTOR_NEG :
- return "bvneg";
+ return "bvneg";
case kind::BITVECTOR_NOT :
- return "bvnot";
+ return "bvnot";
case kind::BITVECTOR_ROTATE_LEFT :
- return "rotate_left";
+ return "rotate_left";
case kind::BITVECTOR_ROTATE_RIGHT :
return "rotate_right";
case kind::BITVECTOR_ULT :
- return "bvult";
+ return "bvult";
case kind::BITVECTOR_ULE :
- return "bvule";
+ return "bvule";
case kind::BITVECTOR_UGT :
return "bvugt";
case kind::BITVECTOR_UGE :
return "bvuge";
case kind::BITVECTOR_SLT :
- return "bvslt";
+ return "bvslt";
case kind::BITVECTOR_SLE :
- return "bvsle";
+ return "bvsle";
case kind::BITVECTOR_SGT :
- return "bvsgt";
+ return "bvsgt";
case kind::BITVECTOR_SGE :
- return "bvsge";
+ return "bvsge";
case kind::BITVECTOR_EXTRACT :
- return "extract";
+ return "extract";
case kind::BITVECTOR_REPEAT :
- return "repeat";
+ return "repeat";
case kind::BITVECTOR_ZERO_EXTEND :
return "zero_extend";
case kind::BITVECTOR_SIGN_EXTEND :
diff --git a/src/proof/proof_utils.h b/src/proof/proof_utils.h
index da10c33a0..546d419fc 100644
--- a/src/proof/proof_utils.h
+++ b/src/proof/proof_utils.h
@@ -17,7 +17,7 @@
#include "cvc4_private.h"
-#pragma once
+#pragma once
#include <set>
#include <vector>
@@ -29,6 +29,61 @@ namespace CVC4 {
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction> ExprSet;
typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
+typedef std::pair<Node, Node> NodePair;
+typedef std::set<NodePair> NodePairSet;
+
+
+struct ProofLetCount {
+ static unsigned counter;
+ static void resetCounter() { counter = 0; }
+ static unsigned newId() { return ++counter; }
+
+ unsigned count;
+ unsigned id;
+ ProofLetCount()
+ : count(0)
+ , id(-1)
+ {}
+
+ void increment() { ++count; }
+ ProofLetCount(unsigned i)
+ : count(1)
+ , id(i)
+ {}
+
+ ProofLetCount(const ProofLetCount& other)
+ : count(other.count)
+ , id (other.id)
+ {}
+
+ bool operator==(const ProofLetCount &other) const {
+ return other.id == id && other.count == count;
+ }
+
+ ProofLetCount& operator=(const ProofLetCount &rhs) {
+ if (&rhs == this) return *this;
+ id = rhs.id;
+ count = rhs.count;
+ return *this;
+ }
+};
+
+struct LetOrderElement {
+ Expr expr;
+ unsigned id;
+ LetOrderElement(Expr e, unsigned i)
+ : expr(e)
+ , id(i)
+ {}
+
+ LetOrderElement()
+ : expr()
+ , id(-1)
+ {}
+};
+
+typedef std::vector<LetOrderElement> Bindings;
+
namespace utils {
std::string toLFSCKind(Kind kind);
@@ -42,7 +97,7 @@ inline unsigned getExtractLow(Expr node) {
}
inline unsigned getSize(Type type) {
- BitVectorType bv(type);
+ BitVectorType bv(type);
return bv.getSize();
}
@@ -60,8 +115,8 @@ inline Expr mkFalse() {
return NodeManager::currentNM()->toExprManager()->mkConst<bool>(false);
}
inline BitVector mkBitVectorOnes(unsigned size) {
- Assert(size > 0);
- return BitVector(1, Integer(1)).signExtend(size - 1);
+ Assert(size > 0);
+ return BitVector(1, Integer(1)).signExtend(size - 1);
}
inline Expr mkExpr(Kind k , Expr expr) {
@@ -73,16 +128,16 @@ inline Expr mkExpr(Kind k , Expr e1, Expr e2) {
inline Expr mkExpr(Kind k , std::vector<Expr>& children) {
return NodeManager::currentNM()->toExprManager()->mkExpr(k, children);
}
-
-
+
+
inline Expr mkOnes(unsigned size) {
- BitVector val = mkBitVectorOnes(size);
- return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
+ BitVector val = mkBitVectorOnes(size);
+ return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
}
inline Expr mkConst(unsigned size, unsigned int value) {
BitVector val(size, value);
- return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
+ return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
}
inline Expr mkConst(const BitVector& value) {
@@ -92,14 +147,14 @@ inline Expr mkConst(const BitVector& value) {
inline Expr mkOr(const std::vector<Expr>& nodes) {
std::set<Expr> all;
all.insert(nodes.begin(), nodes.end());
- Assert(all.size() != 0 );
+ Assert(all.size() != 0 );
if (all.size() == 1) {
// All the same, or just one
return nodes[0];
}
-
-
+
+
NodeBuilder<> disjunction(kind::OR);
std::set<Expr>::const_iterator it = all.begin();
std::set<Expr>::const_iterator it_end = all.end();
@@ -109,23 +164,23 @@ inline Expr mkOr(const std::vector<Expr>& nodes) {
}
Node res = disjunction;
- return res.toExpr();
+ return res.toExpr();
}/* mkOr() */
-
+
inline Expr mkAnd(const std::vector<Expr>& conjunctions) {
std::set<Expr> all;
all.insert(conjunctions.begin(), conjunctions.end());
if (all.size() == 0) {
- return mkTrue();
+ return mkTrue();
}
-
+
if (all.size() == 1) {
// All the same, or just one
return conjunctions[0];
}
-
+
NodeBuilder<> conjunction(kind::AND);
std::set<Expr>::const_iterator it = all.begin();
@@ -135,7 +190,7 @@ inline Expr mkAnd(const std::vector<Expr>& conjunctions) {
++ it;
}
- Node res = conjunction;
+ Node res = conjunction;
return res.toExpr();
}/* mkAnd() */
@@ -144,14 +199,14 @@ inline Expr mkSortedExpr(Kind kind, const std::vector<Expr>& children) {
all.insert(children.begin(), children.end());
if (all.size() == 0) {
- return mkTrue();
+ return mkTrue();
}
-
+
if (all.size() == 1) {
// All the same, or just one
return children[0];
}
-
+
NodeBuilder<> res(kind);
std::set<Expr>::const_iterator it = all.begin();
@@ -165,13 +220,13 @@ inline Expr mkSortedExpr(Kind kind, const std::vector<Expr>& children) {
}/* mkSortedNode() */
inline const bool getBit(Expr expr, unsigned i) {
- Assert (i < utils::getSize(expr) &&
- expr.isConst());
+ Assert (i < utils::getSize(expr) &&
+ expr.isConst());
Integer bit = expr.getConst<BitVector>().extract(i, i).getValue();
- return (bit == 1u);
+ return (bit == 1u);
}
-void collectAtoms(TNode node, NodeSet& seen);
+void collectAtoms(TNode node, std::set<Node>& seen);
}
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index d94b61bf3..bda8094be 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -34,175 +34,99 @@
#include "util/proof.h"
#include "util/statistics_registry.h"
+// Forward declarations.
namespace CVC4 {
-
class CnfProof;
+template <class Solver>
+class ProofProxy;
+} /* namespace CVC4 */
+namespace CVC4 {
/**
* Helper debugging functions
*/
-template <class Solver> void printDebug(typename Solver::TLit l);
-template <class Solver> void printDebug(typename Solver::TClause& c);
+template <class Solver>
+void printDebug(typename Solver::TLit l);
+template <class Solver>
+void printDebug(typename Solver::TClause& c);
enum ClauseKind {
INPUT,
- THEORY_LEMMA, // we need to distinguish because we must reprove deleted theory lemmas
+ THEORY_LEMMA, // we need to distinguish because we must reprove deleted
+ // theory lemmas
LEARNT
-};/* enum ClauseKind */
-
+}; /* enum ClauseKind */
template <class Solver>
struct ResStep {
typename Solver::TLit lit;
ClauseId id;
bool sign;
- ResStep(typename Solver::TLit l, ClauseId i, bool s) :
- lit(l),
- id(i),
- sign(s)
- {}
-};/* struct ResStep */
+ ResStep(typename Solver::TLit l, ClauseId i, bool s)
+ : lit(l), id(i), sign(s) {}
+}; /* struct ResStep */
template <class Solver>
class ResChain {
-public:
- typedef std::vector< ResStep<Solver> > ResSteps;
- typedef std::set < typename Solver::TLit> LitSet;
-
-private:
- ClauseId d_start;
- ResSteps d_steps;
- LitSet* d_redundantLits;
-public:
+ public:
+ typedef std::vector<ResStep<Solver> > ResSteps;
+ typedef std::set<typename Solver::TLit> LitSet;
+
ResChain(ClauseId start);
+ ~ResChain();
+
void addStep(typename Solver::TLit, ClauseId, bool);
- bool redundantRemoved() { return (d_redundantLits == NULL || d_redundantLits->empty()); }
+ bool redundantRemoved() {
+ return (d_redundantLits == NULL || d_redundantLits->empty());
+ }
void addRedundantLit(typename Solver::TLit lit);
- ~ResChain();
- // accessor methods
- ClauseId getStart() { return d_start; }
- ResSteps& getSteps() { return d_steps; }
- LitSet* getRedundant() { return d_redundantLits; }
-};/* class ResChain */
-template <class Solver> class ProofProxy;
+ // accessor methods
+ ClauseId getStart() const { return d_start; }
+ const ResSteps& getSteps() const { return d_steps; }
+ LitSet* getRedundant() const { return d_redundantLits; }
-class CnfProof;
+ private:
+ ClauseId d_start;
+ ResSteps d_steps;
+ LitSet* d_redundantLits;
+}; /* class ResChain */
-template<class Solver>
+template <class Solver>
class TSatProof {
-protected:
- typedef std::set < typename Solver::TLit> LitSet;
- typedef std::set < typename Solver::TVar> VarSet;
- typedef std::hash_map < ClauseId, typename Solver::TCRef > IdCRefMap;
- typedef std::hash_map < typename Solver::TCRef, ClauseId > ClauseIdMap;
- typedef std::hash_map < ClauseId, typename Solver::TLit> IdUnitMap;
- typedef std::hash_map < int, ClauseId> UnitIdMap;
- typedef std::hash_map < ClauseId, ResChain<Solver>* > IdResMap;
- typedef std::hash_map < ClauseId, uint64_t > IdProofRuleMap;
- typedef std::vector < ResChain<Solver>* > ResStack;
- //typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
- typedef std::set < ClauseId > IdSet;
- typedef std::vector < typename Solver::TLit > LitVector;
- typedef __gnu_cxx::hash_map<ClauseId, typename Solver::TClause& > IdToMinisatClause;
- typedef __gnu_cxx::hash_map<ClauseId, LitVector* > IdToConflicts;
-
- typename Solver::Solver* d_solver;
- CnfProof* d_cnfProof;
-
- // clauses
- IdCRefMap d_idClause;
- ClauseIdMap d_clauseId;
- IdUnitMap d_idUnit;
- UnitIdMap d_unitId;
- IdHashSet d_deleted;
- IdToSatClause d_deletedTheoryLemmas;
-
-protected:
- IdHashSet d_inputClauses;
- IdHashSet d_lemmaClauses;
- VarSet d_assumptions; // assumption literals for bv solver
- IdHashSet d_assumptionConflicts; // assumption conflicts not actually added to SAT solver
- IdToConflicts d_assumptionConflictsDebug;
-
- // resolutions
- IdResMap d_resChains;
- ResStack d_resStack;
- bool d_checkRes;
-
- const ClauseId d_emptyClauseId;
- const ClauseId d_nullId;
- // proxy class to break circular dependencies
- ProofProxy<Solver>* d_proxy;
-
- // temporary map for updating CRefs
- ClauseIdMap d_temp_clauseId;
- IdCRefMap d_temp_idClause;
-
- // unit conflict
- ClauseId d_unitConflictId;
- bool d_storedUnitConflict;
-
- ClauseId d_trueLit;
- ClauseId d_falseLit;
-
- std::string d_name;
-public:
+ protected:
+ typedef ResChain<Solver> ResolutionChain;
+
+ typedef std::set<typename Solver::TLit> LitSet;
+ typedef std::set<typename Solver::TVar> VarSet;
+ typedef std::hash_map<ClauseId, typename Solver::TCRef> IdCRefMap;
+ typedef std::hash_map<typename Solver::TCRef, ClauseId> ClauseIdMap;
+ typedef std::hash_map<ClauseId, typename Solver::TLit> IdUnitMap;
+ typedef std::hash_map<int, ClauseId> UnitIdMap;
+ typedef std::hash_map<ClauseId, ResolutionChain*> IdResMap;
+ typedef std::hash_map<ClauseId, uint64_t> IdProofRuleMap;
+ typedef std::vector<ResolutionChain*> ResStack;
+ typedef std::set<ClauseId> IdSet;
+ typedef std::vector<typename Solver::TLit> LitVector;
+ typedef __gnu_cxx::hash_map<ClauseId, typename Solver::TClause&>
+ IdToMinisatClause;
+ typedef __gnu_cxx::hash_map<ClauseId, LitVector*> IdToConflicts;
+
+ public:
TSatProof(Solver* solver, const std::string& name, bool checkRes = false);
virtual ~TSatProof();
void setCnfProof(CnfProof* cnf_proof);
-protected:
- void print(ClauseId id);
- void printRes(ClauseId id);
- void printRes(ResChain<Solver>* res);
-
- bool isInputClause(ClauseId id);
- bool isLemmaClause(ClauseId id);
- bool isAssumptionConflict(ClauseId id);
- bool isUnit(ClauseId id);
- bool isUnit(typename Solver::TLit lit);
- bool hasResolution(ClauseId id);
- void createLitSet(ClauseId id, LitSet& set);
- void registerResolution(ClauseId id, ResChain<Solver>* res);
-
- ClauseId getClauseId(typename Solver::TCRef clause);
- ClauseId getClauseId(typename Solver::TLit lit);
- typename Solver::TCRef getClauseRef(ClauseId id);
- typename Solver::TLit getUnit(ClauseId id);
- ClauseId getUnitId(typename Solver::TLit lit);
- typename Solver::TClause& getClause(typename Solver::TCRef ref);
- void getLitVec(ClauseId id, LitVector& vec);
- virtual void toStream(std::ostream& out);
- bool checkResolution(ClauseId id);
- /**
- * Constructs a resolution tree that proves lit
- * and returns the ClauseId for the unit clause lit
- * @param lit the literal we are proving
- *
- * @return
- */
- ClauseId resolveUnit(typename Solver::TLit lit);
- /**
- * Does a depth first search on removed literals and adds the literals
- * to be removed in the proper order to the stack.
- *
- * @param lit the literal we are recursing on
- * @param removedSet the previously computed set of redundant literals
- * @param removeStack the stack of literals in reverse order of resolution
- */
- void removedDfs(typename Solver::TLit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen);
- void removeRedundantFromRes(ResChain<Solver>* res, ClauseId id);
-public:
void startResChain(typename Solver::TLit start);
void startResChain(typename Solver::TCRef start);
- void addResolutionStep(typename Solver::TLit lit, typename Solver::TCRef clause, bool sign);
+ void addResolutionStep(typename Solver::TLit lit,
+ typename Solver::TCRef clause, bool sign);
/**
* Pops the current resolution of the stack and stores it
* in the resolution map. Also registers the 'clause' parameter
* @param clause the clause the resolution is proving
*/
- //void endResChain(typename Solver::TCRef clause);
+ // void endResChain(typename Solver::TCRef clause);
void endResChain(typename Solver::TLit lit);
void endResChain(ClauseId id);
@@ -219,7 +143,8 @@ public:
void storeLitRedundant(typename Solver::TLit lit);
/// update the CRef Id maps when Minisat does memory reallocation x
- void updateCRef(typename Solver::TCRef old_ref, typename Solver::TCRef new_ref);
+ void updateCRef(typename Solver::TCRef old_ref,
+ typename Solver::TCRef new_ref);
void finishUpdateCRef();
/**
@@ -231,25 +156,22 @@ public:
/// clause registration methods
- ClauseId registerClause(const typename Solver::TCRef clause,
- ClauseKind kind);
- ClauseId registerUnitClause(const typename Solver::TLit lit,
- ClauseKind kind);
+ ClauseId registerClause(const typename Solver::TCRef clause, ClauseKind kind);
+ ClauseId registerUnitClause(const typename Solver::TLit lit, ClauseKind kind);
void registerTrueLit(const typename Solver::TLit lit);
void registerFalseLit(const typename Solver::TLit lit);
ClauseId getTrueUnit() const;
ClauseId getFalseUnit() const;
-
void registerAssumption(const typename Solver::TVar var);
ClauseId registerAssumptionConflict(const typename Solver::TLitVec& confl);
- ClauseId storeUnitConflict(typename Solver::TLit lit,
- ClauseKind kind);
+ ClauseId storeUnitConflict(typename Solver::TLit lit, ClauseKind kind);
/**
- * Marks the deleted clauses as deleted. Note we may still use them in the final
+ * Marks the deleted clauses as deleted. Note we may still use them in the
+ * final
* resolution.
* @param clause
*/
@@ -268,43 +190,171 @@ public:
*/
void storeUnitResolution(typename Solver::TLit lit);
- ProofProxy<Solver>* getProxy() {return d_proxy; }
+ ProofProxy<Solver>* getProxy() { return d_proxy; }
/**
* Constructs the SAT proof for the given clause,
* by collecting the needed clauses in the d_seen
* data-structures, also notifying the proofmanager.
*/
void constructProof(ClauseId id);
- void constructProof() {
- constructProof(d_emptyClauseId);
- }
+ void constructProof() { constructProof(d_emptyClauseId); }
void collectClauses(ClauseId id);
prop::SatClause* buildClause(ClauseId id);
-protected:
- IdSet d_seenLearnt;
- IdToSatClause d_seenInputs;
- IdToSatClause d_seenLemmas;
+
+ virtual void printResolution(ClauseId id, std::ostream& out,
+ std::ostream& paren) = 0;
+ virtual void printResolutions(std::ostream& out, std::ostream& paren) = 0;
+ virtual void printResolutionEmptyClause(std::ostream& out,
+ std::ostream& paren) = 0;
+ virtual void printAssumptionsResolution(ClauseId id, std::ostream& out,
+ std::ostream& paren) = 0;
+
+ void collectClausesUsed(IdToSatClause& inputs, IdToSatClause& lemmas);
+
+ void storeClauseGlue(ClauseId clause, int glue);
+
+ protected:
+ void print(ClauseId id) const;
+ void printRes(ClauseId id) const;
+ void printRes(const ResolutionChain& res) const;
+
+ bool isInputClause(ClauseId id) const;
+ bool isLemmaClause(ClauseId id) const;
+ bool isAssumptionConflict(ClauseId id) const;
+
+ bool isUnit(ClauseId id) const;
+ typename Solver::TLit getUnit(ClauseId id) const;
+
+ bool isUnit(typename Solver::TLit lit) const;
+ ClauseId getUnitId(typename Solver::TLit lit) const;
+
+
+
+ bool hasResolutionChain(ClauseId id) const;
+
+ /** Returns the resolution chain associated with id. Assert fails if
+ * hasResolution(id) does not hold. */
+ const ResolutionChain& getResolutionChain(ClauseId id) const;
+
+ /** Returns a mutable pointer to the resolution chain associated with id.
+ * Assert fails if hasResolution(id) does not hold. */
+ ResolutionChain* getMutableResolutionChain(ClauseId id);
+
+ void createLitSet(ClauseId id, LitSet& set);
+
+ /**
+ * Registers a ClauseId with a resolution chain res.
+ * Takes ownership of the memory associated with res.
+ */
+ void registerResolution(ClauseId id, ResolutionChain* res);
+
+
+ bool hasClauseIdForCRef(typename Solver::TCRef clause) const;
+ ClauseId getClauseIdForCRef(typename Solver::TCRef clause) const;
+
+ bool hasClauseIdForLiteral(typename Solver::TLit lit) const;
+ ClauseId getClauseIdForLiteral(typename Solver::TLit lit) const;
+
+ bool hasClauseRef(ClauseId id) const;
+ typename Solver::TCRef getClauseRef(ClauseId id) const;
+
+
+ const typename Solver::TClause& getClause(typename Solver::TCRef ref) const;
+ typename Solver::TClause* getMutableClause(typename Solver::TCRef ref);
+
+ void getLitVec(ClauseId id, LitVector& vec);
+ virtual void toStream(std::ostream& out);
+
+ bool checkResolution(ClauseId id);
+
+ /**
+ * Constructs a resolution tree that proves lit
+ * and returns the ClauseId for the unit clause lit
+ * @param lit the literal we are proving
+ *
+ * @return
+ */
+ ClauseId resolveUnit(typename Solver::TLit lit);
+
+ /**
+ * Does a depth first search on removed literals and adds the literals
+ * to be removed in the proper order to the stack.
+ *
+ * @param lit the literal we are recursing on
+ * @param removedSet the previously computed set of redundant literals
+ * @param removeStack the stack of literals in reverse order of resolution
+ */
+ void removedDfs(typename Solver::TLit lit, LitSet* removedSet,
+ LitVector& removeStack, LitSet& inClause, LitSet& seen);
+ void removeRedundantFromRes(ResChain<Solver>* res, ClauseId id);
std::string varName(typename Solver::TLit lit);
std::string clauseName(ClauseId id);
-
void addToProofManager(ClauseId id, ClauseKind kind);
void addToCnfProof(ClauseId id);
-public:
- virtual void printResolution(ClauseId id, std::ostream& out, std::ostream& paren) = 0;
- virtual void printResolutions(std::ostream& out, std::ostream& paren) = 0;
- virtual void printResolutionEmptyClause(std::ostream& out, std::ostream& paren) = 0;
- virtual void printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren) = 0;
- void collectClausesUsed(IdToSatClause& inputs,
- IdToSatClause& lemmas);
+ // Internal data.
+ typename Solver::Solver* d_solver;
+ CnfProof* d_cnfProof;
- void storeClauseGlue(ClauseId clause, int glue);
+ // clauses
+ IdCRefMap d_idClause;
+ ClauseIdMap d_clauseId;
+ IdUnitMap d_idUnit;
+ UnitIdMap d_unitId;
+ IdHashSet d_deleted;
+ IdToSatClause d_deletedTheoryLemmas;
+
+ IdHashSet d_inputClauses;
+ IdHashSet d_lemmaClauses;
+ VarSet d_assumptions; // assumption literals for bv solver
+ IdHashSet d_assumptionConflicts; // assumption conflicts not actually added
+ // to SAT solver
+ IdToConflicts d_assumptionConflictsDebug;
+
+ // Resolutions.
+ /**
+ * Map from ClauseId to resolution chain corresponding proving the
+ * clause corresponding to the ClauseId. d_resolutionChains owns the
+ * memory of the ResChain* it contains.
+ */
+ IdResMap d_resolutionChains;
+
+ /*
+ * Stack containting current ResChain* we are working on. d_resStack
+ * owns the memory for the ResChain* it contains. Invariant: no
+ * ResChain* pointer can be both in d_resStack and
+ * d_resolutionChains. Memory ownership is transfered from
+ * d_resStack to d_resolutionChains via registerResolution.
+ */
+ ResStack d_resStack;
+ bool d_checkRes;
+
+ const ClauseId d_emptyClauseId;
+ const ClauseId d_nullId;
+ // proxy class to break circular dependencies
+ ProofProxy<Solver>* d_proxy;
+ // temporary map for updating CRefs
+ ClauseIdMap d_temp_clauseId;
+ IdCRefMap d_temp_idClause;
-private:
+ // unit conflict
+ ClauseId d_unitConflictId;
+ bool d_storedUnitConflict;
+
+ ClauseId d_trueLit;
+ ClauseId d_falseLit;
+
+ std::string d_name;
+
+ IdSet d_seenLearnt;
+ IdToSatClause d_seenInputs;
+ IdToSatClause d_seenLemmas;
+
+ private:
__gnu_cxx::hash_map<ClauseId, int> d_glueMap;
struct Statistics {
IntStat d_numLearnedClauses;
@@ -320,49 +370,47 @@ private:
};
Statistics d_statistics;
-};/* class TSatProof */
+}; /* class TSatProof */
template <class S>
class ProofProxy {
-private:
+ private:
TSatProof<S>* d_proof;
-public:
+
+ public:
ProofProxy(TSatProof<S>* pf);
void updateCRef(typename S::TCRef oldref, typename S::TCRef newref);
-};/* class ProofProxy */
-
+}; /* class ProofProxy */
template <class SatSolver>
class LFSCSatProof : public TSatProof<SatSolver> {
-private:
-
-public:
- LFSCSatProof(SatSolver* solver, const std::string& name, bool checkRes = false)
- : TSatProof<SatSolver>(solver, name, checkRes)
- {}
- virtual void printResolution(ClauseId id, std::ostream& out, std::ostream& paren);
+ private:
+ public:
+ LFSCSatProof(SatSolver* solver, const std::string& name,
+ bool checkRes = false)
+ : TSatProof<SatSolver>(solver, name, checkRes) {}
+ virtual void printResolution(ClauseId id, std::ostream& out,
+ std::ostream& paren);
virtual void printResolutions(std::ostream& out, std::ostream& paren);
- virtual void printResolutionEmptyClause(std::ostream& out, std::ostream& paren);
- virtual void printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren);
-};/* class LFSCSatProof */
-
-
+ virtual void printResolutionEmptyClause(std::ostream& out,
+ std::ostream& paren);
+ virtual void printAssumptionsResolution(ClauseId id, std::ostream& out,
+ std::ostream& paren);
+}; /* class LFSCSatProof */
-template<class Solver>
+template <class Solver>
prop::SatLiteral toSatLiteral(typename Solver::TLit lit);
-
/**
* Convert from minisat clause to SatClause
*
* @param minisat_cl
* @param sat_cl
*/
-template<class Solver>
+template <class Solver>
void toSatClause(const typename Solver::TClause& minisat_cl,
prop::SatClause& sat_cl);
-
-}/* CVC4 namespace */
+} /* CVC4 namespace */
#endif /* __CVC4__SAT__PROOF_H */
diff --git a/src/proof/sat_proof_implementation.h b/src/proof/sat_proof_implementation.h
index e773e4b47..1e01e4dce 100644
--- a/src/proof/sat_proof_implementation.h
+++ b/src/proof/sat_proof_implementation.h
@@ -32,29 +32,28 @@
namespace CVC4 {
template <class Solver>
-void printLit (typename Solver::TLit l) {
+void printLit(typename Solver::TLit l) {
Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1;
}
template <class Solver>
-void printClause (typename Solver::TClause& c) {
+void printClause(const typename Solver::TClause& c) {
for (int i = 0; i < c.size(); i++) {
Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
}
}
template <class Solver>
-void printClause (std::vector<typename Solver::TLit>& c) {
+void printClause(const std::vector<typename Solver::TLit>& c) {
for (unsigned i = 0; i < c.size(); i++) {
Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
}
}
-
template <class Solver>
void printLitSet(const std::set<typename Solver::TLit>& s) {
- typename std::set < typename Solver::TLit>::const_iterator it = s.begin();
- for(; it != s.end(); ++it) {
+ typename std::set<typename Solver::TLit>::const_iterator it = s.begin();
+ for (; it != s.end(); ++it) {
printLit<Solver>(*it);
Debug("proof:sat") << " ";
}
@@ -63,18 +62,17 @@ void printLitSet(const std::set<typename Solver::TLit>& s) {
// purely debugging functions
template <class Solver>
-void printDebug (typename Solver::TLit l) {
+void printDebug(typename Solver::TLit l) {
Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1 << std::endl;
}
template <class Solver>
-void printDebug (typename Solver::TClause& c) {
+void printDebug(typename Solver::TClause& c) {
for (int i = 0; i < c.size(); i++) {
Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
}
Debug("proof:sat") << std::endl;
}
-
/**
* Converts the clause associated to id to a set of literals
*
@@ -84,11 +82,11 @@ void printDebug (typename Solver::TClause& c) {
template <class Solver>
void TSatProof<Solver>::createLitSet(ClauseId id, LitSet& set) {
Assert(set.empty());
- if(isUnit(id)) {
+ if (isUnit(id)) {
set.insert(getUnit(id));
return;
}
- if ( id == d_emptyClauseId) {
+ if (id == d_emptyClauseId) {
return;
}
// if it's an assumption
@@ -101,13 +99,12 @@ void TSatProof<Solver>::createLitSet(ClauseId id, LitSet& set) {
}
typename Solver::TCRef ref = getClauseRef(id);
- typename Solver::TClause& c = getClause(ref);
+ const typename Solver::TClause& c = getClause(ref);
for (int i = 0; i < c.size(); i++) {
set.insert(c[i]);
}
}
-
/**
* Resolves clause1 and clause2 on variable var and stores the
* result in clause1
@@ -124,8 +121,8 @@ bool resolve(const typename Solver::TLit v,
typename Solver::TLit var = sign(v) ? ~v : v;
if (s) {
// literal appears positive in the first clause
- if( !clause2.count(~var)) {
- if(Debug.isOn("proof:sat")) {
+ if (!clause2.count(~var)) {
+ if (Debug.isOn("proof:sat")) {
Debug("proof:sat") << "proof:resolve: Missing literal ";
printLit<Solver>(var);
Debug("proof:sat") << std::endl;
@@ -135,13 +132,13 @@ bool resolve(const typename Solver::TLit v,
clause1.erase(var);
clause2.erase(~var);
typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
- for (; it!= clause2.end(); ++it) {
+ for (; it != clause2.end(); ++it) {
clause1.insert(*it);
}
} else {
// literal appears negative in the first clause
- if( !clause1.count(~var) || !clause2.count(var)) {
- if(Debug.isOn("proof:sat")) {
+ if (!clause1.count(~var) || !clause2.count(var)) {
+ if (Debug.isOn("proof:sat")) {
Debug("proof:sat") << "proof:resolve: Missing literal ";
printLit<Solver>(var);
Debug("proof:sat") << std::endl;
@@ -151,7 +148,7 @@ bool resolve(const typename Solver::TLit v,
clause1.erase(~var);
clause2.erase(var);
typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
- for (; it!= clause2.end(); ++it) {
+ for (; it != clause2.end(); ++it) {
clause1.insert(*it);
}
}
@@ -160,13 +157,19 @@ bool resolve(const typename Solver::TLit v,
/// ResChain
template <class Solver>
-ResChain<Solver>::ResChain(ClauseId start) :
- d_start(start),
- d_steps(),
- d_redundantLits(NULL)
- {}
+ResChain<Solver>::ResChain(ClauseId start)
+ : d_start(start), d_steps(), d_redundantLits(NULL) {}
+
+template <class Solver>
+ResChain<Solver>::~ResChain() {
+ if (d_redundantLits != NULL) {
+ delete d_redundantLits;
+ }
+}
+
template <class Solver>
-void ResChain<Solver>::addStep(typename Solver::TLit lit, ClauseId id, bool sign) {
+void ResChain<Solver>::addStep(typename Solver::TLit lit, ClauseId id,
+ bool sign) {
ResStep<Solver> step(lit, id, sign);
d_steps.push_back(step);
}
@@ -181,50 +184,47 @@ void ResChain<Solver>::addRedundantLit(typename Solver::TLit lit) {
}
}
-
/// ProxyProof
template <class Solver>
-ProofProxy<Solver>::ProofProxy(TSatProof<Solver>* proof):
- d_proof(proof)
-{}
+ProofProxy<Solver>::ProofProxy(TSatProof<Solver>* proof) : d_proof(proof) {}
template <class Solver>
-void ProofProxy<Solver>::updateCRef(typename Solver::TCRef oldref, typename Solver::TCRef newref) {
+void ProofProxy<Solver>::updateCRef(typename Solver::TCRef oldref,
+ typename Solver::TCRef newref) {
d_proof->updateCRef(oldref, newref);
}
-
/// SatProof
template <class Solver>
-TSatProof<Solver>::TSatProof(Solver* solver, const std::string& name, bool checkRes)
- : d_solver(solver)
- , d_cnfProof(NULL)
- , d_idClause()
- , d_clauseId()
- , d_idUnit()
- , d_deleted()
- , d_inputClauses()
- , d_lemmaClauses()
- , d_assumptions()
- , d_assumptionConflicts()
- , d_assumptionConflictsDebug()
- , d_resChains()
- , d_resStack()
- , d_checkRes(checkRes)
- , d_emptyClauseId(ClauseIdEmpty)
- , d_nullId(-2)
- , d_temp_clauseId()
- , d_temp_idClause()
- , d_unitConflictId()
- , d_storedUnitConflict(false)
- , d_trueLit(ClauseIdUndef)
- , d_falseLit(ClauseIdUndef)
- , d_name(name)
- , d_seenLearnt()
- , d_seenInputs()
- , d_seenLemmas()
- , d_statistics(name)
-{
+TSatProof<Solver>::TSatProof(Solver* solver, const std::string& name,
+ bool checkRes)
+ : d_solver(solver),
+ d_cnfProof(NULL),
+ d_idClause(),
+ d_clauseId(),
+ d_idUnit(),
+ d_deleted(),
+ d_inputClauses(),
+ d_lemmaClauses(),
+ d_assumptions(),
+ d_assumptionConflicts(),
+ d_assumptionConflictsDebug(),
+ d_resolutionChains(),
+ d_resStack(),
+ d_checkRes(checkRes),
+ d_emptyClauseId(ClauseIdEmpty),
+ d_nullId(-2),
+ d_temp_clauseId(),
+ d_temp_idClause(),
+ d_unitConflictId(),
+ d_storedUnitConflict(false),
+ d_trueLit(ClauseIdUndef),
+ d_falseLit(ClauseIdUndef),
+ d_name(name),
+ d_seenLearnt(),
+ d_seenInputs(),
+ d_seenLemmas(),
+ d_statistics(name) {
d_proxy = new ProofProxy<Solver>(this);
}
@@ -233,34 +233,53 @@ TSatProof<Solver>::~TSatProof() {
delete d_proxy;
// FIXME: double free if deleted clause also appears in d_seenLemmas?
- IdToSatClause::iterator it = d_deletedTheoryLemmas.begin();
- IdToSatClause::iterator end = d_deletedTheoryLemmas.end();
+ IdToSatClause::const_iterator it = d_deletedTheoryLemmas.begin();
+ IdToSatClause::const_iterator end = d_deletedTheoryLemmas.end();
for (; it != end; ++it) {
ClauseId id = it->first;
// otherwise deleted in next loop
- if (d_seenLemmas.find(id) == d_seenLemmas.end())
+ if (d_seenLemmas.find(id) == d_seenLemmas.end()) {
delete it->second;
+ }
}
- IdToSatClause::iterator seen_it = d_seenLemmas.begin();
- IdToSatClause::iterator seen_end = d_seenLemmas.end();
+ IdToSatClause::const_iterator seen_lemma_it = d_seenLemmas.begin();
+ IdToSatClause::const_iterator seen_lemma_end = d_seenLemmas.end();
- for (; seen_it != seen_end; ++seen_it) {
- delete seen_it->second;
+ for (; seen_lemma_it != seen_lemma_end; ++seen_lemma_it) {
+ delete seen_lemma_it->second;
}
- seen_it = d_seenInputs.begin();
- seen_end = d_seenInputs.end();
+ IdToSatClause::const_iterator seen_input_it = d_seenInputs.begin();
+ IdToSatClause::const_iterator seen_input_end = d_seenInputs.end();
- for (; seen_it != seen_end; ++seen_it) {
- delete seen_it->second;
+ for (; seen_input_it != seen_input_end; ++seen_input_it) {
+ delete seen_input_it->second;
+ }
+
+ typedef typename IdResMap::const_iterator ResolutionChainIterator;
+ ResolutionChainIterator resolution_it = d_resolutionChains.begin();
+ ResolutionChainIterator resolution_it_end = d_resolutionChains.end();
+ for (; resolution_it != resolution_it_end; ++resolution_it) {
+ ResChain<Solver>* current = resolution_it->second;
+ delete current;
+ }
+
+ // It could be the case that d_resStack is not empty at destruction time
+ // (for example in the SAT case).
+ typename ResStack::const_iterator resolution_stack_it = d_resStack.begin();
+ typename ResStack::const_iterator resolution_stack_it_end = d_resStack.end();
+ for (; resolution_stack_it != resolution_stack_it_end;
+ ++resolution_stack_it) {
+ ResChain<Solver>* current = *resolution_stack_it;
+ delete current;
}
}
template <class Solver>
void TSatProof<Solver>::setCnfProof(CnfProof* cnf_proof) {
- Assert (d_cnfProof == NULL);
+ Assert(d_cnfProof == NULL);
d_cnfProof = cnf_proof;
}
@@ -273,19 +292,19 @@ void TSatProof<Solver>::setCnfProof(CnfProof* cnf_proof) {
*/
template <class Solver>
bool TSatProof<Solver>::checkResolution(ClauseId id) {
- if(d_checkRes) {
+ if (d_checkRes) {
bool validRes = true;
- Assert(d_resChains.find(id) != d_resChains.end());
- ResChain<Solver>* res = d_resChains[id];
+ Assert(hasResolutionChain(id));
+ const ResolutionChain& res = getResolutionChain(id);
LitSet clause1;
- createLitSet(res->getStart(), clause1);
- typename ResChain<Solver>::ResSteps& steps = res->getSteps();
+ createLitSet(res.getStart(), clause1);
+ const typename ResolutionChain::ResSteps& steps = res.getSteps();
for (unsigned i = 0; i < steps.size(); i++) {
- typename Solver::TLit var = steps[i].lit;
+ typename Solver::TLit var = steps[i].lit;
LitSet clause2;
- createLitSet (steps[i].id, clause2);
- bool res = resolve<Solver> (var, clause1, clause2, steps[i].sign);
- if(res == false) {
+ createLitSet(steps[i].id, clause2);
+ bool res = resolve<Solver>(var, clause1, clause2, steps[i].sign);
+ if (res == false) {
validRes = false;
break;
}
@@ -307,8 +326,9 @@ bool TSatProof<Solver>::checkResolution(ClauseId id) {
for (unsigned i = 0; i < c.size(); ++i) {
int count = clause1.erase(c[i]);
if (count == 0) {
- if(Debug.isOn("proof:sat")) {
- Debug("proof:sat") << "proof:checkResolution::literal not in computed result ";
+ if (Debug.isOn("proof:sat")) {
+ Debug("proof:sat")
+ << "proof:checkResolution::literal not in computed result ";
printLit<Solver>(c[i]);
Debug("proof:sat") << "\n";
}
@@ -316,9 +336,10 @@ bool TSatProof<Solver>::checkResolution(ClauseId id) {
}
}
validRes = clause1.empty();
- if (! validRes) {
- if(Debug.isOn("proof:sat")) {
- Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, unremoved literals: \n";
+ if (!validRes) {
+ if (Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, "
+ "unremoved literals: \n";
printLitSet<Solver>(clause1);
Debug("proof:sat") << "proof:checkResolution:: result should be: \n";
printClause<Solver>(c);
@@ -331,37 +352,54 @@ bool TSatProof<Solver>::checkResolution(ClauseId id) {
}
}
-
-
-
/// helper methods
template <class Solver>
-ClauseId TSatProof<Solver>::getClauseId(typename Solver::TCRef ref) {
- if(d_clauseId.find(ref) == d_clauseId.end()) {
+bool TSatProof<Solver>::hasClauseIdForCRef(typename Solver::TCRef ref) const {
+ return d_clauseId.find(ref) != d_clauseId.end();
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::getClauseIdForCRef(
+ typename Solver::TCRef ref) const {
+ if (d_clauseId.find(ref) == d_clauseId.end()) {
Debug("proof:sat") << "Missing clause \n";
}
- Assert(d_clauseId.find(ref) != d_clauseId.end());
- return d_clauseId[ref];
+ Assert(hasClauseIdForCRef(ref));
+ return d_clauseId.find(ref)->second;
+}
+
+template <class Solver>
+bool TSatProof<Solver>::hasClauseIdForLiteral(typename Solver::TLit lit) const {
+ return d_unitId.find(toInt(lit)) != d_unitId.end();
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::getClauseIdForLiteral(
+ typename Solver::TLit lit) const {
+ Assert(hasClauseIdForLiteral(lit));
+ return d_unitId.find(toInt(lit))->second;
}
template <class Solver>
-ClauseId TSatProof<Solver>::getClauseId(typename Solver::TLit lit) {
- Assert(d_unitId.find(toInt(lit)) != d_unitId.end());
- return d_unitId[toInt(lit)];
+bool TSatProof<Solver>::hasClauseRef(ClauseId id) const {
+ return d_idClause.find(id) != d_idClause.end();
}
+
template <class Solver>
-typename Solver::TCRef TSatProof<Solver>::getClauseRef(ClauseId id) {
- if (d_idClause.find(id) == d_idClause.end()) {
- Debug("proof:sat") << "proof:getClauseRef cannot find clause "<<id<<" "
- << ((d_deleted.find(id) != d_deleted.end()) ? "deleted" : "")
- << (isUnit(id)? "Unit" : "") << std::endl;
+typename Solver::TCRef TSatProof<Solver>::getClauseRef(ClauseId id) const {
+ if (!hasClauseRef(id)) {
+ Debug("proof:sat") << "proof:getClauseRef cannot find clause " << id << " "
+ << ((d_deleted.find(id) != d_deleted.end()) ? "deleted"
+ : "")
+ << (isUnit(id) ? "Unit" : "") << std::endl;
}
- Assert(d_idClause.find(id) != d_idClause.end());
- return d_idClause[id];
+ Assert(hasClauseRef(id));
+ return d_idClause.find(id)->second;
}
template <class Solver>
-typename Solver::TClause& TSatProof<Solver>::getClause(typename Solver::TCRef ref) {
+const typename Solver::TClause& TSatProof<Solver>::getClause(
+ typename Solver::TCRef ref) const {
Assert(ref != Solver::TCRef_Undef);
Assert(ref >= 0 && ref < d_solver->ca.size());
return d_solver->ca[ref];
@@ -379,85 +417,106 @@ void TSatProof<Solver>::getLitVec(ClauseId id, LitVector& vec) {
return;
}
typename Solver::TCRef cref = getClauseRef(id);
- typename Solver::TClause& cl = getClause(cref);
+ const typename Solver::TClause& cl = getClause(cref);
for (int i = 0; i < cl.size(); ++i) {
vec.push_back(cl[i]);
}
}
-
template <class Solver>
-typename Solver::TLit TSatProof<Solver>::getUnit(ClauseId id) {
- Assert(d_idUnit.find(id) != d_idUnit.end());
- return d_idUnit[id];
+bool TSatProof<Solver>::isUnit(ClauseId id) const {
+ return d_idUnit.find(id) != d_idUnit.end();
}
+
template <class Solver>
-bool TSatProof<Solver>::isUnit(ClauseId id) {
- return d_idUnit.find(id) != d_idUnit.end();
+typename Solver::TLit TSatProof<Solver>::getUnit(ClauseId id) const {
+ Assert(isUnit(id));
+ return d_idUnit.find(id)->second;
}
+
template <class Solver>
-bool TSatProof<Solver>::isUnit(typename Solver::TLit lit) {
+bool TSatProof<Solver>::isUnit(typename Solver::TLit lit) const {
return d_unitId.find(toInt(lit)) != d_unitId.end();
}
+
template <class Solver>
-ClauseId TSatProof<Solver>::getUnitId(typename Solver::TLit lit) {
+ClauseId TSatProof<Solver>::getUnitId(typename Solver::TLit lit) const {
Assert(isUnit(lit));
- return d_unitId[toInt(lit)];
+ return d_unitId.find(toInt(lit))->second;
}
+
template <class Solver>
-bool TSatProof<Solver>::hasResolution(ClauseId id) {
- return d_resChains.find(id) != d_resChains.end();
+bool TSatProof<Solver>::hasResolutionChain(ClauseId id) const {
+ return d_resolutionChains.find(id) != d_resolutionChains.end();
}
+
template <class Solver>
-bool TSatProof<Solver>::isInputClause(ClauseId id) {
- return (d_inputClauses.find(id) != d_inputClauses.end());
+const typename TSatProof<Solver>::ResolutionChain&
+TSatProof<Solver>::getResolutionChain(ClauseId id) const {
+ Assert(hasResolutionChain(id));
+ const ResolutionChain* chain = d_resolutionChains.find(id)->second;
+ return *chain;
}
+
template <class Solver>
-bool TSatProof<Solver>::isLemmaClause(ClauseId id) {
- return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
+typename TSatProof<Solver>::ResolutionChain*
+TSatProof<Solver>::getMutableResolutionChain(ClauseId id) {
+ Assert(hasResolutionChain(id));
+ ResolutionChain* chain = d_resolutionChains.find(id)->second;
+ return chain;
}
template <class Solver>
-bool TSatProof<Solver>::isAssumptionConflict(ClauseId id) {
- return d_assumptionConflicts.find(id) != d_assumptionConflicts.end();
+bool TSatProof<Solver>::isInputClause(ClauseId id) const {
+ return d_inputClauses.find(id) != d_inputClauses.end();
}
+template <class Solver>
+bool TSatProof<Solver>::isLemmaClause(ClauseId id) const {
+ return d_lemmaClauses.find(id) != d_lemmaClauses.end();
+}
+
+template <class Solver>
+bool TSatProof<Solver>::isAssumptionConflict(ClauseId id) const {
+ return d_assumptionConflicts.find(id) != d_assumptionConflicts.end();
+}
template <class Solver>
-void TSatProof<Solver>::print(ClauseId id) {
+void TSatProof<Solver>::print(ClauseId id) const {
if (d_deleted.find(id) != d_deleted.end()) {
- Debug("proof:sat") << "del"<<id;
+ Debug("proof:sat") << "del" << id;
} else if (isUnit(id)) {
printLit<Solver>(getUnit(id));
} else if (id == d_emptyClauseId) {
- Debug("proof:sat") << "empty "<< std::endl;
- }
- else {
+ Debug("proof:sat") << "empty " << std::endl;
+ } else {
typename Solver::TCRef ref = getClauseRef(id);
printClause<Solver>(getClause(ref));
}
}
+
template <class Solver>
-void TSatProof<Solver>::printRes(ClauseId id) {
- Assert(hasResolution(id));
- Debug("proof:sat") << "id "<< id <<": ";
- printRes(d_resChains[id]);
+void TSatProof<Solver>::printRes(ClauseId id) const {
+ Assert(hasResolutionChain(id));
+ Debug("proof:sat") << "id " << id << ": ";
+ printRes(getResolutionChain(id));
}
+
template <class Solver>
-void TSatProof<Solver>::printRes(ResChain<Solver>* res) {
- ClauseId start_id = res->getStart();
+void TSatProof<Solver>::printRes(const ResolutionChain& res) const {
+ ClauseId start_id = res.getStart();
- if(Debug.isOn("proof:sat")) {
+ if (Debug.isOn("proof:sat")) {
Debug("proof:sat") << "(";
print(start_id);
}
- typename ResChain<Solver>::ResSteps& steps = res->getSteps();
- for(unsigned i = 0; i < steps.size(); i++ ) {
+ const typename ResolutionChain::ResSteps& steps = res.getSteps();
+ for (unsigned i = 0; i < steps.size(); i++) {
typename Solver::TLit v = steps[i].lit;
ClauseId id = steps[i].id;
- if(Debug.isOn("proof:sat")) {
+ if (Debug.isOn("proof:sat")) {
Debug("proof:sat") << "[";
printLit<Solver>(v);
Debug("proof:sat") << "] ";
@@ -469,8 +528,8 @@ void TSatProof<Solver>::printRes(ResChain<Solver>* res) {
/// registration methods
template <class Solver>
- ClauseId TSatProof<Solver>::registerClause(typename Solver::TCRef clause,
- ClauseKind kind) {
+ClauseId TSatProof<Solver>::registerClause(typename Solver::TCRef clause,
+ ClauseKind kind) {
Assert(clause != Solver::TCRef_Undef);
typename ClauseIdMap::iterator it = d_clauseId.find(clause);
if (it == d_clauseId.end()) {
@@ -485,10 +544,8 @@ template <class Solver>
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
d_lemmaClauses.insert(newId);
Debug("pf::sat") << "TSatProof::registerClause registering a new lemma clause: "
- << newId << " = " << *buildClause(newId)
- << ". Explainer theory: " << d_cnfProof->getExplainerTheory()
- << std::endl;
- d_cnfProof->registerExplanationLemma(newId);
+ << newId << " = " << *buildClause(newId)
+ << std::endl;
}
}
@@ -496,15 +553,16 @@ template <class Solver>
Assert(kind != INPUT || d_inputClauses.count(id));
Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
- Debug("proof:sat:detailed") << "registerClause CRef: " << clause << " id: " << d_clauseId[clause]
- <<" kind: " << kind << "\n";
- //ProofManager::currentPM()->setRegisteredClauseId( d_clauseId[clause] );
+ Debug("proof:sat:detailed") << "registerClause CRef: " << clause
+ << " id: " << d_clauseId[clause]
+ << " kind: " << kind << "\n";
+ // ProofManager::currentPM()->setRegisteredClauseId( d_clauseId[clause] );
return id;
}
template <class Solver>
ClauseId TSatProof<Solver>::registerUnitClause(typename Solver::TLit lit,
- ClauseKind kind) {
+ ClauseKind kind) {
Debug("cores") << "registerUnitClause " << kind << std::endl;
typename UnitIdMap::iterator it = d_unitId.find(toInt(lit));
if (it == d_unitId.end()) {
@@ -519,59 +577,57 @@ ClauseId TSatProof<Solver>::registerUnitClause(typename Solver::TLit lit,
if (kind == THEORY_LEMMA) {
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
Debug("pf::sat") << "TSatProof::registerUnitClause: registering a new lemma (UNIT CLAUSE): "
- << lit
- << ". Explainer theory: " << d_cnfProof->getExplainerTheory()
- << std::endl;
+ << lit
+ << std::endl;
d_lemmaClauses.insert(newId);
- d_cnfProof->registerExplanationLemma(newId);
}
}
ClauseId id = d_unitId[toInt(lit)];
Assert(kind != INPUT || d_inputClauses.count(id));
Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
Debug("proof:sat:detailed") << "registerUnitClause id: " << id
- <<" kind: " << kind << "\n";
+ << " kind: " << kind << "\n";
// ProofManager::currentPM()->setRegisteredClauseId( d_unitId[toInt(lit)] );
return id;
}
template <class Solver>
void TSatProof<Solver>::registerTrueLit(const typename Solver::TLit lit) {
- Assert (d_trueLit == ClauseIdUndef);
+ Assert(d_trueLit == ClauseIdUndef);
d_trueLit = registerUnitClause(lit, INPUT);
}
template <class Solver>
void TSatProof<Solver>::registerFalseLit(const typename Solver::TLit lit) {
- Assert (d_falseLit == ClauseIdUndef);
+ Assert(d_falseLit == ClauseIdUndef);
d_falseLit = registerUnitClause(lit, INPUT);
}
template <class Solver>
ClauseId TSatProof<Solver>::getTrueUnit() const {
- Assert (d_trueLit != ClauseIdUndef);
+ Assert(d_trueLit != ClauseIdUndef);
return d_trueLit;
}
template <class Solver>
ClauseId TSatProof<Solver>::getFalseUnit() const {
- Assert (d_falseLit != ClauseIdUndef);
+ Assert(d_falseLit != ClauseIdUndef);
return d_falseLit;
}
-
template <class Solver>
void TSatProof<Solver>::registerAssumption(const typename Solver::TVar var) {
- Assert (d_assumptions.find(var) == d_assumptions.end());
+ Assert(d_assumptions.find(var) == d_assumptions.end());
d_assumptions.insert(var);
}
template <class Solver>
-ClauseId TSatProof<Solver>::registerAssumptionConflict(const typename Solver::TLitVec& confl) {
+ClauseId TSatProof<Solver>::registerAssumptionConflict(
+ const typename Solver::TLitVec& confl) {
Debug("proof:sat:detailed") << "registerAssumptionConflict " << std::endl;
// Uniqueness is checked in the bit-vector proof
// should be vars
for (int i = 0; i < confl.size(); ++i) {
- Assert (d_assumptions.find(var(confl[i])) != d_assumptions.end());
+ Assert(d_assumptions.find(var(confl[i])) != d_assumptions.end());
}
ClauseId new_id = ProofManager::currentPM()->nextId();
d_assumptionConflicts.insert(new_id);
@@ -588,9 +644,10 @@ ClauseId TSatProof<Solver>::registerAssumptionConflict(const typename Solver::TL
return new_id;
}
-
template <class Solver>
-void TSatProof<Solver>::removedDfs(typename Solver::TLit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen) {
+void TSatProof<Solver>::removedDfs(typename Solver::TLit lit,
+ LitSet* removedSet, LitVector& removeStack,
+ LitSet& inClause, LitSet& seen) {
// if we already added the literal return
if (seen.count(lit)) {
return;
@@ -604,20 +661,21 @@ void TSatProof<Solver>::removedDfs(typename Solver::TLit lit, LitSet* removedSet
}
int size = getClause(reason_ref).size();
- for (int i = 1; i < size; i++ ) {
+ for (int i = 1; i < size; i++) {
typename Solver::TLit v = getClause(reason_ref)[i];
- if(inClause.count(v) == 0 && seen.count(v) == 0) {
+ if (inClause.count(v) == 0 && seen.count(v) == 0) {
removedDfs(v, removedSet, removeStack, inClause, seen);
}
}
- if(seen.count(lit) == 0) {
+ if (seen.count(lit) == 0) {
seen.insert(lit);
removeStack.push_back(lit);
}
}
template <class Solver>
-void TSatProof<Solver>::removeRedundantFromRes(ResChain<Solver>* res, ClauseId id) {
+void TSatProof<Solver>::removeRedundantFromRes(ResChain<Solver>* res,
+ ClauseId id) {
LitSet* removed = res->getRedundant();
if (removed == NULL) {
return;
@@ -628,11 +686,12 @@ void TSatProof<Solver>::removeRedundantFromRes(ResChain<Solver>* res, ClauseId i
LitVector removeStack;
LitSet seen;
- for (typename LitSet::iterator it = removed->begin(); it != removed->end(); ++it) {
+ for (typename LitSet::iterator it = removed->begin(); it != removed->end();
+ ++it) {
removedDfs(*it, removed, removeStack, inClause, seen);
}
- for (int i = removeStack.size()-1; i >= 0; --i) {
+ for (int i = removeStack.size() - 1; i >= 0; --i) {
typename Solver::TLit lit = removeStack[i];
typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
ClauseId reason_id;
@@ -655,41 +714,50 @@ void TSatProof<Solver>::registerResolution(ClauseId id, ResChain<Solver>* res) {
removeRedundantFromRes(res, id);
Assert(res->redundantRemoved());
- d_resChains[id] = res;
- if(Debug.isOn("proof:sat")) {
+ // Because the SAT solver can add the same clause multiple times, it
+ // could be the case that a resolution chain for this clause already
+ // exists (e.g. when removing units in addClause).
+ if (hasResolutionChain(id)) {
+ ResChain<Solver>* current = d_resolutionChains.find(id)->second;
+ delete current;
+ d_resolutionChains.erase(id);
+ }
+ Assert(!hasResolutionChain(id));
+
+ d_resolutionChains.insert(std::make_pair(id, res));
+ if (Debug.isOn("proof:sat")) {
printRes(id);
}
- if(d_checkRes) {
+ if (d_checkRes) {
Assert(checkResolution(id));
}
- PSTATS(
- d_statistics.d_resChainLengths << ((uint64_t)res->getSteps().size());
- d_statistics.d_avgChainLength.addEntry((uint64_t)res->getSteps().size());
- ++(d_statistics.d_numLearnedClauses);
- )
+ PSTATS(uint64_t resolutionSteps =
+ static_cast<uint64_t>(res.getSteps().size());
+ d_statistics.d_resChainLengths << resolutionSteps;
+ d_statistics.d_avgChainLength.addEntry(resolutionSteps);
+ ++(d_statistics.d_numLearnedClauses);)
}
-
/// recording resolutions
template <class Solver>
void TSatProof<Solver>::startResChain(typename Solver::TCRef start) {
- ClauseId id = getClauseId(start);
- ResChain<Solver>* res = new ResChain<Solver>(id);
+ ClauseId id = getClauseIdForCRef(start);
+ ResolutionChain* res = new ResolutionChain(id);
d_resStack.push_back(res);
}
template <class Solver>
void TSatProof<Solver>::startResChain(typename Solver::TLit start) {
ClauseId id = getUnitId(start);
- ResChain<Solver>* res = new ResChain<Solver>(id);
+ ResolutionChain* res = new ResolutionChain(id);
d_resStack.push_back(res);
}
-
template <class Solver>
void TSatProof<Solver>::addResolutionStep(typename Solver::TLit lit,
- typename Solver::TCRef clause, bool sign) {
+ typename Solver::TCRef clause,
+ bool sign) {
ClauseId id = registerClause(clause, LEARNT);
ResChain<Solver>* res = d_resStack.back();
res->addStep(lit, id, sign);
@@ -697,14 +765,13 @@ void TSatProof<Solver>::addResolutionStep(typename Solver::TLit lit,
template <class Solver>
void TSatProof<Solver>::endResChain(ClauseId id) {
- Debug("proof:sat:detailed") <<"endResChain " << id << "\n";
+ Debug("proof:sat:detailed") << "endResChain " << id << "\n";
Assert(d_resStack.size() > 0);
ResChain<Solver>* res = d_resStack.back();
registerResolution(id, res);
d_resStack.pop_back();
}
-
// template <class Solver>
// void TSatProof<Solver>::endResChain(typename Solver::TCRef clause) {
// Assert(d_resStack.size() > 0);
@@ -718,25 +785,25 @@ template <class Solver>
void TSatProof<Solver>::endResChain(typename Solver::TLit lit) {
Assert(d_resStack.size() > 0);
ClauseId id = registerUnitClause(lit, LEARNT);
- Debug("proof:sat:detailed") <<"endResChain unit " << id << "\n";
- ResChain<Solver>* res = d_resStack.back();
+ Debug("proof:sat:detailed") << "endResChain unit " << id << "\n";
+ ResolutionChain* res = d_resStack.back();
d_glueMap[id] = 1;
registerResolution(id, res);
d_resStack.pop_back();
}
-
template <class Solver>
void TSatProof<Solver>::cancelResChain() {
Assert(d_resStack.size() > 0);
+ ResolutionChain* back = d_resStack.back();
+ delete back;
d_resStack.pop_back();
}
-
template <class Solver>
void TSatProof<Solver>::storeLitRedundant(typename Solver::TLit lit) {
Assert(d_resStack.size() > 0);
- ResChain<Solver>* res = d_resStack.back();
+ ResolutionChain* res = d_resStack.back();
res->addRedundantLit(lit);
}
@@ -755,9 +822,9 @@ void TSatProof<Solver>::storeUnitResolution(typename Solver::TLit lit) {
template <class Solver>
ClauseId TSatProof<Solver>::resolveUnit(typename Solver::TLit lit) {
// first check if we already have a resolution for lit
- if(isUnit(lit)) {
- ClauseId id = getClauseId(lit);
- Assert(hasResolution(id) || isInputClause(id) || isLemmaClause(id));
+ if (isUnit(lit)) {
+ ClauseId id = getClauseIdForLiteral(lit);
+ Assert(hasResolutionChain(id) || isInputClause(id) || isLemmaClause(id));
return id;
}
typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
@@ -768,12 +835,13 @@ ClauseId TSatProof<Solver>::resolveUnit(typename Solver::TLit lit) {
ResChain<Solver>* res = new ResChain<Solver>(reason_id);
// Here, the call to resolveUnit() can reallocate memory in the
// clause allocator. So reload reason ptr each time.
- typename Solver::TClause* reason = &getClause(reason_ref);
- for (int i = 0;
- i < reason->size();
- i++, reason = &getClause(reason_ref)) {
- typename Solver::TLit l = (*reason)[i];
- if(lit != l) {
+ const typename Solver::TClause& initial_reason = getClause(reason_ref);
+ size_t current_reason_size = initial_reason.size();
+ for (size_t i = 0; i < current_reason_size; i++) {
+ const typename Solver::TClause& current_reason = getClause(reason_ref);
+ current_reason_size = current_reason.size();
+ typename Solver::TLit l = current_reason[i];
+ if (lit != l) {
ClauseId res_id = resolveUnit(~l);
res->addStep(l, res_id, !sign(l));
}
@@ -787,16 +855,19 @@ void TSatProof<Solver>::toStream(std::ostream& out) {
Debug("proof:sat") << "TSatProof<Solver>::printProof\n";
Unimplemented("native proof printing not supported yet");
}
+
template <class Solver>
-ClauseId TSatProof<Solver>::storeUnitConflict(typename Solver::TLit conflict_lit,
- ClauseKind kind) {
+ClauseId TSatProof<Solver>::storeUnitConflict(
+ typename Solver::TLit conflict_lit, ClauseKind kind) {
Debug("cores") << "STORE UNIT CONFLICT" << std::endl;
Assert(!d_storedUnitConflict);
d_unitConflictId = registerUnitClause(conflict_lit, kind);
d_storedUnitConflict = true;
- Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+ Debug("proof:sat:detailed") << "storeUnitConflict " << d_unitConflictId
+ << "\n";
return d_unitConflictId;
}
+
template <class Solver>
void TSatProof<Solver>::finalizeProof(typename Solver::TCRef conflict_ref) {
Assert(d_resStack.size() == 0);
@@ -816,10 +887,10 @@ void TSatProof<Solver>::finalizeProof(typename Solver::TCRef conflict_ref) {
return;
} else {
Assert(!d_storedUnitConflict);
- conflict_id = registerClause(conflict_ref, LEARNT); //FIXME
+ conflict_id = registerClause(conflict_ref, LEARNT); // FIXME
}
- if(Debug.isOn("proof:sat")) {
+ if (Debug.isOn("proof:sat")) {
Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
print(conflict_id);
}
@@ -827,13 +898,13 @@ void TSatProof<Solver>::finalizeProof(typename Solver::TCRef conflict_ref) {
ResChain<Solver>* res = new ResChain<Solver>(conflict_id);
// Here, the call to resolveUnit() can reallocate memory in the
// clause allocator. So reload conflict ptr each time.
- typename Solver::TClause* conflict = &getClause(conflict_ref);
- for (int i = 0;
- i < conflict->size();
- ++i, conflict = &getClause(conflict_ref)) {
- typename Solver::TLit lit = (*conflict)[i];
+ size_t conflict_size = getClause(conflict_ref).size();
+ for (size_t i = 0; i < conflict_size; ++i) {
+ const typename Solver::TClause& conflict = getClause(conflict_ref);
+ typename Solver::TLit lit = conflict[i];
ClauseId res_id = resolveUnit(~lit);
res->addStep(lit, res_id, !sign(lit));
+ conflict_size = conflict.size();
}
registerResolution(d_emptyClauseId, res);
}
@@ -845,12 +916,13 @@ void TSatProof<Solver>::updateCRef(typename Solver::TCRef oldref,
if (d_clauseId.find(oldref) == d_clauseId.end()) {
return;
}
- ClauseId id = getClauseId(oldref);
+ ClauseId id = getClauseIdForCRef(oldref);
Assert(d_temp_clauseId.find(newref) == d_temp_clauseId.end());
Assert(d_temp_idClause.find(id) == d_temp_idClause.end());
d_temp_clauseId[newref] = id;
d_temp_idClause[id] = newref;
}
+
template <class Solver>
void TSatProof<Solver>::finishUpdateCRef() {
d_clauseId.swap(d_temp_clauseId);
@@ -859,10 +931,11 @@ void TSatProof<Solver>::finishUpdateCRef() {
d_idClause.swap(d_temp_idClause);
d_temp_idClause.clear();
}
+
template <class Solver>
void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
- if (d_clauseId.find(clause) != d_clauseId.end()) {
- ClauseId id = getClauseId(clause);
+ if (hasClauseIdForCRef(clause)) {
+ ClauseId id = getClauseIdForCRef(clause);
Assert(d_deleted.find(id) == d_deleted.end());
d_deleted.insert(id);
if (isLemmaClause(id)) {
@@ -875,14 +948,13 @@ void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
}
// template<>
-// void toSatClause< ::BVMinisat::Solver> (const BVMinisat::Solver::TClause& minisat_cl,
+// void toSatClause< ::BVMinisat::Solver> (const BVMinisat::Solver::TClause&
+// minisat_cl,
// prop::SatClause& sat_cl) {
// prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
// }
-
-
template <class Solver>
void TSatProof<Solver>::constructProof(ClauseId conflict) {
collectClauses(conflict);
@@ -894,11 +966,10 @@ std::string TSatProof<Solver>::clauseName(ClauseId id) {
if (isInputClause(id)) {
os << ProofManager::getInputClauseName(id, d_name);
return os.str();
- } else
- if (isLemmaClause(id)) {
+ } else if (isLemmaClause(id)) {
os << ProofManager::getLemmaClauseName(id, d_name);
return os.str();
- }else {
+ } else {
os << ProofManager::getLearntClauseName(id, d_name);
return os.str();
}
@@ -944,17 +1015,15 @@ void TSatProof<Solver>::collectClauses(ClauseId id) {
d_seenLearnt.insert(id);
}
- Assert(d_resChains.find(id) != d_resChains.end());
- ResChain<Solver>* res = d_resChains[id];
- PSTATS(
- d_statistics.d_usedResChainLengths << ((uint64_t)res->getSteps().size());
- d_statistics.d_usedClauseGlue << ((uint64_t) d_glueMap[id]);
- );
- ClauseId start = res->getStart();
+ const ResolutionChain& res = getResolutionChain(id);
+ const typename ResolutionChain::ResSteps& steps = res.getSteps();
+ PSTATS(d_statistics.d_usedResChainLengths
+ << ((uint64_t)steps.size());
+ d_statistics.d_usedClauseGlue << ((uint64_t)d_glueMap[id]););
+ ClauseId start = res.getStart();
collectClauses(start);
- typename ResChain<Solver>::ResSteps steps = res->getSteps();
- for(size_t i = 0; i < steps.size(); i++) {
+ for (size_t i = 0; i < steps.size(); i++) {
collectClauses(steps[i].id);
}
}
@@ -964,28 +1033,27 @@ void TSatProof<Solver>::collectClausesUsed(IdToSatClause& inputs,
IdToSatClause& lemmas) {
inputs = d_seenInputs;
lemmas = d_seenLemmas;
- PSTATS (
- d_statistics.d_numLearnedInProof.setData(d_seenLearnt.size());
- d_statistics.d_numLemmasInProof.setData(d_seenLemmas.size());
- );
+ PSTATS(d_statistics.d_numLearnedInProof.setData(d_seenLearnt.size());
+ d_statistics.d_numLemmasInProof.setData(d_seenLemmas.size()););
}
template <class Solver>
void TSatProof<Solver>::storeClauseGlue(ClauseId clause, int glue) {
- Assert (d_glueMap.find(clause) == d_glueMap.end());
+ Assert(d_glueMap.find(clause) == d_glueMap.end());
d_glueMap.insert(std::make_pair(clause, glue));
}
template <class Solver>
TSatProof<Solver>::Statistics::Statistics(const std::string& prefix)
- : d_numLearnedClauses("satproof::"+prefix+"::NumLearnedClauses", 0)
- , d_numLearnedInProof("satproof::"+prefix+"::NumLearnedInProof", 0)
- , d_numLemmasInProof("satproof::"+prefix+"::NumLemmasInProof", 0)
- , d_avgChainLength("satproof::"+prefix+"::AvgResChainLength")
- , d_resChainLengths("satproof::"+prefix+"::ResChainLengthsHist")
- , d_usedResChainLengths("satproof::"+prefix+"::UsedResChainLengthsHist")
- , d_clauseGlue("satproof::"+prefix+"::ClauseGlueHist")
- , d_usedClauseGlue("satproof::"+prefix+"::UsedClauseGlueHist") {
+ : d_numLearnedClauses("satproof::" + prefix + "::NumLearnedClauses", 0),
+ d_numLearnedInProof("satproof::" + prefix + "::NumLearnedInProof", 0),
+ d_numLemmasInProof("satproof::" + prefix + "::NumLemmasInProof", 0),
+ d_avgChainLength("satproof::" + prefix + "::AvgResChainLength"),
+ d_resChainLengths("satproof::" + prefix + "::ResChainLengthsHist"),
+ d_usedResChainLengths("satproof::" + prefix +
+ "::UsedResChainLengthsHist"),
+ d_clauseGlue("satproof::" + prefix + "::ClauseGlueHist"),
+ d_usedClauseGlue("satproof::" + prefix + "::UsedClauseGlueHist") {
smtStatisticsRegistry()->registerStat(&d_numLearnedClauses);
smtStatisticsRegistry()->registerStat(&d_numLearnedInProof);
smtStatisticsRegistry()->registerStat(&d_numLemmasInProof);
@@ -1008,73 +1076,78 @@ TSatProof<Solver>::Statistics::~Statistics() {
smtStatisticsRegistry()->unregisterStat(&d_usedClauseGlue);
}
-
/// LFSCSatProof class
template <class Solver>
-void LFSCSatProof<Solver>::printResolution(ClauseId id, std::ostream& out, std::ostream& paren) {
+void LFSCSatProof<Solver>::printResolution(ClauseId id, std::ostream& out,
+ std::ostream& paren) {
out << "(satlem_simplify _ _ _ ";
- ResChain<Solver>* res = this->d_resChains[id];
- typename ResChain<Solver>::ResSteps& steps = res->getSteps();
+ const ResChain<Solver>& res = this->getResolutionChain(id);
+ const typename ResChain<Solver>::ResSteps& steps = res.getSteps();
- for (int i = steps.size()-1; i >= 0; i--) {
+ for (int i = steps.size() - 1; i >= 0; i--) {
out << "(";
- out << (steps[i].sign? "R" : "Q") << " _ _ ";
+ out << (steps[i].sign ? "R" : "Q") << " _ _ ";
}
- ClauseId start_id = res->getStart();
+ ClauseId start_id = res.getStart();
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) << " "<<ProofManager::getVarName(v, this->d_name) <<")";
+ for (unsigned i = 0; i < steps.size(); i++) {
+ prop::SatVariable v =
+ prop::MinisatSatSolver::toSatVariable(var(steps[i].lit));
+ 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
+ out << "(\\ " << this->clauseName(id) << "\n"; // bind to lemma name
paren << "))"; // closing parethesis for lemma binding and satlem
}
/// LFSCSatProof class
template <class Solver>
-void LFSCSatProof<Solver>::printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren) {
- Assert (this->isAssumptionConflict(id));
+void LFSCSatProof<Solver>::printAssumptionsResolution(ClauseId id,
+ std::ostream& out,
+ std::ostream& paren) {
+ Assert(this->isAssumptionConflict(id));
// print the resolution proving the assumption conflict
printResolution(id, out, paren);
// resolve out assumptions to prove empty clause
out << "(satlem_simplify _ _ _ ";
- std::vector<typename Solver::TLit>& confl = *(this->d_assumptionConflictsDebug[id]);
+ std::vector<typename Solver::TLit>& confl =
+ *(this->d_assumptionConflictsDebug[id]);
- Assert (confl.size());
+ Assert(confl.size());
for (unsigned i = 0; i < confl.size(); ++i) {
prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
- out <<"(";
- out << (lit.isNegated() ? "Q" : "R") <<" _ _ ";
+ out << "(";
+ out << (lit.isNegated() ? "Q" : "R") << " _ _ ";
}
- out << this->clauseName(id)<< " ";
+ out << this->clauseName(id) << " ";
for (int i = confl.size() - 1; i >= 0; --i) {
prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
prop::SatVariable v = lit.getSatVariable();
- out << "unit"<< v <<" ";
- out << ProofManager::getVarName(v, this->d_name) <<")";
+ out << "unit" << v << " ";
+ out << ProofManager::getVarName(v, this->d_name) << ")";
}
- out <<"(\\ e e)\n";
- paren <<")";
+ out << "(\\ e e)\n";
+ paren << ")";
}
-
template <class Solver>
-void LFSCSatProof<Solver>::printResolutions(std::ostream& out, std::ostream& paren) {
+void LFSCSatProof<Solver>::printResolutions(std::ostream& out,
+ std::ostream& paren) {
Debug("bv-proof") << "; print resolutions" << std::endl;
std::set<ClauseId>::iterator it = this->d_seenLearnt.begin();
- for(; it!= this->d_seenLearnt.end(); ++it) {
- if(*it != this->d_emptyClauseId) {
+ for (; it != this->d_seenLearnt.end(); ++it) {
+ if (*it != this->d_emptyClauseId) {
Debug("bv-proof") << "; print resolution for " << *it << std::endl;
printResolution(*it, out, paren);
}
@@ -1083,29 +1156,29 @@ void LFSCSatProof<Solver>::printResolutions(std::ostream& out, std::ostream& par
}
template <class Solver>
-void LFSCSatProof<Solver>::printResolutionEmptyClause(std::ostream& out, std::ostream& paren) {
+void LFSCSatProof<Solver>::printResolutionEmptyClause(std::ostream& out,
+ std::ostream& paren) {
printResolution(this->d_emptyClauseId, out, paren);
}
-
inline std::ostream& operator<<(std::ostream& out, CVC4::ClauseKind k) {
- switch(k) {
- case CVC4::INPUT:
- out << "INPUT";
- break;
- case CVC4::THEORY_LEMMA:
- out << "THEORY_LEMMA";
- break;
- case CVC4::LEARNT:
- out << "LEARNT";
- break;
- default:
- out << "ClauseKind Unknown! [" << unsigned(k) << "]";
+ switch (k) {
+ case CVC4::INPUT:
+ out << "INPUT";
+ break;
+ case CVC4::THEORY_LEMMA:
+ out << "THEORY_LEMMA";
+ break;
+ case CVC4::LEARNT:
+ out << "LEARNT";
+ break;
+ default:
+ out << "ClauseKind Unknown! [" << unsigned(k) << "]";
}
return out;
}
-}/* CVC4 namespace */
+} /* CVC4 namespace */
#endif /* __CVC4__SAT__PROOF_IMPLEMENTATION_H */
diff --git a/src/proof/skolemization_manager.h b/src/proof/skolemization_manager.h
index de510e514..b026e21c2 100644
--- a/src/proof/skolemization_manager.h
+++ b/src/proof/skolemization_manager.h
@@ -37,7 +37,6 @@ public:
Node getSkolem(Node disequality);
Node getDisequality(Node skolem);
bool isSkolem(Node skolem);
-
void clear();
std::hash_map<Node, Node, NodeHashFunction>::const_iterator begin();
diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp
index 088275b3f..d12b561a6 100644
--- a/src/proof/theory_proof.cpp
+++ b/src/proof/theory_proof.cpp
@@ -19,12 +19,14 @@
#include "base/cvc4_assert.h"
#include "context/context.h"
#include "options/bv_options.h"
+#include "options/proof_options.h"
#include "proof/arith_proof.h"
#include "proof/array_proof.h"
#include "proof/bitvector_proof.h"
#include "proof/clause_id.h"
#include "proof/cnf_proof.h"
#include "proof/proof_manager.h"
+#include "proof/proof_output_channel.h"
#include "proof/proof_utils.h"
#include "proof/sat_proof.h"
#include "proof/uf_proof.h"
@@ -45,77 +47,9 @@
namespace CVC4 {
-unsigned CVC4::LetCount::counter = 0;
+unsigned CVC4::ProofLetCount::counter = 0;
static unsigned LET_COUNT = 1;
-//for proof replay
-class ProofOutputChannel : public theory::OutputChannel {
-public:
- Node d_conflict;
- Proof* d_proof;
- Node d_lemma;
-
- ProofOutputChannel() : d_conflict(), d_proof(NULL) {}
- virtual ~ProofOutputChannel() throw() {}
-
- void conflict(TNode n, Proof* pf) throw() {
- Trace("theory-proof-debug") << "; CONFLICT: " << n << std::endl;
- Assert(d_conflict.isNull());
- Assert(!n.isNull());
- d_conflict = n;
- Assert(pf != NULL);
- d_proof = pf;
- }
- bool propagate(TNode x) throw() {
- Trace("theory-proof-debug") << "got a propagation: " << x << std::endl;
- return true;
- }
- theory::LemmaStatus lemma(TNode n, ProofRule rule, bool, bool, bool) throw() {
- Trace("theory-proof-debug") << "new lemma: " << n << std::endl;
- d_lemma = n;
- return theory::LemmaStatus(TNode::null(), 0);
- }
- theory::LemmaStatus splitLemma(TNode, bool) throw() {
- AlwaysAssert(false);
- return theory::LemmaStatus(TNode::null(), 0);
- }
- void requirePhase(TNode n, bool b) throw() {
- Debug("theory-proof-debug") << "ProofOutputChannel::requirePhase called" << std::endl;
- Trace("theory-proof-debug") << "requirePhase " << n << " " << b << std::endl;
- }
- bool flipDecision() throw() {
- Debug("theory-proof-debug") << "ProofOutputChannel::flipDecision called" << std::endl;
- AlwaysAssert(false);
- return false;
- }
- void setIncomplete() throw() {
- Debug("theory-proof-debug") << "ProofOutputChannel::setIncomplete called" << std::endl;
- AlwaysAssert(false);
- }
-};/* class ProofOutputChannel */
-
-//for proof replay
-class MyPreRegisterVisitor {
- theory::Theory* d_theory;
- __gnu_cxx::hash_set<TNode, TNodeHashFunction> d_visited;
-public:
- typedef void return_type;
- MyPreRegisterVisitor(theory::Theory* theory)
- : d_theory(theory)
- , d_visited()
- {}
- bool alreadyVisited(TNode current, TNode parent) { return d_visited.find(current) != d_visited.end(); }
- void visit(TNode current, TNode parent) {
- if(theory::Theory::theoryOf(current) == d_theory->getId()) {
- //Trace("theory-proof-debug") << "preregister " << current << std::endl;
- d_theory->preRegisterTerm(current);
- d_visited.insert(current);
- }
- }
- void start(TNode node) { }
- void done(TNode node) { }
-}; /* class MyPreRegisterVisitor */
-
TheoryProofEngine::TheoryProofEngine()
: d_registrationCache()
, d_theoryProofTable()
@@ -131,13 +65,12 @@ TheoryProofEngine::~TheoryProofEngine() {
}
}
-
void TheoryProofEngine::registerTheory(theory::Theory* th) {
- if( th ){
+ if (th) {
theory::TheoryId id = th->getId();
if(d_theoryProofTable.find(id) == d_theoryProofTable.end()) {
- Trace("theory-proof-debug") << "; register theory " << id << std::endl;
+ Trace("pf::tp") << "TheoryProofEngine::registerTheory: " << id << std::endl;
if (id == theory::THEORY_UF) {
d_theoryProofTable[id] = new LFSCUFProof((theory::uf::TheoryUF*)th, this);
@@ -147,7 +80,6 @@ void TheoryProofEngine::registerTheory(theory::Theory* th) {
if (id == theory::THEORY_BV) {
BitVectorProof * bvp = new LFSCBitVectorProof((theory::bv::TheoryBV*)th, this);
d_theoryProofTable[id] = bvp;
- ((theory::bv::TheoryBV*)th)->setProofLog( bvp );
return;
}
@@ -166,20 +98,54 @@ void TheoryProofEngine::registerTheory(theory::Theory* th) {
}
}
+void TheoryProofEngine::finishRegisterTheory(theory::Theory* th) {
+ if (th) {
+ theory::TheoryId id = th->getId();
+ if (id == theory::THEORY_BV) {
+ Assert(d_theoryProofTable.find(id) != d_theoryProofTable.end());
+
+ BitVectorProof *bvp = (BitVectorProof *)d_theoryProofTable[id];
+ ((theory::bv::TheoryBV*)th)->setProofLog( bvp );
+ return;
+ }
+ }
+}
+
TheoryProof* TheoryProofEngine::getTheoryProof(theory::TheoryId id) {
+ // The UF theory handles queries for the Builtin theory.
+ if (id == theory::THEORY_BUILTIN) {
+ Debug("pf::tp") << "TheoryProofEngine::getTheoryProof: BUILTIN --> UF" << std::endl;
+ id = theory::THEORY_UF;
+ }
+
Assert (d_theoryProofTable.find(id) != d_theoryProofTable.end());
return d_theoryProofTable[id];
}
+void TheoryProofEngine::markTermForFutureRegistration(Expr term, theory::TheoryId id) {
+ d_exprToTheoryIds[term].insert(id);
+}
+
+void TheoryProofEngine::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+ Assert(c1.isConst());
+ Assert(c2.isConst());
+
+ Assert(theory::Theory::theoryOf(c1) == theory::Theory::theoryOf(c2));
+ getTheoryProof(theory::Theory::theoryOf(c1))->printConstantDisequalityProof(os, c1, c2);
+}
+
void TheoryProofEngine::registerTerm(Expr term) {
+ Debug("pf::tp") << "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") << "TheoryProofEngine::registerTerm: registering NEW term: " << term << std::endl;
theory::TheoryId theory_id = theory::Theory::theoryOf(term);
- Debug("pf::tp") << "Term's theory: " << theory_id << std::endl;
+ Debug("pf::tp") << "Term's theory( " << term << " ) = " << theory_id << std::endl;
// don't need to register boolean terms
if (theory_id == theory::THEORY_BUILTIN ||
@@ -193,58 +159,64 @@ void TheoryProofEngine::registerTerm(Expr term) {
if (!supportedTheory(theory_id)) return;
+ // Register the term with its owner theory
getTheoryProof(theory_id)->registerTerm(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;
+ getTheoryProof(theory::THEORY_ARRAY)->registerTerm(term);
+ }
+
d_registrationCache.insert(term);
}
-theory::TheoryId TheoryProofEngine::getTheoryForLemma(ClauseId id) {
+theory::TheoryId TheoryProofEngine::getTheoryForLemma(const prop::SatClause* clause) {
ProofManager* pm = ProofManager::currentPM();
- Debug("pf::tp") << "TheoryProofEngine::getTheoryForLemma( " << id << " )"
- << " = " << pm->getCnfProof()->getOwnerTheory(id) << std::endl;
+ std::set<Node> nodes;
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
+ Expr atom = node.toExpr();
+ if (atom.isConst()) {
+ Assert (atom == utils::mkTrue());
+ continue;
+ }
- if ((pm->getLogic() == "QF_UFLIA") || (pm->getLogic() == "QF_UFLRA")) {
- Debug("pf::tp") << "TheoryProofEngine::getTheoryForLemma: special hack for Arithmetic-with-holes support. "
- << "Returning THEORY_ARITH" << std::endl;
- return theory::THEORY_ARITH;
+ nodes.insert(lit.isNegated() ? node.notNode() : node);
}
- return pm->getCnfProof()->getOwnerTheory(id);
-
- // if (pm->getLogic() == "QF_UF") return theory::THEORY_UF;
- // if (pm->getLogic() == "QF_BV") return theory::THEORY_BV;
- // if (pm->getLogic() == "QF_AX") return theory::THEORY_ARRAY;
- // if (pm->getLogic() == "ALL_SUPPORTED") return theory::THEORY_BV;
-
- // Debug("pf::tp") << "Unsupported logic (" << pm->getLogic() << ")" << std::endl;
-
- // Unreachable();
+ // Ensure that the lemma is in the database.
+ Assert (pm->getCnfProof()->haveProofRecipe(nodes));
+ return pm->getCnfProof()->getProofRecipe(nodes).getTheory();
}
-void LFSCTheoryProofEngine::bind(Expr term, LetMap& map, Bindings& let_order) {
- LetMap::iterator it = map.find(term);
+void LFSCTheoryProofEngine::bind(Expr term, ProofLetMap& map, Bindings& let_order) {
+ ProofLetMap::iterator it = map.find(term);
if (it != map.end()) {
- LetCount& count = it->second;
+ ProofLetCount& count = it->second;
count.increment();
return;
}
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
bind(term[i], map, let_order);
}
- unsigned new_id = LetCount::newId();
- map[term] = LetCount(new_id);
+ unsigned new_id = ProofLetCount::newId();
+ map[term] = ProofLetCount(new_id);
let_order.push_back(LetOrderElement(term, new_id));
}
void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) {
- LetMap map;
+ ProofLetMap map;
Bindings let_order;
bind(term, map, let_order);
std::ostringstream paren;
for (unsigned i = 0; i < let_order.size(); ++i) {
Expr current_expr = let_order[i].expr;
unsigned let_id = let_order[i].id;
- LetMap::const_iterator it = map.find(current_expr);
+ ProofLetMap::const_iterator it = map.find(current_expr);
Assert (it != map.end());
unsigned let_count = it->second.count;
Assert(let_count);
@@ -253,7 +225,7 @@ void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) {
continue;
}
- os << "(@ let"<<let_id << " ";
+ os << "(@ let" <<let_id << " ";
printTheoryTerm(current_expr, os, map);
paren <<")";
}
@@ -264,16 +236,13 @@ void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) {
printTheoryTerm(last, os, map);
}
else {
- os << " let"<< last_let_id;
+ os << " let" << last_let_id;
}
os << paren.str();
}
-
-void LFSCTheoryProofEngine::printTheoryTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCTheoryProofEngine::printTheoryTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
theory::TheoryId theory_id = theory::Theory::theoryOf(term);
- Debug("pf::tp") << std::endl << "LFSCTheoryProofEngine::printTheoryTerm: term = " << term
- << ", theory_id = " << theory_id << std::endl;
// boolean terms and ITEs are special because they
// are common to all theories
@@ -315,6 +284,29 @@ void LFSCTheoryProofEngine::printSort(Type type, std::ostream& os) {
Unreachable();
}
+void LFSCTheoryProofEngine::performExtraRegistrations() {
+ ExprToTheoryIds::const_iterator it;
+ for (it = d_exprToTheoryIds.begin(); it != d_exprToTheoryIds.end(); ++it) {
+ if (d_registrationCache.count(it->first)) { // Only register if the term appeared
+ TheoryIdSet::const_iterator theoryIt;
+ for (theoryIt = it->second.begin(); theoryIt != it->second.end(); ++theoryIt) {
+ Debug("pf::tp") << "\tExtra registration of term " << it->first
+ << " with theory: " << *theoryIt << std::endl;
+ Assert(supportedTheory(*theoryIt));
+ getTheoryProof(*theoryIt)->registerTerm(it->first);
+ }
+ }
+ }
+}
+
+void LFSCTheoryProofEngine::treatBoolsAsFormulas(bool value) {
+ TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
+ TheoryProofTable::const_iterator end = d_theoryProofTable.end();
+ for (; it != end; ++it) {
+ it->second->treatBoolsAsFormulas(value);
+ }
+}
+
void LFSCTheoryProofEngine::registerTermsFromAssertions() {
ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
@@ -322,6 +314,8 @@ void LFSCTheoryProofEngine::registerTermsFromAssertions() {
for(; it != end; ++it) {
registerTerm(*it);
}
+
+ performExtraRegistrations();
}
void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& paren) {
@@ -333,17 +327,51 @@ void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& pare
for (; it != end; ++it) {
Debug("pf::tp") << "printAssertions: assertion is: " << *it << std::endl;
- // FIXME: merge this with counter
- os << "(% A" << counter++ << " (th_holds ";
- printLetTerm(*it, os);
+ std::ostringstream name;
+ name << "A" << counter++;
+ os << "(% " << name.str() << " (th_holds ";
+
+ // Assertions appear before the global let map, so we use a dummpMap to avoid letification here.
+ ProofLetMap dummyMap;
+ printBoundTerm(*it, os, dummyMap);
+
os << ")\n";
paren << ")";
}
- //store map between assertion and counter
- // ProofManager::currentPM()->setAssertion( *it );
+
Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions done" << std::endl << std::endl;
}
+void LFSCTheoryProofEngine::printLemmaRewrites(NodePairSet& rewrites,
+ std::ostream& os,
+ std::ostream& paren) {
+ Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites called" << std::endl << std::endl;
+
+ NodePairSet::const_iterator it;
+
+ for (it = rewrites.begin(); it != rewrites.end(); ++it) {
+ Debug("pf::tp") << "printLemmaRewrites: " << it->first << " --> " << it->second << std::endl;
+
+ Node n1 = it->first;
+ Node n2 = it->second;
+ Assert(n1.toExpr() == utils::mkFalse() ||
+ theory::Theory::theoryOf(n1) == theory::Theory::theoryOf(n2));
+
+ std::ostringstream rewriteRule;
+ rewriteRule << ".lrr" << d_assertionToRewrite.size();
+
+ os << "(th_let_pf _ ";
+ getTheoryProof(theory::Theory::theoryOf(n1))->printRewriteProof(os, n1, n2);
+ os << "(\\ " << rewriteRule.str() << "\n";
+
+ d_assertionToRewrite[it->first] = rewriteRule.str();
+ Debug("pf::tp") << "d_assertionToRewrite[" << it->first << "] = " << rewriteRule.str() << std::endl;
+ paren << "))";
+ }
+
+ Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites done" << std::endl << std::endl;
+}
+
void LFSCTheoryProofEngine::printSortDeclarations(std::ostream& os, std::ostream& paren) {
Debug("pf::tp") << "LFSCTheoryProofEngine::printSortDeclarations called" << std::endl << std::endl;
@@ -378,55 +406,150 @@ void LFSCTheoryProofEngine::printDeferredDeclarations(std::ostream& os, std::ost
}
}
-void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
- std::ostream& os,
- std::ostream& paren) {
- os << " ;; Theory Lemmas \n";
- ProofManager* pm = ProofManager::currentPM();
- IdToSatClause::const_iterator it = lemmas.begin();
- IdToSatClause::const_iterator end = lemmas.end();
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: checking lemma owners..." << std::endl;
+void LFSCTheoryProofEngine::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+ 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) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: new lemma" << std::endl;
- ClauseId id = it->first;
- Debug("pf::tp") << "\tLemma = " << id
- << ". Owner theory: " << pm->getCnfProof()->getOwnerTheory(id) << std::endl;
+ it->second->printAliasingDeclarations(os, paren);
}
- it = lemmas.begin();
+}
- // BitVector theory is special case: must know all
- // conflicts needed ahead of time for resolution
- // proof lemmas
- std::vector<Expr> bv_lemmas;
- for (; it != end; ++it) {
+void LFSCTheoryProofEngine::dumpTheoryLemmas(const IdToSatClause& lemmas) {
+ Debug("pf::dumpLemmas") << "Dumping ALL theory lemmas" << std::endl << std::endl;
+
+ ProofManager* pm = ProofManager::currentPM();
+ for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
ClauseId id = it->first;
+ Debug("pf::dumpLemmas") << "**** \tLemma ID = " << id << std::endl;
const prop::SatClause* clause = it->second;
+ std::set<Node> nodes;
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
+ if (node.isConst()) {
+ Assert (node.toExpr() == utils::mkTrue());
+ continue;
+ }
+ nodes.insert(lit.isNegated() ? node.notNode() : node);
+ }
+
+ LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(nodes);
+ recipe.dump("pf::dumpLemmas");
+ }
+
+ Debug("pf::dumpLemmas") << "Theory lemma printing DONE" << std::endl << std::endl;
+}
- theory::TheoryId theory_id = getTheoryForLemma(id);
- if (theory_id != theory::THEORY_BV) continue;
+// TODO: this function should be moved into the BV prover.
+void LFSCTheoryProofEngine::finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os) {
+ // BitVector theory is special case: must know all conflicts needed
+ // ahead of time for resolution proof lemmas
+ std::vector<Expr> bv_lemmas;
+
+ for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
+ const prop::SatClause* clause = it->second;
std::vector<Expr> conflict;
+ std::set<Node> conflictNodes;
for(unsigned i = 0; i < clause->size(); ++i) {
prop::SatLiteral lit = (*clause)[i];
- Expr atom = pm->getCnfProof()->getAtom(lit.getSatVariable()).toExpr();
+ Node node = ProofManager::currentPM()->getCnfProof()->getAtom(lit.getSatVariable());
+ Expr atom = node.toExpr();
+
+ // The literals (true) and (not false) are omitted from conflicts
if (atom.isConst()) {
Assert (atom == utils::mkTrue() ||
(atom == utils::mkFalse() && lit.isNegated()));
continue;
}
+
Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
conflict.push_back(expr_lit);
+ conflictNodes.insert(lit.isNegated() ? node.notNode() : node);
+ }
+
+ LemmaProofRecipe recipe = ProofManager::currentPM()->getCnfProof()->getProofRecipe(conflictNodes);
+
+ unsigned numberOfSteps = recipe.getNumSteps();
+
+ prop::SatClause currentClause = *clause;
+ std::vector<Expr> currentClauseExpr = conflict;
+
+ for (unsigned i = 0; i < numberOfSteps; ++i) {
+ const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i);
+
+ if (currentStep->getTheory() != theory::THEORY_BV) {
+ continue;
+ }
+
+ // If any rewrites took place, we need to update the conflict clause accordingly
+ std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i);
+ std::map<Node, Node> explanationToMissingAssertion;
+ std::set<Node>::iterator assertionIt;
+ for (assertionIt = missingAssertions.begin();
+ assertionIt != missingAssertions.end();
+ ++assertionIt) {
+ Node negated = (*assertionIt).negate();
+ explanationToMissingAssertion[recipe.getExplanation(negated)] = negated;
+ }
+
+ currentClause = *clause;
+ currentClauseExpr = conflict;
+
+ for (unsigned j = 0; j < i; ++j) {
+ // Literals already used in previous steps need to be negated
+ Node previousLiteralNode = recipe.getStep(j)->getLiteral();
+
+ // If this literal is the result of a rewrite, we need to translate it
+ if (explanationToMissingAssertion.find(previousLiteralNode) !=
+ explanationToMissingAssertion.end()) {
+ previousLiteralNode = explanationToMissingAssertion[previousLiteralNode];
+ }
+
+ Node previousLiteralNodeNegated = previousLiteralNode.negate();
+ prop::SatLiteral previousLiteralNegated =
+ ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated);
+
+ currentClause.push_back(previousLiteralNegated);
+ currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr());
+ }
+
+ // If we're in the final step, the last literal is Null and should not be added.
+ // Otherwise, the current literal does NOT need to be negated
+ Node currentLiteralNode = currentStep->getLiteral();
+
+ if (currentLiteralNode != Node()) {
+ prop::SatLiteral currentLiteral =
+ ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode);
+
+ currentClause.push_back(currentLiteral);
+ currentClauseExpr.push_back(currentLiteralNode.toExpr());
+ }
+
+ bv_lemmas.push_back(utils::mkSortedExpr(kind::OR, currentClauseExpr));
}
- bv_lemmas.push_back(utils::mkSortedExpr(kind::OR, conflict));
}
- // FIXME: ugly, move into bit-vector proof by adding lemma
- // queue inside each theory_proof
+
BitVectorProof* bv = ProofManager::getBitVectorProof();
bv->finalizeConflicts(bv_lemmas);
+ // bv->printResolutionProof(os, paren, letMap);
+}
- bv->printResolutionProof(os, paren);
+void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
+ std::ostream& os,
+ std::ostream& paren,
+ ProofLetMap& map) {
+ os << " ;; Theory Lemmas \n";
+ Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: starting" << std::endl;
+
+ if (Debug.isOn("pf::dumpLemmas")) {
+ dumpTheoryLemmas(lemmas);
+ }
+
+ // finalizeBvConflicts(lemmas, os, paren, map);
+ ProofManager::getBitVectorProof()->printResolutionProof(os, paren, map);
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
Assert (lemmas.size() == 1);
@@ -434,61 +557,255 @@ void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
return;
}
- it = lemmas.begin();
-
+ ProofManager* pm = ProofManager::currentPM();
Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemmas..." << std::endl;
- for (; it != end; ++it) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing a new lemma!" << std::endl;
-
- // Debug("pf::tp") << "\tLemma = " << it->first << ", " << *(it->second) << std::endl;
+ for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
ClauseId id = it->first;
- Debug("pf::tp") << "Owner theory:" << pm->getCnfProof()->getOwnerTheory(id) << std::endl;
const prop::SatClause* clause = it->second;
- // printing clause as it appears in resolution proof
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
- Debug("pf::tp") << "CnfProof printing clause..." << std::endl;
- pm->getCnfProof()->printClause(*clause, os, clause_paren);
- Debug("pf::tp") << "CnfProof printing clause - Done!" << std::endl;
+ Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemma. ID = "
+ << id << std::endl;
std::vector<Expr> clause_expr;
+ std::set<Node> clause_expr_nodes;
for(unsigned i = 0; i < clause->size(); ++i) {
prop::SatLiteral lit = (*clause)[i];
- Expr atom = pm->getCnfProof()->getAtom(lit.getSatVariable()).toExpr();
+ Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
+ Expr atom = node.toExpr();
if (atom.isConst()) {
Assert (atom == utils::mkTrue());
continue;
}
Expr expr_lit = lit.isNegated() ? atom.notExpr(): atom;
clause_expr.push_back(expr_lit);
+ clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node);
}
- Debug("pf::tp") << "Expression printing done!" << std::endl;
-
- // query appropriate theory for proof of clause
- theory::TheoryId theory_id = getTheoryForLemma(id);
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl;
- Debug("theory-proof-debug") << ";; Get theory lemma from " << theory_id << "..." << std::endl;
- getTheoryProof(theory_id)->printTheoryLemmaProof(clause_expr, os, paren);
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl;
- // os << " (clausify_false trust)";
- os << clause_paren.str();
- os << "( \\ " << pm->getLemmaClauseName(id) <<"\n";
- paren << "))";
+ LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(clause_expr_nodes);
+
+ if (recipe.simpleLemma()) {
+ // In a simple lemma, there will be no propositional resolution in the end
+
+ Debug("pf::tp") << "Simple lemma" << std::endl;
+ // Printing the clause as it appears in resolution proof
+ os << "(satlem _ _ ";
+ std::ostringstream clause_paren;
+ pm->getCnfProof()->printClause(*clause, os, clause_paren);
+
+ // Find and handle missing assertions, due to rewrites
+ std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(0);
+ if (!missingAssertions.empty()) {
+ Debug("pf::tp") << "Have missing assertions for this simple lemma!" << std::endl;
+ }
+
+ std::set<Node>::const_iterator missingAssertion;
+ for (missingAssertion = missingAssertions.begin();
+ missingAssertion != missingAssertions.end();
+ ++missingAssertion) {
+
+ Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl;
+ Assert(recipe.wasRewritten(missingAssertion->negate()));
+ Node explanation = recipe.getExplanation(missingAssertion->negate()).negate();
+ Debug("pf::tp") << "Found explanation: " << explanation << std::endl;
+
+ // We have a missing assertion.
+ // rewriteIt->first is the assertion after the rewrite (the explanation),
+ // rewriteIt->second is the original assertion that needs to be fed into the theory.
+
+ bool found = false;
+ unsigned k;
+ for (k = 0; k < clause_expr.size(); ++k) {
+ if (clause_expr[k] == explanation.toExpr()) {
+ found = true;
+ break;
+ }
+ }
+
+ AlwaysAssert(found);
+ Debug("pf::tp") << "Replacing theory assertion "
+ << clause_expr[k]
+ << " with "
+ << *missingAssertion
+ << std::endl;
+
+ 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 << "))";
+
+ Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
+ << pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
+ << std::endl << std::endl;
+
+ pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
+ }
+
+ // Query the appropriate theory for a proof of this clause
+ theory::TheoryId theory_id = getTheoryForLemma(clause);
+ Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl;
+ getTheoryProof(theory_id)->printTheoryLemmaProof(clause_expr, os, paren, map);
+
+ // Turn rewrite filter OFF
+ pm->clearRewriteFilters();
+
+ Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl;
+ os << clause_paren.str();
+ os << "( \\ " << pm->getLemmaClauseName(id) <<"\n";
+ paren << "))";
+ } else { // This is a composite lemma
+
+ unsigned numberOfSteps = recipe.getNumSteps();
+ prop::SatClause currentClause = *clause;
+ std::vector<Expr> currentClauseExpr = clause_expr;
+
+ for (unsigned i = 0; i < numberOfSteps; ++i) {
+ const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i);
+
+ currentClause = *clause;
+ currentClauseExpr = clause_expr;
+
+ for (unsigned j = 0; j < i; ++j) {
+ // Literals already used in previous steps need to be negated
+ Node previousLiteralNode = recipe.getStep(j)->getLiteral();
+ Node previousLiteralNodeNegated = previousLiteralNode.negate();
+ prop::SatLiteral previousLiteralNegated =
+ ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated);
+ currentClause.push_back(previousLiteralNegated);
+ currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr());
+ }
+
+ // If the current literal is NULL, can ignore (final step)
+ // Otherwise, the current literal does NOT need to be negated
+ Node currentLiteralNode = currentStep->getLiteral();
+ if (currentLiteralNode != Node()) {
+ prop::SatLiteral currentLiteral =
+ ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode);
+
+ currentClause.push_back(currentLiteral);
+ currentClauseExpr.push_back(currentLiteralNode.toExpr());
+ }
+
+ os << "(satlem _ _ ";
+ std::ostringstream clause_paren;
+
+ pm->getCnfProof()->printClause(currentClause, os, clause_paren);
+
+ // query appropriate theory for proof of clause
+ theory::TheoryId theory_id = currentStep->getTheory();
+ Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl;
+
+ std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i);
+ if (!missingAssertions.empty()) {
+ Debug("pf::tp") << "Have missing assertions for this step!" << std::endl;
+ }
+
+ // Turn rewrite filter ON
+ std::set<Node>::const_iterator missingAssertion;
+ for (missingAssertion = missingAssertions.begin();
+ missingAssertion != missingAssertions.end();
+ ++missingAssertion) {
+
+ Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl;
+
+ Assert(recipe.wasRewritten(missingAssertion->negate()));
+ Node explanation = recipe.getExplanation(missingAssertion->negate()).negate();
+
+ Debug("pf::tp") << "Found explanation: " << explanation << std::endl;
+
+ // We have a missing assertion.
+ // rewriteIt->first is the assertion after the rewrite (the explanation),
+ // rewriteIt->second is the original assertion that needs to be fed into the theory.
+
+ bool found = false;
+ unsigned k;
+ for (k = 0; k < currentClauseExpr.size(); ++k) {
+ if (currentClauseExpr[k] == explanation.toExpr()) {
+ found = true;
+ break;
+ }
+ }
+
+ AlwaysAssert(found);
+
+ Debug("pf::tp") << "Replacing theory assertion "
+ << currentClauseExpr[k]
+ << " with "
+ << *missingAssertion
+ << std::endl;
+
+ 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 << "))";
+
+ Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
+ << pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
+ << std::endl << std::endl;
+
+ pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
+ }
+
+ getTheoryProof(theory_id)->printTheoryLemmaProof(currentClauseExpr, os, paren, map);
+
+ // Turn rewrite filter OFF
+ pm->clearRewriteFilters();
+
+ Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl;
+ os << clause_paren.str();
+ os << "( \\ " << pm->getLemmaClauseName(id) << "s" << i <<"\n";
+ paren << "))";
+ }
+
+ Assert(numberOfSteps >= 2);
+
+ os << "(satlem_simplify _ _ _ ";
+ for (unsigned i = 0; i < numberOfSteps - 1; ++i) {
+ // Resolve step i with step i + 1
+ if (recipe.getStep(i)->getLiteral().getKind() == kind::NOT) {
+ os << "(Q _ _ ";
+ } else {
+ os << "(R _ _ ";
+ }
+
+ os << pm->getLemmaClauseName(id) << "s" << i;
+ os << " ";
+ }
+
+ os << pm->getLemmaClauseName(id) << "s" << numberOfSteps - 1 << " ";
+
+ prop::SatLiteral v;
+ for (int i = numberOfSteps - 2; i >= 0; --i) {
+ v = ProofManager::currentPM()->getCnfProof()->getLiteral(recipe.getStep(i)->getLiteral());
+ os << ProofManager::getVarName(v.getSatVariable(), "") << ") ";
+ }
+
+ os << "( \\ " << pm->getLemmaClauseName(id) << "\n";
+ paren << "))";
+ }
}
}
-void LFSCTheoryProofEngine::printBoundTerm(Expr term, std::ostream& os, const LetMap& map) {
- // Debug("pf::tp") << "LFSCTheoryProofEngine::printBoundTerm( " << term << " ) " << std::endl;
+void LFSCTheoryProofEngine::printBoundTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
+ Debug("pf::tp") << "LFSCTheoryProofEngine::printBoundTerm( " << term << " ) " << std::endl;
- LetMap::const_iterator it = map.find(term);
+ ProofLetMap::const_iterator it = map.find(term);
if (it != map.end()) {
unsigned id = it->second.id;
unsigned count = it->second.count;
+
if (count > LET_COUNT) {
- os <<"let"<<id;
+ os << "let" << id;
return;
}
}
@@ -496,7 +813,7 @@ void LFSCTheoryProofEngine::printBoundTerm(Expr term, std::ostream& os, const Le
printTheoryTerm(term, os, map);
}
-void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
if (term.isVariable()) {
os << ProofManager::sanitize(term);
return;
@@ -596,20 +913,25 @@ void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const Let
}
-void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
- //default method for replaying proofs: assert (negated) literals back to a fresh copy of the theory
- Assert( d_theory!=NULL );
+void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
+ std::ostream& os,
+ std::ostream& paren,
+ const ProofLetMap& map) {
+ // Default method for replaying proofs: assert (negated) literals back to a fresh copy of the theory
+ Assert(d_theory!=NULL);
+
context::UserContext fakeContext;
ProofOutputChannel oc;
theory::Valuation v(NULL);
//make new copy of theory
theory::Theory* th;
- Trace("theory-proof-debug") << ";; Print theory lemma proof, theory id = " << d_theory->getId() << std::endl;
- if(d_theory->getId()==theory::THEORY_UF) {
+ Trace("pf::tp") << ";; Print theory lemma proof, theory id = " << d_theory->getId() << std::endl;
+
+ if (d_theory->getId()==theory::THEORY_UF) {
th = new theory::uf::TheoryUF(&fakeContext, &fakeContext, oc, v,
ProofManager::currentPM()->getLogicInfo(),
"replay::");
- } else if(d_theory->getId()==theory::THEORY_ARRAY) {
+ } else if (d_theory->getId()==theory::THEORY_ARRAY) {
th = new theory::arrays::TheoryArrays(&fakeContext, &fakeContext, oc, v,
ProofManager::currentPM()->getLogicInfo(),
"replay::");
@@ -626,11 +948,15 @@ void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream&
Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - th->ProduceProofs() DONE" << std::endl;
MyPreRegisterVisitor preRegVisitor(th);
- for( unsigned i=0; i<lemma.size(); i++ ){
- Node lit = Node::fromExpr( lemma[i] ).negate();
- Trace("pf::tp") << "; preregistering and asserting " << lit << std::endl;
- NodeVisitor<MyPreRegisterVisitor>::run(preRegVisitor, lit);
- th->assertFact(lit, false);
+ for (unsigned i=0; i<lemma.size(); i++) {
+ Node strippedLit = (lemma[i].getKind() == kind::NOT) ? lemma[i][0] : lemma[i];
+ if (strippedLit.getKind() == kind::EQUAL ||
+ d_theory->getId() == theory::Theory::theoryOf(strippedLit)) {
+ Node lit = Node::fromExpr( lemma[i] ).negate();
+ Trace("pf::tp") << "; preregistering and asserting " << lit << std::endl;
+ NodeVisitor<MyPreRegisterVisitor>::run(preRegVisitor, lit);
+ th->assertFact(lit, false);
+ }
}
Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - calling th->check()" << std::endl;
@@ -679,7 +1005,7 @@ void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream&
th->check(theory::Theory::EFFORT_FULL);
}
Debug("pf::tp") << "Calling oc.d_proof->toStream(os)" << std::endl;
- oc.d_proof->toStream(os);
+ oc.d_proof->toStream(os, map);
Debug("pf::tp") << "Calling oc.d_proof->toStream(os) -- DONE!" << std::endl;
Debug("pf::tp") << "About to delete the theory solver used for proving the lemma... " << std::endl;
@@ -711,10 +1037,13 @@ void BooleanProof::registerTerm(Expr term) {
}
}
-void LFSCBooleanProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCBooleanProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
Assert (term.getType().isBoolean());
if (term.isVariable()) {
- os << "(p_app " << ProofManager::sanitize(term) <<")";
+ if (d_treatBoolsAsFormulas)
+ os << "(p_app " << ProofManager::sanitize(term) <<")";
+ else
+ os << ProofManager::sanitize(term);
return;
}
@@ -722,6 +1051,32 @@ void LFSCBooleanProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap&
switch(k) {
case kind::OR:
case kind::AND:
+ if (options::lfscLetification() && term.getNumChildren() > 2) {
+ // If letification is on, the entire term is probably a let expression.
+ // However, we need to transform it from (and a b c) into (and a (and b c)) form first.
+ Node currentExpression = term[term.getNumChildren() - 1];
+ for (int i = term.getNumChildren() - 2; i >= 0; --i) {
+ NodeBuilder<> builder(k);
+ builder << term[i];
+ builder << currentExpression.toExpr();
+ currentExpression = builder;
+ }
+
+ // The let map should already have the current expression.
+ ProofLetMap::const_iterator it = map.find(term);
+ if (it != map.end()) {
+ unsigned id = it->second.id;
+ unsigned count = it->second.count;
+
+ if (count > LET_COUNT) {
+ os << "let" << id;
+ break;
+ }
+ }
+ }
+
+ // If letification is off or there were 2 children, same treatment as the other cases.
+ // (No break is intentional).
case kind::XOR:
case kind::IFF:
case kind::IMPLIES:
@@ -753,7 +1108,10 @@ void LFSCBooleanProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap&
return;
case kind::CONST_BOOLEAN:
- os << (term.getConst<bool>() ? "true" : "false");
+ if (d_treatBoolsAsFormulas)
+ os << (term.getConst<bool>() ? "true" : "false");
+ else
+ os << (term.getConst<bool>() ? "t_true" : "t_false");
return;
default:
@@ -786,10 +1144,36 @@ void LFSCBooleanProof::printDeferredDeclarations(std::ostream& os, std::ostream&
// Nothing to do here at this point.
}
+void LFSCBooleanProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+ // Nothing to do here at this point.
+}
+
void LFSCBooleanProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
std::ostream& os,
std::ostream& paren) {
Unreachable("No boolean lemmas yet!");
}
+void TheoryProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2) {
+ // 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);
+ os << " ";
+ d_proofEngine->printBoundTerm(c2, os, emptyMap);
+ os << ")))";
+}
+
+void TheoryProof::printRewriteProof(std::ostream& os, const Node &n1, const Node &n2) {
+ // This is the default for a rewrite proof: just a trust statement.
+ ProofLetMap emptyMap;
+ os << "(trust_f (iff ";
+ d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap);
+ os << " ";
+ d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap);
+ os << "))";
+}
+
} /* namespace CVC4 */
diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h
index 54c86f3f3..5907f9bd5 100644
--- a/src/proof/theory_proof.h
+++ b/src/proof/theory_proof.h
@@ -27,6 +27,7 @@
#include "proof/clause_id.h"
#include "prop/sat_solver_types.h"
#include "util/proof.h"
+#include "proof/proof_utils.h"
namespace CVC4 {
@@ -34,66 +35,21 @@ namespace theory {
class Theory;
} /* namespace CVC4::theory */
-struct LetCount {
- static unsigned counter;
- static void resetCounter() { counter = 0; }
- static unsigned newId() { return ++counter; }
-
- unsigned count;
- unsigned id;
- LetCount()
- : count(0)
- , id(-1)
- {}
-
- void increment() { ++count; }
- LetCount(unsigned i)
- : count(1)
- , id(i)
- {}
- LetCount(const LetCount& other)
- : count(other.count)
- , id (other.id)
- {}
- bool operator==(const LetCount &other) const {
- return other.id == id && other.count == count;
- }
- LetCount& operator=(const LetCount &rhs) {
- if (&rhs == this) return *this;
- id = rhs.id;
- count = rhs.count;
- return *this;
- }
-};
-
-struct LetOrderElement {
- Expr expr;
- unsigned id;
- LetOrderElement(Expr e, unsigned i)
- : expr(e)
- , id(i)
- {}
-
- LetOrderElement()
- : expr()
- , id(-1)
- {}
-};
-
typedef __gnu_cxx::hash_map < ClauseId, prop::SatClause* > IdToSatClause;
-typedef __gnu_cxx::hash_map<Expr, LetCount, ExprHashFunction> LetMap;
-typedef std::vector<LetOrderElement> Bindings;
-
class TheoryProof;
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
typedef std::map<theory::TheoryId, TheoryProof* > TheoryProofTable;
+typedef std::set<theory::TheoryId> TheoryIdSet;
+typedef std::map<Expr, TheoryIdSet> ExprToTheoryIds;
+
class TheoryProofEngine {
protected:
ExprSet d_registrationCache;
TheoryProofTable d_theoryProofTable;
+ ExprToTheoryIds d_exprToTheoryIds;
/**
* Returns whether the theory is currently supported in proof
@@ -113,7 +69,7 @@ public:
*/
virtual void printLetTerm(Expr term, std::ostream& os) = 0;
virtual void printBoundTerm(Expr term, std::ostream& os,
- const LetMap& map) = 0;
+ const ProofLetMap& map) = 0;
/**
* Print the proof representation of the given sort.
@@ -148,6 +104,14 @@ public:
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0;
/**
+ * Print aliasing declarations.
+ *
+ * @param os
+ * @param paren closing parenthesis
+ */
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren) = 0;
+
+ /**
* Print proofs of all the theory lemmas (must prove
* actual clause used in resolution proof).
*
@@ -155,7 +119,7 @@ public:
* @param paren
*/
virtual void printTheoryLemmas(const IdToSatClause& lemmas, std::ostream& os,
- std::ostream& paren) = 0;
+ std::ostream& paren, ProofLetMap& map) = 0;
/**
* Register theory atom (ensures all terms and atoms are declared).
@@ -166,35 +130,67 @@ public:
/**
* Ensures that a theory proof class for the given theory is created.
+ * This method can be invoked regardless of whether the "proof" option
+ * has been set.
*
* @param theory
*/
void registerTheory(theory::Theory* theory);
+ /**
+ * Additional configuration of the theory proof class for the given theory.
+ * This method should only be invoked when the "proof" option has been set.
+ *
+ * @param theory
+ */
+ void finishRegisterTheory(theory::Theory* theory);
- theory::TheoryId getTheoryForLemma(ClauseId id);
+ theory::TheoryId getTheoryForLemma(const prop::SatClause* clause);
TheoryProof* getTheoryProof(theory::TheoryId id);
+
+ void markTermForFutureRegistration(Expr term, theory::TheoryId id);
+
+ void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2);
+
+ virtual void treatBoolsAsFormulas(bool value) {};
+
+ virtual void printTheoryTerm(Expr term, std::ostream& os, const ProofLetMap& map) = 0;
};
class LFSCTheoryProofEngine : public TheoryProofEngine {
- LetMap d_letMap;
- void printTheoryTerm(Expr term, std::ostream& os, const LetMap& map);
- void bind(Expr term, LetMap& map, Bindings& let_order);
+ void bind(Expr term, ProofLetMap& map, Bindings& let_order);
public:
LFSCTheoryProofEngine()
: TheoryProofEngine() {}
+ void printTheoryTerm(Expr term, std::ostream& os, const ProofLetMap& map);
+
void registerTermsFromAssertions();
void printSortDeclarations(std::ostream& os, std::ostream& paren);
void printTermDeclarations(std::ostream& os, std::ostream& paren);
- virtual void printCoreTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printCoreTerm(Expr term, std::ostream& os, const ProofLetMap& map);
virtual void printLetTerm(Expr term, std::ostream& os);
- virtual void printBoundTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printBoundTerm(Expr term, std::ostream& os, const ProofLetMap& map);
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 printTheoryLemmas(const IdToSatClause& lemmas,
std::ostream& os,
- std::ostream& paren);
+ std::ostream& paren,
+ ProofLetMap& map);
virtual void printSort(Type type, std::ostream& os);
+
+ void performExtraRegistrations();
+
+ void treatBoolsAsFormulas(bool value);
+ void finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os);
+
+private:
+ static void dumpTheoryLemmas(const IdToSatClause& lemmas);
+
+ // TODO: this function should be moved into the BV prover.
+
+ std::map<Node, std::string> d_assertionToRewrite;
};
class TheoryProof {
@@ -214,7 +210,7 @@ public:
* @param term expresion representing term
* @param os output stream
*/
- void printTerm(Expr term, std::ostream& os, const LetMap& map) {
+ void printTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
d_proofEngine->printBoundTerm(term, os, map);
}
/**
@@ -223,7 +219,7 @@ public:
* @param term expresion representing term
* @param os output stream
*/
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+ virtual void printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) = 0;
/**
* Print the proof representation of the given type that belongs to some theory.
*
@@ -246,7 +242,10 @@ public:
*
* @param os output stream
*/
- 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);
/**
* Print the sorts declarations for this theory.
*
@@ -270,11 +269,32 @@ public:
*/
virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0;
/**
+ * Print any aliasing declarations.
+ *
+ * @param os
+ * @param paren
+ */
+ virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren) = 0;
+ /**
* Register a term of this theory that appears in the proof.
*
* @param term
*/
virtual void registerTerm(Expr term) = 0;
+ /**
+ * Print a proof for the disequality of two constants that belong to this theory.
+ *
+ * @param term
+ */
+ virtual void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2);
+ /**
+ * Print a proof for the equivalence of n1 and n2.
+ *
+ * @param term
+ */
+ virtual void printRewriteProof(std::ostream& os, const Node &n1, const Node &n2);
+
+ virtual void treatBoolsAsFormulas(bool value) {}
};
class BooleanProof : public TheoryProof {
@@ -285,26 +305,35 @@ public:
virtual void registerTerm(Expr term);
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+ 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 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;
};
class LFSCBooleanProof : public BooleanProof {
public:
LFSCBooleanProof(TheoryProofEngine* proofEngine)
- : BooleanProof(proofEngine)
+ : BooleanProof(proofEngine), d_treatBoolsAsFormulas(true)
{}
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map);
+ 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 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);
+
+ void treatBoolsAsFormulas(bool value) {
+ d_treatBoolsAsFormulas = value;
+ }
+
+private:
+ bool d_treatBoolsAsFormulas;
};
} /* CVC4 namespace */
diff --git a/src/proof/uf_proof.cpp b/src/proof/uf_proof.cpp
index 32ca122b0..139ce5ed2 100644
--- a/src/proof/uf_proof.cpp
+++ b/src/proof/uf_proof.cpp
@@ -67,13 +67,17 @@ inline static bool match(TNode n1, TNode n2) {
void ProofUF::toStream(std::ostream& out) {
+ ProofLetMap map;
+ toStream(out, map);
+}
+
+void ProofUF::toStream(std::ostream& out, const ProofLetMap& map) {
Trace("theory-proof-debug") << "; Print UF proof..." << std::endl;
//AJR : carry this further?
- LetMap map;
toStreamLFSC(out, ProofManager::getUfProof(), d_proof, map);
}
-void ProofUF::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map) {
+void ProofUF::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const ProofLetMap& map) {
Debug("pf::uf") << "ProofUF::toStreamLFSC starting" << std::endl;
Debug("lfsc-uf") << "Printing uf proof in LFSC : " << std::endl;
pf->debug_print("lfsc-uf");
@@ -81,12 +85,21 @@ void ProofUF::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqPr
toStreamRecLFSC( out, tp, pf, 0, map );
}
-Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map) {
+Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const ProofLetMap& map) {
Debug("pf::uf") << std::endl << std::endl << "toStreamRecLFSC called. tb = " << tb << " . proof:" << std::endl;
pf->debug_print("pf::uf");
Debug("pf::uf") << std::endl;
- if(tb == 0) {
+ if (tb == 0) {
+ // Special case: false was an input, so the proof is just "false".
+ if (pf->d_id == theory::eq::MERGED_THROUGH_EQUALITY &&
+ pf->d_node == NodeManager::currentNM()->mkConst(false)) {
+ out << "(clausify_false ";
+ out << ProofManager::getLitName(NodeManager::currentNM()->mkConst(false).notNode());
+ out << ")" << std::endl;
+ return Node();
+ }
+
Assert(pf->d_id == theory::eq::MERGED_THROUGH_TRANS);
Assert(!pf->d_node.isNull());
Assert(pf->d_children.size() >= 2);
@@ -190,42 +203,71 @@ Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::E
++i;
}
}
- Assert(neg >= 0);
+
+ bool disequalityFound = (neg >= 0);
+ if (!disequalityFound) {
+ Debug("pf::uf") << "A disequality was NOT found. UNSAT due to merged constants" << std::endl;
+ Debug("pf::uf") << "Proof for: " << pf->d_node << std::endl;
+ Assert(pf->d_node.getKind() == kind::EQUAL);
+ Assert(pf->d_node.getNumChildren() == 2);
+ Assert (pf->d_node[0].isConst() && pf->d_node[1].isConst());
+ }
Node n1;
std::stringstream ss;
- //Assert(subTrans.d_children.size() == pf->d_children.size() - 1);
Debug("pf::uf") << "\nsubtrans has " << subTrans.d_children.size() << " children\n";
- if(pf->d_children.size() > 2) {
+
+ if(!disequalityFound || subTrans.d_children.size() >= 2) {
n1 = toStreamRecLFSC(ss, tp, &subTrans, 1, map);
} else {
n1 = toStreamRecLFSC(ss, tp, subTrans.d_children[0], 1, map);
Debug("pf::uf") << "\nsubTrans unique child " << subTrans.d_children[0]->d_id << " was proven\ngot: " << n1 << std::endl;
}
- Node n2 = pf->d_children[neg]->d_node;
- Assert(n2.getKind() == kind::NOT);
- out << "(clausify_false (contra _ ";
Debug("pf::uf") << "\nhave proven: " << n1 << std::endl;
- Debug("pf::uf") << "n2 is " << n2[0] << std::endl;
- if (n2[0].getNumChildren() > 0) { Debug("pf::uf") << "\nn2[0]: " << n2[0][0] << std::endl; }
- if (n1.getNumChildren() > 1) { Debug("pf::uf") << "n1[1]: " << n1[1] << std::endl; }
+ out << "(clausify_false (contra _ ";
- if(n2[0].getKind() == kind::APPLY_UF) {
- out << "(trans _ _ _ _ ";
- out << "(symm _ _ _ ";
- out << ss.str();
- out << ") (pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
- } else {
- Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1]) || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
- if(n1[1] == n2[0][0]) {
- out << "(symm _ _ _ " << ss.str() << ")";
+ if (disequalityFound) {
+ Node n2 = pf->d_children[neg]->d_node;
+ Assert(n2.getKind() == kind::NOT);
+ Debug("pf::uf") << "n2 is " << n2[0] << std::endl;
+
+ if (n2[0].getNumChildren() > 0) { Debug("pf::uf") << "\nn2[0]: " << n2[0][0] << std::endl; }
+ if (n1.getNumChildren() > 1) { Debug("pf::uf") << "n1[1]: " << n1[1] << std::endl; }
+
+ if(n2[0].getKind() == kind::APPLY_UF) {
+ out << "(trans _ _ _ _ ";
+
+ if (n1[0] == n2[0]) {
+ out << "(symm _ _ _ ";
+ out << ss.str();
+ out << ") ";
+ } else {
+ Assert(n1[1] == n2[0]);
+ out << ss.str();
+ }
+ out << "(pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
} else {
- out << ss.str();
+ Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1]) || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
+ if(n1[1] == n2[0][0]) {
+ out << "(symm _ _ _ " << ss.str() << ")";
+ } else {
+ out << ss.str();
+ }
+ out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
}
- out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
+ } else {
+ Node n2 = pf->d_node;
+ Assert(n2.getKind() == kind::EQUAL);
+ Assert((n1[0] == n2[0] && n1[1] == n2[1]) || (n1[1] == n2[0] && n1[0] == n2[1]));
+
+ out << ss.str();
+ out << " ";
+ ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out, n1[0].toExpr(), n1[1].toExpr());
+ out << "))" << std::endl;
}
+
return Node();
}
@@ -584,10 +626,10 @@ Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::E
} else if(n1.getKind() == kind::EQUAL || n1.getKind() == kind::IFF) {
// n1 is an equality/iff, but n2 is a predicate
if(n1[0] == n2) {
- n1 = n1[1];
+ n1 = n1[1].iffNode(NodeManager::currentNM()->mkConst(true));
ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
} else if(n1[1] == n2) {
- n1 = n1[0];
+ n1 = n1[0].iffNode(NodeManager::currentNM()->mkConst(true));
ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
} else {
Unreachable();
@@ -595,16 +637,16 @@ Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::E
} else if(n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) {
// n2 is an equality/iff, but n1 is a predicate
if(n2[0] == n1) {
- n1 = n2[1];
+ n1 = n2[1].iffNode(NodeManager::currentNM()->mkConst(true));
ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
} else if(n2[1] == n1) {
- n1 = n2[0];
+ n1 = n2[0].iffNode(NodeManager::currentNM()->mkConst(true));
ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
} else {
Unreachable();
}
} else {
- // Both n1 and n2 are prediacates. Don't know what to do...
+ // Both n1 and n2 are predicates. Don't know what to do...
Unreachable();
}
@@ -655,7 +697,7 @@ void UFProof::registerTerm(Expr term) {
}
}
-void LFSCUFProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map) {
+void LFSCUFProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
Debug("pf::uf") << std::endl << "(pf::uf) LFSCUfProof::printOwnedTerm: term = " << term << std::endl;
Assert (theory::Theory::theoryOf(term) == theory::THEORY_UF);
@@ -667,6 +709,7 @@ void LFSCUFProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map)
}
Assert (term.getKind() == kind::APPLY_UF);
+ d_proofEngine->treatBoolsAsFormulas(false);
if(term.getType().isBoolean()) {
os << "(p_app ";
@@ -683,6 +726,7 @@ void LFSCUFProof::printOwnedTerm(Expr term, std::ostream& os, const LetMap& map)
if(term.getType().isBoolean()) {
os << ")";
}
+ d_proofEngine->treatBoolsAsFormulas(true);
}
void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) {
@@ -692,14 +736,14 @@ void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) {
os << type <<" ";
}
-void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
os << " ;; UF Theory Lemma \n;;";
for (unsigned i = 0; i < lemma.size(); ++i) {
os << lemma[i] <<" ";
}
os <<"\n";
//os << " (clausify_false trust)";
- UFProof::printTheoryLemmaProof( lemma, os, paren );
+ UFProof::printTheoryLemmaProof(lemma, os, paren, map);
}
void LFSCUFProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
@@ -714,6 +758,8 @@ void LFSCUFProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
// declaring the terms
+ Debug("pf::uf") << "LFSCUFProof::printTermDeclarations called" << std::endl;
+
for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
Expr term = *it;
@@ -729,7 +775,8 @@ void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
os << "(arrow";
for (unsigned i = 0; i < args.size(); i++) {
Type arg_type = args[i];
- os << " " << arg_type;
+ os << " ";
+ d_proofEngine->printSort(arg_type, os);
if (i < args.size() - 2) {
os << " (arrow";
fparen << ")";
@@ -742,10 +789,16 @@ void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
}
paren << ")";
}
+
+ Debug("pf::uf") << "LFSCUFProof::printTermDeclarations done" << std::endl;
}
void LFSCUFProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
// Nothing to do here at this point.
}
+void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren) {
+ // Nothing to do here at this point.
+}
+
} /* namespace CVC4 */
diff --git a/src/proof/uf_proof.h b/src/proof/uf_proof.h
index e359eaebd..444b602dc 100644
--- a/src/proof/uf_proof.h
+++ b/src/proof/uf_proof.h
@@ -28,13 +28,14 @@ namespace CVC4 {
//proof object outputted by TheoryUF
class ProofUF : public Proof {
private:
- static Node toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map);
+ static Node toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const ProofLetMap& map);
public:
ProofUF( theory::eq::EqProof * pf ) : d_proof( pf ) {}
//it is simply an equality engine proof
theory::eq::EqProof * d_proof;
void toStream(std::ostream& out);
- static void toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map);
+ void toStream(std::ostream& out, const ProofLetMap& map);
+ static void toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const ProofLetMap& map);
};
@@ -63,12 +64,13 @@ public:
LFSCUFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine)
: UFProof(uf, proofEngine)
{}
- virtual void printOwnedTerm(Expr term, std::ostream& os, const LetMap& map);
+ 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);
};
diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h
index 20724efd2..56a7c61e2 100644
--- a/src/prop/bvminisat/bvminisat.h
+++ b/src/prop/bvminisat/bvminisat.h
@@ -78,6 +78,10 @@ public:
ClauseId addClause(SatClause& clause, bool removable);
+ ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) {
+ Unreachable("Minisat does not support native XOR reasoning");
+ }
+
SatValue propagate();
SatVariable newVar(bool isTheoryAtom = false, bool preRegister = false, bool canErase = true);
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index aa1fc9587..eda736b8a 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -120,7 +120,7 @@ bool CnfStream::hasLiteral(TNode n) const {
return find != d_nodeToLiteralMap.end();
}
-void TseitinCnfStream::ensureLiteral(TNode n) {
+void TseitinCnfStream::ensureLiteral(TNode n, bool noPreregistration) {
// These are not removable and have no proof ID
d_removable = false;
@@ -163,7 +163,7 @@ void TseitinCnfStream::ensureLiteral(TNode n) {
d_literalToNodeMap.insert_safe(~lit, n.notNode());
} else {
// We have a theory atom or variable.
- lit = convertAtom(n);
+ lit = convertAtom(n, noPreregistration);
}
Assert(hasLiteral(n) && getNode(lit) == n);
@@ -232,7 +232,7 @@ void CnfStream::setProof(CnfProof* proof) {
d_cnfProof = proof;
}
-SatLiteral CnfStream::convertAtom(TNode node) {
+SatLiteral CnfStream::convertAtom(TNode node, bool noPreregistration) {
Debug("cnf") << "convertAtom(" << node << ")" << endl;
Assert(!hasLiteral(node), "atom already mapped!");
@@ -247,7 +247,7 @@ SatLiteral CnfStream::convertAtom(TNode node) {
} else {
theoryLiteral = true;
canEliminate = false;
- preRegister = true;
+ preRegister = !noPreregistration;
}
// Make a new literal (variables are not considered theory literals)
@@ -258,7 +258,11 @@ SatLiteral CnfStream::convertAtom(TNode node) {
SatLiteral CnfStream::getLiteral(TNode node) {
Assert(!node.isNull(), "CnfStream: can't getLiteral() of null node");
- Assert(d_nodeToLiteralMap.contains(node), "Literal not in the CNF Cache: %s\n", node.toString().c_str());
+
+ Assert(d_nodeToLiteralMap.contains(node),
+ "Literal not in the CNF Cache: %s\n",
+ node.toString().c_str());
+
SatLiteral literal = d_nodeToLiteralMap[node];
Debug("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal << std::endl;
return literal;
@@ -675,7 +679,7 @@ void TseitinCnfStream::convertAndAssert(TNode node,
bool negated,
ProofRule proof_id,
TNode from,
- theory::TheoryId ownerTheory) {
+ LemmaProofRecipe* proofRecipe) {
Debug("cnf") << "convertAndAssert(" << node
<< ", removable = " << (removable ? "true" : "false")
<< ", negated = " << (negated ? "true" : "false") << ")" << endl;
@@ -685,7 +689,12 @@ void TseitinCnfStream::convertAndAssert(TNode node,
Node assertion = negated ? node.notNode() : (Node)node;
Node from_assertion = negated? from.notNode() : (Node) from;
- d_cnfProof->setExplainerTheory(ownerTheory);
+ 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 cf9d519a7..6cc10d878 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -36,6 +36,9 @@
#include "smt_util/lemma_channels.h"
namespace CVC4 {
+
+class LemmaProofRecipe;
+
namespace prop {
class PropEngine;
@@ -174,7 +177,7 @@ protected:
* structure in this expression. Assumed to not be in the
* translation cache.
*/
- SatLiteral convertAtom(TNode node);
+ SatLiteral convertAtom(TNode node, bool noPreprocessing = false);
public:
@@ -207,14 +210,10 @@ 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 ownerTheory indicates the theory that should invoked to prove the formula.
+ * @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(),
- theory::TheoryId ownerTheory = theory::THEORY_LAST) = 0;
+ virtual void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null(), LemmaProofRecipe* proofRecipe = NULL) = 0;
+
/**
* Get the node that is represented by the given SatLiteral.
* @param literal the literal from the sat solver
@@ -235,7 +234,7 @@ public:
* this is like a "convert-but-don't-assert" version of
* convertAndAssert().
*/
- virtual void ensureLiteral(TNode n) = 0;
+ virtual void ensureLiteral(TNode n, bool noPreregistration = false) = 0;
/**
* Returns the literal that represents the given node in the SAT CNF
@@ -284,7 +283,7 @@ public:
*/
void convertAndAssert(TNode node, bool removable,
bool negated, ProofRule rule, TNode from = TNode::null(),
- theory::TheoryId ownerTheory = theory::THEORY_LAST);
+ LemmaProofRecipe* proofRecipe = NULL);
/**
* Constructs the stream to use the given sat solver.
@@ -337,7 +336,7 @@ private:
*/
SatLiteral toCNF(TNode node, bool negated = false);
- void ensureLiteral(TNode n);
+ void ensureLiteral(TNode n, bool noPreregistration = false);
};/* class TseitinCnfStream */
diff --git a/src/prop/cryptominisat.cpp b/src/prop/cryptominisat.cpp
new file mode 100644
index 000000000..d8f25a786
--- /dev/null
+++ b/src/prop/cryptominisat.cpp
@@ -0,0 +1,230 @@
+/********************* */
+/*! \file cryptominisat.cpp
+ ** \verbatim
+ ** Original author: lianah
+ ** Major contributors:
+ ** Minor contributors (to current version):
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief SAT Solver.
+ **
+ ** Implementation of the cryptominisat for cvc4 (bitvectors).
+ **/
+
+#include "prop/cryptominisat.h"
+
+#include "proof/clause_id.h"
+#include "proof/sat_proof.h"
+
+using namespace CVC4;
+using namespace prop;
+
+#ifdef CVC4_USE_CRYPTOMINISAT
+
+CryptoMinisatSolver::CryptoMinisatSolver(StatisticsRegistry* registry,
+ const std::string& name)
+: d_solver(new CMSat::SATSolver())
+, d_numVariables(0)
+, d_okay(true)
+, d_statistics(registry, name)
+{
+ d_true = newVar();
+ d_false = newVar();
+
+ std::vector<CMSat::Lit> clause(1);
+ clause[0] = CMSat::Lit(d_true, false);
+ d_solver->add_clause(clause);
+
+ clause[0] = CMSat::Lit(d_false, true);
+ d_solver->add_clause(clause);
+}
+
+
+CryptoMinisatSolver::~CryptoMinisatSolver() throw(AssertionException) {
+ delete d_solver;
+}
+
+ClauseId CryptoMinisatSolver::addXorClause(SatClause& clause,
+ bool rhs,
+ bool removable) {
+ Debug("sat::cryptominisat") << "Add xor clause " << clause <<" = " << rhs << "\n";
+
+ if (!d_okay) {
+ Debug("sat::cryptominisat") << "Solver unsat: not adding clause.\n";
+ return ClauseIdError;
+ }
+
+ ++(d_statistics.d_xorClausesAdded);
+
+ // ensure all sat literals have positive polarity by pushing
+ // the negation on the result
+ std::vector<CMSat::Var> xor_clause;
+ for (unsigned i = 0; i < clause.size(); ++i) {
+ xor_clause.push_back(toInternalLit(clause[i]).var());
+ rhs ^= clause[i].isNegated();
+ }
+ bool res = d_solver->add_xor_clause(xor_clause, rhs);
+ d_okay &= res;
+ return ClauseIdError;
+}
+
+ClauseId CryptoMinisatSolver::addClause(SatClause& clause, bool removable){
+ Debug("sat::cryptominisat") << "Add clause " << clause <<"\n";
+
+ if (!d_okay) {
+ Debug("sat::cryptominisat") << "Solver unsat: not adding clause.\n";
+ return ClauseIdError;
+ }
+
+ ++(d_statistics.d_clausesAdded);
+
+ std::vector<CMSat::Lit> internal_clause;
+ toInternalClause(clause, internal_clause);
+ bool res = d_solver->add_clause(internal_clause);
+ d_okay &= res;
+ return ClauseIdError;
+}
+
+bool CryptoMinisatSolver::ok() const {
+ return d_okay;
+}
+
+
+SatVariable CryptoMinisatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){
+ d_solver->new_var();
+ ++d_numVariables;
+ Assert (d_numVariables == d_solver->nVars());
+ return d_numVariables - 1;
+}
+
+SatVariable CryptoMinisatSolver::trueVar() {
+ return d_true;
+}
+
+SatVariable CryptoMinisatSolver::falseVar() {
+ return d_false;
+}
+
+void CryptoMinisatSolver::markUnremovable(SatLiteral lit) {
+ // cryptominisat supports dynamically adding back variables (?)
+ // so this is a no-op
+ return;
+}
+
+void CryptoMinisatSolver::interrupt(){
+ d_solver->interrupt_asap();
+}
+
+SatValue CryptoMinisatSolver::solve(){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_solveTime);
+ ++d_statistics.d_statCallsToSolve;
+ return toSatLiteralValue(d_solver->solve());
+}
+
+SatValue CryptoMinisatSolver::solve(long unsigned int& resource) {
+ // CMSat::SalverConf conf = d_solver->getConf();
+ Unreachable("Not sure how to set different limits for calls to solve in Cryptominisat");
+ return solve();
+}
+
+SatValue CryptoMinisatSolver::value(SatLiteral l){
+ const std::vector<CMSat::lbool> model = d_solver->get_model();
+ CMSat::Var var = l.getSatVariable();
+ Assert (var < model.size());
+ CMSat::lbool value = model[var];
+ return toSatLiteralValue(value);
+}
+
+SatValue CryptoMinisatSolver::modelValue(SatLiteral l){
+ return value(l);
+}
+
+unsigned CryptoMinisatSolver::getAssertionLevel() const {
+ Unreachable("No interface to get assertion level in Cryptominisat");
+ return -1;
+}
+
+// converting from internal sat solver representation
+
+SatVariable CryptoMinisatSolver::toSatVariable(CMSat::Var var) {
+ if (var == CMSat::var_Undef) {
+ return undefSatVariable;
+ }
+ return SatVariable(var);
+}
+
+CMSat::Lit CryptoMinisatSolver::toInternalLit(SatLiteral lit) {
+ if (lit == undefSatLiteral) {
+ return CMSat::lit_Undef;
+ }
+ return CMSat::Lit(lit.getSatVariable(), lit.isNegated());
+}
+
+SatLiteral CryptoMinisatSolver::toSatLiteral(CMSat::Lit lit) {
+ Assert (lit != CMSat::lit_Error);
+ if (lit == CMSat::lit_Undef) {
+ return undefSatLiteral;
+ }
+
+ return SatLiteral(SatVariable(lit.var()),
+ lit.sign());
+}
+
+SatValue CryptoMinisatSolver::toSatLiteralValue(CMSat::lbool res) {
+ if(res == CMSat::l_True) return SAT_VALUE_TRUE;
+ if(res == CMSat::l_Undef) return SAT_VALUE_UNKNOWN;
+ Assert(res == CMSat::l_False);
+ return SAT_VALUE_FALSE;
+}
+
+void CryptoMinisatSolver::toInternalClause(SatClause& clause,
+ std::vector<CMSat::Lit>& internal_clause) {
+ for (unsigned i = 0; i < clause.size(); ++i) {
+ internal_clause.push_back(toInternalLit(clause[i]));
+ }
+ Assert(clause.size() == internal_clause.size());
+}
+
+void CryptoMinisatSolver::toSatClause(std::vector<CMSat::Lit>& clause,
+ SatClause& sat_clause) {
+ for (unsigned i = 0; i < clause.size(); ++i) {
+ sat_clause.push_back(toSatLiteral(clause[i]));
+ }
+ Assert(clause.size() == sat_clause.size());
+}
+
+
+// Satistics for CryptoMinisatSolver
+
+CryptoMinisatSolver::Statistics::Statistics(StatisticsRegistry* registry,
+ const std::string& prefix) :
+ d_registry(registry),
+ d_statCallsToSolve("theory::bv::"+prefix+"::cryptominisat::calls_to_solve", 0),
+ d_xorClausesAdded("theory::bv::"+prefix+"::cryptominisat::xor_clauses", 0),
+ d_clausesAdded("theory::bv::"+prefix+"::cryptominisat::clauses", 0),
+ d_solveTime("theory::bv::"+prefix+"::cryptominisat::solve_time"),
+ d_registerStats(!prefix.empty())
+{
+ if (!d_registerStats)
+ return;
+
+ d_registry->registerStat(&d_statCallsToSolve);
+ d_registry->registerStat(&d_xorClausesAdded);
+ d_registry->registerStat(&d_clausesAdded);
+ d_registry->registerStat(&d_solveTime);
+}
+
+CryptoMinisatSolver::Statistics::~Statistics() {
+ if (!d_registerStats)
+ return;
+ d_registry->unregisterStat(&d_statCallsToSolve);
+ d_registry->unregisterStat(&d_xorClausesAdded);
+ d_registry->unregisterStat(&d_clausesAdded);
+ d_registry->unregisterStat(&d_solveTime);
+}
+#endif
diff --git a/src/prop/cryptominisat.h b/src/prop/cryptominisat.h
new file mode 100644
index 000000000..54d52af0e
--- /dev/null
+++ b/src/prop/cryptominisat.h
@@ -0,0 +1,138 @@
+/********************* */
+/*! \file cryptominisat.h
+ ** \verbatim
+ ** Original author: lianah
+ ** Major contributors:
+ ** Minor contributors (to current version):
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief SAT Solver.
+ **
+ ** Implementation of the cryptominisat sat solver for cvc4 (bitvectors).
+ **/
+
+#include "cvc4_private.h"
+
+#pragma once
+
+#include "prop/sat_solver.h"
+
+#ifdef CVC4_USE_CRYPTOMINISAT
+#include <cryptominisat4/cryptominisat.h>
+namespace CVC4 {
+namespace prop {
+
+class CryptoMinisatSolver : public SatSolver {
+
+private:
+ CMSat::SATSolver* d_solver;
+ unsigned d_numVariables;
+ bool d_okay;
+ SatVariable d_true;
+ SatVariable d_false;
+public:
+ CryptoMinisatSolver(StatisticsRegistry* registry,
+ const std::string& name = "");
+ ~CryptoMinisatSolver() throw(AssertionException);
+
+ ClauseId addClause(SatClause& clause, bool removable);
+ ClauseId addXorClause(SatClause& clause, bool rhs, bool removable);
+
+ bool nativeXor() { return true; }
+
+ SatVariable newVar(bool isTheoryAtom = false, bool preRegister = false, bool canErase = true);
+
+ SatVariable trueVar();
+ SatVariable falseVar();
+
+ void markUnremovable(SatLiteral lit);
+
+ void interrupt();
+
+ SatValue solve();
+ SatValue solve(long unsigned int&);
+ bool ok() const;
+ SatValue value(SatLiteral l);
+ SatValue modelValue(SatLiteral l);
+
+ unsigned getAssertionLevel() const;
+
+
+ // helper methods for converting from the internal Minisat representation
+
+ static SatVariable toSatVariable(CMSat::Var var);
+ static CMSat::Lit toInternalLit(SatLiteral lit);
+ static SatLiteral toSatLiteral(CMSat::Lit lit);
+ static SatValue toSatLiteralValue(bool res);
+ static SatValue toSatLiteralValue(CMSat::lbool res);
+
+ static void toInternalClause(SatClause& clause, std::vector<CMSat::Lit>& internal_clause);
+ static void toSatClause (std::vector<CMSat::Lit>& clause, SatClause& sat_clause);
+
+ class Statistics {
+ public:
+ StatisticsRegistry* d_registry;
+ IntStat d_statCallsToSolve;
+ IntStat d_xorClausesAdded;
+ IntStat d_clausesAdded;
+ TimerStat d_solveTime;
+ bool d_registerStats;
+ Statistics(StatisticsRegistry* registry,
+ const std::string& prefix);
+ ~Statistics();
+ };
+
+ Statistics d_statistics;
+};
+} // CVC4::prop
+} // CVC4
+
+#else // CVC4_USE_CRYPTOMINISAT
+
+namespace CVC4 {
+namespace prop {
+
+class CryptoMinisatSolver : public SatSolver {
+
+public:
+ CryptoMinisatSolver(StatisticsRegistry* registry,
+ const std::string& name = "") { Unreachable(); }
+ /** Assert a clause in the solver. */
+ ClauseId addClause(SatClause& clause, bool removable) {
+ Unreachable();
+ }
+
+ /** Return true if the solver supports native xor resoning */
+ bool nativeXor() { Unreachable(); }
+
+ /** Add a clause corresponding to rhs = l1 xor .. xor ln */
+ ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) {
+ Unreachable();
+ }
+
+ SatVariable newVar(bool isTheoryAtom, bool preRegister, bool canErase) { Unreachable(); }
+ SatVariable trueVar() { Unreachable(); }
+ SatVariable falseVar() { Unreachable(); }
+ SatValue solve() { Unreachable(); }
+ SatValue solve(long unsigned int&) { Unreachable(); }
+ void interrupt() { Unreachable(); }
+ SatValue value(SatLiteral l) { Unreachable(); }
+ SatValue modelValue(SatLiteral l) { Unreachable(); }
+ unsigned getAssertionLevel() const { Unreachable(); }
+ bool ok() const { return false;};
+
+
+};/* class CryptoMinisatSolver */
+} // CVC4::prop
+} // CVC4
+
+#endif // CVC4_USE_CRYPTOMINISAT
+
+
+
+
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 411b89514..a682a893b 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -232,6 +232,8 @@ CRef Solver::reason(Var x) {
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
+ Debug("pf::sat") << "Solver::reason: explanation_cl = " << explanation_cl << std::endl;
+
// Sort the literals by trail index level
lemma_lt lt(*this);
sort(explanation, lt);
@@ -266,6 +268,12 @@ CRef Solver::reason(Var x) {
}
explanation.shrink(i - j);
+ Debug("pf::sat") << "Solver::reason: explanation = " ;
+ for (int i = 0; i < explanation.size(); ++i) {
+ Debug("pf::sat") << explanation[i] << " ";
+ }
+ Debug("pf::sat") << std::endl;
+
// We need an explanation clause so we add a fake literal
if (j == 1) {
// Add not TRUE to the clause
@@ -276,6 +284,7 @@ CRef Solver::reason(Var x) {
CRef real_reason = ca.alloc(explLevel, explanation, true);
// FIXME: at some point will need more information about where this explanation
// came from (ie. the theory/sharing)
+ Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (1)" << std::endl;
PROOF (ClauseId id = ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA);
ProofManager::getCnfProof()->registerConvertedClause(id, true);
// no need to pop current assertion as this is not converted to cnf
@@ -336,6 +345,12 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
// If we are in solve or decision level > 0
if (minisat_busy || decisionLevel() > 0) {
+ Debug("pf::sat") << "Add clause adding a new lemma: ";
+ for (int k = 0; k < ps.size(); ++k) {
+ Debug("pf::sat") << ps[k] << " ";
+ }
+ Debug("pf::sat") << std::endl;
+
lemmas.push();
ps.copyTo(lemmas.last());
lemmas_removable.push(removable);
@@ -379,7 +394,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
cr = ca.alloc(clauseLevel, ps, false);
clauses_persistent.push(cr);
- attachClause(cr);
+ attachClause(cr);
if(PROOF_ON()) {
PROOF(
@@ -1234,12 +1249,12 @@ lbool Solver::search(int nof_conflicts)
} else {
- // If this was a final check, we are satisfiable
+ // If this was a final check, we are satisfiable
if (check_type == CHECK_FINAL) {
- bool decisionEngineDone = proxy->isDecisionEngineDone();
+ bool decisionEngineDone = proxy->isDecisionEngineDone();
// Unless a lemma has added more stuff to the queues
if (!decisionEngineDone &&
- (!order_heap.empty() || qhead < trail.size()) ) {
+ (!order_heap.empty() || qhead < trail.size()) ) {
check_type = CHECK_WITH_THEORY;
continue;
} else if (recheck) {
@@ -1666,6 +1681,13 @@ CRef Solver::updateLemmas() {
{
// The current lemma
vec<Lit>& lemma = lemmas[i];
+
+ Debug("pf::sat") << "Solver::updateLemmas: working on lemma: ";
+ for (int k = 0; k < lemma.size(); ++k) {
+ Debug("pf::sat") << lemma[k] << " ";
+ }
+ Debug("pf::sat") << std::endl;
+
// If it's an empty lemma, we have a conflict at zero level
if (lemma.size() == 0) {
Assert (! PROOF_ON());
@@ -1725,6 +1747,7 @@ CRef Solver::updateLemmas() {
TNode cnf_assertion = lemmas_cnf_assertion[i].first;
TNode cnf_def = lemmas_cnf_assertion[i].second;
+ Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (2)" << std::endl;
ClauseId id = ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA);
ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);
@@ -1741,6 +1764,7 @@ CRef Solver::updateLemmas() {
Node cnf_assertion = lemmas_cnf_assertion[i].first;
Node cnf_def = lemmas_cnf_assertion[i].second;
+ Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (3)" << std::endl;
ClauseId id = ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA);
ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index bfbf9da6f..ff726e299 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -150,7 +150,7 @@ ClauseId MinisatSatSolver::addClause(SatClause& clause, bool removable) {
// FIXME: This relies on the invariant that when ok() is false
// the SAT solver does not add the clause (which is what Minisat currently does)
if (!ok()) {
- return ClauseIdUndef;
+ return ClauseIdUndef;
}
d_minisat->addClause(minisat_clause, removable, clause_id);
PROOF( Assert (clause_id != ClauseIdError););
@@ -185,7 +185,7 @@ SatValue MinisatSatSolver::solve() {
}
bool MinisatSatSolver::ok() const {
- return d_minisat->okay();
+ return d_minisat->okay();
}
void MinisatSatSolver::interrupt() {
@@ -204,20 +204,20 @@ bool MinisatSatSolver::properExplanation(SatLiteral lit, SatLiteral expl) const
return true;
}
-void MinisatSatSolver::requirePhase(SatLiteral lit) {
+void MinisatSatSolver::requirePhase(SatLiteral lit) {
Assert(!d_minisat->rnd_pol);
Debug("minisat") << "requirePhase(" << lit << ")" << " " << lit.getSatVariable() << " " << lit.isNegated() << std::endl;
SatVariable v = lit.getSatVariable();
d_minisat->freezePolarity(v, lit.isNegated());
}
-bool MinisatSatSolver::flipDecision() {
+bool MinisatSatSolver::flipDecision() {
Debug("minisat") << "flipDecision()" << std::endl;
return d_minisat->flipDecision();
}
-bool MinisatSatSolver::isDecision(SatVariable decn) const {
- return d_minisat->isDecision( decn );
+bool MinisatSatSolver::isDecision(SatVariable decn) const {
+ return d_minisat->isDecision( decn );
}
/** Incremental interface */
@@ -291,7 +291,7 @@ namespace CVC4 {
template<>
prop::SatLiteral toSatLiteral< CVC4::Minisat::Solver>(Minisat::Solver::TLit lit) {
return prop::MinisatSatSolver::toSatLiteral(lit);
-}
+}
template<>
void toSatClause< CVC4::Minisat::Solver> (const CVC4::Minisat::Solver::TClause& minisat_cl,
@@ -300,5 +300,3 @@ void toSatClause< CVC4::Minisat::Solver> (const CVC4::Minisat::Solver::TClause&
}
} /* namespace CVC4 */
-
-
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 535ce1a47..ec5297bb7 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -44,6 +44,9 @@ public:
void initialize(context::Context* context, TheoryProxy* theoryProxy);
ClauseId addClause(SatClause& clause, bool removable);
+ ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) {
+ Unreachable("Minisat does not support native XOR reasoning");
+ }
SatVariable newVar(bool isTheoryAtom, bool preRegister, bool canErase);
SatVariable trueVar() { return d_minisat->trueVar(); }
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 54cf4c457..eb607e901 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -132,13 +132,13 @@ void PropEngine::assertFormula(TNode node) {
void PropEngine::assertLemma(TNode node, bool negated,
bool removable,
ProofRule rule,
- theory::TheoryId ownerTheory,
+ 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, ownerTheory);
+ d_cnfStream->convertAndAssert(node, removable, negated, rule, from, proofRecipe);
}
void PropEngine::requirePhase(TNode n, bool phase) {
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index b9ce7ca7e..c02015931 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -37,6 +37,7 @@ namespace CVC4 {
class ResourceManager;
class DecisionEngine;
class TheoryEngine;
+class LemmaProofRecipe;
namespace theory {
class TheoryRegistrar;
@@ -134,7 +135,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, theory::TheoryId ownerTheory, TNode from = TNode::null());
+ void assertLemma(TNode node, bool negated, bool removable, ProofRule rule, LemmaProofRecipe* proofRecipe, TNode from = TNode::null());
/**
* If ever n is decided upon, it must be in the given phase. This
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index 92696ae25..81fb94242 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -49,6 +49,12 @@ public:
virtual ClauseId addClause(SatClause& clause,
bool removable) = 0;
+ /** Return true if the solver supports native xor resoning */
+ virtual bool nativeXor() { return false; }
+
+ /** Add a clause corresponding to rhs = l1 xor .. xor ln */
+ virtual ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) = 0;
+
/**
* Create a new boolean variable in the solver.
* @param isTheoryAtom is this a theory atom that needs to be asserted to theory
@@ -84,7 +90,8 @@ public:
/** Check if the solver is in an inconsistent state */
virtual bool ok() const = 0;
-
+
+ virtual void setProofLog( BitVectorProof * bvp ) {}
};/* class SatSolver */
diff --git a/src/prop/sat_solver_factory.cpp b/src/prop/sat_solver_factory.cpp
index 092ec72f2..7fdc44e66 100644
--- a/src/prop/sat_solver_factory.cpp
+++ b/src/prop/sat_solver_factory.cpp
@@ -16,6 +16,7 @@
#include "prop/sat_solver_factory.h"
+#include "prop/cryptominisat.h"
#include "prop/minisat/minisat.h"
#include "prop/bvminisat/bvminisat.h"
@@ -26,6 +27,12 @@ BVSatSolverInterface* SatSolverFactory::createMinisat(context::Context* mainSatC
return new BVMinisatSatSolver(registry, mainSatContext, name);
}
+SatSolver* SatSolverFactory::createCryptoMinisat(StatisticsRegistry* registry,
+ const std::string& name) {
+return new CryptoMinisatSolver(registry, name);
+}
+
+
DPLLSatSolverInterface* SatSolverFactory::createDPLLMinisat(StatisticsRegistry* registry) {
return new MinisatSatSolver(registry);
}
diff --git a/src/prop/sat_solver_factory.h b/src/prop/sat_solver_factory.h
index 7cc23a8e8..a04bcaaf4 100644
--- a/src/prop/sat_solver_factory.h
+++ b/src/prop/sat_solver_factory.h
@@ -35,6 +35,8 @@ public:
StatisticsRegistry* registry,
const std::string& name = "");
static DPLLSatSolverInterface* createDPLLMinisat(StatisticsRegistry* registry);
+ static SatSolver* createCryptoMinisat(StatisticsRegistry* registry,
+ const std::string& name = "");
};/* class SatSolverFactory */
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 4a4515eb9..6e8f1fbbf 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -99,29 +99,34 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) {
TNode lNode = d_cnfStream->getNode(l);
Debug("prop-explain") << "explainPropagation(" << lNode << ")" << std::endl;
- NodeTheoryPair theoryExplanation = d_theoryEngine->getExplanationAndExplainer(lNode);
- Node explanationNode = theoryExplanation.node;
- theory::TheoryId explainerTheory = theoryExplanation.theory;
+ LemmaProofRecipe* proofRecipe = NULL;
+ PROOF(proofRecipe = new LemmaProofRecipe;);
+
+ Node theoryExplanation = d_theoryEngine->getExplanationAndRecipe(lNode, proofRecipe);
PROOF({
- ProofManager::getCnfProof()->pushCurrentAssertion(explanationNode);
- ProofManager::getCnfProof()->setExplainerTheory(explainerTheory);
+ ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation);
+ ProofManager::getCnfProof()->setProofRecipe(proofRecipe);
+
+ Debug("pf::sat") << "TheoryProxy::explainPropagation: setting lemma recipe to: "
+ << std::endl;
+ proofRecipe->dump("pf::sat");
- Debug("pf::sat") << "TheoryProxy::explainPropagation: setting explainer theory to: "
- << explainerTheory << std::endl;
+ delete proofRecipe;
+ proofRecipe = NULL;
});
- Debug("prop-explain") << "explainPropagation() => " << explanationNode << std::endl;
- if (explanationNode.getKind() == kind::AND) {
- Node::const_iterator it = explanationNode.begin();
- Node::const_iterator it_end = explanationNode.end();
+ Debug("prop-explain") << "explainPropagation() => " << theoryExplanation << std::endl;
+ if (theoryExplanation.getKind() == kind::AND) {
+ Node::const_iterator it = theoryExplanation.begin();
+ Node::const_iterator it_end = theoryExplanation.end();
explanation.push_back(l);
for (; it != it_end; ++ it) {
explanation.push_back(~d_cnfStream->getLiteral(*it));
}
} else {
explanation.push_back(l);
- explanation.push_back(~d_cnfStream->getLiteral(explanationNode));
+ explanation.push_back(~d_cnfStream->getLiteral(theoryExplanation));
}
}
@@ -175,7 +180,9 @@ void TheoryProxy::notifyRestart() {
if(lemmaCount % 1 == 0) {
Debug("shared") << "=) " << asNode << std::endl;
}
- d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID, theory::THEORY_LAST);
+
+ LemmaProofRecipe* noProofRecipe = NULL;
+ d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID, noProofRecipe);
} else {
Debug("shared") << "=(" << asNode << std::endl;
}
diff --git a/src/smt/boolean_terms.cpp b/src/smt/boolean_terms.cpp
index 40b757598..8957ad7f7 100644
--- a/src/smt/boolean_terms.cpp
+++ b/src/smt/boolean_terms.cpp
@@ -458,7 +458,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
goto next_worklist;
}
- if(parentTheory != theory::THEORY_BOOL && top.getType().isBoolean()) {
+ if(parentTheory != theory::THEORY_BOOL && top.getType().isBoolean() && top.getKind()!=kind::SEP_STAR && top.getKind()!=kind::SEP_WAND) {
// still need to rewrite e.g. function applications over boolean
Node topRewritten = rewriteBooleanTermsRec(top, theory::THEORY_BOOL, quantBoolVars);
Node n;
@@ -682,20 +682,22 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
goto next_worklist;
}
} else if(!t.isSort() && t.getNumChildren() > 0) {
- for(TypeNode::iterator i = t.begin(); i != t.end(); ++i) {
- if((*i).isBoolean()) {
- vector<TypeNode> argTypes(t.begin(), t.end());
- replace(argTypes.begin(), argTypes.end(), *i, d_tt.getType());
- TypeNode newType = nm->mkTypeNode(t.getKind(), argTypes);
- Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()),
- newType, "a variable introduced by Boolean-term conversion",
- NodeManager::SKOLEM_EXACT_NAME);
- Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
- top.setAttribute(BooleanTermAttr(), n);
- d_varCache[top] = n;
- result.top() << n;
- worklist.pop();
- goto next_worklist;
+ if( t.getKind()!=kind::SEP_STAR && t.getKind()!=kind::SEP_WAND ){
+ for(TypeNode::iterator i = t.begin(); i != t.end(); ++i) {
+ if((*i).isBoolean()) {
+ vector<TypeNode> argTypes(t.begin(), t.end());
+ replace(argTypes.begin(), argTypes.end(), *i, d_tt.getType());
+ TypeNode newType = nm->mkTypeNode(t.getKind(), argTypes);
+ Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()),
+ newType, "a variable introduced by Boolean-term conversion",
+ NodeManager::SKOLEM_EXACT_NAME);
+ Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
+ top.setAttribute(BooleanTermAttr(), n);
+ d_varCache[top] = n;
+ result.top() << n;
+ worklist.pop();
+ goto next_worklist;
+ }
}
}
}
@@ -714,6 +716,8 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
case kind::RR_REWRITE:
case kind::RR_DEDUCTION:
case kind::RR_REDUCTION:
+ case kind::SEP_STAR:
+ case kind::SEP_WAND:
// not yet supported
result.top() << top;
worklist.pop();
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 5bd1cbdfc..08495c936 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -94,6 +94,7 @@
#include "theory/quantifiers/quantifiers_rewriter.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"
@@ -552,10 +553,10 @@ class SmtEnginePrivate : public NodeManagerListener {
*/
unsigned d_simplifyAssertionsDepth;
- /** whether certain preprocess steps are necessary */
- bool d_needsExpandDefs;
- bool d_needsRewriteBoolTerms;
- bool d_needsConstrainSubTypes;
+ /** TODO: whether certain preprocess steps are necessary */
+ //bool d_needsExpandDefs;
+ //bool d_needsRewriteBoolTerms;
+ //bool d_needsConstrainSubTypes;
public:
/**
@@ -684,9 +685,9 @@ public:
d_abstractValueMap(&d_fakeContext),
d_abstractValues(),
d_simplifyAssertionsDepth(0),
- d_needsExpandDefs(true),
- d_needsRewriteBoolTerms(true),
- d_needsConstrainSubTypes(true), //TODO
+ //d_needsExpandDefs(true),
+ //d_needsRewriteBoolTerms(true),
+ //d_needsConstrainSubTypes(true), //TODO
d_iteSkolemMap(),
d_iteRemover(smt.d_userContext),
d_pbsProcessor(smt.d_userContext),
@@ -990,7 +991,7 @@ public:
Trace("smt-qe-debug") << " return : " << ret << std::endl;
//recursive (for nested quantification)
ret = replaceQuantifiersWithInstantiations( reti, insts, visited );
- }
+ }
}else if( n.getNumChildren()>0 ){
bool childChanged = false;
std::vector< Node > children;
@@ -1061,12 +1062,16 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
// The ProofManager is constructed before any other proof objects such as
// SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
- // initialized in TheoryEngine and PropEngine respectively.
+ // initialized in TheoryEngine and PropEngine respectively.
Assert(d_proofManager == NULL);
+
+ // d_proofManager must be created before Options has been finished
+ // being parsed from the input file. Because of this, we cannot trust
+ // that options::proof() is set correctly yet.
#ifdef CVC4_PROOF
d_proofManager = new ProofManager();
#endif
-
+
// We have mutual dependency here, so we add the prop engine to the theory
// engine later (it is non-essential there)
d_theoryEngine = new TheoryEngine(d_context, d_userContext,
@@ -1078,7 +1083,9 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
TheoryConstructor::addTheory(d_theoryEngine, id);
//register with proof engine if applicable
- THEORY_PROOF(ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine->theoryOf(id)); );
+#ifdef CVC4_PROOF
+ ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine->theoryOf(id));
+#endif
}
d_private->addUseTheoryListListener(d_theoryEngine);
@@ -1100,7 +1107,7 @@ void SmtEngine::finishInit() {
Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
// ensure that our heuristics are properly set up
setDefaults();
-
+
Trace("smt-debug") << "Making decision engine..." << std::endl;
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
@@ -1147,6 +1154,13 @@ void SmtEngine::finishInit() {
d_dumpCommands.clear();
PROOF( ProofManager::currentPM()->setLogic(d_logic); );
+ PROOF({
+ for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
+ ProofManager::currentPM()->getTheoryProofEngine()->
+ finishRegisterTheory(d_theoryEngine->theoryOf(id));
+ }
+ });
+
Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
}
@@ -1237,8 +1251,14 @@ SmtEngine::~SmtEngine() throw() {
delete d_decisionEngine;
d_decisionEngine = NULL;
- PROOF(delete d_proofManager;);
- PROOF(d_proofManager = NULL;);
+
+// d_proofManager is always created when proofs are enabled at configure time.
+// Becuase of this, this code should not be wrapped in PROOF() which
+// additionally checks flags such as options::proof().
+#ifdef CVC4_PROOF
+ delete d_proofManager;
+ d_proofManager = NULL;
+#endif
delete d_stats;
d_stats = NULL;
@@ -1306,9 +1326,9 @@ void SmtEngine::setDefaults() {
}
else if (options::solveIntAsBV() > 0) {
d_logic = LogicInfo("QF_BV");
- // } else if (d_logic.getLogicString() == "QF_UFBV" &&
- // options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- // d_logic = LogicInfo("QF_BV");
+ } else if (d_logic.getLogicString() == "QF_UFBV" &&
+ options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ d_logic = LogicInfo("QF_BV");
}
// set strings-exp
@@ -1333,6 +1353,10 @@ void SmtEngine::setDefaults() {
options::fmfBoundInt.set( true );
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
+ if(! options::fmfInstEngine.wasSetByUser()) {
+ options::fmfInstEngine.set( true );
+ Trace("smt") << "turning on fmf-inst-engine, for strings-exp" << std::endl;
+ }
/*
if(! options::rewriteDivk.wasSetByUser()) {
options::rewriteDivk.set( true );
@@ -1709,20 +1733,24 @@ void SmtEngine::setDefaults() {
//must have finite model finding on
options::finiteModelFind.set( true );
}
-
+
//if it contains a theory with non-termination, do not strictly enforce that quantifiers and theory combination must be interleaved
if( d_logic.isTheoryEnabled(THEORY_STRINGS) || (d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()) ){
if( !options::instWhenStrictInterleave.wasSetByUser() ){
options::instWhenStrictInterleave.set( false );
}
}
-
+
//local theory extensions
if( options::localTheoryExt() ){
if( !options::instMaxLevel.wasSetByUser() ){
options::instMaxLevel.set( 0 );
}
}
+ if( options::instMaxLevel()!=-1 ){
+ Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl;
+ options::cbqi.set(false);
+ }
if(options::fmfBoundIntLazy.wasSetByUser() && options::fmfBoundIntLazy()) {
options::fmfBoundInt.set( true );
@@ -1783,13 +1811,15 @@ void SmtEngine::setDefaults() {
}
//apply counterexample guided instantiation options
- if( options::cegqiSingleInv() ){
- options::ceGuidedInst.set( true );
+ if( options::cegqiSingleInvMode()!=quantifiers::CEGQI_SI_MODE_NONE ){
+ if( !options::ceGuidedInst.wasSetByUser() ){
+ options::ceGuidedInst.set( true );
+ }
}
if( options::ceGuidedInst() ){
//counterexample-guided instantiation for sygus
- if( !options::cegqiSingleInv.wasSetByUser() ){
- options::cegqiSingleInv.set( true );
+ if( !options::cegqiSingleInvMode.wasSetByUser() ){
+ options::cegqiSingleInvMode.set( quantifiers::CEGQI_SI_MODE_USE );
}
if( !options::quantConflictFind.wasSetByUser() ){
options::quantConflictFind.set( false );
@@ -1824,8 +1854,8 @@ void SmtEngine::setDefaults() {
}
}
//counterexample-guided instantiation for non-sygus
- // enable if any quantifiers with arithmetic or datatypes
- if( ( d_logic.isQuantified() && ( d_logic.isTheoryEnabled(THEORY_ARITH) || d_logic.isTheoryEnabled(THEORY_DATATYPES) ) ) ||
+ // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
+ if( ( d_logic.isQuantified() && ( d_logic.isTheoryEnabled(THEORY_ARITH) || d_logic.isTheoryEnabled(THEORY_DATATYPES) || d_logic.isTheoryEnabled(THEORY_BV) ) ) ||
options::cbqiAll() ){
if( !options::cbqi.wasSetByUser() ){
options::cbqi.set( true );
@@ -2583,8 +2613,9 @@ Node SmtEnginePrivate::intToBV(TNode n, NodeMap& cache) {
case kind::CONST_RATIONAL: {
Rational constant = current.getConst<Rational>();
AlwaysAssert(constant.isIntegral());
+ AlwaysAssert(constant >= 0);
BitVector bv(size, constant.getNumerator());
- if (bv.getValue() != constant.getNumerator()) {
+ if (bv.toSignedInt() != constant.getNumerator()) {
throw TypeCheckingException(current.toExpr(), string("Not enough bits for constant in intToBV: ") + current.toString());
}
result = nm->mkConst(bv);
@@ -3837,7 +3868,7 @@ void SmtEnginePrivate::processAssertions() {
ProofManager::currentPM()->addAssertion(d_assertions[i].toExpr());
}
);
-
+
Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if( options::ceGuidedInst() ){
@@ -3856,8 +3887,8 @@ void SmtEnginePrivate::processAssertions() {
}
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
- !d_smt.d_logic.isPure(THEORY_BV)) {
- // && d_smt.d_logic.getLogicString() != "QF_UFBV")
+ !d_smt.d_logic.isPure(THEORY_BV) &&
+ d_smt.d_logic.getLogicString() != "QF_UFBV") {
throw ModalException("Eager bit-blasting does not currently support theory combination. "
"Note that in a QF_BV problem UF symbols can be introduced for division. "
"Try --bv-div-zero-const to interpret division by zero as a constant.");
@@ -3885,7 +3916,6 @@ void SmtEnginePrivate::processAssertions() {
Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
-
dumpAssertions("pre-constrain-subtypes", d_assertions);
{
// Any variables of subtype types need to be constrained properly.
@@ -3965,6 +3995,10 @@ void SmtEnginePrivate::processAssertions() {
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() );
+ }
if( d_smt.d_logic.isQuantified() ){
Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-quant-preprocess" << endl;
//remove rewrite rules
@@ -4220,7 +4254,7 @@ void SmtEnginePrivate::processAssertions() {
Trace("smt-proc") << "SmtEnginePrivate::processAssertions() end" << endl;
dumpAssertions("post-everything", d_assertions);
-
+
//set instantiation level of everything to zero
if( options::instLevelInputOnly() && options::instMaxLevel()!=-1 ){
@@ -4410,74 +4444,75 @@ Result SmtEngine::checkSynth(const Expr& e) throw(TypeCheckingException, ModalEx
Trace("smt-synth") << "Check synthesis conjecture: " << e << std::endl;
Expr e_check = e;
Node conj = Node::fromExpr( e );
- Assert( conj.getKind()==kind::FORALL );
- //possibly run quantifier elimination to make formula into single invocation
- if( conj[1].getKind()==kind::EXISTS ){
- Node conj_se = conj[1][1];
-
- Trace("smt-synth") << "Compute single invocation for " << conj_se << "..." << std::endl;
- quantifiers::SingleInvocationPartition sip( kind::APPLY );
- sip.init( conj_se );
- Trace("smt-synth") << "...finished, got:" << std::endl;
- sip.debugPrint("smt-synth");
-
- if( !sip.isPurelySingleInvocation() && sip.isNonGroundSingleInvocation() ){
- //We are in the case where our synthesis conjecture is exists f. forall xy. P( f( x ), x, y ), P does not contain f.
- //The following will run QE on (exists z x.) exists y. P( z, x, y ) to obtain Q( z, x ),
- // and then constructs exists f. forall x. Q( f( x ), x ), where Q does not contain f. We invoke synthesis solver on this result.
-
- //create new smt engine to do quantifier elimination
- SmtEngine smt_qe( d_exprManager );
- smt_qe.setLogic(getLogicInfo());
- Trace("smt-synth") << "Property is non-ground single invocation, run QE to obtain single invocation." << std::endl;
- //partition variables
- std::vector< Node > qe_vars;
- std::vector< Node > nqe_vars;
- for( unsigned i=0; i<sip.d_all_vars.size(); i++ ){
- Node v = sip.d_all_vars[i];
- if( std::find( sip.d_si_vars.begin(), sip.d_si_vars.end(), v )==sip.d_si_vars.end() ){
- qe_vars.push_back( v );
- }else{
- nqe_vars.push_back( v );
+ if( conj.getKind()==kind::FORALL ){
+ //possibly run quantifier elimination to make formula into single invocation
+ if( conj[1].getKind()==kind::EXISTS ){
+ Node conj_se = conj[1][1];
+
+ Trace("smt-synth") << "Compute single invocation for " << conj_se << "..." << std::endl;
+ quantifiers::SingleInvocationPartition sip( kind::APPLY );
+ sip.init( conj_se );
+ Trace("smt-synth") << "...finished, got:" << std::endl;
+ sip.debugPrint("smt-synth");
+
+ if( !sip.isPurelySingleInvocation() && sip.isNonGroundSingleInvocation() ){
+ //We are in the case where our synthesis conjecture is exists f. forall xy. P( f( x ), x, y ), P does not contain f.
+ //The following will run QE on (exists z x.) exists y. P( z, x, y ) to obtain Q( z, x ),
+ // and then constructs exists f. forall x. Q( f( x ), x ), where Q does not contain f. We invoke synthesis solver on this result.
+
+ //create new smt engine to do quantifier elimination
+ SmtEngine smt_qe( d_exprManager );
+ smt_qe.setLogic(getLogicInfo());
+ Trace("smt-synth") << "Property is non-ground single invocation, run QE to obtain single invocation." << std::endl;
+ //partition variables
+ std::vector< Node > qe_vars;
+ std::vector< Node > nqe_vars;
+ for( unsigned i=0; i<sip.d_all_vars.size(); i++ ){
+ Node v = sip.d_all_vars[i];
+ if( std::find( sip.d_si_vars.begin(), sip.d_si_vars.end(), v )==sip.d_si_vars.end() ){
+ qe_vars.push_back( v );
+ }else{
+ nqe_vars.push_back( v );
+ }
}
+ std::vector< Node > orig;
+ std::vector< Node > subs;
+ //skolemize non-qe variables
+ for( unsigned i=0; i<nqe_vars.size(); i++ ){
+ Node k = NodeManager::currentNM()->mkSkolem( "k", nqe_vars[i].getType(), "qe for non-ground single invocation" );
+ orig.push_back( nqe_vars[i] );
+ subs.push_back( k );
+ Trace("smt-synth") << " subs : " << nqe_vars[i] << " -> " << k << std::endl;
+ }
+ for( std::map< Node, bool >::iterator it = sip.d_funcs.begin(); it != sip.d_funcs.end(); ++it ){
+ orig.push_back( sip.d_func_inv[it->first] );
+ Node k = NodeManager::currentNM()->mkSkolem( "k", sip.d_func_fo_var[it->first].getType(), "qe for function in non-ground single invocation" );
+ subs.push_back( k );
+ Trace("smt-synth") << " subs : " << sip.d_func_inv[it->first] << " -> " << k << std::endl;
+ }
+ Node conj_se_ngsi = sip.getFullSpecification();
+ Node conj_se_ngsi_subs = conj_se_ngsi.substitute( orig.begin(), orig.end(), subs.begin(), subs.end() );
+ Assert( !qe_vars.empty() );
+ conj_se_ngsi_subs = NodeManager::currentNM()->mkNode( kind::EXISTS, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, qe_vars ), conj_se_ngsi_subs );
+
+ Trace("smt-synth") << "Run quantifier elimination on " << conj_se_ngsi_subs << std::endl;
+ Expr qe_res = smt_qe.doQuantifierElimination( conj_se_ngsi_subs.toExpr(), true, false );
+ Trace("smt-synth") << "Result : " << qe_res << std::endl;
+
+ //create single invocation conjecture
+ Node qe_res_n = Node::fromExpr( qe_res );
+ qe_res_n = qe_res_n.substitute( subs.begin(), subs.end(), orig.begin(), orig.end() );
+ if( !nqe_vars.empty() ){
+ qe_res_n = NodeManager::currentNM()->mkNode( kind::EXISTS, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, nqe_vars ), qe_res_n );
+ }
+ Assert( conj.getNumChildren()==3 );
+ qe_res_n = NodeManager::currentNM()->mkNode( kind::FORALL, conj[0], qe_res_n, conj[2] );
+ Trace("smt-synth") << "Converted conjecture after QE : " << qe_res_n << std::endl;
+ e_check = qe_res_n.toExpr();
}
- std::vector< Node > orig;
- std::vector< Node > subs;
- //skolemize non-qe variables
- for( unsigned i=0; i<nqe_vars.size(); i++ ){
- Node k = NodeManager::currentNM()->mkSkolem( "k", nqe_vars[i].getType(), "qe for non-ground single invocation" );
- orig.push_back( nqe_vars[i] );
- subs.push_back( k );
- Trace("smt-synth") << " subs : " << nqe_vars[i] << " -> " << k << std::endl;
- }
- for( std::map< Node, bool >::iterator it = sip.d_funcs.begin(); it != sip.d_funcs.end(); ++it ){
- orig.push_back( sip.d_func_inv[it->first] );
- Node k = NodeManager::currentNM()->mkSkolem( "k", sip.d_func_fo_var[it->first].getType(), "qe for function in non-ground single invocation" );
- subs.push_back( k );
- Trace("smt-synth") << " subs : " << sip.d_func_inv[it->first] << " -> " << k << std::endl;
- }
- Node conj_se_ngsi = sip.getFullSpecification();
- Node conj_se_ngsi_subs = conj_se_ngsi.substitute( orig.begin(), orig.end(), subs.begin(), subs.end() );
- Assert( !qe_vars.empty() );
- conj_se_ngsi_subs = NodeManager::currentNM()->mkNode( kind::EXISTS, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, qe_vars ), conj_se_ngsi_subs );
-
- Trace("smt-synth") << "Run quantifier elimination on " << conj_se_ngsi_subs << std::endl;
- Expr qe_res = smt_qe.doQuantifierElimination( conj_se_ngsi_subs.toExpr(), true, false );
- Trace("smt-synth") << "Result : " << qe_res << std::endl;
-
- //create single invocation conjecture
- Node qe_res_n = Node::fromExpr( qe_res );
- qe_res_n = qe_res_n.substitute( subs.begin(), subs.end(), orig.begin(), orig.end() );
- if( !nqe_vars.empty() ){
- qe_res_n = NodeManager::currentNM()->mkNode( kind::EXISTS, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, nqe_vars ), qe_res_n );
- }
- Assert( conj.getNumChildren()==3 );
- qe_res_n = NodeManager::currentNM()->mkNode( kind::FORALL, conj[0], qe_res_n, conj[2] );
- Trace("smt-synth") << "Converted conjecture after QE : " << qe_res_n << std::endl;
- e_check = qe_res_n.toExpr();
}
}
-
+
return checkSatisfiability( e_check, true, false );
}
@@ -5104,7 +5139,7 @@ Expr SmtEngine::doQuantifierElimination(const Expr& e, bool doFull, bool strict)
Warning() << "Unexpected logic for quantifier elimination " << d_logic << endl;
}
Trace("smt-qe") << "Do quantifier elimination " << e << std::endl;
- Node n_e = Node::fromExpr( e );
+ Node n_e = Node::fromExpr( e );
if( n_e.getKind()!=kind::EXISTS ){
throw ModalException("Expecting an existentially quantified formula as argument to get-qe.");
}
@@ -5131,7 +5166,7 @@ Expr SmtEngine::doQuantifierElimination(const Expr& e, bool doFull, bool strict)
InternalError(ss.str().c_str());
}
//get the instantiations for all quantified formulas
- std::map< Node, std::vector< Node > > insts;
+ std::map< Node, std::vector< Node > > insts;
d_theoryEngine->getInstantiations( insts );
//find the quantified formula that corresponds to the input
Node top_q;
diff --git a/src/smt/smt_engine_check_proof.cpp b/src/smt/smt_engine_check_proof.cpp
index 5634a4651..808f5162c 100644
--- a/src/smt/smt_engine_check_proof.cpp
+++ b/src/smt/smt_engine_check_proof.cpp
@@ -63,14 +63,21 @@ void SmtEngine::checkProof() {
Chat() << "checking proof..." << endl;
- if ( !(d_logic.isPure(theory::THEORY_BOOL) ||
- d_logic.isPure(theory::THEORY_BV) ||
- d_logic.isPure(theory::THEORY_ARRAY) ||
- (d_logic.isPure(theory::THEORY_UF) &&
- ! d_logic.hasCardinalityConstraints())) ||
- d_logic.isQuantified()) {
- // no checking for these yet
- Notice() << "Notice: no proof-checking for non-UF/Bool/BV proofs yet" << endl;
+ std::string logicString = d_logic.getLogicString();
+
+ if (!(
+ // Pure logics
+ logicString == "QF_UF" ||
+ logicString == "QF_AX" ||
+ logicString == "QF_BV" ||
+ // Non-pure logics
+ logicString == "QF_AUF" ||
+ logicString == "QF_UFBV" ||
+ logicString == "QF_ABV" ||
+ logicString == "QF_AUFBV"
+ )) {
+ // This logic is not yet supported
+ Notice() << "Notice: no proof-checking for " << logicString << " proofs yet" << endl;
return;
}
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index e00be40d4..9407ff498 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -49,7 +49,6 @@ inline bool smtEngineInScope() {
// FIXME: Maybe move into SmtScope?
inline ProofManager* currentProofManager() {
#if IS_PROOFS_BUILD
- Assert(options::proof() || options::unsatCores());
Assert(s_smtEngine_current != NULL);
return s_smtEngine_current->d_proofManager;
#else /* IS_PROOFS_BUILD */
diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp
index 11c3dc081..6dfd14157 100644
--- a/src/theory/arrays/array_proof_reconstruction.cpp
+++ b/src/theory/arrays/array_proof_reconstruction.cpp
@@ -101,8 +101,59 @@ void ArrayProofReconstruction::notify(unsigned reasonType, Node reason, Node a,
Debug("pf::ee") << "Getting explanation for ROW guard: "
<< indexOne << " != " << indexTwo << std::endl;
+
eq::EqProof* childProof = new eq::EqProof;
d_equalityEngine->explainEquality(indexOne, indexTwo, false, equalities, childProof);
+
+ // It could be that the guard condition is a constant disequality. In this case,
+ // we need to change it to a different format.
+ if (childProof->d_id == theory::eq::MERGED_THROUGH_CONSTANTS) {
+ // The proof has two children, explaining why each index is a (different) constant.
+ Assert(childProof->d_children.size() == 2);
+
+ Node constantOne, constantTwo;
+ // Each subproof explains why one of the indices is constant.
+
+ if (childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) {
+ constantOne = childProof->d_children[0]->d_node;
+ } else {
+ Assert(childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_EQUALITY);
+ if ((childProof->d_children[0]->d_node[0] == indexOne) ||
+ (childProof->d_children[0]->d_node[0] == indexTwo)) {
+ constantOne = childProof->d_children[0]->d_node[1];
+ } else {
+ constantOne = childProof->d_children[0]->d_node[0];
+ }
+ }
+
+ if (childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) {
+ constantTwo = childProof->d_children[1]->d_node;
+ } else {
+ Assert(childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_EQUALITY);
+ if ((childProof->d_children[1]->d_node[0] == indexOne) ||
+ (childProof->d_children[1]->d_node[0] == indexTwo)) {
+ constantTwo = childProof->d_children[1]->d_node[1];
+ } else {
+ constantTwo = childProof->d_children[1]->d_node[0];
+ }
+ }
+
+ eq::EqProof* constantDisequalityProof = new eq::EqProof;
+ constantDisequalityProof->d_id = theory::eq::MERGED_THROUGH_CONSTANTS;
+ constantDisequalityProof->d_node =
+ NodeManager::currentNM()->mkNode(kind::EQUAL, constantOne, constantTwo).negate();
+
+ // Middle is where we need to insert the new disequality
+ std::vector<eq::EqProof *>::iterator middle = childProof->d_children.begin();
+ ++middle;
+
+ childProof->d_children.insert(middle, constantDisequalityProof);
+
+ childProof->d_id = theory::eq::MERGED_THROUGH_TRANS;
+ childProof->d_node =
+ NodeManager::currentNM()->mkNode(kind::EQUAL, indexOne, indexTwo).negate();
+ }
+
proof->d_children.push_back(childProof);
} else {
// This is the case of (i == k) because ((a[i]:=t)[k] != a[k]),
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 6add1b55f..28a08630e 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -829,7 +829,8 @@ void TheoryArrays::propagate(Effort e)
Node TheoryArrays::explain(TNode literal) {
- return explain(literal, NULL);
+ Node explanation = explain(literal, NULL);
+ return explanation;
}
Node TheoryArrays::explain(TNode literal, eq::EqProof *proof)
@@ -1394,6 +1395,7 @@ void TheoryArrays::check(Effort e) {
break;
default:
Unreachable();
+ break;
}
}
@@ -2231,6 +2233,7 @@ bool TheoryArrays::dischargeLemmas()
void TheoryArrays::conflict(TNode a, TNode b) {
Debug("pf::array") << "TheoryArrays::Conflict called" << std::endl;
eq::EqProof* proof = d_proofsEnabled ? new eq::EqProof() : NULL;
+
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b), proof);
} else {
diff --git a/src/theory/bv/abstraction.cpp b/src/theory/bv/abstraction.cpp
index fdc36ce72..dc5520411 100644
--- a/src/theory/bv/abstraction.cpp
+++ b/src/theory/bv/abstraction.cpp
@@ -41,7 +41,7 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
continue;
}
Node signature = computeSignature(assertions[i][j]);
- storeSignature(signature, assertions[i][j]);
+ storeSignature(signature, assertions[i][j]);
Debug("bv-abstraction") << " assertion: " << assertions[i][j] <<"\n";
Debug("bv-abstraction") << " signature: " << signature <<"\n";
}
@@ -52,7 +52,7 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
for (unsigned i = 0; i < assertions.size(); ++i) {
if (assertions[i].getKind() == kind::OR &&
assertions[i][0].getKind() == kind::AND) {
- std::vector<Node> new_children;
+ std::vector<Node> new_children;
for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) {
if (hasSignature(assertions[i][j])) {
new_children.push_back(abstractSignatures(assertions[i][j]));
@@ -60,10 +60,10 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
new_children.push_back(assertions[i][j]);
}
}
- new_assertions.push_back(utils::mkNode(kind::OR, new_children));
+ new_assertions.push_back(utils::mkNode(kind::OR, new_children));
} else {
// assertions that are not changed
- new_assertions.push_back(assertions[i]);
+ new_assertions.push_back(assertions[i]);
}
}
@@ -71,21 +71,21 @@ bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, st
skolemizeArguments(new_assertions);
}
-
+
// if we are using the eager solver reverse the abstraction
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
if (d_funcToSignature.size() == 0) {
// we did not change anything
return false;
}
- NodeNodeMap seen;
+ NodeNodeMap seen;
for (unsigned i = 0; i < new_assertions.size(); ++i) {
- new_assertions[i] = reverseAbstraction(new_assertions[i], seen);
+ new_assertions[i] = reverseAbstraction(new_assertions[i], seen);
}
// we undo the abstraction functions so the logic is QF_BV still
- return true;
+ return true;
}
-
+
// return true if we have created new function symbols for the problem
return d_funcToSignature.size() != 0;
}
@@ -99,7 +99,7 @@ bool AbstractionModule::isConjunctionOfAtoms(TNode node) {
bool AbstractionModule::isConjunctionOfAtomsRec(TNode node, TNodeSet& seen) {
if (seen.find(node)!= seen.end())
return true;
-
+
if (!node.getType().isBitVector()) {
return (node.getKind() == kind::AND || utils::isBVPredicate(node));
}
@@ -120,30 +120,30 @@ Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) {
if (seen.find(assertion) != seen.end())
return seen[assertion];
-
+
if (isAbstraction(assertion)) {
Node interp = getInterpretation(assertion);
seen[assertion] = interp;
- Assert (interp.getType() == assertion.getType());
+ Assert (interp.getType() == assertion.getType());
return interp;
}
if (assertion.getNumChildren() == 0) {
seen[assertion] = assertion;
- return assertion;
+ return assertion;
}
-
+
NodeBuilder<> result(assertion.getKind());
if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) {
- result << assertion.getOperator();
+ result << assertion.getOperator();
}
for (unsigned i = 0; i < assertion.getNumChildren(); ++i) {
- result << reverseAbstraction(assertion[i], seen);
+ result << reverseAbstraction(assertion[i], seen);
}
Node res = result;
seen[assertion] = res;
- return res;
+ return res;
}
void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
@@ -151,7 +151,7 @@ void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
TNode assertion = assertions[i];
if (assertion.getKind() != kind::OR)
continue;
-
+
bool is_skolemizable = true;
for (unsigned k = 0; k < assertion.getNumChildren(); ++k) {
if (assertion[k].getKind() != kind::EQUAL ||
@@ -191,54 +191,54 @@ void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
NodeBuilder<> skolem_func (kind::APPLY_UF);
skolem_func << func;
std::vector<Node> skolem_args;
-
+
for (unsigned j = 0; j < args.getArity(); ++j) {
bool all_same = true;
for (unsigned k = 1; k < args.getNumEntries(); ++k) {
if ( args.getEntry(k)[j] != args.getEntry(0)[j])
- all_same = false;
+ all_same = false;
}
- Node new_arg = all_same ? (Node)args.getEntry(0)[j] : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
+ Node new_arg = all_same ? (Node)args.getEntry(0)[j] : utils::mkVar(utils::getSize(args.getEntry(0)[j]));
skolem_args.push_back(new_arg);
- skolem_func << new_arg;
+ skolem_func << new_arg;
}
-
- Node skolem_func_eq1 = utils::mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
-
+
+ Node skolem_func_eq1 = utils::mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u));
+
// enumerate arguments assignments
- std::vector<Node> or_assignments;
+ std::vector<Node> or_assignments;
for (ArgsTableEntry::iterator it = args.begin(); it != args.end(); ++it) {
NodeBuilder<> arg_assignment(kind::AND);
ArgsVec& args = *it;
for (unsigned k = 0; k < args.size(); ++k) {
Node eq = utils::mkNode(kind::EQUAL, args[k], skolem_args[k]);
- arg_assignment << eq;
+ arg_assignment << eq;
}
or_assignments.push_back(arg_assignment);
}
-
+
Node new_func_def = utils::mkNode(kind::AND, skolem_func_eq1, utils::mkNode(kind::OR, or_assignments));
- assertion_builder << new_func_def;
+ assertion_builder << new_func_def;
}
Node new_assertion = assertion_builder;
Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments " << assertions[i] << " => \n";
- Debug("bv-abstraction-dbg") << " " << new_assertion;
+ Debug("bv-abstraction-dbg") << " " << new_assertion;
assertions[i] = new_assertion;
}
}
void AbstractionModule::storeSignature(Node signature, TNode assertion) {
if(d_signatures.find(signature) == d_signatures.end()) {
- d_signatures[signature] = 0;
+ d_signatures[signature] = 0;
}
- d_signatures[signature] = d_signatures[signature] + 1;
- d_assertionToSignature[assertion] = signature;
+ d_signatures[signature] = d_signatures[signature] + 1;
+ d_assertionToSignature[assertion] = signature;
}
Node AbstractionModule::computeSignature(TNode node) {
- resetSignatureIndex();
- NodeNodeMap cache;
+ resetSignatureIndex();
+ NodeNodeMap cache;
Node sig = computeSignatureRec(node, cache);
return sig;
}
@@ -247,17 +247,17 @@ Node AbstractionModule::getSignatureSkolem(TNode node) {
Assert (node.getKind() == kind::VARIABLE);
unsigned bitwidth = utils::getSize(node);
if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end()) {
- d_signatureSkolems[bitwidth] = vector<Node>();
+ d_signatureSkolems[bitwidth] = vector<Node>();
}
-
+
vector<Node>& skolems = d_signatureSkolems[bitwidth];
// get the index of bv variables of this size
- unsigned index = getBitwidthIndex(bitwidth);
+ unsigned index = getBitwidthIndex(bitwidth);
Assert (skolems.size() + 1 >= index );
if (skolems.size() == index) {
ostringstream os;
os << "sig_" <<bitwidth <<"_" << index;
- NodeManager* nm = NodeManager::currentNM();
+ NodeManager* nm = NodeManager::currentNM();
skolems.push_back(nm->mkSkolem(os.str(), nm->mkBitVectorType(bitwidth), "skolem for computing signatures"));
}
++(d_signatureIndices[bitwidth]);
@@ -268,12 +268,12 @@ unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) {
if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) {
d_signatureIndices[bitwidth] = 0;
}
- return d_signatureIndices[bitwidth];
+ return d_signatureIndices[bitwidth];
}
void AbstractionModule::resetSignatureIndex() {
for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) {
- it->second = 0;
+ it->second = 0;
}
}
@@ -282,24 +282,24 @@ bool AbstractionModule::hasSignature(Node node) {
}
Node AbstractionModule::getGeneralizedSignature(Node node) {
- NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
+ NodeNodeMap::const_iterator it = d_assertionToSignature.find(node);
Assert (it != d_assertionToSignature.end());
- Node generalized_signature = getGeneralization(it->second);
- return generalized_signature;
+ Node generalized_signature = getGeneralization(it->second);
+ return generalized_signature;
}
Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
if (cache.find(node) != cache.end()) {
- return cache.find(node)->second;
+ return cache.find(node)->second;
}
-
+
if (node.getNumChildren() == 0) {
if (node.getKind() == kind::CONST_BITVECTOR)
return node;
Node sig = getSignatureSkolem(node);
- cache[node] = sig;
- return sig;
+ cache[node] = sig;
+ return sig;
}
NodeBuilder<> builder(node.getKind());
@@ -308,30 +308,30 @@ Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
}
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
Node converted = computeSignatureRec(node[i], cache);
- builder << converted;
+ builder << converted;
}
Node result = builder;
cache[node] = result;
- return result;
+ return result;
}
-/**
+/**
* Returns 0, if the two are equal,
* 1 if s is a generalization of t
* 2 if t is a generalization of s
* -1 if the two cannot be unified
*
- * @param s
- * @param t
- *
- * @return
+ * @param s
+ * @param t
+ *
+ * @return
*/
int AbstractionModule::comparePatterns(TNode s, TNode t) {
if (s.getKind() == kind::SKOLEM &&
t.getKind() == kind::SKOLEM) {
return 0;
}
-
+
if (s.getKind() == kind::CONST_BITVECTOR &&
t.getKind() == kind::CONST_BITVECTOR) {
if (s == t) {
@@ -350,7 +350,7 @@ int AbstractionModule::comparePatterns(TNode s, TNode t) {
t.getKind() == kind::SKOLEM) {
return 2;
}
-
+
if (s.getNumChildren() != t.getNumChildren() ||
s.getKind() != t.getKind())
return -1;
@@ -370,26 +370,26 @@ int AbstractionModule::comparePatterns(TNode s, TNode t) {
}
TNode AbstractionModule::getGeneralization(TNode term) {
- NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
+ NodeNodeMap::iterator it = d_sigToGeneralization.find(term);
// if not in the map we add it
if (it == d_sigToGeneralization.end()) {
d_sigToGeneralization[term] = term;
- return term;
+ return term;
}
- // doesn't have a generalization
+ // doesn't have a generalization
if (it->second == term)
return term;
-
+
TNode generalization = getGeneralization(it->second);
Assert (generalization != term);
d_sigToGeneralization[term] = generalization;
- return generalization;
+ return generalization;
}
void AbstractionModule::storeGeneralization(TNode s, TNode t) {
Assert (s == getGeneralization(s));
Assert (t == getGeneralization(t));
- d_sigToGeneralization[s] = t;
+ d_sigToGeneralization[s] = t;
}
void AbstractionModule::finalizeSignatures() {
@@ -402,29 +402,29 @@ void AbstractionModule::finalizeSignatures() {
for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt) {
TNode t = getGeneralization(tt->first);
TNode s = getGeneralization(ss->first);
-
+
if (t != s) {
int status = comparePatterns(s, t);
- Assert (status);
+ Assert (status);
if (status < 0)
continue;
if (status == 1) {
- storeGeneralization(t, s);
+ storeGeneralization(t, s);
} else {
- storeGeneralization(s, t);
+ storeGeneralization(s, t);
}
}
}
}
// keep only most general signatures
for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
- TNode sig = it->first;
+ TNode sig = it->first;
TNode gen = getGeneralization(sig);
if (sig != gen) {
- Assert (d_signatures.find(gen) != d_signatures.end());
+ Assert (d_signatures.find(gen) != d_signatures.end());
// update the count
d_signatures[gen]+= d_signatures[sig];
- d_signatures.erase(it++);
+ d_signatures.erase(it++);
} else {
++it;
}
@@ -434,12 +434,12 @@ void AbstractionModule::finalizeSignatures() {
// remove signatures that are not frequent enough
for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
if (it->second <= 7) {
- d_signatures.erase(it++);
+ d_signatures.erase(it++);
} else {
++it;
}
}
-
+
for (SignatureMap::const_iterator it = d_signatures.begin(); it != d_signatures.end(); ++it) {
TNode signature = it->first;
// we already processed this signature
@@ -451,31 +451,31 @@ void AbstractionModule::finalizeSignatures() {
collectArgumentTypes(signature, arg_types, seen);
Assert (signature.getType().isBoolean());
// make function return a bitvector of size 1
- //Node bv_function = utils::mkNode(kind::ITE, signature, utils::mkConst(1, 1u), utils::mkConst(1, 0u));
+ //Node bv_function = utils::mkNode(kind::ITE, signature, utils::mkConst(1, 1u), utils::mkConst(1, 0u));
TypeNode range = NodeManager::currentNM()->mkBitVectorType(1);
-
+
TypeNode abs_type = nm->mkFunctionType(arg_types, range);
Node abs_func = nm->mkSkolem("abs_$$", abs_type, "abstraction function for bv theory");
Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n";
// NOTE: signature expression type is BOOLEAN
d_signatureToFunc[signature] = abs_func;
- d_funcToSignature[abs_func] = signature;
+ d_funcToSignature[abs_func] = signature;
}
d_statistics.d_numFunctionsAbstracted.setData(d_signatureToFunc.size());
-
+
Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted " << d_signatureToFunc.size() << " signatures. \n";
}
void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) {
if (seen.find(sig) != seen.end())
return;
-
+
if (sig.getKind() == kind::SKOLEM) {
types.push_back(sig.getType());
- seen.insert(sig);
- return;
+ seen.insert(sig);
+ return;
}
for (unsigned i = 0; i < sig.getNumChildren(); ++i) {
@@ -487,36 +487,36 @@ void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& t
void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) {
if (seen.find(node)!= seen.end())
return;
-
+
if (node.getKind() == kind::VARIABLE ||
node.getKind() == kind::CONST_BITVECTOR) {
// a constant in the node can either map to an argument of the abstraction
- // or can be hard-coded and part of the abstraction
+ // or can be hard-coded and part of the abstraction
if (signature.getKind() == kind::SKOLEM) {
args.push_back(node);
seen.insert(node);
} else {
- Assert (signature.getKind() == kind::CONST_BITVECTOR);
+ Assert (signature.getKind() == kind::CONST_BITVECTOR);
}
- //
- return;
+ //
+ return;
}
Assert (node.getKind() == signature.getKind() &&
- node.getNumChildren() == signature.getNumChildren());
+ node.getNumChildren() == signature.getNumChildren());
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- collectArguments(node[i], signature[i], args, seen);
- seen.insert(node);
+ collectArguments(node[i], signature[i], args, seen);
+ seen.insert(node);
}
}
Node AbstractionModule::abstractSignatures(TNode assertion) {
- Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "<< assertion <<"\n";
+ Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "<< assertion <<"\n";
// assume the assertion has been fully abstracted
Node signature = getGeneralizedSignature(assertion);
-
- Debug("bv-abstraction") << " with sig "<< signature <<"\n";
+
+ Debug("bv-abstraction") << " with sig "<< signature <<"\n";
NodeNodeMap::iterator it = d_signatureToFunc.find(signature);
if (it!= d_signatureToFunc.end()) {
std::vector<Node> args;
@@ -527,16 +527,16 @@ Node AbstractionModule::abstractSignatures(TNode assertion) {
collectArguments(assertion, signature, args, seen);
std::vector<TNode> real_args;
for (unsigned i = 1; i < args.size(); ++i) {
- real_args.push_back(args[i]);
+ real_args.push_back(args[i]);
}
- d_argsTable.addEntry(func, real_args);
- Node result = utils::mkNode(kind::EQUAL, utils::mkNode(kind::APPLY_UF, args),
+ d_argsTable.addEntry(func, real_args);
+ Node result = utils::mkNode(kind::EQUAL, utils::mkNode(kind::APPLY_UF, args),
utils::mkConst(1, 1u));
- Debug("bv-abstraction") << "=> "<< result << "\n";
- Assert (result.getType() == assertion.getType());
- return result;
+ Debug("bv-abstraction") << "=> "<< result << "\n";
+ Assert (result.getType() == assertion.getType());
+ return result;
}
- return assertion;
+ return assertion;
}
bool AbstractionModule::isAbstraction(TNode node) {
@@ -557,11 +557,11 @@ bool AbstractionModule::isAbstraction(TNode node) {
if (constant != utils::mkConst(1, 1u))
return false;
- TNode func_symbol = func.getOperator();
+ TNode func_symbol = func.getOperator();
if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end())
return false;
- return true;
+ return true;
}
Node AbstractionModule::getInterpretation(TNode node) {
@@ -571,51 +571,51 @@ Node AbstractionModule::getInterpretation(TNode node) {
Assert (constant.getKind() == kind::CONST_BITVECTOR &&
apply.getKind() == kind::APPLY_UF);
- Node func = apply.getOperator();
+ Node func = apply.getOperator();
Assert (d_funcToSignature.find(func) != d_funcToSignature.end());
-
+
Node sig = d_funcToSignature[func];
-
+
// substitute arguments in signature
TNodeTNodeMap seen;
unsigned index = 0;
Node result = substituteArguments(sig, apply, index, seen);
- Assert (result.getType().isBoolean());
+ Assert (result.getType().isBoolean());
Assert (index == apply.getNumChildren());
// Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n";
// Debug("bv-abstraction") << " => " << result << "\n";
- return result;
+ return result;
}
Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) {
if (seen.find(signature) != seen.end()) {
- return seen[signature];
+ return seen[signature];
}
-
+
if (signature.getKind() == kind::SKOLEM) {
// return corresponding argument and increment counter
seen[signature] = apply[index];
- return apply[index++];
+ return apply[index++];
}
if (signature.getNumChildren() == 0) {
Assert (signature.getKind() != kind::VARIABLE &&
- signature.getKind() != kind::SKOLEM);
+ signature.getKind() != kind::SKOLEM);
seen[signature] = signature;
- return signature;
+ return signature;
}
-
+
NodeBuilder<> builder(signature.getKind());
if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) {
builder << signature.getOperator();
}
-
+
for (unsigned i = 0; i < signature.getNumChildren(); ++i) {
Node child = substituteArguments(signature[i], apply, index, seen);
- builder << child;
+ builder << child;
}
- Node result = builder;
+ Node result = builder;
seen[signature]= result;
return result;
@@ -625,20 +625,20 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
if (Dump.isOn("bv-abstraction")) {
NodeNodeMap seen;
Node c = reverseAbstraction(conflict, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(c.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
- Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
+ Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
if (conflict.getKind() != kind::AND)
- return conflict;
+ return conflict;
std::vector<Node> conjuncts;
for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
conjuncts.push_back(conflict[i]);
-
+
theory::SubstitutionMap subst(new context::Context());
for (unsigned i = 0; i < conjuncts.size(); ++i) {
TNode conjunct = conjuncts[i];
@@ -658,12 +658,12 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
} else {
continue;
}
-
+
Assert (!subst.hasSubstitution(s));
Assert (!t.isNull() &&
!s.isNull() &&
s!= t);
- subst.addSubstitution(s, t);
+ subst.addSubstitution(s, t);
for (unsigned k = 0; k < conjuncts.size(); k++) {
conjuncts[k] = subst.apply(conjuncts[k]);
@@ -671,28 +671,28 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
}
}
Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts));
-
+
Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
Debug("bv-abstraction") << " => " << new_conflict <<"\n";
if (Dump.isOn("bv-abstraction")) {
-
+
NodeNodeMap seen;
Node nc = reverseAbstraction(new_conflict, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(nc.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
-
- return new_conflict;
+
+ return new_conflict;
}
void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instantiations,
const std::vector<TNode> functions) {
// print header
- Debug("bv-abstraction-dbg") <<"[ ";
+ Debug("bv-abstraction-dbg") <<"[ ";
for (unsigned i = 0; i < functions.size(); ++i) {
for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) {
Debug("bv-abstraction-dgb") << functions[i][j] <<" ";
@@ -706,16 +706,16 @@ void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instant
const std::vector<ArgsVec>& inst = instantiations[i];
for (unsigned j = 0; j < inst.size(); ++j) {
for (unsigned k = 0; k < inst[j].size(); ++k) {
- Debug("bv-abstraction-dbg") << inst[j][k] << " ";
+ Debug("bv-abstraction-dbg") << inst[j][k] << " ";
}
- Debug("bv-abstraction-dbg") << " || ";
+ Debug("bv-abstraction-dbg") << " || ";
}
Debug("bv-abstraction-dbg") <<"]\n";
}
}
void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) {
- Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
+ Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n";
std::vector<TNode> functions;
// collect abstract functions
@@ -737,11 +737,11 @@ void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& le
// if (functions.size() >= 3) {
// // dump conflict
// NodeNodeMap seen;
- // Node reversed = reverseAbstraction(conflict, seen);
- // std::cout << "CONFLICT " << reversed << "\n";
+ // Node reversed = reverseAbstraction(conflict, seen);
+ // std::cout << "CONFLICT " << reversed << "\n";
// }
-
+
if (functions.size() == 0 || functions.size() > options::bvNumFunc()) {
return;
}
@@ -751,31 +751,31 @@ void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& le
SubstitutionMap skolem_subst(new context::Context());
SubstitutionMap reverse_skolem(new context::Context());
makeFreshSkolems(conflict, skolem_subst, reverse_skolem);
-
+
Node skolemized_conflict = skolem_subst.apply(conflict);
for (unsigned i = 0; i < functions.size(); ++i) {
functions[i] = skolem_subst.apply(functions[i]);
}
- conflict = skolem_subst.apply(conflict);
+ conflict = skolem_subst.apply(conflict);
LemmaInstantiatior inst(functions, d_argsTable, conflict);
std::vector<Node> new_lemmas;
- inst.generateInstantiations(new_lemmas);
+ inst.generateInstantiations(new_lemmas);
for (unsigned i = 0; i < new_lemmas.size(); ++i) {
TNode lemma = reverse_skolem.apply(new_lemmas[i]);
if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) {
lemmas.push_back(lemma);
- Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
+ Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
storeLemma(lemma);
if (Dump.isOn("bv-abstraction")) {
NodeNodeMap seen;
Node l = reverseAbstraction(lemma, seen);
- Dump("bv-abstraction") << PushCommand();
+ Dump("bv-abstraction") << PushCommand();
Dump("bv-abstraction") << AssertCommand(l.toExpr());
Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
+ Dump("bv-abstraction") << PopCommand();
}
}
}
@@ -787,18 +787,18 @@ int AbstractionModule::LemmaInstantiatior::next(int val, int index) {
return -1;
}
-/**
+/**
* Assumes the stack without top is consistent, and checks that the
* full stack is consistent
- *
- * @param stack
- *
- * @return
+ *
+ * @param stack
+ *
+ * @return
*/
bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) {
if (stack.empty())
return true;
-
+
unsigned current = stack.size() - 1;
TNode func = d_functions[current];
ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator());
@@ -807,12 +807,12 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
for (unsigned k = 0; k < args.size(); ++k) {
TNode s = func[k];
TNode t = args[k];
-
+
TNode s0 = s;
while (d_subst.hasSubstitution(s0)) {
s0 = d_subst.getSubstitution(s0);
}
-
+
TNode t0 = t;
while (d_subst.hasSubstitution(t0)) {
t0 = d_subst.getSubstitution(t0);
@@ -824,7 +824,7 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
else
continue;
}
-
+
if(s0.getMetaKind() == kind::metakind::VARIABLE &&
t0.isConst()) {
d_subst.addSubstitution(s0, t0);
@@ -839,12 +839,12 @@ bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stac
Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
t0.getMetaKind() == kind::metakind::VARIABLE);
-
+
if (s0 != t0) {
d_subst.addSubstitution(s0, t0);
}
}
- return true;
+ return true;
}
bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
@@ -854,13 +854,13 @@ bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
void AbstractionModule::LemmaInstantiatior::mkLemma() {
Node lemma = d_subst.apply(d_conflict);
// Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n";
- d_lemmas.push_back(lemma);
+ d_lemmas.push_back(lemma);
}
void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
if (!isConsistent(stack))
return;
-
+
if (accept(stack)) {
mkLemma();
return;
@@ -871,7 +871,7 @@ void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
d_ctx->push();
stack.push_back(x);
backtrack(stack);
-
+
d_ctx->pop();
stack.pop_back();
x = next(x, stack.size());
@@ -880,13 +880,13 @@ void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) {
- Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
+ Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations ";
std::vector<int> stack;
backtrack(stack);
- Assert (d_ctx->getLevel() == 0);
- Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
- lemmas.swap(d_lemmas);
+ Assert (d_ctx->getLevel() == 0);
+ Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n";
+ lemmas.swap(d_lemmas);
}
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
@@ -910,7 +910,7 @@ void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, Subst
void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
Assert (fresh_args.size() == 0);
Assert (func.getKind() == kind::APPLY_UF);
- TNodeNodeMap d_map;
+ TNodeNodeMap d_map;
for (unsigned i = 0; i < func.getNumChildren(); ++i) {
TNode arg = func[i];
if (arg.isConst()) {
@@ -918,9 +918,9 @@ void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args)
continue;
}
Assert (arg.getMetaKind() == kind::metakind::VARIABLE);
- TNodeNodeMap::iterator it = d_map.find(arg);
+ TNodeNodeMap::iterator it = d_map.find(arg);
if (it != d_map.end()) {
- fresh_args.push_back(it->second);
+ fresh_args.push_back(it->second);
} else {
Node skolem = utils::mkVar(utils::getSize(arg));
d_map[arg] = skolem;
@@ -947,7 +947,7 @@ Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vect
Debug("bv-abstraction-dbg") <<"\n";
}
-
+
SubstitutionMap subst(new context::Context());
for (unsigned i = 0; i < ss.size(); ++i) {
@@ -982,10 +982,10 @@ Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vect
Assert (s0 != t0);
subst.addSubstitution(s0, t0);
}
-
+
Node res = subst.apply(conflict);
- Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n";
- return res;
+ Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n";
+ return res;
}
void AbstractionModule::storeLemma(TNode lemma) {
@@ -996,7 +996,7 @@ void AbstractionModule::storeLemma(TNode lemma) {
atom = atom.getKind() == kind::NOT ? atom[0] : atom;
Assert (atom.getKind() != kind::NOT);
Assert (utils::isBVPredicate(atom));
- d_lemmaAtoms.insert(atom);
+ d_lemmaAtoms.insert(atom);
}
} else {
lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma;
@@ -1009,9 +1009,9 @@ void AbstractionModule::storeLemma(TNode lemma) {
bool AbstractionModule::isLemmaAtom(TNode node) const {
Assert (node.getType().isBoolean());
node = node.getKind() == kind::NOT? node[0] : node;
-
+
return d_inputAtoms.find(node) == d_inputAtoms.end() &&
- d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
+ d_lemmaAtoms.find(node) != d_lemmaAtoms.end();
}
void AbstractionModule::addInputAtom(TNode atom) {
@@ -1022,31 +1022,31 @@ void AbstractionModule::addInputAtom(TNode atom) {
void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) {
Assert (args.size() == d_arity);
- d_data.push_back(args);
+ d_data.push_back(args);
}
void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) {
if (d_data.find(signature) == d_data.end()) {
- d_data[signature] = ArgsTableEntry(args.size());
+ d_data[signature] = ArgsTableEntry(args.size());
}
ArgsTableEntry& entry = d_data[signature];
- entry.addArguments(args);
+ entry.addArguments(args);
}
bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const {
- return d_data.find(signature) != d_data.end();
+ return d_data.find(signature) != d_data.end();
}
AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) {
Assert (hasEntry(signature));
- return d_data.find(signature)->second;
+ return d_data.find(signature)->second;
}
-AbstractionModule::Statistics::Statistics()
- : d_numFunctionsAbstracted("theory::bv::AbstractioModule::NumFunctionsAbstracted", 0)
- , d_numArgsSkolemized("theory::bv::AbstractioModule::NumArgsSkolemized", 0)
- , d_abstractionTime("theory::bv::AbstractioModule::AbstractionTime")
+AbstractionModule::Statistics::Statistics(const std::string& name)
+ : d_numFunctionsAbstracted(name + "theory::bv::AbstractioModule::NumFunctionsAbstracted", 0)
+ , d_numArgsSkolemized(name + "theory::bv::AbstractioModule::NumArgsSkolemized", 0)
+ , d_abstractionTime(name + "theory::bv::AbstractioModule::AbstractionTime")
{
smtStatisticsRegistry()->registerStat(&d_numFunctionsAbstracted);
smtStatisticsRegistry()->registerStat(&d_numArgsSkolemized);
diff --git a/src/theory/bv/abstraction.h b/src/theory/bv/abstraction.h
index 5d580f6ce..5d48b926e 100644
--- a/src/theory/bv/abstraction.h
+++ b/src/theory/bv/abstraction.h
@@ -38,11 +38,11 @@ class AbstractionModule {
IntStat d_numFunctionsAbstracted;
IntStat d_numArgsSkolemized;
TimerStat d_abstractionTime;
- Statistics();
+ Statistics(const std::string& name);
~Statistics();
};
-
+
class ArgsTableEntry {
std::vector<ArgsVec> d_data;
unsigned d_arity;
@@ -61,11 +61,11 @@ class AbstractionModule {
unsigned getArity() { return d_arity; }
unsigned getNumEntries() { return d_data.size(); }
ArgsVec& getEntry(unsigned i ) { Assert (i < d_data.size()); return d_data[i]; }
- };
+ };
class ArgsTable {
__gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction > d_data;
- bool hasEntry(TNode signature) const;
+ bool hasEntry(TNode signature) const;
public:
typedef __gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction >::iterator iterator;
ArgsTable() {}
@@ -75,12 +75,12 @@ class AbstractionModule {
iterator end() { return d_data.end(); }
};
- /**
+ /**
* Checks if one pattern is a generalization of the other
- *
- * @param s
- * @param t
- *
+ *
+ * @param s
+ * @param t
+ *
* @return 1 if s :> t, 2 if s <: t, 0 if they equivalent and -1 if they are incomparable
*/
static int comparePatterns(TNode s, TNode t);
@@ -93,7 +93,7 @@ class AbstractionModule {
theory::SubstitutionMap d_subst;
TNode d_conflict;
std::vector<Node> d_lemmas;
-
+
void backtrack(std::vector<int>& stack);
int next(int val, int index);
bool isConsistent(const std::vector<int>& stack);
@@ -108,7 +108,7 @@ class AbstractionModule {
, d_conflict(conflict)
, d_lemmas()
{
- Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n";
+ Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n";
// initializing the search space
for (unsigned i = 0; i < functions.size(); ++i) {
TNode func_op = functions[i].getOperator();
@@ -118,31 +118,31 @@ class AbstractionModule {
}
}
- void generateInstantiations(std::vector<Node>& lemmas);
-
+ void generateInstantiations(std::vector<Node>& lemmas);
+
};
-
+
typedef __gnu_cxx::hash_map<Node, std::vector<Node>, NodeHashFunction> NodeVecMap;
typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> NodeTNodeMap;
typedef __gnu_cxx::hash_map<TNode, TNode, TNodeHashFunction> TNodeTNodeMap;
typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeNodeMap;
typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> TNodeNodeMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
- typedef __gnu_cxx::hash_map<unsigned, Node> IntNodeMap;
+ typedef __gnu_cxx::hash_map<unsigned, Node> IntNodeMap;
typedef __gnu_cxx::hash_map<unsigned, unsigned> IndexMap;
typedef __gnu_cxx::hash_map<unsigned, std::vector<Node> > SkolemMap;
typedef __gnu_cxx::hash_map<TNode, unsigned, TNodeHashFunction > SignatureMap;
-
- ArgsTable d_argsTable;
+
+ ArgsTable d_argsTable;
// mapping between signature and uninterpreted function symbol used to
// abstract the signature
NodeNodeMap d_signatureToFunc;
- NodeNodeMap d_funcToSignature;
+ NodeNodeMap d_funcToSignature;
- NodeNodeMap d_assertionToSignature;
+ NodeNodeMap d_assertionToSignature;
SignatureMap d_signatures;
- NodeNodeMap d_sigToGeneralization;
+ NodeNodeMap d_sigToGeneralization;
TNodeSet d_skolems;
// skolems maps
@@ -165,7 +165,7 @@ class AbstractionModule {
Node getGeneralizedSignature(Node node);
Node getSignatureSkolem(TNode node);
- unsigned getBitwidthIndex(unsigned bitwidth);
+ unsigned getBitwidthIndex(unsigned bitwidth);
void resetSignatureIndex();
Node computeSignatureRec(TNode, NodeNodeMap&);
void storeSignature(Node signature, TNode assertion);
@@ -175,14 +175,14 @@ class AbstractionModule {
// crazy instantiation methods
void generateInstantiations(unsigned current,
- std::vector<ArgsTableEntry>& matches,
+ std::vector<ArgsTableEntry>& matches,
std::vector<std::vector<ArgsVec> >& instantiations,
std::vector<std::vector<ArgsVec> >& new_instantiations);
Node tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict);
void makeFreshArgs(TNode func, std::vector<Node>& fresh_args);
void makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map);
-
+
void skolemizeArguments(std::vector<Node>& assertions);
Node reverseAbstraction(Node assertion, NodeNodeMap& seen);
@@ -192,9 +192,9 @@ class AbstractionModule {
void storeLemma(TNode lemma);
Statistics d_statistics;
-
+
public:
- AbstractionModule()
+ AbstractionModule(const std::string& name)
: d_argsTable()
, d_signatureToFunc()
, d_funcToSignature()
@@ -207,34 +207,34 @@ public:
, d_addedLemmas()
, d_lemmaAtoms()
, d_inputAtoms()
- , d_statistics()
+ , d_statistics(name)
{}
- /**
+ /**
* returns true if there are new uninterepreted functions symbols in the output
- *
- * @param assertions
- * @param new_assertions
- *
- * @return
+ *
+ * @param assertions
+ * @param new_assertions
+ *
+ * @return
*/
bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
- /**
- * Returns true if the node represents an abstraction predicate.
- *
- * @param node
- *
- * @return
+ /**
+ * Returns true if the node represents an abstraction predicate.
+ *
+ * @param node
+ *
+ * @return
*/
bool isAbstraction(TNode node);
- /**
- * Returns the interpretation of the abstraction predicate.
- *
- * @param node
- *
- * @return
+ /**
+ * Returns the interpretation of the abstraction predicate.
+ *
+ * @param node
+ *
+ * @return
*/
Node getInterpretation(TNode node);
- Node simplifyConflict(TNode conflict);
+ Node simplifyConflict(TNode conflict);
void generalizeConflict(TNode conflict, std::vector<Node>& lemmas);
void addInputAtom(TNode atom);
bool isLemmaAtom(TNode node) const;
diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp
index 887daa1bd..37e9f4476 100644
--- a/src/theory/bv/aig_bitblaster.cpp
+++ b/src/theory/bv/aig_bitblaster.cpp
@@ -19,7 +19,7 @@
#include "options/bv_options.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
-
+#include "smt/smt_statistics_registry.h"
#ifdef CVC4_USE_ABC
// Function is defined as static in ABC. Not sure how else to do this.
@@ -140,10 +140,24 @@ AigBitblaster::AigBitblaster()
, d_bbAtoms()
, d_aigOutputNode(NULL)
{
- d_nullContext = new context::Context();
- d_satSolver = prop::SatSolverFactory::createMinisat(d_nullContext, "AigBitblaster");
- MinisatEmptyNotify* notify = new MinisatEmptyNotify();
- d_satSolver->setNotify(notify);
+ d_nullContext = new context::Context();
+ switch(options::bvSatSolver()) {
+ case SAT_SOLVER_MINISAT: {
+ prop::BVSatSolverInterface* minisat = prop::SatSolverFactory::createMinisat(d_nullContext,
+ smtStatisticsRegistry(),
+ "AigBitblaster");
+ MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+ minisat->setNotify(notify);
+ d_satSolver = minisat;
+ break;
+ }
+ case SAT_SOLVER_CRYPTOMINISAT:
+ d_satSolver = prop::SatSolverFactory::createCryptoMinisat(smtStatisticsRegistry(),
+ "AigBitblaster");
+ break;
+ default:
+ Unreachable("Unknown SAT solver type");
+ }
}
AigBitblaster::~AigBitblaster() {
@@ -402,7 +416,7 @@ void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
prop::SatLiteral lit(sat_variables[index-1], int_lit < 0);
clause.push_back(lit);
}
- d_satSolver->addClause(clause, false, RULE_INVALID);
+ d_satSolver->addClause(clause, false);
}
}
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
index cfbadbf32..c6c0d6def 100644
--- a/src/theory/bv/bitblaster_template.h
+++ b/src/theory/bv/bitblaster_template.h
@@ -257,7 +257,7 @@ public:
class EagerBitblaster : public TBitblaster<Node> {
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
// sat solver used for bitblasting and associated CnfStream
- prop::BVSatSolverInterface* d_satSolver;
+ prop::SatSolver* d_satSolver;
BitblastingRegistrar* d_bitblastingRegistrar;
context::Context* d_nullContext;
prop::CnfStream* d_cnfStream;
@@ -268,6 +268,8 @@ class EagerBitblaster : public TBitblaster<Node> {
MinisatEmptyNotify d_notify;
+ MinisatEmptyNotify d_notify;
+
Node getModelFromSatSolver(TNode a, bool fullModel);
bool isSharedTerm(TNode node);
@@ -306,7 +308,7 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> {
static Abc_Ntk_t* abcAigNetwork;
context::Context* d_nullContext;
- prop::BVSatSolverInterface* d_satSolver;
+ prop::SatSolver* d_satSolver;
TNodeAigMap d_aigCache;
NodeAigMap d_bbAtoms;
@@ -459,7 +461,7 @@ Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) {
if (Theory::isLeafOf(node, theory::THEORY_BV)) {
// if it is a leaf may ask for fullModel
- value = getModelFromSatSolver(node, fullModel);
+ value = getModelFromSatSolver(node, true);
Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from VarValue" << node <<" => " << value <<"\n";
Assert ((fullModel && !value.isNull() && value.isConst()) || !fullModel);
if (!value.isNull()) {
diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp
index 00d337395..b7e973928 100644
--- a/src/theory/bv/bv_subtheory_algebraic.cpp
+++ b/src/theory/bv/bv_subtheory_algebraic.cpp
@@ -714,7 +714,8 @@ void AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel) {
Assert (!value.isNull() || !fullModel);
// may be a shared term that did not appear in the current assertions
- if (!value.isNull()) {
+ // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
+ if (!value.isNull() && !d_modelMap->hasSubstitution(var)) {
Debug("bitvector-model") << " " << var << " => " << value << "\n";
Assert (value.getKind() == kind::CONST_BITVECTOR);
d_modelMap->addSubstitution(var, value);
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index b7619c4bb..6c6c13ee8 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -37,9 +37,9 @@ namespace bv {
BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
: SubtheorySolver(c, bv),
- d_bitblaster(new TLazyBitblaster(c, bv, "lazy")),
+ d_bitblaster(new TLazyBitblaster(c, bv, bv->getFullInstanceName() + "lazy")),
d_bitblastQueue(c),
- d_statistics(),
+ d_statistics(bv->getFullInstanceName()),
d_validModelCache(c, true),
d_lemmaAtomsQueue(c),
d_useSatPropagation(options::bitvectorPropagate()),
@@ -55,9 +55,9 @@ BitblastSolver::~BitblastSolver() {
delete d_bitblaster;
}
-BitblastSolver::Statistics::Statistics()
- : d_numCallstoCheck("theory::bv::BitblastSolver::NumCallsToCheck", 0)
- , d_numBBLemmas("theory::bv::BitblastSolver::NumTimesLemmasBB", 0)
+BitblastSolver::Statistics::Statistics(const std::string &instanceName)
+ : d_numCallstoCheck(instanceName + "theory::bv::BitblastSolver::NumCallsToCheck", 0)
+ , d_numBBLemmas(instanceName + "theory::bv::BitblastSolver::NumTimesLemmasBB", 0)
{
smtStatisticsRegistry()->registerStat(&d_numCallstoCheck);
smtStatisticsRegistry()->registerStat(&d_numBBLemmas);
@@ -68,8 +68,8 @@ BitblastSolver::Statistics::~Statistics() {
}
void BitblastSolver::setAbstraction(AbstractionModule* abs) {
- d_abstractionModule = abs;
- d_bitblaster->setAbstraction(abs);
+ d_abstractionModule = abs;
+ d_bitblaster->setAbstraction(abs);
}
void BitblastSolver::preRegister(TNode node) {
@@ -117,7 +117,7 @@ void BitblastSolver::bitblastQueue() {
bool BitblastSolver::check(Theory::Effort e) {
Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
- Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
+ Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
++(d_statistics.d_numCallstoCheck);
@@ -135,10 +135,10 @@ bool BitblastSolver::check(Theory::Effort e) {
// skip atoms that are the result of abstraction lemmas
if (d_abstractionModule->isLemmaAtom(fact)) {
d_lemmaAtomsQueue.push_back(fact);
- continue;
+ continue;
}
}
-
+
if (!d_bv->inConflict() &&
(!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
// Some atoms have not been bit-blasted yet
@@ -183,7 +183,7 @@ bool BitblastSolver::check(Theory::Effort e) {
if (options::bvAbstraction() &&
e == Theory::EFFORT_FULL &&
d_lemmaAtomsQueue.size()) {
-
+
// bit-blast lemma atoms
while(!d_lemmaAtomsQueue.empty()) {
TNode lemma_atom = d_lemmaAtomsQueue.front();
@@ -199,7 +199,7 @@ bool BitblastSolver::check(Theory::Effort e) {
return false;
}
}
-
+
Assert(!d_bv->inConflict());
bool ok = d_bitblaster->solve();
if (!ok) {
@@ -210,9 +210,9 @@ bool BitblastSolver::check(Theory::Effort e) {
++(d_statistics.d_numBBLemmas);
return false;
}
-
+
}
-
+
return true;
}
@@ -228,9 +228,9 @@ void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
Node BitblastSolver::getModelValue(TNode node)
{
if (d_bv->d_invalidateModelCache.get()) {
- d_bitblaster->invalidateModelCache();
+ d_bitblaster->invalidateModelCache();
}
- d_bv->d_invalidateModelCache.set(false);
+ d_bv->d_invalidateModelCache.set(false);
Node val = d_bitblaster->getTermModel(node, true);
return val;
}
@@ -241,9 +241,9 @@ void BitblastSolver::setConflict(TNode conflict) {
Node final_conflict = conflict;
if (options::bitvectorQuickXplain() &&
conflict.getKind() == kind::AND) {
- // std::cout << "Original conflict " << conflict.getNumChildren() << "\n";
+ // std::cout << "Original conflict " << conflict.getNumChildren() << "\n";
final_conflict = d_quickXplain->minimizeConflict(conflict);
- //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n";
+ //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n";
}
d_bv->setConflict(final_conflict);
}
@@ -256,4 +256,3 @@ void BitblastSolver::setProofLog( BitVectorProof * bvp ) {
}/* namespace CVC4::theory::bv */
}/* namespace CVC4::theory */
}/* namespace CVC4 */
-
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index e9300138b..fe16d2702 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -37,7 +37,7 @@ class BitblastSolver : public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
IntStat d_numBBLemmas;
- Statistics();
+ Statistics(const std::string &instanceName);
~Statistics();
};
/** Bitblaster */
@@ -71,8 +71,8 @@ public:
Node getModelValue(TNode node);
bool isComplete() { return true; }
void bitblastQueue();
- void setAbstraction(AbstractionModule* module);
- uint64_t computeAtomWeight(TNode atom);
+ void setAbstraction(AbstractionModule* module);
+ uint64_t computeAtomWeight(TNode atom);
void setProofLog( BitVectorProof * bvp );
};
diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp
index 3b54e3794..53fb4f94b 100644
--- a/src/theory/bv/eager_bitblaster.cpp
+++ b/src/theory/bv/eager_bitblaster.cpp
@@ -47,15 +47,30 @@ EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv)
{
d_bitblastingRegistrar = new BitblastingRegistrar(this);
d_nullContext = new context::Context();
-
- d_satSolver = prop::SatSolverFactory::createMinisat(
- d_nullContext, smtStatisticsRegistry(), "EagerBitblaster");
+
+ switch(options::bvSatSolver()) {
+ case SAT_SOLVER_MINISAT: {
+ prop::BVSatSolverInterface* minisat =
+ prop::SatSolverFactory::createMinisat(d_nullContext,
+ smtStatisticsRegistry(),
+ "EagerBitblaster");
+ MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+ minisat->setNotify(notify);
+ d_satSolver = minisat;
+ break;
+ }
+ case SAT_SOLVER_CRYPTOMINISAT:
+ d_satSolver = prop::SatSolverFactory::createCryptoMinisat(smtStatisticsRegistry(),
+ "EagerBitblaster");
+ break;
+ default:
+ Unreachable("Unknown SAT solver type");
+ }
d_cnfStream = new prop::TseitinCnfStream(
d_satSolver, d_bitblastingRegistrar, d_nullContext, options::proof(),
"EagerBitblaster");
- d_satSolver->setNotify(&d_notify);
d_bvp = NULL;
}
@@ -216,7 +231,7 @@ void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
// only shared terms could not have been bit-blasted
Assert (hasBBTerm(var) || isSharedTerm(var));
- Node const_value = getModelFromSatSolver(var, fullModel);
+ Node const_value = getModelFromSatSolver(var, true);
if(const_value != Node()) {
Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= "
diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp
index c821b50cd..b549c329a 100644
--- a/src/theory/bv/lazy_bitblaster.cpp
+++ b/src/theory/bv/lazy_bitblaster.cpp
@@ -491,7 +491,7 @@ void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
// only shared terms could not have been bit-blasted
Assert (hasBBTerm(var) || isSharedTerm(var));
- Node const_value = getModelFromSatSolver(var, fullModel);
+ Node const_value = getModelFromSatSolver(var, true);
Assert (const_value.isNull() || const_value.isConst());
if(const_value != Node()) {
Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 2edadce72..fec93e033 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -44,25 +44,29 @@ namespace bv {
TheoryBV::TheoryBV(context::Context* c, context::UserContext* u,
OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo)
- : Theory(THEORY_BV, c, u, out, valuation, logicInfo),
- d_context(c),
- d_alreadyPropagatedSet(c),
- d_sharedTermsSet(c),
- d_subtheories(),
- d_subtheoryMap(),
- d_statistics(),
- d_staticLearnCache(),
- d_lemmasAdded(c, false),
- d_conflict(c, false),
- d_invalidateModelCache(c, true),
- d_literalsToPropagate(c),
- d_literalsToPropagateIndex(c, 0),
- d_propagatedBy(c),
- d_eagerSolver(NULL),
- d_abstractionModule(new AbstractionModule()),
- d_isCoreTheory(false),
- d_calledPreregister(false)
+ const LogicInfo& logicInfo, std::string name)
+ : Theory(THEORY_BV, c, u, out, valuation, logicInfo, name),
+ d_context(c),
+ d_alreadyPropagatedSet(c),
+ d_sharedTermsSet(c),
+ d_subtheories(),
+ d_subtheoryMap(),
+ d_statistics(getFullInstanceName()),
+ d_staticLearnCache(),
+ d_BVDivByZero(),
+ d_BVRemByZero(),
+ d_funcToArgs(),
+ d_funcToSkolem(u),
+ d_lemmasAdded(c, false),
+ d_conflict(c, false),
+ d_invalidateModelCache(c, true),
+ d_literalsToPropagate(c),
+ d_literalsToPropagateIndex(c, 0),
+ d_propagatedBy(c),
+ d_eagerSolver(NULL),
+ d_abstractionModule(new AbstractionModule(getFullInstanceName())),
+ d_isCoreTheory(false),
+ d_calledPreregister(false)
{
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
@@ -117,14 +121,14 @@ void TheoryBV::spendResource(unsigned ammount) throw(UnsafeInterruptException) {
getOutputChannel().spendResource(ammount);
}
-TheoryBV::Statistics::Statistics():
- d_avgConflictSize("theory::bv::AvgBVConflictSize"),
- d_solveSubstitutions("theory::bv::NumberOfSolveSubstitutions", 0),
- d_solveTimer("theory::bv::solveTimer"),
- d_numCallsToCheckFullEffort("theory::bv::NumberOfFullCheckCalls", 0),
- d_numCallsToCheckStandardEffort("theory::bv::NumberOfStandardCheckCalls", 0),
- d_weightComputationTimer("theory::bv::weightComputationTimer"),
- d_numMultSlice("theory::bv::NumMultSliceApplied", 0)
+TheoryBV::Statistics::Statistics(const std::string &name):
+ d_avgConflictSize(name + "theory::bv::AvgBVConflictSize"),
+ d_solveSubstitutions(name + "theory::bv::NumberOfSolveSubstitutions", 0),
+ d_solveTimer(name + "theory::bv::solveTimer"),
+ d_numCallsToCheckFullEffort(name + "theory::bv::NumberOfFullCheckCalls", 0),
+ d_numCallsToCheckStandardEffort(name + "theory::bv::NumberOfStandardCheckCalls", 0),
+ d_weightComputationTimer(name + "theory::bv::weightComputationTimer"),
+ d_numMultSlice(name + "theory::bv::NumMultSliceApplied", 0)
{
smtStatisticsRegistry()->registerStat(&d_avgConflictSize);
smtStatisticsRegistry()->registerStat(&d_solveSubstitutions);
@@ -175,30 +179,31 @@ Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
}
-void TheoryBV::collectNumerators(TNode term, TNodeSet& seen) {
+void TheoryBV::collectFunctionSymbols(TNode term, TNodeSet& seen) {
if (seen.find(term) != seen.end())
return;
- if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UDIV) {
- unsigned size = utils::getSize(term[0]);
- if (d_BVDivByZeroAckerman.find(size) == d_BVDivByZeroAckerman.end()) {
- d_BVDivByZeroAckerman[size] = TNodeSet();
- }
- d_BVDivByZeroAckerman[size].insert(term[0]);
- seen.insert(term);
- } else if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UREM) {
- unsigned size = utils::getSize(term[0]);
- if (d_BVRemByZeroAckerman.find(size) == d_BVRemByZeroAckerman.end()) {
- d_BVRemByZeroAckerman[size] = TNodeSet();
- }
- d_BVRemByZeroAckerman[size].insert(term[0]);
- seen.insert(term);
+ if (term.getKind() == kind::APPLY_UF) {
+ TNode func = term.getOperator();
+ storeFunction(func, term);
}
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- collectNumerators(term[i], seen);
+ collectFunctionSymbols(term[i], seen);
}
seen.insert(term);
}
+void TheoryBV::storeFunction(TNode func, TNode term) {
+ if (d_funcToArgs.find(func) == d_funcToArgs.end()) {
+ d_funcToArgs.insert(make_pair(func, NodeSet()));
+ }
+ NodeSet& set = d_funcToArgs[func];
+ if (set.find(term) == set.end()) {
+ set.insert(term);
+ Node skolem = utils::mkVar(utils::getSize(term));
+ d_funcToSkolem.addSubstitution(term, skolem);
+ }
+}
+
void TheoryBV::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
Debug("bv-ackermanize") << "TheoryBV::mkAckermanizationAsssertions\n";
@@ -206,51 +211,44 @@ void TheoryBV::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
AlwaysAssert(!options::incrementalSolving());
TNodeSet seen;
for (unsigned i = 0; i < assertions.size(); ++i) {
- collectNumerators(assertions[i], seen);
- }
-
- // process division UF
- Debug("bv-ackermanize") << "Process division UF...\n";
- for (WidthToNumerators::const_iterator it = d_BVDivByZeroAckerman.begin(); it != d_BVDivByZeroAckerman.end(); ++it) {
- const TNodeSet& numerators= it->second;
- for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
- TNodeSet::const_iterator j = i;
- j++;
- for (; j != numerators.end(); ++j) {
- TNode arg1 = *i;
- TNode arg2 = *j;
- TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg1);
- TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg2);
-
- Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
- Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
- Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
- Debug("bv-ackermanize") << " " << lemma << "\n";
- assertions.push_back(lemma);
- }
- }
+ collectFunctionSymbols(assertions[i], seen);
}
- // process remainder UF
- Debug("bv-ackermanize") << "Process remainder UF...\n";
- for (WidthToNumerators::const_iterator it = d_BVRemByZeroAckerman.begin(); it != d_BVRemByZeroAckerman.end(); ++it) {
- const TNodeSet& numerators= it->second;
- for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
- TNodeSet::const_iterator j = i;
- j++;
- for (; j != numerators.end(); ++j) {
- TNode arg1 = *i;
- TNode arg2 = *j;
- TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg1);
- TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg2);
-
- Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
- Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
- Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
- Debug("bv-ackermanize") << " " << lemma << "\n";
+
+ FunctionToArgs::const_iterator it = d_funcToArgs.begin();
+ NodeManager* nm = NodeManager::currentNM();
+ for (; it!= d_funcToArgs.end(); ++it) {
+ TNode func = it->first;
+ const NodeSet& args = it->second;
+ NodeSet::const_iterator it1 = args.begin();
+ for ( ; it1 != args.end(); ++it1) {
+ for(NodeSet::const_iterator it2 = it1; it2 != args.end(); ++it2) {
+ TNode args1 = *it1;
+ TNode args2 = *it2;
+
+ AlwaysAssert (args1.getKind() == kind::APPLY_UF &&
+ args1.getOperator() == func);
+ AlwaysAssert (args2.getKind() == kind::APPLY_UF &&
+ args2.getOperator() == func);
+ AlwaysAssert (args1.getNumChildren() == args2.getNumChildren());
+
+ std::vector<Node> eqs(args1.getNumChildren());
+
+ for (unsigned i = 0; i < args1.getNumChildren(); ++i) {
+ eqs[i] = nm->mkNode(kind::EQUAL, args1[i], args2[i]);
+ }
+
+ Node args_eq = eqs.size() == 1 ? eqs[0] : nm->mkNode(kind::AND, eqs);
+ Node func_eq = nm->mkNode(kind::EQUAL, args1, args2);
+ Node lemma = nm->mkNode(kind::IMPLIES, args_eq, func_eq);
assertions.push_back(lemma);
}
}
}
+
+ // replace applications of UF by skolems (FIXME for model building)
+ for(unsigned i = 0; i < assertions.size(); ++i) {
+ assertions[i] = d_funcToSkolem.apply(assertions[i]);
+ }
}
Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
@@ -278,18 +276,18 @@ Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
kind::BITVECTOR_UREM_TOTAL, num, den);
- if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- // Ackermanize UF if using eager bit-blasting
- Node ackerman_var = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_ACKERMANIZE_UDIV : kind::BITVECTOR_ACKERMANIZE_UREM, num);
- node = nm->mkNode(kind::ITE, den_eq_0, ackerman_var, divTotalNumDen);
- return node;
- } else {
+ // if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ // // Ackermanize UF if using eager bit-blasting
+ // Node ackerman_var = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_ACKERMANIZE_UDIV : kind::BITVECTOR_ACKERMANIZE_UREM, num);
+ // node = nm->mkNode(kind::ITE, den_eq_0, ackerman_var, divTotalNumDen);
+ // return node;
+ // } else {
Node divByZero = getBVDivByZero(node.getKind(), width);
Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
logicRequest.widenLogic(THEORY_UF);
return node;
- }
+ //}
}
break;
@@ -331,7 +329,7 @@ void TheoryBV::sendConflict() {
if (d_conflictNode.isNull()) {
return;
} else {
- Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode;
+ Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode << std::endl;
d_out->conflict(d_conflictNode);
d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
d_conflictNode = Node::null();
@@ -707,7 +705,7 @@ Node TheoryBV::explain(TNode node) {
// return the explanation
Node explanation = utils::mkAnd(assumptions);
Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
- Debug("bitvector::explain") << "TheoryBV::explain done. \n";
+ Debug("bitvector::explain") << "TheoryBV::explain done. \n";
return explanation;
}
@@ -725,6 +723,8 @@ void TheoryBV::addSharedTerm(TNode t) {
EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
{
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
+ return EQUALITY_UNKNOWN;
Assert (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY);
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 0bbcba9b0..ba2a4fc2a 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -56,7 +56,8 @@ class TheoryBV : public Theory {
public:
TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out,
- Valuation valuation, const LogicInfo& logicInfo);
+ Valuation valuation, const LogicInfo& logicInfo,
+ std::string name = "");
~TheoryBV();
@@ -88,8 +89,8 @@ public:
void presolve();
- bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
-
+ bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+
void setProofLog( BitVectorProof * bvp );
private:
@@ -100,10 +101,10 @@ private:
IntStat d_solveSubstitutions;
TimerStat d_solveTimer;
IntStat d_numCallsToCheckFullEffort;
- IntStat d_numCallsToCheckStandardEffort;
+ IntStat d_numCallsToCheckStandardEffort;
TimerStat d_weightComputationTimer;
IntStat d_numMultSlice;
- Statistics();
+ Statistics(const std::string &name);
~Statistics();
};
@@ -121,12 +122,12 @@ private:
*/
Node getBVDivByZero(Kind k, unsigned width);
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
- void collectNumerators(TNode term, TNodeSet& seen);
-
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ void collectFunctionSymbols(TNode term, TNodeSet& seen);
+ void storeFunction(TNode func, TNode term);
typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
NodeSet d_staticLearnCache;
-
+
/**
* Maps from bit-vector width to division-by-zero uninterpreted
* function symbols.
@@ -134,17 +135,15 @@ private:
__gnu_cxx::hash_map<unsigned, Node> d_BVDivByZero;
__gnu_cxx::hash_map<unsigned, Node> d_BVRemByZero;
- /**
- * Maps from bit-vector width to numerators
- * of uninterpreted function symbol
- */
- typedef __gnu_cxx::hash_map<unsigned, TNodeSet > WidthToNumerators;
- WidthToNumerators d_BVDivByZeroAckerman;
- WidthToNumerators d_BVRemByZeroAckerman;
+ typedef __gnu_cxx::hash_map<Node, NodeSet, NodeHashFunction> FunctionToArgs;
+ typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeToNode;
+ // for ackermanization
+ FunctionToArgs d_funcToArgs;
+ CVC4::theory::SubstitutionMap d_funcToSkolem;
context::CDO<bool> d_lemmasAdded;
-
+
// Are we in conflict?
context::CDO<bool> d_conflict;
@@ -167,17 +166,17 @@ private:
typedef context::CDHashMap<Node, SubTheory, NodeHashFunction> PropagatedMap;
PropagatedMap d_propagatedBy;
- EagerBitblastSolver* d_eagerSolver;
+ EagerBitblastSolver* d_eagerSolver;
AbstractionModule* d_abstractionModule;
bool d_isCoreTheory;
bool d_calledPreregister;
-
+
bool wasPropagatedBySubtheory(TNode literal) const {
- return d_propagatedBy.find(literal) != d_propagatedBy.end();
+ return d_propagatedBy.find(literal) != d_propagatedBy.end();
}
-
+
SubTheory getPropagatingSubtheory(TNode literal) const {
- Assert(wasPropagatedBySubtheory(literal));
+ Assert(wasPropagatedBySubtheory(literal));
PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
return (*find).second;
}
@@ -193,7 +192,7 @@ private:
void addSharedTerm(TNode t);
bool isSharedTerm(TNode t) { return d_sharedTermsSet.contains(t); }
-
+
EqualityStatus getEqualityStatus(TNode a, TNode b);
Node getModelValue(TNode var);
@@ -214,7 +213,7 @@ private:
void lemma(TNode node) { d_out->lemma(node, RULE_CONFLICT); d_lemmasAdded = true; }
- void checkForLemma(TNode node);
+ void checkForLemma(TNode node);
friend class LazyBitblaster;
friend class TLazyBitblaster;
diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
index 152a335a5..2bcb6ca1b 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -349,7 +349,7 @@ Node RewriteRule<SdivEliminate>::apply(TNode node) {
Node abs_a = utils::mkNode(kind::ITE, a_lt_0, utils::mkNode(kind::BITVECTOR_NEG, a), a);
Node abs_b = utils::mkNode(kind::ITE, b_lt_0, utils::mkNode(kind::BITVECTOR_NEG, b), b);
- Node a_udiv_b = utils::mkNode(kind::BITVECTOR_UDIV, abs_a, abs_b);
+ Node a_udiv_b = utils::mkNode(options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UDIV_TOTAL : kind::BITVECTOR_UDIV, abs_a, abs_b);
Node neg_result = utils::mkNode(kind::BITVECTOR_NEG, a_udiv_b);
Node condition = utils::mkNode(kind::XOR, a_lt_0, b_lt_0);
@@ -377,7 +377,7 @@ Node RewriteRule<SremEliminate>::apply(TNode node) {
Node abs_a = utils::mkNode(kind::ITE, a_lt_0, utils::mkNode(kind::BITVECTOR_NEG, a), a);
Node abs_b = utils::mkNode(kind::ITE, b_lt_0, utils::mkNode(kind::BITVECTOR_NEG, b), b);
- Node a_urem_b = utils::mkNode(kind::BITVECTOR_UREM, abs_a, abs_b);
+ Node a_urem_b = utils::mkNode( options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UREM_TOTAL : kind::BITVECTOR_UREM, abs_a, abs_b);
Node neg_result = utils::mkNode(kind::BITVECTOR_NEG, a_urem_b);
Node result = utils::mkNode(kind::ITE, a_lt_0, neg_result, a_urem_b);
diff --git a/src/theory/datatypes/datatypes_sygus.cpp b/src/theory/datatypes/datatypes_sygus.cpp
index 5bd6680f2..4514453db 100644
--- a/src/theory/datatypes/datatypes_sygus.cpp
+++ b/src/theory/datatypes/datatypes_sygus.cpp
@@ -402,6 +402,60 @@ void SygusSplit::registerSygusTypeConstructorArg( TypeNode tnn, const Datatype&
}
}
+class ReqTrie {
+public:
+ ReqTrie() : d_req_kind( UNDEFINED_KIND ){}
+ std::map< unsigned, ReqTrie > d_children;
+ Kind d_req_kind;
+ TypeNode d_req_type;
+ Node d_req_const;
+ void print( const char * c, int indent = 0 ){
+ if( d_req_kind!=UNDEFINED_KIND ){
+ Trace(c) << d_req_kind << " ";
+ }else if( !d_req_type.isNull() ){
+ Trace(c) << d_req_type;
+ }else if( !d_req_const.isNull() ){
+ Trace(c) << d_req_const;
+ }else{
+ Trace(c) << "_";
+ }
+ Trace(c) << std::endl;
+ for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ for( int i=0; i<=indent; i++ ) { Trace(c) << " "; }
+ Trace(c) << it->first << " : ";
+ it->second.print( c, indent+1 );
+ }
+ }
+ bool satisfiedBy( quantifiers::TermDbSygus * tdb, TypeNode tn ){
+ if( d_req_kind!=UNDEFINED_KIND ){
+ int c = tdb->getKindArg( tn, d_req_kind );
+ if( c!=-1 ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ if( it->first<dt[c].getNumArgs() ){
+ TypeNode tnc = tdb->getArgType( dt[c], it->first );
+ if( !it->second.satisfiedBy( tdb, tnc ) ){
+ return false;
+ }
+ }else{
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+ }else if( !d_req_const.isNull() ){
+ return tdb->hasConst( tn, d_req_const );
+ }else if( !d_req_type.isNull() ){
+ return tn==d_req_type;
+ }else{
+ return true;
+ }
+ }
+};
+
+
//this function gets all easy redundant cases, before consulting rewriters
bool SygusSplit::considerSygusSplitKind( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Kind k, Kind parent, int arg ) {
Assert( d_tds->hasKind( tn, k ) );
@@ -419,101 +473,168 @@ bool SygusSplit::considerSygusSplitKind( const Datatype& dt, const Datatype& pdt
return arg==firstArg;
}
}
- //push
+ //describes the shape of an alternate term to construct
+ // we check whether this term is in the sygus grammar below
+ ReqTrie rt;
+ bool rt_valid = false;
+
+ //construct rt by cases
if( parent==NOT || parent==BITVECTOR_NOT || parent==UMINUS || parent==BITVECTOR_NEG ){
- //negation normal form
- if( parent==k && isArgDatatype( dt[c], 0, pdt ) ){
- return false;
- }
- Kind nk = UNDEFINED_KIND;
- Kind reqk = UNDEFINED_KIND; //required kind for all children
- if( parent==NOT ){
- if( k==AND ) {
- nk = OR;reqk = NOT;
- }else if( k==OR ){
- nk = AND;reqk = NOT;
- }else if( k==IFF ) {
- nk = XOR;
- }else if( k==XOR ) {
- nk = IFF;
- }
- }
- if( parent==BITVECTOR_NOT ){
- if( k==BITVECTOR_AND ) {
- nk = BITVECTOR_OR;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_OR ){
- nk = BITVECTOR_AND;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_XNOR ) {
- nk = BITVECTOR_XOR;
- }else if( k==BITVECTOR_XOR ) {
- nk = BITVECTOR_XNOR;
- }
- }
- if( parent==UMINUS ){
- if( k==PLUS ){
- nk = PLUS;reqk = UMINUS;
- }
- }
- if( parent==BITVECTOR_NEG ){
- if( k==PLUS ){
- nk = PLUS;reqk = BITVECTOR_NEG;
- }
- }
- if( nk!=UNDEFINED_KIND ){
- Trace("sygus-split-debug") << "Push " << parent << " over " << k << " to " << nk;
- if( reqk!=UNDEFINED_KIND ){
- Trace("sygus-split-debug") << ", reqk = " << reqk;
+ rt_valid = true;
+ //negation normal form
+ if( parent==k ){
+ rt.d_req_type = d_tds->getArgType( dt[c], 0 );
+ }else{
+ Kind reqk = UNDEFINED_KIND; //required kind for all children
+ std::map< unsigned, Kind > reqkc; //required kind for some children
+ if( parent==NOT ){
+ if( k==AND ) {
+ rt.d_req_kind = OR;reqk = NOT;
+ }else if( k==OR ){
+ rt.d_req_kind = AND;reqk = NOT;
+ }else if( k==IFF ) {
+ rt.d_req_kind = XOR;
+ }else if( k==XOR ) {
+ rt.d_req_kind = IFF;
+ }else if( k==ITE ){
+ rt.d_req_kind = ITE;reqkc[1] = NOT;reqkc[2] = NOT;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ }else if( k==LEQ || k==GT ){
+ // (not (~ x y)) -----> (~ (+ y 1) x)
+ rt.d_req_kind = k;
+ rt.d_children[0].d_req_kind = PLUS;
+ rt.d_children[0].d_children[0].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt.d_children[0].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+ rt.d_children[1].d_req_type = d_tds->getArgType( dt[c], 0 );
+ //TODO: other possibilities?
+ }else if( k==LT || k==GEQ ){
+ // (not (~ x y)) -----> (~ y (+ x 1))
+ rt.d_req_kind = k;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt.d_children[1].d_req_kind = PLUS;
+ rt.d_children[1].d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==BITVECTOR_NOT ){
+ if( k==BITVECTOR_AND ) {
+ rt.d_req_kind = BITVECTOR_OR;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_OR ){
+ rt.d_req_kind = BITVECTOR_AND;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_XNOR ) {
+ rt.d_req_kind = BITVECTOR_XOR;
+ }else if( k==BITVECTOR_XOR ) {
+ rt.d_req_kind = BITVECTOR_XNOR;
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==UMINUS ){
+ if( k==PLUS ){
+ rt.d_req_kind = PLUS;reqk = UMINUS;
+ }else{
+ rt_valid = false;
+ }
+ }else if( parent==BITVECTOR_NEG ){
+ if( k==PLUS ){
+ rt.d_req_kind = PLUS;reqk = BITVECTOR_NEG;
+ }else{
+ rt_valid = false;
+ }
}
- Trace("sygus-split-debug") << "?" << std::endl;
- int pcr = d_tds->getKindArg( tnp, nk );
- if( pcr!=-1 ){
- Assert( pcr<(int)pdt.getNumConstructors() );
- if( reqk!=UNDEFINED_KIND ){
+ if( rt_valid && ( reqk!=UNDEFINED_KIND || !reqkc.empty() ) ){
+ int pcr = d_tds->getKindArg( tnp, rt.d_req_kind );
+ if( pcr!=-1 ){
+ Assert( pcr<(int)pdt.getNumConstructors() );
//must have same number of arguments
if( pdt[pcr].getNumArgs()==dt[c].getNumArgs() ){
- bool success = true;
- std::map< int, TypeNode > childTypes;
for( unsigned i=0; i<pdt[pcr].getNumArgs(); i++ ){
- TypeNode tna = d_tds->getArgType( pdt[pcr], i );
- Assert( datatypes::DatatypesRewriter::isTypeDatatype( tna ) );
- if( reqk!=UNDEFINED_KIND ){
- //child must have a NOT
- int nindex = d_tds->getKindArg( tna, reqk );
- if( nindex!=-1 ){
- const Datatype& adt = ((DatatypeType)(tn).toType()).getDatatype();
- if( d_tds->getArgType( dt[c], i )!=d_tds->getArgType( adt[nindex], 0 ) ){
- Trace("sygus-split-debug") << "...arg " << i << " type mismatch." << std::endl;
- success = false;
- break;
- }
- }else{
- Trace("sygus-split-debug") << "...argument " << i << " does not have " << reqk << "." << std::endl;
- success = false;
- break;
+ Kind rk = reqk;
+ if( reqk==UNDEFINED_KIND ){
+ std::map< unsigned, Kind >::iterator itr = reqkc.find( i );
+ if( itr!=reqkc.end() ){
+ rk = itr->second;
}
- }else{
- childTypes[i] = tna;
}
- }
- if( success ){
- Trace("sygus-split-debug") << "...success" << std::endl;
- return false;
+ if( rk!=UNDEFINED_KIND ){
+ rt.d_children[i].d_req_kind = rk;
+ rt.d_children[i].d_children[0].d_req_type = d_tds->getArgType( dt[c], i );
+ }
}
}else{
- Trace("sygus-split-debug") << "...#arg mismatch." << std::endl;
+ rt_valid = false;
}
}else{
- return !isTypeMatch( pdt[pcr], dt[c] );
+ rt_valid = false;
}
- }else{
- Trace("sygus-split-debug") << "...operator not available." << std::endl;
}
}
+ }else if( k==MINUS || k==BITVECTOR_SUB ){
+ if( parent==EQUAL ||
+ parent==MINUS || parent==BITVECTOR_SUB ||
+ parent==LEQ || parent==LT || parent==GEQ || parent==GT ){
+ int oarg = arg==0 ? 1 : 0;
+ // (~ x (- y z)) ----> (~ (+ x z) y)
+ // (~ (- y z) x) ----> (~ y (+ x z))
+ rt.d_req_kind = parent;
+ rt.d_children[arg].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[oarg].d_req_kind = k==MINUS ? PLUS : BITVECTOR_PLUS;
+ rt.d_children[oarg].d_children[0].d_req_type = d_tds->getArgType( pdt[pc], oarg );
+ rt.d_children[oarg].d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt_valid = true;
+ }else if( parent==PLUS || parent==BITVECTOR_PLUS ){
+ // (+ x (- y z)) -----> (- (+ x y) z)
+ // (+ (- y z) x) -----> (- (+ x y) z)
+ rt.d_req_kind = parent==PLUS ? MINUS : BITVECTOR_SUB;
+ int oarg = arg==0 ? 1 : 0;
+ rt.d_children[0].d_req_kind = parent;
+ rt.d_children[0].d_children[0].d_req_type = d_tds->getArgType( pdt[pc], oarg );
+ rt.d_children[0].d_children[1].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
+ rt_valid = true;
+ }
+ }else if( k==ITE ){
+ if( parent!=ITE ){
+ // (o X (ite y z w) X') -----> (ite y (o X z X') (o X w X'))
+ rt.d_req_kind = ITE;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ unsigned n_args = pdt[pc].getNumArgs();
+ for( unsigned r=1; r<=2; r++ ){
+ rt.d_children[r].d_req_kind = parent;
+ for( unsigned q=0; q<n_args; q++ ){
+ if( (int)q==arg ){
+ rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( dt[c], r );
+ }else{
+ rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( pdt[pc], q );
+ }
+ }
+ }
+ rt_valid = true;
+ //TODO: this increases term size but is probably a good idea
+ }
+ }else if( k==NOT ){
+ if( parent==ITE ){
+ // (ite (not y) z w) -----> (ite y w z)
+ rt.d_req_kind = ITE;
+ rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
+ rt.d_children[1].d_req_type = d_tds->getArgType( pdt[pc], 2 );
+ rt.d_children[2].d_req_type = d_tds->getArgType( pdt[pc], 1 );
+ }
}
- if( parent==MINUS || parent==BITVECTOR_SUB ){
-
-
+ Trace("sygus-consider-split") << "Consider sygus split kind " << k << ", parent = " << parent << ", arg = " << arg << "?" << std::endl;
+ if( rt_valid ){
+ rt.print("sygus-consider-split");
+ //check if it meets the requirements
+ if( rt.satisfiedBy( d_tds, tnp ) ){
+ Trace("sygus-consider-split") << "...success!" << std::endl;
+ //do not need to consider the kind in the search since there are ways to construct equivalent terms
+ return false;
+ }else{
+ Trace("sygus-consider-split") << "...failed." << std::endl;
+ }
+ Trace("sygus-consider-split") << std::endl;
}
+ //must consider this kind in the search
return true;
}
@@ -616,6 +737,7 @@ bool SygusSplit::isGenericRedundant( TypeNode tn, Node g, bool active ) {
d_gen_terms[tn][gr] = g;
d_gen_terms_inactive[tn][gr] = g;
Trace("sygus-gnf-debug") << "...not redundant." << std::endl;
+ Trace("sygus-nf-reg") << "*** Sygus (generic) normal form : normal form of " << g << " is " << gr << std::endl;
}else{
Trace("sygus-gnf-debug") << "...redundant." << std::endl;
Trace("sygus-nf") << "* Sygus normal form : simplify since " << g << " and " << itg->second << " both rewrite to " << gr << std::endl;
@@ -849,6 +971,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
}else{
d_redundant[at][prog] = false;
red = false;
+ Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << std::endl;
}
}else{
rep_prog = itnp->second;
@@ -858,6 +981,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
d_redundant[at].erase( rep_prog );
d_redundant[at][prog] = false;
red = false;
+ Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << " (redundant but smaller than " << rep_prog << ") " << std::endl;
}else{
Assert( prog!=itnp->second );
d_redundant[at][prog] = true;
@@ -1090,6 +1214,7 @@ bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node
}
}else{
red = it->second;
+ Trace("sygus-nf-debug") << "Already processed, redundant : " << red << std::endl;
}
if( red ){
if( std::find( d_lemmas_reported[at][prog].begin(), d_lemmas_reported[at][prog].end(), a )==d_lemmas_reported[at][prog].end() ){
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index d035f0fa7..3338e5f31 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -105,7 +105,7 @@ typerule RECORD_UPDATE ::CVC4::theory::datatypes::RecordUpdateTypeRule
operator DT_SIZE 1 "datatypes size"
typerule DT_SIZE ::CVC4::theory::datatypes::DtSizeTypeRule
-operator DT_HEIGHT_BOUND 1 "datatypes height bound"
+operator DT_HEIGHT_BOUND 2 "datatypes height bound"
typerule DT_HEIGHT_BOUND ::CVC4::theory::datatypes::DtHeightBoundTypeRule
endtheory
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index eb8b23973..a2f995935 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -27,9 +27,11 @@
#include "theory/datatypes/datatypes_rewriter.h"
#include "theory/datatypes/theory_datatypes_type_rules.h"
#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/valuation.h"
+#include "options/theory_options.h"
using namespace std;
using namespace CVC4::kind;
@@ -54,8 +56,7 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
//d_consEqc( c ),
d_conflict( c, false ),
d_collectTermsCache( c ),
- d_consTerms( c ),
- d_selTerms( c ),
+ d_functionTerms( c ),
d_singleton_eq( u ),
d_lemmas_produced_c( u )
{
@@ -81,6 +82,8 @@ TheoryDatatypes::~TheoryDatatypes() {
Assert(current != NULL);
delete current;
}
+ delete d_sygus_split;
+ delete d_sygus_sym_break;
}
void TheoryDatatypes::setMasterEqualityEngine(eq::EqualityEngine* eq) {
@@ -91,9 +94,7 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( TNode n, bool doMak
if( !hasEqcInfo( n ) ){
if( doMake ){
//add to labels
- NodeList* lbl = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_labels.insertDataFromContextMemory( n, lbl );
+ d_labels[ n ] = 0;
std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
EqcInfo* ei;
@@ -106,10 +107,10 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( TNode n, bool doMak
if( n.getKind()==APPLY_CONSTRUCTOR ){
ei->d_constructor = n;
}
+
//add to selectors
- NodeList* sel = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_selector_apps.insertDataFromContextMemory( n, sel );
+ d_selector_apps[n] = 0;
+
return ei;
}else{
return NULL;
@@ -178,6 +179,7 @@ void TheoryDatatypes::check(Effort e) {
Trace("datatypes-debug") << "Check for splits " << e << endl;
do {
d_addedFact = false;
+ bool added_split = false;
std::map< TypeNode, Node > rec_singletons;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
@@ -190,7 +192,7 @@ void TheoryDatatypes::check(Effort e) {
if( !hasLabel( eqc, n ) ){
Trace("datatypes-debug") << "No constructor..." << std::endl;
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- Trace("datatypes-debug") << "Datatype " << dt << " is " << dt.isFinite() << " " << dt.isUFinite() << " " << dt.isRecursiveSingleton() << std::endl;
+ Trace("datatypes-debug") << "Datatype " << dt << " is " << dt.isFinite() << " " << dt.isInterpretedFinite() << " " << dt.isRecursiveSingleton() << std::endl;
bool continueProc = true;
if( dt.isRecursiveSingleton() ){
Trace("datatypes-debug") << "Check recursive singleton..." << std::endl;
@@ -251,7 +253,7 @@ void TheoryDatatypes::check(Effort e) {
if( consIndex==-1 ){
consIndex = j;
}
- if( options::finiteModelFind() ? !dt[ j ].isUFinite() : !dt[ j ].isFinite() ) {
+ if( !dt[ j ].isInterpretedFinite() ) {
if( !eqc || !eqc->d_selectors ){
needSplit = false;
}
@@ -311,7 +313,10 @@ void TheoryDatatypes::check(Effort e) {
//doSendLemma( lemma );
d_out->lemma( lemma, false, false, true );
}
- return;
+ added_split = true;
+ if( !options::dtBlastSplits() ){
+ return;
+ }
}
}else{
Trace("dt-split-debug") << "Do not split constructor for " << n << " : " << n.getType() << " " << dt.getNumConstructors() << std::endl;
@@ -323,6 +328,9 @@ void TheoryDatatypes::check(Effort e) {
}
++eqcs_i;
}
+ if( added_split ){
+ return;
+ }
Trace("datatypes-debug") << "Flush pending facts..." << std::endl;
flushPendingFacts();
/*
@@ -870,33 +878,36 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
//merge labels
- NodeListMap::iterator lbl_i = d_labels.find( t2 );
+ NodeIntMap::iterator lbl_i = d_labels.find( t2 );
if( lbl_i != d_labels.end() ){
Trace("datatypes-debug") << " merge labels from " << eqc2 << " " << t2 << std::endl;
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); ++j ){
- Node tt = (*j).getKind()==kind::NOT ? (*j)[0] : (*j);
+ int n_label = (*lbl_i).second;
+ for( int i=0; i<n_label; i++ ){
+ Assert( i<(int)d_labels_data[ t2 ].size() );
+ Node t = d_labels_data[ t2 ][i];
+ Node tt = t.getKind()==kind::NOT ? t[0] : t;
Node t_arg;
int tindex = DatatypesRewriter::isTester( tt, t_arg );
Assert( tindex!=-1 );
- addTester( tindex, *j, eqc1, t1, t_arg );
+ addTester( tindex, t, eqc1, t1, t_arg );
if( d_conflict ){
Trace("datatypes-debug") << " conflict!" << std::endl;
return;
}
}
+
}
//merge selectors
if( !eqc1->d_selectors && eqc2->d_selectors ){
eqc1->d_selectors = true;
checkInst = true;
}
- NodeListMap::iterator sel_i = d_selector_apps.find( t2 );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( t2 );
if( sel_i != d_selector_apps.end() ){
Trace("datatypes-debug") << " merge selectors from " << eqc2 << " " << t2 << std::endl;
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
- addSelector( *j, eqc1, t1, eqc2->d_constructor.get().isNull() );
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ addSelector( d_selector_apps_data[t2][j], eqc1, t1, eqc2->d_constructor.get().isNull() );
}
}
if( checkInst ){
@@ -927,11 +938,11 @@ bool TheoryDatatypes::hasLabel( EqcInfo* eqc, Node n ){
}
Node TheoryDatatypes::getLabel( Node n ) {
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- if( !(*lbl).empty() && (*lbl)[ (*lbl).size() - 1 ].getKind()!=kind::NOT ){
- return (*lbl)[ (*lbl).size() - 1 ];
+ unsigned n_lbl = (*lbl_i).second;
+ if( n_lbl>0 && d_labels_data[n][ n_lbl-1 ].getKind()!=kind::NOT ){
+ return d_labels_data[n][ n_lbl-1 ];
}
}
return Node::null();
@@ -954,9 +965,9 @@ int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){
}
bool TheoryDatatypes::hasTester( Node n ) {
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- return !(*(*lbl_i).second).empty();
+ return (*lbl_i).second>0;
}else{
return false;
}
@@ -969,13 +980,14 @@ void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >
if( lindex!=-1 ){
pcons[ lindex ] = true;
}else{
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- Assert( (*i).getKind()==NOT );
- //pcons[ Datatype::indexOf( (*i)[0].getOperator().toExpr() ) ] = false;
- int tindex = DatatypesRewriter::isTester( (*i)[0] );
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node t = d_labels_data[n][i];
+ Assert( t.getKind()==NOT );
+ //pcons[ Datatype::indexOf( t[0].getOperator().toExpr() ) ] = false;
+ int tindex = DatatypesRewriter::isTester( t[0] );
Assert( tindex!=-1 );
pcons[ tindex ] = false;
}
@@ -984,11 +996,11 @@ void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >
}
void TheoryDatatypes::getSelectorsForCons( Node r, std::map< int, bool >& sels ) {
- NodeListMap::iterator sel_i = d_selector_apps.find( r );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( r );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); j++ ){
- int sindex = Datatype::indexOf( (*j).getOperator().toExpr() );
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ int sindex = Datatype::indexOf( d_selector_apps_data[r][j].getOperator().toExpr() );
sels[sindex] = true;
}
}
@@ -1055,12 +1067,13 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
}
}else{
//otherwise, scan list of labels
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
Assert( lbl_i != d_labels.end() );
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- Assert( (*i).getKind()==NOT );
- j = *i;
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node ti = d_labels_data[n][i];
+ Assert( ti.getKind()==NOT );
+ j = ti;
jt = j[0];
//int jtindex = Datatype::indexOf( jt.getOperator().toExpr() );
int jtindex = DatatypesRewriter::isTester( jt );
@@ -1076,16 +1089,24 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
}
if( !makeConflict ){
Debug("datatypes-labels") << "Add to labels " << t << std::endl;
- lbl->push_back( t );
+ //lbl->push_back( t );
+ d_labels[n] = n_lbl + 1;
+ if( n_lbl<(int)d_labels_data[n].size() ){
+ d_labels_data[n][n_lbl] = t;
+ }else{
+ d_labels_data[n].push_back( t );
+ }
+ n_lbl++;
+
const Datatype& dt = ((DatatypeType)(t_arg.getType()).toType()).getDatatype();
- Debug("datatypes-labels") << "Labels at " << lbl->size() << " / " << dt.getNumConstructors() << std::endl;
+ Debug("datatypes-labels") << "Labels at " << n_lbl << " / " << dt.getNumConstructors() << std::endl;
if( tpolarity ){
instantiate( eqc, n );
}else{
//check if we have reached the maximum number of testers
// in this case, add the positive tester
//this should not be done for sygus, since cases may be limited
- if( lbl->size()==dt.getNumConstructors()-1 && !dt.isSygus() ){
+ if( n_lbl==(int)dt.getNumConstructors()-1 && !dt.isSygus() ){
std::vector< bool > pcons;
getPossibleCons( eqc, n, pcons );
int testerIndex = -1;
@@ -1099,11 +1120,14 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
//we must explain why each term in the set of testers for this equivalence class is equal
std::vector< Node > eq_terms;
NodeBuilder<> nb(kind::AND);
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- nb << (*i);
- Assert( (*i).getKind()==NOT );
+ //for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
+
+ for( int i=0; i<n_lbl; i++ ){
+ Node ti = d_labels_data[n][i];
+ nb << ti;
+ Assert( ti.getKind()==NOT );
Node t_arg2;
- DatatypesRewriter::isTester( (*i)[0], t_arg2 );
+ DatatypesRewriter::isTester( ti[0], t_arg2 );
//Assert( tindex!=-1 );
if( std::find( eq_terms.begin(), eq_terms.end(), t_arg2 )==eq_terms.end() ){
eq_terms.push_back( t_arg2 );
@@ -1140,19 +1164,26 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
void TheoryDatatypes::addSelector( Node s, EqcInfo* eqc, Node n, bool assertFacts ) {
Trace("dt-collapse-sel") << "Add selector : " << s << " to eqc(" << n << ")" << std::endl;
//check to see if it is redundant
- NodeListMap::iterator sel_i = d_selector_apps.find( n );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( n );
Assert( sel_i != d_selector_apps.end() );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
- Node ss = *j;
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ Node ss = d_selector_apps_data[n][j];
if( s.getOperator()==ss.getOperator() && ( s.getKind()!=DT_HEIGHT_BOUND || s[1]==ss[1] ) ){
Trace("dt-collapse-sel") << "...redundant." << std::endl;
return;
}
}
//add it to the vector
- sel->push_back( s );
+ //sel->push_back( s );
+ d_selector_apps[n] = n_sel + 1;
+ if( n_sel<(int)d_selector_apps_data[n].size() ){
+ d_selector_apps_data[n][n_sel] = s;
+ }else{
+ d_selector_apps_data[n].push_back( s );
+ }
+
eqc->d_selectors = true;
}
if( assertFacts && !eqc->d_constructor.get().isNull() ){
@@ -1165,19 +1196,19 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
Trace("datatypes-debug") << "Add constructor : " << c << " to eqc(" << n << ")" << std::endl;
Assert( eqc->d_constructor.get().isNull() );
//check labels
- NodeListMap::iterator lbl_i = d_labels.find( n );
+ NodeIntMap::iterator lbl_i = d_labels.find( n );
if( lbl_i != d_labels.end() ){
size_t constructorIndex = Datatype::indexOf(c.getOperator().toExpr());
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- if( (*i).getKind()==NOT ){
- int tindex = DatatypesRewriter::isTester( (*i)[0] );
+ int n_lbl = (*lbl_i).second;
+ for( int i=0; i<n_lbl; i++ ){
+ Node t = d_labels_data[n][i];
+ if( t.getKind()==NOT ){
+ int tindex = DatatypesRewriter::isTester( t[0] );
Assert( tindex!=-1 );
if( tindex==(int)constructorIndex ){
- Node n = *i;
std::vector< TNode > assumptions;
- explain( *i, assumptions );
- explainEquality( c, (*i)[0][0], true, assumptions );
+ explain( t, assumptions );
+ explainEquality( c, t[0][0], true, assumptions );
d_conflictNode = mkAnd( assumptions );
Trace("dt-conflict") << "CONFLICT: Tester merge eq conflict : " << d_conflictNode << std::endl;
d_out->conflict( d_conflictNode );
@@ -1188,12 +1219,13 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
}
}
//check selectors
- NodeListMap::iterator sel_i = d_selector_apps.find( n );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( n );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
+ int n_sel = (*sel_i).second;
+ for( int j=0; j<n_sel; j++ ){
+ Node s = d_selector_apps_data[n][j];
//collapse the selector
- collapseSelector( *j, c );
+ collapseSelector( s, c );
}
}
eqc->d_constructor.set( c );
@@ -1277,61 +1309,114 @@ EqualityStatus TheoryDatatypes::getEqualityStatus(TNode a, TNode b){
return EQUALITY_FALSE_IN_MODEL;
}
-void TheoryDatatypes::computeCareGraph(){
- Trace("dt-cg") << "Compute graph for dt..." << std::endl;
- vector< pair<TNode, TNode> > currentPairs;
- for( unsigned r=0; r<2; r++ ){
- unsigned functionTerms = r==0 ? d_consTerms.size() : d_selTerms.size();
- for( unsigned i=0; i<functionTerms; i++ ){
- TNode f1 = r==0 ? d_consTerms[i] : d_selTerms[i];
- Assert(d_equalityEngine.hasTerm(f1));
- for( unsigned j=i+1; j<functionTerms; j++ ){
- TNode f2 = r==0 ? d_consTerms[j] : d_selTerms[j];
- Trace("dt-cg-debug") << "dt-cg(" << r << "): " << f1 << " and " << f2 << " " << (f1.getOperator()==f2.getOperator()) << " " << areEqual( f1, f2 ) << std::endl;
- Assert(d_equalityEngine.hasTerm(f2));
- if( f1.getOperator()==f2.getOperator() &&
- ( ( f1.getKind()!=DT_SIZE && f1.getKind()!=DT_HEIGHT_BOUND ) || f1[0].getType()==f2[0].getType() ) &&
- !areEqual( f1, f2 ) ){
- Trace("dt-cg") << "Check " << f1 << " and " << f2 << std::endl;
- bool somePairIsDisequal = false;
- currentPairs.clear();
- for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
- TNode x = f1[k];
- TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- //need to consider types for parametric selectors
- if( x.getType()!=y.getType() || areDisequal(x, y) ){
- somePairIsDisequal = true;
- break;
- }else if( !d_equalityEngine.areEqual( x, y ) ){
- Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
- if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
- Trace("dt-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
- EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
- Trace("dt-cg") << "...eq status is " << eqStatus << std::endl;
- if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
- somePairIsDisequal = true;
- break;
- }else{
- currentPairs.push_back(make_pair(x_shared, y_shared));
- }
+
+
+void TheoryDatatypes::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs ){
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !areEqual( f1, f2 ) ){
+ Trace("dt-cg") << "Check " << f1 << " and " << f2 << std::endl;
+ vector< pair<TNode, TNode> > currentPairs;
+ for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+ TNode x = f1[k];
+ TNode y = f2[k];
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !areDisequal( x, y ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
+ Trace("dt-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ Trace("dt-cg") << "...eq status is " << eqStatus << std::endl;
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
}
}
}
- if (!somePairIsDisequal) {
- for (unsigned c = 0; c < currentPairs.size(); ++ c) {
- Trace("dt-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
- addCarePair(currentPairs[c].first, currentPairs[c].second);
- }
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Trace("dt-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
+ addCarePair(currentPairs[c].first, currentPairs[c].second);
+ n_pairs++;
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1, n_pairs );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
+ }
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
}
}
}
}
}
- Trace("dt-cg") << "Done Compute graph for dt." << std::endl;
+}
+
+void TheoryDatatypes::computeCareGraph(){
+ unsigned n_pairs = 0;
+ Trace("dt-cg-summary") << "Compute graph for dt..." << d_functionTerms.size() << " " << d_sharedTerms.size() << std::endl;
+ Trace("dt-cg") << "Build indices..." << std::endl;
+ std::map< TypeNode, std::map< Node, quantifiers::TermArgTrie > > index;
+ std::map< Node, unsigned > arity;
+ //populate indices
+ unsigned functionTerms = d_functionTerms.size();
+ for( unsigned i=0; i<functionTerms; i++ ){
+ TNode f1 = d_functionTerms[i];
+ Assert(d_equalityEngine.hasTerm(f1));
+ Trace("dt-cg-debug") << "...build for " << f1 << std::endl;
+ //break into index based on operator, and type of first argument (since some operators are parametric)
+ Node op = f1.getOperator();
+ TypeNode tn = f1[0].getType();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_DATATYPES ) ){
+ has_trigger_arg = true;
+ }
+ }
+ //only may contribute to care pairs if has at least one trigger argument
+ if( has_trigger_arg ){
+ index[tn][op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< TypeNode, std::map< Node, quantifiers::TermArgTrie > >::iterator iti = index.begin(); iti != index.end(); ++iti ){
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = iti->second.begin(); itii != iti->second.end(); ++itii ){
+ Trace("dt-cg") << "Process index " << itii->first << ", " << iti->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0, n_pairs );
+ }
+ }
+ Trace("dt-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
}
void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
@@ -1443,7 +1528,7 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
if( neqc.isNull() ){
for( unsigned i=0; i<pcons.size(); i++ ){
//must try the infinite ones first
- bool cfinite = options::finiteModelFind() ? dt[ i ].isUFinite() : dt[ i ].isFinite();
+ bool cfinite = dt[ i ].isInterpretedFinite();
if( pcons[i] && (r==1)==cfinite ){
neqc = DatatypesRewriter::getInstCons( eqc, dt, i );
//for( unsigned j=0; j<neqc.getNumChildren(); j++ ){
@@ -1543,16 +1628,18 @@ Node TheoryDatatypes::getSingletonLemma( TypeNode tn, bool pol ) {
void TheoryDatatypes::collectTerms( Node n ) {
if( d_collectTermsCache.find( n )==d_collectTermsCache.end() ){
d_collectTermsCache[n] = true;
- for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- collectTerms( n[i] );
- }
+ //for( int i=0; i<(int)n.getNumChildren(); i++ ) {
+ // collectTerms( n[i] );
+ //}
if( n.getKind() == APPLY_CONSTRUCTOR ){
Debug("datatypes") << " Found constructor " << n << endl;
- d_consTerms.push_back( n );
+ if( n.getNumChildren()>0 ){
+ d_functionTerms.push_back( n );
+ }
}else{
if( n.getKind() == APPLY_SELECTOR_TOTAL || n.getKind() == DT_SIZE || n.getKind() == DT_HEIGHT_BOUND ){
- d_selTerms.push_back( n );
+ d_functionTerms.push_back( n );
//we must also record which selectors exist
Trace("dt-collapse-sel") << " Found selector " << n << endl;
Node rep = getRepresentative( n[0] );
@@ -2040,21 +2127,19 @@ void TheoryDatatypes::printModelDebug( const char* c ){
if( hasLabel( ei, eqc ) ){
Trace( c ) << getLabel( eqc );
}else{
- NodeListMap::iterator lbl_i = d_labels.find( eqc );
+ NodeIntMap::iterator lbl_i = d_labels.find( eqc );
if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ){
- Trace( c ) << *j << " ";
+ for( int j=0; j<(*lbl_i).second; j++ ){
+ Trace( c ) << d_labels_data[eqc][j] << " ";
}
}
}
Trace( c ) << std::endl;
Trace( c ) << " Selectors : " << ( ei->d_selectors ? "yes, " : "no " );
- NodeListMap::iterator sel_i = d_selector_apps.find( eqc );
+ NodeIntMap::iterator sel_i = d_selector_apps.find( eqc );
if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); j++ ){
- Trace( c ) << *j << " ";
+ for( int j=0; j<(*sel_i).second; j++ ){
+ Trace( c ) << d_selector_apps_data[eqc][j] << " ";
}
}
Trace( c ) << std::endl;
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 4bf04e08c..5722e7822 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -32,12 +32,17 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace datatypes {
class TheoryDatatypes : public Theory {
private:
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+ typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
@@ -157,9 +162,11 @@ private:
* NOT is_[constructor_1]( t )...NOT is_[constructor_n]( t ) followed by
* is_[constructor_(n+1)]( t ), each of which is a unique tester.
*/
- NodeListMap d_labels;
+ NodeIntMap d_labels;
+ std::map< Node, std::vector< Node > > d_labels_data;
/** selector apps for eqch equivalence class */
- NodeListMap d_selector_apps;
+ NodeIntMap d_selector_apps;
+ std::map< Node, std::vector< Node > > d_selector_apps_data;
/** constructor terms */
//BoolMap d_consEqc;
/** Are we in conflict */
@@ -176,10 +183,8 @@ private:
std::vector< Node > d_pending;
std::map< Node, Node > d_pending_exp;
std::vector< Node > d_pending_merge;
- /** All the constructor terms that the theory has seen */
- context::CDList<TNode> d_consTerms;
- /** All the selector terms that the theory has seen */
- context::CDList<TNode> d_selTerms;
+ /** All the function terms that the theory has seen */
+ context::CDList<TNode> d_functionTerms;
/** counter for forcing assignments (ensures fairness) */
unsigned d_dtfCounter;
/** expand definition skolem functions */
@@ -216,6 +221,7 @@ private:
TNode getEqcConstructor( TNode r );
protected:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs );
/** compute care graph */
void computeCareGraph();
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index 5a3645691..9c8387958 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -299,11 +299,10 @@ public:
throw TypeCheckingExceptionPrivate(n, "datatype height bound must be non-negative");
}
}
- return nodeManager->integerType();
+ return nodeManager->booleanType();
}
};/* class DtHeightBoundTypeRule */
-
}/* CVC4::theory::datatypes namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/datatypes/type_enumerator.cpp b/src/theory/datatypes/type_enumerator.cpp
index 6c1155237..c0539743f 100644
--- a/src/theory/datatypes/type_enumerator.cpp
+++ b/src/theory/datatypes/type_enumerator.cpp
@@ -172,7 +172,7 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
Debug("dt-enum") << "datatype is " << d_type << std::endl;
Debug("dt-enum") << "properties : " << d_datatype.isCodatatype() << " " << d_datatype.isRecursiveSingleton();
Debug("dt-enum") << " " << d_datatype.isFinite() << std::endl;
- Debug("dt-enum") << " " << d_datatype.isUFinite() << std::endl;
+ Debug("dt-enum") << " " << d_datatype.isInterpretedFinite() << std::endl;
if( d_datatype.isCodatatype() && hasCyclesDt( d_datatype ) ){
//start with uninterpreted constant
diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h
index bbfd951b3..8473b5d69 100644
--- a/src/theory/datatypes/type_enumerator.h
+++ b/src/theory/datatypes/type_enumerator.h
@@ -159,7 +159,7 @@ public:
}
if( d_ctor>=d_has_debruijn+d_datatype.getNumConstructors() ){
//try next size limit as long as new terms were generated at last size, or other cases
- if( prevSize==d_size_limit || ( d_size_limit==0 && d_datatype.isCodatatype() ) || ( options::finiteModelFind() ? !d_datatype.isUFinite() : !d_datatype.isFinite() ) ){
+ if( prevSize==d_size_limit || ( d_size_limit==0 && d_datatype.isCodatatype() ) || !d_datatype.isInterpretedFinite() ){
d_size_limit++;
d_ctor = d_zeroCtor;
for( unsigned i=0; i<d_sel_sum.size(); i++ ){
diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp
index 04cac7ae5..6ac1c5e32 100644
--- a/src/theory/logic_info.cpp
+++ b/src/theory/logic_info.cpp
@@ -270,7 +270,7 @@ std::string LogicInfo::getLogicString() const {
if(d_theories[THEORY_FP]) {
ss << "FP";
++seen;
- }
+ }
if(d_theories[THEORY_DATATYPES]) {
ss << "DT";
++seen;
@@ -296,7 +296,10 @@ std::string LogicInfo::getLogicString() const {
ss << "FS";
++seen;
}
-
+ if(d_theories[THEORY_SEP]) {
+ ss << "SEP";
+ ++seen;
+ }
if(seen != d_sharingTheories) {
Unhandled("can't extract a logic string from LogicInfo; at least one "
"active theory is unknown to LogicInfo::getLogicString() !");
@@ -439,6 +442,10 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_SETS);
p += 2;
}
+ if(!strncmp(p, "SEP", 3)) {
+ enableTheory(THEORY_SEP);
+ p += 3;
+ }
}
}
if(*p != '\0') {
diff --git a/src/theory/quantifiers/alpha_equivalence.cpp b/src/theory/quantifiers/alpha_equivalence.cpp
index 80066d690..a00d6d8a1 100644..100755
--- a/src/theory/quantifiers/alpha_equivalence.cpp
+++ b/src/theory/quantifiers/alpha_equivalence.cpp
@@ -30,17 +30,30 @@ struct sortTypeOrder {
};
Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ) {
+ std::map< Node, bool > visited;
while( !tt.empty() ){
if( tt.size()==arg_index.size()+1 ){
Node t = tt.back();
- Node op = t.hasOperator() ? t.getOperator() : t;
- arg_index.push_back( 0 );
+ Node op;
+ if( t.hasOperator() ){
+ if( visited.find( t )==visited.end() ){
+ visited[t] = true;
+ op = t.getOperator();
+ arg_index.push_back( 0 );
+ }else{
+ op = t;
+ arg_index.push_back( -1 );
+ }
+ }else{
+ op = t;
+ arg_index.push_back( 0 );
+ }
Trace("aeq-debug") << op << " ";
aen = &(aen->d_children[op][t.getNumChildren()]);
}else{
Node t = tt.back();
int i = arg_index.back();
- if( i==(int)t.getNumChildren() ){
+ if( i==-1 || i==(int)t.getNumChildren() ){
tt.pop_back();
arg_index.pop_back();
}else{
@@ -56,9 +69,9 @@ Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersE
}else{
if( q.getNumChildren()==2 ){
//lemma ( q <=> d_quant )
- Trace("quant-ae") << "Alpha equivalent : " << std::endl;
- Trace("quant-ae") << " " << q << std::endl;
- Trace("quant-ae") << " " << aen->d_quant << std::endl;
+ Trace("alpha-eq") << "Alpha equivalent : " << std::endl;
+ Trace("alpha-eq") << " " << q << std::endl;
+ Trace("alpha-eq") << " " << aen->d_quant << std::endl;
lem = q.iffNode( aen->d_quant );
}else{
//do not reduce annotated quantified formulas based on alpha equivalence
diff --git a/src/theory/quantifiers/alpha_equivalence.h b/src/theory/quantifiers/alpha_equivalence.h
index 8e7556eb6..8e7556eb6 100644..100755
--- a/src/theory/quantifiers/alpha_equivalence.h
+++ b/src/theory/quantifiers/alpha_equivalence.h
diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp
index 5192da7de..97116dee4 100644..100755
--- a/src/theory/quantifiers/ambqi_builder.cpp
+++ b/src/theory/quantifiers/ambqi_builder.cpp
@@ -787,7 +787,7 @@ void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
Node n = fm->d_uf_terms[f][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
fapps.push_back( n );
}
diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h
index 3669d38b7..3669d38b7 100644..100755
--- a/src/theory/quantifiers/ambqi_builder.h
+++ b/src/theory/quantifiers/ambqi_builder.h
diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp
index c8d18aced..c8d18aced 100644..100755
--- a/src/theory/quantifiers/anti_skolem.cpp
+++ b/src/theory/quantifiers/anti_skolem.cpp
diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h
index 721371159..721371159 100644..100755
--- a/src/theory/quantifiers/anti_skolem.h
+++ b/src/theory/quantifiers/anti_skolem.h
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index d32ef59a1..7184624da 100644..100755
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -28,7 +28,7 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
-BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
+BoundedIntegers::IntRangeModel::IntRangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) {
if( options::fmfBoundIntLazy() ){
d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
@@ -40,7 +40,7 @@ BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::C
}
}
-void BoundedIntegers::RangeModel::initialize() {
+void BoundedIntegers::IntRangeModel::initialize() {
//add initial split lemma
Node ltr = NodeManager::currentNM()->mkNode( LT, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
ltr = Rewriter::rewrite( ltr );
@@ -55,7 +55,7 @@ void BoundedIntegers::RangeModel::initialize() {
d_bi->addLiteralFromRange(ltr_lit, d_range);
}
-void BoundedIntegers::RangeModel::assertNode(Node n) {
+void BoundedIntegers::IntRangeModel::assertNode(Node n) {
bool pol = n.getKind()!=NOT;
Node nlit = n.getKind()==NOT ? n[0] : n;
if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){
@@ -93,7 +93,7 @@ void BoundedIntegers::RangeModel::assertNode(Node n) {
}
}
-void BoundedIntegers::RangeModel::allocateRange() {
+void BoundedIntegers::IntRangeModel::allocateRange() {
d_curr_max++;
int newBound = d_curr_max;
Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
@@ -110,7 +110,7 @@ void BoundedIntegers::RangeModel::allocateRange() {
d_bi->addLiteralFromRange(ltr_lit, d_range);
}
-Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
+Node BoundedIntegers::IntRangeModel::getNextDecisionRequest() {
//request the current cardinality as a decision literal, if not already asserted
for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
int i = (*it).second;
@@ -129,7 +129,7 @@ Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
return Node::null();
}
-bool BoundedIntegers::RangeModel::proxyCurrentRange() {
+bool BoundedIntegers::IntRangeModel::proxyCurrentRange() {
//Trace("model-engine") << "Range(" << d_range << ") currently is " << d_curr_max.get() << std::endl;
if( d_range!=d_proxy_range ){
//int curr = d_curr_range.get();
@@ -148,11 +148,24 @@ bool BoundedIntegers::RangeModel::proxyCurrentRange() {
}
+
+
+
BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
QuantifiersModule(qe), d_assertions(c){
}
+BoundedIntegers::~BoundedIntegers() {
+ for( std::map< Node, RangeModel * >::iterator it = d_rms.begin(); it != d_rms.end(); ++it ){
+ delete it->second;
+ }
+}
+
+void BoundedIntegers::presolve() {
+ d_bnd_it.clear();
+}
+
bool BoundedIntegers::isBound( Node f, Node v ) {
return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
}
@@ -172,62 +185,79 @@ bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
return false;
}
-void BoundedIntegers::processLiteral( Node f, Node lit, bool pol,
+void BoundedIntegers::processLiteral( Node q, Node lit, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map ) {
- if( lit.getKind()==GEQ && lit[0].getType().isInteger() ){
- std::map< Node, Node > msum;
- if (QuantArith::getMonomialSumLit( lit, msum )){
- Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl;
- QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" );
- for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
- if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( f, it->first ) ){
- Node veq;
- if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){
- Node n1 = veq[0];
- Node n2 = veq[1];
- if(pol){
- //flip
- n1 = veq[1];
- n2 = veq[0];
- if( n1.getKind()==BOUND_VARIABLE ){
- n2 = QuantArith::offset( n2, 1 );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term ) {
+ if( lit.getKind()==GEQ ){
+ if( lit[0].getType().isInteger() ){
+ std::map< Node, Node > msum;
+ if( QuantArith::getMonomialSumLit( lit, msum ) ){
+ Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl;
+ QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" );
+ for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){
+ Node veq;
+ if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){
+ Node n1 = veq[0];
+ Node n2 = veq[1];
+ if(pol){
+ //flip
+ n1 = veq[1];
+ n2 = veq[0];
+ if( n1.getKind()==BOUND_VARIABLE ){
+ n2 = QuantArith::offset( n2, 1 );
+ }else{
+ n1 = QuantArith::offset( n1, -1 );
+ }
+ veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
+ }
+ Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
+ Node t = n1==it->first ? n2 : n1;
+ if( !hasNonBoundVar( q, t ) ) {
+ Trace("bound-int-debug") << "The bound is relevant." << std::endl;
+ int loru = n1==it->first ? 0 : 1;
+ bound_lit_type_map[it->first] = BOUND_INT_RANGE;
+ bound_int_range_term[loru][it->first] = t;
+ bound_lit_map[loru][it->first] = lit;
+ bound_lit_pol_map[loru][it->first] = pol;
}else{
- n1 = QuantArith::offset( n1, -1 );
+ Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
}
- veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
- }
- Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
- Node t = n1==it->first ? n2 : n1;
- if( !hasNonBoundVar( f, t ) ) {
- Trace("bound-int-debug") << "The bound is relevant." << std::endl;
- int loru = n1==it->first ? 0 : 1;
- d_bounds[loru][f][it->first] = t;
- bound_lit_map[loru][it->first] = lit;
- bound_lit_pol_map[loru][it->first] = pol;
- }else{
- Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
}
}
}
}
}
+ }else if( lit.getKind()==MEMBER ){
+ //TODO: enable this when sets models are fixed
+ /*
+ if( !pol && lit[0].getKind()==BOUND_VARIABLE && !isBound( q, lit[0] ) && !lit[1].hasBoundVar() ){
+ Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is membership." << std::endl;
+ bound_lit_type_map[lit[0]] = BOUND_SET_MEMBER;
+ bound_lit_map[0][lit[0]] = lit;
+ bound_lit_pol_map[0][lit[0]] = pol;
+ }
+ */
}else if( lit.getKind()==LEQ || lit.getKind()==LT || lit.getKind()==GT ) {
Message() << "BoundedIntegers : Bad kind for literal : " << lit << std::endl;
}
}
-void BoundedIntegers::process( Node f, Node n, bool pol,
+void BoundedIntegers::process( Node q, Node n, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term ){
if( (n.getKind()==OR && pol) || (n.getKind()==AND && !pol) ){
for( unsigned i=0; i<n.getNumChildren(); i++) {
- process( f, n[i], pol, bound_lit_map, bound_lit_pol_map );
+ process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}
}else if( n.getKind()==NOT ){
- process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map );
+ process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}else {
- processLiteral( f, n, pol, bound_lit_map, bound_lit_pol_map );
+ processLiteral( q, n, pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
}
}
@@ -258,58 +288,99 @@ void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
}
}
+void BoundedIntegers::setBoundedVar( Node q, Node v, unsigned bound_type ) {
+ d_bound_type[q][v] = bound_type;
+ d_set_nums[q][v] = d_set[q].size();
+ d_set[q].push_back( v );
+ Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v << std::endl;
+}
+
void BoundedIntegers::registerQuantifier( Node f ) {
Trace("bound-int") << "Register quantifier " << f << std::endl;
- bool hasIntType = false;
- int finiteTypes = 0;
- std::map< Node, int > numMap;
- for( unsigned i=0; i<f[0].getNumChildren(); i++) {
- numMap[f[0][i]] = i;
- if( f[0][i].getType().isInteger() ){
- hasIntType = true;
- }
- else if( f[0][i].getType().isSort() || f[0][i].getType().getCardinality().isFinite() ){
- finiteTypes++;
- }
- }
- if( hasIntType ){
- bool success;
- do{
- std::map< int, std::map< Node, Node > > bound_lit_map;
- std::map< int, std::map< Node, bool > > bound_lit_pol_map;
- success = false;
- process( f, f[1], true, bound_lit_map, bound_lit_pol_map );
- for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
- Node v = it->first;
- if( !isBound(f,v) ){
- if( d_bounds[1][f].find(v)!=d_bounds[1][f].end() ){
- d_set[f].push_back(v);
- d_set_nums[f].push_back(numMap[v]);
+
+ bool success;
+ do{
+ std::map< Node, unsigned > bound_lit_type_map;
+ std::map< int, std::map< Node, Node > > bound_lit_map;
+ std::map< int, std::map< Node, bool > > bound_lit_pol_map;
+ std::map< int, std::map< Node, Node > > bound_int_range_term;
+ success = false;
+ process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
+ //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
+ for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
+ Node v = it->first;
+ if( !isBound( f, v ) ){
+ bool setBoundVar = false;
+ if( it->second==BOUND_INT_RANGE ){
+ //must have both
+ if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){
+ setBoundedVar( f, v, BOUND_INT_RANGE );
+ setBoundVar = true;
success = true;
- //set Attributes on literals
for( unsigned b=0; b<2; b++ ){
- Assert( bound_lit_map[b].find( v )!=bound_lit_map[b].end() );
+ //set the bounds
+ Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() );
+ d_bounds[b][f][v] = bound_int_range_term[b][v];
+ }
+ Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
+ d_range[f][v] = Rewriter::rewrite( r );
+ Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
+ }
+ }else if( it->second==BOUND_SET_MEMBER ){
+ setBoundedVar( f, v, BOUND_SET_MEMBER );
+ setBoundVar = true;
+ d_setm_range[f][v] = bound_lit_map[0][v][1];
+ Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl;
+ }
+ if( setBoundVar ){
+ //set Attributes on literals
+ for( unsigned b=0; b<2; b++ ){
+ if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){
Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
BoundIntLitAttribute bila;
bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
+ }else{
+ Assert( it->second!=BOUND_INT_RANGE );
}
- Trace("bound-int") << "Variable " << v << " is bound because of literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
}
}
}
- }while( success );
- Trace("bound-int") << "Bounds are : " << std::endl;
- for( unsigned i=0; i<d_set[f].size(); i++) {
- Node v = d_set[f][i];
- Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
- d_range[f][v] = Rewriter::rewrite( r );
+ }
+ }while( success );
+
+ Trace("bound-int") << "Bounds are : " << std::endl;
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ if( d_bound_type[f][v]==BOUND_INT_RANGE ){
Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
+ }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl;
+ }
+ }
+
+ bool bound_success = true;
+ for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+ if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
+ TypeNode tn = f[0][i].getType();
+ if( !tn.isSort() && !getTermDatabase()->mayComplete( tn ) ){
+ Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
+ bound_success = false;
+ break;
+ }
}
- if( d_set[f].size()==(f[0].getNumChildren()-finiteTypes) ){
- d_bound_quants.push_back( f );
- for( unsigned i=0; i<d_set[f].size(); i++) {
- Node v = d_set[f][i];
- Node r = d_range[f][v];
+ }
+
+ if( bound_success ){
+ d_bound_quants.push_back( f );
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ if( d_bound_type[f][v]==BOUND_INT_RANGE || d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ Node r;
+ if( d_bound_type[f][v]==BOUND_INT_RANGE ){
+ r = d_range[f][v];
+ }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
+ r = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] );
+ }
bool isProxy = false;
if( r.hasBoundVar() ){
//introduce a new bound
@@ -319,18 +390,15 @@ void BoundedIntegers::registerQuantifier( Node f ) {
r = new_range;
isProxy = true;
}
- if( r.getKind()!=CONST_RATIONAL ){
+ if( !r.isConst() ){
if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
- Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << " " << r.getKind() << std::endl;
+ Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
d_ranges.push_back( r );
- d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
+ d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
d_rms[r]->initialize();
}
}
}
- }else{
- Trace("bound-int-warn") << "Warning : Bounded Integers : Could not find bounds for " << f << std::endl;
- //Message() << "Bound integers : Cannot infer bounds of " << f << std::endl;
}
}
}
@@ -376,39 +444,28 @@ Node BoundedIntegers::getNextDecisionRequest() {
return Node::null();
}
+unsigned BoundedIntegers::getBoundVarType( Node q, Node v ) {
+ std::map< Node, unsigned >::iterator it = d_bound_type[q].find( v );
+ if( it==d_bound_type[q].end() ){
+ return BOUND_NONE;
+ }else{
+ return it->second;
+ }
+}
+
void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
l = d_bounds[0][f][v];
u = d_bounds[1][f][v];
if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
- //must create substitution
+ //get the substitution
std::vector< Node > vars;
std::vector< Node > subs;
- Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
- for( unsigned i=0; i<d_set[f].size(); i++) {
- if( d_set[f][i]!=v ){
- Trace("bound-int-rsi") << "Look up the value for " << d_set[f][i] << " " << rsi->d_var_order[d_set_nums[f][i]] << std::endl;
- Trace("bound-int-rsi") << "term : " << rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]) << std::endl;
- vars.push_back(d_set[f][i]);
- subs.push_back(rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]));
- }else{
- break;
- }
- }
- Trace("bound-int-rsi") << "Do substitution..." << std::endl;
- //check if it has been instantiated
- if (!vars.empty() && !d_bnd_it[f][v].hasInstantiated(subs)){
- //must add the lemma
- Node nn = d_nground_range[f][v];
- nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[f][v] );
- Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
- d_quantEngine->getOutputChannel().lemma(lem, false, true);
- l = Node::null();
- u = Node::null();
- return;
- }else{
+ if( getRsiSubsitution( f, v, vars, subs, rsi ) ){
u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }else{
+ u = Node::null();
+ l = Node::null();
}
}
}
@@ -416,12 +473,86 @@ void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l,
void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
getBounds( f, v, rsi, l, u );
Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
- l = d_quantEngine->getModel()->getCurrentModelValue( l );
- u = d_quantEngine->getModel()->getCurrentModelValue( u );
+ if( !l.isNull() ){
+ l = d_quantEngine->getModel()->getCurrentModelValue( l );
+ }
+ if( !u.isNull() ){
+ u = d_quantEngine->getModel()->getCurrentModelValue( u );
+ }
Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
return;
}
-bool BoundedIntegers::isGroundRange(Node f, Node v) {
- return isBoundVar(f,v) && !getLowerBound(f,v).hasBoundVar() && !getUpperBound(f,v).hasBoundVar();
+bool BoundedIntegers::isGroundRange( Node q, Node v ) {
+ if( isBoundVar(q,v) ){
+ if( d_bound_type[q][v]==BOUND_INT_RANGE ){
+ return !getLowerBound(q,v).hasBoundVar() && !getUpperBound(q,v).hasBoundVar();
+ }else if( d_bound_type[q][v]==BOUND_SET_MEMBER ){
+ return !d_setm_range[q][v].hasBoundVar();
+ }
+ }
+ return false;
}
+
+Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) {
+ Node sr = d_setm_range[q][v];
+ if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){
+ //get the substitution
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
+ sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }else{
+ sr = Node::null();
+ }
+ }
+ return sr;
+}
+
+Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
+ Node sr = getSetRange( q, v, rsi );
+ if( !sr.isNull() ){
+ Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl;
+ sr = d_quantEngine->getModel()->getCurrentModelValue( sr );
+ Trace("bound-int-rsi") << "Value is " << sr << std::endl;
+ }
+ return sr;
+}
+
+bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) {
+
+ Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
+ Assert( d_set_nums[q].find( v )!=d_set_nums[q].end() );
+ int vindex = d_set_nums[q][v];
+ Assert( d_set_nums[q][v]==vindex );
+ Trace("bound-int-rsi-debug") << " index order is " << vindex << std::endl;
+ //must take substitution for all variables that are iterating at higher level
+ for( int i=0; i<vindex; i++) {
+ Assert( d_set_nums[q][d_set[q][i]]==i );
+ Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl;
+ int v = rsi->getVariableOrder( i );
+ Assert( q[0][v]==d_set[q][i] );
+ Node t = rsi->getCurrentTerm( v );
+ Trace("bound-int-rsi") << "term : " << t << std::endl;
+ vars.push_back( d_set[q][i] );
+ subs.push_back( t );
+ }
+
+ //check if it has been instantiated
+ if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){
+ if( d_bound_type[q][v]==BOUND_INT_RANGE ){
+ //must add the lemma
+ Node nn = d_nground_range[q][v];
+ nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] );
+ Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
+ d_quantEngine->getOutputChannel().lemma(lem, false, true);
+ }else{
+ //TODO : sets
+ }
+ return false;
+ }else{
+ return true;
+ }
+}
+
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
index 7d15097bd..ab4bcba96 100644..100755
--- a/src/theory/quantifiers/bounded_integers.h
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -39,31 +39,57 @@ class BoundedIntegers : public QuantifiersModule
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
typedef context::CDHashMap<int, bool> IntBoolMap;
+public:
+ enum {
+ BOUND_FINITE,
+ BOUND_INT_RANGE,
+ BOUND_SET_MEMBER,
+ BOUND_NONE
+ };
private:
//for determining bounds
bool isBound( Node f, Node v );
bool hasNonBoundVar( Node f, Node b );
- std::map< Node, std::map< Node, Node > > d_bounds[2];
+ //bound type
+ std::map< Node, std::map< Node, unsigned > > d_bound_type;
std::map< Node, std::vector< Node > > d_set;
- std::map< Node, std::vector< int > > d_set_nums;
+ std::map< Node, std::map< Node, int > > d_set_nums;
+ //integer lower/upper bounds
+ std::map< Node, std::map< Node, Node > > d_bounds[2];
std::map< Node, std::map< Node, Node > > d_range;
std::map< Node, std::map< Node, Node > > d_nground_range;
+ //set membership range
+ std::map< Node, std::map< Node, Node > > d_setm_range;
void hasFreeVar( Node f, Node n );
void process( Node f, Node n, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term );
void processLiteral( Node f, Node lit, bool pol,
+ std::map< Node, unsigned >& bound_lit_type_map,
std::map< int, std::map< Node, Node > >& bound_lit_map,
- std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+ std::map< int, std::map< Node, Node > >& bound_int_range_term );
std::vector< Node > d_bound_quants;
private:
class RangeModel {
+ public:
+ RangeModel(){}
+ virtual ~RangeModel(){}
+ virtual void initialize() = 0;
+ virtual void assertNode(Node n) = 0;
+ virtual Node getNextDecisionRequest() = 0;
+ virtual bool proxyCurrentRange() = 0;
+ };
+ class IntRangeModel : public RangeModel {
private:
BoundedIntegers * d_bi;
void allocateRange();
Node d_proxy_range;
public:
- RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
+ IntRangeModel( BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
+ virtual ~IntRangeModel(){}
Node d_range;
int d_curr_max;
std::map< int, Node > d_range_literal;
@@ -108,27 +134,36 @@ private:
std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
private:
void addLiteralFromRange( Node lit, Node r );
+
+ void setBoundedVar( Node f, Node v, unsigned bound_type );
public:
BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
- ~BoundedIntegers() throw() {}
-
+ virtual ~BoundedIntegers();
+
+ void presolve();
bool needsCheck( Theory::Effort e );
void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
Node getNextDecisionRequest();
- bool isBoundVar( Node f, Node v ) { return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end(); }
- unsigned getNumBoundVars( Node f ) { return d_set[f].size(); }
- Node getBoundVar( Node f, int i ) { return d_set[f][i]; }
- int getBoundVarNum( Node f, int i ) { return d_set_nums[f][i]; }
- Node getLowerBound( Node f, Node v ){ return d_bounds[0][f][v]; }
- Node getUpperBound( Node f, Node v ){ return d_bounds[1][f][v]; }
+ bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); }
+ unsigned getBoundVarType( Node q, Node v );
+ unsigned getNumBoundVars( Node q ) { return d_set[q].size(); }
+ Node getBoundVar( Node q, int i ) { return d_set[q][i]; }
+ //for integer range
+ Node getLowerBound( Node q, Node v ){ return d_bounds[0][q][v]; }
+ Node getUpperBound( Node q, Node v ){ return d_bounds[1][q][v]; }
void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
bool isGroundRange(Node f, Node v);
+ //for set range
+ Node getSetRange( Node q, Node v, RepSetIterator * rsi );
+ Node getSetRangeValue( Node q, Node v, RepSetIterator * rsi );
/** Identify this module */
std::string identify() const { return "BoundedIntegers"; }
+private:
+ bool getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi );
};
}
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 43f5ee2fd..a0d9bda0f 100644..100755
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -28,7 +28,7 @@ using namespace CVC4::theory;
using namespace CVC4::theory::inst;
bool CandidateGenerator::isLegalCandidate( Node n ){
- return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ) );
+ return d_qe->getTermDatabase()->isTermActive( n ) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) );
}
void CandidateGeneratorQueue::addCandidate( Node n ) {
@@ -59,7 +59,7 @@ Node CandidateGeneratorQueue::getNextCandidate(){
}
CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node pat ) :
- d_qe( qe ), d_term_iter( -1 ){
+CandidateGenerator( qe ), d_term_iter( -1 ){
d_op = qe->getTermDatabase()->getMatchOperator( pat );
Assert( !d_op.isNull() );
d_op_arity = pat.getNumChildren();
@@ -186,7 +186,7 @@ Node CandidateGeneratorQE::getNextCandidate(){
}
CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+ CandidateGenerator( qe ), d_match_pattern( mpat ){
Assert( mpat.getKind()==EQUAL );
for( unsigned i=0; i<2; i++ ){
if( !quantifiers::TermDb::hasInstConstAttr(mpat[i]) ){
@@ -225,7 +225,7 @@ Node CandidateGeneratorQELitEq::getNextCandidate(){
CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+CandidateGenerator( qe ), d_match_pattern( mpat ){
Assert( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF );
d_match_pattern_type = d_match_pattern[0].getType();
@@ -259,7 +259,7 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
- d_match_pattern( mpat ), d_qe( qe ){
+ CandidateGenerator( qe ), d_match_pattern( mpat ){
d_match_pattern_type = mpat.getType();
Assert( mpat.getKind()==INST_CONSTANT );
d_f = quantifiers::TermDb::getInstConstAttr( mpat );
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 18ef6a086..4fc6969fc 100644..100755
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -33,8 +33,10 @@ namespace inst {
/** base class for generating candidates for matching */
class CandidateGenerator {
+protected:
+ QuantifiersEngine* d_qe;
public:
- CandidateGenerator(){}
+ CandidateGenerator( QuantifiersEngine* qe ) : d_qe( qe ){}
virtual ~CandidateGenerator(){}
/** Get candidates functions. These set up a context to get all match candidates.
@@ -54,7 +56,7 @@ public:
virtual void resetInstantiationRound() = 0;
public:
/** legal candidate */
- static bool isLegalCandidate( Node n );
+ bool isLegalCandidate( Node n );
};/* class CandidateGenerator */
/** candidate generator queue (for manual candidate generation) */
@@ -63,7 +65,7 @@ private:
std::vector< Node > d_candidates;
int d_candidate_index;
public:
- CandidateGeneratorQueue() : d_candidate_index( 0 ){}
+ CandidateGeneratorQueue( QuantifiersEngine* qe ) : CandidateGenerator( qe ), d_candidate_index( 0 ){}
~CandidateGeneratorQueue() throw() {}
void addCandidate( Node n );
@@ -80,8 +82,6 @@ class CandidateGeneratorQE : public CandidateGenerator
private:
//operator you are looking for
Node d_op;
- //instantiator pointer
- QuantifiersEngine* d_qe;
//the equality class iterator
unsigned d_op_arity;
std::vector< quantifiers::TermArgTrie* > d_tindex;
@@ -122,8 +122,6 @@ private:
Node d_match_pattern;
Node d_match_gterm;
bool d_do_mgt;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
public:
CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQELitEq() throw() {}
@@ -142,8 +140,6 @@ private:
Node d_match_pattern;
//type of disequality
TypeNode d_match_pattern_type;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
public:
CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQELitDeq() throw() {}
@@ -161,8 +157,6 @@ private:
//equality you are trying to match equalities for
Node d_match_pattern;
TypeNode d_match_pattern_type;
- //einstantiator pointer
- QuantifiersEngine* d_qe;
// quantifier/index for the variable we are matching
Node d_f;
unsigned d_index;
diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp
index d9059a3e6..71bf7c426 100644..100755
--- a/src/theory/quantifiers/ce_guided_instantiation.cpp
+++ b/src/theory/quantifiers/ce_guided_instantiation.cpp
@@ -21,6 +21,8 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/theory_engine.h"
+#include "prop/prop_engine.h"
+#include "theory/bv/theory_bv_rewriter.h"
using namespace CVC4::kind;
using namespace std;
@@ -46,7 +48,7 @@ void CegConjecture::assign( Node q ) {
Assert( q.getKind()==FORALL );
d_assert_quant = q;
//register with single invocation if applicable
- if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInv() ){
+ if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
d_ceg_si->initialize( q );
if( q!=d_ceg_si->d_quant ){
//Node red_lem = NodeManager::currentNM()->mkNode( OR, q.negate(), d_cegqi_si->d_quant );
@@ -55,12 +57,15 @@ void CegConjecture::assign( Node q ) {
}
}
d_quant = q;
+ Assert( d_candidates.empty() );
+ std::vector< Node > vars;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ vars.push_back( q[0][i] );
d_candidates.push_back( NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() ) );
}
Trace("cegqi") << "Base quantified formula is : " << q << std::endl;
//construct base instantiation
- d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, d_candidates ) );
+ d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, vars, d_candidates ) );
Trace("cegqi") << "Base instantiation is : " << d_base_inst << std::endl;
if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) ){
CegInstantiation::collectDisjuncts( d_base_inst, d_base_disj );
@@ -130,14 +135,18 @@ Node CegConjecture::getLiteral( QuantifiersEngine * qe, int i ) {
qe->getOutputChannel().lemma( lem );
qe->getOutputChannel().requirePhase( lit, true );
- if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){
//implies height bounds on each candidate variable
std::vector< Node > lem_c;
for( unsigned j=0; j<d_candidates.size(); j++ ){
- lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) );
+ if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) );
+ }else{
+ //lem_c.push_back( NodeManager::currentNM()->mkNode( DT_SIZE_BOUND, d_candidates[j], c ) );
+ }
}
Node hlem = NodeManager::currentNM()->mkNode( OR, lit.negate(), lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c ) );
- Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (dt-height-pred) : " << hlem << std::endl;
+ Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (pred) : " << hlem << std::endl;
qe->getOutputChannel().lemma( hlem );
}
return lit;
@@ -257,8 +266,45 @@ void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) {
}
}
+void CegInstantiation::preRegisterQuantifier( Node q ) {
+ if( options::sygusDirectEval() ){
+ if( q.getNumChildren()==3 && q[2].getKind()==INST_PATTERN_LIST && q[2][0].getKind()==INST_PATTERN ){
+ //check whether it is an evaluation axiom
+ Node pat = q[2][0][0];
+ if( pat.getKind()==APPLY_UF ){
+ TypeNode tn = pat[0].getType();
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ //do unfolding if it induces Boolean structure,
+ //do direct evaluation if it does not induce Boolean structure,
+ // the reasoning is unfolding over these terms does not lead to helpful conflict analysis, and introduces many shared terms
+ bool directEval = true;
+ TypeNode ptn = pat.getType();
+ if( ptn.isBoolean() || ptn.isBitVector() ){
+ directEval = false;
+ }else{
+ unsigned cindex = Datatype::indexOf(pat[0].getOperator().toExpr() );
+ Node base = d_quantEngine->getTermDatabaseSygus()->getGenericBase( tn, dt, cindex );
+ Trace("cegqi-debug") << "Generic base term for " << pat[0] << " is " << base << std::endl;
+ if( base.getKind()==ITE ){
+ directEval = false;
+ }
+ }
+ if( directEval ){
+ //take ownership of this quantified formula (will use direct evaluation instead of unfolding instantiation)
+ d_quantEngine->setOwner( q, this );
+ d_eval_axioms[q] = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
void CegInstantiation::registerQuantifier( Node q ) {
- if( d_quantEngine->getOwner( q )==this ){
+ if( d_quantEngine->getOwner( q )==this && d_eval_axioms.find( q )==d_eval_axioms.end() ){
if( !d_conj->isAssigned() ){
Trace("cegqi") << "Register conjecture : " << q << std::endl;
d_conj->assign( q );
@@ -278,7 +324,7 @@ void CegInstantiation::registerQuantifier( Node q ) {
if( it!=d_uf_measure.end() ){
mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, d_conj->d_candidates[j] ) );
}
- }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){
//measure term is a fresh constant
mc.push_back( NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() ) );
}
@@ -291,6 +337,8 @@ void CegInstantiation::registerQuantifier( Node q ) {
}else{
Assert( d_conj->d_quant==q );
}
+ }else{
+ Trace("cegqi-debug") << "Register quantifier : " << q << std::endl;
}
}
@@ -317,7 +365,7 @@ Node CegInstantiation::getNextDecisionRequest() {
Trace("cegqi-debug") << "CEGQI : Decide next on : " << req_dec[i] << "..." << std::endl;
return req_dec[i];
}else{
- Trace("cegqi-debug") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
+ Trace("cegqi-debug2") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
}
}
@@ -350,6 +398,11 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
Trace("cegqi-engine-debug") << conj->d_candidates[i] << " ";
}
Trace("cegqi-engine-debug") << std::endl;
+ Trace("cegqi-engine-debug") << " * Candidate ce skolems : ";
+ for( unsigned i=0; i<conj->d_ce_sk.size(); i++ ){
+ Trace("cegqi-engine-debug") << conj->d_ce_sk[i] << " ";
+ }
+ Trace("cegqi-engine-debug") << std::endl;
if( conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){
Trace("cegqi-engine") << " * Current term size : " << conj->d_curr_lit.get() << std::endl;
}
@@ -374,6 +427,24 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
}
std::vector< Node > model_values;
if( getModelValues( conj, conj->d_candidates, model_values ) ){
+ if( options::sygusDirectEval() ){
+ std::vector< Node > eager_eval_lem;
+ for( unsigned j=0; j<conj->d_candidates.size(); j++ ){
+ d_quantEngine->getTermDatabaseSygus()->registerModelValue( conj->d_candidates[j], model_values[j], eager_eval_lem );
+ }
+ if( !eager_eval_lem.empty() ){
+ for( unsigned j=0; j<eager_eval_lem.size(); j++ ){
+ Node lem = eager_eval_lem[j];
+ if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){
+ //FIXME: hack to incorporate hacks from BV for division by zero
+ lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem );
+ }
+ Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
+ d_quantEngine->addLemma( lem );
+ }
+ return;
+ }
+ }
//check if we must apply fairness lemmas
if( conj->getCegqiFairMode()==CEGQI_FAIR_UF_DT_SIZE ){
std::vector< Node > lems;
@@ -390,6 +461,7 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
}
}
//must get a counterexample to the value of the current candidate
+ Assert( conj->d_candidates.size()==model_values.size() );
Node inst = conj->d_base_inst.substitute( conj->d_candidates.begin(), conj->d_candidates.end(), model_values.begin(), model_values.end() );
//check whether we will run CEGIS on inner skolem variables
bool sk_refine = ( !conj->isGround() || conj->d_refine_count==0 );
@@ -422,10 +494,30 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
Node lem = NodeManager::currentNM()->mkNode( OR, ic );
lem = Rewriter::rewrite( lem );
d_last_inst_si = false;
+ //eagerly unfold applications of evaluation function
+ if( options::sygusDirectEval() ){
+ Trace("cegqi-eager") << "pre-unfold counterexample : " << lem << std::endl;
+ std::map< Node, Node > visited_n;
+ lem = getEagerUnfold( lem, visited_n );
+ }
+
Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl;
- d_quantEngine->addLemma( lem );
- ++(d_statistics.d_cegqi_lemmas_ce);
- Trace("cegqi-engine") << " ...find counterexample." << std::endl;
+ if( d_quantEngine->addLemma( lem ) ){
+ ++(d_statistics.d_cegqi_lemmas_ce);
+ Trace("cegqi-engine") << " ...find counterexample." << std::endl;
+ }else{
+ //this may happen if we eagerly unfold, simplify to true
+ if( !options::sygusDirectEval() ){
+ Trace("cegqi-engine") << " ...FAILED to add candidate!" << std::endl;
+ }else{
+ Trace("cegqi-engine-debug") << " ...FAILED to add candidate!" << std::endl;
+ }
+ if( conj->d_refine_count==0 ){
+ //immediately go to refine candidate
+ checkCegConjecture( conj );
+ return;
+ }
+ }
}
}else{
@@ -589,6 +681,74 @@ void CegInstantiation::getMeasureLemmas( Node n, Node v, std::vector< Node >& le
}
}
+Node CegInstantiation::getEagerUnfold( Node n, std::map< Node, Node >& visited ) {
+ std::map< Node, Node >::iterator itv = visited.find( n );
+ if( itv==visited.end() ){
+ Trace("cegqi-eager-debug") << "getEagerUnfold " << n << std::endl;
+ Node ret;
+ if( n.getKind()==APPLY_UF ){
+ TypeNode tn = n[0].getType();
+ Trace("cegqi-eager-debug") << "check " << n[0].getType() << std::endl;
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ Trace("cegqi-eager") << "Unfold eager : " << n << std::endl;
+ Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( n[0], tn );
+ Trace("cegqi-eager") << "Built-in term : " << bTerm << std::endl;
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ Assert( var_list.getNumChildren()+1==n.getNumChildren() );
+ for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+ vars.push_back( var_list[j] );
+ }
+ for( unsigned j=1; j<n.getNumChildren(); j++ ){
+ Node nc = getEagerUnfold( n[j], visited );
+ if( var_list[j-1].getType().isBoolean() ){
+ //TODO: remove this case when boolean term conversion is eliminated
+ Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u));
+ subs.push_back( nc.eqNode( c ) );
+ }else{
+ subs.push_back( nc );
+ }
+ Assert( subs[j-1].getType()==var_list[j-1].getType() );
+ }
+ Assert( vars.size()==subs.size() );
+ bTerm = bTerm.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ Trace("cegqi-eager") << "Built-in term after subs : " << bTerm << std::endl;
+ Trace("cegqi-eager-debug") << "Types : " << bTerm.getType() << " " << n.getType() << std::endl;
+ Assert( n.getType()==bTerm.getType() );
+ ret = bTerm;
+ }
+ }
+ }
+ if( ret.isNull() ){
+ if( n.getKind()!=FORALL ){
+ bool childChanged = false;
+ std::vector< Node > children;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node nc = getEagerUnfold( n[i], visited );
+ childChanged = childChanged || n[i]!=nc;
+ children.push_back( nc );
+ }
+ if( childChanged ){
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.insert( children.begin(), n.getOperator() );
+ }
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ }
+ if( ret.isNull() ){
+ ret = n;
+ }
+ }
+ visited[n] = ret;
+ return ret;
+ }else{
+ return itv->second;
+ }
+}
+
void CegInstantiation::printSynthSolution( std::ostream& out ) {
if( d_conj->isAssigned() ){
Trace("cegqi-debug") << "Printing synth solution..." << std::endl;
diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h
index 57dc31850..c8b41c035 100644..100755
--- a/src/theory/quantifiers/ce_guided_instantiation.h
+++ b/src/theory/quantifiers/ce_guided_instantiation.h
@@ -126,6 +126,8 @@ private:
CegConjecture * d_conj;
/** last instantiation by single invocation module? */
bool d_last_inst_si;
+ /** evaluation axioms */
+ std::map< Node, bool > d_eval_axioms;
private: //for enforcing fairness
/** measure functions */
std::map< TypeNode, Node > d_uf_measure;
@@ -139,6 +141,8 @@ private: //for enforcing fairness
std::map< Node, std::map< int, Node > > d_size_term_lemma;
/** get measure lemmas */
void getMeasureLemmas( Node n, Node v, std::vector< Node >& lems );
+ /** get eager unfolding */
+ Node getEagerUnfold( Node n, std::map< Node, Node >& visited );
private:
/** check conjecture */
void checkCegConjecture( CegConjecture * conj );
@@ -156,6 +160,7 @@ public:
/* Call during quantifier engine's check */
void check( Theory::Effort e, unsigned quant_e );
/* Called for new quantifiers */
+ void preRegisterQuantifier( Node q );
void registerQuantifier( Node q );
void assertNode( Node n );
Node getNextDecisionRequest();
diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp
index 33856d226..3177739ac 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv.cpp
@@ -111,6 +111,7 @@ void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems
void CegConjectureSingleInv::initialize( Node q ) {
Assert( d_quant.isNull() );
+ Assert( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE );
//initialize data
d_quant = q;
//process
@@ -121,6 +122,7 @@ void CegConjectureSingleInv::initialize( Node q ) {
std::map< Node, std::map< Node, std::vector< Node > > > prog_invoke;
std::vector< Node > progs;
std::map< Node, std::map< Node, bool > > contains;
+ bool is_syntax_restricted = false;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
progs.push_back( q[0][i] );
//check whether all types have ITE
@@ -131,161 +133,173 @@ void CegConjectureSingleInv::initialize( Node q ) {
d_has_ites = false;
}
}
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( dt.isSygus() );
+ if( !dt.getSygusAllowAll() ){
+ is_syntax_restricted = true;
+ }
}
- Node qq = q[1];
- if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
- qq = q[1][0][1];
- }else{
- qq = TermDb::simpleNegate( qq );
- }
- //remove the deep embedding
- std::map< Node, Node > visited;
- std::vector< TypeNode > types;
- std::vector< Node > order_vars;
- std::map< Node, Node > single_inv_app_map;
- int type_valid = 0;
- qq = removeDeepEmbedding( qq, progs, types, type_valid, visited );
- Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl;
+ //abort if not aggressive
bool singleInvocation = true;
- if( type_valid==0 ){
- //process the single invocation-ness of the property
- d_sip->init( types, qq );
- Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
- d_sip->debugPrint( "cegqi-si" );
- //map from program to bound variables
- for( unsigned j=0; j<progs.size(); j++ ){
- Node prog = progs[j];
- std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog );
- if( it_nsi!=d_nsi_op_map.end() ){
- Node op = it_nsi->second;
- std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op );
- if( it_fov!=d_sip->d_func_fo_var.end() ){
- Node pv = it_fov->second;
- Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() );
- Node inv = d_sip->d_func_inv[op];
- single_inv_app_map[prog] = inv;
- Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl;
- d_prog_to_sol_index[prog] = order_vars.size();
- order_vars.push_back( pv );
+ if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_USE && is_syntax_restricted ){
+ singleInvocation = false;
+ Trace("cegqi-si") << "...grammar is restricted, do not use single invocation techniques." << std::endl;
+ }else{
+ Node qq = q[1];
+ if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
+ qq = q[1][0][1];
+ }else{
+ qq = TermDb::simpleNegate( qq );
+ }
+ //remove the deep embedding
+ std::map< Node, Node > visited;
+ std::vector< TypeNode > types;
+ std::vector< Node > order_vars;
+ std::map< Node, Node > single_inv_app_map;
+ int type_valid = 0;
+ qq = removeDeepEmbedding( qq, progs, types, type_valid, visited );
+ Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl;
+ if( type_valid==0 ){
+ //process the single invocation-ness of the property
+ d_sip->init( types, qq );
+ Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
+ d_sip->debugPrint( "cegqi-si" );
+ //map from program to bound variables
+ for( unsigned j=0; j<progs.size(); j++ ){
+ Node prog = progs[j];
+ std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog );
+ if( it_nsi!=d_nsi_op_map.end() ){
+ Node op = it_nsi->second;
+ std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op );
+ if( it_fov!=d_sip->d_func_fo_var.end() ){
+ Node pv = it_fov->second;
+ Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() );
+ Node inv = d_sip->d_func_inv[op];
+ single_inv_app_map[prog] = inv;
+ Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl;
+ d_prog_to_sol_index[prog] = order_vars.size();
+ order_vars.push_back( pv );
+ }
+ }else{
+ //does not mention the function
}
- }else{
- //does not mention the function
}
- }
- //reorder the variables
- Assert( d_sip->d_func_vars.size()==order_vars.size() );
- d_sip->d_func_vars.clear();
- d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() );
+ //reorder the variables
+ Assert( d_sip->d_func_vars.size()==order_vars.size() );
+ d_sip->d_func_vars.clear();
+ d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() );
- //check if it is single invocation
- if( !d_sip->d_conjuncts[1].empty() ){
- singleInvocation = false;
- if( options::cegqiSingleInvPartial() ){
- //this enables partially single invocation techniques
- d_nsingle_inv = d_sip->getNonSingleInvocation();
- d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv );
- d_full_inv = d_sip->getFullSpecification();
- d_full_inv = TermDb::simpleNegate( d_full_inv );
- singleInvocation = true;
- }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
- //if we are doing invariant templates, then construct the template
- std::map< Node, bool > has_inv;
- std::map< Node, std::vector< Node > > inv_pre_post[2];
- for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){
- std::vector< Node > disjuncts;
- Node func;
- int pol = -1;
- Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl;
- d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts );
- if( pol>=0 ){
- Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() );
- Node prog = d_nsi_op_map_to_prog[func];
- Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl;
- Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) );
- c = pol==0 ? TermDb::simpleNegate( c ) : c;
- Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl;
- inv_pre_post[pol][prog].push_back( c );
- has_inv[prog] = true;
- }else{
- Trace("cegqi-inv") << "...no status." << std::endl;
+ //check if it is single invocation
+ if( !d_sip->d_conjuncts[1].empty() ){
+ singleInvocation = false;
+ if( options::cegqiSingleInvPartial() ){
+ //this enables partially single invocation techniques
+ d_nsingle_inv = d_sip->getNonSingleInvocation();
+ d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv );
+ d_full_inv = d_sip->getFullSpecification();
+ d_full_inv = TermDb::simpleNegate( d_full_inv );
+ singleInvocation = true;
+ }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
+ //if we are doing invariant templates, then construct the template
+ std::map< Node, bool > has_inv;
+ std::map< Node, std::vector< Node > > inv_pre_post[2];
+ for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){
+ std::vector< Node > disjuncts;
+ Node func;
+ int pol = -1;
+ Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl;
+ d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts );
+ if( pol>=0 ){
+ Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() );
+ Node prog = d_nsi_op_map_to_prog[func];
+ Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl;
+ Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) );
+ c = pol==0 ? TermDb::simpleNegate( c ) : c;
+ Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl;
+ inv_pre_post[pol][prog].push_back( c );
+ has_inv[prog] = true;
+ }else{
+ Trace("cegqi-inv") << "...no status." << std::endl;
+ }
}
- }
- Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl;
- //now, contruct the template for the invariant(s)
- std::map< Node, Node > prog_templ;
- for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){
- Node prog = iti->first;
- Trace("cegqi-inv") << "...for " << prog << "..." << std::endl;
- Trace("cegqi-inv") << " args : ";
+ Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl;
+ //now, contruct the template for the invariant(s)
+ std::map< Node, Node > prog_templ;
+ for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){
+ Node prog = iti->first;
+ Trace("cegqi-inv") << "...for " << prog << "..." << std::endl;
+ Trace("cegqi-inv") << " args : ";
+ for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
+ std::stringstream ss;
+ ss << "i_" << j;
+ Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() );
+ d_prog_templ_vars[prog].push_back( v );
+ Trace("cegqi-inv") << v << " ";
+ }
+ Trace("cegqi-inv") << std::endl;
+ Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) :
+ ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) );
+ d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) :
+ ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) );
+ d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
+ Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
+ Node invariant = single_inv_app_map[prog];
+ invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+ Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
+ //construct template
+ Node templ;
+ if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
+ //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
+ templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant );
+ }else{
+ Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
+ //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
+ templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant );
+ }
+ visited.clear();
+ templ = addDeepEmbedding( templ, visited );
+ Trace("cegqi-inv") << " template : " << templ << std::endl;
+ prog_templ[prog] = templ;
+ }
+ Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] );
+ visited.clear();
+ bd = addDeepEmbedding( bd, visited );
+ Trace("cegqi-inv") << " body : " << bd << std::endl;
+ bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars );
+ Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl;
+ //make inner existential
+ std::vector< Node > new_var_bv;
for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
std::stringstream ss;
- ss << "i_" << j;
- Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() );
- d_prog_templ_vars[prog].push_back( v );
- Trace("cegqi-inv") << v << " ";
+ ss << "ss_" << j;
+ new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) );
}
- Trace("cegqi-inv") << std::endl;
- Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) :
- ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) );
- d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) :
- ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) );
- d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
- Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
- Node invariant = single_inv_app_map[prog];
- invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
- Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
- //construct template
- Node templ;
- if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
- //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
- templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant );
- }else{
- Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
- //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
- templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant );
+ bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() );
+ Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
+ for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
+ new_var_bv.push_back( q[1][0][0][j] );
}
- visited.clear();
- templ = addDeepEmbedding( templ, visited );
- Trace("cegqi-inv") << " template : " << templ << std::endl;
- prog_templ[prog] = templ;
- }
- Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] );
- visited.clear();
- bd = addDeepEmbedding( bd, visited );
- Trace("cegqi-inv") << " body : " << bd << std::endl;
- bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars );
- Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl;
- //make inner existential
- std::vector< Node > new_var_bv;
- for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
- std::stringstream ss;
- ss << "ss_" << j;
- new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) );
- }
- bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() );
- Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
- for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
- new_var_bv.push_back( q[1][0][0][j] );
- }
- if( !new_var_bv.empty() ){
- Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv );
- bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate();
+ if( !new_var_bv.empty() ){
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv );
+ bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate();
+ }
+ //make outer universal
+ bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd );
+ bd = Rewriter::rewrite( bd );
+ Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl;
+ d_quant = bd;
}
- //make outer universal
- bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd );
- bd = Rewriter::rewrite( bd );
- Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl;
- d_quant = bd;
+ }else{
+ //we are fully single invocation
}
}else{
- //we are fully single invocation
+ Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl;
+ singleInvocation = false;
}
- }else{
- Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl;
- singleInvocation = false;
}
if( singleInvocation ){
d_single_inv = d_sip->getSingleInvocation();
@@ -534,6 +548,7 @@ bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){
return false;
}else{
Trace("cegqi-engine") << siss.str() << std::endl;
+ Assert( d_single_inv_var.size()==subs.size() );
Node lem = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), subs.begin(), subs.end() );
if( d_qe->getTermDatabase()->containsVtsTerm( lem ) ){
Trace("cegqi-engine-debug") << "Rewrite based on vts symbols..." << std::endl;
@@ -595,6 +610,7 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
for( unsigned i=0; i<d_sip->d_all_vars.size(); i++ ){
subs.push_back( NodeManager::currentNM()->mkSkolem( "kv", d_sip->d_all_vars[i].getType(), "created for verifying nsi" ) );
}
+ Assert( d_sip->d_all_vars.size()==subs.size() );
inst = inst.substitute( d_sip->d_all_vars.begin(), d_sip->d_all_vars.end(), subs.begin(), subs.end() );
Trace("cegqi-nsi") << "NSI : verification : " << inst << std::endl;
Trace("cegqi-lemma") << "Cegqi::Lemma : verification lemma : " << inst << std::endl;
@@ -751,6 +767,7 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int&
std::sort( indices.begin(), indices.end(), ssii );
Trace("csi-sol") << "Construct solution" << std::endl;
s = constructSolution( indices, sol_index, 0 );
+ Assert( vars.size()==d_sol->d_varList.size() );
s = s.substitute( vars.begin(), vars.end(), d_sol->d_varList.begin(), d_sol->d_varList.end() );
}
d_orig_solution = s;
@@ -826,8 +843,8 @@ Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& rec
}
bool CegConjectureSingleInv::needsCheck() {
- if( options::cegqiSingleInvMultiInstAbort() ){
- if( !hasITEs() ){
+ if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_ALL_ABORT ){
+ if( !d_has_ites ){
return d_inst.empty();
}
}
@@ -922,6 +939,7 @@ void SingleInvocationPartition::process( Node n ) {
std::vector< Node > funcs;
//normalize the invocations
if( !terms.empty() ){
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
}
std::vector< Node > children;
@@ -940,6 +958,7 @@ void SingleInvocationPartition::process( Node n ) {
}
Trace("si-prt") << std::endl;
cr = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
Trace("si-prt-debug") << "...normalized invocations to " << cr << std::endl;
//now must check if it has other bound variables
@@ -974,6 +993,7 @@ void SingleInvocationPartition::process( Node n ) {
}
}
}
+ Assert( terms.size()==subs.size() );
cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
}
cr = Rewriter::rewrite( cr );
@@ -982,6 +1002,7 @@ void SingleInvocationPartition::process( Node n ) {
TermDb::getBoundVars( cr, d_all_vars );
if( singleInvocation ){
//replace with single invocation formulation
+ Assert( si_terms.size()==si_subs.size() );
cr = cr.substitute( si_terms.begin(), si_terms.end(), si_subs.begin(), si_subs.end() );
cr = Rewriter::rewrite( cr );
Trace("si-prt") << ".....si version=" << cr << std::endl;
diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h
index 4d2f9a0e5..4d2f9a0e5 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv.h
+++ b/src/theory/quantifiers/ce_guided_single_inv.h
diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
index 6394fca3d..6394fca3d 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp
diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.h b/src/theory/quantifiers/ce_guided_single_inv_ei.h
index 42e0b0820..42e0b0820 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_ei.h
+++ b/src/theory/quantifiers/ce_guided_single_inv_ei.h
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
index 240c2ed12..240c2ed12 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.h b/src/theory/quantifiers/ce_guided_single_inv_sol.h
index cb6f6bc41..cb6f6bc41 100644..100755
--- a/src/theory/quantifiers/ce_guided_single_inv_sol.h
+++ b/src/theory/quantifiers/ce_guided_single_inv_sol.h
diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp
index da488ea98..cd263e90c 100644..100755
--- a/src/theory/quantifiers/ceg_instantiator.cpp
+++ b/src/theory/quantifiers/ceg_instantiator.cpp
@@ -22,6 +22,9 @@
#include "theory/quantifiers/term_database.h"
#include "theory/theory_engine.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "util/bitvector.h"
+
//#define MBP_STRICT_ASSERTIONS
using namespace std;
@@ -466,6 +469,36 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::
}
}
}
+ /* TODO: algebraic reasoning for bitvector instantiation
+ else if( pvtn.isBitVector() ){
+ if( atom.getKind()==BITVECTOR_ULT || atom.getKind()==BITVECTOR_ULE ){
+ for( unsigned t=0; t<2; t++ ){
+ if( atom[t]==pv ){
+ computeProgVars( atom[1-t] );
+ if( d_inelig.find( atom[1-t] )==d_inelig.end() ){
+ //only ground terms TODO: more
+ if( d_prog_var[atom[1-t]].empty() ){
+ Node veq_c;
+ Node uval;
+ if( ( !pol && atom.getKind()==BITVECTOR_ULT ) || ( pol && atom.getKind()==BITVECTOR_ULE ) ){
+ uval = atom[1-t];
+ }else{
+ uval = NodeManager::currentNM()->mkNode( (atom.getKind()==BITVECTOR_ULT)==(t==1) ? BITVECTOR_PLUS : BITVECTOR_SUB, atom[1-t],
+ bv::utils::mkConst(pvtn.getConst<BitVectorSize>(), 1) );
+ }
+ if( subs_proc[uval].find( veq_c )==subs_proc[uval].end() ){
+ subs_proc[uval][veq_c] = true;
+ if( doAddInstantiationInc( uval, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ */
}
}
}
@@ -685,7 +718,7 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::
//[5] resort to using value in model
// do so if we are in effort=1, or if the variable is boolean, or if we are solving for a subfield of a datatype
- if( ( effort>0 || pvtn.isBoolean() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){
+ if( ( effort>0 || pvtn.isBoolean() || pvtn.isBitVector() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){
Node mv = getModelValue( pv );
Node pv_coeff_m;
Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl;
@@ -781,6 +814,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
}
}
if( success ){
+ Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl;
vars.push_back( pv );
btyp.push_back( bt );
sf.push_back( pv, n, pv_coeff );
@@ -800,8 +834,10 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
curr_var.pop_back();
is_cv = true;
}
+ Trace("cbqi-inst-debug2") << "Recurse..." << std::endl;
success = doAddInstantiation( sf, ssf, vars, btyp, new_theta, curr_var.empty() ? i+1 : i, effort, cons, curr_var );
if( !success ){
+ Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl;
if( is_cv ){
curr_var.push_back( pv );
}
@@ -814,6 +850,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int
if( success ){
return true;
}else{
+ Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl;
//revert substitution information
for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){
sf.d_subs[it->first] = it->second;
@@ -1035,7 +1072,13 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node
if( !it->second.isNull() ){
c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
}
- Node c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
+ Assert( !c_coeff.isNull() );
+ Node c;
+ if( msum_term[it->first].isNull() ){
+ c = c_coeff;
+ }else{
+ c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
+ }
children.push_back( c );
Trace("cegqi-si-apply-subs-debug") << "Add child : " << c << std::endl;
}
@@ -1594,6 +1637,7 @@ int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, No
realPart = real_part.empty() ? d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) );
Assert( d_out->isEligibleForInstantiation( realPart ) );
//re-isolate
+ Trace("cbqi-inst-debug") << "Re-isolate..." << std::endl;
ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() );
Trace("cbqi-inst-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl;
Trace("cbqi-inst-debug") << " real part : " << realPart << std::endl;
diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h
index 3d7bbcb55..3d7bbcb55 100644..100755
--- a/src/theory/quantifiers/ceg_instantiator.h
+++ b/src/theory/quantifiers/ceg_instantiator.h
diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp
index 2cc49ef5a..f4eb67d74 100644..100755
--- a/src/theory/quantifiers/conjecture_generator.cpp
+++ b/src/theory/quantifiers/conjecture_generator.cpp
@@ -285,7 +285,7 @@ Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
}
bool ConjectureGenerator::isHandledTerm( TNode n ){
- return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
+ return d_quantEngine->getTermDatabase()->isTermActive( n ) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
}
Node ConjectureGenerator::getGroundEqc( TNode r ) {
@@ -425,7 +425,7 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {
eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
while( !eqc_i.isFinished() ){
TNode n = (*eqc_i);
- if( getTermDatabase()->hasTermCurrent( n ) && !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){
+ if( getTermDatabase()->hasTermCurrent( n ) && getTermDatabase()->isTermActive( n ) && ( n.getKind()!=EQUAL || isFalse ) ){
if( firstTime ){
Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;
firstTime = false;
@@ -1572,7 +1572,6 @@ bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode,
if( d_match_status_child_num==0 ){
//initial binding
TNode f = s->getTgFunc( d_typ, d_status_num );
- //std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );
Assert( !eqc.isNull() );
TermArgTrie * tat = s->getTermDatabase()->getTermArgTrie( eqc, f );
if( tat ){
@@ -1726,9 +1725,9 @@ void TermGenEnv::collectSignatureInformation() {
d_func_kind.clear();
d_func_args.clear();
TypeNode tnull;
- for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){
- if( getTermDatabase()->getNumGroundTerms( it->first )>0 ){
- Node nn = getTermDatabase()->getGroundTerm( it->first, 0 );
+ for( std::map< Node, std::vector< Node > >::iterator it = getTermDatabase()->d_op_map.begin(); it != getTermDatabase()->d_op_map.end(); ++it ){
+ if( !it->second.empty() ){
+ Node nn = it->second[0];
Trace("sg-rel-sig-debug") << "Check in signature : " << nn << std::endl;
if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){
bool do_enum = true;
@@ -1750,7 +1749,7 @@ void TermGenEnv::collectSignatureInformation() {
d_typ_tg_funcs[nn.getType()].push_back( it->first );
d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED );
Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;
- getTermDatabase()->computeUfEqcTerms( it->first );
+ //getTermDatabase()->computeUfEqcTerms( it->first );
}
}
Trace("sg-rel-sig-debug") << "Done check in signature : " << nn << std::endl;
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h
index c89d0f2ee..c89d0f2ee 100644..100755
--- a/src/theory/quantifiers/conjecture_generator.h
+++ b/src/theory/quantifiers/conjecture_generator.h
diff --git a/src/theory/quantifiers/equality_infer.cpp b/src/theory/quantifiers/equality_infer.cpp
index c3064116f..5190025ee 100644..100755
--- a/src/theory/quantifiers/equality_infer.cpp
+++ b/src/theory/quantifiers/equality_infer.cpp
@@ -53,10 +53,10 @@ void EqualityInference::addToExplanation( std::vector< Node >& exp, Node e ) {
}
void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc ) {
- NodeListMap::iterator re_i = d_rep_exp.find( eqc );
+ NodeIntMap::iterator re_i = d_rep_exp.find( eqc );
if( re_i!=d_rep_exp.end() ){
- for( unsigned i=0; i<(*re_i).second->size(); i++ ){
- addToExplanation( exp, (*(*re_i).second)[i] );
+ for( int i=0; i<(*re_i).second; i++ ){
+ addToExplanation( exp, d_rep_exp_data[eqc][i] );
}
}
//for( unsigned i=0; i<d_eqci[n]->d_rep_exp.size(); i++ ){
@@ -65,16 +65,19 @@ void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc
}
void EqualityInference::addToExplanationEqc( Node eqc, std::vector< Node >& exp_to_add ) {
- NodeListMap::iterator re_i = d_rep_exp.find( eqc );
- NodeList* re;
+ NodeIntMap::iterator re_i = d_rep_exp.find( eqc );
+ int n_re = 0;
if( re_i != d_rep_exp.end() ){
- re = (*re_i).second;
- }else{
- re = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) );
- d_rep_exp.insertDataFromContextMemory( eqc, re );
+ n_re = (*re_i).second;
}
+ d_rep_exp[eqc] = n_re + exp_to_add.size();
for( unsigned i=0; i<exp_to_add.size(); i++ ){
- re->push_back( exp_to_add[i] );
+ if( n_re<(int)d_rep_exp_data[eqc].size() ){
+ d_rep_exp_data[eqc][n_re] = exp_to_add[i];
+ }else{
+ d_rep_exp_data[eqc].push_back( exp_to_add[i] );
+ }
+ n_re++;
}
//for( unsigned i=0; i<exp_to_add.size(); i++ ){
// eqci->d_rep_exp.push_back( exp_to_add[i] );
@@ -204,16 +207,18 @@ void EqualityInference::eqNotifyNewClass(TNode t) {
void EqualityInference::addToUseList( Node used, Node eqc ) {
#if 1
- NodeListMap::iterator ul_i = d_uselist.find( used );
- NodeList* ul;
+ NodeIntMap::iterator ul_i = d_uselist.find( used );
+ int n_ul = 0;
if( ul_i != d_uselist.end() ){
- ul = (*ul_i).second;
- }else{
- ul = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) );
- d_uselist.insertDataFromContextMemory( used, ul );
+ n_ul = (*ul_i).second;
}
+ d_uselist[ used ] = n_ul + 1;
Trace("eq-infer-debug") << " add to use list : " << used << " -> " << eqc << std::endl;
- (*ul).push_back( eqc );
+ if( n_ul<(int)d_uselist_data[used].size() ){
+ d_uselist_data[used][n_ul] = eqc;
+ }else{
+ d_uselist_data[used].push_back( eqc );
+ }
#else
std::map< Node, EqcInfo * >::iterator itu = d_eqci.find( used );
EqcInfo * eqci_used;
@@ -356,12 +361,12 @@ void EqualityInference::eqNotifyMerge(TNode t1, TNode t2) {
//go through all equivalence classes that may refer to v_solve
std::map< Node, bool > processed;
processed[v_solve] = true;
- NodeListMap::iterator ul_i = d_uselist.find( v_solve );
+ NodeIntMap::iterator ul_i = d_uselist.find( v_solve );
if( ul_i != d_uselist.end() ){
- NodeList* ul = (*ul_i).second;
- Trace("eq-infer-debug") << " use list size = " << ul->size() << std::endl;
- for( unsigned j=0; j<ul->size(); j++ ){
- Node r = (*ul)[j];
+ int n_ul = (*ul_i).second;
+ Trace("eq-infer-debug") << " use list size = " << n_ul << std::endl;
+ for( int j=0; j<n_ul; j++ ){
+ Node r = d_uselist_data[v_solve][j];
//Trace("eq-infer-debug") << " use list size = " << eqci_solved->d_uselist.size() << std::endl;
//for( unsigned j=0; j<eqci_solved->d_uselist.size(); j++ ){
// Node r = eqci_solved->d_uselist[j];
diff --git a/src/theory/quantifiers/equality_infer.h b/src/theory/quantifiers/equality_infer.h
index 93c7bd080..80d6ef98b 100644..100755
--- a/src/theory/quantifiers/equality_infer.h
+++ b/src/theory/quantifiers/equality_infer.h
@@ -39,7 +39,7 @@ class EqualityInference
typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap< Node, NodeList *, NodeHashFunction > NodeListMap;
+ typedef context::CDHashMap< Node, int, NodeHashFunction > NodeIntMap;
private:
context::Context * d_c;
Node d_one;
@@ -67,11 +67,13 @@ private:
BoolMap d_elim_vars;
std::map< Node, EqcInfo * > d_eqci;
NodeMap d_rep_to_eqc;
- NodeListMap d_rep_exp;
+ NodeIntMap d_rep_exp;
+ std::map< Node, std::vector< Node > > d_rep_exp_data;
/** set eqc rep */
void setEqcRep( Node t, Node r, std::vector< Node >& exp_to_add, EqcInfo * eqci );
/** use list */
- NodeListMap d_uselist;
+ NodeIntMap d_uselist;
+ std::map< Node, std::vector< Node > > d_uselist_data;
void addToUseList( Node used, Node eqc );
/** pending merges */
NodeList d_pending_merges;
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index a833f48d2..670f0eff3 100644..100755
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -406,8 +406,8 @@ Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri
//check the type of n
if( n.getKind()==INST_CONSTANT ){
int v = n.getAttribute(InstVarNumAttribute());
- depIndex = ri->d_var_order[ v ];
- val = ri->getTerm( v );
+ depIndex = ri->getIndexOrder( v );
+ val = ri->getCurrentTerm( v );
}else if( n.getKind()==ITE ){
int depIndex1, depIndex2;
int eval = evaluate( n[0], depIndex1, ri );
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index cbe83cfa5..cbe83cfa5 100644..100755
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index 33c853328..a0665cb7f 100644..100755
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -405,7 +405,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
bool needsDefault = true;
for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
Node n = fm->d_uf_terms[op][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
add_conds.push_back( n );
add_values.push_back( n );
Node r = fm->getUsedRepresentative(n);
@@ -764,7 +764,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
//set the domains based on the entry
for (unsigned i=0; i<c.getNumChildren(); i++) {
- if (riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS) {
+ if( riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS || riter.d_enum_type[i]==RepSetIterator::ENUM_SET_MEMBERS ){
TypeNode tn = c[i].getType();
if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
if( fm->isInterval(c[i]) || fm->isStar(c[i]) ){
@@ -773,6 +773,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
if (d_rep_ids[tn].find(c[i])!=d_rep_ids[tn].end()) {
riter.d_domain[i].clear();
riter.d_domain[i].push_back(d_rep_ids[tn][c[i]]);
+ riter.d_enum_type[i] = RepSetIterator::ENUM_DOMAIN_ELEMENTS;
}else{
Trace("fmc-exh") << "---- Does not have rep : " << c[i] << " for type " << tn << std::endl;
return false;
@@ -792,7 +793,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
std::vector< Node > ev_inst;
std::vector< Node > inst;
for( int i=0; i<riter.getNumTerms(); i++ ){
- Node rr = riter.getTerm( i );
+ Node rr = riter.getCurrentTerm( i );
Node r = rr;
//if( r.getType().isSort() ){
r = fm->getUsedRepresentative( r );
@@ -826,18 +827,18 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
int index = riter.increment();
Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
if( !riter.isFinished() ){
- if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
+ if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_INT_RANGE) {
Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
riter.increment2( index-1 );
}
}
}
d_addedLemmas += addedLemmas;
- Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.d_incomplete << std::endl;
- return addedLemmas>0 || !riter.d_incomplete;
+ Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
+ return addedLemmas>0 || !riter.isIncomplete();
}else{
Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl;
- return false;
+ return !riter.isIncomplete();
}
}
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
index 411b7a5eb..411b7a5eb 100644..100755
--- a/src/theory/quantifiers/full_model_check.h
+++ b/src/theory/quantifiers/full_model_check.h
diff --git a/src/theory/quantifiers/fun_def_engine.cpp b/src/theory/quantifiers/fun_def_engine.cpp
index cf1d14663..cf1d14663 100644..100755
--- a/src/theory/quantifiers/fun_def_engine.cpp
+++ b/src/theory/quantifiers/fun_def_engine.cpp
diff --git a/src/theory/quantifiers/fun_def_engine.h b/src/theory/quantifiers/fun_def_engine.h
index 3b95281c0..3b95281c0 100644..100755
--- a/src/theory/quantifiers/fun_def_engine.h
+++ b/src/theory/quantifiers/fun_def_engine.h
diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp
index 9109aab8a..9109aab8a 100644..100755
--- a/src/theory/quantifiers/fun_def_process.cpp
+++ b/src/theory/quantifiers/fun_def_process.cpp
diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h
index 1f6ee6562..1f6ee6562 100644..100755
--- a/src/theory/quantifiers/fun_def_process.h
+++ b/src/theory/quantifiers/fun_def_process.h
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index 8818175db..8818175db 100644..100755
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index ad287c1a3..ad287c1a3 100644..100755
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index bf05de3bb..2d3bf76f6 100644..100755
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -32,6 +32,7 @@ namespace theory {
namespace inst {
InstMatchGenerator::InstMatchGenerator( Node pat ){
+ d_cg = NULL;
d_needsReset = true;
d_active_add = false;
Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
@@ -43,12 +44,20 @@ InstMatchGenerator::InstMatchGenerator( Node pat ){
}
InstMatchGenerator::InstMatchGenerator() {
+ d_cg = NULL;
d_needsReset = true;
d_active_add = false;
d_next = NULL;
d_matchPolicy = MATCH_GEN_DEFAULT;
}
+InstMatchGenerator::~InstMatchGenerator() throw() {
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ delete d_children[i];
+ }
+ delete d_cg;
+}
+
void InstMatchGenerator::setActiveAdd(bool val){
d_active_add = val;
if( d_next!=NULL ){
@@ -150,7 +159,7 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector<
d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
}
}else{
- d_cg = new CandidateGeneratorQueue;
+ d_cg = new CandidateGeneratorQueue( qe );
Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
@@ -249,7 +258,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
Trace("matching-debug2") << "Reset children..." << std::endl;
//now, fit children into match
//we will be requesting candidates for matching terms for each child
- for( int i=0; i<(int)d_children.size(); i++ ){
+ for( unsigned i=0; i<d_children.size(); i++ ){
d_children[i]->reset( t[ d_children_index[i] ], qe );
}
Trace("matching-debug2") << "Continue next " << d_next << std::endl;
@@ -484,7 +493,7 @@ d_f( q ){
}
Debug("smart-multi-trigger") << std::endl;
}
- for( int i=0; i<(int)pats.size(); i++ ){
+ for( unsigned i=0; i<pats.size(); i++ ){
Node n = pats[i];
//make the match generator
d_children.push_back( InstMatchGenerator::mkInstMatchGenerator(q, n, qe ) );
@@ -492,7 +501,7 @@ d_f( q ){
std::vector< int > unique_vars;
std::map< int, bool > shared_vars;
int numSharedVars = 0;
- for( int j=0; j<(int)d_var_contains[n].size(); j++ ){
+ for( unsigned j=0; j<d_var_contains[n].size(); j++ ){
if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
unique_vars.push_back( d_var_contains[n][j] );
@@ -503,7 +512,7 @@ d_f( q ){
}
//we use the latest shared variables, then unique variables
std::vector< int > vars;
- int index = i==0 ? (int)(pats.size()-1) : (i-1);
+ unsigned index = i==0 ? pats.size()-1 : (i-1);
while( numSharedVars>0 && index!=i ){
for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
if( it->second ){
@@ -519,16 +528,24 @@ d_f( q ){
}
vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
Debug("smart-multi-trigger") << " Index[" << i << "]: ";
- for( int i=0; i<(int)vars.size(); i++ ){
- Debug("smart-multi-trigger") << vars[i] << " ";
+ for( unsigned j=0; j<vars.size(); j++ ){
+ Debug("smart-multi-trigger") << vars[j] << " ";
}
Debug("smart-multi-trigger") << std::endl;
//make ordered inst match trie
- InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder;
- imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() );
- d_children_trie.push_back( InstMatchTrieOrdered( imtio ) );
+ d_imtio[i] = new InstMatchTrie::ImtIndexOrder;
+ d_imtio[i]->d_order.insert( d_imtio[i]->d_order.begin(), vars.begin(), vars.end() );
+ d_children_trie.push_back( InstMatchTrieOrdered( d_imtio[i] ) );
}
+}
+InstMatchGeneratorMulti::~InstMatchGeneratorMulti() throw() {
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ delete d_children[i];
+ }
+ for( std::map< unsigned, InstMatchTrie::ImtIndexOrder* >::iterator it = d_imtio.begin(); it != d_imtio.end(); ++it ){
+ delete it->second;
+ }
}
/** reset instantiation round (call this whenever equivalence classes have changed) */
@@ -697,7 +714,7 @@ int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){
return addedLemmas;
}
-InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q ), d_match_pattern( pat ) {
+InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe ) : d_f( q ), d_match_pattern( pat ) {
if( d_match_pattern.getKind()==NOT ){
d_match_pattern = d_match_pattern[0];
d_pol = false;
@@ -720,10 +737,11 @@ InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q
}
d_match_pattern_arg_types.push_back( d_match_pattern[i].getType() );
}
+ d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
}
void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) {
- d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+
}
int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ){
@@ -751,6 +769,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, Q
tat = NULL;
}
}
+ Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl;
if( tat ){
InstMatch m( q );
m.add( baseMatch );
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index a1d907001..096774c51 100644..100755
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -91,7 +91,7 @@ public:
InstMatchGenerator( Node pat );
InstMatchGenerator();
/** destructor */
- ~InstMatchGenerator() throw() {}
+ virtual ~InstMatchGenerator() throw();
/** The pattern we are producing matches for.
If null, this is a multi trigger that is merging matches from d_children.
*/
@@ -125,7 +125,7 @@ public:
class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
public:
VarMatchGeneratorBooleanTerm( Node var, Node comp );
- ~VarMatchGeneratorBooleanTerm() throw() {}
+ virtual ~VarMatchGeneratorBooleanTerm() throw() {}
Node d_comp;
bool d_rm_prev;
/** reset instantiation round (call this at beginning of instantiation round) */
@@ -142,7 +142,7 @@ public:
class VarMatchGeneratorTermSubs : public InstMatchGenerator {
public:
VarMatchGeneratorTermSubs( Node var, Node subs );
- ~VarMatchGeneratorTermSubs() throw() {}
+ virtual ~VarMatchGeneratorTermSubs() throw() {}
TNode d_var;
TypeNode d_var_type;
Node d_subs;
@@ -183,6 +183,8 @@ private:
int d_matchPolicy;
/** children generators */
std::vector< InstMatchGenerator* > d_children;
+ /** order */
+ std::map< unsigned, InstMatchTrie::ImtIndexOrder* > d_imtio;
/** inst match tries for each child */
std::vector< InstMatchTrieOrdered > d_children_trie;
/** calculate matches */
@@ -191,7 +193,7 @@ public:
/** constructors */
InstMatchGeneratorMulti( Node q, std::vector< Node >& pats, QuantifiersEngine* qe );
/** destructor */
- ~InstMatchGeneratorMulti() throw() {}
+ virtual ~InstMatchGeneratorMulti() throw();
/** reset instantiation round (call this whenever equivalence classes have changed) */
void resetInstantiationRound( QuantifiersEngine* qe );
/** reset, eqc is the equivalence class to search in (any if eqc=null) */
@@ -224,7 +226,7 @@ private:
void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat );
public:
/** constructors */
- InstMatchGeneratorSimple( Node q, Node pat );
+ InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe );
/** destructor */
~InstMatchGeneratorSimple() throw() {}
/** reset instantiation round (call this whenever equivalence classes have changed) */
diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp
index d4be58636..41c9c40c8 100644..100755
--- a/src/theory/quantifiers/inst_propagator.cpp
+++ b/src/theory/quantifiers/inst_propagator.cpp
@@ -34,6 +34,7 @@ bool EqualityQueryInstProp::reset( Theory::Effort e ) {
d_uf.clear();
d_uf_exp.clear();
d_diseq_list.clear();
+ d_uf_func_map_trie.clear();
return true;
}
@@ -103,8 +104,7 @@ TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& arg
if( !t.isNull() ){
return t;
}else{
- //TODO?
- return TNode::null();
+ return d_uf_func_map_trie[f].existsTerm( args );
}
}
@@ -118,6 +118,7 @@ Node EqualityQueryInstProp::getRepresentativeExp( Node a, std::vector< Node >& e
Node ar = getUfRepresentative( a, exp );
if( !ar.isNull() ){
if( engine_has_a || getEngine()->hasTerm( ar ) ){
+ Trace("qip-eq") << "getRepresentativeExp " << a << " returns " << ar << std::endl;
Assert( getEngine()->hasTerm( ar ) );
Assert( getEngine()->getRepresentative( ar )==ar );
return ar;
@@ -168,6 +169,21 @@ bool EqualityQueryInstProp::areDisequalExp( Node a, Node b, std::vector< Node >&
}
}
+TNode EqualityQueryInstProp::getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp ) {
+ TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args );
+ if( !t.isNull() ){
+ return t;
+ }else{
+ TNode tt = d_uf_func_map_trie[f].existsTerm( args );
+ if( !tt.isNull() ){
+ //TODO?
+ return tt;
+ }else{
+ return tt;
+ }
+ }
+}
+
Node EqualityQueryInstProp::getUfRepresentative( Node a, std::vector< Node >& exp ) {
Assert( exp.empty() );
std::map< Node, Node >::iterator it = d_uf.find( a );
@@ -252,7 +268,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
}
-
+
if( swap ){
//swap
Node temp_r = ar;
@@ -262,7 +278,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
Assert( !getEngine()->hasTerm( ar ) || getEngine()->hasTerm( br ) );
Assert( ar!=br );
-
+
std::vector< Node > exp_d;
if( areDisequalExp( ar, br, exp_d ) ){
if( pol ){
@@ -279,18 +295,20 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
Assert( d_uf_exp[ar].empty() );
Assert( d_uf_exp[br].empty() );
+ //registerUfTerm( ar );
d_uf[ar] = br;
merge_exp( d_uf_exp[ar], exp_a );
merge_exp( d_uf_exp[ar], exp_b );
merge_exp( d_uf_exp[ar], reason );
+ //registerUfTerm( br );
d_uf[br] = br;
d_uf_exp[br].clear();
Trace("qip-eq") << "EqualityQueryInstProp::setEqual : merge " << ar << " -> " << br << ", exp size = " << d_uf_exp[ar].size() << ", status = " << status << std::endl;
a = ar;
b = br;
-
+
//carry disequality list
std::map< Node, std::map< Node, std::vector< Node > > >::iterator itd = d_diseq_list.find( ar );
if( itd!=d_diseq_list.end() ){
@@ -302,13 +320,13 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
}
-
+
return status;
}else{
Trace("qip-eq") << "EqualityQueryInstProp::setEqual : disequal " << ar << " <> " << br << std::endl;
Assert( d_diseq_list[ar].find( br )==d_diseq_list[ar].end() );
Assert( d_diseq_list[br].find( ar )==d_diseq_list[br].end() );
-
+
merge_exp( d_diseq_list[ar][br], reason );
merge_exp( d_diseq_list[br][ar], reason );
return STATUS_NONE;
@@ -316,187 +334,234 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No
}
}
-void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) {
- if( is_prop ){
- if( isLiteral( n ) ){
- props.push_back( pol ? n : n.negate() );
- return;
+void EqualityQueryInstProp::registerUfTerm( TNode n ) {
+ if( d_uf.find( n )==d_uf.end() ){
+ if( !getEngine()->hasTerm( n ) ){
+ TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !getEngine()->hasTerm( n[i] ) ){
+ return;
+ }else{
+ args.push_back( n[i] );
+ }
+ }
+ d_uf_func_map_trie[f].addTerm( n, args );
+ }
}
}
+}
+
+//void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) {
+void EqualityQueryInstProp::addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch ) {
+ if( is_watch ){
+ watch.push_back( n );
+ }
args.push_back( n );
}
-bool EqualityQueryInstProp::isLiteral( Node n ) {
- Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind();
- Assert( ak!=NOT );
- return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE;
+bool EqualityQueryInstProp::isPropagateLiteral( Node n ) {
+ if( n==d_true || n==d_false ){
+ return false;
+ }else{
+ Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind();
+ Assert( ak!=NOT );
+ return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE;
+ }
+}
+
+void EqualityQueryInstProp::setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out ) {
+ if( watch.empty() ){
+ watch.push_back( n );
+ }
+ for( unsigned j=0; j<watch.size(); j++ ){
+ Trace("qip-eval") << "Watch : " << n << " -> " << watch[j] << std::endl;
+ watch_list_out[n].push_back( watch[j] );
+ }
+}
+
+void EqualityQueryInstProp::collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list ) {
+ std::map< Node, std::vector< Node > >::iterator it = watch_list_out.find( n );
+ if( it!=watch_list_out.end() && std::find( watch_list.begin(), watch_list.end(), n )==watch_list.end() ){
+ watch_list.push_back( n );
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ collectWatchList( it->second[j], watch_list_out, watch_list );
+ }
+ }
}
-//this is identical to TermDb::evaluateTerm2, but tracks more information
-Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol,
- std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) {
- std::map< Node, Node >::iterator itv = visited.find( n );
- if( itv != visited.end() ){
+//this is similar to TermDb::evaluateTerm2, but tracks more information
+Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited,
+ bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props ) {
+ int polIndex = hasPol ? ( pol ? 1 : -1 ) : 0;
+ std::map< Node, Node >::iterator itv = visited[polIndex].find( n );
+ if( itv!=visited[polIndex].end() ){
return itv->second;
}else{
- visited[n] = n;
- Trace("qip-eval") << "evaluate term : " << n << std::endl;
- std::vector< Node > exp_n;
- Node ret = getRepresentativeExp( n, exp_n );
- if( ret.isNull() ){
- //term is not known to be equal to a representative in equality engine, evaluate it
- Kind k = n.getKind();
- if( k==FORALL ){
- ret = Node::null();
- }else{
- std::map< Node, bool > watch_list_out_curr;
- TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
- std::vector< Node > args;
- bool ret_set = false;
- bool childChanged = false;
- int abort_i = -1;
- //get the child entailed polarity
- Assert( n.getKind()!=IMPLIES );
- bool newHasPol, newPol;
- QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );
- //for each child
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props );
- if( c.isNull() ){
- ret = Node::null();
- ret_set = true;
- break;
- }else if( c==d_true || c==d_false ){
- //short-circuiting
- if( k==kind::AND || k==kind::OR ){
- if( (k==kind::AND)==(c==d_false) ){
- ret = c;
- ret_set = true;
- break;
- }else{
- //redundant
- c = Node::null();
- childChanged = true;
- }
- }else if( k==kind::ITE && i==0 ){
- Assert( watch_list_out_curr.empty() );
- ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props );
- ret_set = true;
- break;
- }else if( k==kind::NOT ){
- ret = c==d_true ? d_false : d_true;
+ visited[polIndex][n] = n;
+ Node ret;
+ //check if it should be propagated in this context
+ if( hasPol && isPropagateLiteral( n ) ){
+ Assert( n.getType().isBoolean() );
+ //must be Boolean
+ ret = evaluateTermExp( n, exp, visited, false, pol, watch_list_out, props );
+ if( isPropagateLiteral( ret ) ){
+ Trace("qip-eval") << "-----> propagate : " << ret << std::endl;
+ props.push_back( pol ? ret : ret.negate() );
+ ret = pol ? d_true : d_false;
+ }
+ }else{
+ Trace("qip-eval") << "evaluate term : " << n << " [" << polIndex << "]" << std::endl;
+ std::vector< Node > exp_n;
+ ret = getRepresentativeExp( n, exp_n );
+ if( ret.isNull() ){
+ //term is not known to be equal to a representative in equality engine, evaluate it
+ Kind k = n.getKind();
+ if( k!=FORALL ){
+ TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
+ std::vector< Node > args;
+ bool ret_set = false;
+ bool childChanged = false;
+ int abort_i = -1;
+ //get the child entailed polarity
+ Assert( n.getKind()!=IMPLIES );
+ bool newHasPol, newPol;
+ QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );
+ std::vector< Node > watch;
+ //for each child
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out, props );
+ if( c.isNull() ){
+ ret = Node::null();
ret_set = true;
break;
- }
- }
- if( !c.isNull() ){
- childChanged = childChanged || n[i]!=c;
- if( !f.isNull() && !watch_list_out_curr.empty() ){
- // we are done if this is an UF application and an argument is unevaluated
- args.push_back( c );
- abort_i = i;
- break;
- }else if( ( k==kind::AND || k==kind::OR ) ){
- if( c.getKind()==k ){
- //flatten
- for( unsigned j=0; j<c.getNumChildren(); j++ ){
- addArgument( args, props, c[j], newHasPol, newPol );
+ }else if( c==d_true || c==d_false ){
+ //short-circuiting
+ if( k==kind::AND || k==kind::OR ){
+ if( (k==kind::AND)==(c==d_false) ){
+ ret = c;
+ ret_set = true;
+ break;
+ }else{
+ //redundant
+ c = Node::null();
+ childChanged = true;
}
- }else{
- addArgument( args, props, c, newHasPol, newPol );
+ }else if( k==kind::ITE && i==0 ){
+ ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out, props );
+ ret_set = true;
+ break;
+ }else if( k==kind::NOT ){
+ ret = c==d_true ? d_false : d_true;
+ ret_set = true;
+ break;
}
- //if we are in a branching position
- if( hasPol && !newHasPol && args.size()>=2 ){
- //we are done if at least two args are unevaluated
+ }
+ if( !c.isNull() ){
+ childChanged = childChanged || n[i]!=c;
+ bool is_watch = watch_list_out.find( c )!=watch_list_out.end();
+ if( !f.isNull() && is_watch ){
+ // we are done if this is an UF application and an argument is unevaluated
+ addArgument( c, args, watch, is_watch );
abort_i = i;
break;
+ }else if( k==kind::AND || k==kind::OR || k==kind::ITE || k==IFF ){
+ Trace("qip-eval-debug") << "Adding argument " << c << " to " << k << ", isProp = " << newHasPol << std::endl;
+ if( ( k==kind::AND || k==kind::OR ) && c.getKind()==k ){
+ //flatten
+ for( unsigned j=0; j<c.getNumChildren(); j++ ){
+ addArgument( c[j], args, watch, is_watch );
+ }
+ }else{
+ addArgument( c, args, watch, is_watch );
+ }
+ Trace("qip-eval-debug") << "props/args = " << props.size() << "/" << args.size() << std::endl;
+ //if we are in a branching position
+ if( hasPol && !newHasPol && args.size()>=2 ){
+ //we are done if at least two args are unevaluated
+ abort_i = i;
+ break;
+ }
+ }else{
+ addArgument( c, args, watch, is_watch );
}
- }else if( k==kind::ITE ){
- //we are done if we are ITE and condition is unevaluated
- Assert( i==0 );
- args.push_back( c );
- abort_i = i;
- break;
- }else{
- args.push_back( c );
}
}
- }
- //add remaining children if we aborted
- if( abort_i!=-1 ){
- for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){
- args.push_back( n[i] );
- }
- }
- //copy over the watch list
- for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){
- watch_list_out[itc->first] = itc->second;
- }
-
- //if we have not short-circuited evaluation
- if( !ret_set ){
- //if it is an indexed term, return the congruent term
- if( !f.isNull() && watch_list_out.empty() ){
- std::vector< TNode > t_args;
- for( unsigned i=0; i<args.size(); i++ ) {
- t_args.push_back( args[i] );
- }
- Assert( args.size()==n.getNumChildren() );
- //args contains terms known by the equality engine
- TNode nn = getCongruentTerm( f, t_args );
- Trace("qip-eval") << " got congruent term " << nn << " from DB for " << n << std::endl;
- if( !nn.isNull() ){
- //successfully constructed representative in EE
- Assert( exp_n.empty() );
- ret = getRepresentativeExp( nn, exp_n );
- Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl;
- merge_exp( exp, exp_n );
- ret_set = true;
- Assert( !ret.isNull() );
+ //add remaining children if we aborted
+ if( abort_i!=-1 ){
+ Trace("qip-eval-debug") << "..." << n << " aborted at " << abort_i << std::endl;
+ for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){
+ args.push_back( n[i] );
}
}
+ //if we have not short-circuited evaluation
if( !ret_set ){
- if( childChanged ){
- Trace("qip-eval") << "return rewrite" << std::endl;
- if( ( k==kind::AND || k==kind::OR ) ){
- if( args.empty() ){
- ret = k==kind::AND ? d_true : d_false;
- ret_set = true;
- }else if( args.size()==1 ){
- ret = args[0];
- ret_set = true;
- }
+ //if it is an indexed term, return the congruent term
+ if( !f.isNull() && watch.empty() ){
+ std::vector< TNode > t_args;
+ for( unsigned i=0; i<args.size(); i++ ) {
+ Trace("qip-eval") << "arg " << i << " : " << args[i] << std::endl;
+ t_args.push_back( args[i] );
+ }
+ Assert( args.size()==n.getNumChildren() );
+ //args contains terms known by the equality engine
+ TNode nn = getCongruentTerm( f, t_args );
+ Trace("qip-eval") << " got congruent term " << nn << " for " << n << std::endl;
+ if( !nn.isNull() ){
+ //successfully constructed representative in EE
+ Assert( exp_n.empty() );
+ ret = getRepresentativeExp( nn, exp_n );
+ Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl;
+ merge_exp( exp, exp_n );
+ ret_set = true;
+ Assert( !ret.isNull() );
+ Assert( ret!=n );
+ // we have that n == ret, check if the union find should be updated TODO?
}else{
- Assert( args.size()==n.getNumChildren() );
+ watch.push_back( ret );
}
- if( !ret_set ){
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- args.insert( args.begin(), n.getOperator() );
+ }
+ if( !ret_set ){
+ if( childChanged || args.size()!=n.getNumChildren() ){
+ Trace("qip-eval") << "return rewrite" << std::endl;
+ if( k==kind::AND || k==kind::OR ){
+ if( args.empty() ){
+ ret = k==kind::AND ? d_true : d_false;
+ ret_set = true;
+ }else if( args.size()==1 ){
+ //need to re-evaluate (may be new propagations)
+ ret = evaluateTermExp( args[0], exp, visited, hasPol, pol, watch_list_out, props );
+ ret_set = true;
+ }
+ }else{
+ Assert( args.size()==n.getNumChildren() );
}
- ret = NodeManager::currentNM()->mkNode( k, args );
- ret = Rewriter::rewrite( ret );
- //re-evaluate
- Node ret_eval = getRepresentativeExp( ret, exp_n );
- if( !ret_eval.isNull() ){
- ret = ret_eval;
- watch_list_out.clear();
- }else{
- watch_list_out[ret] = true;
+ if( !ret_set ){
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ args.insert( args.begin(), n.getOperator() );
+ }
+ ret = NodeManager::currentNM()->mkNode( k, args );
+ setWatchList( ret, watch, watch_list_out );
+ ret = Rewriter::rewrite( ret );
+ //need to re-evaluate
+ ret = evaluateTermExp( ret, exp, visited, hasPol, pol, watch_list_out, props );
}
+ }else{
+ ret = n;
+ setWatchList( ret, watch, watch_list_out );
}
- }else{
- ret = n;
- watch_list_out[ret] = true;
}
}
}
+ }else{
+ Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;
+ merge_exp( exp, exp_n );
}
- }else{
- Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;
- merge_exp( exp, exp_n );
}
- Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl;
- visited[n] = ret;
+
+ Trace("qip-eval") << "evaluated term : " << n << " [" << polIndex << "], got : " << ret << ", exp size = " << exp.size() << ", watch list size = " << watch_list_out.size() << std::endl;
+ visited[polIndex][n] = ret;
return ret;
}
}
@@ -545,6 +610,7 @@ bool InstPropagator::reset( Theory::Effort e ) {
d_watch_list.clear();
d_update_list.clear();
d_relevant_inst.clear();
+ d_has_relevant_inst = false;
return d_qy.reset( e );
}
@@ -556,10 +622,7 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st
Trace("qip-prop") << " " << terms[i] << std::endl;
}
}
- unsigned id = d_icount;
- d_icount++;
- Trace("qip-prop") << "...assign id=" << id << std::endl;
- d_ii[id].init( q, lem, terms, body );
+ unsigned id = allocateInstantiation( q, lem, terms, body );
//initialize the information
if( cacheConclusion( id, body ) ){
Assert( d_update_list.empty() );
@@ -582,35 +645,67 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st
return !d_conflict;
}else{
Assert( false );
- return true;
+ return false;
+ }
+}
+
+void InstPropagator::filterInstantiations() {
+ if( d_has_relevant_inst ){
+ //now, inform quantifiers engine which instances should be retracted
+ Trace("qip-prop-debug") << "...remove instantiation ids : ";
+ for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){
+ if( !it->second.d_q.isNull() ){
+ if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){
+ if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){
+ Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl;
+ Assert( false );
+ }else{
+ Trace("qip-prop-debug") << it->first << " ";
+ }
+ }else{
+ //mark the quantified formula as relevant
+ d_qe->markRelevant( it->second.d_q );
+ }
+ }
+ }
+ Trace("qip-prop-debug") << std::endl;
+ Trace("quant-engine-conflict") << "-----> InstPropagator::" << ( d_conflict ? "conflict" : "propagate" ) << " with " << d_relevant_inst.size() << " instances." << std::endl;
}
}
+unsigned InstPropagator::allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body ) {
+ unsigned id = d_icount;
+ d_icount++;
+ Trace("qip-prop") << "...assign id=" << id << std::endl;
+ d_ii[id].init( q, lem, terms, body );
+ return id;
+}
+
bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
Assert( !d_conflict );
Assert( ii.d_active );
Trace("qip-prop-debug") << "Update info [" << id << "]..." << std::endl;
//update the evaluation of the current lemma
- std::map< Node, Node > visited;
- std::map< Node, bool > watch_list;
+ std::map< Node, std::vector< Node > > watch_list_out;
+ std::map< int, std::map< Node, Node > > visited;
+ std::vector< Node > exp;
std::vector< Node > props;
- Node eval = d_qy.evaluateTermExp( ii.d_curr, ii.d_curr_exp, visited, true, true, watch_list, props );
+ Node eval = d_qy.evaluateTermExp( ii.d_curr, exp, visited, true, true, watch_list_out, props );
+ EqualityQueryInstProp::merge_exp( ii.d_curr_exp, exp );
if( eval.isNull() ){
ii.d_active = false;
}else if( firstTime || eval!=ii.d_curr ){
- if( EqualityQueryInstProp::isLiteral( eval ) ){
- props.push_back( eval );
- eval = d_qy.d_true;
- watch_list.clear();
- }
+ std::vector< Node > watch_list;
+ d_qy.collectWatchList( eval, watch_list_out, watch_list );
if( Trace.isOn("qip-prop") ){
Trace("qip-prop") << "Update info [" << id << "]..." << std::endl;
- Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << ", exp = ";
+ Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << std::endl;
+ Trace("qip-prop") << "...explanation = ";
debugPrintExplanation( ii.d_curr_exp, "qip-prop" );
Trace("qip-prop") << std::endl;
Trace("qip-prop") << "...watch list: " << std::endl;
- for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw!=watch_list.end(); ++itw ){
- Trace("qip-prop") << " " << itw->first << std::endl;
+ for( unsigned i=0; i<watch_list.size(); i++ ){
+ Trace("qip-prop") << " " << watch_list[i] << std::endl;
}
Trace("qip-prop") << "...new propagations: " << std::endl;
for( unsigned i=0; i<props.size(); i++ ){
@@ -627,8 +722,13 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
}else{
for( unsigned i=0; i<props.size(); i++ ){
Trace("qip-prop-debug2") << "Process propagation " << props[i] << std::endl;
+ Assert( d_qy.isPropagateLiteral( props[i] ) );
//if we haven't propagated this literal yet
if( cacheConclusion( id, props[i], 1 ) ){
+ //watch list for propagated literal: may not yet be purely EE representatives
+ std::vector< Node > prop_watch_list;
+ d_qy.collectWatchList( props[i], watch_list_out, prop_watch_list );
+
Node lit = props[i].getKind()==NOT ? props[i][0] : props[i];
bool pol = props[i].getKind()!=NOT;
if( lit.getKind()==EQUAL ){
@@ -647,10 +747,10 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {
ii.d_curr = eval;
//update the watch list
Trace("qip-prop-debug") << "...updating watch list for [" << id << "], curr is " << ii.d_curr << std::endl;
- //Here, we need to be notified of enough terms such that if we are not notified, then update( ii ) will return no propagations.
- // Similar to two-watched literals, but since we are in UF, we need to watch all terms on a complete path of two terms.
- for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw != watch_list.end(); ++itw ){
- d_watch_list[ itw->first ][ id ] = true;
+ //Here, we need to be notified of enough terms such that if we are not notified, then update( id, ii ) will return no propagations.
+ // Similar to two-watched literals, but since we are taking into account UF, we need to watch all terms on a complete path of two terms.
+ for( unsigned i=0; i<watch_list.size(); i++ ){
+ d_watch_list[ watch_list[i] ][ id ] = true;
}
}else{
Trace("qip-prop-debug") << "...conclusion " << eval << " is duplicate." << std::endl;
@@ -682,10 +782,12 @@ void InstPropagator::propagate( Node a, Node b, bool pol, std::vector< Node >& e
}
if( pol ){
if( status==EqualityQueryInstProp::STATUS_MERGED_KNOWN ){
+ Trace("qip-rlv-propagate") << "Relevant propagation : " << a << ( pol ? " == " : " != " ) << b << std::endl;
Assert( d_qy.getEngine()->hasTerm( a ) );
Assert( d_qy.getEngine()->hasTerm( b ) );
Trace("qip-prop-debug") << "...equality between known terms." << std::endl;
addRelevantInstances( exp, "qip-propagate" );
+ //d_has_relevant_inst = true;
}
Trace("qip-prop-debug") << "...merged representatives " << a << " and " << b << std::endl;
for( unsigned i=0; i<2; i++ ){
@@ -712,25 +814,7 @@ void InstPropagator::conflict( std::vector< Node >& exp ) {
d_conflict = true;
d_relevant_inst.clear();
addRelevantInstances( exp, "qip-propagate" );
-
- //now, inform quantifiers engine which instances should be retracted
- Trace("qip-prop-debug") << "...remove instantiation ids : ";
- for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){
- if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){
- if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){
- Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl;
- Assert( false );
- }else{
- Trace("qip-prop-debug") << it->first << " ";
- }
- }else{
- //mark the quantified formula as relevant
- d_qe->markRelevant( it->second.d_q );
- }
- }
- Trace("qip-prop-debug") << std::endl;
- //will interupt the quantifiers engine
- Trace("quant-engine-conflict") << "-----> InstPropagator::conflict with " << exp.size() << " instances." << std::endl;
+ d_has_relevant_inst = true;
}
bool InstPropagator::cacheConclusion( unsigned id, Node body, int prop_index ) {
diff --git a/src/theory/quantifiers/inst_propagator.h b/src/theory/quantifiers/inst_propagator.h
index 0c02c7f95..6201cf152 100644..100755
--- a/src/theory/quantifiers/inst_propagator.h
+++ b/src/theory/quantifiers/inst_propagator.h
@@ -64,9 +64,11 @@ public:
bool areEqualExp( Node a, Node b, std::vector< Node >& exp );
/** returns true is a and b are disequal in the current context */
bool areDisequalExp( Node a, Node b, std::vector< Node >& exp );
+ /** get congruent term */
+ TNode getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp );
private:
/** term index */
- std::map< Node, TermArgTrie > d_func_map_trie;
+ std::map< Node, TermArgTrie > d_uf_func_map_trie;
/** union find for terms beyond what is stored in equality engine */
std::map< Node, Node > d_uf;
std::map< Node, std::vector< Node > > d_uf_exp;
@@ -74,7 +76,9 @@ private:
/** disequality list, stores explanations */
std::map< Node, std::map< Node, std::vector< Node > > > d_diseq_list;
/** add arg */
- void addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol );
+ void addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch );
+ /** register term */
+ void registerUfTerm( TNode n );
public:
enum {
STATUS_CONFLICT,
@@ -89,10 +93,13 @@ public:
public:
//for explanations
static void merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size = -1 );
+ //for watch list
+ static void setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out );
+ static void collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list );
- Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol,
- std::map< Node, bool >& watch_list_out, std::vector< Node >& props );
- static bool isLiteral( Node n );
+ Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited,
+ bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props );
+ bool isPropagateLiteral( Node n );
};
class InstPropagator : public QuantifiersUtil {
@@ -104,13 +111,18 @@ private:
InstPropagator& d_ip;
public:
InstantiationNotifyInstPropagator(InstPropagator& ip): d_ip(ip) {}
- virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) {
- return d_ip.notifyInstantiation( quant_e, q, lem, terms, body );
+ virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) {
+ return d_ip.notifyInstantiation( quant_e, q, lem, terms, body );
}
+ virtual void filterInstantiations() { d_ip.filterInstantiations(); }
};
InstantiationNotifyInstPropagator d_notify;
/** notify instantiation method */
bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body );
+ /** remove instance ids */
+ void filterInstantiations();
+ /** allocate instantiation */
+ unsigned allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body );
/** equality query */
EqualityQueryInstProp d_qy;
class InstInfo {
@@ -137,13 +149,13 @@ private:
std::vector< unsigned > d_update_list;
/** relevant instances */
std::map< unsigned, bool > d_relevant_inst;
+ bool d_has_relevant_inst;
private:
bool update( unsigned id, InstInfo& i, bool firstTime = false );
void propagate( Node a, Node b, bool pol, std::vector< Node >& exp );
void conflict( std::vector< Node >& exp );
bool cacheConclusion( unsigned id, Node body, int prop_index = 0 );
void addRelevantInstances( std::vector< Node >& exp, const char * c );
-
void debugPrintExplanation( std::vector< Node >& exp, const char * c );
public:
InstPropagator( QuantifiersEngine* qe );
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index 149330c61..523d868b5 100644..100755
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -190,7 +190,7 @@ bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visit
bool InstStrategyCbqi::hasNonCbqiVariable( Node q ){
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
TypeNode tn = q[0][i].getType();
- if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() ){
+ if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() && !tn.isBitVector() ){
if( options::cbqiSplx() ){
return true;
}else{
@@ -242,7 +242,7 @@ Node InstStrategyCbqi::getNextDecisionRequest(){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q );
bool value;
if( !d_quantEngine->getValuation().hasSatValue( cel, value ) ){
- Trace("cbqi-debug2") << "CBQI: get next decision " << cel << std::endl;
+ Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl;
return cel;
}
}
@@ -692,8 +692,10 @@ CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
void InstStrategyCegqi::registerQuantifier( Node q ) {
if( options::cbqiPreRegInst() ){
- //just get the instantiator
- getInstantiator( q );
+ if( doCbqi( q ) ){
+ //just get the instantiator
+ getInstantiator( q );
+ }
}
}
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
index 8ed59778b..8ed59778b 100644..100755
--- a/src/theory/quantifiers/inst_strategy_cbqi.h
+++ b/src/theory/quantifiers/inst_strategy_cbqi.h
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 630880690..efd765c86 100644..100755
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -34,9 +34,10 @@ using namespace CVC4::theory::quantifiers;
struct sortQuantifiersForSymbol {
QuantifiersEngine* d_qe;
+ std::map< Node, Node > d_op_map;
bool operator() (Node i, Node j) {
- int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() );
- int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() );
+ int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[i] );
+ int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[j] );
if( nqfsi<nqfsj ){
return true;
}else if( nqfsi>nqfsj ){
@@ -83,9 +84,8 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl;
if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
- int matchOption = 0;
for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){
- Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL );
+ Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], true, Trigger::TR_RETURN_NULL );
if( t ){
d_user_gen[f].push_back( t );
}
@@ -134,11 +134,10 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){
if( usable ){
Trace("user-pat") << "Add user pattern: " << pat << " for " << q << std::endl;
//check match option
- int matchOption = 0;
if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
d_user_gen_wait[q].push_back( nodes );
}else{
- Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, matchOption, true, Trigger::TR_MAKE_NEW );
+ Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, true, Trigger::TR_MAKE_NEW );
if( t ){
d_user_gen[q].push_back( t );
}else{
@@ -279,8 +278,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
for( unsigned i=0; i<patTermsF.size(); i++ ){
Assert( tinfo.find( patTermsF[i] )!=tinfo.end() );
- Trace("auto-gen-trigger-debug") << " " << patTermsF[i];
- Trace("auto-gen-trigger-debug") << " info[" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
+ Trace("auto-gen-trigger-debug") << " " << patTermsF[i] << std::endl;
+ Trace("auto-gen-trigger-debug2") << " info = [" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
}
Trace("auto-gen-trigger-debug") << std::endl;
}
@@ -306,10 +305,28 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
last_weight = curr_w;
}
}
+ d_num_trigger_vars[f] = vcMap.size();
+ if( d_num_trigger_vars[f]>0 && d_num_trigger_vars[f]<f[0].getNumChildren() ){
+ Trace("auto-gen-trigger-partial") << "Quantified formula : " << f << std::endl;
+ Trace("auto-gen-trigger-partial") << "...does not contain all variables in triggers!!!" << std::endl;
+ if( options::partialTriggers() ){
+ std::vector< Node > vcs[2];
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
+ vcs[ vcMap.find( ic )==vcMap.end() ? 0 : 1 ].push_back( f[0][i] );
+ }
+ for( unsigned i=0; i<2; i++ ){
+ d_vc_partition[i][f] = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, vcs[i] );
+ }
+ }else{
+ return;
+ }
+ }
for( unsigned i=0; i<patTermsF.size(); i++ ){
Node pat = patTermsF[i];
if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){
Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl;
+ Node mpat = pat;
//process the pattern: if it has a required polarity, consider it
Assert( tinfo.find( pat )!=tinfo.end() );
int rpol = tinfo[pat].d_reqPol;
@@ -317,19 +334,30 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
unsigned num_fv = tinfo[pat].d_fv.size();
Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl;
if( rpol!=0 ){
+ Assert( rpol==1 || rpol==-1 );
if( Trigger::isRelationalTrigger( pat ) ){
pat = rpol==-1 ? pat.negate() : pat;
}else{
Assert( Trigger::isAtomicTrigger( pat ) );
if( pat.getType().isBoolean() && rpoleq.isNull() ){
- pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
+ if( options::literalMatchMode()==LITERAL_MATCH_USE ){
+ pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
+ }else if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+ pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==1 ) );
+ }
}else{
Assert( !rpoleq.isNull() );
if( rpol==-1 ){
- //all equivalence classes except rpoleq
- pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
+ if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+ //all equivalence classes except rpoleq
+ pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
+ }
}else if( rpol==1 ){
- //all equivalence classes that are not disequal to rpoleq TODO
+ if( options::literalMatchMode()==LITERAL_MATCH_AGG ){
+ //only equivalence class rpoleq
+ pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq );
+ }
+ //all equivalence classes that are not disequal to rpoleq TODO?
}
}
}
@@ -337,10 +365,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}else{
if( Trigger::isRelationalTrigger( pat ) ){
//consider both polarities
- addPatternToPool( f, pat.negate(), num_fv );
+ addPatternToPool( f, pat.negate(), num_fv, mpat );
}
}
- addPatternToPool( f, pat, num_fv );
+ addPatternToPool( f, pat, num_fv, mpat );
}
}
//tinfo not used below this point
@@ -372,19 +400,23 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
if( options::relevantTriggers() ){
sortQuantifiersForSymbol sqfs;
sqfs.d_qe = d_quantEngine;
+ for( unsigned i=0; i<patTerms.size(); i++ ){
+ Assert( d_pat_to_mpat.find( patTerms[i] )!=d_pat_to_mpat.end() );
+ Assert( d_pat_to_mpat[patTerms[i]].hasOperator() );
+ sqfs.d_op_map[ patTerms[i] ] = d_pat_to_mpat[patTerms[i]].getOperator();
+ }
//sort based on # occurrences (this will cause Trigger to select rarer symbols)
std::sort( patTerms.begin(), patTerms.end(), sqfs );
Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
for( unsigned i=0; i<patTerms.size(); i++ ){
- Debug("relevant-trigger") << " " << patTerms[i] << " (";
- Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
+ Debug("relevant-trigger") << " " << patTerms[i] << " from " << d_pat_to_mpat[patTerms[i]] << " (";
+ Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_pat_to_mpat[patTerms[i]].getOperator() ) << ")" << std::endl;
}
}
//now, generate the trigger...
- int matchOption = 0;
Trigger* tr = NULL;
if( d_is_single_trigger[ patTerms[0] ] ){
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL );
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
d_single_trigger_gen[ patTerms[0] ] = true;
}else{
//only generate multi trigger if option set, or if no single triggers exist
@@ -402,29 +434,14 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
d_made_multi_trigger[f] = true;
}
//will possibly want to get an old trigger
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD );
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, false, Trigger::TR_GET_OLD, d_num_trigger_vars[f] );
}
if( tr ){
- unsigned tindex;
- if( tr->isMultiTrigger() ){
- //disable all other multi triggers
- for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][f].begin(); it != d_auto_gen_trigger[1][f].end(); ++it ){
- d_auto_gen_trigger[1][f][ it->first ] = false;
- }
- tindex = 1;
- }else{
- tindex = 0;
- }
- //making it during an instantiation round, so must reset
- if( d_auto_gen_trigger[tindex][f].find( tr )==d_auto_gen_trigger[tindex][f].end() ){
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- }
- d_auto_gen_trigger[tindex][f][tr] = true;
+ addTrigger( tr, f );
//if we are generating additional triggers...
- if( tindex==0 ){
- int index = 0;
- if( index<(int)patTerms.size() ){
+ if( !tr->isMultiTrigger() ){
+ unsigned index = 0;
+ if( index<patTerms.size() ){
//Notice() << "check add additional" << std::endl;
//check if similar patterns exist, and if so, add them additionally
int nqfs_curr = 0;
@@ -433,18 +450,13 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}
index++;
bool success = true;
- while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
+ while( success && index<patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
success = false;
if( !options::relevantTriggers() ||
d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
d_single_trigger_gen[ patTerms[index] ] = true;
- Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL );
- if( tr2 ){
- //Notice() << "Add additional trigger " << patTerms[index] << std::endl;
- tr2->resetInstantiationRound();
- tr2->reset( Node::null() );
- d_auto_gen_trigger[0][f][tr2] = true;
- }
+ Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
+ addTrigger( tr2, f );
success = true;
}
index++;
@@ -457,8 +469,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
}
}
-void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv ) {
- if( num_fv==q[0].getNumChildren() && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
+void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
+ d_pat_to_mpat[pat] = mpat;
+ unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
+ if( num_fv==num_vars && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
d_patTerms[0][q].push_back( pat );
d_is_single_trigger[ pat ] = true;
}else{
@@ -467,6 +481,38 @@ void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned n
}
}
+
+void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
+ if( tr ){
+ if( d_num_trigger_vars[q]<q[0].getNumChildren() ){
+ //partial trigger : generate implication to mark user pattern
+ Node ipl = NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, d_quantEngine->getTermDatabase()->getVariableNode( tr->getInstPattern(), q ) );
+ Node qq = NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[1][q], NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[0][q], q[1] ), ipl );
+ Trace("auto-gen-trigger-partial") << "Make partially specified user pattern: " << std::endl;
+ Trace("auto-gen-trigger-partial") << " " << qq << std::endl;
+ Node lem = NodeManager::currentNM()->mkNode( OR, q.negate(), qq );
+ d_quantEngine->addLemma( lem );
+ }else{
+ unsigned tindex;
+ if( tr->isMultiTrigger() ){
+ //disable all other multi triggers
+ for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][q].begin(); it != d_auto_gen_trigger[1][q].end(); ++it ){
+ d_auto_gen_trigger[1][q][ it->first ] = false;
+ }
+ tindex = 1;
+ }else{
+ tindex = 0;
+ }
+ //making it during an instantiation round, so must reset
+ if( d_auto_gen_trigger[tindex][q].find( tr )==d_auto_gen_trigger[tindex][q].end() ){
+ tr->resetInstantiationRound();
+ tr->reset( Node::null() );
+ }
+ d_auto_gen_trigger[tindex][q][tr] = true;
+ }
+ }
+}
+
bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
if( q.getNumChildren()==3 ){
std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q );
@@ -519,8 +565,7 @@ bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) {
Trace("local-t-ext") << " " << patTerms[i] << std::endl;
}
Trace("local-t-ext") << std::endl;
- int matchOption = 0;
- Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, true, Trigger::TR_GET_OLD );
+ Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, true, Trigger::TR_GET_OLD );
d_lte_trigger[f] = tr;
}else{
Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl;
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h
index 028f24b27..e6d993294 100644..100755
--- a/src/theory/quantifiers/inst_strategy_e_matching.h
+++ b/src/theory/quantifiers/inst_strategy_e_matching.h
@@ -83,14 +83,18 @@ private:
std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
//instantiation no patterns
std::map< Node, std::vector< Node > > d_user_no_gen;
+ // number of trigger variables per quantifier
+ std::map< Node, unsigned > d_num_trigger_vars;
+ std::map< Node, Node > d_vc_partition[2];
+ std::map< Node, Node > d_pat_to_mpat;
private:
/** process functions */
void processResetInstantiationRound( Theory::Effort effort );
int process( Node q, Theory::Effort effort, int e );
/** generate triggers */
void generateTriggers( Node q );
- void addPatternToPool( Node q, Node pat, unsigned num_fv );
- //bool addTrigger( inst::Trigger * tr, Node f, unsigned r );
+ void addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat );
+ void addTrigger( inst::Trigger * tr, Node f );
/** has user patterns */
bool hasUserPatterns( Node q );
/** has user patterns */
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 955dc5d86..db597d031 100644..100755
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -137,11 +137,7 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){
doInstantiationRound( e );
if( d_quantEngine->inConflict() ){
Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting );
- Trace("inst-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound();
- if( lastWaiting>0 ){
- Trace("inst-engine") << " (prev " << lastWaiting << ")";
- }
- Trace("inst-engine") << std::endl;
+ Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
}else if( d_quantEngine->hasAddedLemma() ){
Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
}
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
index d2b3740a1..d2b3740a1 100644..100755
--- a/src/theory/quantifiers/instantiation_engine.h
+++ b/src/theory/quantifiers/instantiation_engine.h
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
index b03c4ad3b..b03c4ad3b 100644..100755
--- a/src/theory/quantifiers/kinds
+++ b/src/theory/quantifiers/kinds
diff --git a/src/theory/quantifiers/local_theory_ext.cpp b/src/theory/quantifiers/local_theory_ext.cpp
index ada28c084..ada28c084 100644..100755
--- a/src/theory/quantifiers/local_theory_ext.cpp
+++ b/src/theory/quantifiers/local_theory_ext.cpp
diff --git a/src/theory/quantifiers/local_theory_ext.h b/src/theory/quantifiers/local_theory_ext.h
index 94abf3c90..94abf3c90 100644..100755
--- a/src/theory/quantifiers/local_theory_ext.h
+++ b/src/theory/quantifiers/local_theory_ext.h
diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp
index 582599680..582599680 100644..100755
--- a/src/theory/quantifiers/macros.cpp
+++ b/src/theory/quantifiers/macros.cpp
diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h
index 39ec2f0a1..39ec2f0a1 100644..100755
--- a/src/theory/quantifiers/macros.h
+++ b/src/theory/quantifiers/macros.h
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 3ae36b1d4..10a5ae41b 100644..100755
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -66,7 +66,7 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){
tests++;
std::vector< Node > terms;
for( int k=0; k<riter.getNumTerms(); k++ ){
- terms.push_back( riter.getTerm( k ) );
+ terms.push_back( riter.getCurrentTerm( k ) );
}
Node n = d_qe->getInstantiation( f, vars, terms );
Node val = fm->getValue( n );
@@ -84,7 +84,9 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){
}
Trace("quant-check-model") << "." << std::endl;
}else{
- Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
+ if( riter.isIncomplete() ){
+ Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
+ }
}
}
}
@@ -114,7 +116,7 @@ bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
QModelBuilderIG::QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ) {
+QModelBuilder( c, qe ), d_basisNoMatch( c ) {
}
@@ -302,7 +304,7 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
Node n = fmig->d_uf_terms[op][i];
//for calculating if op is constant
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) ){
Node v = fmig->getRepresentative( n );
if( i==0 ){
d_uf_prefs[op].d_const_val = v;
@@ -312,12 +314,11 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
}
}
//for calculating terms that we don't need to consider
- if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
- if( !n.getAttribute(BasisNoMatchAttribute()) ){
+ if( d_qe->getTermDatabase()->isTermActive( n ) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
+ if( d_basisNoMatch.find( n )==d_basisNoMatch.end() ){
//need to consider if it is not congruent modulo model basis
if( !tabt.addTerm( fmig, n ) ){
- BasisNoMatchAttribute bnma;
- n.setAttribute(bnma,true);
+ d_basisNoMatch[n] = true;
}
}
}
@@ -382,8 +383,8 @@ bool QModelBuilderIG::isQuantifierActive( Node f ){
}
bool QModelBuilderIG::isTermActive( Node n ){
- return !n.getAttribute(NoMatchAttribute()) || //it is not congruent to another active term
- ( n.getAttribute(ModelBasisArgAttribute())!=0 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
+ return d_qe->getTermDatabase()->isTermActive( n ) || //it is not congruent to another active term
+ ( n.getAttribute(ModelBasisArgAttribute())!=0 && d_basisNoMatch.find( n )==d_basisNoMatch.end() ); //or it has model basis arguments
//and is not congruent modulo model basis
//to another active term
}
@@ -400,15 +401,19 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
d_triedLemmas++;
- for( int i=0; i<(int)riter.d_index.size(); i++ ){
- Trace("try") << i << " : " << riter.d_index[i] << " : " << riter.getTerm( i ) << std::endl;
+ if( Debug.isOn("inst-fmf-ei-debug") ){
+ for( int i=0; i<(int)riter.d_index.size(); i++ ){
+ Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl;
+ }
}
int eval = 0;
int depIndex;
//see if instantiation is already true in current model
- Debug("fmf-model-eval") << "Evaluating ";
- riter.debugPrintSmall("fmf-model-eval");
- Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ if( Debug.isOn("fmf-model-eval") ){
+ Debug("fmf-model-eval") << "Evaluating ";
+ riter.debugPrintSmall("fmf-model-eval");
+ Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ }
//if evaluate(...)==1, then the instantiation is already true in the model
// depIndex is the index of the least significant variable that this evaluation relies upon
depIndex = riter.getNumTerms()-1;
@@ -426,7 +431,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
//instantiation was not shown to be true, construct the match
InstMatch m( f );
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_qe, riter.d_index_order[i], riter.getTerm( i ) );
+ m.set( d_qe, i, riter.getCurrentTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
//add as instantiation
@@ -464,8 +469,8 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
Trace("model-engine-warn") << std::endl;
}
}
- //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
- d_incomplete_check = riter.d_incomplete;
+ //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+ d_incomplete_check = riter.isIncomplete();
return true;
}else{
return false;
@@ -667,7 +672,7 @@ int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
//if applicable, try to add exceptions here
if( !tr_terms.empty() ){
//make a trigger for these terms, add instantiations
- inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW );
+ inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW );
//Notice() << "Trigger = " << (*tr) << std::endl;
tr->resetInstantiationRound();
tr->reset( Node::null() );
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
index 906673903..e4f9529a8 100644..100755
--- a/src/theory/quantifiers/model_builder.h
+++ b/src/theory/quantifiers/model_builder.h
@@ -57,15 +57,6 @@ public:
-/** Attribute true for nodes that should not be used when considered for inst-gen basis */
-struct BasisNoMatchAttributeId {};
-/** use the special for boolean flag */
-typedef expr::Attribute< BasisNoMatchAttributeId,
- bool,
- expr::attr::NullCleanupStrategy,
- true // context dependent
- > BasisNoMatchAttribute;
-
class TermArgBasisTrie {
private:
bool addTerm2( FirstOrderModel* fm, Node n, int argIndex );
@@ -85,7 +76,9 @@ public:
*/
class QModelBuilderIG : public QModelBuilder
{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
protected:
+ BoolMap d_basisNoMatch;
//map from operators to model preference data
std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
//built model uf
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index 0bbca88eb..5d575969f 100644..100755
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -153,27 +153,23 @@ int ModelEngine::checkModel(){
//d_quantEngine->getEqualityQuery()->flattenRepresentatives( fm->d_rep_set.d_type_reps );
//for debugging
- if( Trace.isOn("model-engine") || Trace.isOn("model-engine-debug") ){
- for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
- it != fm->d_rep_set.d_type_reps.end(); ++it ){
- if( it->first.isSort() ){
- Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
- if( Trace.isOn("model-engine-debug") ){
- Trace("model-engine-debug") << " Reps : ";
- for( size_t i=0; i<it->second.size(); i++ ){
- Trace("model-engine-debug") << it->second[i] << " ";
- }
- Trace("model-engine-debug") << std::endl;
- Trace("model-engine-debug") << " Term reps : ";
- for( size_t i=0; i<it->second.size(); i++ ){
- Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
- Trace("model-engine-debug") << r << " ";
- }
- Trace("model-engine-debug") << std::endl;
- Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
- Trace("model-engine-debug") << " Basis term : " << mbt << std::endl;
- }
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
+ it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+ Trace("model-engine-debug") << " Reps : ";
+ for( size_t i=0; i<it->second.size(); i++ ){
+ Trace("model-engine-debug") << it->second[i] << " ";
}
+ Trace("model-engine-debug") << std::endl;
+ Trace("model-engine-debug") << " Term reps : ";
+ for( size_t i=0; i<it->second.size(); i++ ){
+ Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
+ Trace("model-engine-debug") << r << " ";
+ }
+ Trace("model-engine-debug") << std::endl;
+ Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
+ Trace("model-engine-debug") << " Basis term : " << mbt << std::endl;
}
}
@@ -221,11 +217,12 @@ int ModelEngine::checkModel(){
//print debug information
if( d_quantEngine->inConflict() ){
- Trace("model-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound() << std::endl;
+ Trace("model-engine") << "Conflict, added lemmas = ";
}else{
- Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
- Trace("model-engine") << d_totalLemmas << std::endl;
- }
+ Trace("model-engine") << "Added Lemmas = ";
+ }
+ Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / ";
+ Trace("model-engine") << d_totalLemmas << std::endl;
return d_addedLemmas;
}
@@ -281,15 +278,15 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
//create a rep set iterator and iterate over the (relevant) domain of the quantifier
RepSetIterator riter( d_quantEngine, &(d_quantEngine->getModel()->d_rep_set) );
if( riter.setQuantifier( f ) ){
- Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.d_incomplete << "..." << std::endl;
- if( !riter.d_incomplete ){
+ Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
+ if( !riter.isIncomplete() ){
int triedLemmas = 0;
int addedLemmas = 0;
while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
//instantiation was not shown to be true, construct the match
InstMatch m( f );
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_quantEngine, riter.d_index_order[i], riter.getTerm( i ) );
+ m.set( d_quantEngine, i, riter.getCurrentTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
@@ -309,11 +306,10 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
d_statistics.d_exh_inst_lemmas += addedLemmas;
}
}else{
- Trace("fmf-exh-inst") << "...exhaustive instantiation failed to set, incomplete=" << riter.d_incomplete << "..." << std::endl;
- Assert( riter.d_incomplete );
+ Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
}
//if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
- d_incomplete_check = d_incomplete_check || riter.d_incomplete;
+ d_incomplete_check = d_incomplete_check || riter.isIncomplete();
}
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 12f18aa08..12f18aa08 100644..100755
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index ca87a607d..bac2aa35c 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -49,6 +49,7 @@ QuantInfo::~QuantInfo() {
void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
d_q = q;
+ d_extra_var.clear();
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
d_match.push_back( TNode::null() );
d_match_term.push_back( TNode::null() );
@@ -77,33 +78,31 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
}
}
*/
- if( d_mg->isValid() ){
- for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- if( d_vars[j].getKind()!=BOUND_VARIABLE ){
- d_var_mg[j] = NULL;
- bool is_tsym = false;
- if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
- is_tsym = true;
- d_tsym_vars.push_back( j );
- }
- if( !is_tsym || options::qcfTConstraint() ){
- d_var_mg[j] = new MatchGen( this, d_vars[j], true );
- }
- if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
- Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
- d_mg->setInvalid();
- break;
- }else{
- std::vector< int > bvars;
- d_var_mg[j]->determineVariableOrder( this, bvars );
- }
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){
+ d_var_mg[j] = NULL;
+ bool is_tsym = false;
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
+ is_tsym = true;
+ d_tsym_vars.push_back( j );
+ }
+ if( !is_tsym || options::qcfTConstraint() ){
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );
+ }
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
+ d_mg->setInvalid();
+ break;
+ }else{
+ std::vector< int > bvars;
+ d_var_mg[j]->determineVariableOrder( this, bvars );
}
- }
- if( d_mg->isValid() ){
- std::vector< int > bvars;
- d_mg->determineVariableOrder( this, bvars );
}
}
+ if( d_mg->isValid() ){
+ std::vector< int > bvars;
+ d_mg->determineVariableOrder( this, bvars );
+ }
}else{
Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
}
@@ -113,14 +112,15 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
//optimization : record variable argument positions for terms that must be matched
std::vector< TNode > vars;
//TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137)
- //if( options::qcfSkipRd() ){
- // for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- // vars.push_back( d_vars[j] );
- // }
- //}
- //get all variables that are always relevant
- std::map< TNode, bool > visited;
- getPropagateVars( vars, q[1], false, visited );
+ if( options::qcfSkipRd() ){
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ vars.push_back( d_vars[j] );
+ }
+ }else{
+ //get all variables that are always relevant
+ std::map< TNode, bool > visited;
+ getPropagateVars( p, vars, q[1], false, visited );
+ }
for( unsigned j=0; j<vars.size(); j++ ){
Node v = vars[j];
TNode f = p->getTermDatabase()->getMatchOperator( v );
@@ -141,7 +141,7 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) {
}
}
-void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){
+void QuantInfo::getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){
std::map< TNode, bool >::iterator itv = visited.find( n );
if( itv==visited.end() ){
visited[n] = true;
@@ -150,6 +150,12 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol,
if( d_var_num.find( n )!=d_var_num.end() ){
Assert( std::find( vars.begin(), vars.end(), n )==vars.end() );
vars.push_back( n );
+ TNode f = p->getTermDatabase()->getMatchOperator( n );
+ if( !f.isNull() ){
+ if( std::find( p->d_func_rel_dom[f].begin(), p->d_func_rel_dom[f].end(), d_q )==p->d_func_rel_dom[f].end() ){
+ p->d_func_rel_dom[f].push_back( d_q );
+ }
+ }
}else if( MatchGen::isHandledBoolConnective( n ) ){
Assert( n.getKind()!=IMPLIES );
QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol );
@@ -157,12 +163,16 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol,
Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl;
if( rec ){
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- getPropagateVars( vars, n[i], pol, visited );
+ getPropagateVars( p, vars, n[i], pol, visited );
}
}
}
}
+bool QuantInfo::isBaseMatchComplete() {
+ return d_vars_set.size()==(d_q[0].getNumChildren()+d_extra_var.size());
+}
+
void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
if( n.getKind()==FORALL ){
@@ -209,7 +219,6 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
if( n.getKind()==BOUND_VARIABLE ){
d_inMatchConstraint[n] = true;
}
- //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
if( d_var_num.find( n )==d_var_num.end() ){
Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
d_var_num[n] = d_vars.size();
@@ -219,6 +228,8 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
d_match_term.push_back( TNode::null() );
if( n.getKind()==ITE ){
registerNode( n, false, false );
+ }else if( n.getKind()==BOUND_VARIABLE ){
+ d_extra_var.push_back( n );
}else{
for( unsigned i=0; i<n.getNumChildren(); i++ ){
flatten( n[i], beneathQuant );
@@ -233,13 +244,15 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) {
}
-void QuantInfo::reset_round( QuantConflictFind * p ) {
+bool QuantInfo::reset_round( QuantConflictFind * p ) {
for( unsigned i=0; i<d_match.size(); i++ ){
d_match[i] = TNode::null();
d_match_term[i] = TNode::null();
}
+ d_vars_set.clear();
d_curr_var_deq.clear();
d_tconstraints.clear();
+
//add built-in variable constraints
for( unsigned r=0; r<2; r++ ){
for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
@@ -257,7 +270,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) {
d_mg->d_children.clear();
d_mg->d_n = NodeManager::currentNM()->mkConst( true );
d_mg->d_type = MatchGen::typ_ground;
- return;
+ return false;
}
}
}
@@ -268,6 +281,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) {
}
//now, reset for matching
d_mg->reset( p, false, this );
+ return true;
}
int QuantInfo::getCurrentRepVar( int v ) {
@@ -377,11 +391,12 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo
}
}
}
- d_match[v] = TNode::null();
+ unsetMatch( p, v );
return 1;
}else{
//std::map< int, TNode >::iterator itm = d_match.find( v );
bool isGroundRep = false;
+ bool isGround = false;
if( vn!=-1 ){
Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
//std::map< int, TNode >::iterator itmn = d_match.find( vn );
@@ -428,13 +443,14 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo
Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
if( d_match[v].isNull() ){
//isGroundRep = true; ??
+ isGround = true;
}else{
//compare ground values
Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
}
}
- if( setMatch( p, v, n, isGroundRep ) ){
+ if( setMatch( p, v, n, isGroundRep, isGround ) ){
Debug("qcf-match-debug") << " -> success" << std::endl;
return 1;
}else{
@@ -500,7 +516,7 @@ bool QuantInfo::isConstrainedVar( int v ) {
}
}
-bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ) {
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ) {
if( getCurrentCanBeEqual( p, v, n ) ){
if( isGroundRep ){
//fail if n does not exist in the relevant domain of each of the argument positions
@@ -518,6 +534,12 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe
}
}
Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ if( isGround ){
+ if( d_vars[v].getKind()==BOUND_VARIABLE ){
+ d_vars_set[v] = true;
+ Debug("qcf-match-debug") << "---- now bound " << d_vars_set.size() << " / " << d_q[0].getNumChildren() << " base variables." << std::endl;
+ }
+ }
d_match[v] = n;
return true;
}else{
@@ -525,6 +547,14 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe
}
}
+void QuantInfo::unsetMatch( QuantConflictFind * p, int v ) {
+ Debug("qcf-match-debug") << "-- unbind : " << v << std::endl;
+ if( d_vars[v].getKind()==BOUND_VARIABLE && d_vars_set.find( v )!=d_vars_set.end() ){
+ d_vars_set.erase( v );
+ }
+ d_match[ v ] = TNode::null();
+}
+
bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
for( int i=0; i<getNumVars(); i++ ){
//std::map< int, TNode >::iterator it = d_match.find( i );
@@ -538,6 +568,42 @@ bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
}
bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
+ if( options::qcfEagerTest() ){
+ //check whether the instantiation evaluates as expected
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ Trace("qcf-instance-check") << "Possible conflict instance for " << d_q << " : " << std::endl;
+ std::map< TNode, TNode > subs;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ Trace("qcf-instance-check") << " " << terms[i] << std::endl;
+ subs[d_q[0][i]] = terms[i];
+ }
+ for( unsigned i=0; i<d_extra_var.size(); i++ ){
+ Node n = getCurrentExpValue( d_extra_var[i] );
+ Trace("qcf-instance-check") << " " << d_extra_var[i] << " -> " << n << std::endl;
+ subs[d_extra_var[i]] = n;
+ }
+ if( !p->getTermDatabase()->isEntailed( d_q[1], subs, false, false ) ){
+ Trace("qcf-instance-check") << "...not entailed to be false." << std::endl;
+ return true;
+ }
+ }else{
+ Node inst = p->d_quantEngine->getInstantiation( d_q, terms );
+ Node inst_eval = p->getTermDatabase()->evaluateTerm( inst, NULL, options::qcfTConstraint() );
+ if( Trace.isOn("qcf-instance-check") ){
+ Trace("qcf-instance-check") << "Possible propagating instance for " << d_q << " : " << std::endl;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ Trace("qcf-instance-check") << " " << terms[i] << std::endl;
+ }
+ Trace("qcf-instance-check") << "...evaluates to " << inst_eval << std::endl;
+ }
+ if( inst_eval.isNull() || inst_eval==p->getTermDatabase()->d_true || !isPropagatingInstance( p, inst_eval ) ){
+ Trace("qcf-instance-check") << "...spurious." << std::endl;
+ return true;
+ }else{
+ Trace("qcf-instance-check") << "...not spurious." << std::endl;
+ }
+ }
+ }
if( !d_tconstraints.empty() ){
//check constraints
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
@@ -552,6 +618,26 @@ bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node
return false;
}
+bool QuantInfo::isPropagatingInstance( QuantConflictFind * p, Node n ) {
+ if( n.getKind()==FORALL ){
+ //TODO?
+ return true;
+ }else if( n.getKind()==NOT || n.getKind()==AND || n.getKind()==OR || n.getKind()==EQUAL || n.getKind()==ITE || n.getKind()==IFF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isPropagatingInstance( p, n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ if( p->getEqualityEngine()->hasTerm( n ) || isGroundSubterm( n ) ){
+ return true;
+ }
+ }
+ Trace("qcf-instance-check-debug") << "...not propagating instance because of " << n << std::endl;
+ return false;
+}
+
bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
Node rew = Rewriter::rewrite( lit );
@@ -606,6 +692,9 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
doFail = true;
success = false;
}else{
+ if( isBaseMatchComplete() && options::qcfEagerTest() ){
+ return true;
+ }
//solve for interpreted symbol matches
// this breaks the invariant that all introduced constraints are over existing terms
for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
@@ -636,7 +725,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
if( !z.isNull() ){
Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
assigned.push_back( vn );
- if( !setMatch( p, vn, z, false ) ){
+ if( !setMatch( p, vn, z, false, true ) ){
success = false;
break;
}
@@ -678,7 +767,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
if( !sum.isNull() ){
assigned.push_back( slv_v );
Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
- if( !setMatch( p, slv_v, sum, false ) ){
+ if( !setMatch( p, slv_v, sum, false, true ) ){
success = false;
}
p->d_tempCache.push_back( sum );
@@ -764,7 +853,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
int currIndex = d_una_eqc_count[d_una_index];
d_una_eqc_count[d_una_index]++;
Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
- if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true ) ){
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true, true ) ){
d_match_term[d_unassigned[d_una_index]] = TNode::null();
Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
d_una_index++;
@@ -813,9 +902,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
}
return true;
}else{
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
+ revertMatch( p, assigned );
assigned.clear();
return false;
}
@@ -837,9 +924,9 @@ void QuantInfo::getMatch( std::vector< Node >& terms ){
}
}
-void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+void QuantInfo::revertMatch( QuantConflictFind * p, std::vector< int >& assigned ) {
for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
+ unsetMatch( p, assigned[i] );
}
}
@@ -899,26 +986,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
if( isVar ){
Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
if( n.getKind()==ITE ){
- /*
- d_type = typ_ite_var;
- d_type_not = false;
- d_n = n;
- d_children.push_back( MatchGen( qi, d_n[0] ) );
- if( d_children[0].isValid() ){
- d_type = typ_ite_var;
- for( unsigned i=1; i<=2; i++ ){
- Node nn = n.eqNode( n[i] );
- d_children.push_back( MatchGen( qi, nn ) );
- d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- }else{
-*/
- d_type = typ_invalid;
- //}
+ d_type = typ_invalid;
}else{
d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
d_qni_var_num[0] = qi->getVarNum( n );
@@ -961,26 +1029,6 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
break;
}
}
- /*
- else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
- Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
- //if variable equality/disequality at top level, remove immediately
- bool cIsNot = d_children[d_children.size()-1].d_type_not;
- Node cn = d_children[d_children.size()-1].d_n;
- Assert( cn.getKind()==EQUAL );
- Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
- //make it a built-in constraint instead
- for( unsigned i=0; i<2; i++ ){
- if( p->d_qinfo[q].isVar( cn[i] ) ){
- int v = p->d_qinfo[q].getVarNum( cn[i] );
- Node cno = cn[i==0 ? 1 : 0];
- p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
- break;
- }
- }
- d_children.pop_back();
- }
- */
}
}else{
d_type = typ_invalid;
@@ -1003,6 +1051,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
}
}else{
d_qni_gterm[i] = d_n[i];
+ qi->setGroundSubterm( d_n[i] );
}
}
d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
@@ -1013,21 +1062,8 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
//we will just evaluate
d_n = n;
d_type = typ_ground;
+ qi->setGroundSubterm( d_n );
}
- //if( d_type!=typ_invalid ){
- //determine an efficient children ordering
- //if( !d_children.empty() ){
- //for( unsigned i=0; i<d_children.size(); i++ ){
- // d_children_order.push_back( i );
- //}
- //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
- //sort based on the type of the constraint : ground comes first, then literals, then others
- //MatchGenSort mgs;
- //mgs.d_mg = this;
- //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
- //}
- //}
- //}
}
Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
debugPrintType( "qcf-qregister-debug", d_type, true );
@@ -1036,78 +1072,96 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar )
}
-void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
- int v = qi->getVarNum( n );
- if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
- cbvars.push_back( v );
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectBoundVar( qi, n[i], cbvars );
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getKind()==FORALL ){
+ hasNested = true;
+ }
+ int v = qi->getVarNum( n );
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
+ cbvars.push_back( v );
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectBoundVar( qi, n[i], cbvars, visited, hasNested );
+ }
}
}
void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
- Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
- bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
- std::map< int, std::vector< int > > c_to_vars;
- std::map< int, std::vector< int > > vars_to_c;
- std::map< int, int > vb_count;
- std::map< int, int > vu_count;
- std::vector< bool > assigned;
- Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
- for( unsigned i=0; i<d_children.size(); i++ ){
- collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
- assigned.push_back( false );
- vb_count[i] = 0;
- vu_count[i] = 0;
- for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
- int v = c_to_vars[i][j];
- vars_to_c[v].push_back( i );
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- vu_count[i]++;
- if( !isCom ){
- bvars.push_back( v );
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << ", #bvars = " << bvars.size() << std::endl;
+ bool isComm = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
+ if( isComm ){
+ std::map< int, std::vector< int > > c_to_vars;
+ std::map< int, std::vector< int > > vars_to_c;
+ std::map< int, int > vb_count;
+ std::map< int, int > vu_count;
+ std::map< int, bool > has_nested;
+ std::vector< bool > assigned;
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ std::map< Node, bool > visited;
+ has_nested[i] = false;
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i], visited, has_nested[i] );
+ assigned.push_back( false );
+ vb_count[i] = 0;
+ vu_count[i] = 0;
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
+ int v = c_to_vars[i][j];
+ vars_to_c[v].push_back( i );
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ vu_count[i]++;
+ }else{
+ vb_count[i]++;
}
- }else{
- vb_count[i]++;
}
}
- }
- if( isCom ){
- //children that bind the least number of unbound variables go first
+ //children that bind no unbound variable, then the most number of bound, unbound variables go first
+ Trace("qcf-qregister-vo") << "Variable order for " << d_n << " : " << std::endl;
do {
+ int min_score0 = -1;
int min_score = -1;
int min_score_index = -1;
for( unsigned i=0; i<d_children.size(); i++ ){
if( !assigned[i] ){
- int score = vu_count[i];
- if( min_score==-1 || score<min_score ){
+ Trace("qcf-qregister-debug2") << "Child " << i << " has b/ub : " << vb_count[i] << "/" << vu_count[i] << std::endl;
+ int score0 = 0;//has_nested[i] ? 0 : 1;
+ int score;
+ if( !options::qcfVoExp() ){
+ score = vu_count[i];
+ }else{
+ score = vu_count[i]==0 ? 0 : ( 1 + qi->d_vars.size()*( qi->d_vars.size() - vb_count[i] ) + ( qi->d_vars.size() - vu_count[i] ) );
+ }
+ if( min_score==-1 || score0<min_score0 || ( score0==min_score0 && score<min_score ) ){
+ min_score0 = score0;
min_score = score;
min_score_index = i;
}
}
}
- Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
+ Trace("qcf-qregister-vo") << " " << d_children_order.size()+1 << ": " << d_children[min_score_index].d_n << " : ";
+ Trace("qcf-qregister-vo") << vu_count[min_score_index] << " " << vb_count[min_score_index] << " " << has_nested[min_score_index] << std::endl;
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << std::endl;
+ Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl;
Assert( min_score_index!=-1 );
//add to children order
d_children_order.push_back( min_score_index );
assigned[min_score_index] = true;
- //if( vb_count[min_score_index]==0 ){
- // d_independent.push_back( min_score_index );
- //}
//determine order internal to children
d_children[min_score_index].determineVariableOrder( qi, bvars );
Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
//now, make it a bound variable
- for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
- int v = c_to_vars[min_score_index][i];
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
- int vc = vars_to_c[v][j];
- vu_count[vc]--;
- vb_count[vc]++;
+ if( vu_count[min_score_index]>0 ){
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
+ int v = c_to_vars[min_score_index][i];
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
+ int vc = vars_to_c[v][j];
+ vu_count[vc]--;
+ vb_count[vc]++;
+ }
+ bvars.push_back( v );
}
- bvars.push_back( v );
}
}
Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
@@ -1117,6 +1171,16 @@ void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars
for( unsigned i=0; i<d_children.size(); i++ ){
d_children_order.push_back( i );
d_children[i].determineVariableOrder( qi, bvars );
+ //now add to bvars
+ std::map< Node, bool > visited;
+ std::vector< int > cvars;
+ bool has_nested = false;
+ collectBoundVar( qi, d_children[i].d_n, cvars, visited, has_nested );
+ for( unsigned j=0; j<cvars.size(); j++ ){
+ if( std::find( bvars.begin(), bvars.end(), cvars[j] )==bvars.end() ){
+ bvars.push_back( cvars[j] );
+ }
+ }
}
}
}
@@ -1169,15 +1233,20 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qni.clear();
d_qni_bound.clear();
d_child_counter = -1;
+ d_use_children = true;
d_tgt_orig = d_tgt;
//set up processing matches
if( d_type==typ_invalid ){
- //do nothing
+ d_use_children = false;
}else if( d_type==typ_ground ){
+ d_use_children = false;
if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
d_child_counter = 0;
}
+ }else if( qi->isBaseMatchComplete() && options::qcfEagerTest() ){
+ d_use_children = false;
+ d_child_counter = 0;
}else if( d_type==typ_bool_var ){
//get current value of the variable
TNode n = qi->getCurrentValue( d_n );
@@ -1195,7 +1264,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}else{
//unassigned, set match to true/false
d_qni_bound[0] = vn;
- qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false );
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false, true );
d_child_counter = 0;
}
if( d_child_counter==0 ){
@@ -1203,11 +1272,14 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
}else if( d_type==typ_var ){
Assert( isHandledUfTerm( d_n ) );
- Node f = getMatchOperator( p, d_n );
+ TNode f = getMatchOperator( p, d_n );
Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );
if( qni!=NULL ){
d_qn.push_back( qni );
+ }else{
+ //inform irrelevant quantifiers
+ p->setIrrelevantFunction( f );
}
d_matched_basis = false;
}else if( d_type==typ_tsym || d_type==typ_tconstraint ){
@@ -1257,7 +1329,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
}
}else{
- //otherwise, add a constraint to a variable
+ //otherwise, add a constraint to a variable TODO: this may be over-eager at effort > conflict, since equality may be a propagation
if( vn[1]!=-1 && vn[0]==-1 ){
//swap
Node t = nn[1];
@@ -1292,7 +1364,9 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qn.push_back( NULL );
}else{
if( d_tgt && d_n.getKind()==FORALL ){
- //do nothing
+ //fail
+ }else if( d_n.getKind()==FORALL && p->d_effort==QuantConflictFind::effort_conflict && !options::qcfNestedConflict() ){
+ //fail
}else{
//reset the first child to d_tgt
d_child_counter = 0;
@@ -1309,7 +1383,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
debugPrintType( "qcf-match", d_type );
Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
- if( d_type==typ_invalid || d_type==typ_ground ){
+ if( !d_use_children ){
if( d_child_counter==0 ){
d_child_counter = -1;
return true;
@@ -1423,7 +1497,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
Assert( it->second<qi->getNumVars() );
- qi->d_match[ it->second ] = TNode::null();
+ qi->unsetMatch( p, it->second );
qi->d_match_term[ it->second ] = TNode::null();
}
d_qni_bound.clear();
@@ -1654,7 +1728,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
if( it != d_qn[index]->d_data.end() ) {
d_qni.push_back( it );
//set the match
- if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true ) ){
+ if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true, true ) ){
Debug("qcf-match-debug") << " Binding variable" << std::endl;
if( d_qn.size()<d_qni_size ){
d_qn.push_back( &it->second );
@@ -1699,7 +1773,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
d_qni[index]++;
if( d_qni[index]!=d_qn[index]->d_data.end() ){
success = true;
- if( qi->setMatch( p, itb->second, d_qni[index]->first, true ) ){
+ if( qi->setMatch( p, itb->second, d_qni[index]->first, true, true ) ){
Debug("qcf-match-debug") << " Bind next variable" << std::endl;
if( d_qn.size()<d_qni_size ){
d_qn.push_back( &d_qni[index]->second );
@@ -1709,7 +1783,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
invalidMatch = true;
}
}else{
- qi->d_match[ itb->second ] = TNode::null();
+ qi->unsetMatch( p, itb->second );
qi->d_match_term[ itb->second ] = TNode::null();
Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
}
@@ -1779,7 +1853,7 @@ void MatchGen::setInvalid() {
}
bool MatchGen::isHandledBoolConnective( TNode n ) {
- return n.getType().isBoolean() && TermDb::isBoolConnective( n.getKind() );
+ return TermDb::isBoolConnective( n.getKind() ) && ( n.getKind()!=ITE || n.getType().isBoolean() );
}
bool MatchGen::isHandledUfTerm( TNode n ) {
@@ -1835,28 +1909,31 @@ void QuantConflictFind::registerQuantifier( Node q ) {
if( d_quantEngine->hasOwnership( q, this ) ){
d_quants.push_back( q );
d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
+ if( Trace.isOn("qcf-qregister") ){
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ }
//make QcfNode structure
Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
d_qinfo[q].initialize( this, q, q[1] );
//debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
- }
- }
-
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ if( Trace.isOn("qcf-qregister") ){
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
}
}
@@ -1933,6 +2010,18 @@ void QuantConflictFind::reset_round( Theory::Effort level ) {
d_needs_computeRelEqr = true;
}
+void QuantConflictFind::setIrrelevantFunction( TNode f ) {
+ if( d_irr_func.find( f )==d_irr_func.end() ){
+ d_irr_func[f] = true;
+ std::map< TNode, std::vector< Node > >::iterator it = d_func_rel_dom.find( f );
+ if( it != d_func_rel_dom.end()){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ d_irr_quant[it->second[j]] = true;
+ }
+ }
+ }
+}
+
/** check */
void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){
@@ -1955,14 +2044,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
}
computeRelevantEqr();
- //determine order for quantified formulas
- std::vector< Node > qorder;
- for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
- Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
- if( d_quantEngine->hasOwnership( q, this ) ){
- qorder.push_back( q );
- }
- }
+ d_irr_func.clear();
+ d_irr_quant.clear();
+
if( Trace.isOn("qcf-debug") ){
Trace("qcf-debug") << std::endl;
debugPrint("qcf-debug");
@@ -1973,77 +2057,83 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
for( short e = effort_conflict; e<=end_e; e++ ){
d_effort = e;
Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
- for( unsigned j=0; j<qorder.size(); j++ ){
- Node q = qorder[j];
- QuantInfo * qi = &d_qinfo[q];
-
- Assert( d_qinfo.find( q )!=d_qinfo.end() );
- if( qi->matchGeneratorIsValid() ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->getNextMatch( this ) ){
- Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- std::vector< int > assigned;
- if( !qi->isMatchSpurious( this ) ){
- if( qi->completeMatch( this, assigned ) ){
- std::vector< Node > terms;
- qi->getMatch( terms );
- if( !qi->isTConstraintSpurious( this, terms ) ){
- //for debugging
- if( Debug.isOn("qcf-check-inst") ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( !getTermDatabase()->isEntailed( inst, true ) );
- Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict );
- }
- if( d_quantEngine->addInstantiation( q, terms ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quantEngine->markRelevant( q );
- ++(d_statistics.d_conflict_inst);
- if( options::qcfAllConflict() ){
- isConflict = true;
+ for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
+ if( d_quantEngine->hasOwnership( q, this ) && d_irr_quant.find( q )==d_irr_quant.end() ){
+ QuantInfo * qi = &d_qinfo[q];
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( qi->matchGeneratorIsValid() ){
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ if( qi->reset_round( this ) ){
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->getNextMatch( this ) ){
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ if( !qi->isMatchSpurious( this ) ){
+ std::vector< int > assigned;
+ if( qi->completeMatch( this, assigned ) ){
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ bool tcs = qi->isTConstraintSpurious( this, terms );
+ if( !tcs ){
+ //for debugging
+ if( Debug.isOn("qcf-check-inst") ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( !getTermDatabase()->isEntailed( inst, true ) );
+ Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict );
+ }
+ if( d_quantEngine->addInstantiation( q, terms ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quantEngine->markRelevant( q );
+ ++(d_statistics.d_conflict_inst);
+ if( options::qcfAllConflict() ){
+ isConflict = true;
+ }else{
+ d_conflict.set( true );
+ }
+ break;
+ }else if( e==effort_prop_eq ){
+ d_quantEngine->markRelevant( q );
+ ++(d_statistics.d_prop_inst);
+ }
}else{
- d_conflict.set( true );
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
+ //this should only happen if the algorithm generates the same propagating instance twice this round
+ //in this case, break to avoid exponential behavior
+ break;
}
- break;
- }else if( e==effort_prop_eq ){
- d_quantEngine->markRelevant( q );
- ++(d_statistics.d_prop_inst);
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is T-inconsistent)" << std::endl;
}
+ //clean up assigned
+ qi->revertMatch( this, assigned );
+ d_tempCache.clear();
}else{
- Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
- //this should only happen if the algorithm generates the same propagating instance twice this round
- //in this case, break to avoid exponential behavior
- break;
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
}
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
}
- //clean up assigned
- qi->revertMatch( assigned );
- d_tempCache.clear();
- }else{
- Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
}
- }else{
- Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl;
+ if( d_conflict ){
+ break;
+ }
}
}
- Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl;
- if( d_conflict ){
- break;
- }
}
}
if( addedLemmas>0 ){
@@ -2074,17 +2164,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
void QuantConflictFind::computeRelevantEqr() {
if( d_needs_computeRelEqr ){
d_needs_computeRelEqr = false;
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
- //d_uf_terms.clear();
- //d_eqc_uf_terms.clear();
+ Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl;
d_eqcs.clear();
- //d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
- //now, store matches
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
while( !eqcs_i.isFinished() ){
Node r = (*eqcs_i);
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index 8b42b0916..47a66b1b1 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -35,6 +35,7 @@ class MatchGen {
private:
//current children information
int d_child_counter;
+ bool d_use_children;
//children of this object
std::vector< int > d_children_order;
unsigned getNumChildren() { return d_children.size(); }
@@ -61,7 +62,7 @@ private:
std::map< int, Node > d_ground_eval;
//determine variable order
void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
- void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested );
public:
//type of the match generator
enum {
@@ -116,7 +117,16 @@ private: //for completing match
std::vector< int > d_una_eqc_count;
//optimization: track which arguments variables appear under UF terms in
std::map< int, std::map< TNode, std::vector< unsigned > > > d_var_rel_dom;
- void getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited );
+ void getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited );
+ //optimization: number of variables set, to track when we can stop
+ std::map< int, bool > d_vars_set;
+ std::map< Node, bool > d_ground_terms;
+ std::vector< Node > d_extra_var;
+public:
+ void setGroundSubterm( Node t ) { d_ground_terms[t] = true; }
+ bool isGroundSubterm( Node t ) { return d_ground_terms.find( t )!=d_ground_terms.end(); }
+ bool isBaseMatchComplete();
+ bool isPropagatingInstance( QuantConflictFind * p, Node n );
public:
QuantInfo();
~QuantInfo();
@@ -146,7 +156,7 @@ public:
}
Node d_q;
- void reset_round( QuantConflictFind * p );
+ bool reset_round( QuantConflictFind * p );
public:
//initialize
void initialize( QuantConflictFind * p, Node q, Node qn );
@@ -161,12 +171,13 @@ public:
bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
- bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep );
+ bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround );
+ void unsetMatch( QuantConflictFind * p, int v );
bool isMatchSpurious( QuantConflictFind * p );
bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
- void revertMatch( std::vector< int >& assigned );
+ void revertMatch( QuantConflictFind * p, std::vector< int >& assigned );
void debugPrintMatch( const char * c );
bool isConstrainedVar( int v );
public:
@@ -184,6 +195,11 @@ private:
std::map< Kind, Node > d_zero;
//for storing nodes created during t-constraint solving (prevents memory leaks)
std::vector< Node > d_tempCache;
+ //optimization: list of quantifiers that depend on ground function applications
+ std::map< TNode, std::vector< Node > > d_func_rel_dom;
+ std::map< TNode, bool > d_irr_func;
+ std::map< Node, bool > d_irr_quant;
+ void setIrrelevantFunction( TNode f );
private:
std::map< Node, Node > d_op_node;
int d_fid_count;
diff --git a/src/theory/quantifiers/quant_equality_engine.cpp b/src/theory/quantifiers/quant_equality_engine.cpp
index 3f89a799c..3f89a799c 100644..100755
--- a/src/theory/quantifiers/quant_equality_engine.cpp
+++ b/src/theory/quantifiers/quant_equality_engine.cpp
diff --git a/src/theory/quantifiers/quant_equality_engine.h b/src/theory/quantifiers/quant_equality_engine.h
index 26654de4d..26654de4d 100644..100755
--- a/src/theory/quantifiers/quant_equality_engine.h
+++ b/src/theory/quantifiers/quant_equality_engine.h
diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp
index 9fb943e5e..5aff1a848 100644..100755
--- a/src/theory/quantifiers/quant_split.cpp
+++ b/src/theory/quantifiers/quant_split.cpp
@@ -48,11 +48,11 @@ void QuantDSplit::preRegisterQuantifier( Node q ) {
}else{
int score = -1;
if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){
- score = dt.isUFinite() ? 1 : -1;
+ score = dt.isInterpretedFinite() ? 1 : -1;
}else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){
- score = dt.isUFinite() ? 1 : -1;
+ score = dt.isInterpretedFinite() ? 1 : -1;
}
- Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isUFinite() << " " << dt.isFinite() << ")" << std::endl;
+ Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isInterpretedFinite() << " " << dt.isFinite() << ")" << std::endl;
if( score>max_score ){
max_index = i;
max_score = score;
diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h
index d36824998..d36824998 100644..100755
--- a/src/theory/quantifiers/quant_split.h
+++ b/src/theory/quantifiers/quant_split.h
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 3b7787a20..b9aab0236 100644..100755
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -33,22 +33,15 @@ eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
}
bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+ return d_quantEngine->getEqualityQuery()->areEqual( n1, n2 );
}
bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+ return d_quantEngine->getEqualityQuery()->areDisequal( n1, n2 );
}
TNode QuantifiersModule::getRepresentative( TNode n ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- if( ee->hasTerm( n ) ){
- return ee->getRepresentative( n );
- }else{
- return n;
- }
+ return d_quantEngine->getEqualityQuery()->getRepresentative( n );
}
quantifiers::TermDb * QuantifiersModule::getTermDatabase() {
@@ -389,7 +382,7 @@ void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int
}
void QuantPhaseReq::getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ) {
- if( n.getKind()==AND || n.getKind()==OR ){
+ if( n.getKind()==AND || n.getKind()==OR || n.getKind()==SEP_STAR ){
newHasPol = hasPol;
newPol = pol;
}else if( n.getKind()==IMPLIES ){
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 79cdae437..79cdae437 100644..100755
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index b797f4ce9..b797f4ce9 100644..100755
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index 53cef796a..53cef796a 100644..100755
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 5aae4d640..68f824c57 100644..100755
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -48,7 +48,7 @@ bool QuantifiersRewriter::isClause( Node n ){
bool QuantifiersRewriter::isLiteral( Node n ){
switch( n.getKind() ){
case NOT:
- return isLiteral( n[0] );
+ return n[0].getKind()!=NOT && isLiteral( n[0] );
break;
case OR:
case AND:
@@ -59,7 +59,8 @@ bool QuantifiersRewriter::isLiteral( Node n ){
return false;
break;
case EQUAL:
- return n[0].getType()!=NodeManager::currentNM()->booleanType();
+ //for boolean terms
+ return !n[0].getType().isBoolean();
break;
default:
break;
@@ -185,19 +186,10 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
std::vector< Node > args;
- for( int i=0; i<(int)in[0].getNumChildren(); i++ ){
- args.push_back( in[0][i] );
- }
- Node body = in[1];
+ Node body = in;
bool doRewrite = false;
- std::vector< Node > ipl;
- while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){
- if( body.getNumChildren()==3 ){
- for( unsigned i=0; i<body[2].getNumChildren(); i++ ){
- ipl.push_back( body[2][i] );
- }
- }
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
args.push_back( body[0][i] );
}
body = body[1];
@@ -205,16 +197,11 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
if( doRewrite ){
std::vector< Node > children;
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
+ args.push_back( body[0][i] );
+ }
children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
- children.push_back( body );
- if( in.getNumChildren()==3 ){
- for( unsigned i=0; i<in[2].getNumChildren(); i++ ){
- ipl.push_back( in[2][i] );
- }
- }
- if( !ipl.empty() ){
- children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) );
- }
+ children.push_back( body[1] );
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
@@ -244,7 +231,7 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
ret = ret.negate();
status = REWRITE_AGAIN_FULL;
}else if( in.getKind()==FORALL ){
- if( in[1].isConst() ){
+ if( in[1].isConst() && in.getNumChildren()==2 ){
return RewriteResponse( status, in[1] );
}else{
//compute attributes
@@ -273,121 +260,98 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
return RewriteResponse( status, ret );
}
-Node QuantifiersRewriter::computeElimSymbols( Node body ) {
- if( isLiteral( body ) ){
- return body;
- }else{
- bool childrenChanged = false;
- Kind k = body.getKind();
- if( body.getKind()==IMPLIES ){
- k = OR;
- childrenChanged = true;
- }else if( body.getKind()==XOR ){
- k = IFF;
+bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){
+ if( ( k==OR || k==AND ) && options::elimTautQuant() ){
+ Node lit = c.getKind()==NOT ? c[0] : c;
+ bool pol = c.getKind()!=NOT;
+ std::map< Node, bool >::iterator it = lit_pol.find( lit );
+ if( it==lit_pol.end() ){
+ lit_pol[lit] = pol;
+ children.push_back( c );
+ }else{
childrenChanged = true;
- }
- std::vector< Node > children;
- std::map< Node, bool > lit_pol;
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- Node c = computeElimSymbols( body[i] );
- if( i==0 && ( body.getKind()==IMPLIES || body.getKind()==XOR ) ){
- c = c.negate();
- }
- if( ( k==OR || k==AND ) && options::elimTautQuant() ){
- Node lit = c.getKind()==NOT ? c[0] : c;
- bool pol = c.getKind()!=NOT;
- std::map< Node, bool >::iterator it = lit_pol.find( lit );
- if( it==lit_pol.end() ){
- lit_pol[lit] = pol;
- children.push_back( c );
- }else{
- childrenChanged = true;
- if( it->second!=pol ){
- return NodeManager::currentNM()->mkConst( k==OR );
- }
- }
- }else{
- children.push_back( c );
+ if( it->second!=pol ){
+ return false;
}
- childrenChanged = childrenChanged || c!=body[i];
- }
- //if( body.getKind()==ITE && isLiteral( body[0] ) ){
- // ret = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ),
- // NodeManager::currentNM()->mkNode( OR, body[0], body[2] ) );
- //}
- if( childrenChanged ){
- return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
- }else{
- return body;
}
+ }else{
+ children.push_back( c );
}
+ return true;
}
-Node QuantifiersRewriter::computeNNF( Node body ){
- if( body.getKind()==NOT ){
+// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF
+Node QuantifiersRewriter::computeElimSymbols( Node body ) {
+ Kind ok = body.getKind();
+ Kind k = ok;
+ bool negAllCh = false;
+ bool negCh1 = false;
+ if( ok==IMPLIES ){
+ k = OR;
+ negCh1 = true;
+ }else if( ok==XOR ){
+ k = IFF;
+ negCh1 = true;
+ }else if( ok==NOT ){
if( body[0].getKind()==NOT ){
- return computeNNF( body[0][0] );
- }else if( isLiteral( body[0] ) ){
- return body;
+ return computeElimSymbols( body[0][0] );
+ }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
+ k = AND;
+ negAllCh = true;
+ negCh1 = body[0].getKind()==IMPLIES;
+ body = body[0];
+ }else if( body[0].getKind()==AND ){
+ k = OR;
+ negAllCh = true;
+ body = body[0];
+ }else if( body[0].getKind()==XOR || body[0].getKind()==IFF ){
+ k = IFF;
+ negCh1 = ( body[0].getKind()==IFF );
+ body = body[0];
+ }else if( body[0].getKind()==ITE ){
+ k = body[0].getKind();
+ negAllCh = true;
+ negCh1 = true;
+ body = body[0];
}else{
- std::vector< Node > children;
- Kind k = body[0].getKind();
-
- if( body[0].getKind()==OR || body[0].getKind()==AND ){
- k = body[0].getKind()==AND ? OR : AND;
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node nc = computeNNF( body[0][i].notNode() );
- if( nc.getKind()==k ){
- for( unsigned j=0; j<nc.getNumChildren(); j++ ){
- children.push_back( nc[j] );
- }
- }else{
- children.push_back( nc );
- }
- }
- }else if( body[0].getKind()==IFF ){
- for( int i=0; i<2; i++ ){
- Node nn = i==0 ? body[0][i] : body[0][i].notNode();
- children.push_back( computeNNF( nn ) );
- }
- }else if( body[0].getKind()==ITE ){
- for( int i=0; i<3; i++ ){
- Node nn = i==0 ? body[0][i] : body[0][i].notNode();
- children.push_back( computeNNF( nn ) );
- }
- }else{
- Notice() << "Unhandled Quantifiers NNF: " << body << std::endl;
- return body;
- }
- return NodeManager::currentNM()->mkNode( k, children );
+ return body;
}
- }else if( isLiteral( body ) ){
+ }else if( ok!=IFF && ok!=ITE && ok!=AND && ok!=OR ){
+ //a literal
return body;
- }else{
- std::vector< Node > children;
- bool childrenChanged = false;
- bool isAssoc = body.getKind()==AND || body.getKind()==OR;
- for( int i=0; i<(int)body.getNumChildren(); i++ ){
- Node nc = computeNNF( body[i] );
- if( isAssoc && nc.getKind()==body.getKind() ){
- for( unsigned j=0; j<nc.getNumChildren(); j++ ){
- children.push_back( nc[j] );
+ }
+ bool childrenChanged = false;
+ std::vector< Node > children;
+ std::map< Node, bool > lit_pol;
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
+ bool success = true;
+ if( c.getKind()==k && ( k==OR || k==AND ) ){
+ //flatten
+ childrenChanged = true;
+ for( unsigned j=0; j<c.getNumChildren(); j++ ){
+ if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
+ success = false;
+ break;
}
- childrenChanged = true;
- }else{
- children.push_back( nc );
- childrenChanged = childrenChanged || nc!=body[i];
}
- }
- if( childrenChanged ){
- return NodeManager::currentNM()->mkNode( body.getKind(), children );
}else{
- return body;
+ success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
}
+ if( !success ){
+ // tautology
+ Assert( k==OR || k==AND );
+ return NodeManager::currentNM()->mkConst( k==OR );
+ }
+ childrenChanged = childrenChanged || c!=body[i];
+ }
+ if( childrenChanged || k!=ok ){
+ return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
+ }else{
+ return body;
}
}
-
void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons,
std::vector< Node >& conj ){
if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){
@@ -463,6 +427,8 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){
std::map< Node, bool >::iterator it = currCond.find( n );
if( it!=currCond.end() ){
return it->second ? 1 : -1;
+ }else if( n.getKind()==NOT ){
+ return -getEntailedCond( n[0], currCond );
}else if( n.getKind()==AND || n.getKind()==OR ){
bool hasZero = false;
for( unsigned i=0; i<n.getNumChildren(); i++ ){
@@ -483,8 +449,7 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){
}else if( res==-1 ){
return getEntailedCond( n[2], currCond );
}
- }
- if( n.getKind()==IFF || n.getKind()==ITE ){
+ }else if( n.getKind()==IFF || n.getKind()==ITE ){
unsigned start = n.getKind()==IFF ? 0 : 1;
int res1 = 0;
for( unsigned j=start; j<=(start+1); j++ ){
@@ -1049,144 +1014,6 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
return body;
}
-Node QuantifiersRewriter::computeClause( Node n ){
- Assert( isClause( n ) );
- if( isLiteral( n ) ){
- return n;
- }else{
- NodeBuilder<> t(OR);
- if( n.getKind()==NOT ){
- if( n[0].getKind()==NOT ){
- return computeClause( n[0][0] );
- }else{
- //De-Morgan's law
- Assert( n[0].getKind()==AND );
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- Node nn = computeClause( n[0][i].notNode() );
- addNodeToOrBuilder( nn, t );
- }
- }
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nn = computeClause( n[i] );
- addNodeToOrBuilder( nn, t );
- }
- }
- return t.constructNode();
- }
-}
-
-Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){
- if( isLiteral( n ) ){
- return n;
- }else if( !forcePred && isClause( n ) ){
- return computeClause( n );
- }else{
- Kind k = n.getKind();
- NodeBuilder<> t(k);
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nc = n[i];
- Node ncnf = computeCNF( nc, args, defs, k!=OR );
- if( k==OR ){
- addNodeToOrBuilder( ncnf, t );
- }else{
- t << ncnf;
- }
- }
- if( !forcePred && k==OR ){
- return t.constructNode();
- }else{
- //compute the free variables
- Node nt = t;
- std::vector< Node > activeArgs;
- computeArgVec( args, activeArgs, nt );
- std::vector< TypeNode > argTypes;
- for( int i=0; i<(int)activeArgs.size(); i++ ){
- argTypes.push_back( activeArgs[i].getType() );
- }
- //create the predicate
- Assert( argTypes.size()>0 );
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, NodeManager::currentNM()->booleanType() );
- std::stringstream ss;
- ss << "cnf_" << n.getKind() << "_" << n.getId();
- Node op = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "was created by the quantifiers rewriter" );
- std::vector< Node > predArgs;
- predArgs.push_back( op );
- predArgs.insert( predArgs.end(), activeArgs.begin(), activeArgs.end() );
- Node pred = NodeManager::currentNM()->mkNode( APPLY_UF, predArgs );
- Trace("quantifiers-rewrite-cnf-debug") << "Made predicate " << pred << " for " << nt << std::endl;
- //create the bound var list
- Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, activeArgs );
- //now, look at the structure of nt
- if( nt.getKind()==NOT ){
- //case for NOT
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( i==0 ? nt[0].notNode() : nt[0] );
- tt << ( i==0 ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else if( nt.getKind()==OR ){
- //case for OR
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- NodeBuilder<> tt(OR);
- tt << nt[i].notNode() << pred;
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- NodeBuilder<> tt(OR);
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- tt << nt[i];
- }
- tt << pred.notNode();
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }else if( nt.getKind()==AND ){
- //case for AND
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- NodeBuilder<> tt(OR);
- tt << nt[i] << pred.notNode();
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- NodeBuilder<> tt(OR);
- for( int i=0; i<(int)nt.getNumChildren(); i++ ){
- tt << nt[i].notNode();
- }
- tt << pred;
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }else if( nt.getKind()==IFF ){
- //case for IFF
- for( int i=0; i<4; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( ( i==0 || i==3 ) ? nt[0].notNode() : nt[0] );
- tt << ( ( i==1 || i==3 ) ? nt[1].notNode() : nt[1] );
- tt << ( ( i==0 || i==1 ) ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else if( nt.getKind()==ITE ){
- //case for ITE
- for( int j=1; j<=2; j++ ){
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( ( j==1 ) ? nt[0].notNode() : nt[0] );
- tt << ( ( i==1 ) ? nt[j].notNode() : nt[j] );
- tt << ( ( i==0 ) ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }
- for( int i=0; i<2; i++ ){
- NodeBuilder<> tt(OR);
- tt << ( i==0 ? nt[1].notNode() : nt[1] );
- tt << ( i==0 ? nt[2].notNode() : nt[2] );
- tt << ( i==1 ? pred.notNode() : pred );
- defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
- }
- }else{
- Notice() << "Unhandled Quantifiers CNF: " << nt << std::endl;
- }
- return pred;
- }
- }
-}
-
Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){
if( body.getKind()==FORALL ){
if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){
@@ -1194,15 +1021,13 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
std::vector< Node > subs;
//for doing prenexing of same-signed quantifiers
//must rename each variable that already exists
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
terms.push_back( body[0][i] );
subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) );
}
args.insert( args.end(), subs.begin(), subs.end() );
Node newBody = body[1];
newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
- Debug("quantifiers-substitute-debug") << "Did substitute have an effect" << (body[1] != newBody) << body[1] << " became " << newBody << endl;
return newBody;
}else{
return body;
@@ -1211,7 +1036,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
Assert( body.getKind()!=EXISTS );
bool childrenChanged = false;
std::vector< Node > newChildren;
- for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
bool newHasPol;
bool newPol;
QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
@@ -1237,7 +1062,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
}
}
-Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node body ) {
+Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) {
Assert( body.getKind()==OR );
size_t var_found_count = 0;
size_t eqc_count = 0;
@@ -1253,8 +1078,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
Node n = body[i];
std::vector< Node > lit_args;
computeArgVec( args, lit_args, n );
- if (lit_args.empty()) {
- lits.push_back(n);
+ if( lit_args.empty() ){
+ lits.push_back( n );
}else {
//collect the equivalence classes this literal belongs to, and the new variables it contributes
std::vector< int > eqcs;
@@ -1306,8 +1131,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
eqc_to_lit[eqcz].push_back(n);
}
}
- if ( eqc_active>1 || !lits.empty() ){
- Trace("clause-split-debug") << "Split clause " << f << std::endl;
+ if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
+ Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
Trace("clause-split-debug") << " Ground literals: " << std::endl;
for( size_t i=0; i<lits.size(); i++) {
Trace("clause-split-debug") << " " << lits[i] << std::endl;
@@ -1330,27 +1155,21 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node
Node fa = NodeManager::currentNM()->mkNode( FORALL, bvl, body );
lits.push_back(fa);
}
- Assert( lits.size()>1 );
- Node nf = NodeManager::currentNM()->mkNode(OR,lits);
+ Assert( !lits.empty() );
+ Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
Trace("clause-split-debug") << "Made node : " << nf << std::endl;
return nf;
+ }else{
+ return mkForAll( args, body, qa );
}
- return f;
}
Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ){
- std::vector< Node > activeArgs;
- //if cegqi is on, may be synthesis conjecture, in which case we want to keep all variables
- if( options::ceGuidedInst() && qa.d_sygus ){
- activeArgs.insert( activeArgs.end(), args.begin(), args.end() );
- }else{
- computeArgVec2( args, activeArgs, body, qa.d_ipl );
- }
- if( activeArgs.empty() ){
+ if( args.empty() ){
return body;
}else{
std::vector< Node > children;
- children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) );
+ children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
children.push_back( body );
if( !qa.d_ipl.isNull() ){
children.push_back( qa.d_ipl );
@@ -1359,82 +1178,59 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttri
}
}
-Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ){
+//computes miniscoping, also eliminates variables that do not occur free in body
+Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ){
if( body.getKind()==FORALL ){
- //combine arguments
+ //combine prenex
std::vector< Node > newArgs;
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ newArgs.insert( newArgs.end(), args.begin(), args.end() );
+ for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
newArgs.push_back( body[0][i] );
}
- newArgs.insert( newArgs.end(), args.begin(), args.end() );
- return mkForAll( newArgs, body[ 1 ], qa );
- }else{
- if( body.getKind()==NOT ){
- //push not downwards
- if( body[0].getKind()==NOT ){
- return computeMiniscoping( f, args, body[0][0], qa );
- }else if( body[0].getKind()==AND ){
- if( options::miniscopeQuantFreeVar() ){
- NodeBuilder<> t(kind::OR);
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
- }
- return computeMiniscoping( f, args, t.constructNode(), qa );
- }
- }else if( body[0].getKind()==OR ){
- if( options::miniscopeQuant() ){
- NodeBuilder<> t(kind::AND);
- for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node trm = body[0][i].negate();
- t << computeMiniscoping( f, args, trm, qa );
- }
- return t.constructNode();
+ return mkForAll( newArgs, body[1], qa );
+ }else if( body.getKind()==AND ){
+ if( options::miniscopeQuant() ){
+ //break apart
+ NodeBuilder<> t(kind::AND);
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ t << computeMiniscoping( args, body[i], qa );
+ }
+ Node retVal = t;
+ return retVal;
+ }
+ }else if( body.getKind()==OR ){
+ if( options::quantSplit() ){
+ //splitting subsumes free variable miniscoping, apply it with higher priority
+ return computeSplit( args, body, qa );
+ }else if( options::miniscopeQuantFreeVar() ){
+ Node newBody = body;
+ NodeBuilder<> body_split(kind::OR);
+ NodeBuilder<> tb(kind::OR);
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ Node trm = body[i];
+ if( TermDb::containsTerms( body[i], args ) ){
+ tb << trm;
+ }else{
+ body_split << trm;
}
}
- }else if( body.getKind()==AND ){
- if( options::miniscopeQuant() ){
- //break apart
- NodeBuilder<> t(kind::AND);
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- t << computeMiniscoping( f, args, body[i], qa );
- }
- Node retVal = t;
- return retVal;
- }
- }else if( body.getKind()==OR ){
- if( options::quantSplit() ){
- //splitting subsumes free variable miniscoping, apply it with higher priority
- Node nf = computeSplit( f, args, body );
- if( nf!=f ){
- return nf;
- }
- }else if( options::miniscopeQuantFreeVar() ){
- Node newBody = body;
- NodeBuilder<> body_split(kind::OR);
- NodeBuilder<> tb(kind::OR);
- for( unsigned i=0; i<body.getNumChildren(); i++ ){
- Node trm = body[i];
- if( TermDb::containsTerms( body[i], args ) ){
- tb << trm;
- }else{
- body_split << trm;
- }
- }
- if( tb.getNumChildren()==0 ){
- return body_split;
- }else if( body_split.getNumChildren()>0 ){
- newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- body_split << mkForAll( args, newBody, qa );
- return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
- }
+ if( tb.getNumChildren()==0 ){
+ return body_split;
+ }else if( body_split.getNumChildren()>0 ){
+ newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
+ std::vector< Node > activeArgs;
+ computeArgVec2( args, activeArgs, newBody, qa.d_ipl );
+ body_split << mkForAll( activeArgs, newBody, qa );
+ return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
}
}
+ }else if( body.getKind()==NOT ){
+ Assert( isLiteral( body[0] ) );
}
- //if( body==f[1] ){
- // return f;
- //}else{
- return mkForAll( args, body, qa );
- //}
+ //remove variables that don't occur
+ std::vector< Node > activeArgs;
+ computeArgVec2( args, activeArgs, body, qa.d_ipl );
+ return mkForAll( activeArgs, body, qa );
}
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){
@@ -1552,19 +1348,14 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q
return is_std;
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return options::aggressiveMiniscopeQuant() && is_std;
- }else if( computeOption==COMPUTE_NNF ){
- return true;
}else if( computeOption==COMPUTE_PROCESS_TERMS ){
- return true;
- //return options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE || options::iteCondVarSplitQuant();
+ return options::condRewriteQuant();
}else if( computeOption==COMPUTE_COND_SPLIT ){
return ( options::iteDtTesterSplitQuant() || options::condVarSplitQuant() ) && !is_strict_trigger;
}else if( computeOption==COMPUTE_PRENEX ){
return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant() && is_std;
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
return ( options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant() ) && is_std;
- //}else if( computeOption==COMPUTE_CNF ){
- // return options::cnfQuant();
}else if( computeOption==COMPUTE_PURIFY_EXPAND ){
return options::purifyQuant() && is_std;
}else{
@@ -1584,11 +1375,9 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut
n = computeElimSymbols( n );
}else if( computeOption==COMPUTE_MINISCOPING ){
//return directly
- return computeMiniscoping( f, args, n, qa );
+ return computeMiniscoping( args, n, qa );
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return computeAggressiveMiniscoping( args, n );
- }else if( computeOption==COMPUTE_NNF ){
- n = computeNNF( n );
}else if( computeOption==COMPUTE_PROCESS_TERMS ){
std::vector< Node > new_conds;
n = computeProcessTerms( n, args, new_conds, f, qa );
@@ -1602,9 +1391,6 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut
n = computePrenex( n, args, true );
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
n = computeVarElimination( n, args, qa );
- //}else if( computeOption==COMPUTE_CNF ){
- //n = computeCNF( n, args, defs, false );
- //ipl = Node::null();
}else if( computeOption==COMPUTE_PURIFY_EXPAND ){
std::vector< Node > conj;
computePurifyExpand( n, conj, args, qa );
@@ -1738,15 +1524,15 @@ struct ContainsQuantAttributeId {};
typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute;
// check if the given node contains a universal quantifier
-bool QuantifiersRewriter::containsQuantifiers(Node n) {
+bool QuantifiersRewriter::containsQuantifiers( Node n ){
if( n.hasAttribute(ContainsQuantAttribute()) ){
return n.getAttribute(ContainsQuantAttribute())==1;
- } else if(n.getKind() == kind::FORALL) {
+ }else if( n.getKind() == kind::FORALL ){
return true;
- } else {
+ }else{
bool cq = false;
for( unsigned i = 0; i < n.getNumChildren(); ++i ){
- if( containsQuantifiers(n[i]) ){
+ if( containsQuantifiers( n[i] ) ){
cq = true;
break;
}
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index 2071d1793..776517109 100644..100755
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -38,6 +38,7 @@ public:
static int getPurifyId( Node n );
static int getPurifyIdLit( Node n );
private:
+ static bool addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged );
static void addNodeToOrBuilder( Node n, NodeBuilder<>& t );
static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa );
static void computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n, std::map< Node, bool >& visited );
@@ -46,7 +47,6 @@ private:
static Node computeProcessTerms2( Node body, bool hasPol, bool pol, std::map< Node, bool >& currCond, int nCurrCond,
std::map< Node, Node >& cache, std::map< Node, Node >& icache,
std::vector< Node >& new_vars, std::vector< Node >& new_conds );
- static Node computeClause( Node n );
static void computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons, std::vector< Node >& conj );
static bool isConditionalVariableElim( Node n, int pol=0 );
static bool isVariableElim( Node v, Node s, std::map< Node, std::vector< int > >& var_parent );
@@ -57,15 +57,13 @@ private:
static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent );
private:
static Node computeElimSymbols( Node body );
- static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa );
+ static Node computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa );
static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body );
- static Node computeNNF( Node body );
//cache is dependent upon currCond, icache is not, new_conds are negated conditions
static Node computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa );
static Node computeCondSplit( Node body, QAttributes& qa );
- static Node computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred );
static Node computePrenex( Node body, std::vector< Node >& args, bool pol );
- static Node computeSplit( Node f, std::vector< Node >& args, Node body );
+ static Node computeSplit( std::vector< Node >& args, Node body, QAttributes& qa );
static Node computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa );
static Node computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent );
static void computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa );
@@ -74,7 +72,6 @@ private:
COMPUTE_ELIM_SYMBOLS = 0,
COMPUTE_MINISCOPING,
COMPUTE_AGGRESSIVE_MINISCOPING,
- COMPUTE_NNF,
COMPUTE_PROCESS_TERMS,
COMPUTE_PRENEX,
COMPUTE_VAR_ELIMINATION,
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index b353fce2f..b4b51fd84 100644..100755
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -110,7 +110,7 @@ void RelevantDomain::compute(){
for( unsigned i=0; i<sz; i++ ){
Node n = it->second[i];
//if it is a non-redundant term
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( db->isTermActive( n ) ){
for( unsigned j=0; j<n.getNumChildren(); j++ ){
RDomain * rf = getRDomain( op, j );
rf->addTerm( n[j] );
diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h
index 2b90520fd..2b90520fd 100644..100755
--- a/src/theory/quantifiers/relevant_domain.h
+++ b/src/theory/quantifiers/relevant_domain.h
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
index 5365dbcfa..2c58b8f77 100644..100755
--- a/src/theory/quantifiers/rewrite_engine.cpp
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -175,7 +175,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) {
for( unsigned j=0; j<to_remove.size(); j++ ){
Node ns = d_quantEngine->getSubstitute( to_remove[j], inst );
Trace("rewrite-engine-inst-debug") << "Will remove : " << ns << std::endl;
- ns.setAttribute(NoMatchAttribute(),true);
+ d_quantEngine->getTermDatabase()->setTermInactive( ns );
}
*/
}else{
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
index 424530696..424530696 100644..100755
--- a/src/theory/quantifiers/rewrite_engine.h
+++ b/src/theory/quantifiers/rewrite_engine.h
diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp
index 2a2b13583..2a2b13583 100644..100755
--- a/src/theory/quantifiers/symmetry_breaking.cpp
+++ b/src/theory/quantifiers/symmetry_breaking.cpp
diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h
index 38fea4f45..e682955e7 100644..100755
--- a/src/theory/quantifiers/symmetry_breaking.h
+++ b/src/theory/quantifiers/symmetry_breaking.h
@@ -42,9 +42,7 @@ class SubsortSymmetryBreaker {
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
- //typedef context::CDChunkList<int> IntList;
typedef context::CDList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
private:
/** quantifiers engine */
QuantifiersEngine* d_qe;
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 8b09d8e5d..d3a5e178f 100644..100755
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -84,13 +84,13 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
}
}
-TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_id_count( 0 ), d_typ_id_count( 0 ) {
+TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_inactive_map( c ), d_op_id_count( 0 ), d_typ_id_count( 0 ) {
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
if( options::ceGuidedInst() ){
- d_sygus_tdb = new TermDbSygus;
+ d_sygus_tdb = new TermDbSygus( c, qe );
}else{
d_sygus_tdb = NULL;
}
@@ -163,9 +163,18 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi
//if this is an atomic trigger, consider adding it
if( inst::Trigger::isAtomicTrigger( n ) ){
Trace("term-db") << "register term in db " << n << std::endl;
+ if( options::finiteModelFind() ){
+ computeModelBasisArgAttribute( n );
+ }
+
Node op = getMatchOperator( n );
+ Trace("term-db-debug") << " match operator is : " << op << std::endl;
d_op_map[op].push_back( n );
added.insert( n );
+
+ if( d_sygus_tdb ){
+ d_sygus_tdb->registerEvalTerm( n );
+ }
if( options::eagerInstQuant() ){
for( unsigned i=0; i<n.getNumChildren(); i++ ){
@@ -178,6 +187,8 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi
}
}
}
+ }else{
+ setTermInactive( n );
}
rec = true;
}
@@ -210,7 +221,7 @@ void TermDb::computeUfEqcTerms( TNode f ) {
for( unsigned i=0; i<d_op_map[f].size(); i++ ){
TNode n = d_op_map[f][i];
if( hasTermCurrent( n ) ){
- if( !n.getAttribute(NoMatchAttribute()) ){
+ if( isTermActive( n ) ){
computeArgReps( n );
TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n;
d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] );
@@ -220,7 +231,84 @@ void TermDb::computeUfEqcTerms( TNode f ) {
}
}
+void TermDb::computeUfTerms( TNode f ) {
+ if( d_op_nonred_count.find( f )==d_op_nonred_count.end() ){
+ d_op_nonred_count[ f ] = 0;
+ std::map< Node, std::vector< Node > >::iterator it = d_op_map.find( f );
+ if( it!=d_op_map.end() ){
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
+ Trace("term-db-debug") << "Adding terms for operator " << f << std::endl;
+ unsigned congruentCount = 0;
+ unsigned nonCongruentCount = 0;
+ unsigned alreadyCongruentCount = 0;
+ unsigned relevantCount = 0;
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ //to be added to term index, term must be relevant, and exist in EE
+ if( hasTermCurrent( n ) && ee->hasTerm( n ) ){
+ relevantCount++;
+ if( isTermActive( n ) ){
+ computeArgReps( n );
+
+ Trace("term-db-debug") << "Adding term " << n << " with arg reps : ";
+ for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){
+ Trace("term-db-debug") << d_arg_reps[n][i] << " ";
+ if( std::find( d_func_map_rel_dom[f][i].begin(),
+ d_func_map_rel_dom[f][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[f][i].end() ){
+ d_func_map_rel_dom[f][i].push_back( d_arg_reps[n][i] );
+ }
+ }
+ Trace("term-db-debug") << std::endl;
+ Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl;
+ Node at = d_func_map_trie[ f ].addOrGetTerm( n, d_arg_reps[n] );
+ Trace("term-db-debug2") << "...add term returned " << at << std::endl;
+ if( at!=n && ee->areEqual( at, n ) ){
+ setTermInactive( n );
+ Trace("term-db-debug") << n << " is redundant." << std::endl;
+ congruentCount++;
+ }else{
+ if( at!=n && ee->areDisequal( at, n, false ) ){
+ std::vector< Node > lits;
+ lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) );
+ for( unsigned i=0; i<at.getNumChildren(); i++ ){
+ if( at[i]!=n[i] ){
+ lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() );
+ }
+ }
+ Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits );
+ if( Trace.isOn("term-db-lemma") ){
+ Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl;
+ if( !d_quantEngine->getTheoryEngine()->needCheck() ){
+ Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl;
+ }
+ Trace("term-db-lemma") << " add lemma : " << lem << std::endl;
+ }
+ d_quantEngine->addLemma( lem );
+ d_consistent_ee = false;
+ return;
+ }
+ nonCongruentCount++;
+ d_op_nonred_count[ f ]++;
+ }
+ }else{
+ Trace("term-db-debug") << n << " is already redundant." << std::endl;
+ alreadyCongruentCount++;
+ }
+ }else{
+ Trace("term-db-debug") << n << " is not relevant." << std::endl;
+ }
+ }
+ if( Trace.isOn("tdb") ){
+ Trace("tdb") << "Term db size [" << f << "] : " << nonCongruentCount << " / ";
+ Trace("tdb") << ( nonCongruentCount + congruentCount ) << " / " << ( nonCongruentCount + congruentCount + alreadyCongruentCount ) << " / ";
+ Trace("tdb") << relevantCount << " / " << it->second.size() << std::endl;
+ }
+ }
+ }
+}
+
bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) {
+ computeUfTerms( f );
Assert( d_quantEngine->getTheoryEngine()->getMasterEqualityEngine()->getRepresentative( r )==r );
std::map< Node, std::map< unsigned, std::vector< Node > > >::iterator it = d_func_map_rel_dom.find( f );
if( it != d_func_map_rel_dom.end() ){
@@ -237,25 +325,23 @@ bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) {
//return a term n' equivalent to n
// maximal subterms of n' are representatives in the equality engine qy
-Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ) {
+Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests ) {
std::map< TNode, Node >::iterator itv = visited.find( n );
if( itv != visited.end() ){
return itv->second;
}
Trace("term-db-eval") << "evaluate term : " << n << std::endl;
- Node ret;
- if( n.getKind()==BOUND_VARIABLE ){
- return n;
+ Node ret = n;
+ if( n.getKind()==FORALL || n.getKind()==BOUND_VARIABLE ){
+ //do nothing
}else if( !qy->hasTerm( n ) ){
//term is not known to be equal to a representative in equality engine, evaluate it
- if( n.getKind()==FORALL ){
- ret = Node::null();
- }else if( n.hasOperator() ){
+ if( n.hasOperator() ){
TNode f = getMatchOperator( n );
std::vector< TNode > args;
bool ret_set = false;
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- TNode c = evaluateTerm2( n[i], visited, qy );
+ TNode c = evaluateTerm2( n[i], visited, qy, useEntailmentTests );
if( c.isNull() ){
ret = Node::null();
ret_set = true;
@@ -267,7 +353,7 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ
ret_set = true;
break;
}else if( n.getKind()==kind::ITE && i==0 ){
- ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy );
+ ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy, useEntailmentTests );
ret_set = true;
break;
}
@@ -295,6 +381,22 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ
}
ret = NodeManager::currentNM()->mkNode( n.getKind(), args );
ret = Rewriter::rewrite( ret );
+ if( ret.getKind()==kind::EQUAL ){
+ if( qy->areDisequal( ret[0], ret[1] ) ){
+ ret = d_false;
+ }
+ }
+ if( useEntailmentTests ){
+ if( ret.getKind()==kind::EQUAL || ret.getKind()==kind::GEQ ){
+ for( unsigned j=0; j<2; j++ ){
+ std::pair<bool, Node> et = d_quantEngine->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, j==0 ? ret : ret.negate() );
+ if( et.first ){
+ ret = j==0 ? d_true : d_false;
+ break;
+ }
+ }
+ }
+ }
}
}
}
@@ -316,14 +418,16 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su
return n;
}else if( n.getKind()==BOUND_VARIABLE ){
if( hasSubs ){
- Assert( subs.find( n )!=subs.end() );
- Trace("term-db-entail") << "...substitution is : " << subs[n] << std::endl;
- if( subsRep ){
- Assert( qy->getEngine()->hasTerm( subs[n] ) );
- Assert( qy->getEngine()->getRepresentative( subs[n] )==subs[n] );
- return subs[n];
- }else{
- return getEntailedTerm2( subs[n], subs, subsRep, hasSubs, qy );
+ std::map< TNode, TNode >::iterator it = subs.find( n );
+ if( it!=subs.end() ){
+ Trace("term-db-entail") << "...substitution is : " << it->second << std::endl;
+ if( subsRep ){
+ Assert( qy->getEngine()->hasTerm( it->second ) );
+ Assert( qy->getEngine()->getRepresentative( it->second )==it->second );
+ return it->second;
+ }else{
+ return getEntailedTerm2( it->second, subs, subsRep, hasSubs, qy );
+ }
}
}
}else if( n.getKind()==ITE ){
@@ -355,12 +459,12 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su
return TNode::null();
}
-Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy ) {
+Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy, bool useEntailmentTests ) {
if( qy==NULL ){
qy = d_quantEngine->getEqualityQuery();
}
std::map< TNode, Node > visited;
- return evaluateTerm2( n, visited, qy );
+ return evaluateTerm2( n, visited, qy, useEntailmentTests );
}
TNode TermDb::getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy ) {
@@ -436,6 +540,8 @@ bool TermDb::isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
return qy->getEngine()->getRepresentative( n1 ) == ( pol ? d_true : d_false );
}
}
+ }else if( n.getKind()==FORALL && !pol ){
+ return isEntailed2( n[1], subs, subsRep, hasSubs, pol, qy );
}
return false;
}
@@ -457,6 +563,18 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
return isEntailed2( n, subs, subsRep, true, pol, qy );
}
+bool TermDb::isTermActive( Node n ) {
+ return d_inactive_map.find( n )==d_inactive_map.end();
+ //return !n.getAttribute(NoMatchAttribute());
+}
+
+void TermDb::setTermInactive( Node n ) {
+ d_inactive_map[n] = true;
+ //Trace("term-db-debug2") << "set no match attribute" << std::endl;
+ //NoMatchAttribute nma;
+ //n.setAttribute(nma,true);
+}
+
bool TermDb::hasTermCurrent( Node n, bool useMode ) {
if( !useMode ){
return d_has_map.find( n )!=d_has_map.end();
@@ -556,10 +674,6 @@ void TermDb::presolve() {
}
bool TermDb::reset( Theory::Effort effort ){
- int nonCongruentCount = 0;
- int congruentCount = 0;
- int alreadyCongruentCount = 0;
- int nonRelevantCount = 0;
d_op_nonred_count.clear();
d_arg_reps.clear();
d_func_map_trie.clear();
@@ -614,89 +728,20 @@ bool TermDb::reset( Theory::Effort effort ){
}
}
+/*
//rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- d_op_nonred_count[ it->first ] = 0;
- Trace("term-db-debug") << "Adding terms for operator " << it->first << std::endl;
- for( unsigned i=0; i<it->second.size(); i++ ){
- Node n = it->second[i];
- //to be added to term index, term must be relevant, and exist in EE
- if( hasTermCurrent( n ) && ee->hasTerm( n ) ){
- if( !n.getAttribute(NoMatchAttribute()) ){
- if( options::finiteModelFind() ){
- computeModelBasisArgAttribute( n );
- }
- computeArgReps( n );
-
- Trace("term-db-debug") << "Adding term " << n << " with arg reps : ";
- for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){
- Trace("term-db-debug") << d_arg_reps[n][i] << " ";
- if( std::find( d_func_map_rel_dom[it->first][i].begin(),
- d_func_map_rel_dom[it->first][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[it->first][i].end() ){
- d_func_map_rel_dom[it->first][i].push_back( d_arg_reps[n][i] );
- }
- }
- Trace("term-db-debug") << std::endl;
- if( ee->hasTerm( n ) ){
- Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl;
- }
- Node at = d_func_map_trie[ it->first ].addOrGetTerm( n, d_arg_reps[n] );
- if( at!=n && ee->areEqual( at, n ) ){
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- Trace("term-db-debug") << n << " is redundant." << std::endl;
- congruentCount++;
- }else{
- if( at!=n && ee->areDisequal( at, n, false ) ){
- std::vector< Node > lits;
- lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) );
- for( unsigned i=0; i<at.getNumChildren(); i++ ){
- if( at[i]!=n[i] ){
- lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() );
- }
- }
- Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits );
- if( Trace.isOn("term-db-lemma") ){
- Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl;
- if( !d_quantEngine->getTheoryEngine()->needCheck() ){
- Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl;
- }
- Trace("term-db-lemma") << " add lemma : " << lem << std::endl;
- }
- d_quantEngine->addLemma( lem );
- d_consistent_ee = false;
- return false;
- }
- nonCongruentCount++;
- d_op_nonred_count[ it->first ]++;
- }
- }else{
- Trace("term-db-debug") << n << " is already redundant." << std::endl;
- congruentCount++;
- alreadyCongruentCount++;
- }
- }else{
- Trace("term-db-debug") << n << " is not relevant." << std::endl;
- nonRelevantCount++;
- }
- }
- }
- Trace("term-db-stats") << "TermDb: Reset" << std::endl;
- Trace("term-db-stats") << "Non-Congruent/Congruent/Non-Relevant = ";
- Trace("term-db-stats") << nonCongruentCount << " / " << congruentCount << " (" << alreadyCongruentCount << ") / " << nonRelevantCount << std::endl;
- if( Trace.isOn("term-db-index") ){
- Trace("term-db-index") << "functions : " << std::endl;
- for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- if( it->second.size()>0 ){
- Trace("term-db-index") << "- " << it->first << std::endl;
- d_func_map_trie[ it->first ].debugPrint("term-db-index", it->second[0]);
- }
+ computeUfTerms( it->first );
+ if( !d_consistent_ee ){
+ return false;
}
}
+*/
return true;
}
TermArgTrie * TermDb::getTermArgTrie( Node f ) {
+ computeUfTerms( f );
std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
if( itut!=d_func_map_trie.end() ){
return &itut->second;
@@ -725,11 +770,18 @@ TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) {
}
TNode TermDb::getCongruentTerm( Node f, Node n ) {
- computeArgReps( n );
- return d_func_map_trie[f].existsTerm( d_arg_reps[n] );
+ computeUfTerms( f );
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
+ if( itut!=d_func_map_trie.end() ){
+ computeArgReps( n );
+ return itut->second.existsTerm( d_arg_reps[n] );
+ }else{
+ return TNode::null();
+ }
}
TNode TermDb::getCongruentTerm( Node f, std::vector< TNode >& args ) {
+ computeUfTerms( f );
return d_func_map_trie[f].existsTerm( args );
}
@@ -822,6 +874,7 @@ void TermDb::makeInstantiationConstantsFor( Node q ){
Debug("quantifiers-engine") << "Instantiation constants for " << q << " : " << std::endl;
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
d_vars[q].push_back( q[0][i] );
+ d_var_num[q][q[0][i]] = i;
//make instantiation constants
Node ic = NodeManager::currentNM()->mkInstConstant( q[0][i].getType() );
d_inst_constants_map[ic] = q;
@@ -832,9 +885,8 @@ void TermDb::makeInstantiationConstantsFor( Node q ){
ic.setAttribute( ivna, i );
InstConstantAttribute ica;
ic.setAttribute( ica, q );
- //also set the no-match attribute
- NoMatchAttribute nma;
- ic.setAttribute(nma,true);
+ //also set the term inactive
+ setTermInactive( ic );
}
}
}
@@ -892,11 +944,6 @@ Node TermDb::getInstConstAttr( Node n ) {
}
InstConstantAttribute ica;
n.setAttribute(ica, q);
- if( !q.isNull() ){
- //also set the no-match attribute
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- }
}
return n.getAttribute(InstConstantAttribute());
}
@@ -1005,9 +1052,12 @@ Node TermDb::getCounterexampleLiteral( Node q ){
Node TermDb::getInstConstantNode( Node n, Node q ){
makeInstantiationConstantsFor( q );
- Node n2 = n.substitute( d_vars[q].begin(), d_vars[q].end(),
- d_inst_constants[q].begin(), d_inst_constants[q].end() );
- return n2;
+ return n.substitute( d_vars[q].begin(), d_vars[q].end(), d_inst_constants[q].begin(), d_inst_constants[q].end() );
+}
+
+Node TermDb::getVariableNode( Node n, Node q ) {
+ makeInstantiationConstantsFor( q );
+ return n.substitute( d_inst_constants[q].begin(), d_inst_constants[q].end(), d_vars[q].begin(), d_vars[q].end() );
}
Node TermDb::getInstantiatedNode( Node n, Node q, std::vector< Node >& terms ) {
@@ -1512,7 +1562,7 @@ struct sortTermOrder {
//this function makes a canonical representation of a term (
// - orders variables left to right
// - if apply_torder, then sort direct subterms of commutative operators
-Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder ) {
+Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder, std::map< TNode, Node >& visited ) {
Trace("canon-term-debug") << "Get canonical term for " << n << std::endl;
if( n.getKind()==BOUND_VARIABLE ){
std::map< TNode, TNode >::iterator it = subs.find( n );
@@ -1529,32 +1579,38 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun
return it->second;
}
}else if( n.getNumChildren()>0 ){
- //collect children
- Trace("canon-term-debug") << "Collect children" << std::endl;
- std::vector< Node > cchildren;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- cchildren.push_back( n[i] );
- }
- //if applicable, first sort by term order
- if( apply_torder && isComm( n.getKind() ) ){
- Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl;
- sortTermOrder sto;
- sto.d_tdb = this;
- std::sort( cchildren.begin(), cchildren.end(), sto );
- }
- //now make canonical
- Trace("canon-term-debug") << "Make canonical children" << std::endl;
- for( unsigned i=0; i<cchildren.size(); i++ ){
- cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder );
- }
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl;
- cchildren.insert( cchildren.begin(), n.getOperator() );
- }
- Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl;
- Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren );
- Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl;
- return ret;
+ std::map< TNode, Node >::iterator it = visited.find( n );
+ if( it!=visited.end() ){
+ return it->second;
+ }else{
+ //collect children
+ Trace("canon-term-debug") << "Collect children" << std::endl;
+ std::vector< Node > cchildren;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ cchildren.push_back( n[i] );
+ }
+ //if applicable, first sort by term order
+ if( apply_torder && isComm( n.getKind() ) ){
+ Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl;
+ sortTermOrder sto;
+ sto.d_tdb = this;
+ std::sort( cchildren.begin(), cchildren.end(), sto );
+ }
+ //now make canonical
+ Trace("canon-term-debug") << "Make canonical children" << std::endl;
+ for( unsigned i=0; i<cchildren.size(); i++ ){
+ cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder, visited );
+ }
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl;
+ cchildren.insert( cchildren.begin(), n.getOperator() );
+ }
+ Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl;
+ Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren );
+ Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl;
+ visited[n] = ret;
+ return ret;
+ }
}else{
Trace("canon-term-debug") << "...return 0-child term." << std::endl;
return n;
@@ -1564,7 +1620,8 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun
Node TermDb::getCanonicalTerm( TNode n, bool apply_torder ){
std::map< TypeNode, unsigned > var_count;
std::map< TNode, TNode > subs;
- return getCanonicalTerm( n, var_count, subs, apply_torder );
+ std::map< TNode, Node > visited;
+ return getCanonicalTerm( n, var_count, subs, apply_torder, visited );
}
void TermDb::getVtsTerms( std::vector< Node >& t, bool isFree, bool create, bool inc_delta ) {
@@ -1790,6 +1847,18 @@ bool TermDb::getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& c
}
}
+void TermDb::getRelevancyCondition( Node n, std::vector< Node >& cond ) {
+ if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+ unsigned scindex = Datatype::cindexOf(n.getOperator().toExpr());
+ const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
+ Node rc = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[scindex].getTester() ), n[0] ).negate();
+ if( std::find( cond.begin(), cond.end(), rc )==cond.end() ){
+ cond.push_back( rc );
+ }
+ getRelevancyCondition( n[0], cond );
+ }
+}
+
bool TermDb::containsTerm2( Node n, Node t, std::map< Node, bool >& visited ) {
if( n==t ){
return true;
@@ -1856,7 +1925,7 @@ bool TermDb::containsUninterpretedConstant( Node n ) {
bool ret = false;
if( n.getKind()==UNINTERPRETED_CONSTANT ){
ret = true;
- }else{
+ }else{
for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( containsUninterpretedConstant( n[i] ) ){
ret = true;
@@ -1884,7 +1953,8 @@ Node TermDb::simpleNegate( Node n ){
bool TermDb::isAssoc( Kind k ) {
return k==PLUS || k==MULT || k==AND || k==OR || k==XOR || k==IFF ||
- k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT;
+ k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT ||
+ k==STRING_CONCAT;
}
bool TermDb::isComm( Kind k ) {
@@ -2184,11 +2254,15 @@ bool TermDb::isQAttrQuantElimPartial( Node q ) {
}
}
-TermDbSygus::TermDbSygus(){
+TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
}
+bool TermDbSygus::reset( Theory::Effort e ) {
+ return true;
+}
+
TNode TermDbSygus::getVar( TypeNode tn, int i ) {
while( i>=(int)d_fv[tn].size() ){
std::stringstream ss;
@@ -2400,8 +2474,8 @@ Node TermDbSygus::sygusToBuiltin( Node n, TypeNode tn ) {
std::map< Node, Node >::iterator it = d_sygus_to_builtin[tn].find( n );
if( it==d_sygus_to_builtin[tn].end() ){
Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n << ", type = " << tn << std::endl;
- Assert( n.getKind()==APPLY_CONSTRUCTOR );
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( n.getKind()==APPLY_CONSTRUCTOR );
unsigned i = Datatype::indexOf( n.getOperator().toExpr() );
Assert( n.getNumChildren()==dt[i].getNumArgs() );
std::map< TypeNode, int > var_count;
@@ -3051,6 +3125,7 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node >
std::string name = std::string( str.begin() + found +1, str.end() );
out << name;
}else{
+ Trace("ajr-temp") << "[[print operator " << op << "]]" << std::endl;
out << op;
}
if( n.getNumChildren()>0 ){
@@ -3118,3 +3193,91 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node >
out << n;
}
}
+
+Node TermDbSygus::getAnchor( Node n ) {
+ if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+ return getAnchor( n[0] );
+ }else{
+ return n;
+ }
+}
+
+void TermDbSygus::registerEvalTerm( Node n ) {
+ if( options::sygusDirectEval() ){
+ if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){
+ Trace("sygus-eager") << "TermDbSygus::eager: Register eval term : " << n << std::endl;
+ TypeNode tn = n[0].getType();
+ if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ if( dt.isSygus() ){
+ Node f = n.getOperator();
+ Trace("sygus-eager") << "...the evaluation function is : " << f << std::endl;
+ if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
+ d_evals[n[0]].push_back( n );
+ TypeNode tn = n[0].getType();
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ Assert( dt.isSygus() );
+ d_eval_args[n[0]].push_back( std::vector< Node >() );
+ for( unsigned j=1; j<n.getNumChildren(); j++ ){
+ if( var_list[j-1].getType().isBoolean() ){
+ //TODO: remove this case when boolean term conversion is eliminated
+ Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u));
+ d_eval_args[n[0]].back().push_back( n[j].eqNode( c ) );
+ }else{
+ d_eval_args[n[0]].back().push_back( n[j] );
+ }
+ }
+ Node a = getAnchor( n[0] );
+ d_subterms[a][n[0]] = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& lems ) {
+ std::map< Node, std::map< Node, bool > >::iterator its = d_subterms.find( a );
+ if( its!=d_subterms.end() ){
+ Trace("sygus-eager") << "registerModelValue : " << a << ", has " << its->second.size() << " registered subterms." << std::endl;
+ for( std::map< Node, bool >::iterator itss = its->second.begin(); itss != its->second.end(); ++itss ){
+ Node n = itss->first;
+ Trace("sygus-eager-debug") << "...process : " << n << std::endl;
+ std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_eval_args.find( n );
+ if( it!=d_eval_args.end() && !it->second.empty() ){
+ TNode at = a;
+ TNode vt = v;
+ Node vn = n.substitute( at, vt );
+ vn = Rewriter::rewrite( vn );
+ unsigned start = d_node_mv_args_proc[n][vn];
+ Node antec = n.eqNode( vn ).negate();
+ TypeNode tn = n.getType();
+ Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ Assert( dt.isSygus() );
+ Trace("sygus-eager") << "TermDbSygus::eager: Register model value : " << vn << " for " << n << std::endl;
+ Trace("sygus-eager") << "...it has " << it->second.size() << " evaluations, already processed " << start << "." << std::endl;
+ Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( vn, tn );
+ Trace("sygus-eager") << "Built-in term : " << bTerm << std::endl;
+ std::vector< Node > vars;
+ Node var_list = Node::fromExpr( dt.getSygusVarList() );
+ for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+ vars.push_back( var_list[j] );
+ }
+ //for each evaluation
+ for( unsigned i=start; i<it->second.size(); i++ ){
+ Assert( vars.size()==it->second[i].size() );
+ Node sBTerm = bTerm.substitute( vars.begin(), vars.end(), it->second[i].begin(), it->second[i].end() );
+ Node lem = NodeManager::currentNM()->mkNode( n.getType().isBoolean() ? IFF : EQUAL, d_evals[n][i], sBTerm );
+ lem = NodeManager::currentNM()->mkNode( OR, antec, lem );
+ Trace("sygus-eager") << "Lemma : " << lem << std::endl;
+ lems.push_back( lem );
+ }
+ d_node_mv_args_proc[n][vn] = it->second.size();
+ }
+ }
+ }
+}
+
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index a62b343a2..7ab3668eb 100644..100755
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -47,15 +47,6 @@ typedef expr::Attribute< SygusAttributeId, bool > SygusAttribute;
struct SynthesisAttributeId {};
typedef expr::Attribute< SynthesisAttributeId, bool > SynthesisAttribute;
-/** Attribute true for nodes that should not be used for matching */
-struct NoMatchAttributeId {};
-/** use the special for boolean flag */
-typedef expr::Attribute< NoMatchAttributeId,
- bool,
- expr::attr::NullCleanupStrategy,
- true // context dependent
- > NoMatchAttribute;
-
// attribute for "contains instantiation constants from"
struct InstConstantAttributeId {};
typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute;
@@ -179,6 +170,7 @@ class TermDb : public QuantifiersUtil {
friend class ::CVC4::theory::quantifiers::ConjectureGenerator;
friend class ::CVC4::theory::quantifiers::TermGenEnv;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
private:
/** reference to the quantifiers engine */
QuantifiersEngine* d_quantEngine;
@@ -211,6 +203,8 @@ private:
std::map< Node, std::vector< Node > > d_op_map;
/** map from type nodes to terms of that type */
std::map< TypeNode, std::vector< Node > > d_type_map;
+ /** inactive map */
+ NodeBoolMap d_inactive_map;
/** count number of non-redundant ground terms per operator */
std::map< Node, int > d_op_nonred_count;
@@ -228,7 +222,7 @@ private:
/** set has term */
void setHasTerm( Node n );
/** evaluate term */
- Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy );
+ Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests );
TNode getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy );
bool isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy );
public:
@@ -254,18 +248,23 @@ public:
void computeArgReps( TNode n );
/** compute uf eqc terms */
void computeUfEqcTerms( TNode f );
+ /** compute uf terms */
+ void computeUfTerms( TNode f );
/** in relevant domain */
bool inRelevantDomain( TNode f, unsigned i, TNode r );
/** evaluate a term under a substitution. Return representative in EE if possible.
* subsRep is whether subs contains only representatives
*/
- Node evaluateTerm( TNode n, EqualityQuery * qy = NULL );
+ Node evaluateTerm( TNode n, EqualityQuery * qy = NULL, bool useEntailmentTests = false );
/** get entailed term, does not construct new terms, less aggressive */
TNode getEntailedTerm( TNode n, EqualityQuery * qy = NULL );
TNode getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy = NULL );
/** is entailed (incomplete check) */
bool isEntailed( TNode n, bool pol, EqualityQuery * qy = NULL );
bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy = NULL );
+ /** is active */
+ bool isTermActive( Node n );
+ void setTermInactive( Node n );
/** has term */
bool hasTermCurrent( Node n, bool useMode = true );
/** is term eligble for instantiation? */
@@ -274,7 +273,7 @@ public:
Node getEligibleTermInEqc( TNode r );
/** is inst closure */
bool isInstClosure( Node r );
-
+
//for model basis
private:
//map from types to model basis terms
@@ -301,6 +300,7 @@ public:
private:
/** map from universal quantifiers to the list of variables */
std::map< Node, std::vector< Node > > d_vars;
+ std::map< Node, std::map< Node, unsigned > > d_var_num;
/** map from universal quantifiers to the list of instantiation constants */
std::map< Node, std::vector< Node > > d_inst_constants;
/** map from universal quantifiers to their inst constant body */
@@ -312,6 +312,8 @@ private:
/** make instantiation constants for */
void makeInstantiationConstantsFor( Node q );
public:
+ /** get variable number */
+ unsigned getVariableNum( Node q, Node v ) { return d_var_num[q][v]; }
/** get the i^th instantiation constant of q */
Node getInstantiationConstant( Node q, int i ) const;
/** get number of instantiation constants for q */
@@ -327,6 +329,7 @@ public:
instantiation.
*/
Node getInstConstantNode( Node n, Node q );
+ Node getVariableNode( Node n, Node q );
/** get substituted node */
Node getInstantiatedNode( Node n, Node q, std::vector< Node >& terms );
@@ -419,7 +422,8 @@ private:
//free variables
std::map< TypeNode, std::vector< Node > > d_cn_free_var;
// get canonical term, return null if it contains a term apart from handled signature
- Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder );
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder,
+ std::map< TNode, Node >& visited );
public:
/** get id for operator */
int getIdForOperator( Node op );
@@ -461,6 +465,8 @@ public:
static Node ensureType( Node n, TypeNode tn );
/** get ensure type condition */
static bool getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& cond );
+ /** get relevancy condition */
+ static void getRelevancyCondition( Node n, std::vector< Node >& cond );
private:
//helper for contains term
static bool containsTerm2( Node n, Node t, std::map< Node, bool >& visited );
@@ -541,6 +547,8 @@ public:
class TermDbSygus {
private:
+ /** reference to the quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
std::map< TypeNode, std::vector< Node > > d_fv;
std::map< Node, TypeNode > d_fv_stype;
std::map< Node, int > d_fv_num;
@@ -554,7 +562,6 @@ public:
private:
std::map< TypeNode, std::map< int, Node > > d_generic_base;
std::map< TypeNode, std::vector< Node > > d_generic_templ;
- Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
bool getMatch( Node p, Node n, std::map< int, Node >& s );
bool getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s );
public:
@@ -581,7 +588,11 @@ private:
std::map< TypeNode, std::map< Node, Node > > d_sygus_to_builtin;
std::map< TypeNode, std::map< Node, Node > > d_builtin_const_to_sygus;
public:
- TermDbSygus();
+ TermDbSygus( context::Context* c, QuantifiersEngine* qe );
+ ~TermDbSygus(){}
+ bool reset( Theory::Effort e );
+ std::string identify() const { return "TermDbSygus"; }
+
bool isRegistered( TypeNode tn );
TypeNode sygusToBuiltinType( TypeNode tn );
int getKindArg( TypeNode tn, Kind k );
@@ -615,6 +626,7 @@ public:
/** get value */
Node getTypeMaxValue( TypeNode tn );
TypeNode getSygusTypeForVar( Node v );
+ Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
Node mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre );
Node sygusToBuiltin( Node n, TypeNode tn );
Node builtinToSygusConst( Node c, TypeNode tn, int rcons_depth = 0 );
@@ -633,6 +645,18 @@ public:
static Kind getOperatorKind( Node op );
/** print sygus term */
static void printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs );
+
+ /** get anchor */
+ static Node getAnchor( Node n );
+//for eager instantiation
+private:
+ std::map< Node, std::map< Node, bool > > d_subterms;
+ std::map< Node, std::vector< Node > > d_evals;
+ std::map< Node, std::vector< std::vector< Node > > > d_eval_args;
+ std::map< Node, std::map< Node, unsigned > > d_node_mv_args_proc;
+public:
+ void registerEvalTerm( Node n );
+ void registerModelValue( Node n, Node v, std::vector< Node >& lems );
};
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index efe40aaa8..7ad13b3a8 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -72,8 +72,11 @@ void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) {
void TheoryQuantifiers::preRegisterTerm(TNode n) {
Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
- if( n.getKind()==FORALL && !TermDb::hasInstConstAttr(n) ){
- getQuantifiersEngine()->registerQuantifier( n );
+ if( n.getKind()==FORALL ){
+ if( !options::cbqi() || options::recurseCbqi() || !TermDb::hasInstConstAttr(n) ){
+ getQuantifiersEngine()->registerQuantifier( n );
+ Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() done " << n << endl;
+ }
}
}
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index 6775e0536..6775e0536 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
index 6ba57afb4..6ba57afb4 100644..100755
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index 38635b37b..ee091919d 100644..100755
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -43,9 +43,8 @@ void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){
}
/** trigger class constructor */
-Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption )
- : d_quantEngine( qe ), d_f( f )
-{
+Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes )
+ : d_quantEngine( qe ), d_f( f ) {
d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
Trace("trigger") << "Trigger for " << f << ": " << std::endl;
for( unsigned i=0; i<d_nodes.size(); i++ ){
@@ -53,7 +52,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int
}
if( d_nodes.size()==1 ){
if( isSimpleTrigger( d_nodes[0] ) ){
- d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] );
+ d_mg = new InstMatchGeneratorSimple( f, d_nodes[0], qe );
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes[0], qe );
d_mg->setActiveAdd(true);
@@ -87,7 +86,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int
}
Trigger::~Trigger() {
- if(d_mg != NULL) { delete d_mg; }
+ delete d_mg;
}
void Trigger::resetInstantiationRound(){
@@ -112,6 +111,10 @@ int Trigger::addTerm( Node t ){
return d_mg->addTerm( d_f, t, d_quantEngine );
}
+Node Trigger::getInstPattern(){
+ return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes );
+}
+
int Trigger::addInstantiations( InstMatch& baseMatch ){
int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine );
if( addedLemmas>0 ){
@@ -124,77 +127,85 @@ int Trigger::addInstantiations( InstMatch& baseMatch ){
return addedLemmas;
}
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption ){
- std::vector< Node > trNodes;
- if( !keepAll ){
- //only take nodes that contribute variables to the trigger when added
- std::vector< Node > temp;
- temp.insert( temp.begin(), nodes.begin(), nodes.end() );
- std::map< Node, bool > vars;
- std::map< Node, std::vector< Node > > patterns;
- size_t varCount = 0;
- std::map< Node, std::vector< Node > > varContains;
- quantifiers::TermDb::getVarContains( f, temp, varContains );
- for( unsigned i=0; i<temp.size(); i++ ){
- bool foundVar = false;
+bool Trigger::mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ) {
+ //only take nodes that contribute variables to the trigger when added
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+ std::map< Node, bool > vars;
+ std::map< Node, std::vector< Node > > patterns;
+ size_t varCount = 0;
+ std::map< Node, std::vector< Node > > varContains;
+ quantifiers::TermDb::getVarContains( q, temp, varContains );
+ for( unsigned i=0; i<temp.size(); i++ ){
+ bool foundVar = false;
+ for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
+ Node v = varContains[ temp[i] ][j];
+ Assert( quantifiers::TermDb::getInstConstAttr(v)==q );
+ if( vars.find( v )==vars.end() ){
+ varCount++;
+ vars[ v ] = true;
+ foundVar = true;
+ }
+ }
+ if( foundVar ){
+ trNodes.push_back( temp[i] );
for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
Node v = varContains[ temp[i] ][j];
- Assert( quantifiers::TermDb::getInstConstAttr(v)==f );
- if( vars.find( v )==vars.end() ){
- varCount++;
- vars[ v ] = true;
- foundVar = true;
- }
- }
- if( foundVar ){
- trNodes.push_back( temp[i] );
- for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
- Node v = varContains[ temp[i] ][j];
- patterns[ v ].push_back( temp[i] );
- }
- }
- if( varCount==f[0].getNumChildren() ){
- break;
+ patterns[ v ].push_back( temp[i] );
}
}
- if( varCount<f[0].getNumChildren() && !options::partialTriggers() ){
- Trace("trigger-debug") << "Don't consider trigger since it does not contain all variables in " << f << std::endl;
- for( unsigned i=0; i<nodes.size(); i++) {
- Trace("trigger-debug") << nodes[i] << " ";
- }
- Trace("trigger-debug") << std::endl;
+ if( varCount==n_vars ){
+ break;
+ }
+ }
+ if( varCount<n_vars ){
+ Trace("trigger-debug") << "Don't consider trigger since it does not contain specified number of variables." << std::endl;
+ for( unsigned i=0; i<nodes.size(); i++) {
+ Trace("trigger-debug") << nodes[i] << " ";
+ }
+ Trace("trigger-debug") << std::endl;
- //do not generate multi-trigger if it does not contain all variables
- return NULL;
- }else{
- //now, minimize the trigger
- for( unsigned i=0; i<trNodes.size(); i++ ){
- bool keepPattern = false;
- Node n = trNodes[i];
+ //do not generate multi-trigger if it does not contain all variables
+ return false;
+ }else{
+ //now, minimize the trigger
+ for( unsigned i=0; i<trNodes.size(); i++ ){
+ bool keepPattern = false;
+ Node n = trNodes[i];
+ for( unsigned j=0; j<varContains[ n ].size(); j++ ){
+ Node v = varContains[ n ][j];
+ if( patterns[v].size()==1 ){
+ keepPattern = true;
+ break;
+ }
+ }
+ if( !keepPattern ){
+ //remove from pattern vector
for( unsigned j=0; j<varContains[ n ].size(); j++ ){
Node v = varContains[ n ][j];
- if( patterns[v].size()==1 ){
- keepPattern = true;
- break;
- }
- }
- if( !keepPattern ){
- //remove from pattern vector
- for( unsigned j=0; j<varContains[ n ].size(); j++ ){
- Node v = varContains[ n ][j];
- for( unsigned k=0; k<patterns[v].size(); k++ ){
- if( patterns[v][k]==n ){
- patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
- break;
- }
+ for( unsigned k=0; k<patterns[v].size(); k++ ){
+ if( patterns[v][k]==n ){
+ patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
+ break;
}
}
- //remove from trigger nodes
- trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
- i--;
}
+ //remove from trigger nodes
+ trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
+ i--;
}
}
+ }
+ return true;
+}
+
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, bool keepAll, int trOption, unsigned use_n_vars ){
+ std::vector< Node > trNodes;
+ if( !keepAll ){
+ unsigned n_vars = use_n_vars==0 ? f[0].getNumChildren() : use_n_vars;
+ if( !mkTriggerTerms( f, nodes, n_vars, trNodes ) ){
+ return NULL;
+ }
}else{
trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
}
@@ -211,15 +222,15 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
}
}
- Trigger* t = new Trigger( qe, f, trNodes, matchOption );
+ Trigger* t = new Trigger( qe, f, trNodes );
qe->getTriggerDatabase()->addTrigger( trNodes, t );
return t;
}
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption ){
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll, int trOption, unsigned use_n_vars ){
std::vector< Node > nodes;
nodes.push_back( n );
- return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption );
+ return mkTrigger( qe, f, nodes, keepAll, trOption, use_n_vars );
}
bool Trigger::isUsable( Node n, Node q ){
@@ -273,7 +284,7 @@ bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) {
return true;
}
}
- }else if( isAtomicTrigger( n1 ) && isUsable( n1, q ) ){
+ }else if( isUsableAtomicTrigger( n1, q ) ){
if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermDb::containsTerm( n1, n2 ) ){
return true;
}else if( !quantifiers::TermDb::hasInstConstAttr(n2) ){
@@ -328,24 +339,25 @@ Node Trigger::getIsUsableTrigger( Node n, Node q ) {
return rtr2;
}
}else{
- bool usable = quantifiers::TermDb::getInstConstAttr(n)==q && isAtomicTrigger( n ) && isUsable( n, q );
- Trace("trigger-debug") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==q) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
- if( usable ){
+ Trace("trigger-debug") << n << " usable : " << ( quantifiers::TermDb::getInstConstAttr(n)==q ) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
+ if( isUsableAtomicTrigger( n, q ) ){
return pol ? n : NodeManager::currentNM()->mkNode( IFF, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
}
}
return Node::null();
}
+bool Trigger::isUsableAtomicTrigger( Node n, Node q ) {
+ return quantifiers::TermDb::getInstConstAttr( n )==q && isAtomicTrigger( n ) && isUsable( n, q );
+}
+
bool Trigger::isUsableTrigger( Node n, Node q ){
Node nu = getIsUsableTrigger( n, q );
return !nu.isNull();
}
bool Trigger::isAtomicTrigger( Node n ){
- Kind k = n.getKind();
- return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
- ( k!=APPLY_UF && isAtomicTriggerKind( k ) );
+ return isAtomicTriggerKind( n.getKind() );
}
bool Trigger::isAtomicTriggerKind( Kind k ) {
@@ -363,8 +375,13 @@ bool Trigger::isRelationalTriggerKind( Kind k ) {
}
bool Trigger::isCbqiKind( Kind k ) {
- return quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ||
- k==APPLY_CONSTRUCTOR || k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER;
+ if( quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ){
+ return true;
+ }else{
+ //CBQI typically works for satisfaction-complete theories
+ TheoryId t = kindToTheoryId( k );
+ return t==THEORY_BV || t==THEORY_DATATYPES;
+ }
}
bool Trigger::isSimpleTrigger( Node n ){
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index 41f2a1c38..a3da4d398 100644..100755
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -76,6 +76,8 @@ class Trigger {
int addTerm( Node t );
/** return whether this is a multi-trigger */
bool isMultiTrigger() { return d_nodes.size()>1; }
+ /** get inst pattern list */
+ Node getInstPattern();
/** add all available instantiations exhaustively, in any equivalence class
if limitInst>0, limitInst is the max # of instantiations to try */
@@ -84,8 +86,6 @@ class Trigger {
ie : quantifier engine;
f : forall something ....
nodes : (multi-)trigger
- matchOption : which policy to use for creating matches
- (one of InstMatchGenerator::MATCH_GEN_* )
keepAll: don't remove unneeded patterns;
trOption : policy for dealing with triggers that already existed
(see below)
@@ -95,18 +95,19 @@ class Trigger {
TR_GET_OLD, //return a previous trigger if it had already been created
TR_RETURN_NULL //return null if a duplicate is found
};
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f,
- std::vector< Node >& nodes, int matchOption = 0,
- bool keepAll = true, int trOption = TR_MAKE_NEW );
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n,
- int matchOption = 0, bool keepAll = true,
- int trOption = TR_MAKE_NEW );
+ //nodes input, trNodes output
+ static bool mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes );
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes,
+ bool keepAll = true, int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 );
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll = true,
+ int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 );
static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt,
std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo,
bool filterInst = false );
/** is usable trigger */
static bool isUsableTrigger( Node n, Node q );
static Node getIsUsableTrigger( Node n, Node q );
+ static bool isUsableAtomicTrigger( Node n, Node q );
static bool isAtomicTrigger( Node n );
static bool isAtomicTriggerKind( Kind k );
static bool isRelationalTrigger( Node n );
@@ -135,7 +136,7 @@ class Trigger {
}
private:
/** trigger constructor */
- Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0 );
+ Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes );
/** is subterm of trigger usable */
static bool isUsable( Node n, Node q );
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 6d3b17254..d81efe1da 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -57,6 +57,7 @@ using namespace CVC4::theory::inst;
QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te):
d_te( te ),
+ d_conflict_c(c, false),
//d_quants(u),
d_quants_red(u),
d_lemmas_produced_c(u),
@@ -88,7 +89,6 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
d_tr_trie = new inst::TriggerTrie;
d_curr_effort_level = QEFFORT_NONE;
d_conflict = false;
- d_num_added_lemmas_round = 0;
d_hasAddedLemma = false;
//don't add true lemma
d_lemmas_produced_c[d_term_db->d_true] = true;
@@ -352,7 +352,7 @@ void QuantifiersEngine::check( Theory::Effort e ){
std::vector< QuantifiersModule* > qm;
if( d_model->checkNeeded() ){
needsCheck = needsCheck || e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
- for( int i=0; i<(int)d_modules.size(); i++ ){
+ for( unsigned i=0; i<d_modules.size(); i++ ){
if( d_modules[i]->needsCheck( e ) ){
qm.push_back( d_modules[i] );
needsCheck = true;
@@ -366,7 +366,6 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
d_conflict = false;
- d_num_added_lemmas_round = 0;
d_hasAddedLemma = false;
bool setIncomplete = false;
if( e==Theory::EFFORT_LAST_CALL ){
@@ -380,6 +379,8 @@ void QuantifiersEngine::check( Theory::Effort e ){
Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl;
if( needsCheck ){
+ //this will fail if a set of instances is marked as a conflict, but is not
+ Assert( !d_conflict_c.get() );
//flush previous lemmas (for instance, if was interupted), or other lemmas to process
flushLemmas();
if( d_hasAddedLemma ){
@@ -393,6 +394,12 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
d_recorded_inst.clear();
}
+
+ double clSet = 0;
+ if( Trace.isOn("quant-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("quant-engine") << ">>>>> Quantifiers Engine Round, effort = " << e << " <<<<<" << std::endl;
+ }
if( Trace.isOn("quant-engine-debug") ){
Trace("quant-engine-debug") << "Quantifiers Engine check, level = " << e << std::endl;
@@ -453,7 +460,6 @@ void QuantifiersEngine::check( Theory::Effort e ){
flushLemmas();
if( d_hasAddedLemma ){
return;
-
}
if( e==Theory::EFFORT_LAST_CALL ){
@@ -545,6 +551,13 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
}
+ if( Trace.isOn("quant-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("quant-engine") << "Finished quantifiers engine, total time = " << (clSet2-clSet);
+ Trace("quant-engine") << ", added lemma = " << d_hasAddedLemma;
+ Trace("quant-engine") << std::endl;
+ }
+
Trace("quant-engine-debug2") << "Finished quantifiers engine check." << std::endl;
}else{
Trace("quant-engine-debug2") << "Quantifiers Engine does not need check." << std::endl;
@@ -564,7 +577,7 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
if( setIncomplete ){
- Trace("quant-engine-debug") << "Set incomplete flag." << std::endl;
+ Trace("quant-engine") << "Set incomplete flag." << std::endl;
getOutputChannel().setIncomplete();
}
//output debug stats
@@ -621,6 +634,7 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
//check whether we should apply a reduction
if( reduceQuantifier( f ) ){
+ Trace("quant") << "...reduced." << std::endl;
d_quants[f] = false;
return false;
}else{
@@ -628,6 +642,7 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
d_term_db->makeInstantiationConstantsFor( f );
d_term_db->computeAttributes( f );
for( unsigned i=0; i<d_modules.size(); i++ ){
+ Trace("quant-debug") << "pre-register with " << d_modules[i]->identify() << "..." << std::endl;
d_modules[i]->preRegisterQuantifier( f );
}
QuantifiersModule * qm = getOwner( f );
@@ -640,11 +655,11 @@ bool QuantifiersEngine::registerQuantifier( Node f ){
}
//register with each module
for( unsigned i=0; i<d_modules.size(); i++ ){
+ Trace("quant-debug") << "register with " << d_modules[i]->identify() << "..." << std::endl;
d_modules[i]->registerQuantifier( f );
}
+ //TODO: remove this
Node ceBody = d_term_db->getInstConstantBody( f );
- //generate the phase requirements
- //d_phase_reqs[f] = new QuantPhaseReq( ceBody, true );
//also register it with the strong solver
//if( options::finiteModelFind() ){
// ((uf::TheoryUF*)d_te->theoryOf( THEORY_UF ))->getStrongSolver()->registerQuantifier( f );
@@ -874,8 +889,9 @@ Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){
Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& vars, std::vector< Node >& terms, bool doVts ){
Node body;
+ Assert( vars.size()==terms.size() );
//process partial instantiation if necessary
- if( d_term_db->d_vars[q].size()!=vars.size() ){
+ if( q[0].getNumChildren()!=vars.size() ){
body = q[ 1 ].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
std::vector< Node > uninst_vars;
//doing a partial instantiation, must add quantifier for all uninstantiated variables
@@ -884,6 +900,8 @@ Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& vars, std
uninst_vars.push_back( q[0][i] );
}
}
+ Trace("partial-inst") << "Partially instantiating with " << vars.size() << " / " << q[0].getNumChildren() << " for " << q << std::endl;
+ Assert( !uninst_vars.empty() );
Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, uninst_vars );
body = NodeManager::currentNM()->mkNode( FORALL, bvl, body );
Trace("partial-inst") << "Partial instantiation : " << q << std::endl;
@@ -922,6 +940,7 @@ Node QuantifiersEngine::getInstantiation( Node q, InstMatch& m, bool doVts ){
}
Node QuantifiersEngine::getInstantiation( Node q, std::vector< Node >& terms, bool doVts ) {
+ Assert( d_term_db->d_vars.find( q )!=d_term_db->d_vars.end() );
return getInstantiation( q, d_term_db->d_vars[q], terms, doVts );
}
@@ -956,7 +975,6 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
d_lemmas_produced_c[ lem ] = true;
d_lemmas_waiting.push_back( lem );
Trace("inst-add-debug") << "Added lemma" << std::endl;
- d_num_added_lemmas_round++;
return true;
}else{
Trace("inst-add-debug") << "Duplicate." << std::endl;
@@ -965,7 +983,6 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
}else{
//do not need to rewrite, will be rewritten after sending
d_lemmas_waiting.push_back( lem );
- d_num_added_lemmas_round++;
return true;
}
}
@@ -997,6 +1014,7 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
Assert( !d_conflict );
Assert( terms.size()==q[0].getNumChildren() );
Trace("inst-add-debug") << "For quantified formula " << q << ", add instantiation: " << std::endl;
+ std::vector< Node > rlv_cond;
for( unsigned i=0; i<terms.size(); i++ ){
Trace("inst-add-debug") << " " << q[0][i];
Trace("inst-add-debug2") << " -> " << terms[i];
@@ -1014,20 +1032,29 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
if( terms[i].isNull() ){
Trace("inst-add-debug") << " --> Failed to make term vector, due to term/type restrictions." << std::endl;
return false;
+ }else{
+ //get relevancy conditions
+ if( options::instRelevantCond() ){
+ quantifiers::TermDb::getRelevancyCondition( terms[i], rlv_cond );
+ }
}
#ifdef CVC4_ASSERTIONS
bool bad_inst = false;
if( quantifiers::TermDb::containsUninterpretedConstant( terms[i] ) ){
+ Trace("inst") << "***& inst contains uninterpreted constant : " << terms[i] << std::endl;
bad_inst = true;
}else if( !terms[i].getType().isSubtypeOf( q[0][i].getType() ) ){
+ Trace("inst") << "***& inst bad type : " << terms[i] << " " << terms[i].getType() << "/" << q[0][i].getType() << std::endl;
bad_inst = true;
}else if( options::cbqi() ){
Node icf = quantifiers::TermDb::getInstConstAttr(terms[i]);
if( !icf.isNull() ){
if( icf==q ){
+ Trace("inst") << "***& inst contains inst constant attr : " << terms[i] << std::endl;
+ bad_inst = true;
+ }else if( quantifiers::TermDb::containsTerms( terms[i], d_term_db->d_inst_constants[q] ) ){
+ Trace("inst") << "***& inst contains inst constants : " << terms[i] << std::endl;
bad_inst = true;
- }else{
- bad_inst = quantifiers::TermDb::containsTerms( terms[i], d_term_db->d_inst_constants[q] );
}
}
}
@@ -1079,13 +1106,21 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
Assert( d_term_db->d_vars[q].size()==terms.size() );
Node body = getInstantiation( q, d_term_db->d_vars[q], terms, doVts ); //do virtual term substitution
+ Node orig_body = body;
body = quantifiers::QuantifiersRewriter::preprocess( body, true );
Trace("inst-debug") << "...preprocess to " << body << std::endl;
//construct the lemma
Trace("inst-assert") << "(assert " << body << ")" << std::endl;
body = Rewriter::rewrite(body);
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, q.negate(), body );
+ Node lem;
+ if( rlv_cond.empty() ){
+ lem = NodeManager::currentNM()->mkNode( kind::OR, q.negate(), body );
+ }else{
+ rlv_cond.push_back( q.negate() );
+ rlv_cond.push_back( body );
+ lem = NodeManager::currentNM()->mkNode( kind::OR, rlv_cond );
+ }
lem = Rewriter::rewrite(lem);
//check for lemma duplication
@@ -1106,15 +1141,20 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
}
}
if( options::instMaxLevel()!=-1 ){
- uint64_t maxInstLevel = 0;
- for( unsigned i=0; i<terms.size(); i++ ){
- if( terms[i].hasAttribute(InstLevelAttribute()) ){
- if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
- maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
+ if( doVts ){
+ //virtual term substitution/instantiation level features are incompatible
+ Assert( false );
+ }else{
+ uint64_t maxInstLevel = 0;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ if( terms[i].hasAttribute(InstLevelAttribute()) ){
+ if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
+ maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
+ }
}
}
+ setInstantiationLevelAttr( orig_body, q[1], maxInstLevel+1 );
}
- setInstantiationLevelAttr( body, q[1], maxInstLevel+1 );
}
if( d_curr_effort_level>QEFFORT_CONFLICT && d_curr_effort_level<QEFFORT_NONE ){
//notify listeners
@@ -1122,6 +1162,7 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
if( !d_inst_notify[j]->notifyInstantiation( d_curr_effort_level, q, lem, terms, body ) ){
Trace("inst-add-debug") << "...we are in conflict." << std::endl;
d_conflict = true;
+ d_conflict_c = true;
Assert( !d_lemmas_waiting.empty() );
break;
}
@@ -1205,9 +1246,19 @@ quantifiers::UserPatMode QuantifiersEngine::getInstUserPatMode() {
void QuantifiersEngine::flushLemmas(){
if( !d_lemmas_waiting.empty() ){
+ //filter based on notify classes
+ if( !d_inst_notify.empty() ){
+ unsigned prev_lem_sz = d_lemmas_waiting.size();
+ for( unsigned j=0; j<d_inst_notify.size(); j++ ){
+ d_inst_notify[j]->filterInstantiations();
+ }
+ if( prev_lem_sz!=d_lemmas_waiting.size() ){
+ Trace("quant-engine") << "...filtered instances : " << d_lemmas_waiting.size() << " / " << prev_lem_sz << std::endl;
+ }
+ }
//take default output channel if none is provided
d_hasAddedLemma = true;
- for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
+ for( unsigned i=0; i<d_lemmas_waiting.size(); i++ ){
Trace("qe-lemma") << "Lemma : " << d_lemmas_waiting[i] << std::endl;
getOutputChannel().lemma( d_lemmas_waiting[i], false, true );
}
@@ -1403,7 +1454,7 @@ bool EqualityQueryQuantifiersEngine::processInferences( Theory::Effort e ) {
Trace("quant-engine-ee-proc") << " explanation : " << eq_exp << std::endl;
Assert( ee->hasTerm( eq[0] ) );
Assert( ee->hasTerm( eq[1] ) );
- if( ee->areDisequal( eq[0], eq[1], false ) ){
+ if( areDisequal( eq[0], eq[1] ) ){
Trace("quant-engine-ee-proc") << "processInferences : Conflict : " << eq << std::endl;
if( Trace.isOn("term-db-lemma") ){
Trace("term-db-lemma") << "Disequal terms, equal by normalization : " << eq[0] << " " << eq[1] << "!!!!" << std::endl;
@@ -1445,11 +1496,10 @@ bool EqualityQueryQuantifiersEngine::areEqual( Node a, Node b ){
}else{
eq::EqualityEngine* ee = getEngine();
if( ee->hasTerm( a ) && ee->hasTerm( b ) ){
- if( ee->areEqual( a, b ) ){
- return true;
- }
+ return ee->areEqual( a, b );
+ }else{
+ return false;
}
- return false;
}
}
@@ -1459,11 +1509,10 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){
}else{
eq::EqualityEngine* ee = getEngine();
if( ee->hasTerm( a ) && ee->hasTerm( b ) ){
- if( ee->areDisequal( a, b, false ) ){
- return true;
- }
+ return ee->areDisequal( a, b, false );
+ }else{
+ return a.isConst() && b.isConst();
}
- return false;
}
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 4ee66f9e7..1f4a04218 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -48,6 +48,7 @@ class InstantiationNotify {
public:
InstantiationNotify(){}
virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) = 0;
+ virtual void filterInstantiations() = 0;
};
namespace quantifiers {
@@ -156,8 +157,7 @@ private: //this information is reset during check
unsigned d_curr_effort_level;
/** are we in conflict */
bool d_conflict;
- /** number of lemmas we actually added this round (for debugging) */
- unsigned d_num_added_lemmas_round;
+ context::CDO< bool > d_conflict_c;
/** has added lemma this round */
bool d_hasAddedLemma;
private:
@@ -295,9 +295,9 @@ private:
bool removeInstantiationInternal( Node q, std::vector< Node >& terms );
/** set instantiation level attr */
static void setInstantiationLevelAttr( Node n, Node qn, uint64_t level );
+public:
/** flush lemmas */
void flushLemmas();
-public:
/** get instantiation */
Node getInstantiation( Node q, std::vector< Node >& vars, std::vector< Node >& terms, bool doVts = false );
/** get instantiation */
@@ -330,8 +330,6 @@ public:
bool inConflict() { return d_conflict; }
/** get number of waiting lemmas */
unsigned getNumLemmasWaiting() { return d_lemmas_waiting.size(); }
- /** get number of waiting lemmas */
- unsigned getNumLemmasAddedThisRound() { return d_num_added_lemmas_round; }
/** get needs check */
bool getInstWhenNeedsCheck( Theory::Effort e );
/** get user pat mode */
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index d7178a8c1..184553ba7 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -127,19 +127,11 @@ int RepSet::getNumRelevantGroundReps( TypeNode t ) {
}
void RepSet::toStream(std::ostream& out){
-#if 0
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- out << it->first << " : " << std::endl;
- for( int i=0; i<(int)it->second.size(); i++ ){
- out << " " << i << ": " << it->second[i] << std::endl;
- }
- }
-#else
for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
if( !it->first.isFunction() && !it->first.isPredicate() ){
out << "(" << it->first << " " << it->second.size();
out << " (";
- for( int i=0; i<(int)it->second.size(); i++ ){
+ for( unsigned i=0; i<it->second.size(); i++ ){
if( i>0 ){ out << " "; }
out << it->second[i];
}
@@ -147,7 +139,6 @@ void RepSet::toStream(std::ostream& out){
out << ")" << std::endl;
}
}
-#endif
}
@@ -157,10 +148,11 @@ RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe),
int RepSetIterator::domainSize( int i ) {
Assert(i>=0);
- if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){
- return d_domain[i].size();
+ int v = d_var_order[i];
+ if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
+ return d_domain[v].size();
}else{
- return d_domain[i][0];
+ return d_domain[v][0];
}
}
@@ -188,15 +180,15 @@ bool RepSetIterator::setFunctionDomain( Node op ){
bool RepSetIterator::initialize(){
Trace("rsi") << "Initialize rep set iterator..." << std::endl;
- for( size_t i=0; i<d_types.size(); i++ ){
+ for( unsigned v=0; v<d_types.size(); v++ ){
d_index.push_back( 0 );
//store default index order
- d_index_order.push_back( i );
- d_var_order[i] = i;
+ d_index_order.push_back( v );
+ d_var_order[v] = v;
//store default domain
d_domain.push_back( RepDomain() );
- TypeNode tn = d_types[i];
- Trace("rsi") << "Var #" << i << " is type " << tn << "..." << std::endl;
+ TypeNode tn = d_types[v];
+ Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl;
if( tn.isSort() ){
//must ensure uninterpreted type is non-empty.
if( !d_rep_set->hasType( tn ) ){
@@ -209,59 +201,59 @@ bool RepSetIterator::initialize(){
Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
d_rep_set->add( tn, var );
}
- }else if( tn.isInteger() ){
- bool inc = false;
- //check if it is bound
+ }else{
+ bool inc = true;
+ //check if it is bound by bounded integer module
if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
- if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
+ unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
+ if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
Trace("rsi") << " variable is bounded integer." << std::endl;
- d_enum_type.push_back( ENUM_RANGE );
- }else{
- inc = true;
+ d_enum_type.push_back( ENUM_INT_RANGE );
+ inc = false;
+ }else if( bvt==quantifiers::BoundedIntegers::BOUND_SET_MEMBER ){
+ Trace("rsi") << " variable is bounded by set membership." << std::endl;
+ d_enum_type.push_back( ENUM_SET_MEMBERS );
+ inc = false;
}
- }else{
- inc = true;
}
if( inc ){
//check if it is otherwise bound
- if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){
+ if( d_bounds[0].find( v )!=d_bounds[0].end() && d_bounds[1].find( v )!=d_bounds[1].end() ){
Trace("rsi") << " variable is bounded." << std::endl;
- d_enum_type.push_back( ENUM_RANGE );
+ d_enum_type.push_back( ENUM_INT_RANGE );
+ }else if( d_qe->getTermDatabase()->mayComplete( tn ) ){
+ Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
+ d_rep_set->complete( tn );
+ //must have succeeded
+ Assert( d_rep_set->hasType( tn ) );
}else{
Trace("rsi") << " variable cannot be bounded." << std::endl;
- Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
+ Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
d_incomplete = true;
}
}
- //enumerate if the sort is reasonably small
- }else if( d_qe->getTermDatabase()->mayComplete( tn ) ){
- Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
- d_rep_set->complete( tn );
- //must have succeeded
- Assert( d_rep_set->hasType( tn ) );
- }else{
- Trace("rsi") << " variable cannot be bounded." << std::endl;
- Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
- d_incomplete = true;
}
//if we have yet to determine the type of enumeration
- if( d_enum_type.size()<=i ){
+ if( d_enum_type.size()<=v ){
d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
if( d_rep_set->hasType( tn ) ){
- for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
- d_domain[i].push_back( j );
+ for( unsigned j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
+ d_domain[v].push_back( j );
}
}else{
+ Assert( d_incomplete );
return false;
}
}
}
//must set a variable index order based on bounded integers
- if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) {
+ if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
std::vector< int > varOrder;
- for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){
- varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i));
+ for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars( d_owner ); i++ ){
+ Node v = d_qe->getBoundedIntegers()->getBoundVar( d_owner, i );
+ Trace("bound-int-rsi") << " bound var #" << i << " is " << v << std::endl;
+ varOrder.push_back( d_qe->getTermDatabase()->getVariableNum( d_owner, v ) );
}
for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
@@ -283,14 +275,10 @@ bool RepSetIterator::initialize(){
Trace("bound-int-rsi") << indexOrder[i] << " ";
}
Trace("bound-int-rsi") << std::endl;
- setIndexOrder(indexOrder);
+ setIndexOrder( indexOrder );
}
//now reset the indices
- for (unsigned i=0; i<d_index.size(); i++) {
- if (!resetIndex(i, true)){
- break;
- }
- }
+ do_reset_increment( -1, true );
return true;
}
@@ -298,46 +286,40 @@ void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
d_index_order.clear();
d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
//make the d_var_order mapping
- for( int i=0; i<(int)d_index_order.size(); i++ ){
+ for( unsigned i=0; i<d_index_order.size(); i++ ){
d_var_order[d_index_order[i]] = i;
}
}
-/*
-void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
- d_domain.clear();
- d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
- //we are done if a domain is empty
- for( int i=0; i<(int)d_domain.size(); i++ ){
- if( d_domain[i].empty() ){
- d_index.clear();
- }
- }
-}
-*/
-bool RepSetIterator::resetIndex( int i, bool initial ) {
+
+int RepSetIterator::resetIndex( int i, bool initial ) {
d_index[i] = 0;
- int ii = d_index_order[i];
- Trace("bound-int-rsi") << "Reset " << i << " " << ii << " " << initial << std::endl;
+ int v = d_var_order[i];
+ Trace("bound-int-rsi") << "Reset " << i << ", var order = " << v << ", initial = " << initial << std::endl;
//determine the current range
- if( d_enum_type[ii]==ENUM_RANGE ){
- if( initial || ( d_qe->getBoundedIntegers() && !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][ii] ) ) ){
- Trace("bound-int-rsi") << "Getting range of " << d_owner[0][ii] << std::endl;
+ if( initial || ( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() &&
+ d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) &&
+ !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][v] ) ) ){
+ Trace("bound-int-rsi") << "Getting range of " << d_owner[0][v] << std::endl;
+ if( d_enum_type[v]==ENUM_INT_RANGE ){
Node actual_l;
Node l, u;
- if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
- d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][ii], this, l, u );
+ if( d_qe->getBoundedIntegers() ){
+ unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
+ if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
+ d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][v], this, l, u );
+ }
}
for( unsigned b=0; b<2; b++ ){
- if( d_bounds[b].find(ii)!=d_bounds[b].end() ){
- Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][ii] << std::endl;
- if( b==0 && (l.isNull() || d_bounds[b][ii].getConst<Rational>() > l.getConst<Rational>()) ){
+ if( d_bounds[b].find(v)!=d_bounds[b].end() ){
+ Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][v] << std::endl;
+ if( b==0 && (l.isNull() || d_bounds[b][v].getConst<Rational>() > l.getConst<Rational>()) ){
if( !l.isNull() ){
//bound was limited externally, record that the value lower bound is not equal to the term lower bound
- actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii], l );
+ actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v], l );
}
- l = d_bounds[b][ii];
- }else if( b==1 && (u.isNull() || d_bounds[b][ii].getConst<Rational>() <= u.getConst<Rational>()) ){
- u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii],
+ l = d_bounds[b][v];
+ }else if( b==1 && (u.isNull() || d_bounds[b][v].getConst<Rational>() <= u.getConst<Rational>()) ){
+ u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v],
NodeManager::currentNM()->mkConst( Rational(1) ) );
u = Rewriter::rewrite( u );
}
@@ -346,73 +328,109 @@ bool RepSetIterator::resetIndex( int i, bool initial ) {
if( l.isNull() || u.isNull() ){
//failed, abort the iterator
- d_index.clear();
- return false;
+ return -1;
}else{
- Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " to " << l << "..." << u << std::endl;
+ Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][v] << " to " << l << "..." << u << std::endl;
Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
- d_domain[ii].clear();
+ d_domain[v].clear();
Node tl = l;
Node tu = u;
- if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
- d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][ii], this, tl, tu );
+ if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) ){
+ d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][v], this, tl, tu );
}
- d_lower_bounds[ii] = tl;
+ d_lower_bounds[v] = tl;
if( !actual_l.isNull() ){
//if bound was limited externally, must consider the offset
- d_lower_bounds[ii] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
+ d_lower_bounds[v] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
}
- if( ra==NodeManager::currentNM()->mkConst(true) ){
+ if( ra==d_qe->getTermDatabase()->d_true ){
long rr = range.getConst<Rational>().getNumerator().getLong()+1;
Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl;
- d_domain[ii].push_back( (int)rr );
+ d_domain[v].push_back( (int)rr );
+ if( rr<=0 ){
+ return 0;
+ }
}else{
- Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][ii] << "." << std::endl;
- d_incomplete = true;
- d_domain[ii].push_back( 0 );
+ Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][v] << "." << std::endl;
+ return -1;
}
}
- }else{
- Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl;
+ }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
+ Assert( d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] )==quantifiers::BoundedIntegers::BOUND_SET_MEMBER );
+ Node srv = d_qe->getBoundedIntegers()->getSetRangeValue( d_owner, d_owner[0][v], this );
+ if( srv.isNull() ){
+ return -1;
+ }
+ Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
+ d_domain[v].clear();
+ d_setm_bounds[v].clear();
+ if( srv.getKind()!=EMPTYSET ){
+ //TODO: need term model, not value model
+ while( srv.getKind()==UNION ){
+ Assert( srv[1].getKind()==kind::SINGLETON );
+ d_setm_bounds[v].push_back( srv[1][0] );
+ srv = srv[0];
+ }
+ d_setm_bounds[v].push_back( srv[0] );
+ d_domain[v].push_back( d_setm_bounds[v].size() );
+ }else{
+ d_domain[v].push_back( 0 );
+ return 0;
+ }
}
}
- return true;
+ return 1;
}
-int RepSetIterator::increment2( int counter ){
+int RepSetIterator::increment2( int i ){
Assert( !isFinished() );
#ifdef DISABLE_EVAL_SKIP_MULTIPLE
- counter = (int)d_index.size()-1;
+ i = (int)d_index.size()-1;
#endif
//increment d_index
- if( counter>=0){
- Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ if( i>=0){
+ Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
}
- while( counter>=0 && d_index[counter]>=(int)(domainSize(counter)-1) ){
- counter--;
- if( counter>=0){
- Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ while( i>=0 && d_index[i]>=(int)(domainSize(i)-1) ){
+ i--;
+ if( i>=0){
+ Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
}
}
- if( counter==-1 ){
+ if( i==-1 ){
d_index.clear();
+ return -1;
}else{
- d_index[counter]++;
- bool emptyDomain = false;
- for( int i=(int)d_index.size()-1; i>counter; i-- ){
- if (!resetIndex(i)){
- break;
- }else if( domainSize(i)<=0 ){
- emptyDomain = true;
- }
+ Trace("rsi-debug") << "increment " << i << std::endl;
+ d_index[i]++;
+ return do_reset_increment( i );
+ }
+}
+
+int RepSetIterator::do_reset_increment( int i, bool initial ) {
+ bool emptyDomain = false;
+ for( unsigned ii=(i+1); ii<d_index.size(); ii++ ){
+ int ri_res = resetIndex( ii, initial );
+ if( ri_res==-1 ){
+ //failed
+ d_index.clear();
+ d_incomplete = true;
+ break;
+ }else if( ri_res==0 ){
+ emptyDomain = true;
}
+ //force next iteration if currently an empty domain
if( emptyDomain ){
- Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl;
- return increment();
+ d_index[ii] = domainSize(ii)-1;
}
}
- return counter;
+ if( emptyDomain ){
+ Trace("rsi-debug") << "This is an empty domain, increment." << std::endl;
+ return increment();
+ }else{
+ return i;
+ }
}
int RepSetIterator::increment(){
@@ -427,33 +445,38 @@ bool RepSetIterator::isFinished(){
return d_index.empty();
}
-Node RepSetIterator::getTerm( int i ){
- Trace("rsi-debug") << "rsi : get term " << i << ", index order = " << d_index_order[i] << std::endl;
- //int index = d_index_order[i];
- int index = i;
- if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){
- TypeNode tn = d_types[index];
+Node RepSetIterator::getCurrentTerm( int v ){
+ Trace("rsi-debug") << "rsi : get term " << v << ", index order = " << d_index_order[v] << std::endl;
+ int ii = d_index_order[v];
+ int curr = d_index[ii];
+ if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
+ TypeNode tn = d_types[v];
Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
- return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
+ Assert( 0<=d_domain[v][curr] && d_domain[v][curr]<(int)d_rep_set->d_type_reps[tn].size() );
+ return d_rep_set->d_type_reps[tn][d_domain[v][curr]];
+ }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
+ Assert( 0<=curr && curr<(int)d_setm_bounds[v].size() );
+ return d_setm_bounds[v][curr];
}else{
- Trace("rsi-debug") << "Get, with offset : " << index << " " << d_lower_bounds[index] << " " << d_index[index] << std::endl;
- Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[index],
- NodeManager::currentNM()->mkConst( Rational(d_index[index]) ) );
+ Trace("rsi-debug") << "Get, with offset : " << v << " " << d_lower_bounds[v] << " " << curr << std::endl;
+ Assert( !d_lower_bounds[v].isNull() );
+ Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[v], NodeManager::currentNM()->mkConst( Rational(curr) ) );
t = Rewriter::rewrite( t );
return t;
}
}
void RepSetIterator::debugPrint( const char* c ){
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;
+ for( unsigned v=0; v<d_index.size(); v++ ){
+ Debug( c ) << v << " : " << getCurrentTerm( v ) << std::endl;
}
}
void RepSetIterator::debugPrintSmall( const char* c ){
Debug( c ) << "RI: ";
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";
+ for( unsigned v=0; v<d_index.size(); v++ ){
+ Debug( c ) << v << ": " << getCurrentTerm( v ) << " ";
}
Debug( c ) << std::endl;
}
+
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 08fc7dd52..ee927de86 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -64,22 +64,42 @@ class RepSetIterator {
public:
enum {
ENUM_DOMAIN_ELEMENTS,
- ENUM_RANGE,
+ ENUM_INT_RANGE,
+ ENUM_SET_MEMBERS,
};
private:
QuantifiersEngine * d_qe;
//initialize function
bool initialize();
- //for enum ranges
+ //for int ranges
std::map< int, Node > d_lower_bounds;
+ //for set ranges
+ std::map< int, std::vector< Node > > d_setm_bounds;
//domain size
int domainSize( int i );
//node this is rep set iterator is for
Node d_owner;
- //reset index
- bool resetIndex( int i, bool initial = false );
+ //reset index, 1:success, 0:empty, -1:fail
+ int resetIndex( int i, bool initial = false );
/** set index order */
void setIndexOrder( std::vector< int >& indexOrder );
+ /** do reset increment the iterator at index=counter */
+ int do_reset_increment( int counter, bool initial = false );
+ //ordering for variables we are indexing over
+ // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
+ // then we consider instantiations in this order:
+ // a/x a/y a/z
+ // a/x b/y a/z
+ // b/x a/y a/z
+ // b/x b/y a/z
+ // ...
+ std::vector< int > d_index_order;
+ //variables to index they are considered at
+ // for example, if d_index_order = { 2, 0, 1 }
+ // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
+ std::map< int, int > d_var_order;
+ //are we only considering a strict subset of the domain of the quantifier?
+ bool d_incomplete;
public:
RepSetIterator( QuantifiersEngine * qe, RepSet* rs );
~RepSetIterator(){}
@@ -92,43 +112,34 @@ public:
RepSet* d_rep_set;
//enumeration type?
std::vector< int > d_enum_type;
- //index we are considering
+ //current tuple we are considering
std::vector< int > d_index;
//types we are considering
std::vector< TypeNode > d_types;
//domain we are considering
std::vector< RepDomain > d_domain;
- //are we only considering a strict subset of the domain of the quantifier?
- bool d_incomplete;
- //ordering for variables we are indexing over
- // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
- // then we consider instantiations in this order:
- // a/x a/y a/z
- // a/x b/y a/z
- // b/x a/y a/z
- // b/x b/y a/z
- // ...
- std::vector< int > d_index_order;
- //variables to index they are considered at
- // for example, if d_index_order = { 2, 0, 1 }
- // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
- std::map< int, int > d_var_order;
//intervals
std::map< int, Node > d_bounds[2];
public:
/** increment the iterator at index=counter */
- int increment2( int counter );
+ int increment2( int i );
/** increment the iterator */
int increment();
/** is the iterator finished? */
bool isFinished();
/** get the i_th term we are considering */
- Node getTerm( int i );
+ Node getCurrentTerm( int v );
/** get the number of terms we are considering */
int getNumTerms() { return (int)d_index_order.size(); }
/** debug print */
void debugPrint( const char* c );
void debugPrintSmall( const char* c );
+ //get index order, returns var #
+ int getIndexOrder( int v ) { return d_index_order[v]; }
+ //get variable order, returns index #
+ int getVariableOrder( int i ) { return d_var_order[i]; }
+ //is incomplete
+ bool isIncomplete() { return d_incomplete; }
};/* class RepSetIterator */
}/* CVC4::theory namespace */
diff --git a/src/theory/sep/kinds b/src/theory/sep/kinds
new file mode 100644
index 000000000..6c4ad33db
--- /dev/null
+++ b/src/theory/sep/kinds
@@ -0,0 +1,37 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+theory THEORY_SEP ::CVC4::theory::sep::TheorySep "theory/sep/theory_sep.h"
+typechecker "theory/sep/theory_sep_type_rules.h"
+
+properties polite stable-infinite parametric
+properties check propagate presolve getNextDecisionRequest
+
+rewriter ::CVC4::theory::sep::TheorySepRewriter "theory/sep/theory_sep_rewriter.h"
+
+# constants
+constant SEP_NIL_REF \
+ ::CVC4::NilRef \
+ ::CVC4::NilRefHashFunction \
+ "expr/sepconst.h" \
+ "the nil reference constant; payload is an instance of the CVC4::NilRef class"
+
+variable SEP_NIL "separation nil"
+
+operator SEP_EMP 1 "separation empty heap"
+operator SEP_PTO 2 "points to relation"
+operator SEP_STAR 2: "separation star"
+operator SEP_WAND 2 "separation magic wand"
+operator SEP_LABEL 2 "separation label"
+
+typerule SEP_NIL_REF ::CVC4::theory::sep::SepNilRefTypeRule
+typerule SEP_EMP ::CVC4::theory::sep::SepEmpTypeRule
+typerule SEP_PTO ::CVC4::theory::sep::SepPtoTypeRule
+typerule SEP_STAR ::CVC4::theory::sep::SepStarTypeRule
+typerule SEP_WAND ::CVC4::theory::sep::SepWandTypeRule
+typerule SEP_LABEL ::CVC4::theory::sep::SepLabelTypeRule
+
+endtheory
diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp
new file mode 100644
index 000000000..836a04afa
--- /dev/null
+++ b/src/theory/sep/theory_sep.cpp
@@ -0,0 +1,1534 @@
+/********************* */
+/*! \file theory_sep.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of the theory of sep.
+ **
+ ** Implementation of the theory of sep.
+ **/
+
+
+#include "theory/sep/theory_sep.h"
+#include "theory/valuation.h"
+#include "expr/kind.h"
+#include <map>
+#include "theory/rewriter.h"
+#include "theory/theory_model.h"
+#include "options/sep_options.h"
+#include "options/smt_options.h"
+#include "smt/logic_exception.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+TheorySep::TheorySep(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
+ Theory(THEORY_SEP, c, u, out, valuation, logicInfo),
+ d_notify(*this),
+ d_equalityEngine(d_notify, c, "theory::sep::TheorySep", true),
+ d_conflict(c, false),
+ d_reduce(u),
+ d_infer(c),
+ d_infer_exp(c),
+ d_spatial_assertions(c)
+{
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::SEP_PTO);
+ //d_equalityEngine.addFunctionKind(kind::SEP_STAR);
+}
+
+TheorySep::~TheorySep() {
+ for( std::map< Node, HeapAssertInfo * >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){
+ delete it->second;
+ }
+}
+
+void TheorySep::setMasterEqualityEngine(eq::EqualityEngine* eq) {
+ d_equalityEngine.setMasterEqualityEngine(eq);
+}
+
+Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) {
+ if( assumptions.empty() ){
+ return d_true;
+ }else if( assumptions.size()==1 ){
+ return assumptions[0];
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::AND, assumptions );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// PREPROCESSING
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+Node TheorySep::ppRewrite(TNode term) {
+ Trace("sep-pp") << "ppRewrite : " << term << std::endl;
+/*
+ Node s_atom = term.getKind()==kind::NOT ? term[0] : term;
+ if( s_atom.getKind()==kind::SEP_PTO || s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_EMP ){
+ //get the reference type (will compute d_type_references)
+ int card = 0;
+ TypeNode tn = getReferenceType( s_atom, card );
+ Trace("sep-pp") << " reference type is " << tn << ", card is " << card << std::endl;
+ }
+*/
+ return term;
+}
+
+//must process assertions at preprocess so that quantified assertions are processed properly
+void TheorySep::processAssertions( std::vector< Node >& assertions ) {
+ std::map< Node, bool > visited;
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ processAssertion( assertions[i], visited );
+ }
+}
+
+void TheorySep::processAssertion( Node n, std::map< Node, bool >& visited ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_EMP ){
+ //get the reference type (will compute d_type_references)
+ int card = 0;
+ TypeNode tn = getReferenceType( n, card );
+ Trace("sep-pp") << " reference type is " << tn << ", card is " << card << std::endl;
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ processAssertion( n[i], visited );
+ }
+ }
+ }
+}
+
+Theory::PPAssertStatus TheorySep::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
+
+ return PP_ASSERT_STATUS_UNSOLVED;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// T-PROPAGATION / REGISTRATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+bool TheorySep::propagate(TNode literal)
+{
+ Debug("sep") << "TheorySep::propagate(" << literal << ")" << std::endl;
+ // If already in conflict, no more propagation
+ if (d_conflict) {
+ Debug("sep") << "TheorySep::propagate(" << literal << "): already in conflict" << std::endl;
+ return false;
+ }
+ bool ok = d_out->propagate(literal);
+ if (!ok) {
+ d_conflict = true;
+ }
+ return ok;
+}/* TheorySep::propagate(TNode) */
+
+
+void TheorySep::explain(TNode literal, std::vector<TNode>& assumptions) {
+ if( literal.getKind()==kind::SEP_LABEL ||
+ ( literal.getKind()==kind::NOT && literal[0].getKind()==kind::SEP_LABEL ) ){
+ //labelled assertions are never given to equality engine and should only come from the outside
+ assumptions.push_back( literal );
+ }else{
+ // Do the work
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+ if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+ d_equalityEngine.explainEquality( atom[0], atom[1], polarity, assumptions, NULL );
+ } else {
+ d_equalityEngine.explainPredicate( atom, polarity, assumptions );
+ }
+ }
+}
+
+void TheorySep::preRegisterTermRec(TNode t, std::map< TNode, bool >& visited ) {
+ if( visited.find( t )==visited.end() ){
+ visited[t] = true;
+ Trace("sep-prereg-debug") << "Preregister : " << t << std::endl;
+ if( t.getKind()==kind::SEP_NIL ){
+ Trace("sep-prereg") << "Preregister nil : " << t << std::endl;
+ //per type, all nil variable references are equal
+ TypeNode tn = t.getType();
+ std::map< TypeNode, Node >::iterator it = d_nil_ref.find( tn );
+ if( it==d_nil_ref.end() ){
+ Trace("sep-prereg") << "...set as reference." << std::endl;
+ d_nil_ref[tn] = t;
+ }else{
+ Node nr = it->second;
+ Trace("sep-prereg") << "...reference is " << nr << "." << std::endl;
+ if( t!=nr ){
+ if( d_reduce.find( t )==d_reduce.end() ){
+ d_reduce.insert( t );
+ Node lem = NodeManager::currentNM()->mkNode( tn.isBoolean() ? kind::IFF : kind::EQUAL, t, nr );
+ Trace("sep-lemma") << "Sep::Lemma: nil ref eq : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ preRegisterTermRec( t[i], visited );
+ }
+ }
+ }
+}
+
+void TheorySep::preRegisterTerm(TNode term){
+ std::map< TNode, bool > visited;
+ preRegisterTermRec( term, visited );
+}
+
+
+void TheorySep::propagate(Effort e){
+
+}
+
+
+Node TheorySep::explain(TNode literal)
+{
+ Debug("sep") << "TheorySep::explain(" << literal << ")" << std::endl;
+ std::vector<TNode> assumptions;
+ explain(literal, assumptions);
+ return mkAnd(assumptions);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// SHARING
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::addSharedTerm(TNode t) {
+ Debug("sep") << "TheorySep::addSharedTerm(" << t << ")" << std::endl;
+ d_equalityEngine.addTriggerTerm(t, THEORY_SEP);
+}
+
+
+EqualityStatus TheorySep::getEqualityStatus(TNode a, TNode b) {
+ Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ else if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
+}
+
+
+void TheorySep::computeCareGraph() {
+ Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl;
+ for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) {
+ TNode a = d_sharedTerms[i];
+ TypeNode aType = a.getType();
+ for (unsigned j = i + 1; j < d_sharedTerms.size(); ++ j) {
+ TNode b = d_sharedTerms[j];
+ if (b.getType() != aType) {
+ // We don't care about the terms of different types
+ continue;
+ }
+ switch (d_valuation.getEqualityStatus(a, b)) {
+ case EQUALITY_TRUE_AND_PROPAGATED:
+ case EQUALITY_FALSE_AND_PROPAGATED:
+ // If we know about it, we should have propagated it, so we can skip
+ break;
+ default:
+ // Let's split on it
+ addCarePair(a, b);
+ break;
+ }
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// MODEL GENERATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::collectModelInfo( TheoryModel* m, bool fullModel )
+{
+ // Send the equality engine information to the model
+ m->assertEqualityEngine( &d_equalityEngine );
+
+ if( fullModel ){
+ for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){
+ Trace("sep-model") << "; Model for heap, type = " << it->first << " : " << std::endl;
+ computeLabelModel( it->second, d_tmodel );
+ if( d_label_model[it->second].d_heap_locs_model.empty() ){
+ Trace("sep-model") << "; [empty]" << std::endl;
+ }else{
+ for( unsigned j=0; j<d_label_model[it->second].d_heap_locs_model.size(); j++ ){
+ Assert( d_label_model[it->second].d_heap_locs_model[j].getKind()==kind::SINGLETON );
+ Node l = d_label_model[it->second].d_heap_locs_model[j][0];
+ Trace("sep-model") << "; " << l << " -> ";
+ if( d_pto_model[l].isNull() ){
+ Trace("sep-model") << "_";
+ }else{
+ Trace("sep-model") << d_pto_model[l];
+ }
+ Trace("sep-model") << std::endl;
+ }
+ }
+ Node nil = getNilRef( it->first );
+ Node vnil = d_valuation.getModel()->getRepresentative( nil );
+ Trace("sep-model") << "; sep.nil = " << vnil << std::endl;
+ Trace("sep-model") << std::endl;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// NOTIFICATIONS
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::presolve() {
+ Trace("sep-pp") << "Presolving" << std::endl;
+ //TODO: cleanup if incremental?
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// MAIN SOLVER
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheorySep::check(Effort e) {
+ if (done() && !fullEffort(e) && e != EFFORT_LAST_CALL) {
+ return;
+ }
+
+ getOutputChannel().spendResource(options::theoryCheckStep());
+
+ TimerStat::CodeTimer checkTimer(d_checkTime);
+ Trace("sep-check") << "Sep::check(): " << e << endl;
+
+ while( !done() && !d_conflict ){
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+
+ Trace("sep-assert") << "TheorySep::check(): processing " << fact << std::endl;
+
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if( atom.getKind()==kind::SEP_EMP ){
+ TypeNode tn = atom[0].getType();
+ if( d_emp_arg.find( tn )==d_emp_arg.end() ){
+ d_emp_arg[tn] = atom[0];
+ }else{
+ //normalize argument TODO
+ }
+ }
+ TNode s_atom = atom.getKind()==kind::SEP_LABEL ? atom[0] : atom;
+ TNode s_lbl = atom.getKind()==kind::SEP_LABEL ? atom[1] : TNode::null();
+ bool is_spatial = s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_PTO || s_atom.getKind()==kind::SEP_EMP;
+ if( is_spatial && s_lbl.isNull() ){
+ if( d_reduce.find( fact )==d_reduce.end() ){
+ Trace("sep-lemma-debug") << "Reducing unlabelled assertion " << atom << std::endl;
+ d_reduce.insert( fact );
+ //introduce top-level label, add iff
+ int card;
+ TypeNode refType = getReferenceType( s_atom, card );
+ Trace("sep-lemma-debug") << "...reference type is : " << refType << ", card is " << card << std::endl;
+ Node b_lbl = getBaseLabel( refType );
+ Node s_atom_new = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, s_atom, b_lbl );
+ Node lem;
+ if( polarity ){
+ lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom.negate(), s_atom_new );
+ }else{
+ lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom, s_atom_new.negate() );
+ }
+ Trace("sep-lemma-debug") << "Sep::Lemma : base reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
+ }else{
+ //do reductions
+ if( is_spatial ){
+ if( d_reduce.find( fact )==d_reduce.end() ){
+ Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl;
+ d_reduce.insert( fact );
+ Node conc;
+ std::map< Node, Node >::iterator its = d_red_conc[s_lbl].find( s_atom );
+ if( its==d_red_conc[s_lbl].end() ){
+ //make conclusion based on type of assertion
+ if( s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND ){
+ std::vector< Node > children;
+ std::vector< Node > c_lems;
+ int card;
+ TypeNode tn = getReferenceType( s_atom, card );
+ Assert( d_reference_bound.find( tn )!=d_reference_bound.end() );
+ c_lems.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, s_lbl, d_reference_bound[tn] ) );
+ if( options::sepPreciseBound() ){
+ //more precise bound
+ Trace("sep-bound") << "Propagate Bound(" << s_lbl << ") = ";
+ Assert( d_lbl_reference_bound.find( s_lbl )!=d_lbl_reference_bound.end() );
+ for( unsigned j=0; j<d_lbl_reference_bound[s_lbl].size(); j++ ){
+ Trace("sep-bound") << d_lbl_reference_bound[s_lbl][j] << " ";
+ }
+ Trace("sep-bound") << std::endl << " to children of " << s_atom << std::endl;
+ //int rb_start = 0;
+ for( unsigned j=0; j<s_atom.getNumChildren(); j++ ){
+ int ccard = 0;
+ getReferenceType( s_atom, ccard, j );
+ Node c_lbl = getLabel( s_atom, j, s_lbl );
+ Trace("sep-bound") << " for " << c_lbl << ", card = " << ccard << " : ";
+ std::vector< Node > bound_loc;
+ bound_loc.insert( bound_loc.end(), d_references[s_atom][j].begin(), d_references[s_atom][j].end() );
+/* //this is unsound
+ for( int k=0; k<ccard; k++ ){
+ Assert( rb_start<(int)d_lbl_reference_bound[s_lbl].size() );
+ d_lbl_reference_bound[c_lbl].push_back( d_lbl_reference_bound[s_lbl][rb_start] );
+ Trace("sep-bound") << d_lbl_reference_bound[s_lbl][rb_start] << " ";
+ bound_loc.push_back( d_lbl_reference_bound[s_lbl][rb_start] );
+ rb_start++;
+ }
+*/
+ //carry all locations for now
+ bound_loc.insert( bound_loc.end(), d_lbl_reference_bound[s_lbl].begin(), d_lbl_reference_bound[s_lbl].end() );
+ Trace("sep-bound") << std::endl;
+ Node bound_v = mkUnion( tn, bound_loc );
+ Trace("sep-bound") << " ...bound value : " << bound_v << std::endl;
+ children.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, c_lbl, bound_v ) );
+ }
+ Trace("sep-bound") << "Done propagate Bound(" << s_lbl << ")" << std::endl;
+ }
+ std::vector< Node > labels;
+ getLabelChildren( s_atom, s_lbl, children, labels );
+ Node empSet = NodeManager::currentNM()->mkConst(EmptySet(s_lbl.getType().toType()));
+ Assert( children.size()>1 );
+ if( s_atom.getKind()==kind::SEP_STAR ){
+ //reduction for heap : union, pairwise disjoint
+ Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, labels[0], labels[1] );
+ for( unsigned i=2; i<labels.size(); i++ ){
+ ulem = NodeManager::currentNM()->mkNode( kind::UNION, ulem, labels[i] );
+ }
+ ulem = s_lbl.eqNode( ulem );
+ Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, union : " << ulem << std::endl;
+ c_lems.push_back( ulem );
+ for( unsigned i=0; i<labels.size(); i++ ){
+ for( unsigned j=(i+1); j<labels.size(); j++ ){
+ Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, labels[i], labels[j] );
+ Node ilem = s.eqNode( empSet );
+ Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, disjoint : " << ilem << std::endl;
+ c_lems.push_back( ilem );
+ }
+ }
+ }else{
+ Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, s_lbl, labels[0] );
+ ulem = ulem.eqNode( labels[1] );
+ Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, union : " << ulem << std::endl;
+ c_lems.push_back( ulem );
+ Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, s_lbl, labels[0] );
+ Node ilem = s.eqNode( empSet );
+ Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl;
+ c_lems.push_back( ilem );
+ }
+ //send out definitional lemmas for introduced sets
+ for( unsigned j=0; j<c_lems.size(); j++ ){
+ Trace("sep-lemma") << "Sep::Lemma : definition : " << c_lems[j] << std::endl;
+ d_out->lemma( c_lems[j] );
+ }
+ //children.insert( children.end(), c_lems.begin(), c_lems.end() );
+ conc = NodeManager::currentNM()->mkNode( kind::AND, children );
+ }else if( s_atom.getKind()==kind::SEP_PTO ){
+ Node ss = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] );
+ if( s_lbl!=ss ){
+ conc = s_lbl.eqNode( ss );
+ }
+ Node ssn = NodeManager::currentNM()->mkNode( kind::EQUAL, s_atom[0], getNilRef(s_atom[0].getType()) ).negate();
+ conc = conc.isNull() ? ssn : NodeManager::currentNM()->mkNode( kind::AND, conc, ssn );
+ }else{
+ //labeled emp should be rewritten
+ Assert( false );
+ }
+ d_red_conc[s_lbl][s_atom] = conc;
+ }else{
+ conc = its->second;
+ }
+ if( !conc.isNull() ){
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( !use_polarity ){
+ // introduce guard, assert positive version
+ Trace("sep-lemma-debug") << "Negated spatial constraint asserted to sep theory: " << fact << std::endl;
+ Node lit = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+ lit = getValuation().ensureLiteral( lit );
+ d_neg_guard[s_lbl][s_atom] = lit;
+ Trace("sep-lemma-debug") << "Neg guard : " << s_lbl << " " << s_atom << " " << lit << std::endl;
+ AlwaysAssert( !lit.isNull() );
+ d_out->requirePhase( lit, true );
+ d_neg_guards.push_back( lit );
+ d_guard_to_assertion[lit] = s_atom;
+ //Node lem = NodeManager::currentNM()->mkNode( kind::IFF, lit, conc );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit.negate(), conc );
+ Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }else{
+ //reduce based on implication
+ Node ant = atom;
+ if( polarity ){
+ ant = atom.negate();
+ }
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, ant, conc );
+ Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl;
+ d_out->lemma( lem );
+ }
+ }else{
+ Trace("sep-lemma-debug") << "Trivial conclusion, do not add lemma." << std::endl;
+ }
+ }
+ }
+ //assert to equality engine
+ if( !is_spatial ){
+ Trace("sep-assert") << "Asserting " << atom << ", pol = " << polarity << " to EE..." << std::endl;
+ if( s_atom.getKind()==kind::EQUAL ){
+ d_equalityEngine.assertEquality(atom, polarity, fact);
+ }else{
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ }
+ Trace("sep-assert") << "Done asserting " << atom << " to EE." << std::endl;
+ }else if( s_atom.getKind()==kind::SEP_PTO ){
+ Node pto_lbl = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] );
+ if( polarity && s_lbl!=pto_lbl ){
+ //also propagate equality
+ Node eq = s_lbl.eqNode( pto_lbl );
+ Trace("sep-assert") << "Asserting implied equality " << eq << " to EE..." << std::endl;
+ d_equalityEngine.assertEquality(eq, true, fact);
+ Trace("sep-assert") << "Done asserting implied equality " << eq << " to EE." << std::endl;
+ }
+ //associate the equivalence class of the lhs with this pto
+ Node r = getRepresentative( s_lbl );
+ HeapAssertInfo * ei = getOrMakeEqcInfo( r, true );
+ addPto( ei, r, atom, polarity );
+ }
+ //maybe propagate
+ doPendingFacts();
+ //add to spatial assertions
+ if( !d_conflict && is_spatial ){
+ d_spatial_assertions.push_back( fact );
+ }
+ }
+ }
+
+ if( e == EFFORT_LAST_CALL && !d_conflict && !d_valuation.needCheck() ){
+ Trace("sep-process") << "Checking heap at full effort..." << std::endl;
+ d_label_model.clear();
+ d_tmodel.clear();
+ d_pto_model.clear();
+ Trace("sep-process") << "---Locations---" << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator itt = d_type_references_all.begin(); itt != d_type_references_all.end(); ++itt ){
+ for( unsigned k=0; k<itt->second.size(); k++ ){
+ Node t = itt->second[k];
+ Trace("sep-process") << " " << t << " = ";
+ if( d_valuation.getModel()->hasTerm( t ) ){
+ Node v = d_valuation.getModel()->getRepresentative( t );
+ Trace("sep-process") << v << std::endl;
+ d_tmodel[v] = t;
+ }else{
+ Trace("sep-process") << "?" << std::endl;
+ }
+ }
+ }
+ Trace("sep-process") << "---" << std::endl;
+ //build positive/negative assertion lists for labels
+ std::map< Node, bool > assert_active;
+ //get the inactive assertions
+ std::map< Node, std::vector< Node > > lbl_to_assertions;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ lbl_to_assertions[s_lbl].push_back( fact );
+ //check whether assertion is active : either polarity=true, or guard is not asserted false
+ assert_active[fact] = true;
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( use_polarity ){
+ if( s_atom.getKind()==kind::SEP_PTO ){
+ Node vv = d_valuation.getModel()->getRepresentative( s_atom[0] );
+ if( d_pto_model.find( vv )==d_pto_model.end() ){
+ Trace("sep-inst") << "Pto : " << s_atom[0] << " (" << vv << ") -> " << s_atom[1] << std::endl;
+ d_pto_model[vv] = s_atom[1];
+ }
+ }
+ }else{
+ if( d_neg_guard[s_lbl].find( s_atom )!=d_neg_guard[s_lbl].end() ){
+ //check if the guard is asserted positively
+ Node guard = d_neg_guard[s_lbl][s_atom];
+ bool value;
+ if( getValuation().hasSatValue( guard, value ) ) {
+ assert_active[fact] = value;
+ }
+ }
+ }
+ }
+ //(recursively) set inactive sub-assertions
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ if( !assert_active[fact] ){
+ setInactiveAssertionRec( fact, lbl_to_assertions, assert_active );
+ }
+ }
+ //set up model information based on active assertions
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ if( assert_active[fact] ){
+ computeLabelModel( s_lbl, d_tmodel );
+ }
+ }
+ //debug print
+ if( Trace.isOn("sep-process") ){
+ Trace("sep-process") << "--- Current spatial assertions : " << std::endl;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ Trace("sep-process") << " " << fact;
+ if( !assert_active[fact] ){
+ Trace("sep-process") << " [inactive]";
+ }
+ Trace("sep-process") << std::endl;
+ }
+ Trace("sep-process") << "---" << std::endl;
+ }
+ if(Trace.isOn("sep-eqc")) {
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ Trace("sep-eqc") << "EQC:" << std::endl;
+ while( !eqcs2_i.isFinished() ){
+ Node eqc = (*eqcs2_i);
+ eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ Trace("sep-eqc") << "Eqc( " << eqc << " ) : { ";
+ while( !eqc2_i.isFinished() ) {
+ if( (*eqc2_i)!=eqc ){
+ Trace("sep-eqc") << (*eqc2_i) << " ";
+ }
+ ++eqc2_i;
+ }
+ Trace("sep-eqc") << " } " << std::endl;
+ ++eqcs2_i;
+ }
+ Trace("sep-eqc") << std::endl;
+ }
+
+ if( options::sepCheckNeg() ){
+ //get active labels
+ std::map< Node, bool > active_lbl;
+ if( options::sepMinimalRefine() ){
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ if( !use_polarity ){
+ Assert( assert_active.find( fact )!=assert_active.end() );
+ if( assert_active[fact] ){
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_lbl = atom[1];
+ if( d_label_map[s_atom].find( s_lbl )!=d_label_map[s_atom].end() ){
+ Trace("sep-process-debug") << "Active lbl : " << s_lbl << std::endl;
+ active_lbl[s_lbl] = true;
+ }
+ }
+ }
+ }
+ }
+
+ //process spatial assertions
+ bool addedLemma = false;
+ bool needAddLemma = false;
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+
+ bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
+ Trace("sep-process-debug") << " check atom : " << s_atom << " use polarity " << use_polarity << std::endl;
+ if( !use_polarity ){
+ Assert( assert_active.find( fact )!=assert_active.end() );
+ if( assert_active[fact] ){
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_lbl = atom[1];
+ Trace("sep-process") << "--> Active negated atom : " << s_atom << ", lbl = " << s_lbl << std::endl;
+ //add refinement lemma
+ if( d_label_map[s_atom].find( s_lbl )!=d_label_map[s_atom].end() ){
+ needAddLemma = true;
+ int card;
+ TypeNode tn = getReferenceType( s_atom, card );
+ tn = NodeManager::currentNM()->mkSetType(tn);
+ //tn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(tn));
+ Node o_b_lbl_mval = d_label_model[s_lbl].getValue( tn );
+ Trace("sep-process") << " Model for " << s_lbl << " : " << o_b_lbl_mval << std::endl;
+
+ //get model values
+ std::map< int, Node > mvals;
+ for( std::map< int, Node >::iterator itl = d_label_map[s_atom][s_lbl].begin(); itl != d_label_map[s_atom][s_lbl].end(); ++itl ){
+ Node sub_lbl = itl->second;
+ int sub_index = itl->first;
+ computeLabelModel( sub_lbl, d_tmodel );
+ Node lbl_mval = d_label_model[sub_lbl].getValue( tn );
+ Trace("sep-process-debug") << " child " << sub_index << " : " << sub_lbl << ", mval = " << lbl_mval << std::endl;
+ mvals[sub_index] = lbl_mval;
+ }
+
+ // Now, assert model-instantiated implication based on the negation
+ Assert( d_label_model.find( s_lbl )!=d_label_model.end() );
+ std::vector< Node > conc;
+ bool inst_success = true;
+ if( options::sepExp() ){
+ //old refinement lemmas
+ for( std::map< int, Node >::iterator itl = d_label_map[s_atom][s_lbl].begin(); itl != d_label_map[s_atom][s_lbl].end(); ++itl ){
+ int sub_index = itl->first;
+ std::map< Node, Node > visited;
+ Node c = applyLabel( s_atom[itl->first], mvals[sub_index], visited );
+ Trace("sep-process-debug") << " applied inst : " << c << std::endl;
+ if( s_atom.getKind()==kind::SEP_STAR || sub_index==0 ){
+ conc.push_back( c.negate() );
+ }else{
+ conc.push_back( c );
+ }
+ }
+ }else{
+ //new refinement
+ std::map< Node, Node > visited;
+ Node inst = instantiateLabel( s_atom, s_lbl, s_lbl, o_b_lbl_mval, visited, d_pto_model, d_tmodel, tn, active_lbl );
+ Trace("sep-inst-debug") << " applied inst : " << inst << std::endl;
+ if( inst.isNull() ){
+ inst_success = false;
+ }else{
+ inst = Rewriter::rewrite( inst );
+ if( inst==( polarity ? d_true : d_false ) ){
+ inst_success = false;
+ }
+ conc.push_back( polarity ? inst : inst.negate() );
+ }
+ }
+ if( inst_success ){
+ std::vector< Node > lemc;
+ Node pol_atom = atom;
+ if( polarity ){
+ pol_atom = atom.negate();
+ }
+ lemc.push_back( pol_atom );
+ //lemc.push_back( s_lbl.eqNode( o_b_lbl_mval ).negate() );
+ //lemc.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, o_b_lbl_mval, s_lbl ).negate() );
+ lemc.insert( lemc.end(), conc.begin(), conc.end() );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lemc );
+ if( std::find( d_refinement_lem[s_atom][s_lbl].begin(), d_refinement_lem[s_atom][s_lbl].end(), lem )==d_refinement_lem[s_atom][s_lbl].end() ){
+ d_refinement_lem[s_atom][s_lbl].push_back( lem );
+ Trace("sep-process") << "-----> refinement lemma (#" << d_refinement_lem[s_atom][s_lbl].size() << ") : " << lem << std::endl;
+ Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : " << lem << std::endl;
+ d_out->lemma( lem );
+ addedLemma = true;
+ }else{
+ Trace("sep-process") << "*** repeated refinement lemma : " << lem << std::endl;
+ }
+ }
+ }else{
+ Trace("sep-process-debug") << " no children." << std::endl;
+ Assert( s_atom.getKind()==kind::SEP_PTO );
+ }
+ }else{
+ Trace("sep-process-debug") << "--> inactive negated assertion " << s_atom << std::endl;
+ }
+ }
+ }
+ if( !addedLemma ){
+ if( needAddLemma ){
+ Trace("sep-process") << "WARNING : could not find refinement lemma!!!" << std::endl;
+ Assert( false );
+ d_out->setIncomplete();
+ }
+ }
+ }
+ }
+ Trace("sep-check") << "Sep::check(): " << e << " done, conflict=" << d_conflict.get() << endl;
+}
+
+
+Node TheorySep::getNextDecisionRequest() {
+ for( unsigned i=0; i<d_neg_guards.size(); i++ ){
+ Node g = d_neg_guards[i];
+ bool success = true;
+ if( getLogicInfo().isQuantified() ){
+ Assert( d_guard_to_assertion.find( g )!= d_guard_to_assertion.end() );
+ Node a = d_guard_to_assertion[g];
+ Node q = quantifiers::TermDb::getInstConstAttr( a );
+ if( !q.isNull() ){
+ //must wait to decide on counterexample literal from quantified formula
+ Node cel = getQuantifiersEngine()->getTermDatabase()->getCounterexampleLiteral( q );
+ bool value;
+ if( d_valuation.hasSatValue( cel, value ) ){
+ success = value;
+ }else{
+ Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : wait to decide on " << g << " until " << cel << " is set " << std::endl;
+ success = false;
+ }
+ }
+ }
+ if( success ){
+ bool value;
+ if( !d_valuation.hasSatValue( g, value ) ) {
+ Trace("sep-dec") << "TheorySep::getNextDecisionRequest : " << g << " (" << i << "/" << d_neg_guards.size() << ")" << std::endl;
+ return g;
+ }
+ }
+ }
+ Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : null" << std::endl;
+ return Node::null();
+}
+
+void TheorySep::conflict(TNode a, TNode b) {
+ Trace("sep-conflict") << "Sep::conflict : " << a << " " << b << std::endl;
+ Node conflictNode;
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ conflictNode = explain(a.iffNode(b));
+ } else {
+ conflictNode = explain(a.eqNode(b));
+ }
+ d_conflict = true;
+ d_out->conflict( conflictNode );
+}
+
+
+TheorySep::HeapAssertInfo::HeapAssertInfo( context::Context* c ) : d_pto(c), d_has_neg_pto(c,false) {
+
+}
+
+TheorySep::HeapAssertInfo * TheorySep::getOrMakeEqcInfo( Node n, bool doMake ) {
+ std::map< Node, HeapAssertInfo* >::iterator e_i = d_eqc_info.find( n );
+ if( e_i==d_eqc_info.end() ){
+ if( doMake ){
+ HeapAssertInfo* ei = new HeapAssertInfo( getSatContext() );
+ d_eqc_info[n] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*e_i).second;
+ }
+}
+
+TypeNode TheorySep::getReferenceType( Node atom, int& card, int index ) {
+ Trace("sep-type") << "getReference type " << atom << " " << index << std::endl;
+ Assert( atom.getKind()==kind::SEP_PTO || atom.getKind()==kind::SEP_STAR || atom.getKind()==kind::SEP_WAND || atom.getKind()==kind::SEP_EMP || index!=-1 );
+ std::map< int, TypeNode >::iterator it = d_reference_type[atom].find( index );
+ if( it==d_reference_type[atom].end() ){
+ card = 0;
+ TypeNode tn;
+ if( index==-1 && ( atom.getKind()==kind::SEP_STAR || atom.getKind()==kind::SEP_WAND ) ){
+ for( unsigned i=0; i<atom.getNumChildren(); i++ ){
+ int cardc = 0;
+ TypeNode ctn = getReferenceType( atom, cardc, i );
+ if( !ctn.isNull() ){
+ tn = ctn;
+ }
+ for( unsigned j=0; j<d_references[atom][i].size(); j++ ){
+ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), d_references[atom][i][j] )==d_references[atom][index].end() ){
+ d_references[atom][index].push_back( d_references[atom][i][j] );
+ }
+ }
+ card = card + cardc;
+ }
+ }else{
+ Node n = index==-1 ? atom : atom[index];
+ //will compute d_references as well
+ std::map< Node, int > visited;
+ tn = getReferenceType2( atom, card, index, n, visited );
+ }
+ if( tn.isNull() && index==-1 ){
+ tn = NodeManager::currentNM()->booleanType();
+ }
+ d_reference_type[atom][index] = tn;
+ d_reference_type_card[atom][index] = card;
+ Trace("sep-type") << "...ref type return " << card << " for " << atom << " " << index << std::endl;
+ //add to d_type_references
+ if( index==-1 ){
+ //only contributes if top-level (index=-1)
+ for( unsigned i=0; i<d_references[atom][index].size(); i++ ){
+ Assert( !d_references[atom][index][i].isNull() );
+ if( std::find( d_type_references[tn].begin(), d_type_references[tn].end(), d_references[atom][index][i] )==d_type_references[tn].end() ){
+ d_type_references[tn].push_back( d_references[atom][index][i] );
+ }
+ }
+ // update maximum cardinality value
+ if( card>(int)d_card_max[tn] ){
+ d_card_max[tn] = card;
+ }
+ }
+ return tn;
+ }else{
+ Assert( d_reference_type_card[atom].find( index )!=d_reference_type_card[atom].end() );
+ card = d_reference_type_card[atom][index];
+ return it->second;
+ }
+}
+
+TypeNode TheorySep::getReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited ) {
+ if( visited.find( n )==visited.end() ){
+ Trace("sep-type-debug") << "visit : " << n << " : " << atom << " " << index << std::endl;
+ visited[n] = -1;
+ if( n.getKind()==kind::SEP_PTO ){
+ TypeNode tn1 = n[0].getType();
+ TypeNode tn2 = n[1].getType();
+ if( quantifiers::TermDb::hasBoundVarAttr( n[0] ) ){
+ d_reference_bound_invalid[tn1] = true;
+ }else{
+ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), n[0] )==d_references[atom][index].end() ){
+ d_references[atom][index].push_back( n[0] );
+ }
+ }
+ std::map< TypeNode, TypeNode >::iterator itt = d_loc_to_data_type.find( tn1 );
+ if( itt==d_loc_to_data_type.end() ){
+ Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl;
+ d_loc_to_data_type[tn1] = tn2;
+ }else{
+ if( itt->second!=tn2 ){
+ std::stringstream ss;
+ ss << "ERROR: location type " << tn1 << " is already associated with data type " << itt->second << ", offending atom is " << atom << " with data type " << tn2 << std::endl;
+ throw LogicException(ss.str());
+ Assert( false );
+ }
+ }
+ card = 1;
+ visited[n] = card;
+ return tn1;
+ //return n[1].getType();
+ }else if( n.getKind()==kind::SEP_EMP ){
+ card = 1;
+ visited[n] = card;
+ return n[0].getType();
+ }else if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND ){
+ Assert( n!=atom );
+ //get the references
+ card = 0;
+ TypeNode tn = getReferenceType( n, card );
+ for( unsigned j=0; j<d_references[n][-1].size(); j++ ){
+ if( std::find( d_references[atom][index].begin(), d_references[atom][index].end(), d_references[n][-1][j] )==d_references[atom][index].end() ){
+ d_references[atom][index].push_back( d_references[n][-1][j] );
+ }
+ }
+ visited[n] = card;
+ return tn;
+ }else{
+ card = 0;
+ TypeNode otn;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int cardc = 0;
+ TypeNode tn = getReferenceType2( atom, cardc, index, n[i], visited );
+ if( !tn.isNull() ){
+ otn = tn;
+ }
+ card = cardc>card ? cardc : card;
+ }
+ visited[n] = card;
+ return otn;
+ }
+ }else{
+ Trace("sep-type-debug") << "already visit : " << n << " : " << atom << " " << index << std::endl;
+ card = 0;
+ return TypeNode::null();
+ }
+}
+/*
+
+int TheorySep::getCardinality( Node n, std::vector< Node >& refs ) {
+ std::map< Node, int > visited;
+ return getCardinality2( n, refs, visited );
+}
+
+int TheorySep::getCardinality2( Node n, std::vector< Node >& refs, std::map< Node, int >& visited ) {
+ std::map< Node, int >::iterator it = visited.find( n );
+ if( it!=visited.end() ){
+ return it->second;
+ }else{
+
+
+ }
+}
+*/
+
+Node TheorySep::getBaseLabel( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_base_label.find( tn );
+ if( it==d_base_label.end() ){
+ Trace("sep") << "Make base label for " << tn << std::endl;
+ std::stringstream ss;
+ ss << "__Lb";
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(tn);
+ //TypeNode ltn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(tn));
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "" );
+ d_base_label[tn] = n_lbl;
+ //make reference bound
+ Trace("sep") << "Make reference bound label for " << tn << std::endl;
+ std::stringstream ss2;
+ ss2 << "__Lu";
+ d_reference_bound[tn] = NodeManager::currentNM()->mkSkolem( ss2.str(), ltn, "" );
+ d_type_references_all[tn].insert( d_type_references_all[tn].end(), d_type_references[tn].begin(), d_type_references[tn].end() );
+ //add a reference type for maximum occurrences of empty in a constraint
+ unsigned n_emp = d_card_max[tn]>d_card_max[TypeNode::null()] ? d_card_max[tn] : d_card_max[TypeNode::null()];
+ for( unsigned r=0; r<n_emp; r++ ){
+ Node e = NodeManager::currentNM()->mkSkolem( "e", tn, "cardinality bound element for seplog" );
+ //d_type_references_all[tn].push_back( NodeManager::currentNM()->mkSkolem( "e", NodeManager::currentNM()->mkRefType(tn) ) );
+ if( options::sepDisequalC() ){
+ //ensure that it is distinct from all other references so far
+ for( unsigned j=0; j<d_type_references_all[tn].size(); j++ ){
+ Node eq = NodeManager::currentNM()->mkNode( e.getType().isBoolean() ? kind::IFF : kind::EQUAL, e, d_type_references_all[tn][j] );
+ d_out->lemma( eq.negate() );
+ }
+ }
+ d_type_references_all[tn].push_back( e );
+ d_lbl_reference_bound[d_base_label[tn]].push_back( e );
+ }
+ //construct bound
+ d_reference_bound_max[tn] = mkUnion( tn, d_type_references_all[tn] );
+ Trace("sep-bound") << "overall bound for " << d_base_label[tn] << " : " << d_reference_bound_max[tn] << std::endl;
+
+ if( d_reference_bound_invalid.find( tn )==d_reference_bound_invalid.end() ){
+ Node slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_reference_bound[tn], d_reference_bound_max[tn] );
+ Trace("sep-lemma") << "Sep::Lemma: reference bound for " << tn << " : " << slem << std::endl;
+ d_out->lemma( slem );
+ }else{
+ Trace("sep-bound") << "reference cannot be bound (possibly due to quantified pto)." << std::endl;
+ }
+ //slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_base_label[tn], d_reference_bound_max[tn] );
+ //Trace("sep-lemma") << "Sep::Lemma: base reference bound for " << tn << " : " << slem << std::endl;
+ //d_out->lemma( slem );
+ return n_lbl;
+ }else{
+ return it->second;
+ }
+}
+
+Node TheorySep::getNilRef( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_nil_ref.find( tn );
+ if( it==d_nil_ref.end() ){
+ Node nil = NodeManager::currentNM()->mkSepNil( tn );
+ d_nil_ref[tn] = nil;
+ return nil;
+ }else{
+ return it->second;
+ }
+}
+
+Node TheorySep::mkUnion( TypeNode tn, std::vector< Node >& locs ) {
+ Node u;
+ if( locs.empty() ){
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(tn);
+ return NodeManager::currentNM()->mkConst(EmptySet(ltn.toType()));
+ }else{
+ for( unsigned i=0; i<locs.size(); i++ ){
+ Node s = locs[i];
+ Assert( !s.isNull() );
+ s = NodeManager::currentNM()->mkNode( kind::SINGLETON, s );
+ if( u.isNull() ){
+ u = s;
+ }else{
+ u = NodeManager::currentNM()->mkNode( kind::UNION, s, u );
+ }
+ }
+ return u;
+ }
+}
+
+Node TheorySep::getLabel( Node atom, int child, Node lbl ) {
+ std::map< int, Node >::iterator it = d_label_map[atom][lbl].find( child );
+ if( it==d_label_map[atom][lbl].end() ){
+ int card;
+ TypeNode refType = getReferenceType( atom, card );
+ std::stringstream ss;
+ ss << "__Lc" << child;
+ TypeNode ltn = NodeManager::currentNM()->mkSetType(refType);
+ //TypeNode ltn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(refType));
+ Node n_lbl = NodeManager::currentNM()->mkSkolem( ss.str(), ltn, "" );
+ d_label_map[atom][lbl][child] = n_lbl;
+ d_label_map_parent[n_lbl] = lbl;
+ return n_lbl;
+ }else{
+ return (*it).second;
+ }
+}
+
+Node TheorySep::applyLabel( Node n, Node lbl, std::map< Node, Node >& visited ) {
+ Assert( n.getKind()!=kind::SEP_LABEL );
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){
+ return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl );
+ }else if( !n.getType().isBoolean() || n.getNumChildren()==0 ){
+ return n;
+ }else{
+ std::map< Node, Node >::iterator it = visited.find( n );
+ if( it==visited.end() ){
+ std::vector< Node > children;
+ if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ children.push_back( n.getOperator() );
+ }
+ bool childChanged = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node aln = applyLabel( n[i], lbl, visited );
+ children.push_back( aln );
+ childChanged = childChanged || aln!=n[i];
+ }
+ Node ret = n;
+ if( childChanged ){
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ visited[n] = ret;
+ return ret;
+ }else{
+ return it->second;
+ }
+ }
+}
+
+Node TheorySep::instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std::map< Node, Node >& visited, std::map< Node, Node >& pto_model, std::map< Node, Node >& tmodel,
+ TypeNode rtn, std::map< Node, bool >& active_lbl, unsigned ind ) {
+ Trace("sep-inst-debug") << "Instantiate label " << n << " " << lbl << " " << lbl_v << std::endl;
+ if( options::sepMinimalRefine() && lbl!=o_lbl && active_lbl.find( lbl )!=active_lbl.end() ){
+ Trace("sep-inst") << "...do not instantiate " << o_lbl << " since it has an active sublabel " << lbl << std::endl;
+ return Node::null();
+ }else{
+ if( Trace.isOn("sep-inst") ){
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){
+ for( unsigned j=0; j<ind; j++ ){ Trace("sep-inst") << " "; }
+ Trace("sep-inst") << n << "[" << lbl << "] :: " << lbl_v << std::endl;
+ }
+ }
+ Assert( n.getKind()!=kind::SEP_LABEL );
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND ){
+ if( lbl==o_lbl ){
+ std::vector< Node > children;
+ children.resize( n.getNumChildren() );
+ Assert( d_label_map[n].find( lbl )!=d_label_map[n].end() );
+ for( std::map< int, Node >::iterator itl = d_label_map[n][lbl].begin(); itl != d_label_map[n][lbl].end(); ++itl ){
+ Node sub_lbl = itl->second;
+ int sub_index = itl->first;
+ Assert( sub_index>=0 && sub_index<(int)children.size() );
+ Trace("sep-inst-debug") << "Sublabel " << sub_index << " is " << sub_lbl << std::endl;
+ Node lbl_mval;
+ if( n.getKind()==kind::SEP_WAND && sub_index==1 ){
+ Assert( d_label_map[n][lbl].find( 0 )!=d_label_map[n][lbl].end() );
+ Node sub_lbl_0 = d_label_map[n][lbl][0];
+ computeLabelModel( sub_lbl_0, tmodel );
+ Assert( d_label_model.find( sub_lbl_0 )!=d_label_model.end() );
+ lbl_mval = NodeManager::currentNM()->mkNode( kind::UNION, lbl, d_label_model[sub_lbl_0].getValue( rtn ) );
+ }else{
+ computeLabelModel( sub_lbl, tmodel );
+ Assert( d_label_model.find( sub_lbl )!=d_label_model.end() );
+ lbl_mval = d_label_model[sub_lbl].getValue( rtn );
+ }
+ Trace("sep-inst-debug") << "Sublabel value is " << lbl_mval << std::endl;
+ children[sub_index] = instantiateLabel( n[sub_index], o_lbl, sub_lbl, lbl_mval, visited, pto_model, tmodel, rtn, active_lbl, ind+1 );
+ if( children[sub_index].isNull() ){
+ return Node::null();
+ }
+ }
+ if( n.getKind()==kind::SEP_STAR ){
+ Assert( children.size()>1 );
+ return NodeManager::currentNM()->mkNode( kind::AND, children );
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::OR, children[0].negate(), children[1] );
+ }
+ }else{
+ //nested star/wand, label it and return
+ return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl_v );
+ }
+ }else if( n.getKind()==kind::SEP_PTO ){
+ //check if this pto reference is in the base label, if not, then it does not need to be added as an assumption
+ Assert( d_label_model.find( o_lbl )!=d_label_model.end() );
+ Node vr = d_valuation.getModel()->getRepresentative( n[0] );
+ Node svr = NodeManager::currentNM()->mkNode( kind::SINGLETON, vr );
+ bool inBaseHeap = std::find( d_label_model[o_lbl].d_heap_locs_model.begin(), d_label_model[o_lbl].d_heap_locs_model.end(), svr )!=d_label_model[o_lbl].d_heap_locs_model.end();
+ Trace("sep-inst-debug") << "Is in base (non-instantiating) heap : " << inBaseHeap << " for value ref " << vr << " in " << o_lbl << std::endl;
+ std::vector< Node > children;
+ if( inBaseHeap ){
+ Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] );
+ children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, n[0], n[1] ), s ) );
+ }else{
+ //look up value of data
+ std::map< Node, Node >::iterator it = pto_model.find( vr );
+ if( it!=pto_model.end() ){
+ if( n[1]!=it->second ){
+ children.push_back( NodeManager::currentNM()->mkNode( n[1].getType().isBoolean() ? kind::IFF : kind::EQUAL, n[1], it->second ) );
+ }
+ }else{
+ Trace("sep-inst-debug") << "Data for " << vr << " was not specified, do not add condition." << std::endl;
+ }
+ }
+ children.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] ), lbl_v ) );
+ Node ret = children.empty() ? NodeManager::currentNM()->mkConst( true ) : ( children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ) );
+ Trace("sep-inst-debug") << "Return " << ret << std::endl;
+ return ret;
+ }else if( n.getKind()==kind::SEP_EMP ){
+ //return NodeManager::currentNM()->mkConst( lbl_v.getKind()==kind::EMPTYSET );
+ return lbl_v.eqNode( NodeManager::currentNM()->mkConst(EmptySet(lbl_v.getType().toType())) );
+ }else{
+ std::map< Node, Node >::iterator it = visited.find( n );
+ if( it==visited.end() ){
+ std::vector< Node > children;
+ if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ children.push_back( n.getOperator() );
+ }
+ bool childChanged = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node aln = instantiateLabel( n[i], o_lbl, lbl, lbl_v, visited, pto_model, tmodel, rtn, active_lbl, ind );
+ if( aln.isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( aln );
+ childChanged = childChanged || aln!=n[i];
+ }
+ }
+ Node ret = n;
+ if( childChanged ){
+ ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+ //careful about caching
+ //visited[n] = ret;
+ return ret;
+ }else{
+ return it->second;
+ }
+ }
+ }
+}
+
+void TheorySep::setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active ) {
+ Trace("sep-process-debug") << "setInactiveAssertionRec::inactive : " << fact << std::endl;
+ assert_active[fact] = false;
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode s_atom = atom[0];
+ TNode s_lbl = atom[1];
+ if( s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_STAR ){
+ for( unsigned j=0; j<s_atom.getNumChildren(); j++ ){
+ Node lblc = getLabel( s_atom, j, s_lbl );
+ for( unsigned k=0; k<lbl_to_assertions[lblc].size(); k++ ){
+ setInactiveAssertionRec( lbl_to_assertions[lblc][k], lbl_to_assertions, assert_active );
+ }
+ }
+ }
+}
+
+void TheorySep::getLabelChildren( Node s_atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels ) {
+ for( unsigned i=0; i<s_atom.getNumChildren(); i++ ){
+ Node lblc = getLabel( s_atom, i, lbl );
+ Assert( !lblc.isNull() );
+ std::map< Node, Node > visited;
+ Node lc = applyLabel( s_atom[i], lblc, visited );
+ Assert( !lc.isNull() );
+ if( i==1 && s_atom.getKind()==kind::SEP_WAND ){
+ lc = lc.negate();
+ }
+ children.push_back( lc );
+ labels.push_back( lblc );
+ }
+ Assert( children.size()>1 );
+}
+
+void TheorySep::computeLabelModel( Node lbl, std::map< Node, Node >& tmodel ) {
+ if( !d_label_model[lbl].d_computed ){
+ d_label_model[lbl].d_computed = true;
+
+ //we must get the value of lbl from the model: this is being run at last call, after the model is constructed
+ //Assert(...); TODO
+ Node v_val = d_valuation.getModel()->getRepresentative( lbl );
+ Trace("sep-process") << "Model value (from valuation) for " << lbl << " : " << v_val << std::endl;
+ if( v_val.getKind()!=kind::EMPTYSET ){
+ while( v_val.getKind()==kind::UNION ){
+ Assert( v_val[1].getKind()==kind::SINGLETON );
+ d_label_model[lbl].d_heap_locs_model.push_back( v_val[1] );
+ v_val = v_val[0];
+ }
+ Assert( v_val.getKind()==kind::SINGLETON );
+ d_label_model[lbl].d_heap_locs_model.push_back( v_val );
+ }
+ //end hack
+ for( unsigned j=0; j<d_label_model[lbl].d_heap_locs_model.size(); j++ ){
+ Node u = d_label_model[lbl].d_heap_locs_model[j];
+ Assert( u.getKind()==kind::SINGLETON );
+ u = u[0];
+ Node tt;
+ std::map< Node, Node >::iterator itm = tmodel.find( u );
+ if( itm==tmodel.end() ) {
+ //Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << std::endl;
+ //Assert( false );
+ //tt = u;
+ //TypeNode tn = u.getType().getRefConstituentType();
+ TypeNode tn = u.getType();
+ Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << ", cref type " << tn << std::endl;
+ Assert( d_type_references_all.find( tn )!=d_type_references_all.end() && !d_type_references_all[tn].empty() );
+ tt = d_type_references_all[tn][0];
+ }else{
+ tt = itm->second;
+ }
+ Node stt = NodeManager::currentNM()->mkNode( kind::SINGLETON, tt );
+ Trace("sep-process-debug") << "...model : add " << tt << " for " << u << " in lbl " << lbl << std::endl;
+ d_label_model[lbl].d_heap_locs.push_back( stt );
+ }
+ }
+}
+
+Node TheorySep::getRepresentative( Node t ) {
+ if( d_equalityEngine.hasTerm( t ) ){
+ return d_equalityEngine.getRepresentative( t );
+ }else{
+ return t;
+ }
+}
+
+bool TheorySep::hasTerm( Node a ){
+ return d_equalityEngine.hasTerm( a );
+}
+
+bool TheorySep::areEqual( Node a, Node b ){
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areEqual( a, b );
+ }else{
+ return false;
+ }
+}
+
+bool TheorySep::areDisequal( Node a, Node b ){
+ if( a==b ){
+ return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ if( d_equalityEngine.areDisequal( a, b, false ) ){
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void TheorySep::eqNotifyPreMerge(TNode t1, TNode t2) {
+
+}
+
+void TheorySep::eqNotifyPostMerge(TNode t1, TNode t2) {
+ HeapAssertInfo * e2 = getOrMakeEqcInfo( t2, false );
+ if( e2 && ( !e2->d_pto.get().isNull() || e2->d_has_neg_pto.get() ) ){
+ HeapAssertInfo * e1 = getOrMakeEqcInfo( t1, true );
+ if( !e2->d_pto.get().isNull() ){
+ if( !e1->d_pto.get().isNull() ){
+ Trace("sep-pto-debug") << "While merging " << t1 << " " << t2 << ", merge pto." << std::endl;
+ mergePto( e1->d_pto.get(), e2->d_pto.get() );
+ }else{
+ e1->d_pto.set( e2->d_pto.get() );
+ }
+ }
+ e1->d_has_neg_pto.set( e1->d_has_neg_pto.get() || e2->d_has_neg_pto.get() );
+ //validate
+ validatePto( e1, t1 );
+ }
+}
+
+void TheorySep::validatePto( HeapAssertInfo * ei, Node ei_n ) {
+ if( !ei->d_pto.get().isNull() && ei->d_has_neg_pto.get() ){
+ for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != kind::NOT;
+ if( !polarity ){
+ TNode atom = polarity ? fact : fact[0];
+ Assert( atom.getKind()==kind::SEP_LABEL );
+ TNode s_atom = atom[0];
+ if( s_atom.getKind()==kind::SEP_PTO ){
+ if( areEqual( atom[1], ei_n ) ){
+ addPto( ei, ei_n, atom, false );
+ }
+ }
+ }
+ }
+ //we have now processed all pending negated pto
+ ei->d_has_neg_pto.set( false );
+ }
+}
+
+void TheorySep::addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ) {
+ Trace("sep-pto") << "Add pto " << p << ", pol = " << polarity << " to eqc " << ei_n << std::endl;
+ if( !ei->d_pto.get().isNull() ){
+ if( polarity ){
+ Trace("sep-pto-debug") << "...eqc " << ei_n << " already has pto " << ei->d_pto.get() << ", merge." << std::endl;
+ mergePto( ei->d_pto.get(), p );
+ }else{
+ Node pb = ei->d_pto.get();
+ Trace("sep-pto") << "Process positive/negated pto " << " " << pb << " " << p << std::endl;
+ Assert( pb.getKind()==kind::SEP_LABEL && pb[0].getKind()==kind::SEP_PTO );
+ Assert( p.getKind()==kind::SEP_LABEL && p[0].getKind()==kind::SEP_PTO );
+ Assert( areEqual( pb[1], p[1] ) );
+ std::vector< Node > exp;
+ if( pb[1]!=p[1] ){
+ exp.push_back( pb[1].eqNode( p[1] ) );
+ }
+ exp.push_back( pb );
+ exp.push_back( p.negate() );
+ std::vector< Node > conc;
+ if( pb[0][1]!=p[0][1] ){
+ conc.push_back( pb[0][1].eqNode( p[0][1] ).negate() );
+ }
+ if( pb[1]!=p[1] ){
+ conc.push_back( pb[1].eqNode( p[1] ).negate() );
+ }
+ Node n_conc = conc.empty() ? d_false : ( conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::OR, conc ) );
+ sendLemma( exp, n_conc, "PTO_NEG_PROP" );
+ }
+ }else{
+ if( polarity ){
+ ei->d_pto.set( p );
+ validatePto( ei, ei_n );
+ }else{
+ ei->d_has_neg_pto.set( true );
+ }
+ }
+}
+
+void TheorySep::mergePto( Node p1, Node p2 ) {
+ Trace("sep-lemma-debug") << "Merge pto " << p1 << " " << p2 << std::endl;
+ Assert( p1.getKind()==kind::SEP_LABEL && p1[0].getKind()==kind::SEP_PTO );
+ Assert( p2.getKind()==kind::SEP_LABEL && p2[0].getKind()==kind::SEP_PTO );
+ if( !areEqual( p1[0][1], p2[0][1] ) ){
+ std::vector< Node > exp;
+ if( p1[1]!=p2[1] ){
+ Assert( areEqual( p1[1], p2[1] ) );
+ exp.push_back( p1[1].eqNode( p2[1] ) );
+ }
+ exp.push_back( p1 );
+ exp.push_back( p2 );
+ sendLemma( exp, p1[0][1].eqNode( p2[0][1] ), "PTO_PROP" );
+ }
+}
+
+void TheorySep::sendLemma( std::vector< Node >& ant, Node conc, const char * c, bool infer ) {
+ Trace("sep-lemma-debug") << "Do rewrite on inference : " << conc << std::endl;
+ conc = Rewriter::rewrite( conc );
+ Trace("sep-lemma-debug") << "Got : " << conc << std::endl;
+ if( conc!=d_true ){
+ if( infer && conc!=d_false ){
+ Node ant_n;
+ if( ant.empty() ){
+ ant_n = d_true;
+ }else if( ant.size()==1 ){
+ ant_n = ant[0];
+ }else{
+ ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant );
+ }
+ Trace("sep-lemma") << "Sep::Infer: " << conc << " from " << ant_n << " by " << c << std::endl;
+ d_pending_exp.push_back( ant_n );
+ d_pending.push_back( conc );
+ d_infer.push_back( ant_n );
+ d_infer_exp.push_back( conc );
+ }else{
+ std::vector< TNode > ant_e;
+ for( unsigned i=0; i<ant.size(); i++ ){
+ Trace("sep-lemma-debug") << "Explain : " << ant[i] << std::endl;
+ explain( ant[i], ant_e );
+ }
+ Node ant_n;
+ if( ant_e.empty() ){
+ ant_n = d_true;
+ }else if( ant_e.size()==1 ){
+ ant_n = ant_e[0];
+ }else{
+ ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant_e );
+ }
+ if( conc==d_false ){
+ Trace("sep-lemma") << "Sep::Conflict: " << ant_n << " by " << c << std::endl;
+ d_out->conflict( ant_n );
+ d_conflict = true;
+ }else{
+ Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant_n << " by " << c << std::endl;
+ d_pending_exp.push_back( ant_n );
+ d_pending.push_back( conc );
+ d_pending_lem.push_back( d_pending.size()-1 );
+ }
+ }
+ }
+}
+
+void TheorySep::doPendingFacts() {
+ if( d_pending_lem.empty() ){
+ for( unsigned i=0; i<d_pending.size(); i++ ){
+ if( d_conflict ){
+ break;
+ }
+ Node atom = d_pending[i].getKind()==kind::NOT ? d_pending[i][0] : d_pending[i];
+ bool pol = d_pending[i].getKind()!=kind::NOT;
+ Trace("sep-pending") << "Sep : Assert to EE : " << atom << ", pol = " << pol << std::endl;
+ if( atom.getKind()==kind::EQUAL ){
+ d_equalityEngine.assertEquality(atom, pol, d_pending_exp[i]);
+ }else{
+ d_equalityEngine.assertPredicate(atom, pol, d_pending_exp[i]);
+ }
+ }
+ }else{
+ for( unsigned i=0; i<d_pending_lem.size(); i++ ){
+ if( d_conflict ){
+ break;
+ }
+ int index = d_pending_lem[i];
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, d_pending_exp[index], d_pending[index] );
+ d_out->lemma( lem );
+ Trace("sep-pending") << "Sep : Lemma : " << lem << std::endl;
+ }
+ }
+ d_pending_exp.clear();
+ d_pending.clear();
+ d_pending_lem.clear();
+}
+
+void TheorySep::debugPrintHeap( HeapInfo& heap, const char * c ) {
+ Trace(c) << "[" << std::endl;
+ Trace(c) << " ";
+ for( unsigned j=0; j<heap.d_heap_locs.size(); j++ ){
+ Trace(c) << heap.d_heap_locs[j] << " ";
+ }
+ Trace(c) << std::endl;
+ Trace(c) << "]" << std::endl;
+}
+
+Node TheorySep::HeapInfo::getValue( TypeNode tn ) {
+ Assert( d_heap_locs.size()==d_heap_locs_model.size() );
+ if( d_heap_locs.empty() ){
+ return NodeManager::currentNM()->mkConst(EmptySet(tn.toType()));
+ }else if( d_heap_locs.size()==1 ){
+ return d_heap_locs[0];
+ }else{
+ Node curr = NodeManager::currentNM()->mkNode( kind::UNION, d_heap_locs[0], d_heap_locs[1] );
+ for( unsigned j=2; j<d_heap_locs.size(); j++ ){
+ curr = NodeManager::currentNM()->mkNode( kind::UNION, curr, d_heap_locs[j] );
+ }
+ return curr;
+ }
+}
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h
new file mode 100644
index 000000000..852a36721
--- /dev/null
+++ b/src/theory/sep/theory_sep.h
@@ -0,0 +1,294 @@
+/********************* */
+/*! \file theory_sep.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: Dejan Jovanovic, Clark Barrett
+ ** Minor contributors (to current version): Tim King, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Theory of sep
+ **
+ ** Theory of sep.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_H
+
+#include "theory/theory.h"
+#include "util/statistics_registry.h"
+#include "theory/uf/equality_engine.h"
+#include "context/cdchunk_list.h"
+#include "context/cdhashmap.h"
+#include "context/cdhashset.h"
+#include "context/cdqueue.h"
+
+namespace CVC4 {
+namespace theory {
+
+class TheoryModel;
+
+namespace sep {
+
+class TheorySep : public Theory {
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MISC
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ /** True node for predicates = true */
+ Node d_true;
+
+ /** True node for predicates = false */
+ Node d_false;
+
+ Node mkAnd( std::vector< TNode >& assumptions );
+
+ void processAssertion( Node n, std::map< Node, bool >& visited );
+
+ public:
+
+ TheorySep(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ ~TheorySep();
+
+ void setMasterEqualityEngine(eq::EqualityEngine* eq);
+
+ std::string identify() const { return std::string("TheorySep"); }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PREPROCESSING
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+ Node ppRewrite(TNode atom);
+
+ void processAssertions( std::vector< Node >& assertions );
+ /////////////////////////////////////////////////////////////////////////////
+ // T-PROPAGATION / REGISTRATION
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ /** Should be called to propagate the literal. */
+ bool propagate(TNode literal);
+
+ /** Explain why this literal is true by adding assumptions */
+ void explain(TNode literal, std::vector<TNode>& assumptions);
+
+ void preRegisterTermRec(TNode t, std::map< TNode, bool >& visited );
+ public:
+
+ void preRegisterTerm(TNode t);
+ void propagate(Effort e);
+ Node explain(TNode n);
+
+ public:
+
+ void addSharedTerm(TNode t);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+ void computeCareGraph();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MODEL GENERATION
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // NOTIFICATIONS
+ /////////////////////////////////////////////////////////////////////////////
+
+ private:
+ public:
+
+ Node getNextDecisionRequest();
+
+ void presolve();
+ void shutdown() { }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MAIN SOLVER
+ /////////////////////////////////////////////////////////////////////////////
+ public:
+
+ void check(Effort e);
+
+ private:
+
+ // NotifyClass: template helper class for d_equalityEngine - handles call-back from congruence closure module
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheorySep& d_sep;
+ public:
+ NotifyClass(TheorySep& sep): d_sep(sep) {}
+
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
+ // Just forward to sep
+ if (value) {
+ return d_sep.propagate(equality);
+ } else {
+ return d_sep.propagate(equality.notNode());
+ }
+ }
+
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Unreachable();
+ }
+
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ // Propagate equality between shared terms
+ return d_sep.propagate(t1.eqNode(t2));
+ } else {
+ return d_sep.propagate(t1.eqNode(t2).notNode());
+ }
+ return true;
+ }
+
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("sep::propagate") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_sep.conflict(t1, t2);
+ }
+
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sep.eqNotifyPreMerge( t1, t2 ); }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sep.eqNotifyPostMerge( t1, t2 ); }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+ };
+
+ /** The notify class for d_equalityEngine */
+ NotifyClass d_notify;
+
+ /** Equaltity engine */
+ eq::EqualityEngine d_equalityEngine;
+
+ /** Are we in conflict? */
+ context::CDO<bool> d_conflict;
+ std::vector< Node > d_pending_exp;
+ std::vector< Node > d_pending;
+ std::vector< int > d_pending_lem;
+
+ /** list of all refinement lemms */
+ std::map< Node, std::map< Node, std::vector< Node > > > d_refinement_lem;
+
+ /** Conflict when merging constants */
+ void conflict(TNode a, TNode b);
+
+ //cache for positive polarity start reduction
+ NodeSet d_reduce;
+ std::map< Node, std::map< Node, Node > > d_red_conc;
+ std::map< Node, std::map< Node, Node > > d_neg_guard;
+ std::vector< Node > d_neg_guards;
+ std::map< Node, Node > d_guard_to_assertion;
+ //cache for references
+ std::map< Node, std::map< int, TypeNode > > d_reference_type;
+ std::map< Node, std::map< int, int > > d_reference_type_card;
+ std::map< Node, std::map< int, std::vector< Node > > > d_references;
+ /** inferences: maintained to ensure ref count for internally introduced nodes */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ NodeList d_spatial_assertions;
+
+ //currently fix one data type for each location type, throw error if using more than one
+ std::map< TypeNode, TypeNode > d_loc_to_data_type;
+ //information about types
+ std::map< TypeNode, Node > d_base_label;
+ std::map< TypeNode, Node > d_nil_ref;
+ //reference bound
+ std::map< TypeNode, Node > d_reference_bound;
+ std::map< TypeNode, Node > d_reference_bound_max;
+ std::map< TypeNode, bool > d_reference_bound_invalid;
+ std::map< TypeNode, std::vector< Node > > d_type_references;
+ std::map< TypeNode, std::vector< Node > > d_type_references_all;
+ std::map< TypeNode, unsigned > d_card_max;
+ //bounds for labels
+ std::map< Node, std::vector< Node > > d_lbl_reference_bound;
+ //for empty argument
+ std::map< TypeNode, Node > d_emp_arg;
+ //map from ( atom, label, child index ) -> label
+ std::map< Node, std::map< Node, std::map< int, Node > > > d_label_map;
+ std::map< Node, Node > d_label_map_parent;
+
+ //term model
+ std::map< Node, Node > d_tmodel;
+ std::map< Node, Node > d_pto_model;
+
+ class HeapAssertInfo {
+ public:
+ HeapAssertInfo( context::Context* c );
+ ~HeapAssertInfo(){}
+ context::CDO< Node > d_pto;
+ context::CDO< bool > d_has_neg_pto;
+ };
+ std::map< Node, HeapAssertInfo * > d_eqc_info;
+ HeapAssertInfo * getOrMakeEqcInfo( Node n, bool doMake = false );
+
+ //calculate the element type of the heap for spatial assertions
+ TypeNode getReferenceType( Node atom, int& card, int index = -1 );
+ TypeNode getReferenceType2( Node atom, int& card, int index, Node n, std::map< Node, int >& visited);
+ //get the base label for the spatial assertion
+ Node getBaseLabel( TypeNode tn );
+ Node getNilRef( TypeNode tn );
+ Node getLabel( Node atom, int child, Node lbl );
+ Node applyLabel( Node n, Node lbl, std::map< Node, Node >& visited );
+ void getLabelChildren( Node atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels );
+
+ class HeapInfo {
+ public:
+ HeapInfo() : d_computed(false) {}
+ //information about the model
+ bool d_computed;
+ std::vector< Node > d_heap_locs;
+ std::vector< Node > d_heap_locs_model;
+ //get value
+ Node getValue( TypeNode tn );
+ };
+ //heap info ( label -> HeapInfo )
+ std::map< Node, HeapInfo > d_label_model;
+
+ void debugPrintHeap( HeapInfo& heap, const char * c );
+ void validatePto( HeapAssertInfo * ei, Node ei_n );
+ void addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity );
+ void mergePto( Node p1, Node p2 );
+ void computeLabelModel( Node lbl, std::map< Node, Node >& tmodel );
+ Node instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std::map< Node, Node >& visited, std::map< Node, Node >& pto_model, std::map< Node, Node >& tmodel,
+ TypeNode rtn, std::map< Node, bool >& active_lbl, unsigned ind = 0 );
+ void setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active );
+
+ Node mkUnion( TypeNode tn, std::vector< Node >& locs );
+private:
+ Node getRepresentative( Node t );
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+
+ void sendLemma( std::vector< Node >& ant, Node conc, const char * c, bool infer = false );
+ void doPendingFacts();
+public:
+ eq::EqualityEngine* getEqualityEngine() {
+ return &d_equalityEngine;
+ }
+
+};/* class TheorySep */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_H */
diff --git a/src/theory/sep/theory_sep_rewriter.cpp b/src/theory/sep/theory_sep_rewriter.cpp
new file mode 100644
index 000000000..d58c2c13d
--- /dev/null
+++ b/src/theory/sep/theory_sep_rewriter.cpp
@@ -0,0 +1,184 @@
+/********************* */
+/*! \file theory_sep_rewriter.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "expr/attribute.h"
+#include "theory/sep/theory_sep_rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+void TheorySepRewriter::getStarChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children ){
+ Assert( n.getKind()==kind::SEP_STAR );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==kind::SEP_EMP ){
+ s_children.push_back( n[i] );
+ }else if( n[i].getKind()==kind::SEP_STAR ){
+ getStarChildren( n[i], s_children, ns_children );
+ }else if( n[i].getKind()==kind::SEP_PTO ){
+ s_children.push_back( n[i] );
+ }else{
+ std::vector< Node > temp_s_children;
+ getAndChildren( n[i], temp_s_children, ns_children );
+ Node to_add;
+ if( temp_s_children.size()==0 ){
+ to_add = NodeManager::currentNM()->mkConst( true );
+ }else{
+ //remove empty star
+ std::vector< Node > temp_s_children2;
+ for( unsigned i=0; i<temp_s_children.size(); i++ ){
+ if( temp_s_children[i].getKind()!=kind::SEP_EMP ){
+ temp_s_children2.push_back( temp_s_children[i] );
+ }
+ }
+ if( temp_s_children2.size()==1 ){
+ to_add = temp_s_children2[0];
+ }else if( temp_s_children2.size()>1 ){
+ to_add = NodeManager::currentNM()->mkNode( kind::AND, temp_s_children2 );
+ }
+ }
+ if( !to_add.isNull() ){
+ //flatten star
+ if( to_add.getKind()==kind::SEP_STAR ){
+ getStarChildren( to_add, s_children, ns_children );
+ }else if( std::find( s_children.begin(), s_children.end(), to_add )==s_children.end() ){
+ s_children.push_back( to_add );
+ }
+ }
+ }
+ }
+}
+
+void TheorySepRewriter::getAndChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children ) {
+ if( n.getKind()==kind::AND ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getAndChildren( n[i], s_children, ns_children );
+ }
+ }else{
+ std::map< Node, bool > visited;
+ if( isSpatial( n, visited ) ){
+ if( std::find( s_children.begin(), s_children.end(), n )==s_children.end() ){
+ s_children.push_back( n );
+ }
+ }else{
+ if( std::find( ns_children.begin(), ns_children.end(), n )==ns_children.end() ){
+ if( n!=NodeManager::currentNM()->mkConst(true) ){
+ ns_children.push_back( n );
+ }
+ }
+ }
+ }
+}
+
+bool TheorySepRewriter::isSpatial( Node n, std::map< Node, bool >& visited ) {
+ if( visited.find( n )==visited.end() ){
+ visited[n] = true;
+ if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP || n.getKind()==kind::SEP_LABEL ){
+ return true;
+ }else if( n.getType().isBoolean() ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( isSpatial( n[i], visited ) ){
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+RewriteResponse TheorySepRewriter::postRewrite(TNode node) {
+ Trace("sep-postrewrite") << "Sep::postRewrite start " << node << std::endl;
+ Node retNode = node;
+ switch (node.getKind()) {
+ case kind::SEP_LABEL: {
+ if( node[0].getKind()==kind::SEP_PTO ){
+ Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, node[0][0] );
+ if( node[1]!=s ){
+ Node c1 = node[1].eqNode( s );
+ Node c2 = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, node[0][0], node[0][1] ), s );
+ retNode = NodeManager::currentNM()->mkNode( kind::AND, c1, c2 );
+ }
+ }
+ if( node[0].getKind()==kind::SEP_EMP ){
+ retNode = node[1].eqNode( NodeManager::currentNM()->mkConst(EmptySet(node[1].getType().toType())) );
+ }
+ break;
+ }
+ case kind::SEP_PTO: {
+ break;
+ }
+ case kind::SEP_STAR: {
+ //flatten
+ std::vector< Node > s_children;
+ std::vector< Node > ns_children;
+ getStarChildren( node, s_children, ns_children );
+ if( !s_children.empty() ){
+ Node schild;
+ if( s_children.size()==1 ) {
+ schild = s_children[0];
+ }else{
+ schild = NodeManager::currentNM()->mkNode( kind::SEP_STAR, s_children );
+ }
+ ns_children.push_back( schild );
+ }
+ Assert( !ns_children.empty() );
+ if( ns_children.size()==1 ){
+ retNode = ns_children[0];
+ }else{
+ retNode = NodeManager::currentNM()->mkNode( kind::AND, ns_children );
+ }
+ break;
+ }
+ case kind::EQUAL:
+ case kind::IFF: {
+ if(node[0] == node[1]) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ else if (node[0].isConst() && node[1].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(false));
+ }
+ if (node[0] > node[1]) {
+ Node newNode = NodeManager::currentNM()->mkNode(node.getKind(), node[1], node[0]);
+ return RewriteResponse(REWRITE_DONE, newNode);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if( node!=retNode ){
+ Trace("sep-rewrite") << "Sep::rewrite : " << node << " -> " << retNode << std::endl;
+ }
+ return RewriteResponse(node==retNode ? REWRITE_DONE : REWRITE_AGAIN_FULL, retNode);
+}
+
+
+/*
+RewriteResponse TheorySepRewriter::preRewrite(TNode node) {
+ if( node.getKind()==kind::SEP_EMP ){
+ Trace("sep-prerewrite") << "Sep::preRewrite emp star " << std::endl;
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkNode( kind::SEP_EMP, NodeManager::currentNM()->mkConst( true ) ) );
+ }else{
+ Trace("sep-prerewrite") << "Sep::preRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+}
+*/
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/sep/theory_sep_rewriter.h b/src/theory/sep/theory_sep_rewriter.h
new file mode 100644
index 000000000..02adbebe5
--- /dev/null
+++ b/src/theory/sep/theory_sep_rewriter.h
@@ -0,0 +1,53 @@
+/********************* */
+/*! \file theory_sep_rewriter.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+
+class TheorySepRewriter {
+private:
+ static void getStarChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children );
+ static void getAndChildren( Node n, std::vector< Node >& s_children, std::vector< Node >& ns_children );
+ static bool isSpatial( Node n, std::map< Node, bool >& visited );
+public:
+
+ static RewriteResponse postRewrite(TNode node);
+ static inline RewriteResponse preRewrite(TNode node) {
+ Trace("sep-prerewrite") << "Sep::preRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+
+ static inline void init() {}
+ static inline void shutdown() {}
+
+};/* class TheorySepRewriter */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_REWRITER_H */
diff --git a/src/theory/sep/theory_sep_type_rules.h b/src/theory/sep/theory_sep_type_rules.h
new file mode 100644
index 000000000..7d4eb303e
--- /dev/null
+++ b/src/theory/sep/theory_sep_type_rules.h
@@ -0,0 +1,114 @@
+/********************* */
+/*! \file theory_sep_type_rules.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Typing and cardinality rules for the theory of sep
+ **
+ ** Typing and cardinality rules for the theory of sep.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H
+#define __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H
+
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sep {
+
+class SepNilRefTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return TypeNode::fromType( n.getConst<NilRef>().getType() );
+ }
+};
+
+class SepEmpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::SEP_EMP);
+ return nodeManager->booleanType();
+ }
+};
+
+struct SepPtoTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::SEP_PTO);
+ if( check ) {
+ TypeNode refType = n[0].getType(check);
+ TypeNode ptType = n[1].getType(check);
+ }
+ return nodeManager->booleanType();
+ }
+};/* struct SepSelectTypeRule */
+
+struct SepStarTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_STAR);
+ if( check ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TypeNode ctype = n[i].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep star is not Boolean");
+ }
+ }
+ }
+ return btype;
+ }
+};/* struct SepStarTypeRule */
+
+struct SepWandTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_WAND);
+ if( check ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TypeNode ctype = n[i].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep magic wand is not Boolean");
+ }
+ }
+ }
+ return btype;
+ }
+};/* struct SepWandTypeRule */
+
+struct SepLabelTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TypeNode btype = nodeManager->booleanType();
+ Assert(n.getKind() == kind::SEP_LABEL);
+ if( check ){
+ TypeNode ctype = n[0].getType( check );
+ if( ctype!=btype ){
+ throw TypeCheckingExceptionPrivate(n, "child of sep label is not Boolean");
+ }
+ TypeNode stype = n[1].getType( check );
+ if( !stype.isSet() ){
+ throw TypeCheckingExceptionPrivate(n, "label of sep label is not a set");
+ }
+ }
+ return btype;
+ }
+};/* struct SepLabelTypeRule */
+
+}/* CVC4::theory::sep namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__SEP__THEORY_SEP_TYPE_RULES_H */
diff --git a/src/theory/sets/kinds b/src/theory/sets/kinds
index 3fb73749d..c92eab4bd 100644
--- a/src/theory/sets/kinds
+++ b/src/theory/sets/kinds
@@ -64,6 +64,7 @@ typerule PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
typerule TRANSPOSE ::CVC4::theory::sets::RelTransposeTypeRule
typerule TCLOSURE ::CVC4::theory::sets::RelTransClosureTypeRule
+
construle UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index 217432670..37071eb2e 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -139,6 +139,20 @@ private:
*/
bool lemma(Node n, SetsLemmaTag t);
+ /** send out a lemma */
+ enum SetsLemmaTag {
+ SETS_LEMMA_DISEQUAL,
+ SETS_LEMMA_MEMBER,
+ SETS_LEMMA_GRAPH,
+ SETS_LEMMA_OTHER
+ };
+
+ /**
+ * returns true if a lemmas was generated
+ * returns false otherwise (found in cache)
+ */
+ bool lemma(Node n, SetsLemmaTag t);
+
class TermInfoManager {
TheorySetsPrivate& d_theory;
context::Context* d_context;
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index 92d6c9b6d..478dcbdb6 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -275,6 +275,7 @@ struct RelTransClosureTypeRule {
}
};/* struct RelTransClosureTypeRule */
+
struct SetsProperties {
inline static Cardinality computeCardinality(TypeNode type) {
Assert(type.getKind() == kind::SET_TYPE);
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index 53344dd6c..a665a02c1 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -39,6 +39,10 @@ RegExpOpr::RegExpOpr()
d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
}
+RegExpOpr::~RegExpOpr(){
+
+}
+
int RegExpOpr::gcd ( int a, int b ) {
int c;
while ( a != 0 ) {
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index c537553f2..075391370 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -99,6 +99,7 @@ private:
public:
RegExpOpr();
+ ~RegExpOpr();
bool checkConstRegExp( Node r );
void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index b3e1925ae..57344236e 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -28,6 +28,7 @@
#include "theory/strings/type_enumerator.h"
#include "theory/theory_model.h"
#include "theory/valuation.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4::context;
@@ -74,9 +75,11 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
d_preproc(u),
d_preproc_cache(u),
d_extf_infer_cache(c),
+ d_ee_disequalities(c),
d_congruent(c),
d_proxy_var(u),
d_proxy_var_to_length(u),
+ d_functionsTerms(c),
d_neg_ctn_eqlen(c),
d_neg_ctn_ulen(c),
d_neg_ctn_cached(u),
@@ -124,7 +127,9 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
}
TheoryStrings::~TheoryStrings() {
-
+ for( std::map< Node, EqcInfo* >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){
+ delete it->second;
+ }
}
Node TheoryStrings::getRepresentative( Node t ) {
@@ -467,18 +472,30 @@ void TheoryStrings::preRegisterTerm(TNode n) {
break;
}
default: {
- if( n.getType().isString() ) {
+ TypeNode tn = n.getType();
+ if( tn.isString() ) {
registerTerm( n, 0 );
// FMF
if( n.getKind() == kind::VARIABLE && options::stringFMF() ){
d_input_vars.insert(n);
}
- } else if (n.getType().isBoolean()) {
+ d_equalityEngine.addTerm(n);
+ } else if (tn.isBoolean()) {
// Get triggered for both equal and dis-equal
d_equalityEngine.addTriggerPredicate(n);
} else {
// Function applications/predicates
d_equalityEngine.addTerm(n);
+ if( options::stringExp() ){
+ //collect extended functions here: some may not be asserted to strings (such as those with return type Int),
+ // but we need to record them so they are treated properly
+ std::map< Node, bool > visited;
+ collectExtendedFuncTerms( n, visited );
+ }
+ }
+ //concat terms do not contribute to theory combination? TODO: verify
+ if( n.hasOperator() && kindToTheoryId( n.getKind() )==THEORY_STRINGS && n.getKind()!=kind::STRING_CONCAT ){
+ d_functionsTerms.push_back( n );
}
}
}
@@ -486,6 +503,7 @@ void TheoryStrings::preRegisterTerm(TNode n) {
}
Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
+ Trace("strings-exp-def") << "TheoryStrings::expandDefinition : " << node << std::endl;
return node;
}
@@ -740,53 +758,23 @@ void TheoryStrings::eqNotifyNewClass(TNode t){
/** called when two equivalance classes will merge */
void TheoryStrings::eqNotifyPreMerge(TNode t1, TNode t2){
- EqcInfo * e2 = getOrMakeEqcInfo(t2, false);
- if( e2 ){
- EqcInfo * e1 = getOrMakeEqcInfo( t1 );
- //add information from e2 to e1
- if( !e2->d_const_term.get().isNull() ){
- e1->d_const_term.set( e2->d_const_term );
- }
- if( !e2->d_length_term.get().isNull() ){
- e1->d_length_term.set( e2->d_length_term );
- }
- if( e2->d_cardinality_lem_k.get()>e1->d_cardinality_lem_k.get() ) {
- e1->d_cardinality_lem_k.set( e2->d_cardinality_lem_k );
- }
- if( !e2->d_normalized_length.get().isNull() ){
- e1->d_normalized_length.set( e2->d_normalized_length );
- }
+ EqcInfo * e2 = getOrMakeEqcInfo(t2, false);
+ if( e2 ){
+ EqcInfo * e1 = getOrMakeEqcInfo( t1 );
+ //add information from e2 to e1
+ if( !e2->d_const_term.get().isNull() ){
+ e1->d_const_term.set( e2->d_const_term );
}
- /*
- if( hasTerm( d_zero ) ){
- Node leqc;
- if( areEqual(d_zero, t1) ){
- leqc = t2;
- }else if( areEqual(d_zero, t2) ){
- leqc = t1;
- }
- if( !leqc.isNull() ){
- //scan equivalence class to see if we apply
- eq::EqClassIterator eqc_i = eq::EqClassIterator( leqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ){
- Node n = (*eqc_i);
- if( n.getKind()==kind::STRING_LENGTH ){
- if( !hasTerm( d_emptyString ) || !areEqual(n[0], d_emptyString ) ){
- //apply the rule length(n[0])==0 => n[0] == ""
- Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, n[0], d_emptyString );
- d_pending.push_back( eq );
- Node eq_exp = NodeManager::currentNM()->mkNode( kind::EQUAL, n, d_zero );
- d_pending_exp[eq] = eq_exp;
- Trace("strings-infer") << "Strings : Infer Empty : " << eq << " from " << eq_exp << std::endl;
- d_infer.push_back(eq);
- d_infer_exp.push_back(eq_exp);
- }
- }
- ++eqc_i;
- }
- }
+ if( !e2->d_length_term.get().isNull() ){
+ e1->d_length_term.set( e2->d_length_term );
+ }
+ if( e2->d_cardinality_lem_k.get()>e1->d_cardinality_lem_k.get() ) {
+ e1->d_cardinality_lem_k.set( e2->d_cardinality_lem_k );
}
- */
+ if( !e2->d_normalized_length.get().isNull() ){
+ e1->d_normalized_length.set( e2->d_normalized_length );
+ }
+ }
}
/** called when two equivalance classes have merged */
@@ -796,11 +784,106 @@ void TheoryStrings::eqNotifyPostMerge(TNode t1, TNode t2) {
/** called when two equivalance classes are disequal */
void TheoryStrings::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ if( t1.getType().isString() ){
+ //store disequalities between strings, may need to check if their lengths are equal/disequal
+ d_ee_disequalities.push_back( t1.eqNode( t2 ) );
+ }
+}
+void TheoryStrings::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth ) {
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !d_equalityEngine.areEqual( f1, f2 ) ){
+ Trace("strings-cg-debug") << "TheoryStrings::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
+ vector< pair<TNode, TNode> > currentPairs;
+ for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+ TNode x = f1[k];
+ TNode y = f2[k];
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !d_equalityEngine.areDisequal( x, y, false ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_STRINGS) && d_equalityEngine.isTriggerTerm(y, THEORY_STRINGS) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_STRINGS);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_STRINGS);
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
+ }
+ }
+ }
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Trace("strings-cg-pair") << "TheoryStrings::computeCareGraph(): pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
+ Trace("ajr-temp") << currentPairs[c].first << ", " << currentPairs[c].second << std::endl;
+ addCarePair(currentPairs[c].first, currentPairs[c].second);
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1 );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
+ }
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
+ }
+ }
+ }
+ }
+ }
}
void TheoryStrings::computeCareGraph(){
- Theory::computeCareGraph();
+ //computing the care graph here is probably still necessary, due to operators that take non-string arguments TODO: verify
+ Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Build term indices..." << std::endl;
+ std::map< Node, quantifiers::TermArgTrie > index;
+ std::map< Node, unsigned > arity;
+ unsigned functionTerms = d_functionsTerms.size();
+ for (unsigned i = 0; i < functionTerms; ++ i) {
+ TNode f1 = d_functionsTerms[i];
+ Trace("strings-cg") << "...build for " << f1 << std::endl;
+ Node op = f1.getOperator();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_STRINGS ) ){
+ has_trigger_arg = true;
+ }
+ }
+ if( has_trigger_arg ){
+ index[op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = index.begin(); itii != index.end(); ++itii ){
+ Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Process index " << itii->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0 );
+ }
}
void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
@@ -1136,8 +1219,12 @@ void TheoryStrings::checkExtendedFuncsEval( int effort ) {
}else{
if( !areEqual( n, nrc ) ){
if( n.getType().isBoolean() ){
- d_extf_exp[n].push_back( nrc==d_true ? n.negate() : n );
- conc = d_false;
+ if( areEqual( n, nrc==d_true ? d_false : d_true ) ){
+ d_extf_exp[n].push_back( nrc==d_true ? n.negate() : n );
+ conc = d_false;
+ }else{
+ conc = nrc==d_true ? n : n.negate();
+ }
}else{
conc = n.eqNode( nrc );
}
@@ -1145,7 +1232,7 @@ void TheoryStrings::checkExtendedFuncsEval( int effort ) {
}
if( !conc.isNull() ){
Trace("strings-extf") << " resolve extf : " << nr << " -> " << nrc << std::endl;
- sendInference( d_extf_exp[n], conc, effort==0 ? "EXTF" : "EXTF-N", n.getType().isInteger() || d_extf_exp[n].empty() );
+ sendInference( d_extf_exp[n], conc, effort==0 ? "EXTF" : "EXTF-N", true );
if( d_conflict ){
Trace("strings-extf-debug") << " conflict, return." << std::endl;
return;
@@ -1745,9 +1832,9 @@ bool TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & n
}
nf.insert( nf.end(), normal_forms[nf_index].begin(), normal_forms[nf_index].end() );
nf_exp.insert( nf_exp.end(), normal_forms_exp[nf_index].begin(), normal_forms_exp[nf_index].end() );
- //if( eqc!=normal_form_src[nf_index] ){
- // nf_exp.push_back( eqc.eqNode( normal_form_src[nf_index] ) );
- //}
+ if( eqc!=normal_form_src[nf_index] ){
+ nf_exp.push_back( eqc.eqNode( normal_form_src[nf_index] ) );
+ }
Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
d_normal_forms_base[eqc] = normal_form_src[nf_index];
//*/
@@ -2639,23 +2726,17 @@ int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node
void TheoryStrings::addNormalFormPair( Node n1, Node n2 ){
if( !isNormalFormPair( n1, n2 ) ){
- //Assert( !isNormalFormPair( n1, n2 ) );
- NodeList* lst;
- NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
- if( nf_i == d_nf_pairs.end() ){
- if( d_nf_pairs.find( n2 )!=d_nf_pairs.end() ){
- addNormalFormPair( n2, n1 );
- return;
- }
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_nf_pairs.insertDataFromContextMemory( n1, lst );
- Trace("strings-nf") << "Create cache for " << n1 << std::endl;
- } else {
- lst = (*nf_i).second;
- }
- Trace("strings-nf") << "Add normal form pair : " << n1 << " " << n2 << std::endl;
- lst->push_back( n2 );
+ int index = 0;
+ NodeIntMap::const_iterator it = d_nf_pairs.find( n1 );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ }
+ d_nf_pairs[n1] = index + 1;
+ if( index<(int)d_nf_pairs_data[n1].size() ){
+ d_nf_pairs_data[n1][index] = n2;
+ }else{
+ d_nf_pairs_data[n1].push_back( n2 );
+ }
Assert( isNormalFormPair( n1, n2 ) );
} else {
Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
@@ -2668,15 +2749,14 @@ bool TheoryStrings::isNormalFormPair( Node n1, Node n2 ) {
}
bool TheoryStrings::isNormalFormPair2( Node n1, Node n2 ) {
- //Trace("strings-debug") << "is normal form pair. " << n1 << " " << n2 << std::endl;
- NodeList* lst;
- NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
- if( nf_i != d_nf_pairs.end() ) {
- lst = (*nf_i).second;
- for( NodeList::const_iterator i = lst->begin(); i != lst->end(); ++i ) {
- Node n = *i;
- if( n==n2 ) {
- return true;
+ //Trace("strings-debug") << "is normal form pair. " << n1 << " " << n2 << std::endl;
+ NodeIntMap::const_iterator it = d_nf_pairs.find( n1 );
+ if( it!=d_nf_pairs.end() ){
+ Assert( d_nf_pairs_data.find( n1 )!=d_nf_pairs_data.end() );
+ for( int i=0; i<(*it).second; i++ ){
+ Assert( i<(int)d_nf_pairs_data[n1].size() );
+ if( d_nf_pairs_data[n1][i]==n2 ){
+ return true;
}
}
}
@@ -2752,7 +2832,7 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
eq = eq.isNull() ? d_false : Rewriter::rewrite( eq );
if( eq!=d_true ){
if( Trace.isOn("strings-infer-debug") ){
- Trace("strings-infer-debug") << "infer : " << eq << " from: " << std::endl;
+ Trace("strings-infer-debug") << "By " << c << ", infer : " << eq << " from: " << std::endl;
for( unsigned i=0; i<exp.size(); i++ ){
Trace("strings-infer-debug") << " " << exp[i] << std::endl;
}
@@ -2761,8 +2841,8 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
}
//Trace("strings-infer-debug") << "as lemma : " << asLemma << std::endl;
}
- bool doSendLemma = ( asLemma || eq==d_false || eq.getKind()==kind::OR || options::stringInferAsLemmas() );
- if( doSendLemma ){
+ //check if we should send a lemma or an inference
+ if( asLemma || eq==d_false || eq.getKind()==kind::OR || !exp_n.empty() || options::stringInferAsLemmas() ){
Node eq_exp;
if( options::stringRExplainLemmas() ){
eq_exp = mkExplain( exp, exp_n );
@@ -2780,7 +2860,6 @@ void TheoryStrings::sendInference( std::vector< Node >& exp, std::vector< Node >
}
sendLemma( eq_exp, eq, c );
}else{
- Assert( exp_n.empty() );
sendInfer( mkAnd( exp ), eq, c );
}
}
@@ -3064,30 +3143,56 @@ void TheoryStrings::getConcatVec( Node n, std::vector< Node >& c ) {
void TheoryStrings::checkDeqNF() {
std::vector< std::vector< Node > > cols;
std::vector< Node > lts;
- separateByLength( d_strings_eqc, cols, lts );
- for( unsigned i=0; i<cols.size(); i++ ){
- if( cols[i].size()>1 && d_lemma_cache.empty() ){
- Trace("strings-solve") << "- Verify disequalities are processed for " << cols[i][0];
- printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
- Trace("strings-solve") << "... #eql = " << cols[i].size() << std::endl;
- //must ensure that normal forms are disequal
- for( unsigned j=0; j<cols[i].size(); j++ ){
- for( unsigned k=(j+1); k<cols[i].size(); k++ ){
- if( areDisequal( cols[i][j], cols[i][k] ) ){
- Assert( !d_conflict );
- //if( !areDisequal( cols[i][j], cols[i][k] ) ){
- // sendSplit( cols[i][j], cols[i][k], "D-NORM", true );
- // return;
- //}else{
- Trace("strings-solve") << "- Compare " << cols[i][j] << " ";
- printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
- Trace("strings-solve") << " against " << cols[i][k] << " ";
- printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
- Trace("strings-solve") << "..." << std::endl;
- if( processDeq( cols[i][j], cols[i][k] ) ){
- return;
+ std::map< Node, std::map< Node, bool > > processed;
+
+ //for each pair of disequal strings, must determine whether their lengths are equal or disequal
+ bool addedLSplit = false;
+ for( NodeList::const_iterator id = d_ee_disequalities.begin(); id != d_ee_disequalities.end(); ++id ) {
+ Node eq = *id;
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ n[i] = d_equalityEngine.getRepresentative( eq[i] );
+ }
+ if( processed[n[0]].find( n[1] )==processed[n[0]].end() ){
+ processed[n[0]][n[1]] = true;
+ Node lt[2];
+ for( unsigned i=0; i<2; i++ ){
+ EqcInfo* ei = getOrMakeEqcInfo( n[i], false );
+ lt[i] = ei ? ei->d_length_term : Node::null();
+ if( lt[i].isNull() ){
+ lt[i] = eq[i];
+ }
+ lt[i] = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt[i] );
+ }
+ if( !areEqual( lt[0], lt[1] ) && !areDisequal( lt[0], lt[1] ) ){
+ addedLSplit = true;
+ sendSplit( lt[0], lt[1], "DEQ-LENGTH-SP" );
+ }
+ }
+ }
+
+ if( !addedLSplit ){
+ separateByLength( d_strings_eqc, cols, lts );
+ for( unsigned i=0; i<cols.size(); i++ ){
+ if( cols[i].size()>1 && d_lemma_cache.empty() ){
+ Trace("strings-solve") << "- Verify disequalities are processed for " << cols[i][0] << ", normal form : ";
+ printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
+ Trace("strings-solve") << "... #eql = " << cols[i].size() << std::endl;
+ //must ensure that normal forms are disequal
+ for( unsigned j=0; j<cols[i].size(); j++ ){
+ for( unsigned k=(j+1); k<cols[i].size(); k++ ){
+ //for strings that are disequal, but have the same length
+ if( areDisequal( cols[i][j], cols[i][k] ) ){
+ Assert( !d_conflict );
+ Trace("strings-solve") << "- Compare " << cols[i][j] << " ";
+ printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
+ Trace("strings-solve") << " against " << cols[i][k] << " ";
+ printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ if( processDeq( cols[i][j], cols[i][k] ) ){
+ return;
+ }
}
- //}
}
}
}
@@ -3149,6 +3254,9 @@ void TheoryStrings::checkCardinality() {
//int cardinality = options::stringCharCardinality();
//Trace("strings-solve-debug2") << "get cardinality: " << cardinality << endl;
+ //AJR: this will create a partition of eqc, where each collection has length that are pairwise propagated to be equal.
+ // we do not require disequalities between the lengths of each collection, since we split on disequalities between lengths of string terms that are disequal (DEQ-LENGTH-SP).
+ // TODO: revisit this?
std::vector< std::vector< Node > > cols;
std::vector< Node > lts;
separateByLength( d_strings_eqc, cols, lts );
@@ -3159,54 +3267,51 @@ void TheoryStrings::checkCardinality() {
if( cols[i].size() > 1 ) {
// size > c^k
unsigned card_need = 1;
- double curr = (double)cols[i].size()-1;
+ double curr = (double)cols[i].size();
while( curr>d_card_size ){
curr = curr/(double)d_card_size;
card_need++;
}
+ Trace("strings-card") << "Need length " << card_need << " for this number of strings (where alphabet size is " << d_card_size << ")." << std::endl;
Node cmp = NodeManager::currentNM()->mkNode( kind::GEQ, lr, NodeManager::currentNM()->mkConst( Rational( card_need ) ) );
cmp = Rewriter::rewrite( cmp );
if( cmp!=d_true ){
unsigned int int_k = (unsigned int)card_need;
- bool allDisequal = true;
for( std::vector< Node >::iterator itr1 = cols[i].begin();
itr1 != cols[i].end(); ++itr1) {
for( std::vector< Node >::iterator itr2 = itr1 + 1;
itr2 != cols[i].end(); ++itr2) {
if(!areDisequal( *itr1, *itr2 )) {
- allDisequal = false;
// add split lemma
sendSplit( *itr1, *itr2, "CARD-SP" );
return;
}
}
}
- if( allDisequal ){
- EqcInfo* ei = getOrMakeEqcInfo( lr, true );
- Trace("strings-card") << "Previous cardinality used for " << lr << " is " << ((int)ei->d_cardinality_lem_k.get()-1) << std::endl;
- if( int_k+1 > ei->d_cardinality_lem_k.get() ){
- Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
- //add cardinality lemma
- Node dist = NodeManager::currentNM()->mkNode( kind::DISTINCT, cols[i] );
- std::vector< Node > vec_node;
- vec_node.push_back( dist );
- for( std::vector< Node >::iterator itr1 = cols[i].begin();
- itr1 != cols[i].end(); ++itr1) {
- Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr1 );
- if( len!=lr ) {
- Node len_eq_lr = len.eqNode(lr);
- vec_node.push_back( len_eq_lr );
- }
- }
- Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
- Node cons = NodeManager::currentNM()->mkNode( kind::GEQ, len, k_node );
- cons = Rewriter::rewrite( cons );
- ei->d_cardinality_lem_k.set( int_k+1 );
- if( cons!=d_true ){
- sendInference( d_empty_vec, vec_node, cons, "CARDINALITY", true );
- return;
+ EqcInfo* ei = getOrMakeEqcInfo( lr, true );
+ Trace("strings-card") << "Previous cardinality used for " << lr << " is " << ((int)ei->d_cardinality_lem_k.get()-1) << std::endl;
+ if( int_k+1 > ei->d_cardinality_lem_k.get() ){
+ Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
+ //add cardinality lemma
+ Node dist = NodeManager::currentNM()->mkNode( kind::DISTINCT, cols[i] );
+ std::vector< Node > vec_node;
+ vec_node.push_back( dist );
+ for( std::vector< Node >::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end(); ++itr1) {
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr1 );
+ if( len!=lr ) {
+ Node len_eq_lr = len.eqNode(lr);
+ vec_node.push_back( len_eq_lr );
}
}
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
+ Node cons = NodeManager::currentNM()->mkNode( kind::GEQ, len, k_node );
+ cons = Rewriter::rewrite( cons );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( cons!=d_true ){
+ sendInference( d_empty_vec, vec_node, cons, "CARDINALITY", true );
+ return;
+ }
}
}
}
@@ -3275,11 +3380,9 @@ void TheoryStrings::separateByLength(std::vector< Node >& n,
Assert( d_equalityEngine.getRepresentative(eqc)==eqc );
EqcInfo* ei = getOrMakeEqcInfo( eqc, false );
Node lt = ei ? ei->d_length_term : Node::null();
- Trace("ajr-temp") << "Length term for " << eqc << " is " << lt << std::endl;
if( !lt.isNull() ){
lt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
Node r = d_equalityEngine.getRepresentative( lt );
- Trace("ajr-temp") << "Length term rep for " << eqc << " is " << lt << std::endl;
if( eqc_to_leqc.find( r )==eqc_to_leqc.end() ){
eqc_to_leqc[r] = leqc_counter;
leqc_to_eqc[leqc_counter] = r;
@@ -3318,6 +3421,26 @@ void TheoryStrings::updateMpl( Node n, int b ) {
}
*/
+
+unsigned TheoryStrings::getNumMemberships( Node n, bool isPos ) {
+ if( isPos ){
+ NodeIntMap::const_iterator it = d_pos_memberships.find( n );
+ if( it!=d_pos_memberships.end() ){
+ return (*it).second;
+ }
+ }else{
+ NodeIntMap::const_iterator it = d_neg_memberships.find( n );
+ if( it!=d_neg_memberships.end() ){
+ return (*it).second;
+ }
+ }
+ return 0;
+}
+
+Node TheoryStrings::getMembership( Node n, bool isPos, unsigned i ) {
+ return isPos ? d_pos_memberships_data[n][i] : d_neg_memberships_data[n][i];
+}
+
//// Regular Expressions
Node TheoryStrings::mkRegExpAntec(Node atom, Node ant) {
if(d_regexp_ant.find(atom) == d_regexp_ant.end()) {
@@ -3395,10 +3518,8 @@ bool TheoryStrings::normalizePosMemberships(std::map< Node, std::vector< Node >
Trace("regexp-check") << "Normalizing Positive Memberships ... " << std::endl;
- for(NodeListMap::const_iterator itr_xr = d_pos_memberships.begin();
- itr_xr != d_pos_memberships.end(); ++itr_xr ) {
+ for( NodeIntMap::const_iterator itr_xr = d_pos_memberships.begin(); itr_xr != d_pos_memberships.end(); ++itr_xr ){
Node x = (*itr_xr).first;
- NodeList* lst = (*itr_xr).second;
Node nf_x = x;
std::vector< Node > nf_x_exp;
if(d_normal_forms.find( x ) != d_normal_forms.end()) {
@@ -3412,10 +3533,11 @@ bool TheoryStrings::normalizePosMemberships(std::map< Node, std::vector< Node >
std::vector< Node > vec_x;
std::vector< Node > vec_r;
- for(NodeList::const_iterator itr_lst = lst->begin();
- itr_lst != lst->end(); ++itr_lst) {
- Node r = *itr_lst;
- Node nf_r = normalizeRegexp((*lst)[0]);
+ unsigned n_pmem = (*itr_xr).second;
+ Assert( getNumMemberships( x, true )==n_pmem );
+ for( unsigned k=0; k<n_pmem; k++ ){
+ Node r = getMembership( x, true, k );
+ Node nf_r = normalizeRegexp( r ); //AJR: fixed (was normalizing mem #0 always)
Node memb = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, nf_x, nf_r);
if(d_processed_memberships.find(memb) == d_processed_memberships.end()) {
if(d_regexp_opr.checkConstRegExp(nf_r)) {
@@ -3645,46 +3767,43 @@ void TheoryStrings::checkMemberships() {
Trace("regexp-debug") << "Checking Memberships ... " << std::endl;
//if(options::stringEIT()) {
//TODO: Opt for normal forms
- for(NodeListMap::const_iterator itr_xr = d_pos_memberships.begin();
- itr_xr != d_pos_memberships.end(); ++itr_xr ) {
+ for( NodeIntMap::const_iterator itr_xr = d_pos_memberships.begin(); itr_xr != d_pos_memberships.end(); ++itr_xr ){
bool spflag = false;
Node x = (*itr_xr).first;
- NodeList* lst = (*itr_xr).second;
Trace("regexp-debug") << "Checking Memberships for " << x << std::endl;
if(d_inter_index.find(x) == d_inter_index.end()) {
d_inter_index[x] = 0;
}
int cur_inter_idx = d_inter_index[x];
- if(cur_inter_idx != (int)lst->size()) {
- if(lst->size() == 1) {
- d_inter_cache[x] = (*lst)[0];
+ unsigned n_pmem = (*itr_xr).second;
+ Assert( getNumMemberships( x, true )==n_pmem );
+ if( cur_inter_idx != (int)n_pmem ) {
+ if( n_pmem == 1) {
+ d_inter_cache[x] = getMembership( x, true, 0 );
d_inter_index[x] = 1;
Trace("regexp-debug") << "... only one choice " << std::endl;
- } else if(lst->size() > 1) {
+ } else if(n_pmem > 1) {
Node r;
if(d_inter_cache.find(x) != d_inter_cache.end()) {
r = d_inter_cache[x];
}
if(r.isNull()) {
- r = (*lst)[0];
+ r = getMembership( x, true, 0 );
cur_inter_idx = 1;
}
- NodeList::const_iterator itr_lst = lst->begin();
- for(int i=0; i<cur_inter_idx; i++) {
- ++itr_lst;
- }
- Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << lst->size() << std::endl;
- for(;itr_lst != lst->end(); ++itr_lst) {
- Node r2 = *itr_lst;
+
+ unsigned k_start = cur_inter_idx;
+ Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << n_pmem << std::endl;
+ for(unsigned k = k_start; k<n_pmem; k++) {
+ Node r2 = getMembership( x, true, k );
r = d_regexp_opr.intersect(r, r2, spflag);
if(spflag) {
break;
} else if(r == d_emptyRegexp) {
std::vector< Node > vec_nodes;
- ++itr_lst;
- for(NodeList::const_iterator itr2 = lst->begin();
- itr2 != itr_lst; ++itr2) {
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, *itr2);
+ for( unsigned kk=0; kk<=k; kk++ ){
+ Node rr = getMembership( x, true, kk );
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, rr);
vec_nodes.push_back( n );
}
Node conc;
@@ -3699,7 +3818,7 @@ void TheoryStrings::checkMemberships() {
//updates
if(!d_conflict && !spflag) {
d_inter_cache[x] = r;
- d_inter_index[x] = (int)lst->size();
+ d_inter_index[x] = (int)n_pmem;
}
}
}
@@ -4322,44 +4441,52 @@ void TheoryStrings::addMembership(Node assertion) {
Node x = atom[0];
Node r = atom[1];
if(polarity) {
- NodeList* lst;
- NodeListMap::iterator itr_xr = d_pos_memberships.find( x );
- if( itr_xr == d_pos_memberships.end() ){
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_pos_memberships.insertDataFromContextMemory( x, lst );
- } else {
- lst = (*itr_xr).second;
- }
- //check
- for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
- if( r == *itr ) {
- return;
+ int index = 0;
+ NodeIntMap::const_iterator it = d_pos_memberships.find( x );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ for( int k=0; k<index; k++ ){
+ if( k<(int)d_pos_memberships_data[x].size() ){
+ if( d_pos_memberships_data[x][k]==r ){
+ return;
+ }
+ }else{
+ break;
+ }
}
}
- lst->push_back( r );
+ d_pos_memberships[x] = index + 1;
+ if( index<(int)d_pos_memberships_data[x].size() ){
+ d_pos_memberships_data[x][index] = r;
+ }else{
+ d_pos_memberships_data[x].push_back( r );
+ }
} else if(!options::stringIgnNegMembership()) {
/*if(options::stringEIT() && d_regexp_opr.checkConstRegExp(r)) {
int rt;
Node r2 = d_regexp_opr.complement(r, rt);
Node a = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r2);
}*/
- NodeList* lst;
- NodeListMap::iterator itr_xr = d_neg_memberships.find( x );
- if( itr_xr == d_neg_memberships.end() ){
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_neg_memberships.insertDataFromContextMemory( x, lst );
- } else {
- lst = (*itr_xr).second;
- }
- //check
- for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
- if( r == *itr ) {
- return;
+ int index = 0;
+ NodeIntMap::const_iterator it = d_neg_memberships.find( x );
+ if( it!=d_nf_pairs.end() ){
+ index = (*it).second;
+ for( int k=0; k<index; k++ ){
+ if( k<(int)d_neg_memberships_data[x].size() ){
+ if( d_neg_memberships_data[x][k]==r ){
+ return;
+ }
+ }else{
+ break;
+ }
}
}
- lst->push_back( r );
+ d_neg_memberships[x] = index + 1;
+ if( index<(int)d_neg_memberships_data[x].size() ){
+ d_neg_memberships_data[x][index] = r;
+ }else{
+ d_neg_memberships_data[x].push_back( r );
+ }
}
// old
if(polarity || !options::stringIgnNegMembership()) {
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index b9da524de..2deb09654 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -33,6 +33,11 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace strings {
/**
@@ -45,7 +50,6 @@ typedef expr::Attribute< StringsProxyVarAttributeId, bool > StringsProxyVarAttri
class TheoryStrings : public Theory {
typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
@@ -160,7 +164,8 @@ private:
std::map< Node, std::vector< Node > > d_normal_forms_exp;
std::map< Node, std::map< Node, std::map< bool, int > > > d_normal_forms_exp_depend;
//map of pairs of terms that have the same normal form
- NodeListMap d_nf_pairs;
+ NodeIntMap d_nf_pairs;
+ std::map< Node, std::vector< Node > > d_nf_pairs_data;
void addNormalFormPair( Node n1, Node n2 );
bool isNormalFormPair( Node n1, Node n2 );
bool isNormalFormPair2( Node n1, Node n2 );
@@ -176,6 +181,8 @@ private:
// extended functions inferences cache
NodeSet d_extf_infer_cache;
std::vector< Node > d_empty_vec;
+ //
+ NodeList d_ee_disequalities;
private:
NodeSet d_congruent;
std::map< Node, Node > d_eqc_to_const;
@@ -236,6 +243,8 @@ private:
//maintain which concat terms have the length lemma instantiated
NodeNodeMap d_proxy_var;
NodeNodeMap d_proxy_var_to_length;
+ /** All the function terms that the theory has seen */
+ context::CDList<TNode> d_functionsTerms;
private:
//initial check
void checkInit();
@@ -304,6 +313,8 @@ private:
//cardinality check
void checkCardinality();
+private:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth );
public:
/** preregister term */
void preRegisterTerm(TNode n);
@@ -410,8 +421,12 @@ private:
NodeSet d_regexp_ucached;
NodeSet d_regexp_ccached;
// stored assertions
- NodeListMap d_pos_memberships;
- NodeListMap d_neg_memberships;
+ NodeIntMap d_pos_memberships;
+ std::map< Node, std::vector< Node > > d_pos_memberships_data;
+ NodeIntMap d_neg_memberships;
+ std::map< Node, std::vector< Node > > d_neg_memberships_data;
+ unsigned getNumMemberships( Node n, bool isPos );
+ Node getMembership( Node n, bool isPos, unsigned i );
// semi normal forms for symbolic expression
std::map< Node, Node > d_nf_regexps;
std::map< Node, std::vector< Node > > d_nf_regexps_exp;
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index a4f42bddd..ba811644a 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -33,6 +33,10 @@ StringsPreprocess::StringsPreprocess( context::UserContext* u ) : d_cache( u ){
d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
}
+StringsPreprocess::~StringsPreprocess(){
+
+}
+
/*
int StringsPreprocess::checkFixLenVar( Node t ) {
int ret = 2;
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
index 5bc9667ea..abc7b5a91 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -40,6 +40,7 @@ private:
Node simplify( Node t, std::vector< Node > &new_nodes );
public:
StringsPreprocess( context::UserContext* u );
+ ~StringsPreprocess();
Node decompose( Node t, std::vector< Node > &new_nodes );
void simplify(std::vector< Node > &vec_node);
diff --git a/src/theory/term_registration_visitor.cpp b/src/theory/term_registration_visitor.cpp
index 830e7f809..e758002fa 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -37,8 +37,12 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE /*||
- parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
+ parent.getKind() == kind::REWRITE_RULE ||
+ parent.getKind() == kind::SEP_STAR ||
+ parent.getKind() == kind::SEP_WAND ||
+ ( parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean() )
+ // parent.getKind() == kind::CARDINALITY_CONSTRAINT
+ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
@@ -64,14 +68,8 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -130,14 +128,8 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -189,8 +181,12 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE /*||
- parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
+ parent.getKind() == kind::REWRITE_RULE ||
+ parent.getKind() == kind::SEP_STAR ||
+ parent.getKind() == kind::SEP_WAND ||
+ ( parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean() )
+ // parent.getKind() == kind::CARDINALITY_CONSTRAINT
+ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
@@ -222,14 +218,8 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -244,14 +234,8 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
@@ -297,14 +281,8 @@ void SharedTermsVisitor::visit(TNode current, TNode parent) {
TypeNode type = current.getType();
typeTheoryId = Theory::theoryOf(type);
if (typeTheoryId != currentTheoryId) {
- if (options::finiteModelFind() && type.isSort()) {
- // We're looking for finite models
+ if (type.isInterpretedFinite()) {
useType = true;
- } else {
- Cardinality card = type.getCardinality();
- if (card.isFinite()) {
- useType = true;
- }
}
}
}
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 382d4cf65..e8518b1f6 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -781,6 +781,14 @@ public:
assertions_iterator facts_end() const {
return d_facts.end();
}
+ /**
+ * Whether facts have been asserted to this theory.
+ *
+ * @return true iff facts have been asserted to this theory.
+ */
+ bool hasFacts() {
+ return !d_facts.empty();
+ }
typedef context::CDList<TNode>::const_iterator shared_terms_iterator;
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index f2231ff7a..881acdddd 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -26,6 +26,8 @@
#include "options/bv_options.h"
#include "options/options.h"
#include "options/quantifiers_options.h"
+#include "proof/cnf_proof.h"
+#include "proof/lemma_proof.h"
#include "proof/proof_manager.h"
#include "proof/theory_proof.h"
#include "smt/ite_removal.h"
@@ -53,6 +55,104 @@ using namespace CVC4::theory;
namespace CVC4 {
+inline void flattenAnd(Node n, std::vector<TNode>& out){
+ Assert(n.getKind() == kind::AND);
+ for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){
+ Node curr = *i;
+ if(curr.getKind() == kind::AND){
+ flattenAnd(curr, out);
+ }else{
+ out.push_back(curr);
+ }
+ }
+}
+
+inline Node flattenAnd(Node n){
+ std::vector<TNode> out;
+ flattenAnd(n, out);
+ return NodeManager::currentNM()->mkNode(kind::AND, out);
+}
+
+theory::LemmaStatus TheoryEngine::EngineOutputChannel::lemma(TNode lemma,
+ ProofRule rule,
+ bool removable,
+ bool preprocess,
+ bool sendAtoms)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
+ Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << ", preprocess = " << preprocess << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ PROOF({
+ // Theory lemmas have one step that proves the empty clause
+ proofRecipe = new LemmaProofRecipe;
+
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(d_theory, emptyNode);
+
+ Node rewritten;
+ if (lemma.getKind() == kind::OR) {
+ for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
+ rewritten = theory::Rewriter::rewrite(lemma[i]);
+ if (rewritten != lemma[i]) {
+ proofRecipe->addRewriteRule(lemma[i].negate(), rewritten.negate());
+ }
+ proofStep.addAssertion(lemma[i]);
+ proofRecipe->addBaseAssertion(rewritten);
+ }
+ } else {
+ rewritten = theory::Rewriter::rewrite(lemma);
+ if (rewritten != lemma) {
+ proofRecipe->addRewriteRule(lemma.negate(), rewritten.negate());
+ }
+ proofStep.addAssertion(lemma);
+ proofRecipe->addBaseAssertion(rewritten);
+ }
+ proofRecipe->addStep(proofStep);
+ });
+
+ theory::LemmaStatus result = d_engine->lemma(lemma,
+ rule,
+ false,
+ removable,
+ preprocess,
+ sendAtoms ? d_theory : theory::THEORY_LAST,
+ proofRecipe);
+ PROOF(delete proofRecipe;);
+ return result;
+}
+
+theory::LemmaStatus TheoryEngine::EngineOutputChannel::splitLemma(TNode lemma, bool removable)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
+ Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ Debug("pf::explain") << "TheoryEngine::EngineOutputChannel::splitLemma( " << lemma << " )" << std::endl;
+ theory::LemmaStatus result = d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory, proofRecipe);
+ return result;
+}
+
+bool TheoryEngine::EngineOutputChannel::propagate(TNode literal)
+ throw(AssertionException, UnsafeInterruptException) {
+ Debug("theory::propagate") << "EngineOutputChannel<" << d_theory << ">::propagate(" << literal << ")" << std::endl;
+ ++ d_statistics.propagations;
+ d_engine->d_outputChannelUsed = true;
+ return d_engine->propagate(literal, d_theory);
+}
+
+void TheoryEngine::EngineOutputChannel::conflict(TNode conflictNode, Proof* pf)
+ throw(AssertionException, UnsafeInterruptException) {
+ Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
+ Assert (pf == NULL); // Theory shouldn't be producing proofs yet
+ ++ d_statistics.conflicts;
+ d_engine->d_outputChannelUsed = true;
+ d_engine->conflict(conflictNode, d_theory);
+}
+
void TheoryEngine::finishInit() {
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
@@ -161,7 +261,9 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- PROOF (ProofManager::currentPM()->initTheoryProofEngine(); );
+#ifdef CVC4_PROOF
+ ProofManager::currentPM()->initTheoryProofEngine();
+#endif
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
@@ -416,18 +518,29 @@ void TheoryEngine::check(Theory::Effort effort) {
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
if( effort == Theory::EFFORT_FULL && ! d_inConflict && ! needCheck() ) {
- //d_theoryTable[THEORY_STRINGS]->check(Theory::EFFORT_LAST_CALL);
- if(d_logicInfo.isQuantified()) {
- // quantifiers engine must pass effort last call check
- d_quantEngine->check(Theory::EFFORT_LAST_CALL);
- // if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built
- } else if(options::produceModels()) {
- // must build model at this point
- d_curr_model_builder->buildModel(d_curr_model, true);
+ //calls to theories requiring the model go here
+ //FIXME: this should not be theory-specific
+ if(d_logicInfo.isTheoryEnabled(THEORY_SEP)) {
+ Assert( d_theoryTable[THEORY_SEP]!=NULL );
+ if( d_theoryTable[THEORY_SEP]->hasFacts() ){
+ // must build model at this point
+ d_curr_model_builder->buildModel(getModel(), false);
+ d_theoryTable[THEORY_SEP]->check(Theory::EFFORT_LAST_CALL);
+ }
}
- Trace("theory::assertions-model") << endl;
- if (Trace.isOn("theory::assertions-model")) {
- printAssertions("theory::assertions-model");
+ if( ! d_inConflict && ! needCheck() ){
+ if(d_logicInfo.isQuantified()) {
+ // quantifiers engine must pass effort last call check
+ d_quantEngine->check(Theory::EFFORT_LAST_CALL);
+ // if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built
+ } else if(options::produceModels()) {
+ // must build model at this point
+ d_curr_model_builder->buildModel(getModel(), true);
+ }
+ Trace("theory::assertions-model") << endl;
+ if (Trace.isOn("theory::assertions-model")) {
+ printAssertions("theory::assertions-model");
+ }
}
}
@@ -497,7 +610,10 @@ void TheoryEngine::combineTheories() {
// We need to split on it
Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
- lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory, carePair.theory);
+
+ LemmaProofRecipe* proofRecipe = NULL;
+ lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory, proofRecipe);
+
// This code is supposed to force preference to follow what the theory models already have
// but it doesn't seem to make a big difference - need to explore more -Clark
// if (true) {
@@ -963,7 +1079,7 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
- Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl;
Assert(toTheoryId != fromTheoryId);
if(toTheoryId != THEORY_SAT_SOLVER &&
@@ -1176,6 +1292,23 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
}
} else {
+ // We could be propagating a unit-clause lemma. In this case, we need to provide a
+ // recipe.
+ // TODO: Consider putting this someplace else? This is the only refence to the proof
+ // manager in this class.
+
+ PROOF({
+ LemmaProofRecipe proofRecipe;
+ proofRecipe.addBaseAssertion(literal);
+
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theory, emptyNode);
+ proofStep.addAssertion(literal);
+ proofRecipe.addStep(proofStep);
+
+ ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
+ });
+
// Just send off to the SAT solver
Assert(d_propEngine->isSatLiteral(literal));
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
@@ -1270,7 +1403,7 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
return conjunction;
}
-NodeTheoryPair TheoryEngine::getExplanationAndExplainer(TNode node) {
+Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) {
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
@@ -1278,32 +1411,90 @@ NodeTheoryPair TheoryEngine::getExplanationAndExplainer(TNode node) {
// If we're not in shared mode, explanations are simple
if (!d_logicInfo.isSharingEnabled()) {
+ Debug("theory::explain") << "TheoryEngine::getExplanation: sharing is NOT enabled. "
+ << " Responsible theory is: "
+ << theoryOf(atom)->getId() << std::endl;
+
Node explanation = theoryOf(atom)->explain(node);
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
- return NodeTheoryPair(explanation, theoryOf(atom)->getId());
+ PROOF({
+ if(proofRecipe) {
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theoryOf(atom)->getId(), emptyNode);
+ proofStep.addAssertion(node);
+ proofRecipe->addBaseAssertion(node);
+
+ if (explanation.getKind() == kind::AND) {
+ // If the explanation is a conjunction, the recipe for the corresponding lemma is
+ // the negation of its conjuncts.
+ Node flat = flattenAnd(explanation);
+ for (unsigned i = 0; i < flat.getNumChildren(); ++i) {
+ if (flat[i].isConst() && flat[i].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ if (flat[i].getKind() == kind::NOT &&
+ flat[i][0].isConst() && !flat[i][0].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ Debug("theory::explain") << "TheoryEngine::getExplanationAndRecipe: adding recipe assertion: "
+ << flat[i].negate() << std::endl;
+ proofStep.addAssertion(flat[i].negate());
+ proofRecipe->addBaseAssertion(flat[i].negate());
+ }
+ } else {
+ // The recipe for proving it is by negating it. "True" is not an acceptable reason.
+ if (!((explanation.isConst() && explanation.getConst<bool>()) ||
+ (explanation.getKind() == kind::NOT &&
+ explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
+ proofStep.addAssertion(explanation.negate());
+ proofRecipe->addBaseAssertion(explanation.negate());
+ }
+ }
+
+ proofRecipe->addStep(proofStep);
+ }
+ });
+
+ return explanation;
}
+ Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
+
// Initial thing to explain
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
Assert(d_propagationMap.find(toExplain) != d_propagationMap.end());
NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain];
+ Debug("theory::explain") << "TheoryEngine::getExplanation: explainer for node "
+ << nodeExplainerPair.node
+ << " is theory: " << nodeExplainerPair.theory << std::endl;
TheoryId explainer = nodeExplainerPair.theory;
// Create the workplace for explanations
std::vector<NodeTheoryPair> explanationVector;
explanationVector.push_back(d_propagationMap[toExplain]);
// Process the explanation
- getExplanation(explanationVector);
+ if (proofRecipe) {
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(explainer, emptyNode);
+ proofStep.addAssertion(node);
+ proofRecipe->addStep(proofStep);
+ proofRecipe->addBaseAssertion(node);
+ }
+
+ getExplanation(explanationVector, proofRecipe);
Node explanation = mkExplanation(explanationVector);
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
- return NodeTheoryPair(explanation, explainer);
+ return explanation;
}
Node TheoryEngine::getExplanation(TNode node) {
- return getExplanationAndExplainer(node).node;
+ LemmaProofRecipe *dontCareRecipe = NULL;
+ return getExplanationAndRecipe(node, dontCareRecipe);
}
struct AtomsCollect {
@@ -1406,7 +1597,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
bool removable,
bool preprocess,
theory::TheoryId atomsTo,
- theory::TheoryId ownerTheory) {
+ LemmaProofRecipe* proofRecipe) {
// For resource-limiting (also does a time check).
// spendResource();
@@ -1456,10 +1647,10 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, ownerTheory, node);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, proofRecipe, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, ownerTheory, node);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, proofRecipe, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
@@ -1493,22 +1684,69 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
<< CheckSatCommand(conflict.toExpr());
}
+ LemmaProofRecipe* proofRecipe = NULL;
+ PROOF({
+ proofRecipe = new LemmaProofRecipe;
+ Node emptyNode;
+ LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
+
+ if (conflict.getKind() == kind::AND) {
+ for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+ proofStep.addAssertion(conflict[i].negate());
+ }
+ } else {
+ proofStep.addAssertion(conflict.negate());
+ }
+
+ proofRecipe->addStep(proofStep);
+ });
+
// In the multiple-theories case, we need to reconstruct the conflict
if (d_logicInfo.isSharingEnabled()) {
// Create the workplace for explanations
std::vector<NodeTheoryPair> explanationVector;
explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
+
// Process the explanation
- getExplanation(explanationVector);
+ getExplanation(explanationVector, proofRecipe);
Node fullConflict = mkExplanation(explanationVector);
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST, theoryId);
+ lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST, proofRecipe);
+
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST, theoryId);
+ PROOF({
+ if (conflict.getKind() == kind::AND) {
+ // If the conflict is a conjunction, the corresponding lemma is derived by negating
+ // its conjuncts.
+ for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+ if (conflict[i].isConst() && conflict[i].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ if (conflict[i].getKind() == kind::NOT &&
+ conflict[i][0].isConst() && !conflict[i][0].getConst<bool>()) {
+ ++ i;
+ continue;
+ }
+ proofRecipe->getStep(0)->addAssertion(conflict[i].negate());
+ proofRecipe->addBaseAssertion(conflict[i].negate());
+ }
+ } else {
+ proofRecipe->getStep(0)->addAssertion(conflict.negate());
+ proofRecipe->addBaseAssertion(conflict.negate());
+ }
+ });
+
+ lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST, proofRecipe);
}
+
+ PROOF({
+ delete proofRecipe;
+ proofRecipe = NULL;
+ });
}
void TheoryEngine::staticInitializeBVOptions(const std::vector<Node>& assertions) {
@@ -1558,15 +1796,9 @@ void TheoryEngine::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
Node TheoryEngine::ppSimpITE(TNode assertion)
{
- if(options::incrementalSolving()){
- // disabling the d_iteUtilities->simpITE(assertion) pass for incremental solving.
- // This is paranoia. We do not actually know of a bug coming from this.
- // TODO re-enable
+ if (!d_iteRemover.containsTermITE(assertion)) {
return assertion;
- } else if(!d_iteRemover.containsTermITE(assertion)){
- return assertion;
- }else{
-
+ } else {
Node result = d_iteUtilities->simpITE(assertion);
Node res_rewritten = Rewriter::rewrite(result);
@@ -1576,10 +1808,9 @@ Node TheoryEngine::ppSimpITE(TNode assertion)
Chat() << "ending simplifyWithCare()"
<< " post simplifyWithCare()" << postSimpWithCare.getId() << endl;
result = Rewriter::rewrite(postSimpWithCare);
- }else{
+ } else {
result = res_rewritten;
}
-
return result;
}
}
@@ -1667,19 +1898,21 @@ bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
return result;
}
-void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector)
-{
+void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) {
Assert(explanationVector.size() > 0);
unsigned i = 0; // Index of the current literal we are processing
unsigned j = 0; // Index of the last literal we are keeping
- while (i < explanationVector.size()) {
+ std::set<Node> inputAssertions;
+ PROOF(inputAssertions = proofRecipe->getStep(0)->getAssertions(););
+ while (i < explanationVector.size()) {
// Get the current literal to explain
NodeTheoryPair toExplain = explanationVector[i];
- Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
+ Debug("theory::explain") << "[i=" << i << "] TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
+
// If a true constant or a negation of a false constant we can ignore it
if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) {
@@ -1693,6 +1926,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// If from the SAT solver, keep it
if (toExplain.theory == THEORY_SAT_SOLVER) {
+ Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl;
explanationVector[j++] = explanationVector[i++];
continue;
}
@@ -1711,10 +1945,26 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// See if it was sent to the theory by another theory
PropagationMap::const_iterator find = d_propagationMap.find(toExplain);
if (find != d_propagationMap.end()) {
+ Debug("theory::explain") << "\tTerm was propagated by another theory (theory = "
+ << theoryOf((*find).second.theory)->getId() << ")" << std::endl;
// There is some propagation, check if its a timely one
if ((*find).second.timestamp < toExplain.timestamp) {
+ Debug("theory::explain") << "\tRelevant timetsamp, pushing "
+ << (*find).second.node << "to index = " << explanationVector.size() << std::endl;
explanationVector.push_back((*find).second);
- ++ i;
+ ++i;
+
+ PROOF({
+ if (toExplain.node != (*find).second.node) {
+ Debug("pf::explain") << "TheoryEngine::getExplanation: Rewrite alert! toAssert = " << toExplain.node
+ << ", toExplain = " << (*find).second.node << std::endl;
+
+ if (proofRecipe) {
+ proofRecipe->addRewriteRule(toExplain.node, (*find).second.node);
+ }
+ }
+ })
+
continue;
}
}
@@ -1723,21 +1973,61 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
Node explanation;
if (toExplain.theory == THEORY_BUILTIN) {
explanation = d_sharedTerms.explain(toExplain.node);
+ Debug("theory::explain") << "\tTerm was propagated by THEORY_BUILTIN. Explanation: " << explanation << std::endl;
} else {
explanation = theoryOf(toExplain.theory)->explain(toExplain.node);
+ Debug("theory::explain") << "\tTerm was propagated by owner theory: "
+ << theoryOf(toExplain.theory)->getId()
+ << ". Explanation: " << explanation << std::endl;
}
+
Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << endl;
Assert(explanation != toExplain.node, "wasn't sent to you, so why are you explaining it trivially");
// Mark the explanation
NodeTheoryPair newExplain(explanation, toExplain.theory, toExplain.timestamp);
explanationVector.push_back(newExplain);
+
++ i;
+
+ PROOF({
+ if (proofRecipe) {
+ // If we're expanding the target node of the explanation (this is the first expansion...),
+ // we don't want to add it as a separate proof step. It is already part of the assertions.
+ if (inputAssertions.find(toExplain.node) == inputAssertions.end()) {
+ LemmaProofRecipe::ProofStep proofStep(toExplain.theory, toExplain.node);
+ if (explanation.getKind() == kind::AND) {
+ Node flat = flattenAnd(explanation);
+ for (unsigned k = 0; k < flat.getNumChildren(); ++ k) {
+ // If a true constant or a negation of a false constant we can ignore it
+ if (! ((flat[k].isConst() && flat[k].getConst<bool>()) ||
+ (flat[k].getKind() == kind::NOT && flat[k][0].isConst() && !flat[k][0].getConst<bool>()))) {
+ proofStep.addAssertion(flat[k].negate());
+ }
+ }
+ } else {
+ if (! ((explanation.isConst() && explanation.getConst<bool>()) ||
+ (explanation.getKind() == kind::NOT && explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
+ proofStep.addAssertion(explanation.negate());
+ }
+ }
+ proofRecipe->addStep(proofStep);
+ }
+ }
+ });
}
// Keep only the relevant literals
explanationVector.resize(j);
-}
+ PROOF({
+ if (proofRecipe) {
+ // The remaining literals are the base of the proof
+ for (unsigned k = 0; k < explanationVector.size(); ++k) {
+ proofRecipe->addBaseAssertion(explanationVector[k].node.negate());
+ }
+ }
+ });
+}
void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
{
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index db94edd7c..53c4aac77 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -50,6 +50,7 @@
namespace CVC4 {
class ResourceManager;
+class LemmaProofRecipe;
/**
* A pair of a theory and a node. This is used to mark the flow of
@@ -270,46 +271,18 @@ class TheoryEngine {
}
}
- void conflict(TNode conflictNode, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException) {
- Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
- Assert(pf == NULL); // theory shouldn't be producing proofs yet
- ++ d_statistics.conflicts;
- d_engine->d_outputChannelUsed = true;
- d_engine->conflict(conflictNode, d_theory);
- }
+ void conflict(TNode conflictNode, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException);
- bool propagate(TNode literal) throw(AssertionException, UnsafeInterruptException) {
- Trace("theory::propagate") << "EngineOutputChannel<" << d_theory << ">::propagate(" << literal << ")" << std::endl;
- ++ d_statistics.propagations;
- d_engine->d_outputChannelUsed = true;
- return d_engine->propagate(literal, d_theory);
- }
+ bool propagate(TNode literal) throw(AssertionException, UnsafeInterruptException);
theory::LemmaStatus lemma(TNode lemma,
ProofRule rule,
bool removable = false,
bool preprocess = false,
bool sendAtoms = false)
- throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, rule, false, removable, preprocess, sendAtoms ? d_theory : theory::THEORY_LAST, d_theory);
- }
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException);
- /*theory::LemmaStatus preservedLemma(TNode lemma, bool removable = false, bool preprocess = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException, LogicException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::preservedLemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable, preprocess, d_theory);
- }*/
-
- theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
- Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::splitLemma(" << lemma << ")" << std::endl;
- ++ d_statistics.lemmas;
- d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory, d_theory);
- }
+ theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException);
void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
NodeManager* curr = NodeManager::currentNM();
@@ -456,7 +429,7 @@ class TheoryEngine {
bool removable,
bool preprocess,
theory::TheoryId atomsTo,
- theory::TheoryId ownerTheory);
+ LemmaProofRecipe* proofRecipe);
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
@@ -606,9 +579,10 @@ private:
* asking relevant theories to explain the propagations. Initially
* the explanation vector should contain only the element (node, theory)
* where the node is the one to be explained, and the theory is the
- * theory that sent the literal.
+ * theory that sent the literal. The lemmaProofRecipe will contain a list
+ * of the explanation steps required to produce the original node.
*/
- void getExplanation(std::vector<NodeTheoryPair>& explanationVector);
+ void getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* lemmaProofRecipe);
public:
@@ -730,7 +704,7 @@ public:
* Returns an explanation of the node propagated to the SAT solver and the theory
* that propagated it.
*/
- NodeTheoryPair getExplanationAndExplainer(TNode node);
+ Node getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe);
/**
* collect model info
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index fa7e497e2..f43a2aa7f 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -561,7 +561,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
TheoryModel* tm = (TheoryModel*)m;
// buildModel with fullModel = true should only be called once in any context
- Assert(!tm->d_modelBuilt);
+ Assert(!tm->isBuilt());
tm->d_modelBuilt = fullModel;
// Reset model
@@ -832,6 +832,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
Assert(!t.isBoolean() || (*i2).getKind() == kind::APPLY_UF);
Node n;
if (t.getCardinality().isInfinite()) {
+ // if (!t.isInterpretedFinite()) {
bool success;
do{
Trace("model-builder-debug") << "Enumerate term of type " << t << std::endl;
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index 6e4f77336..833b124eb 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -36,6 +36,7 @@ class TheoryModel : public Model
protected:
/** substitution map for this model */
SubstitutionMap d_substitutions;
+ context::CDO<bool> d_modelBuilt;
public:
TheoryModel(context::Context* c, std::string name, bool enableFuncModels);
virtual ~TheoryModel() throw();
@@ -51,7 +52,6 @@ public:
/** true/false nodes */
Node d_true;
Node d_false;
- context::CDO<bool> d_modelBuilt;
mutable std::hash_map<Node, Node, NodeHashFunction> d_modelCache;
protected:
@@ -62,6 +62,8 @@ protected:
*/
Node getModelValue(TNode n, bool hasBoundVars = false, bool useDontCares = false) const;
public:
+ /** is built */
+ bool isBuilt() { return d_modelBuilt.get(); }
/**
* Get value function. This should be called only after a ModelBuilder has called buildModel(...)
* on this model.
diff --git a/src/theory/type_enumerator.h b/src/theory/type_enumerator.h
index d1318aaa8..bcd7e695f 100644
--- a/src/theory/type_enumerator.h
+++ b/src/theory/type_enumerator.h
@@ -115,7 +115,7 @@ public:
// On Mac clang, there appears to be a code generation bug in an exception
// block here. For now, there doesn't appear a good workaround; just disable
// assertions on that setup.
-#if defined(CVC4_ASSERTIONS) && !(defined(__APPLE__) && defined(__clang__))
+#if defined(CVC4_ASSERTIONS) && !(defined(__clang__))
if(d_te->isFinished()) {
try {
**d_te;
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 9b429765e..25b12f75f 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -964,12 +964,9 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
std::vector<EqProof *> orderedChildren;
bool nullCongruenceFound = false;
for (unsigned i = 0; i < eqpc->d_children.size(); ++i) {
- if (eqpc->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE && eqpc->d_children[i]->d_node.isNull()) {
-
- // For now, assume there can only be one null congruence child
- Assert(!nullCongruenceFound);
+ if (eqpc->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE &&
+ eqpc->d_children[i]->d_node.isNull()) {
nullCongruenceFound = true;
-
Debug("pf::ee") << "Have congruence with empty d_node. Splitting..." << std::endl;
orderedChildren.insert(orderedChildren.begin(), eqpc->d_children[i]->d_children[0]);
orderedChildren.push_back(eqpc->d_children[i]->d_children[1]);
@@ -1192,6 +1189,9 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
getExplanation(childId, getEqualityNode(childId).getFind(), equalities, eqpcc);
if( eqpc ) {
eqpc->d_children.push_back( eqpcc );
+
+ Debug("pf::ee") << "MERGED_THROUGH_CONSTANTS. Dumping the child proof" << std::endl;
+ eqpc->debug_print("pf::ee", 1);
}
}
@@ -1605,6 +1605,7 @@ void EqualityEngine::propagate() {
}
void EqualityEngine::debugPrintGraph() const {
+ Debug("equality::graph") << std::endl << "Dumping graph" << std::endl;
for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++ nodeId) {
Debug("equality::graph") << d_nodes[nodeId] << " " << nodeId << "(" << getEqualityNode(nodeId).getFind() << "):";
@@ -1618,6 +1619,7 @@ void EqualityEngine::debugPrintGraph() const {
Debug("equality::graph") << std::endl;
}
+ Debug("equality::graph") << std::endl;
}
bool EqualityEngine::areEqual(TNode t1, TNode t2) const {
@@ -2209,9 +2211,15 @@ bool EqClassIterator::isFinished() const {
return d_current == null_id;
}
-void EqProof::debug_print( const char * c, unsigned tb ) const{
- for( unsigned i=0; i<tb; i++ ) { Debug( c ) << " "; }
- Debug( c ) << d_id << "(";
+void EqProof::debug_print(const char* c, unsigned tb, PrettyPrinter* prettyPrinter) const {
+ for(unsigned i=0; i<tb; i++) { Debug( c ) << " "; }
+
+ if (prettyPrinter)
+ Debug( c ) << prettyPrinter->printTag(d_id);
+ else
+ Debug( c ) << d_id;
+
+ Debug( c ) << "(";
if( !d_children.empty() || !d_node.isNull() ){
if( !d_node.isNull() ){
Debug( c ) << std::endl;
@@ -2221,7 +2229,7 @@ void EqProof::debug_print( const char * c, unsigned tb ) const{
for( unsigned i=0; i<d_children.size(); i++ ){
if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
Debug( c ) << std::endl;
- d_children[i]->debug_print( c, tb+1 );
+ d_children[i]->debug_print( c, tb+1, prettyPrinter );
}
}
Debug( c ) << ")" << std::endl;
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index f30f1e8a0..843e7ce7f 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -902,11 +902,17 @@ public:
class EqProof
{
public:
+ class PrettyPrinter {
+ public:
+ virtual ~PrettyPrinter() {}
+ virtual std::string printTag(unsigned tag) = 0;
+ };
+
EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY){}
unsigned d_id;
Node d_node;
std::vector< EqProof * > d_children;
- void debug_print( const char * c, unsigned tb = 0 ) const;
+ void debug_print(const char * c, unsigned tb = 0, PrettyPrinter* prettyPrinter = NULL) const;
};/* class EqProof */
} // Namespace eq
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 0c7bed773..ae935798e 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -26,6 +26,8 @@
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/quantifiers/term_database.h"
+#include "options/theory_options.h"
using namespace std;
@@ -431,100 +433,107 @@ void TheoryUF::addSharedTerm(TNode t) {
d_equalityEngine.addTriggerTerm(t, THEORY_UF);
}
-void TheoryUF::computeCareGraph() {
-
- if (d_sharedTerms.size() > 0) {
-
- vector< pair<TNode, TNode> > currentPairs;
-
- // Go through the function terms and see if there are any to split on
- unsigned functionTerms = d_functionsTerms.size();
- for (unsigned i = 0; i < functionTerms; ++ i) {
-
- TNode f1 = d_functionsTerms[i];
- Node op = f1.getOperator();
-
- for (unsigned j = i + 1; j < functionTerms; ++ j) {
-
- TNode f2 = d_functionsTerms[j];
-
- // If the operators are not the same, we can skip this pair
- if (f2.getOperator() != op) {
- continue;
- }
-
+//TODO: move quantifiers::TermArgTrie to src/theory/
+void TheoryUF::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth ){
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !d_equalityEngine.areEqual( f1, f2 ) ){
Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
-
- // If the terms are already known to be equal, we are also in good shape
- if (d_equalityEngine.areEqual(f1, f2)) {
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): equal, skipping" << std::endl;
- continue;
- }
-
- // We have two functions f(x1, ..., xn) and f(y1, ..., yn) no known to be equal
- // We split on the argument pairs that are are not known, unless there is some
- // argument pair that is already dis-equal.
- bool somePairIsDisequal = false;
- currentPairs.clear();
+ vector< pair<TNode, TNode> > currentPairs;
for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
-
TNode x = f1[k];
TNode y = f2[k];
-
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking arguments " << x << " and " << y << std::endl;
-
- if (d_equalityEngine.areDisequal(x, y, false)) {
- // Mark that there is a dis-equal pair and break
- somePairIsDisequal = true;
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): disequal, disregarding all" << std::endl;
- break;
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !d_equalityEngine.areDisequal( x, y, false ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_UF) && d_equalityEngine.isTriggerTerm(y, THEORY_UF) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
+ EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
+ }
+ }
}
-
- if (d_equalityEngine.areEqual(x, y)) {
- // We don't need this one
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): equal" << std::endl;
- continue;
- }
-
- if (!d_equalityEngine.isTriggerTerm(x, THEORY_UF) || !d_equalityEngine.isTriggerTerm(y, THEORY_UF)) {
- // Not connected to shared terms, we don't care
- continue;
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
+ addCarePair(currentPairs[c].first, currentPairs[c].second);
+ }
+ }
+ }
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1 );
+ }
+ }
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
-
- // Get representative trigger terms
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
-
- EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
- switch (eqStatusDomain) {
- case EQUALITY_FALSE_AND_PROPAGATED:
- case EQUALITY_FALSE:
- case EQUALITY_FALSE_IN_MODEL:
- somePairIsDisequal = true;
- continue;
- break;
- default:
- break;
- // nothing
+ }
+ }
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
-
- // Otherwise, we need to figure it out
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
- currentPairs.push_back(make_pair(x_shared, y_shared));
}
+ }
+ }
+ }
+}
- if (!somePairIsDisequal) {
- for (unsigned i = 0; i < currentPairs.size(); ++ i) {
- addCarePair(currentPairs[i].first, currentPairs[i].second);
- }
+void TheoryUF::computeCareGraph() {
+
+ if (d_sharedTerms.size() > 0) {
+ //use term indexing
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..." << std::endl;
+ std::map< Node, quantifiers::TermArgTrie > index;
+ std::map< Node, unsigned > arity;
+ unsigned functionTerms = d_functionsTerms.size();
+ for (unsigned i = 0; i < functionTerms; ++ i) {
+ TNode f1 = d_functionsTerms[i];
+ Node op = f1.getOperator();
+ std::vector< TNode > reps;
+ bool has_trigger_arg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_UF ) ){
+ has_trigger_arg = true;
}
}
+ if( has_trigger_arg ){
+ index[op].addTerm( f1, reps );
+ arity[op] = reps.size();
+ }
+ }
+ //for each index
+ for( std::map< Node, quantifiers::TermArgTrie >::iterator itii = index.begin(); itii != index.end(); ++itii ){
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index " << itii->first << "..." << std::endl;
+ addCarePairs( &itii->second, NULL, arity[ itii->first ], 0 );
}
}
}/* TheoryUF::computeCareGraph() */
void TheoryUF::conflict(TNode a, TNode b) {
eq::EqProof* pf = d_proofsEnabled ? new eq::EqProof() : NULL;
+
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b),pf);
} else {
@@ -542,9 +551,9 @@ void TheoryUF::eqNotifyNewClass(TNode t) {
}
void TheoryUF::eqNotifyPreMerge(TNode t1, TNode t2) {
- if (getLogicInfo().isQuantified()) {
+ //if (getLogicInfo().isQuantified()) {
//getQuantifiersEngine()->getEfficientEMatcher()->merge( t1, t2 );
- }
+ //}
}
void TheoryUF::eqNotifyPostMerge(TNode t1, TNode t2) {
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index 42a804c09..3a83decec 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -32,6 +32,11 @@
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace uf {
class UfTermDb;
@@ -204,6 +209,8 @@ public:
StrongSolverTheoryUF* getStrongSolver() {
return d_thss;
}
+private:
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth );
};/* class TheoryUF */
}/* CVC4::theory::uf namespace */
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index ed28cc2fc..cda94e1c4 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -1670,6 +1670,12 @@ StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c,
}
}
+StrongSolverTheoryUF::~StrongSolverTheoryUF() {
+ for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ delete it->second;
+ }
+}
+
SortInference* StrongSolverTheoryUF::getSortInference() {
return d_th->getQuantifiersEngine()->getTheoryEngine()->getSortInference();
}
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 11f0664f3..4e4dbef83 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -414,7 +414,7 @@ private:
SubsortSymmetryBreaker* d_sym_break;
public:
StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
- ~StrongSolverTheoryUF() {}
+ ~StrongSolverTheoryUF();
/** get theory */
TheoryUF* getTheory() { return d_th; }
/** disequality propagator */
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index 165937c13..7e13668cd 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -87,6 +87,10 @@ Node Valuation::getModelValue(TNode var) {
return d_engine->getModelValue(var);
}
+TheoryModel* Valuation::getModel() {
+ return d_engine->getModel();
+}
+
Node Valuation::ensureLiteral(TNode n) {
return d_engine->ensureLiteral(n);
}
diff --git a/src/theory/valuation.h b/src/theory/valuation.h
index 4ecdecad0..54af14fdd 100644
--- a/src/theory/valuation.h
+++ b/src/theory/valuation.h
@@ -32,6 +32,7 @@ namespace theory {
class EntailmentCheckParameters;
class EntailmentCheckSideEffects;
+class TheoryModel;
/**
* The status of an equality in the current context.
@@ -106,6 +107,11 @@ public:
Node getModelValue(TNode var);
/**
+ * Returns pointer to model.
+ */
+ TheoryModel* getModel();
+
+ /**
* Ensure that the given node will have a designated SAT literal
* that is definitionally equal to it. The result of this function
* is a Node that can be queried via getSatValue().
diff --git a/src/util/bitvector.h b/src/util/bitvector.h
index a04cbb58f..4a74c1c53 100644
--- a/src/util/bitvector.h
+++ b/src/util/bitvector.h
@@ -338,6 +338,15 @@ public:
return d_value;
}
+ Integer toSignedInt() const {
+ // returns Integer corresponding to two's complement interpretation of bv
+ unsigned size = d_size;
+ Integer sign_bit = d_value.extractBitRange(1,size-1);
+ Integer val = d_value.extractBitRange(size-1, 0);
+ Integer res = Integer(-1) * sign_bit.multiplyByPow2(size - 1) + val;
+ return res;
+ }
+
/**
Returns k is the integer is equal to 2^{k-1} and zero
otherwise
@@ -356,14 +365,6 @@ private:
unsigned d_size;
Integer d_value;
- Integer toSignedInt() const {
- // returns Integer corresponding to two's complement interpretation of bv
- unsigned size = d_size;
- Integer sign_bit = d_value.extractBitRange(1,size-1);
- Integer val = d_value.extractBitRange(size-1, 0);
- Integer res = Integer(-1) * sign_bit.multiplyByPow2(size - 1) + val;
- return res;
- }
};/* class BitVector */
diff --git a/src/util/proof.h b/src/util/proof.h
index fc5f7f901..b4a8a3d29 100644
--- a/src/util/proof.h
+++ b/src/util/proof.h
@@ -21,13 +21,21 @@
#define __CVC4__PROOF_H
#include <iosfwd>
+#include <ext/hash_map>
namespace CVC4 {
+class Expr;
+class ProofLetCount;
+struct ExprHashFunction;
+
+typedef __gnu_cxx::hash_map<Expr, ProofLetCount, ExprHashFunction> ProofLetMap;
+
class CVC4_PUBLIC Proof {
public:
virtual ~Proof() { }
virtual void toStream(std::ostream& out) = 0;
+ virtual void toStream(std::ostream& out, const ProofLetMap& map) = 0;
};/* class Proof */
}/* CVC4 namespace */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback