summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLiana Hadarean <lianahady@gmail.com>2013-09-30 13:56:51 -0400
committerLiana Hadarean <lianahady@gmail.com>2013-09-30 13:56:51 -0400
commit7d2265eb2b5dc96ddff04211959e208b1cb8a7f0 (patch)
tree26fb270349580c90efe163ca7767bccce6607902 /src
parentdb6df44574927f9b75db664e1e490f757725d13a (diff)
parent0c2eafec69b694a507ac914bf285fe0574be085f (diff)
merged golden
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am46
-rw-r--r--src/bindings/Makefile.am6
-rw-r--r--src/bindings/compat/java/include/cvc3/JniUtils.h2
-rw-r--r--src/compat/cvc3_compat.cpp27
-rw-r--r--src/cvc4.i5
-rw-r--r--src/decision/Makefile.am4
-rw-r--r--src/decision/decision_engine.cpp38
-rw-r--r--src/decision/decision_engine.h7
-rw-r--r--src/decision/justification_heuristic.cpp11
-rw-r--r--src/decision/options10
-rw-r--r--src/decision/options_handlers.h50
-rw-r--r--src/decision/relevancy.cpp379
-rw-r--r--src/decision/relevancy.h421
-rw-r--r--src/expr/attribute.h18
-rw-r--r--src/expr/attribute_internals.h28
-rw-r--r--src/expr/command.cpp217
-rw-r--r--src/expr/command.h60
-rw-r--r--src/expr/expr.i4
-rw-r--r--src/expr/expr_manager.i4
-rw-r--r--src/expr/expr_manager_template.cpp41
-rw-r--r--src/expr/expr_manager_template.h86
-rw-r--r--src/expr/expr_template.cpp13
-rw-r--r--src/expr/expr_template.h6
-rw-r--r--src/expr/metakind_template.h45
-rwxr-xr-xsrc/expr/mkmetakind9
-rw-r--r--src/expr/node.h12
-rw-r--r--src/expr/node_builder.h41
-rw-r--r--src/expr/node_manager.h174
-rw-r--r--src/expr/node_value.h10
-rw-r--r--src/expr/type.cpp4
-rw-r--r--src/expr/type.h3
-rw-r--r--src/expr/type.i4
-rw-r--r--src/expr/type_node.cpp11
-rw-r--r--src/expr/type_node.h13
-rw-r--r--src/include/cvc4_private_library.h2
-rw-r--r--src/include/cvc4_public.h3
-rw-r--r--src/lib/clock_gettime.h6
-rw-r--r--src/main/command_executor.cpp32
-rw-r--r--src/main/command_executor.h3
-rw-r--r--src/main/command_executor_portfolio.cpp17
-rw-r--r--src/main/driver_unified.cpp10
-rw-r--r--src/main/interactive_shell.cpp7
-rw-r--r--src/main/main.cpp8
-rw-r--r--src/main/main.h2
-rw-r--r--src/main/options4
-rw-r--r--src/main/portfolio.cpp2
-rw-r--r--src/main/portfolio_util.h1
-rw-r--r--src/main/util.cpp11
-rw-r--r--src/options/Makefile.am12
-rw-r--r--src/options/base_options5
-rwxr-xr-xsrc/options/mkoptions88
-rw-r--r--src/options/options.h22
-rw-r--r--src/options/options_template.cpp105
-rw-r--r--src/parser/antlr_input.cpp11
-rw-r--r--src/parser/antlr_input.h12
-rw-r--r--src/parser/antlr_line_buffered_input.cpp9
-rw-r--r--src/parser/bounded_token_buffer.cpp2
-rw-r--r--src/parser/cvc/Cvc.g60
-rw-r--r--src/parser/cvc/Makefile.am2
-rw-r--r--src/parser/options4
-rw-r--r--src/parser/parser.cpp63
-rw-r--r--src/parser/parser.h82
-rw-r--r--src/parser/parser_builder.cpp15
-rw-r--r--src/parser/parser_builder.h10
-rw-r--r--src/parser/smt1/smt1.cpp7
-rw-r--r--src/parser/smt1/smt1.h4
-rw-r--r--src/parser/smt2/Smt2.g283
-rw-r--r--src/parser/smt2/smt2.cpp229
-rw-r--r--src/parser/smt2/smt2.h32
-rw-r--r--src/parser/tptp/Tptp.g643
-rw-r--r--src/parser/tptp/tptp.cpp103
-rw-r--r--src/parser/tptp/tptp.h93
-rw-r--r--src/parser/tptp/tptp_input.cpp4
-rw-r--r--src/parser/tptp/tptp_input.h2
-rw-r--r--src/printer/Makefile.am4
-rw-r--r--src/printer/ast/ast_printer.cpp4
-rw-r--r--src/printer/ast/ast_printer.h4
-rw-r--r--src/printer/cvc/cvc_printer.cpp4
-rw-r--r--src/printer/cvc/cvc_printer.h2
-rw-r--r--src/printer/printer.cpp7
-rw-r--r--src/printer/printer.h9
-rw-r--r--src/printer/smt1/smt1_printer.cpp4
-rw-r--r--src/printer/smt1/smt1_printer.h4
-rw-r--r--src/printer/smt2/smt2_printer.cpp101
-rw-r--r--src/printer/smt2/smt2_printer.h4
-rw-r--r--src/printer/tptp/tptp_printer.cpp83
-rw-r--r--src/printer/tptp/tptp_printer.h46
-rw-r--r--src/proof/cnf_proof.cpp2
-rw-r--r--src/proof/cnf_proof.h2
-rw-r--r--src/proof/sat_proof.cpp57
-rw-r--r--src/proof/sat_proof.h31
-rw-r--r--src/prop/cnf_stream.cpp6
-rw-r--r--src/prop/minisat/core/Solver.cc33
-rw-r--r--src/prop/minisat/core/Solver.h4
-rw-r--r--src/prop/minisat/minisat.h5
-rw-r--r--src/prop/minisat/mtl/Vec.h2
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc8
-rw-r--r--src/prop/options4
-rw-r--r--src/prop/prop_engine.cpp4
-rw-r--r--src/smt/boolean_terms.cpp46
-rw-r--r--src/smt/options6
-rw-r--r--src/smt/options_handlers.h16
-rw-r--r--src/smt/smt_engine.cpp735
-rw-r--r--src/smt/smt_engine.h34
-rw-r--r--src/smt/smt_options_template.cpp65
-rw-r--r--src/theory/Makefile.am10
-rw-r--r--src/theory/arith/Makefile.am4
-rw-r--r--src/theory/arith/approx_simplex.cpp336
-rw-r--r--src/theory/arith/approx_simplex.h11
-rw-r--r--src/theory/arith/arith_rewriter.cpp95
-rw-r--r--src/theory/arith/arith_static_learner.h1
-rw-r--r--src/theory/arith/attempt_solution_simplex.cpp135
-rw-r--r--src/theory/arith/attempt_solution_simplex.h (renamed from src/theory/arith/pure_update_simplex.h)53
-rw-r--r--src/theory/arith/bound_counts.h242
-rw-r--r--src/theory/arith/callbacks.cpp4
-rw-r--r--src/theory/arith/callbacks.h16
-rw-r--r--src/theory/arith/constraint.cpp22
-rw-r--r--src/theory/arith/constraint.h2
-rw-r--r--src/theory/arith/dual_simplex.cpp37
-rw-r--r--src/theory/arith/error_set.cpp12
-rw-r--r--src/theory/arith/error_set.h16
-rw-r--r--src/theory/arith/fc_simplex.cpp17
-rw-r--r--src/theory/arith/kinds26
-rw-r--r--src/theory/arith/linear_equality.cpp572
-rw-r--r--src/theory/arith/linear_equality.h205
-rw-r--r--src/theory/arith/matrix.cpp2
-rw-r--r--src/theory/arith/matrix.h6
-rw-r--r--src/theory/arith/normal_form.cpp35
-rw-r--r--src/theory/arith/normal_form.h14
-rw-r--r--src/theory/arith/options24
-rw-r--r--src/theory/arith/partial_model.cpp217
-rw-r--r--src/theory/arith/partial_model.h115
-rw-r--r--src/theory/arith/pure_update_simplex.cpp261
-rw-r--r--src/theory/arith/simplex-converge.cpp1674
-rw-r--r--src/theory/arith/simplex-converge.h531
-rw-r--r--src/theory/arith/simplex.cpp17
-rw-r--r--src/theory/arith/simplex.h4
-rw-r--r--src/theory/arith/simplex_update.h2
-rw-r--r--src/theory/arith/soi_simplex.cpp252
-rw-r--r--src/theory/arith/soi_simplex.h13
-rw-r--r--src/theory/arith/tableau.cpp2
-rw-r--r--src/theory/arith/tableau.h6
-rw-r--r--src/theory/arith/theory_arith.cpp5
-rw-r--r--src/theory/arith/theory_arith.h3
-rw-r--r--src/theory/arith/theory_arith_private.cpp724
-rw-r--r--src/theory/arith/theory_arith_private.h41
-rw-r--r--src/theory/arith/theory_arith_type_rules.h59
-rw-r--r--src/theory/arrays/Makefile.am4
-rw-r--r--src/theory/arrays/theory_arrays.cpp79
-rw-r--r--src/theory/arrays/theory_arrays_model.cpp65
-rw-r--r--src/theory/arrays/theory_arrays_model.h58
-rw-r--r--src/theory/arrays/theory_arrays_rewriter.h14
-rw-r--r--src/theory/atom_requests.cpp62
-rw-r--r--src/theory/atom_requests.h107
-rw-r--r--src/theory/booleans/theory_bool.cpp1
-rw-r--r--src/theory/builtin/kinds25
-rw-r--r--src/theory/builtin/theory_builtin_rewriter.cpp3
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.h16
-rw-r--r--src/theory/bv/bitblaster.cpp196
-rw-r--r--src/theory/bv/bitblaster.h93
-rw-r--r--src/theory/bv/bv_subtheory.h29
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp17
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h10
-rw-r--r--src/theory/bv/bv_subtheory_core.cpp203
-rw-r--r--src/theory/bv/bv_subtheory_core.h28
-rw-r--r--src/theory/bv/bv_subtheory_inequality.cpp87
-rw-r--r--src/theory/bv/bv_subtheory_inequality.h30
-rw-r--r--src/theory/bv/kinds11
-rw-r--r--src/theory/bv/options6
-rw-r--r--src/theory/bv/theory_bv.cpp72
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules.h20
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h10
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h51
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_simplification.h17
-rw-r--r--src/theory/bv/theory_bv_rewriter.cpp196
-rw-r--r--src/theory/bv/theory_bv_rewriter.h3
-rw-r--r--src/theory/bv/theory_bv_type_rules.h28
-rw-r--r--src/theory/bv/theory_bv_utils.h2
-rw-r--r--src/theory/datatypes/datatypes_rewriter.h11
-rw-r--r--src/theory/datatypes/kinds4
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp156
-rw-r--r--src/theory/idl/Makefile4
-rw-r--r--src/theory/idl/Makefile.am19
-rw-r--r--src/theory/idl/idl_assertion.cpp213
-rw-r--r--src/theory/idl/idl_assertion.h91
-rw-r--r--src/theory/idl/idl_assertion_db.cpp59
-rw-r--r--src/theory/idl/idl_assertion_db.h86
-rw-r--r--src/theory/idl/idl_model.cpp64
-rw-r--r--src/theory/idl/idl_model.h84
-rw-r--r--src/theory/idl/kinds8
-rw-r--r--src/theory/idl/options12
-rw-r--r--src/theory/idl/theory_idl.cpp143
-rw-r--r--src/theory/idl/theory_idl.h63
-rw-r--r--src/theory/ite_simplifier.cpp4
-rw-r--r--src/theory/ite_simplifier.h6
-rw-r--r--src/theory/logic_info.cpp28
-rw-r--r--src/theory/logic_info.h4
-rw-r--r--src/theory/model.cpp29
-rw-r--r--src/theory/options4
-rw-r--r--src/theory/output_channel.h7
-rw-r--r--src/theory/quantifiers/Makefile.am17
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp372
-rw-r--r--src/theory/quantifiers/bounded_integers.h127
-rw-r--r--src/theory/quantifiers/candidate_generator.cpp30
-rw-r--r--src/theory/quantifiers/candidate_generator.h42
-rw-r--r--src/theory/quantifiers/first_order_model.cpp254
-rw-r--r--src/theory/quantifiers/first_order_model.h106
-rw-r--r--src/theory/quantifiers/first_order_reasoning.cpp171
-rw-r--r--src/theory/quantifiers/first_order_reasoning.h45
-rw-r--r--src/theory/quantifiers/full_model_check.cpp1409
-rw-r--r--src/theory/quantifiers/full_model_check.h160
-rw-r--r--src/theory/quantifiers/inst_gen.cpp10
-rw-r--r--src/theory/quantifiers/inst_match.cpp21
-rw-r--r--src/theory/quantifiers/inst_match.h3
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp224
-rw-r--r--src/theory/quantifiers/inst_match_generator.h9
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.cpp285
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.h14
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.cpp4
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp17
-rw-r--r--src/theory/quantifiers/model_builder.cpp368
-rw-r--r--src/theory/quantifiers/model_builder.h90
-rw-r--r--src/theory/quantifiers/model_engine.cpp232
-rw-r--r--src/theory/quantifiers/model_engine.h34
-rw-r--r--src/theory/quantifiers/options31
-rw-r--r--src/theory/quantifiers/quant_util.cpp102
-rw-r--r--src/theory/quantifiers/quant_util.h12
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp4
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.h4
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.cpp268
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.h32
-rwxr-xr-xsrc/theory/quantifiers/rewrite_engine.cpp184
-rwxr-xr-xsrc/theory/quantifiers/rewrite_engine.h54
-rwxr-xr-xsrc/theory/quantifiers/symmetry_breaking.cpp314
-rwxr-xr-xsrc/theory/quantifiers/symmetry_breaking.h118
-rw-r--r--src/theory/quantifiers/term_database.cpp122
-rw-r--r--src/theory/quantifiers/term_database.h28
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp8
-rw-r--r--src/theory/quantifiers/trigger.cpp145
-rw-r--r--src/theory/quantifiers/trigger.h3
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers_engine.cpp89
-rw-r--r--src/theory/quantifiers_engine.h24
-rw-r--r--src/theory/rep_set.cpp198
-rw-r--r--src/theory/rep_set.h32
-rw-r--r--src/theory/rewriterules/rr_inst_match.cpp23
-rw-r--r--src/theory/rewriterules/rr_inst_match.h2
-rw-r--r--src/theory/rewriterules/rr_trigger.cpp20
-rw-r--r--src/theory/rewriterules/rr_trigger.h3
-rw-r--r--src/theory/rewriterules/theory_rewriterules.h2
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.cpp15
-rw-r--r--src/theory/rewriterules/theory_rewriterules_type_rules.h2
-rw-r--r--src/theory/shared_terms_database.cpp4
-rw-r--r--src/theory/strings/Makefile4
-rw-r--r--src/theory/strings/Makefile.am19
-rw-r--r--src/theory/strings/kinds105
-rw-r--r--src/theory/strings/options11
-rw-r--r--src/theory/strings/theory_strings.cpp1711
-rw-r--r--src/theory/strings/theory_strings.h244
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp135
-rw-r--r--src/theory/strings/theory_strings_preprocess.h44
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp156
-rw-r--r--src/theory/strings/theory_strings_rewriter.h49
-rw-r--r--src/theory/strings/theory_strings_type_rules.h223
-rw-r--r--src/theory/strings/type_enumerator.h130
-rw-r--r--src/theory/substitutions.cpp75
-rw-r--r--src/theory/substitutions.h20
-rw-r--r--src/theory/term_registration_visitor.cpp9
-rw-r--r--src/theory/term_registration_visitor.h15
-rw-r--r--src/theory/theory.cpp28
-rw-r--r--src/theory/theory.h37
-rw-r--r--src/theory/theory_engine.cpp349
-rw-r--r--src/theory/theory_engine.h40
-rw-r--r--src/theory/theory_test_utils.h5
-rw-r--r--src/theory/theoryof_mode.h16
-rw-r--r--src/theory/type_enumerator.h21
-rw-r--r--src/theory/uf/equality_engine.cpp2
-rw-r--r--src/theory/uf/equality_engine.h14
-rw-r--r--src/theory/uf/options12
-rw-r--r--src/theory/uf/symmetry_breaker.cpp37
-rw-r--r--src/theory/uf/symmetry_breaker.h28
-rw-r--r--src/theory/uf/theory_uf.cpp3
-rw-r--r--src/theory/uf/theory_uf_model.cpp96
-rw-r--r--src/theory/uf/theory_uf_model.h16
-rw-r--r--src/theory/uf/theory_uf_rewriter.h1
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp265
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h45
-rw-r--r--src/util/Makefile.am13
-rw-r--r--src/util/bitvector.h14
-rw-r--r--src/util/boolean_simplification.h2
-rw-r--r--src/util/chain.h50
-rw-r--r--src/util/chain.i12
-rw-r--r--src/util/cvc4_assert.cpp2
-rw-r--r--src/util/cvc4_assert.h14
-rw-r--r--src/util/datatype.h1
-rw-r--r--src/util/debug.h4
-rw-r--r--src/util/divisible.cpp29
-rw-r--r--src/util/divisible.h62
-rw-r--r--src/util/divisible.i10
-rw-r--r--src/util/dump.h1
-rw-r--r--src/util/exception.h8
-rw-r--r--src/util/ite_removal.cpp6
-rw-r--r--src/util/output.h2
-rw-r--r--src/util/output.i70
-rw-r--r--src/util/rational_cln_imp.h4
-rw-r--r--src/util/record.h1
-rw-r--r--src/util/recursion_breaker.h2
-rw-r--r--src/util/regexp.h353
-rw-r--r--src/util/result.cpp21
-rw-r--r--src/util/result.h33
-rw-r--r--src/util/result.i3
-rw-r--r--src/util/sort_inference.cpp308
-rw-r--r--src/util/sort_inference.h46
-rw-r--r--src/util/statistics_registry.h2
-rw-r--r--src/util/util_model.cpp2
-rw-r--r--src/util/util_model.h12
316 files changed, 16512 insertions, 8055 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 64d95deed..e6d5f80ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,7 +110,7 @@ svn_versioninfo.cpp: svninfo
# This .tmp business is to keep from having to re-compile options.cpp
# (and then re-link the libraries) if nothing has changed.
svninfo: svninfo.tmp
- $(AM_V_GEN)diff -q svninfo.tmp svninfo &>/dev/null || mv svninfo.tmp svninfo || true
+ $(AM_V_GEN)if diff -q svninfo.tmp svninfo &>/dev/null; then rm -f svninfo.tmp; else mv svninfo.tmp svninfo; fi
# .PHONY ensures the .tmp version is always rebuilt (to check for any changes)
.PHONY: svninfo.tmp
svninfo.tmp:
@@ -138,7 +138,7 @@ git_versioninfo.cpp: gitinfo
# This .tmp business is to keep from having to re-compile options.cpp
# (and then re-link the libraries) if nothing has changed.
gitinfo: gitinfo.tmp
- $(AM_V_GEN)diff -q gitinfo.tmp gitinfo &>/dev/null || mv gitinfo.tmp gitinfo || true
+ $(AM_V_GEN)if diff -q gitinfo.tmp gitinfo &>/dev/null; then rm -f gitinfo.tmp; else mv gitinfo.tmp gitinfo; fi || true
# .PHONY ensures the .tmp version is always rebuilt (to check for any changes)
.PHONY: gitinfo.tmp
gitinfo.tmp:
@@ -163,15 +163,18 @@ install-data-local:
$(mkinstalldirs) "$$(dirname "$(DESTDIR)$(includedir)/cvc4/$$d")"; \
if [ -e "$$f" ]; then \
path="$$f"; \
- fixpath="$$f.fix"; \
else \
path="$(srcdir)/$$f"; \
- fixpath="$(builddir)/$$f.fix"; \
- $(MKDIR_P) "`dirname "$$fixpath"`"; \
fi; \
+ fixpath="$(top_builddir)/header_install.fix"; \
sed 's,^\([ \t]*#[ \t]*include[ \t*]\)"\(.*\)"\([ \t]*\)$$,\1<cvc4/\2>\3,' "$$path" > "$$fixpath" || exit 1; \
echo $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d"; \
- $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d" || exit 1; \
+ if $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d"; then \
+ rm -f "$$fixpath"; \
+ else \
+ rm -f "$$fixpath"; \
+ exit 1; \
+ fi; \
done
uninstall-local:
@@ -196,34 +199,3 @@ uninstall-local:
-rmdir "$(DESTDIR)$(includedir)/cvc4/bindings"
-rmdir "$(DESTDIR)$(includedir)/cvc4"
-rmdir "$(DESTDIR)$(libdir)/ocaml/cvc4"
-
-# clean up the .fix files
-mostlyclean-local:
- (echo include/cvc4.h; \
- echo include/cvc4_public.h; \
- echo include/cvc4parser_public.h; \
- echo util/tls.h; \
- echo util/integer.h; \
- echo util/rational.h; \
- find * -name '*.h.fix' | \
- xargs grep -l '^# *include *<cvc4/cvc4.*_public\.h>' | \
- sed 's,\.fix$$,,'; \
- (cd "$(srcdir)" && find * -name '*.h' | \
- xargs grep -l '^# *include *"cvc4.*_public\.h"')) | \
- while read f; do \
- if expr "$$f" : ".*_\(template\|private\|private_library\|test_utils\)\.h$$" &>/dev/null; then \
- continue; \
- fi; \
- d="$$(echo "$$f" | sed 's,^include/,,')"; \
- if [ -e "$$f" ]; then \
- path="$$f"; \
- fixpath="$$f.fix"; \
- else \
- path="$(srcdir)/$$f"; \
- fixpath="$(builddir)/$$f.fix"; \
- $(MKDIR_P) "`dirname "$$fixpath"`"; \
- fi; \
- echo rm -f "$$fixpath"; \
- rm -f "$$fixpath"; \
- done
-
diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am
index cc2a7c53f..80e65d180 100644
--- a/src/bindings/Makefile.am
+++ b/src/bindings/Makefile.am
@@ -142,7 +142,7 @@ endif
endif
nodist_java_libcvc4jni_la_SOURCES = java.cpp
-java_libcvc4jni_la_CXXFLAGS = @FNO_STRICT_ALIASING@ @WNO_UNUSED_VARIABLE@ @WNO_UNINITIALIZED@
+java_libcvc4jni_la_CXXFLAGS = -Wno-all @FNO_STRICT_ALIASING@ @WNO_UNUSED_VARIABLE@ @WNO_UNINITIALIZED@
nodist_csharp_CVC4_la_SOURCES = csharp.cpp
nodist_perl_CVC4_la_SOURCES = perl.cpp
nodist_php_CVC4_la_SOURCES = php.cpp
@@ -171,7 +171,9 @@ MOSTLYCLEANFILES = \
$(patsubst %,%.d,$(filter-out c c++,$(CVC4_LANGUAGE_BINDINGS))) \
CVC4.jar
-java_libcvc4jni_la-java.lo java.lo: java.cpp
+java_libcvc4jni_la-java.lo: java.cpp
+ $(AM_V_CXX)$(LTCXXCOMPILE) -c $(JAVA_CPPFLAGS) $(java_libcvc4jni_la_CXXFLAGS) -o $@ $<
+java.lo: java.cpp
$(AM_V_CXX)$(LTCXXCOMPILE) -c $(JAVA_CPPFLAGS) $(java_libcvc4jni_la_CXXFLAGS) -o $@ $<
CVC4.jar: java.cpp
$(AM_V_GEN) \
diff --git a/src/bindings/compat/java/include/cvc3/JniUtils.h b/src/bindings/compat/java/include/cvc3/JniUtils.h
index 567c691fe..404774c62 100644
--- a/src/bindings/compat/java/include/cvc3/JniUtils.h
+++ b/src/bindings/compat/java/include/cvc3/JniUtils.h
@@ -109,7 +109,7 @@ namespace Java_cvc3_JniUtils {
// embeds a c++ object into a jobject,
// and takes over the responsibility to deallocate it
template <class T> jobject embed_own(JNIEnv* env, T* cobj) {
- DebugAssert(&cobj != NULL, "JniUtils::embed_own: null object given");
+ DebugAssert(cobj != NULL, "JniUtils::embed_own: null object given");
return embed<T>(env, cobj, typeid(cobj), &DeleteEmbedded<T>::deleteEmbedded);
}
diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp
index 0ecc6b5c7..2b552684a 100644
--- a/src/compat/cvc3_compat.cpp
+++ b/src/compat/cvc3_compat.cpp
@@ -25,6 +25,7 @@
#include "util/hash.h"
#include "util/subrange_bound.h"
#include "util/predicate.h"
+#include "util/output.h"
#include "parser/parser.h"
#include "parser/parser_builder.h"
@@ -1065,8 +1066,8 @@ Type ValidityChecker::intType() {
}
Type ValidityChecker::subrangeType(const Expr& l, const Expr& r) {
- bool noLowerBound = l.getType().isString() && l.getConst<string>() == "_NEGINF";
- bool noUpperBound = r.getType().isString() && r.getConst<string>() == "_POSINF";
+ bool noLowerBound = l.getType().isString() && l.getConst<CVC4::String>() == "_NEGINF";
+ bool noUpperBound = r.getType().isString() && r.getConst<CVC4::String>() == "_POSINF";
CVC4::CheckArgument(noLowerBound || (l.getKind() == CVC4::kind::CONST_RATIONAL && l.getConst<Rational>().isIntegral()), l);
CVC4::CheckArgument(noUpperBound || (r.getKind() == CVC4::kind::CONST_RATIONAL && r.getConst<Rational>().isIntegral()), r);
CVC4::SubrangeBound bl = noLowerBound ? CVC4::SubrangeBound() : CVC4::SubrangeBound(l.getConst<Rational>().getNumerator());
@@ -1196,7 +1197,7 @@ void ValidityChecker::dataType(const std::vector<std::string>& names,
CVC4::CheckArgument(selectors[i][j].size() == types[i][j].size(), types, "expected sub-vectors in selectors and types vectors to match in size");
for(unsigned k = 0; k < selectors[i][j].size(); ++k) {
if(types[i][j][k].getType().isString()) {
- ctor.addArg(selectors[i][j][k], CVC4::DatatypeUnresolvedType(types[i][j][k].getConst<string>()));
+ ctor.addArg(selectors[i][j][k], CVC4::DatatypeUnresolvedType(types[i][j][k].getConst<CVC4::String>().toString()));
} else {
ctor.addArg(selectors[i][j][k], exprToType(types[i][j][k]));
}
@@ -1306,12 +1307,12 @@ Expr ValidityChecker::getTypePred(const Type&t, const Expr& e) {
}
Expr ValidityChecker::stringExpr(const std::string& str) {
- return d_em->mkConst(str);
+ return d_em->mkConst(CVC4::String(str));
}
Expr ValidityChecker::idExpr(const std::string& name) {
// represent as a string expr, CVC4 doesn't have id exprs
- return d_em->mkConst(name);
+ return d_em->mkConst(CVC4::String(name));
}
Expr ValidityChecker::listExpr(const std::vector<Expr>& kids) {
@@ -1332,21 +1333,21 @@ Expr ValidityChecker::listExpr(const Expr& e1, const Expr& e2, const Expr& e3) {
Expr ValidityChecker::listExpr(const std::string& op,
const std::vector<Expr>& kids) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), vector<CVC4::Expr>(kids.begin(), kids.end()));
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), vector<CVC4::Expr>(kids.begin(), kids.end()));
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1);
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1,
const Expr& e2) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1, e2);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1, e2);
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1,
const Expr& e2, const Expr& e3) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1, e2, e3);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1, e2, e3);
}
void ValidityChecker::printExpr(const Expr& e) {
@@ -2273,7 +2274,7 @@ void ValidityChecker::popto(int stackLevel) {
}
int ValidityChecker::scopeLevel() {
- return d_parserContext->getDeclarationLevel();
+ return d_parserContext->scopeLevel();
}
void ValidityChecker::pushScope() {
@@ -2287,12 +2288,12 @@ void ValidityChecker::popScope() {
void ValidityChecker::poptoScope(int scopeLevel) {
CVC4::CheckArgument(scopeLevel >= 0, scopeLevel,
"Cannot pop to a negative scope level %d", scopeLevel);
- CVC4::CheckArgument(unsigned(scopeLevel) <= d_parserContext->getDeclarationLevel(),
+ CVC4::CheckArgument(unsigned(scopeLevel) <= d_parserContext->scopeLevel(),
scopeLevel,
"Cannot pop to a scope level higher than the current one! "
"At scope level %u, user requested scope level %d",
- d_parserContext->getDeclarationLevel(), scopeLevel);
- while(unsigned(scopeLevel) < d_parserContext->getDeclarationLevel()) {
+ d_parserContext->scopeLevel(), scopeLevel);
+ while(unsigned(scopeLevel) < d_parserContext->scopeLevel()) {
popScope();
}
}
diff --git a/src/cvc4.i b/src/cvc4.i
index 965452b84..6e9380146 100644
--- a/src/cvc4.i
+++ b/src/cvc4.i
@@ -54,9 +54,11 @@ using namespace CVC4;
#include "expr/expr.h"
#include "util/datatype.h"
#include "expr/command.h"
-#include "bindings/java_stream_adapters.h"
+#ifdef SWIGJAVA
+#include "bindings/java_stream_adapters.h"
std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
+#endif
%}
%template(vectorCommandPtr) std::vector< CVC4::Command* >;
@@ -248,7 +250,6 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
%include "util/bool.i"
%include "util/sexpr.i"
%include "util/statistics.i"
-%include "util/output.i"
%include "util/result.i"
%include "util/configuration.i"
%include "util/bitvector.i"
diff --git a/src/decision/Makefile.am b/src/decision/Makefile.am
index 6d49c6301..f75a17a69 100644
--- a/src/decision/Makefile.am
+++ b/src/decision/Makefile.am
@@ -12,9 +12,7 @@ libdecision_la_SOURCES = \
decision_engine.cpp \
decision_strategy.h \
justification_heuristic.h \
- justification_heuristic.cpp \
- relevancy.h \
- relevancy.cpp
+ justification_heuristic.cpp
EXTRA_DIST = \
options_handlers.h
diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp
index 687515ff0..073a3ff6b 100644
--- a/src/decision/decision_engine.cpp
+++ b/src/decision/decision_engine.cpp
@@ -16,7 +16,6 @@
#include "decision/decision_engine.h"
#include "decision/justification_heuristic.h"
-#include "decision/relevancy.h"
#include "expr/node.h"
#include "decision/options.h"
@@ -62,18 +61,6 @@ void DecisionEngine::init()
enableStrategy(ds);
d_needIteSkolemMap.push_back(ds);
}
- if(options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY) {
- if(options::incrementalSolving()) {
- Warning() << "Relevancy decision heuristic and incremental not supported together"
- << std::endl;
- return; // Currently not supported with incremental
- }
- RelevancyStrategy* ds =
- new decision::Relevancy(this, d_satContext);
- enableStrategy(ds);
- d_needIteSkolemMap.push_back(ds);
- d_relevancyStrategy = ds;
- }
}
@@ -82,6 +69,13 @@ void DecisionEngine::enableStrategy(DecisionStrategy* ds)
d_enabledStrategies.push_back(ds);
}
+void DecisionEngine::clearStrategies(){
+ for(unsigned i = 0; i < d_enabledStrategies.size(); ++i){
+ delete d_enabledStrategies[i];
+ }
+ d_enabledStrategies.clear();
+ d_needIteSkolemMap.clear();
+}
bool DecisionEngine::isRelevant(SatVariable var)
{
@@ -105,13 +99,6 @@ SatValue DecisionEngine::getPolarity(SatVariable var)
}
}
-
-
-
-
-
-
-
void DecisionEngine::addAssertions(const vector<Node> &assertions)
{
Assert(false); // doing this so that we revisit what to do
@@ -139,15 +126,4 @@ void DecisionEngine::addAssertions(const vector<Node> &assertions,
addAssertions(assertions, assertionsEnd, iteSkolemMap);
}
-// void DecisionEngine::addAssertion(Node n)
-// {
-// d_result = SAT_VALUE_UNKNOWN;
-// if(needIteSkolemMap()) {
-// d_assertions.push_back(n);
-// }
-// for(unsigned i = 0; i < d_needIteSkolemMap.size(); ++i)
-// d_needIteSkolemMap[i]->notifyAssertionsAvailable();
-// }
-
-
}/* CVC4 namespace */
diff --git a/src/decision/decision_engine.h b/src/decision/decision_engine.h
index bc071f7f6..f28b13774 100644
--- a/src/decision/decision_engine.h
+++ b/src/decision/decision_engine.h
@@ -96,6 +96,10 @@ public:
/* enables decision stragies based on options */
void init();
+ /* clears all of the strategies */
+ void clearStrategies();
+
+
/**
* This is called by SmtEngine, at shutdown time, just before
* destruction. It is important because there are destruction
@@ -106,8 +110,7 @@ public:
d_engineState = 2;
Trace("decision") << "Shutting down decision engine" << std::endl;
- for(unsigned i = 0; i < d_enabledStrategies.size(); ++i)
- delete d_enabledStrategies[i];
+ clearStrategies();
}
// Interface for External World to use our services
diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp
index de49f6e0a..78de1a74e 100644
--- a/src/decision/justification_heuristic.cpp
+++ b/src/decision/justification_heuristic.cpp
@@ -96,7 +96,8 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl;
// Sanity check: if it was false, aren't we inconsistent?
- Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
+ // Commenting out. See bug 374. In short, to do with how CNF stream works.
+ // Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
SatValue desiredVal = SAT_VALUE_TRUE;
SatLiteral litDecision;
@@ -105,6 +106,7 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
if(litDecision != undefSatLiteral) {
setPrvsIndex(i);
+ Trace("decision") << "jh: spliting on " << litDecision << std::endl;
return litDecision;
}
}
@@ -441,8 +443,9 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value");
/* Good luck, hope you can get what you want */
- Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
- "invariant violated");
+ // See bug 374
+ // Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
+ // "invariant violated");
/* What type of node is this */
Kind k = node.getKind();
@@ -458,12 +461,12 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
* If not in theory of booleans, check if this is something to split-on.
*/
if(tId != theory::THEORY_BOOL) {
-
// if node has embedded ites, resolve that first
if(handleEmbeddedITEs(node) == FOUND_SPLITTER)
return FOUND_SPLITTER;
if(litVal != SAT_VALUE_UNKNOWN) {
+ Assert(litVal == desiredVal);
setJustified(node);
return NO_SPLITTER;
}
diff --git a/src/decision/options b/src/decision/options
index b86577e7b..1f0b137cb 100644
--- a/src/decision/options
+++ b/src/decision/options
@@ -6,17 +6,9 @@
module DECISION "decision/options.h" Decision heuristics
# When/whether to use any decision strategies
-option decisionMode --decision=MODE decision::DecisionMode :handler CVC4::decision::stringToDecisionMode :default decision::DECISION_STRATEGY_INTERNAL :read-write :include "decision/decision_mode.h" :handler-include "decision/options_handlers.h"
+option decisionMode decision-mode --decision=MODE decision::DecisionMode :handler CVC4::decision::stringToDecisionMode :default decision::DECISION_STRATEGY_INTERNAL :read-write :include "decision/decision_mode.h" :handler-include "decision/options_handlers.h"
choose decision mode, see --decision=help
-option decisionRelevancyLeaves bool
-# permille = part per thousand
-option decisionMaxRelTimeAsPermille --decision-budget=N "unsigned short" :read-write :predicate less_equal(1000L) :predicate CVC4::decision::checkDecisionBudget :predicate-include "decision/options_handlers.h"
- impose a budget for relevancy heuristic which increases linearly with each decision. N between 0 and 1000. (default: 1000, no budget)
-# if false, do justification stuff using relevancy.h
-option decisionComputeRelevancy bool
-# use the must be relevant
-option decisionMustRelevancy bool
# only use DE to determine when to stop, not to make decisions
option decisionStopOnly bool
diff --git a/src/decision/options_handlers.h b/src/decision/options_handlers.h
index 05d975ef1..44a623970 100644
--- a/src/decision/options_handlers.h
+++ b/src/decision/options_handlers.h
@@ -37,31 +37,8 @@ justification\n\
justification-stoponly\n\
+ Use the justification heuristic only to stop early, not for decisions\n\
";
-/** Under-development options, commenting out from help for the release */
-/*
-\n\
-relevancy\n\
-+ Under development may-relevancy\n\
-\n\
-relevancy-leaves\n\
-+ May-relevancy, but decide only on leaves\n\
-\n\
-Developer modes:\n\
-\n\
-justification-rel\n\
-+ Use the relevancy code to do the justification stuff\n\
-+ (This should do exact same thing as justification)\n\
-\n\
-justification-must\n\
-+ Start deciding on literals close to root instead of those\n\
-+ near leaves (don't expect it to work well) [Unimplemented]\n\
-";*/
inline DecisionMode stringToDecisionMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
- options::decisionRelevancyLeaves.set(false);
- options::decisionMaxRelTimeAsPermille.set(1000);
- options::decisionComputeRelevancy.set(true);
- options::decisionMustRelevancy.set(false);
options::decisionStopOnly.set(false);
if(optarg == "internal") {
@@ -71,25 +48,6 @@ inline DecisionMode stringToDecisionMode(std::string option, std::string optarg,
} else if(optarg == "justification-stoponly") {
options::decisionStopOnly.set(true);
return DECISION_STRATEGY_JUSTIFICATION;
- } else if(optarg == "relevancy") {
- options::decisionRelevancyLeaves.set(false);
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "relevancy-leaves") {
- options::decisionRelevancyLeaves.set(true);
- Trace("options") << "version is " << options::version() << std::endl;
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "justification-rel") {
- // relevancyLeaves : irrelevant
- // maxRelTimeAsPermille : irrelevant
- options::decisionComputeRelevancy.set(false);
- options::decisionMustRelevancy.set(false);
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "justification-must") {
- // relevancyLeaves : irrelevant
- // maxRelTimeAsPermille : irrelevant
- options::decisionComputeRelevancy.set(false);
- options::decisionMustRelevancy.set(true);
- return DECISION_STRATEGY_RELEVANCY;
} else if(optarg == "help") {
puts(decisionModeHelp.c_str());
exit(1);
@@ -99,14 +57,6 @@ inline DecisionMode stringToDecisionMode(std::string option, std::string optarg,
}
}
-inline void checkDecisionBudget(std::string option, unsigned short budget, SmtEngine* smt) throw(OptionException) {
- if(budget == 0) {
- Warning() << "Decision budget is 0. Consider using internal decision heuristic and "
- << std::endl << " removing this option." << std::endl;
-
- }
-}
-
inline DecisionWeightInternal stringToDecisionWeightInternal(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "off")
return DECISION_WEIGHT_INTERNAL_OFF;
diff --git a/src/decision/relevancy.cpp b/src/decision/relevancy.cpp
deleted file mode 100644
index f83e238d4..000000000
--- a/src/decision/relevancy.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/********************* */
-/*! \file relevancy.cpp
- ** \verbatim
- ** Original author: Kshitij Bansal
- ** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Justification heuristic for decision making
- **
- ** A ATGP-inspired justification-based decision heuristic. See
- ** [insert reference] for more details. This code is, or not, based
- ** on the CVC3 implementation of the same heuristic -- note below.
- **
- ** It needs access to the simplified but non-clausal formula.
- **/
-/*****************************************************************************/
-
-#include "relevancy.h"
-
-#include "expr/node_manager.h"
-#include "expr/kind.h"
-#include "theory/rewriter.h"
-#include "util/ite_removal.h"
-
-// Relevancy stuff
-
-const double Relevancy::secondsPerDecision = 0.001;
-const double Relevancy::secondsPerExpense = 1e-7;
-const double Relevancy::EPS = 1e-9;
-
-
-void Relevancy::setJustified(TNode n)
-{
- Debug("decision") << " marking [" << n.getId() << "]"<< n << "as justified" << std::endl;
- d_justified.insert(n);
- if(options::decisionComputeRelevancy()) {
- d_relevancy[n] = d_maxRelevancy[n];
- updateRelevancy(n);
- }
-}
-
-bool Relevancy::checkJustified(TNode n)
-{
- return d_justified.find(n) != d_justified.end();
-}
-
-SatValue Relevancy::tryGetSatValue(Node n)
-{
- Debug("decision") << " " << n << " has sat value " << " ";
- if(d_decisionEngine->hasSatLiteral(n) ) {
- Debug("decision") << d_decisionEngine->getSatValue(n) << std::endl;
- return d_decisionEngine->getSatValue(n);
- } else {
- Debug("decision") << "NO SAT LITERAL" << std::endl;
- return SAT_VALUE_UNKNOWN;
- }//end of else
-}
-
-void Relevancy::computeITEs(TNode n, IteList &l)
-{
- Debug("jh-ite") << " computeITEs( " << n << ", &l)\n";
- for(unsigned i=0; i<n.getNumChildren(); ++i) {
- SkolemMap::iterator it2 = d_iteAssertions.find(n[i]);
- if(it2 != d_iteAssertions.end())
- l.push_back(it2->second);
- computeITEs(n[i], l);
- }
-}
-
-const Relevancy::IteList& Relevancy::getITEs(TNode n)
-{
- IteCache::iterator it = d_iteCache.find(n);
- if(it != d_iteCache.end()) {
- return it->second;
- } else {
- // Compute the list of ITEs
- // TODO: optimize by avoiding multiple lookup for d_iteCache[n]
- d_iteCache[n] = vector<TNode>();
- computeITEs(n, d_iteCache[n]);
- return d_iteCache[n];
- }
-}
-
-bool Relevancy::findSplitterRec(TNode node,
- SatValue desiredVal)
-{
- Trace("decision")
- << "findSplitterRec([" << node.getId() << "]" << node << ", "
- << desiredVal << ", .. )" << std::endl;
-
- ++d_expense;
-
- /* Handle NOT as a special case */
- while (node.getKind() == kind::NOT) {
- desiredVal = invertValue(desiredVal);
- node = node[0];
- }
-
- /* Avoid infinite loops */
- if(d_visited.find(node) != d_visited.end()) {
- Debug("decision") << " node repeated. kind was " << node.getKind() << std::endl;
- Assert(false);
- Assert(node.getKind() == kind::ITE);
- return false;
- }
-
- /* Base case */
- if(checkJustified(node)) {
- return false;
- }
-
- /**
- * If we have already explored the subtree for some desiredVal, we
- * skip this and continue exploring the rest
- */
- if(d_polarityCache.find(node) == d_polarityCache.end()) {
- d_polarityCache[node] = desiredVal;
- } else {
- Assert(d_multipleBacktrace || options::decisionComputeRelevancy());
- return true;
- }
-
- d_visited.insert(node);
-
-#if defined CVC4_ASSERTIONS || defined CVC4_TRACING
- // We don't always have a sat literal, so remember that. Will need
- // it for some assertions we make.
- bool litPresent = d_decisionEngine->hasSatLiteral(node);
- if(Trace.isOn("decision")) {
- if(!litPresent) {
- Trace("decision") << "no sat literal for this node" << std::endl;
- }
- }
- //Assert(litPresent); -- fails
-#endif
-
- // Get value of sat literal for the node, if there is one
- SatValue litVal = tryGetSatValue(node);
-
- /* You'd better know what you want */
- Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value");
-
- /* Good luck, hope you can get what you want */
- Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
- "invariant violated");
-
- /* What type of node is this */
- Kind k = node.getKind();
- theory::TheoryId tId = theory::kindToTheoryId(k);
-
- /* Some debugging stuff */
- Trace("jh-findSplitterRec") << "kind = " << k << std::endl;
- Trace("jh-findSplitterRec") << "theoryId = " << tId << std::endl;
- Trace("jh-findSplitterRec") << "node = " << node << std::endl;
- Trace("jh-findSplitterRec") << "litVal = " << litVal << std::endl;
-
- /**
- * If not in theory of booleans, and not a "boolean" EQUAL (IFF),
- * then check if this is something to split-on.
- */
- if(tId != theory::THEORY_BOOL
- // && !(k == kind::EQUAL && node[0].getType().isBoolean())
- ) {
-
- // if node has embedded ites -- which currently happens iff it got
- // replaced during ite removal -- then try to resolve that first
- const IteList& l = getITEs(node);
- Debug("jh-ite") << " ite size = " << l.size() << std::endl;
- for(unsigned i = 0; i < l.size(); ++i) {
- Assert(l[i].getKind() == kind::ITE, "Expected ITE");
- Debug("jh-ite") << " i = " << i
- << " l[i] = " << l[i] << std::endl;
- if(d_visited.find(node) != d_visited.end() ) continue;
- if(findSplitterRec(l[i], SAT_VALUE_TRUE)) {
- d_visited.erase(node);
- return true;
- }
- }
- Debug("jh-ite") << " ite done " << l.size() << std::endl;
-
- if(litVal != SAT_VALUE_UNKNOWN) {
- d_visited.erase(node);
- setJustified(node);
- return false;
- } else {
- /* if(not d_decisionEngine->hasSatLiteral(node))
- throw GiveUpException(); */
- Assert(d_decisionEngine->hasSatLiteral(node));
- SatVariable v = d_decisionEngine->getSatLiteral(node).getSatVariable();
- *d_curDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE );
- Trace("decision") << "decision " << *d_curDecision << std::endl;
- Trace("decision") << "Found something to split. Glad to be able to serve you." << std::endl;
- d_visited.erase(node);
- return true;
- }
- }
-
- bool ret = false;
- SatValue flipCaseVal = SAT_VALUE_FALSE;
- switch (k) {
-
- case kind::CONST_BOOLEAN:
- Assert(node.getConst<bool>() == false || desiredVal == SAT_VALUE_TRUE);
- Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE);
- break;
-
- case kind::AND:
- if (desiredVal == SAT_VALUE_FALSE) ret = handleOrTrue(node, SAT_VALUE_FALSE);
- else ret = handleOrFalse(node, SAT_VALUE_TRUE);
- break;
-
- case kind::OR:
- if (desiredVal == SAT_VALUE_FALSE) ret = handleOrFalse(node, SAT_VALUE_FALSE);
- else ret = handleOrTrue(node, SAT_VALUE_TRUE);
- break;
-
- case kind::IMPLIES:
- Assert(node.getNumChildren() == 2, "Expected 2 fanins");
- if (desiredVal == SAT_VALUE_FALSE) {
- ret = findSplitterRec(node[0], SAT_VALUE_TRUE);
- if(ret) break;
- ret = findSplitterRec(node[1], SAT_VALUE_FALSE);
- break;
- }
- else {
- if (tryGetSatValue(node[0]) != SAT_VALUE_TRUE) {
- ret = findSplitterRec(node[0], SAT_VALUE_FALSE);
- //if(!ret || !d_multipleBacktrace)
- break;
- }
- if (tryGetSatValue(node[1]) != SAT_VALUE_FALSE) {
- ret = findSplitterRec(node[1], SAT_VALUE_TRUE);
- break;
- }
- Assert(d_multipleBacktrace, "No controlling input found (3)");
- }
- break;
-
- case kind::XOR:
- flipCaseVal = SAT_VALUE_TRUE;
- case kind::IFF: {
- SatValue val = tryGetSatValue(node[0]);
- if (val != SAT_VALUE_UNKNOWN) {
- ret = findSplitterRec(node[0], val);
- if (ret) break;
- if (desiredVal == flipCaseVal) val = invertValue(val);
- ret = findSplitterRec(node[1], val);
- }
- else {
- val = tryGetSatValue(node[1]);
- if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE;
- if (desiredVal == flipCaseVal) val = invertValue(val);
- ret = findSplitterRec(node[0], val);
- if(ret) break;
- Assert(false, "Unable to find controlling input (4)");
- }
- break;
- }
-
- case kind::ITE:
- ret = handleITE(node, desiredVal);
- break;
-
- default:
- Assert(false, "Unexpected Boolean operator");
- break;
- }//end of switch(k)
-
- d_visited.erase(node);
- if(ret == false) {
- Assert(litPresent == false || litVal == desiredVal,
- "Output should be justified");
- setJustified(node);
- }
- return ret;
-
- Unreachable();
-}/* findRecSplit method */
-
-bool Relevancy::handleOrFalse(TNode node, SatValue desiredVal) {
- Debug("jh-findSplitterRec") << " handleOrFalse (" << node << ", "
- << desiredVal << std::endl;
-
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or
- (node.getKind() == kind::OR and desiredVal == SAT_VALUE_FALSE) );
-
- int n = node.getNumChildren();
- bool ret = false;
- for(int i = 0; i < n; ++i) {
- if (findSplitterRec(node[i], desiredVal)) {
- if(!options::decisionComputeRelevancy())
- return true;
- else
- ret = true;
- }
- }
- return ret;
-}
-
-bool Relevancy::handleOrTrue(TNode node, SatValue desiredVal) {
- Debug("jh-findSplitterRec") << " handleOrTrue (" << node << ", "
- << desiredVal << std::endl;
-
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or
- (node.getKind() == kind::OR and desiredVal == SAT_VALUE_TRUE) );
-
- int n = node.getNumChildren();
- SatValue desiredValInverted = invertValue(desiredVal);
- for(int i = 0; i < n; ++i) {
- if ( tryGetSatValue(node[i]) != desiredValInverted ) {
- // PRE RELEVANCY return findSplitterRec(node[i], desiredVal);
- bool ret = findSplitterRec(node[i], desiredVal);
- if(ret) {
- // Splitter could be found... so can't justify this node
- if(!d_multipleBacktrace)
- return true;
- }
- else {
- // Splitter couldn't be found... should be justified
- return false;
- }
- }
- }
- // Multiple backtrace is on, so must have reached here because
- // everything had splitter
- if(d_multipleBacktrace) return true;
-
- if(Debug.isOn("jh-findSplitterRec")) {
- Debug("jh-findSplitterRec") << " * ** " << std::endl;
- Debug("jh-findSplitterRec") << node.getKind() << " "
- << node << std::endl;
- for(unsigned i = 0; i < node.getNumChildren(); ++i)
- Debug("jh-findSplitterRec") << "child: " << tryGetSatValue(node[i])
- << std::endl;
- Debug("jh-findSplitterRec") << "node: " << tryGetSatValue(node)
- << std::endl;
- }
- Assert(false, "No controlling input found");
- return false;
-}
-
-bool Relevancy::handleITE(TNode node, SatValue desiredVal)
-{
- Debug("jh-findSplitterRec") << " handleITE (" << node << ", "
- << desiredVal << std::endl;
-
- //[0]: if, [1]: then, [2]: else
- SatValue ifVal = tryGetSatValue(node[0]);
- if (ifVal == SAT_VALUE_UNKNOWN) {
-
- // are we better off trying false? if not, try true
- SatValue ifDesiredVal =
- (tryGetSatValue(node[2]) == desiredVal ||
- tryGetSatValue(node[1]) == invertValue(desiredVal))
- ? SAT_VALUE_FALSE : SAT_VALUE_TRUE;
-
- if(findSplitterRec(node[0], ifDesiredVal)) return true;
-
- Assert(false, "No controlling input found (6)");
- } else {
-
- // Try to justify 'if'
- if(findSplitterRec(node[0], ifVal)) return true;
-
- // If that was successful, we need to go into only one of 'then'
- // or 'else'
- int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2;
- int chVal = tryGetSatValue(node[ch]);
- if( (chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal) &&
- findSplitterRec(node[ch], desiredVal) ) {
- return true;
- }
- }// else (...ifVal...)
- return false;
-}//handleITE
diff --git a/src/decision/relevancy.h b/src/decision/relevancy.h
deleted file mode 100644
index fd16eb0cc..000000000
--- a/src/decision/relevancy.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/********************* */
-/*! \file relevancy.h
- ** \verbatim
- ** Original author: Kshitij Bansal
- ** Major contributors: none
- ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Justification heuristic for decision making
- **
- ** A ATGP-inspired justification-based decision heuristic. See
- ** [insert reference] for more details. This code is, or not, based
- ** on the CVC3 implementation of the same heuristic.
- **
- ** It needs access to the simplified but non-clausal formula.
- **
- ** Relevancy
- ** ---------
- **
- ** This class also currently computes the may-relevancy of a node
- **
- ** A node is may-relevant if there is a path from the root of the
- ** formula to the node such that no node on the path is justified. As
- ** contrapositive, a node is not relevant (with the may-notion) if all
- ** path from the root to the node go through a justified node.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__DECISION__RELEVANCY
-#define __CVC4__DECISION__RELEVANCY
-
-#include "decision_engine.h"
-#include "decision_strategy.h"
-#include "decision/options.h"
-
-#include "context/cdhashset.h"
-#include "context/cdhashmap.h"
-#include "expr/node.h"
-#include "prop/sat_solver_types.h"
-
-namespace CVC4 {
-
-namespace decision {
-
-class RelGiveUpException : public Exception {
-public:
- RelGiveUpException() :
- Exception("relevancy: giving up") {
- }
-};/* class GiveUpException */
-
-class Relevancy : public RelevancyStrategy {
- typedef std::vector<TNode> IteList;
- typedef hash_map<TNode,IteList,TNodeHashFunction> IteCache;
- typedef hash_map<TNode,TNode,TNodeHashFunction> SkolemMap;
- typedef hash_map<TNode,SatValue,TNodeHashFunction> PolarityCache;
-
- // being 'justified' is monotonic with respect to decisions
- context::CDHashSet<Node, NodeHashFunction> d_justified;
- context::CDO<unsigned> d_prvsIndex;
-
- IntStat d_helfulness;
- IntStat d_polqueries;
- IntStat d_polhelp;
- IntStat d_giveup;
- IntStat d_expense; /* Total number of nodes considered over
- all calls to the findSplitter function */
- TimerStat d_timestat;
-
- /**
- * A copy of the assertions that need to be justified
- * directly. Doesn't have ones introduced during during ITE-removal.
- */
- std::vector<TNode> d_assertions;
- //TNode is fine since decisionEngine has them too
-
- /** map from ite-rewrite skolem to a boolean-ite assertion */
- SkolemMap d_iteAssertions;
- // 'key' being TNode is fine since if a skolem didn't exist anywhere,
- // we won't look it up. as for 'value', same reason as d_assertions
-
- /** Cache for ITE skolems present in a atomic formula */
- IteCache d_iteCache;
-
- /**
- * This is used to prevent infinite loop when trying to find a
- * splitter. Can happen when exploring assertion corresponding to a
- * term-ITE.
- */
- hash_set<TNode,TNodeHashFunction> d_visited;
-
- /**
- * May-relevancy of a node is an integer. For a node n, it becomes
- * irrelevant when d_maxRelevancy[n] = d_relevancy[n]
- */
- hash_map<TNode,int,TNodeHashFunction> d_maxRelevancy;
- context::CDHashMap<TNode,int,TNodeHashFunction> d_relevancy;
- PolarityCache d_polarityCache;
-
- /** **** * * *** * * OPTIONS *** * * ** * * **** */
-
- /**
- * do we do "multiple-backtrace" to try to justify a node
- */
- bool d_multipleBacktrace;
- //bool d_computeRelevancy; // are we in a mode where we compute relevancy?
-
- static const double secondsPerDecision;
- static const double secondsPerExpense;
- static const double EPS;
-
- /** Maximum time this algorithm should spent as part of whole algorithm */
- double d_maxTimeAsPercentageOfTotalTime;
-
- /** current decision for the recursive call */
- SatLiteral* d_curDecision;
-public:
- Relevancy(CVC4::DecisionEngine* de, context::Context *c):
- RelevancyStrategy(de, c),
- d_justified(c),
- d_prvsIndex(c, 0),
- d_helfulness("decision::rel::preventedDecisions", 0),
- d_polqueries("decision::rel::polarityQueries", 0),
- d_polhelp("decision::rel::polarityHelp", 0),
- d_giveup("decision::rel::giveup", 0),
- d_expense("decision::rel::expense", 0),
- d_timestat("decision::rel::time"),
- d_relevancy(c),
- d_multipleBacktrace(options::decisionComputeRelevancy()),
- // d_computeRelevancy(decOpt.computeRelevancy),
- d_maxTimeAsPercentageOfTotalTime(options::decisionMaxRelTimeAsPermille()*1.0/10.0),
- d_curDecision(NULL)
- {
- Warning() << "There are known bugs in this Relevancy code which we know"
- << "how to fix (but haven't yet)." << std::endl
- << "Please bug kshitij if you wish to use." << std::endl;
-
- StatisticsRegistry::registerStat(&d_helfulness);
- StatisticsRegistry::registerStat(&d_polqueries);
- StatisticsRegistry::registerStat(&d_polhelp);
- StatisticsRegistry::registerStat(&d_giveup);
- StatisticsRegistry::registerStat(&d_expense);
- StatisticsRegistry::registerStat(&d_timestat);
- Trace("decision") << "relevancy enabled with" << std::endl;
- Trace("decision") << " * computeRelevancy: " << (options::decisionComputeRelevancy() ? "on" : "off")
- << std::endl;
- Trace("decision") << " * relevancyLeaves: " << (options::decisionRelevancyLeaves() ? "on" : "off")
- << std::endl;
- Trace("decision") << " * mustRelevancy [unimplemented]: " << (options::decisionMustRelevancy() ? "on" : "off")
- << std::endl;
- }
- ~Relevancy() {
- StatisticsRegistry::unregisterStat(&d_helfulness);
- StatisticsRegistry::unregisterStat(&d_polqueries);
- StatisticsRegistry::unregisterStat(&d_polhelp);
- StatisticsRegistry::unregisterStat(&d_giveup);
- StatisticsRegistry::unregisterStat(&d_expense);
- StatisticsRegistry::unregisterStat(&d_timestat);
- }
- prop::SatLiteral getNext(bool &stopSearch) {
- Debug("decision") << std::endl;
- Trace("decision") << "Relevancy::getNext()" << std::endl;
- TimerStat::CodeTimer codeTimer(d_timestat);
-
- if( d_maxTimeAsPercentageOfTotalTime < 100.0 - EPS &&
- double(d_polqueries.getData())*secondsPerDecision <
- d_maxTimeAsPercentageOfTotalTime*double(d_expense.getData())*secondsPerExpense
- ) {
- ++d_giveup;
- return undefSatLiteral;
- }
-
- d_visited.clear();
- d_polarityCache.clear();
-
- for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) {
- Trace("decision") << d_assertions[i] << std::endl;
-
- // Sanity check: if it was false, aren't we inconsistent?
- Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
-
- SatValue desiredVal = SAT_VALUE_TRUE;
- SatLiteral litDecision = findSplitter(d_assertions[i], desiredVal);
-
- if(!options::decisionComputeRelevancy() && litDecision != undefSatLiteral) {
- d_prvsIndex = i;
- return litDecision;
- }
- }
-
- if(options::decisionComputeRelevancy()) return undefSatLiteral;
-
- Trace("decision") << "jh: Nothing to split on " << std::endl;
-
-#if defined CVC4_ASSERTIONS || defined CVC4_DEBUG
- bool alljustified = true;
- for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) {
- TNode curass = d_assertions[i];
- while(curass.getKind() == kind::NOT)
- curass = curass[0];
- alljustified &= checkJustified(curass);
-
- if(Debug.isOn("decision")) {
- if(!checkJustified(curass))
- Debug("decision") << "****** Not justified [i="<<i<<"]: "
- << d_assertions[i] << std::endl;
- }
- }
- Assert(alljustified);
-#endif
-
- // SAT solver can stop...
- stopSearch = true;
- d_decisionEngine->setResult(SAT_VALUE_TRUE);
- return prop::undefSatLiteral;
- }
-
- void addAssertions(const std::vector<Node> &assertions,
- unsigned assertionsEnd,
- IteSkolemMap iteSkolemMap) {
- Trace("decision")
- << "Relevancy::addAssertions()"
- << " size = " << assertions.size()
- << " assertionsEnd = " << assertionsEnd
- << std::endl;
-
- // Save mapping between ite skolems and ite assertions
- for(IteSkolemMap::iterator i = iteSkolemMap.begin();
- i != iteSkolemMap.end(); ++i) {
- Assert(i->second >= assertionsEnd && i->second < assertions.size());
- Debug("jh-ite") << " jh-ite: " << (i->first) << " maps to "
- << assertions[(i->second)] << std::endl;
- d_iteAssertions[i->first] = assertions[i->second];
- }
-
- // Save the 'real' assertions locally
- for(unsigned i = 0; i < assertionsEnd; ++i) {
- d_assertions.push_back(assertions[i]);
- d_visited.clear();
- if(options::decisionComputeRelevancy()) increaseMaxRelevancy(assertions[i]);
- d_visited.clear();
- }
-
- }
-
- bool isRelevant(TNode n) {
- Trace("decision") << "isRelevant(" << n << "): ";
-
- if(Debug.isOn("decision")) {
- if(d_maxRelevancy.find(n) == d_maxRelevancy.end()) {
- // we are becuase of not getting information about literals
- // created using newLiteral command... need to figure how to
- // handle that
- Message() << "isRelevant: WARNING: didn't find node when we should had" << std::endl;
- }
- }
-
- if(d_maxRelevancy.find(n) == d_maxRelevancy.end()) {
- Trace("decision") << "yes [not found in db]" << std::endl;
- return true;
- }
-
- if(options::decisionRelevancyLeaves() && !isAtomicFormula(n)) {
- Trace("decision") << "no [not a leaf]" << std::endl;
- return false;
- }
-
- Trace("decision") << (d_maxRelevancy[n] == d_relevancy[n] ? "no":"yes")
- << std::endl;
-
- Debug("decision") << " maxRel: " << (d_maxRelevancy[n] )
- << " rel: " << d_relevancy[n].get() << std::endl;
- // Assert(d_maxRelevancy.find(n) != d_maxRelevancy.end());
- Assert(0 <= d_relevancy[n] && d_relevancy[n] <= d_maxRelevancy[n]);
-
- if(d_maxRelevancy[n] == d_relevancy[n]) {
- ++d_helfulness; // preventedDecisions
- return false;
- } else {
- return true;
- }
- }
-
- SatValue getPolarity(TNode n) {
- Trace("decision") << "getPolarity([" << n.getId() << "]" << n << "): ";
- Assert(n.getKind() != kind::NOT);
- ++d_polqueries;
- PolarityCache::iterator it = d_polarityCache.find(n);
- if(it == d_polarityCache.end()) {
- Trace("decision") << "don't know" << std::endl;
- return SAT_VALUE_UNKNOWN;
- } else {
- ++d_polhelp;
- Trace("decision") << it->second << std::endl;
- return it->second;
- }
- }
-
- /* Compute justified */
- /*bool computeJustified() {
-
- }*/
-private:
- SatLiteral findSplitter(TNode node, SatValue desiredVal)
- {
- bool ret;
- SatLiteral litDecision;
- try {
- // init
- d_curDecision = &litDecision;
-
- // solve
- ret = findSplitterRec(node, desiredVal);
-
- // post
- d_curDecision = NULL;
- }catch(RelGiveUpException &e) {
- return prop::undefSatLiteral;
- }
- if(ret == true) {
- Trace("decision") << "Yippee!!" << std::endl;
- return litDecision;
- } else {
- return undefSatLiteral;
- }
- }
-
- /**
- * Do all the hardwork.
- * Return 'true' if the node cannot be justfied, 'false' it it can be.
- * Sets 'd_curDecision' if unable to justify (depending on the mode)
- * If 'd_computeRelevancy' is on does multiple backtrace
- */
- bool findSplitterRec(TNode node, SatValue value);
- // Functions to make findSplitterRec modular...
- bool handleOrFalse(TNode node, SatValue desiredVal);
- bool handleOrTrue(TNode node, SatValue desiredVal);
- bool handleITE(TNode node, SatValue desiredVal);
-
- /* Helper functions */
- void setJustified(TNode);
- bool checkJustified(TNode);
-
- /* If literal exists corresponding to the node return
- that. Otherwise an UNKNOWN */
- SatValue tryGetSatValue(Node n);
-
- /* Get list of all term-ITEs for the atomic formula v */
- const Relevancy::IteList& getITEs(TNode n);
-
- /* Compute all term-ITEs in a node recursively */
- void computeITEs(TNode n, IteList &l);
-
- /* Checks whether something is an atomic formula or not */
- bool isAtomicFormula(TNode n) {
- return theory::kindToTheoryId(n.getKind()) != theory::THEORY_BOOL;
- }
-
- /** Recursively increase relevancies */
- void updateRelevancy(TNode n) {
- if(d_visited.find(n) != d_visited.end()) return;
-
- Assert(d_relevancy[n] <= d_maxRelevancy[n]);
-
- if(d_relevancy[n] != d_maxRelevancy[n])
- return;
-
- d_visited.insert(n);
- if(isAtomicFormula(n)) {
- const IteList& l = getITEs(n);
- for(unsigned i = 0; i < l.size(); ++i) {
- if(d_visited.find(l[i]) == d_visited.end()) continue;
- d_relevancy[l[i]] = d_relevancy[l[i]] + 1;
- updateRelevancy(l[i]);
- }
- } else {
- for(unsigned i = 0; i < n.getNumChildren(); ++i) {
- if(d_visited.find(n[i]) == d_visited.end()) continue;
- d_relevancy[n[i]] = d_relevancy[n[i]] + 1;
- updateRelevancy(n[i]);
- }
- }
- d_visited.erase(n);
- }
-
- /* */
- void increaseMaxRelevancy(TNode n) {
-
- Debug("decision")
- << "increaseMaxRelevancy([" << n.getId() << "]" << n << ")"
- << std::endl;
-
- d_maxRelevancy[n]++;
-
- // don't update children multiple times
- if(d_visited.find(n) != d_visited.end()) return;
-
- d_visited.insert(n);
- // Part to make the recursive call
- if(isAtomicFormula(n)) {
- const IteList& l = getITEs(n);
- for(unsigned i = 0; i < l.size(); ++i)
- if(d_visited.find(l[i]) == d_visited.end())
- increaseMaxRelevancy(l[i]);
- } else {
- for(unsigned i = 0; i < n.getNumChildren(); ++i)
- increaseMaxRelevancy(n[i]);
- } //else (...atomic formula...)
- }
-
-};/* class Relevancy */
-
-}/* namespace decision */
-
-}/* namespace CVC4 */
-
-#endif /* __CVC4__DECISION__RELEVANCY */
diff --git a/src/expr/attribute.h b/src/expr/attribute.h
index 70f04be85..721a09403 100644
--- a/src/expr/attribute.h
+++ b/src/expr/attribute.h
@@ -446,7 +446,7 @@ struct HasAttribute<false, AttrKind> {
static inline bool hasAttribute(const AttributeManager* am,
NodeValue* nv) {
typedef typename AttrKind::value_type value_type;
- typedef KindValueToTableValueMapping<value_type> mapping;
+ //typedef KindValueToTableValueMapping<value_type> mapping;
typedef typename getTable<value_type, AttrKind::context_dependent>::
table_type table_type;
@@ -522,14 +522,14 @@ AttributeManager::setAttribute(NodeValue* nv,
template <class T>
inline void AttributeManager::deleteFromTable(AttrHash<T>& table,
NodeValue* nv) {
- for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::s_id; ++id) {
+ for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::getId(); ++id) {
typedef AttributeTraits<T, false> traits_t;
typedef AttrHash<T> hash_t;
std::pair<uint64_t, NodeValue*> pr = std::make_pair(id, nv);
- if(traits_t::cleanup[id] != NULL) {
+ if(traits_t::getCleanup()[id] != NULL) {
typename hash_t::iterator i = table.find(pr);
if(i != table.end()) {
- traits_t::cleanup[id]((*i).second);
+ traits_t::getCleanup()[id]((*i).second);
table.erase(pr);
}
} else {
@@ -544,7 +544,7 @@ inline void AttributeManager::deleteFromTable(AttrHash<T>& table,
template <class T>
inline void AttributeManager::deleteFromTable(CDAttrHash<T>& table,
NodeValue* nv) {
- for(unsigned id = 0; id < attr::LastAttributeId<T, true>::s_id; ++id) {
+ for(unsigned id = 0; id < attr::LastAttributeId<T, true>::getId(); ++id) {
table.obliterate(std::make_pair(id, nv));
}
}
@@ -558,8 +558,8 @@ inline void AttributeManager::deleteAllFromTable(AttrHash<T>& table) {
bool anyRequireClearing = false;
typedef AttributeTraits<T, false> traits_t;
typedef AttrHash<T> hash_t;
- for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::s_id; ++id) {
- if(traits_t::cleanup[id] != NULL) {
+ for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::getId(); ++id) {
+ if(traits_t::getCleanup()[id] != NULL) {
anyRequireClearing = true;
}
}
@@ -575,8 +575,8 @@ inline void AttributeManager::deleteAllFromTable(AttrHash<T>& table) {
<< " node_value: " << ((*it).first.second)
<< std::endl;
*/
- if(traits_t::cleanup[id] != NULL) {
- traits_t::cleanup[id]((*it).second);
+ if(traits_t::getCleanup()[id] != NULL) {
+ traits_t::getCleanup()[id]((*it).second);
}
++it;
}
diff --git a/src/expr/attribute_internals.h b/src/expr/attribute_internals.h
index 4893075c3..a0086440b 100644
--- a/src/expr/attribute_internals.h
+++ b/src/expr/attribute_internals.h
@@ -679,13 +679,12 @@ namespace attr {
*/
template <class T, bool context_dep>
struct LastAttributeId {
- static uint64_t s_id;
+ static uint64_t& getId() {
+ static uint64_t s_id = 0;
+ return s_id;
+ }
};
-/** Initially zero. */
-template <class T, bool context_dep>
-uint64_t LastAttributeId<T, context_dep>::s_id = 0;
-
}/* CVC4::expr::attr namespace */
// ATTRIBUTE TRAITS ============================================================
@@ -699,13 +698,12 @@ namespace attr {
template <class T, bool context_dep>
struct AttributeTraits {
typedef void (*cleanup_t)(T);
- static std::vector<cleanup_t> cleanup;
+ static std::vector<cleanup_t>& getCleanup() {
+ static std::vector<cleanup_t> cleanup;
+ return cleanup;
+ }
};
-template <class T, bool context_dep>
-std::vector<typename AttributeTraits<T, context_dep>::cleanup_t>
- AttributeTraits<T, context_dep>::cleanup;
-
}/* CVC4::expr::attr namespace */
// ATTRIBUTE DEFINITION ========================================================
@@ -765,9 +763,9 @@ public:
typedef typename attr::KindValueToTableValueMapping<value_t>::
table_value_type table_value_type;
typedef attr::AttributeTraits<table_value_type, context_dep> traits;
- uint64_t id = attr::LastAttributeId<table_value_type, context_dep>::s_id++;
- //Assert(traits::cleanup.size() == id);// sanity check
- traits::cleanup.push_back(attr::getCleanupStrategy<value_t,
+ uint64_t id = attr::LastAttributeId<table_value_type, context_dep>::getId()++;
+ Assert(traits::getCleanup().size() == id);// sanity check
+ traits::getCleanup().push_back(attr::getCleanupStrategy<value_t,
CleanupStrategy>::fn);
return id;
}
@@ -827,7 +825,7 @@ public:
* return the id.
*/
static inline uint64_t registerAttribute() {
- uint64_t id = attr::LastAttributeId<bool, context_dep>::s_id++;
+ uint64_t id = attr::LastAttributeId<bool, context_dep>::getId()++;
AlwaysAssert( id <= 63,
"Too many boolean node attributes registered "
"during initialization !" );
@@ -876,7 +874,7 @@ template <class T, class value_t, class CleanupStrategy, bool context_dep>
const uint64_t Attribute<T, value_t, CleanupStrategy, context_dep>::s_id =
( attr::AttributeTraits<typename attr::KindValueToTableValueMapping<value_t>::
table_value_type,
- context_dep>::cleanup.size(),
+ context_dep>::getCleanup().size(),
Attribute<T, value_t, CleanupStrategy, context_dep>::registerAttribute() );
/** Assign unique IDs to attributes at load time. */
diff --git a/src/expr/command.cpp b/src/expr/command.cpp
index 3a88a6cba..8ae448657 100644
--- a/src/expr/command.cpp
+++ b/src/expr/command.cpp
@@ -100,7 +100,7 @@ bool Command::fail() const throw() {
void Command::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
invoke(smtEngine);
if(!(isMuted() && ok())) {
- printResult(out);
+ printResult(out, smtEngine->getOption("command-verbosity:" + getCommandName()).getIntegerValue().toUnsignedInt());
}
}
@@ -119,9 +119,11 @@ void CommandStatus::toStream(std::ostream& out, OutputLanguage language) const t
Printer::getPrinter(language)->toStream(out, this);
}
-void Command::printResult(std::ostream& out) const throw() {
+void Command::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(d_commandStatus != NULL) {
- out << *d_commandStatus;
+ if((!ok() && verbosity >= 1) || verbosity >= 2) {
+ out << *d_commandStatus;
+ }
}
}
@@ -148,6 +150,10 @@ Command* EmptyCommand::clone() const {
return new EmptyCommand(d_name);
}
+std::string EmptyCommand::getCommandName() const throw() {
+ return "empty";
+}
+
/* class EchoCommand */
EchoCommand::EchoCommand(std::string output) throw() :
@@ -166,7 +172,7 @@ void EchoCommand::invoke(SmtEngine* smtEngine) throw() {
void EchoCommand::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
out << d_output << std::endl;
d_commandStatus = CommandSuccess::instance();
- printResult(out);
+ printResult(out, smtEngine->getOption("command-verbosity:" + getCommandName()).getIntegerValue().toUnsignedInt());
}
Command* EchoCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
@@ -177,6 +183,10 @@ Command* EchoCommand::clone() const {
return new EchoCommand(d_output);
}
+std::string EchoCommand::getCommandName() const throw() {
+ return "echo";
+}
+
/* class AssertCommand */
AssertCommand::AssertCommand(const Expr& e) throw() :
@@ -204,6 +214,11 @@ Command* AssertCommand::clone() const {
return new AssertCommand(d_expr);
}
+std::string AssertCommand::getCommandName() const throw() {
+ return "assert";
+}
+
+
/* class PushCommand */
void PushCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -223,6 +238,10 @@ Command* PushCommand::clone() const {
return new PushCommand();
}
+std::string PushCommand::getCommandName() const throw() {
+ return "push";
+}
+
/* class PopCommand */
void PopCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -242,6 +261,10 @@ Command* PopCommand::clone() const {
return new PopCommand();
}
+std::string PopCommand::getCommandName() const throw() {
+ return "pop";
+}
+
/* class CheckSatCommand */
CheckSatCommand::CheckSatCommand() throw() :
@@ -269,9 +292,9 @@ Result CheckSatCommand::getResult() const throw() {
return d_result;
}
-void CheckSatCommand::printResult(std::ostream& out) const throw() {
+void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -289,6 +312,10 @@ Command* CheckSatCommand::clone() const {
return c;
}
+std::string CheckSatCommand::getCommandName() const throw() {
+ return "check-sat";
+}
+
/* class QueryCommand */
QueryCommand::QueryCommand(const Expr& e) throw() :
@@ -312,9 +339,9 @@ Result QueryCommand::getResult() const throw() {
return d_result;
}
-void QueryCommand::printResult(std::ostream& out) const throw() {
+void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -332,6 +359,10 @@ Command* QueryCommand::clone() const {
return c;
}
+std::string QueryCommand::getCommandName() const throw() {
+ return "query";
+}
+
/* class QuitCommand */
QuitCommand::QuitCommand() throw() {
@@ -350,6 +381,10 @@ Command* QuitCommand::clone() const {
return new QuitCommand();
}
+std::string QuitCommand::getCommandName() const throw() {
+ return "exit";
+}
+
/* class CommentCommand */
CommentCommand::CommentCommand(std::string comment) throw() : d_comment(comment) {
@@ -372,6 +407,10 @@ Command* CommentCommand::clone() const {
return new CommentCommand(d_comment);
}
+std::string CommentCommand::getCommandName() const throw() {
+ return "comment";
+}
+
/* class CommandSequence */
CommandSequence::CommandSequence() throw() :
@@ -422,16 +461,13 @@ void CommandSequence::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
d_commandStatus = CommandSuccess::instance();
}
-CommandSequence::const_iterator CommandSequence::begin() const throw() {
- return d_commandSequence.begin();
-}
-
Command* CommandSequence::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
CommandSequence* seq = new CommandSequence();
for(iterator i = begin(); i != end(); ++i) {
Command* cmd_to_export = *i;
Command* cmd = cmd_to_export->exportTo(exprManager, variableMap);
seq->addCommand(cmd);
+ Debug("export") << "[export] so far coverted: " << seq << endl;
}
seq->d_index = d_index;
return seq;
@@ -446,6 +482,10 @@ Command* CommandSequence::clone() const {
return seq;
}
+CommandSequence::const_iterator CommandSequence::begin() const throw() {
+ return d_commandSequence.begin();
+}
+
CommandSequence::const_iterator CommandSequence::end() const throw() {
return d_commandSequence.end();
}
@@ -458,6 +498,10 @@ CommandSequence::iterator CommandSequence::end() throw() {
return d_commandSequence.end();
}
+std::string CommandSequence::getCommandName() const throw() {
+ return "sequence";
+}
+
/* class DeclarationSequenceCommand */
/* class DeclarationDefinitionCommand */
@@ -500,6 +544,10 @@ Command* DeclareFunctionCommand::clone() const {
return new DeclareFunctionCommand(d_symbol, d_func, d_type);
}
+std::string DeclareFunctionCommand::getCommandName() const throw() {
+ return "declare-fun";
+}
+
/* class DeclareTypeCommand */
DeclareTypeCommand::DeclareTypeCommand(const std::string& id, size_t arity, Type t) throw() :
@@ -530,6 +578,10 @@ Command* DeclareTypeCommand::clone() const {
return new DeclareTypeCommand(d_symbol, d_arity, d_type);
}
+std::string DeclareTypeCommand::getCommandName() const throw() {
+ return "declare-sort";
+}
+
/* class DefineTypeCommand */
DefineTypeCommand::DefineTypeCommand(const std::string& id,
@@ -571,6 +623,10 @@ Command* DefineTypeCommand::clone() const {
return new DefineTypeCommand(d_symbol, d_params, d_type);
}
+std::string DefineTypeCommand::getCommandName() const throw() {
+ return "define-sort";
+}
+
/* class DefineFunctionCommand */
DefineFunctionCommand::DefineFunctionCommand(const std::string& id,
@@ -616,7 +672,7 @@ void DefineFunctionCommand::invoke(SmtEngine* smtEngine) throw() {
}
Command* DefineFunctionCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- Expr func = d_func.exportTo(exprManager, variableMap);
+ Expr func = d_func.exportTo(exprManager, variableMap, /* flags = */ ExprManager::VAR_FLAG_DEFINED);
vector<Expr> formals;
transform(d_formals.begin(), d_formals.end(), back_inserter(formals),
ExportTransformer(exprManager, variableMap));
@@ -628,6 +684,10 @@ Command* DefineFunctionCommand::clone() const {
return new DefineFunctionCommand(d_symbol, d_func, d_formals, d_formula);
}
+std::string DefineFunctionCommand::getCommandName() const throw() {
+ return "define-fun";
+}
+
/* class DefineNamedFunctionCommand */
DefineNamedFunctionCommand::DefineNamedFunctionCommand(const std::string& id,
@@ -695,6 +755,10 @@ Command* SetUserAttributeCommand::clone() const{
return new SetUserAttributeCommand( d_attr, d_expr );
}
+std::string SetUserAttributeCommand::getCommandName() const throw() {
+ return "set-user-attribute";
+}
+
/* class SimplifyCommand */
SimplifyCommand::SimplifyCommand(Expr term) throw() :
@@ -718,9 +782,9 @@ Expr SimplifyCommand::getResult() const throw() {
return d_result;
}
-void SimplifyCommand::printResult(std::ostream& out) const throw() {
+void SimplifyCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -738,6 +802,10 @@ Command* SimplifyCommand::clone() const {
return c;
}
+std::string SimplifyCommand::getCommandName() const throw() {
+ return "simplify";
+}
+
/* class ExpandDefinitionsCommand */
ExpandDefinitionsCommand::ExpandDefinitionsCommand(Expr term) throw() :
@@ -757,9 +825,9 @@ Expr ExpandDefinitionsCommand::getResult() const throw() {
return d_result;
}
-void ExpandDefinitionsCommand::printResult(std::ostream& out) const throw() {
+void ExpandDefinitionsCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -777,6 +845,10 @@ Command* ExpandDefinitionsCommand::clone() const {
return c;
}
+std::string ExpandDefinitionsCommand::getCommandName() const throw() {
+ return "expand-definitions";
+}
+
/* class GetValueCommand */
GetValueCommand::GetValueCommand(Expr term) throw() :
@@ -795,17 +867,17 @@ const std::vector<Expr>& GetValueCommand::getTerms() const throw() {
void GetValueCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- vector<Node> result;
- NodeManager* nm = NodeManager::fromExprManager(smtEngine->getExprManager());
+ vector<Expr> result;
+ ExprManager* em = smtEngine->getExprManager();
+ NodeManager* nm = NodeManager::fromExprManager(em);
for(std::vector<Expr>::const_iterator i = d_terms.begin(); i != d_terms.end(); ++i) {
Assert(nm == NodeManager::fromExprManager((*i).getExprManager()));
smt::SmtScope scope(smtEngine);
Node request = Node::fromExpr(options::expandDefinitions() ? smtEngine->expandDefinitions(*i) : *i);
Node value = Node::fromExpr(smtEngine->getValue(*i));
- result.push_back(nm->mkNode(kind::SEXPR, request, value));
+ result.push_back(nm->mkNode(kind::SEXPR, request, value).toExpr());
}
- Node n = nm->mkNode(kind::SEXPR, result);
- d_result = nm->toExpr(n);
+ d_result = em->mkExpr(kind::SEXPR, result);
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
@@ -816,9 +888,9 @@ Expr GetValueCommand::getResult() const throw() {
return d_result;
}
-void GetValueCommand::printResult(std::ostream& out) const throw() {
+void GetValueCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
Expr::dag::Scope scope(out, false);
out << d_result << endl;
@@ -841,6 +913,10 @@ Command* GetValueCommand::clone() const {
return c;
}
+std::string GetValueCommand::getCommandName() const throw() {
+ return "get-value";
+}
+
/* class GetAssignmentCommand */
GetAssignmentCommand::GetAssignmentCommand() throw() {
@@ -859,9 +935,9 @@ SExpr GetAssignmentCommand::getResult() const throw() {
return d_result;
}
-void GetAssignmentCommand::printResult(std::ostream& out) const throw() {
+void GetAssignmentCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -879,6 +955,10 @@ Command* GetAssignmentCommand::clone() const {
return c;
}
+std::string GetAssignmentCommand::getCommandName() const throw() {
+ return "get-assignment";
+}
+
/* class GetModelCommand */
GetModelCommand::GetModelCommand() throw() {
@@ -900,9 +980,9 @@ Model* GetModelCommand::getResult() const throw() {
}
*/
-void GetModelCommand::printResult(std::ostream& out) const throw() {
+void GetModelCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << *d_result;
}
@@ -922,6 +1002,10 @@ Command* GetModelCommand::clone() const {
return c;
}
+std::string GetModelCommand::getCommandName() const throw() {
+ return "get-model";
+}
+
/* class GetProofCommand */
GetProofCommand::GetProofCommand() throw() {
@@ -940,9 +1024,9 @@ Proof* GetProofCommand::getResult() const throw() {
return d_result;
}
-void GetProofCommand::printResult(std::ostream& out) const throw() {
+void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
d_result->toStream(out);
}
@@ -960,6 +1044,10 @@ Command* GetProofCommand::clone() const {
return c;
}
+std::string GetProofCommand::getCommandName() const throw() {
+ return "get-proof";
+}
+
/* class GetUnsatCoreCommand */
GetUnsatCoreCommand::GetUnsatCoreCommand() throw() {
@@ -977,9 +1065,9 @@ void GetUnsatCoreCommand::invoke(SmtEngine* smtEngine) throw() {
d_commandStatus = new CommandUnsupported();
}
-void GetUnsatCoreCommand::printResult(std::ostream& out) const throw() {
+void GetUnsatCoreCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
//do nothing -- unsat cores not yet supported
// d_result->toStream(out);
@@ -998,6 +1086,10 @@ Command* GetUnsatCoreCommand::clone() const {
return c;
}
+std::string GetUnsatCoreCommand::getCommandName() const throw() {
+ return "get-unsat-core";
+}
+
/* class GetAssertionsCommand */
GetAssertionsCommand::GetAssertionsCommand() throw() {
@@ -1021,9 +1113,9 @@ std::string GetAssertionsCommand::getResult() const throw() {
return d_result;
}
-void GetAssertionsCommand::printResult(std::ostream& out) const throw() {
+void GetAssertionsCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result;
}
@@ -1041,6 +1133,10 @@ Command* GetAssertionsCommand::clone() const {
return c;
}
+std::string GetAssertionsCommand::getCommandName() const throw() {
+ return "get-assertions";
+}
+
/* class SetBenchmarkStatusCommand */
SetBenchmarkStatusCommand::SetBenchmarkStatusCommand(BenchmarkStatus status) throw() :
@@ -1071,6 +1167,10 @@ Command* SetBenchmarkStatusCommand::clone() const {
return new SetBenchmarkStatusCommand(d_status);
}
+std::string SetBenchmarkStatusCommand::getCommandName() const throw() {
+ return "set-info";
+}
+
/* class SetBenchmarkLogicCommand */
SetBenchmarkLogicCommand::SetBenchmarkLogicCommand(std::string logic) throw() :
@@ -1098,6 +1198,10 @@ Command* SetBenchmarkLogicCommand::clone() const {
return new SetBenchmarkLogicCommand(d_logic);
}
+std::string SetBenchmarkLogicCommand::getCommandName() const throw() {
+ return "set-logic";
+}
+
/* class SetInfoCommand */
SetInfoCommand::SetInfoCommand(std::string flag, const SExpr& sexpr) throw() :
@@ -1118,7 +1222,8 @@ void SetInfoCommand::invoke(SmtEngine* smtEngine) throw() {
smtEngine->setInfo(d_flag, d_sexpr);
d_commandStatus = CommandSuccess::instance();
} catch(UnrecognizedOptionException&) {
- d_commandStatus = new CommandUnsupported();
+ // As per SMT-LIB spec, silently accept unknown set-info keys
+ d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
}
@@ -1132,6 +1237,10 @@ Command* SetInfoCommand::clone() const {
return new SetInfoCommand(d_flag, d_sexpr);
}
+std::string SetInfoCommand::getCommandName() const throw() {
+ return "set-info";
+}
+
/* class GetInfoCommand */
GetInfoCommand::GetInfoCommand(std::string flag) throw() :
@@ -1162,9 +1271,9 @@ std::string GetInfoCommand::getResult() const throw() {
return d_result;
}
-void GetInfoCommand::printResult(std::ostream& out) const throw() {
+void GetInfoCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else if(d_result != "") {
out << d_result << endl;
}
@@ -1182,6 +1291,10 @@ Command* GetInfoCommand::clone() const {
return c;
}
+std::string GetInfoCommand::getCommandName() const throw() {
+ return "get-info";
+}
+
/* class SetOptionCommand */
SetOptionCommand::SetOptionCommand(std::string flag, const SExpr& sexpr) throw() :
@@ -1216,6 +1329,10 @@ Command* SetOptionCommand::clone() const {
return new SetOptionCommand(d_flag, d_sexpr);
}
+std::string SetOptionCommand::getCommandName() const throw() {
+ return "set-option";
+}
+
/* class GetOptionCommand */
GetOptionCommand::GetOptionCommand(std::string flag) throw() :
@@ -1228,11 +1345,9 @@ std::string GetOptionCommand::getFlag() const throw() {
void GetOptionCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- vector<SExpr> v;
- v.push_back(SExpr(SExpr::Keyword(string(":") + d_flag)));
- v.push_back(smtEngine->getOption(d_flag));
+ SExpr res = smtEngine->getOption(d_flag);
stringstream ss;
- ss << SExpr(v);
+ ss << res;
d_result = ss.str();
d_commandStatus = CommandSuccess::instance();
} catch(UnrecognizedOptionException&) {
@@ -1246,9 +1361,9 @@ std::string GetOptionCommand::getResult() const throw() {
return d_result;
}
-void GetOptionCommand::printResult(std::ostream& out) const throw() {
+void GetOptionCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else if(d_result != "") {
out << d_result << endl;
}
@@ -1266,6 +1381,10 @@ Command* GetOptionCommand::clone() const {
return c;
}
+std::string GetOptionCommand::getCommandName() const throw() {
+ return "get-option";
+}
+
/* class DatatypeDeclarationCommand */
DatatypeDeclarationCommand::DatatypeDeclarationCommand(const DatatypeType& datatype) throw() :
@@ -1295,6 +1414,10 @@ Command* DatatypeDeclarationCommand::clone() const {
return new DatatypeDeclarationCommand(d_datatypes);
}
+std::string DatatypeDeclarationCommand::getCommandName() const throw() {
+ return "declare-datatypes";
+}
+
/* class RewriteRuleCommand */
RewriteRuleCommand::RewriteRuleCommand(const std::vector<Expr>& vars,
@@ -1395,6 +1518,10 @@ Command* RewriteRuleCommand::clone() const {
return new RewriteRuleCommand(d_vars, d_guards, d_head, d_body, d_triggers);
}
+std::string RewriteRuleCommand::getCommandName() const throw() {
+ return "rewrite-rule";
+}
+
/* class PropagateRuleCommand */
PropagateRuleCommand::PropagateRuleCommand(const std::vector<Expr>& vars,
@@ -1512,6 +1639,10 @@ Command* PropagateRuleCommand::clone() const {
return new PropagateRuleCommand(d_vars, d_guards, d_heads, d_body, d_triggers);
}
+std::string PropagateRuleCommand::getCommandName() const throw() {
+ return "propagate-rule";
+}
+
/* output stream insertion operator for benchmark statuses */
std::ostream& operator<<(std::ostream& out,
BenchmarkStatus status) throw() {
diff --git a/src/expr/command.h b/src/expr/command.h
index 38a8b1efa..a3d58e5dd 100644
--- a/src/expr/command.h
+++ b/src/expr/command.h
@@ -215,6 +215,8 @@ public:
std::string toString() const throw();
+ virtual std::string getCommandName() const throw() = 0;
+
/**
* If false, instruct this Command not to print a success message.
*/
@@ -240,7 +242,7 @@ public:
/** Get the command status (it's NULL if we haven't run yet). */
const CommandStatus* getCommandStatus() const throw() { return d_commandStatus; }
- virtual void printResult(std::ostream& out) const throw();
+ virtual void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
/**
* Maps this Command into one for a different ExprManager, using
@@ -287,6 +289,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class EmptyCommand */
class CVC4_PUBLIC EchoCommand : public Command {
@@ -300,6 +303,7 @@ public:
void invoke(SmtEngine* smtEngine, std::ostream& out) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class EchoCommand */
class CVC4_PUBLIC AssertCommand : public Command {
@@ -312,6 +316,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class AssertCommand */
class CVC4_PUBLIC PushCommand : public Command {
@@ -320,6 +325,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PushCommand */
class CVC4_PUBLIC PopCommand : public Command {
@@ -328,6 +334,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PopCommand */
class CVC4_PUBLIC DeclarationDefinitionCommand : public Command {
@@ -352,6 +359,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DeclareFunctionCommand */
class CVC4_PUBLIC DeclareTypeCommand : public DeclarationDefinitionCommand {
@@ -366,6 +374,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DeclareTypeCommand */
class CVC4_PUBLIC DefineTypeCommand : public DeclarationDefinitionCommand {
@@ -381,6 +390,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DefineTypeCommand */
class CVC4_PUBLIC DefineFunctionCommand : public DeclarationDefinitionCommand {
@@ -399,6 +409,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DefineFunctionCommand */
/**
@@ -433,6 +444,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetUserAttributeCommand */
@@ -447,9 +459,10 @@ public:
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
Result getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CheckSatCommand */
class CVC4_PUBLIC QueryCommand : public Command {
@@ -462,9 +475,10 @@ public:
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
Result getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class QueryCommand */
// this is TRANSFORM in the CVC presentation language
@@ -478,9 +492,10 @@ public:
Expr getTerm() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SimplifyCommand */
class CVC4_PUBLIC ExpandDefinitionsCommand : public Command {
@@ -493,9 +508,10 @@ public:
Expr getTerm() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class ExpandDefinitionsCommand */
class CVC4_PUBLIC GetValueCommand : public Command {
@@ -509,9 +525,10 @@ public:
const std::vector<Expr>& getTerms() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetValueCommand */
class CVC4_PUBLIC GetAssignmentCommand : public Command {
@@ -522,9 +539,10 @@ public:
~GetAssignmentCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
SExpr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetAssignmentCommand */
class CVC4_PUBLIC GetModelCommand : public Command {
@@ -537,9 +555,10 @@ public:
void invoke(SmtEngine* smtEngine) throw();
// Model is private to the library -- for now
//Model* getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetModelCommand */
class CVC4_PUBLIC GetProofCommand : public Command {
@@ -550,9 +569,10 @@ public:
~GetProofCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Proof* getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetProofCommand */
class CVC4_PUBLIC GetUnsatCoreCommand : public Command {
@@ -562,9 +582,10 @@ public:
GetUnsatCoreCommand() throw();
~GetUnsatCoreCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetUnsatCoreCommand */
class CVC4_PUBLIC GetAssertionsCommand : public Command {
@@ -575,9 +596,10 @@ public:
~GetAssertionsCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetAssertionsCommand */
class CVC4_PUBLIC SetBenchmarkStatusCommand : public Command {
@@ -590,6 +612,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetBenchmarkStatusCommand */
class CVC4_PUBLIC SetBenchmarkLogicCommand : public Command {
@@ -602,6 +625,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetBenchmarkLogicCommand */
class CVC4_PUBLIC SetInfoCommand : public Command {
@@ -616,6 +640,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetInfoCommand */
class CVC4_PUBLIC GetInfoCommand : public Command {
@@ -628,9 +653,10 @@ public:
std::string getFlag() const throw();
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetInfoCommand */
class CVC4_PUBLIC SetOptionCommand : public Command {
@@ -645,6 +671,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetOptionCommand */
class CVC4_PUBLIC GetOptionCommand : public Command {
@@ -657,9 +684,10 @@ public:
std::string getFlag() const throw();
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetOptionCommand */
class CVC4_PUBLIC DatatypeDeclarationCommand : public Command {
@@ -673,6 +701,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DatatypeDeclarationCommand */
class CVC4_PUBLIC RewriteRuleCommand : public Command {
@@ -703,6 +732,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class RewriteRuleCommand */
class CVC4_PUBLIC PropagateRuleCommand : public Command {
@@ -738,6 +768,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PropagateRuleCommand */
@@ -748,6 +779,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class QuitCommand */
class CVC4_PUBLIC CommentCommand : public Command {
@@ -759,6 +791,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CommentCommand */
class CVC4_PUBLIC CommandSequence : public Command {
@@ -788,6 +821,7 @@ public:
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CommandSequence */
class CVC4_PUBLIC DeclarationSequence : public CommandSequence {
diff --git a/src/expr/expr.i b/src/expr/expr.i
index 977345a63..c649a5ebb 100644
--- a/src/expr/expr.i
+++ b/src/expr/expr.i
@@ -9,7 +9,11 @@
#endif /* SWIGJAVA */
%}
+#ifdef SWIGPYTHON
+%rename(doApply) CVC4::ExprHashFunction::operator()(CVC4::Expr) const;
+#else /* SWIGPYTHON */
%rename(apply) CVC4::ExprHashFunction::operator()(CVC4::Expr) const;
+#endif /* SWIGPYTHON */
%ignore CVC4::operator<<(std::ostream&, const Expr&);
%ignore CVC4::operator<<(std::ostream&, const TypeCheckingException&);
diff --git a/src/expr/expr_manager.i b/src/expr/expr_manager.i
index a386af5ee..a2ff0337a 100644
--- a/src/expr/expr_manager.i
+++ b/src/expr/expr_manager.i
@@ -34,6 +34,10 @@
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::UninterpretedConstant>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::kind::Kind_t>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Datatype>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::TupleSelect>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::TupleUpdate>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::RecordSelect>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::RecordUpdate>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Rational>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::BitVector>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Predicate>;
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 524bc2095..d87c498e6 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -304,8 +304,8 @@ Expr ExprManager::mkExpr(Kind kind, Expr child1, const std::vector<Expr>& otherC
Expr ExprManager::mkExpr(Expr opExpr) {
const unsigned n = 0;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -323,8 +323,8 @@ Expr ExprManager::mkExpr(Expr opExpr) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1) {
const unsigned n = 1;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -342,8 +342,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2) {
const unsigned n = 2;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -363,8 +363,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3) {
const unsigned n = 3;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -386,8 +386,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr child4) {
const unsigned n = 4;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -410,8 +410,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr child4, Expr child5) {
const unsigned n = 5;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -434,8 +434,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr ExprManager::mkExpr(Expr opExpr, const std::vector<Expr>& children) {
const unsigned n = children.size();
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -509,7 +509,6 @@ FunctionType ExprManager::mkPredicateType(const std::vector<Type>& sorts) {
TupleType ExprManager::mkTupleType(const std::vector<Type>& types) {
NodeManagerScope nms(d_nodeManager);
- Assert( types.size() >= 1 );
std::vector<TypeNode> typeNodes;
for (unsigned i = 0, i_end = types.size(); i < i_end; ++ i) {
typeNodes.push_back(*types[i].d_typeNode);
@@ -719,9 +718,9 @@ TesterType ExprManager::mkTesterType(Type domain) const {
return Type(d_nodeManager, new TypeNode(d_nodeManager->mkTesterType(*domain.d_typeNode)));
}
-SortType ExprManager::mkSort(const std::string& name) const {
+SortType ExprManager::mkSort(const std::string& name, uint32_t flags) const {
NodeManagerScope nms(d_nodeManager);
- return SortType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkSort(name))));
+ return SortType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkSort(name, flags))));
}
SortConstructorType ExprManager::mkSortConstructor(const std::string& name,
@@ -805,20 +804,20 @@ Type ExprManager::getType(Expr e, bool check) throw (TypeCheckingException) {
return t;
}
-Expr ExprManager::mkVar(const std::string& name, Type type, bool isGlobal) {
+Expr ExprManager::mkVar(const std::string& name, Type type, uint32_t flags) {
Assert(NodeManager::currentNM() == NULL, "ExprManager::mkVar() should only be called externally, not from within CVC4 code. Please use mkSkolem().");
NodeManagerScope nms(d_nodeManager);
- Node* n = d_nodeManager->mkVarPtr(name, *type.d_typeNode, isGlobal);
+ Node* n = d_nodeManager->mkVarPtr(name, *type.d_typeNode, flags);
Debug("nm") << "set " << name << " on " << *n << std::endl;
INC_STAT_VAR(type, false);
return Expr(this, n);
}
-Expr ExprManager::mkVar(Type type, bool isGlobal) {
+Expr ExprManager::mkVar(Type type, uint32_t flags) {
Assert(NodeManager::currentNM() == NULL, "ExprManager::mkVar() should only be called externally, not from within CVC4 code. Please use mkSkolem().");
NodeManagerScope nms(d_nodeManager);
INC_STAT_VAR(type, false);
- return Expr(this, d_nodeManager->mkVarPtr(*type.d_typeNode, isGlobal));
+ return Expr(this, d_nodeManager->mkVarPtr(*type.d_typeNode, flags));
}
Expr ExprManager::mkBoundVar(const std::string& name, Type type) {
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index fd81c9bf8..3f0ec2f9c 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -430,8 +430,14 @@ public:
/** Make a type representing a tester with the given parameterization. */
TesterType mkTesterType(Type domain) const;
+ /** Bits for use in mkSort() flags. */
+ enum {
+ SORT_FLAG_NONE = 0,
+ SORT_FLAG_PLACEHOLDER = 1
+ };/* enum */
+
/** Make a new sort with the given name. */
- SortType mkSort(const std::string& name) const;
+ SortType mkSort(const std::string& name, uint32_t flags = SORT_FLAG_NONE) const;
/** Make a sort constructor from a name and arity. */
SortConstructorType mkSortConstructor(const std::string& name,
@@ -468,10 +474,82 @@ public:
Type getType(Expr e, bool check = false)
throw(TypeCheckingException);
- // variables are special, because duplicates are permitted
- Expr mkVar(const std::string& name, Type type, bool isGlobal = false);
- Expr mkVar(Type type, bool isGlobal = false);
+ /** Bits for use in mkVar() flags. */
+ enum {
+ VAR_FLAG_NONE = 0,
+ VAR_FLAG_GLOBAL = 1,
+ VAR_FLAG_DEFINED = 2
+ };/* enum */
+
+ /**
+ * Create a new, fresh variable. This variable is guaranteed to be
+ * distinct from every variable thus far in the ExprManager, even
+ * if it shares a name with another; this is to support any kind of
+ * scoping policy on top of ExprManager. The SymbolTable class
+ * can be used to store and lookup symbols by name, if desired.
+ *
+ * @param name a name to associate to the fresh new variable
+ * @param type the type for the new variable
+ * @param flags - VAR_FLAG_NONE - no flags;
+ * VAR_FLAG_GLOBAL - whether this variable is to be
+ * considered "global" or not. Note that this information isn't
+ * used by the ExprManager, but is passed on to the ExprManager's
+ * event subscribers like the model-building service; if isGlobal
+ * is true, this newly-created variable will still available in
+ * models generated after an intervening pop.
+ * VAR_FLAG_DEFINED - if this is to be a "defined" symbol, e.g., for
+ * use with SmtEngine::defineFunction(). This keeps a declaration
+ * from being emitted in API dumps (since a subsequent definition is
+ * expected to be dumped instead).
+ */
+ Expr mkVar(const std::string& name, Type type, uint32_t flags = VAR_FLAG_NONE);
+
+ /**
+ * Create a (nameless) new, fresh variable. This variable is guaranteed
+ * to be distinct from every variable thus far in the ExprManager.
+ *
+ * @param type the type for the new variable
+ * @param flags - VAR_FLAG_GLOBAL - whether this variable is to be considered "global"
+ * or not. Note that this information isn't used by the ExprManager,
+ * but is passed on to the ExprManager's event subscribers like the
+ * model-building service; if isGlobal is true, this newly-created
+ * variable will still available in models generated after an
+ * intervening pop.
+ */
+ Expr mkVar(Type type, uint32_t flags = VAR_FLAG_NONE);
+
+ /**
+ * Create a new, fresh variable for use in a binder expression
+ * (the BOUND_VAR_LIST of a FORALL, EXISTS, or LAMBDA). It is
+ * an error for this bound variable to exist outside of a binder,
+ * and it should also only be used in a single binder expression.
+ * That is, two distinct FORALL expressions should use entirely
+ * disjoint sets of bound variables (however, a single FORALL
+ * expression can be used in multiple places in a formula without
+ * a problem). This newly-created bound variable is guaranteed to
+ * be distinct from every variable thus far in the ExprManager, even
+ * if it shares a name with another; this is to support any kind of
+ * scoping policy on top of ExprManager. The SymbolTable class
+ * can be used to store and lookup symbols by name, if desired.
+ *
+ * @param name a name to associate to the fresh new bound variable
+ * @param type the type for the new bound variable
+ */
Expr mkBoundVar(const std::string& name, Type type);
+
+ /**
+ * Create a (nameless) new, fresh variable for use in a binder
+ * expression (the BOUND_VAR_LIST of a FORALL, EXISTS, or LAMBDA).
+ * It is an error for this bound variable to exist outside of a
+ * binder, and it should also only be used in a single binder
+ * expression. That is, two distinct FORALL expressions should use
+ * entirely disjoint sets of bound variables (however, a single FORALL
+ * expression can be used in multiple places in a formula without
+ * a problem). This newly-created bound variable is guaranteed to
+ * be distinct from every variable thus far in the ExprManager.
+ *
+ * @param type the type for the new bound variable
+ */
Expr mkBoundVar(Type type);
/** Get a reference to the statistics registry for this ExprManager */
diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp
index 7e809ed62..ad9ec49ac 100644
--- a/src/expr/expr_template.cpp
+++ b/src/expr/expr_template.cpp
@@ -115,7 +115,7 @@ namespace expr {
static Node exportConstant(TNode n, NodeManager* to);
-Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap) {
+Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags) {
if(n.isNull()) return Node::null();
if(theory::kindToTheoryId(n.getKind()) == theory::THEORY_DATATYPES) {
throw ExportUnsupportedException
@@ -146,7 +146,7 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
bool isGlobal;
Node::fromExpr(from_e).getAttribute(GlobalVarAttr(), isGlobal);
NodeManagerScope nullScope(NULL);
- to_e = to->mkVar(name, type, isGlobal);// FIXME thread safety
+ to_e = to->mkVar(name, type, isGlobal ? ExprManager::VAR_FLAG_GLOBAL : flags);// FIXME thread safety
} else if(n.getKind() == kind::SKOLEM) {
// skolems are only available at the Node level (not the Expr level)
TypeNode typeNode = TypeNode::fromType(type);
@@ -178,13 +178,13 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
Debug("export") << "+ parameterized, op is " << n.getOperator() << std::endl;
children.reserve(n.getNumChildren() + 1);
- children.push_back(exportInternal(n.getOperator(), from, to, vmap));
+ children.push_back(exportInternal(n.getOperator(), from, to, vmap, flags));
} else {
children.reserve(n.getNumChildren());
}
for(TNode::iterator i = n.begin(), i_end = n.end(); i != i_end; ++i) {
Debug("export") << "+ child: " << *i << std::endl;
- children.push_back(exportInternal(*i, from, to, vmap));
+ children.push_back(exportInternal(*i, from, to, vmap, flags));
}
if(Debug.isOn("export")) {
ExprManagerScope ems(*to);
@@ -199,11 +199,12 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
}/* CVC4::expr namespace */
-Expr Expr::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) const {
+Expr Expr::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap,
+ uint32_t flags /* = 0 */) const {
Assert(d_exprManager != exprManager,
"No sense in cloning an Expr in the same ExprManager");
ExprManagerScope ems(*this);
- return Expr(exprManager, new Node(expr::exportInternal(*d_node, d_exprManager, exprManager, variableMap)));
+ return Expr(exprManager, new Node(expr::exportInternal(*d_node, d_exprManager, exprManager, variableMap, flags)));
}
Expr& Expr::operator=(const Expr& e) {
diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h
index 7772de81e..e262fada8 100644
--- a/src/expr/expr_template.h
+++ b/src/expr/expr_template.h
@@ -81,7 +81,7 @@ namespace expr {
class CVC4_PUBLIC ExprDag;
class CVC4_PUBLIC ExprSetLanguage;
- NodeTemplate<true> exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ NodeTemplate<true> exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
}/* CVC4::expr namespace */
/**
@@ -510,7 +510,7 @@ public:
* variableMap for the translation and extending it with any new
* mappings.
*/
- Expr exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) const;
+ Expr exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap, uint32_t flags = 0) const;
/**
* IOStream manipulator to set the maximum depth of Exprs when
@@ -591,7 +591,7 @@ private:
friend class TypeCheckingException;
friend class expr::pickle::Pickler;
friend class prop::TheoryProxy;
- friend NodeTemplate<true> expr::exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ friend NodeTemplate<true> expr::exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
friend std::ostream& CVC4::operator<<(std::ostream& out, const Expr& e);
template <bool ref_count> friend class NodeTemplate;
diff --git a/src/expr/metakind_template.h b/src/expr/metakind_template.h
index 22d7baac3..93cebe00a 100644
--- a/src/expr/metakind_template.h
+++ b/src/expr/metakind_template.h
@@ -126,18 +126,6 @@ ${metakind_kinds}
return metaKinds[k + 1];
}/* metaKindOf(k) */
-/**
- * Map a kind of the operator to the kind of the enclosing expression. For
- * example, since the kind of functions is just VARIABLE, it should map
- * VARIABLE to APPLY_UF.
- */
-static inline Kind operatorKindToKind(Kind k) {
- switch (k) {
-${metakind_operatorKinds}
- default:
- return kind::UNDEFINED_KIND; /* LAST_KIND */
- };
-}
}/* CVC4::kind namespace */
namespace expr {
@@ -282,6 +270,13 @@ inline void NodeValueConstPrinter::toStream(std::ostream& out, TNode n) {
toStream(out, n.d_nv);
}
+// The reinterpret_cast of d_children to various constant payload types
+// in deleteNodeValueConstant(), below, can flag a "strict aliasing"
+// warning; it should actually be okay, because we never access the
+// embedded constant as a NodeValue* child, and never access an embedded
+// NodeValue* child as a constant.
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+
/**
* Cleanup to be performed when a NodeValue zombie is collected, and
* it has CONSTANT metakind. This calls the destructor for the underlying
@@ -301,6 +296,9 @@ ${metakind_constDeleters}
}
}
+// re-enable the strict-aliasing warning
+# pragma GCC diagnostic warning "-Wstrict-aliasing"
+
inline unsigned getLowerBoundForKind(::CVC4::Kind k) {
static const unsigned lbs[] = {
0, /* NULL_EXPR */
@@ -324,9 +322,30 @@ ${metakind_ubchildren}
}
}/* CVC4::kind::metakind namespace */
+
+/**
+ * Map a kind of the operator to the kind of the enclosing expression. For
+ * example, since the kind of functions is just VARIABLE, it should map
+ * VARIABLE to APPLY_UF.
+ */
+static inline Kind operatorToKind(::CVC4::expr::NodeValue* nv) {
+ if(nv->getKind() == kind::BUILTIN) {
+ return nv->getConst<Kind>();
+ } else if(nv->getKind() == kind::LAMBDA) {
+ return kind::APPLY_UF;
+ }
+
+ switch(Kind k CVC4_UNUSED = nv->getKind()) {
+${metakind_operatorKinds}
+
+ default:
+ return kind::UNDEFINED_KIND; /* LAST_KIND */
+ };
+}
+
}/* CVC4::kind namespace */
-#line 330 "${template}"
+#line 349 "${template}"
namespace theory {
diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind
index d8192e432..7ffe0230b 100755
--- a/src/expr/mkmetakind
+++ b/src/expr/mkmetakind
@@ -303,8 +303,9 @@ struct ConstantMapReverse< ::CVC4::kind::$1 > {
function registerOperatorToKind {
operatorKind=$1
applyKind=$2
- metakind_operatorKinds="${metakind_operatorKinds} case kind::$applyKind: return kind::$operatorKind;
-";
+ metakind_operatorKinds="${metakind_operatorKinds}
+#line $lineno \"$kf\"
+ case kind::$applyKind: return kind::$operatorKind;";
}
function register_metakind {
@@ -381,8 +382,8 @@ while [ $# -gt 0 ]; do
/* from $b */
"
metakind_operatorKinds="${metakind_operatorKinds}
- /* from $b */
-"
+
+ /* from $b */"
source "$kf"
if ! $seen_theory; then
echo "$kf: error: no theory content found in file!" >&2
diff --git a/src/expr/node.h b/src/expr/node.h
index 7003aae87..e6a163a8b 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -182,7 +182,7 @@ class NodeTemplate {
friend class expr::NodeValue;
friend class expr::pickle::PicklerPrivate;
- friend Node expr::exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ friend Node expr::exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
/** A convenient null-valued encapsulated pointer */
static NodeTemplate s_null;
@@ -1094,7 +1094,7 @@ NodeTemplate<ref_count>& NodeTemplate<ref_count>::
operator=(const NodeTemplate& e) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != e.d_nv )) {
+ if(__builtin_expect( ( d_nv != e.d_nv ), true )) {
if(ref_count) {
// shouldn't ever fail
Assert(d_nv->d_rc > 0,
@@ -1118,7 +1118,7 @@ NodeTemplate<ref_count>& NodeTemplate<ref_count>::
operator=(const NodeTemplate<!ref_count>& e) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != e.d_nv )) {
+ if(__builtin_expect( ( d_nv != e.d_nv ), true )) {
if(ref_count) {
// shouldn't ever fail
Assert(d_nv->d_rc > 0, "Node reference count would be negative");
@@ -1337,7 +1337,11 @@ NodeTemplate<ref_count>::substitute(TNode node, TNode replacement,
NodeBuilder<> nb(getKind());
if(getMetaKind() == kind::metakind::PARAMETERIZED) {
// push the operator
- nb << getOperator();
+ if(getOperator() == node) {
+ nb << replacement;
+ } else {
+ nb << getOperator().substitute(node, replacement, cache);
+ }
}
for(const_iterator i = begin(),
iend = end();
diff --git a/src/expr/node_builder.h b/src/expr/node_builder.h
index 773828ccb..64080c275 100644
--- a/src/expr/node_builder.h
+++ b/src/expr/node_builder.h
@@ -228,7 +228,7 @@ class NodeBuilder {
* Internally, this state is represented by d_nv pointing to NULL.
*/
inline bool isUsed() const {
- return EXPECT_FALSE( d_nv == NULL );
+ return __builtin_expect( ( d_nv == NULL ), false );
}
/**
@@ -259,7 +259,7 @@ class NodeBuilder {
* heap-allocated by this class).
*/
inline bool nvIsAllocated() const {
- return EXPECT_FALSE( d_nv != &d_inlineNv ) && EXPECT_TRUE( d_nv != NULL );
+ return __builtin_expect( ( d_nv != &d_inlineNv ), false ) && __builtin_expect(( d_nv != NULL ), true );
}
/**
@@ -267,7 +267,7 @@ class NodeBuilder {
* first.
*/
inline bool nvNeedsToBeAllocated() const {
- return EXPECT_FALSE( d_nv->d_nchildren == d_nvMaxChildren );
+ return __builtin_expect( ( d_nv->d_nchildren == d_nvMaxChildren ), false );
}
/**
@@ -279,7 +279,7 @@ class NodeBuilder {
inline void realloc() {
size_t newSize = 2 * size_t(d_nvMaxChildren);
size_t hardLimit = (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1;
- realloc(EXPECT_FALSE( newSize > hardLimit ) ? hardLimit : newSize);
+ realloc(__builtin_expect( ( newSize > hardLimit ), false ) ? hardLimit : newSize);
}
/**
@@ -297,7 +297,7 @@ class NodeBuilder {
* double-decremented on destruction/clear. Otherwise, do nothing.
*/
inline void allocateNvIfNecessaryForAppend() {
- if(EXPECT_FALSE( nvNeedsToBeAllocated() )) {
+ if(__builtin_expect( ( nvNeedsToBeAllocated() ), false )) {
realloc();
}
}
@@ -331,8 +331,8 @@ class NodeBuilder {
* @throws bad_alloc if the reallocation fails
*/
void crop() {
- if(EXPECT_FALSE( nvIsAllocated() ) &&
- EXPECT_TRUE( d_nvMaxChildren > d_nv->d_nchildren )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false ) &&
+ __builtin_expect( ( d_nvMaxChildren > d_nv->d_nchildren ), true )) {
// Ensure d_nv is not modified on allocation failure
expr::NodeValue* newBlock = (expr::NodeValue*)
std::realloc(d_nv,
@@ -419,9 +419,9 @@ public:
}
inline ~NodeBuilder() {
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
dealloc();
- } else if(EXPECT_FALSE( !isUsed() )) {
+ } else if(__builtin_expect( ( !isUsed() ), false )) {
decrRefCounts();
}
}
@@ -578,7 +578,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -600,7 +600,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -619,7 +619,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -660,6 +660,9 @@ public:
Assert(!isUsed(), "NodeBuilder is one-shot only; "
"attempt to access it after conversion");
Assert(!n.isNull(), "Cannot use NULL Node as a child of a Node");
+ if(n.getKind() == kind::BUILTIN) {
+ return *this << NodeManager::operatorToKind(n);
+ }
allocateNvIfNecessaryForAppend();
expr::NodeValue* nv = n.d_nv;
nv->inc();
@@ -756,9 +759,9 @@ template <unsigned nchild_thresh>
void NodeBuilder<nchild_thresh>::clear(Kind k) {
Assert(k != kind::NULL_EXPR, "illegal Node-building clear kind");
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
dealloc();
- } else if(EXPECT_FALSE( !isUsed() )) {
+ } else if(__builtin_expect( ( !isUsed() ), false )) {
decrRefCounts();
} else {
setUnused();
@@ -783,7 +786,7 @@ void NodeBuilder<nchild_thresh>::realloc(size_t toSize) {
"attempt to realloc() a NodeBuilder to size %u (beyond hard limit of %u)",
toSize, (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1 );
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
// Ensure d_nv is not modified on allocation failure
expr::NodeValue* newBlock = (expr::NodeValue*)
std::realloc(d_nv, sizeof(expr::NodeValue) +
@@ -980,7 +983,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() {
#if 0
// if the kind is PARAMETERIZED, check that the operator is correctly-kinded
Assert(kind::metaKindOf(getKind()) != kind::metakind::PARAMETERIZED ||
- kind::operatorKindToKind(getOperator().getKind()) == getKind(),
+ NodeManager::operatorToKind(getOperator()) == getKind(),
"Attempted to construct a parameterized kind `%s' with "
"incorrectly-kinded operator `%s'",
kind::kindToString(getKind()).c_str(),
@@ -992,7 +995,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() {
// NodeManager pool of Nodes. See implementation notes at the top
// of this file.
- if(EXPECT_TRUE( ! nvIsAllocated() )) {
+ if(__builtin_expect( ( ! nvIsAllocated() ), true )) {
/** Case 1. d_nv points to d_inlineNv: it is the backing store
** allocated "inline" in this NodeBuilder. **/
@@ -1165,7 +1168,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() const {
#if 0
// if the kind is PARAMETERIZED, check that the operator is correctly-kinded
Assert(kind::metaKindOf(getKind()) != kind::metakind::PARAMETERIZED ||
- kind::operatorKindToKind(getOperator().getKind()) == getKind(),
+ NodeManager::operatorToKind(getOperator()) == getKind(),
"Attempted to construct a parameterized kind `%s' with "
"incorrectly-kinded operator `%s'",
kind::kindToString(getKind()).c_str(),
@@ -1177,7 +1180,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() const {
// NodeManager pool of Nodes. See implementation notes at the top
// of this file.
- if(EXPECT_TRUE( ! nvIsAllocated() )) {
+ if(__builtin_expect( ( ! nvIsAllocated() ), true )) {
/** Case 1. d_nv points to d_inlineNv: it is the backing store
** allocated "inline" in this NodeBuilder. **/
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 0c62d31c5..31f6d75d9 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -75,12 +75,12 @@ typedef expr::Attribute<expr::attr::DatatypeRecordTag, TypeNode> DatatypeRecordA
class NodeManagerListener {
public:
virtual ~NodeManagerListener() { }
- virtual void nmNotifyNewSort(TypeNode tn) { }
+ virtual void nmNotifyNewSort(TypeNode tn, uint32_t flags) { }
virtual void nmNotifyNewSortConstructor(TypeNode tn) { }
- virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort) { }
+ virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort, uint32_t flags) { }
virtual void nmNotifyNewDatatypes(const std::vector<DatatypeType>& datatypes) { }
- virtual void nmNotifyNewVar(TNode n, bool isGlobal) { }
- virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) { }
+ virtual void nmNotifyNewVar(TNode n, uint32_t flags) { }
+ virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, uint32_t flags) { }
};/* class NodeManagerListener */
class NodeManager {
@@ -90,8 +90,8 @@ class NodeManager {
friend class expr::TypeChecker;
// friends so they can access mkVar() here, which is private
- friend Expr ExprManager::mkVar(const std::string&, Type, bool isGlobal);
- friend Expr ExprManager::mkVar(Type, bool isGlobal);
+ friend Expr ExprManager::mkVar(const std::string&, Type, uint32_t flags);
+ friend Expr ExprManager::mkVar(Type, uint32_t flags);
// friend so it can access NodeManager's d_listeners and notify clients
friend std::vector<DatatypeType> ExprManager::mkMutualDatatypeTypes(const std::vector<Datatype>&, const std::set<Type>&);
@@ -309,12 +309,12 @@ class NodeManager {
* version of this is private to avoid internal uses of mkVar() from
* within CVC4. Such uses should employ mkSkolem() instead.
*/
- Node mkVar(const std::string& name, const TypeNode& type, bool isGlobal = false);
- Node* mkVarPtr(const std::string& name, const TypeNode& type, bool isGlobal = false);
+ Node mkVar(const std::string& name, const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
+ Node* mkVarPtr(const std::string& name, const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a variable with the given type. */
- Node mkVar(const TypeNode& type, bool isGlobal = false);
- Node* mkVarPtr(const TypeNode& type, bool isGlobal = false);
+ 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:
@@ -353,6 +353,9 @@ public:
d_listeners.erase(elt);
}
+ /** Get a Kind from an operator expression */
+ static inline Kind operatorToKind(TNode n);
+
// general expression-builders
/** Create a node with one child. */
@@ -680,6 +683,9 @@ public:
/** Get the (singleton) type for strings. */
inline TypeNode stringType();
+ /** Get the (singleton) type for RegExp. */
+ inline TypeNode regexpType();
+
/** Get the bound var list type. */
inline TypeNode boundVarListType();
@@ -775,14 +781,15 @@ public:
inline TypeNode mkTesterType(TypeNode domain);
/** Make a new (anonymous) sort of arity 0. */
- inline TypeNode mkSort();
+ inline TypeNode mkSort(uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort with the given name of arity 0. */
- inline TypeNode mkSort(const std::string& name);
+ inline TypeNode mkSort(const std::string& name, uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort by parameterizing the given sort constructor. */
inline TypeNode mkSort(TypeNode constructor,
- const std::vector<TypeNode>& children);
+ const std::vector<TypeNode>& children,
+ uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort with the given name and arity. */
inline TypeNode mkSortConstructor(const std::string& name, size_t arity);
@@ -1026,6 +1033,11 @@ inline TypeNode NodeManager::stringType() {
return TypeNode(mkTypeConst<TypeConstant>(STRING_TYPE));
}
+/** Get the (singleton) type for regexps. */
+inline TypeNode NodeManager::regexpType() {
+ return TypeNode(mkTypeConst<TypeConstant>(REGEXP_TYPE));
+}
+
/** Get the bound var list type. */
inline TypeNode NodeManager::boundVarListType() {
return TypeNode(mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE));
@@ -1087,7 +1099,6 @@ NodeManager::mkPredicateType(const std::vector<TypeNode>& sorts) {
}
inline TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
- Assert(types.size() >= 1);
std::vector<TypeNode> typeNodes;
for (unsigned i = 0; i < types.size(); ++ i) {
CheckArgument(!types[i].isFunctionLike(), types,
@@ -1218,31 +1229,32 @@ inline bool NodeManager::hasOperator(Kind k) {
}
}
-inline TypeNode NodeManager::mkSort() {
+inline TypeNode NodeManager::mkSort(uint32_t flags) {
NodeBuilder<1> nb(this, kind::SORT_TYPE);
Node sortTag = NodeBuilder<0>(this, kind::SORT_TAG);
nb << sortTag;
TypeNode tn = nb.constructTypeNode();
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewSort(tn);
+ (*i)->nmNotifyNewSort(tn, flags);
}
return tn;
}
-inline TypeNode NodeManager::mkSort(const std::string& name) {
+inline TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
NodeBuilder<1> nb(this, kind::SORT_TYPE);
Node sortTag = NodeBuilder<0>(this, kind::SORT_TAG);
nb << sortTag;
TypeNode tn = nb.constructTypeNode();
setAttribute(tn, expr::VarNameAttr(), name);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewSort(tn);
+ (*i)->nmNotifyNewSort(tn, flags);
}
return tn;
}
inline TypeNode NodeManager::mkSort(TypeNode constructor,
- const std::vector<TypeNode>& children) {
+ const std::vector<TypeNode>& children,
+ uint32_t flags) {
Assert(constructor.getKind() == kind::SORT_TYPE &&
constructor.getNumChildren() == 0,
"expected a sort constructor");
@@ -1260,7 +1272,7 @@ inline TypeNode NodeManager::mkSort(TypeNode constructor,
TypeNode type = nb.constructTypeNode();
setAttribute(type, expr::VarNameAttr(), name);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyInstantiateSortConstructor(constructor, type);
+ (*i)->nmNotifyInstantiateSortConstructor(constructor, type, flags);
}
return type;
}
@@ -1280,6 +1292,10 @@ inline TypeNode NodeManager::mkSortConstructor(const std::string& name,
return type;
}
+inline Kind NodeManager::operatorToKind(TNode n) {
+ return kind::operatorToKind(n.d_nv);
+}
+
inline Node NodeManager::mkNode(Kind kind, TNode child1) {
NodeBuilder<1> nb(this, kind);
nb << child1;
@@ -1367,80 +1383,114 @@ inline Node* NodeManager::mkNodePtr(Kind kind,
// for operators
inline Node NodeManager::mkNode(TNode opNode) {
- NodeBuilder<1> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<1> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode) {
- NodeBuilder<1> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<1> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1) {
- NodeBuilder<2> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1;
+ NodeBuilder<2> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1) {
- NodeBuilder<2> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1;
+ NodeBuilder<2> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2) {
- NodeBuilder<3> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2;
+ NodeBuilder<3> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2) {
- NodeBuilder<3> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2;
+ NodeBuilder<3> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3) {
- NodeBuilder<4> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3;
+ NodeBuilder<4> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3) {
- NodeBuilder<4> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3;
+ NodeBuilder<4> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4) {
- NodeBuilder<5> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4;
+ NodeBuilder<5> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4) {
- NodeBuilder<5> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4;
+ NodeBuilder<5> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4, TNode child5) {
- NodeBuilder<6> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4 << child5;
+ NodeBuilder<6> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4 << child5;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4, TNode child5) {
- NodeBuilder<6> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4 << child5;
+ NodeBuilder<6> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4 << child5;
return nb.constructNodePtr();
}
@@ -1449,8 +1499,10 @@ template <bool ref_count>
inline Node NodeManager::mkNode(TNode opNode,
const std::vector<NodeTemplate<ref_count> >&
children) {
- NodeBuilder<> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
nb.append(children);
return nb.constructNode();
}
@@ -1459,8 +1511,10 @@ template <bool ref_count>
inline Node* NodeManager::mkNodePtr(TNode opNode,
const std::vector<NodeTemplate<ref_count> >&
children) {
- NodeBuilder<> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
nb.append(children);
return nb.constructNodePtr();
}
@@ -1487,27 +1541,27 @@ inline TypeNode NodeManager::mkTypeNode(Kind kind,
}
-inline Node NodeManager::mkVar(const std::string& name, const TypeNode& type, bool isGlobal) {
+inline Node NodeManager::mkVar(const std::string& name, const TypeNode& type, uint32_t flags) {
Node n = NodeBuilder<0>(this, kind::VARIABLE);
setAttribute(n, TypeAttr(), type);
setAttribute(n, TypeCheckedAttr(), true);
setAttribute(n, expr::VarNameAttr(), name);
- setAttribute(n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(n, isGlobal);
+ (*i)->nmNotifyNewVar(n, flags);
}
return n;
}
inline Node* NodeManager::mkVarPtr(const std::string& name,
- const TypeNode& type, bool isGlobal) {
+ const TypeNode& type, uint32_t flags) {
Node* n = NodeBuilder<0>(this, kind::VARIABLE).constructNodePtr();
setAttribute(*n, TypeAttr(), type);
setAttribute(*n, TypeCheckedAttr(), true);
setAttribute(*n, expr::VarNameAttr(), name);
- setAttribute(*n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(*n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(*n, isGlobal);
+ (*i)->nmNotifyNewVar(*n, flags);
}
return n;
}
@@ -1525,24 +1579,24 @@ inline Node* NodeManager::mkBoundVarPtr(const std::string& name,
return n;
}
-inline Node NodeManager::mkVar(const TypeNode& type, bool isGlobal) {
+inline Node NodeManager::mkVar(const TypeNode& type, uint32_t flags) {
Node n = NodeBuilder<0>(this, kind::VARIABLE);
setAttribute(n, TypeAttr(), type);
setAttribute(n, TypeCheckedAttr(), true);
- setAttribute(n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(n, isGlobal);
+ (*i)->nmNotifyNewVar(n, flags);
}
return n;
}
-inline Node* NodeManager::mkVarPtr(const TypeNode& type, bool isGlobal) {
+inline Node* NodeManager::mkVarPtr(const TypeNode& type, uint32_t flags) {
Node* n = NodeBuilder<0>(this, kind::VARIABLE).constructNodePtr();
setAttribute(*n, TypeAttr(), type);
setAttribute(*n, TypeCheckedAttr(), true);
- setAttribute(*n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(*n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(*n, isGlobal);
+ (*i)->nmNotifyNewVar(*n, flags);
}
return n;
}
diff --git a/src/expr/node_value.h b/src/expr/node_value.h
index 13fdc6a7f..56ac70c1e 100644
--- a/src/expr/node_value.h
+++ b/src/expr/node_value.h
@@ -299,7 +299,7 @@ private:
RefCountGuard(const NodeValue* nv) :
d_nv(const_cast<NodeValue*>(nv)) {
// inc()
- if(EXPECT_TRUE( d_nv->d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_nv->d_rc < MAX_RC ), true )) {
++d_nv->d_rc;
}
}
@@ -309,7 +309,7 @@ private:
// E.g., this can happen when debugging code calls the print
// routines below. As RefCountGuards are scoped on the stack,
// this should be fine---but not in multithreaded contexts!
- if(EXPECT_TRUE( d_nv->d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_nv->d_rc < MAX_RC ), true )) {
--d_nv->d_rc;
}
}
@@ -400,16 +400,16 @@ inline void NodeValue::inc() {
"NodeValue is currently being deleted "
"and increment is being called on it. Don't Do That!");
// FIXME multithreading
- if(EXPECT_TRUE( d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_rc < MAX_RC ), true )) {
++d_rc;
}
}
inline void NodeValue::dec() {
// FIXME multithreading
- if(EXPECT_TRUE( d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_rc < MAX_RC ), true )) {
--d_rc;
- if(EXPECT_FALSE( d_rc == 0 )) {
+ if(__builtin_expect( ( d_rc == 0 ), false )) {
Assert(NodeManager::currentNM() != NULL,
"No current NodeManager on destruction of NodeValue: "
"maybe a public CVC4 interface function is missing a NodeManagerScope ?");
diff --git a/src/expr/type.cpp b/src/expr/type.cpp
index 71c25bd50..f3cf992ba 100644
--- a/src/expr/type.cpp
+++ b/src/expr/type.cpp
@@ -317,6 +317,10 @@ bool Type::isSubrange() const {
return d_typeNode->isSubrange();
}
+size_t FunctionType::getArity() const {
+ return d_typeNode->getNumChildren() - 1;
+}
+
vector<Type> FunctionType::getArgTypes() const {
NodeManagerScope nms(d_nodeManager);
vector<Type> args;
diff --git a/src/expr/type.h b/src/expr/type.h
index 5e4e86264..3c772d461 100644
--- a/src/expr/type.h
+++ b/src/expr/type.h
@@ -415,6 +415,9 @@ public:
/** Construct from the base type */
FunctionType(const Type& type = Type()) throw(IllegalArgumentException);
+ /** Get the arity of the function type */
+ size_t getArity() const;
+
/** Get the argument types */
std::vector<Type> getArgTypes() const;
diff --git a/src/expr/type.i b/src/expr/type.i
index e227cca23..6394dda67 100644
--- a/src/expr/type.i
+++ b/src/expr/type.i
@@ -2,7 +2,11 @@
#include "expr/type.h"
%}
+#ifdef SWIGPYTHON
+%rename(doApply) CVC4::TypeHashFunction::operator()(const CVC4::Type&) const;
+#else /* SWIGPYTHON */
%rename(apply) CVC4::TypeHashFunction::operator()(const CVC4::Type&) const;
+#endif /* SWIGPYTHON */
%ignore CVC4::operator<<(std::ostream&, const Type&);
diff --git a/src/expr/type_node.cpp b/src/expr/type_node.cpp
index e654b5d71..2fc380224 100644
--- a/src/expr/type_node.cpp
+++ b/src/expr/type_node.cpp
@@ -123,6 +123,15 @@ bool TypeNode::isSubtypeOf(TypeNode t) const {
}
return true;
}
+ if(isFunction()) {
+ // A function is a subtype of another if the args are the same type, and
+ // the return type is a subtype of the other's. This is enough for now
+ // (and it's necessary for model generation, since a Real-valued function
+ // might return a constant Int and thus the model value is typed differently).
+ return t.isFunction() &&
+ getArgTypes() == t.getArgTypes() &&
+ getRangeType().isSubtypeOf(t.getRangeType());
+ }
if(isPredicateSubtype()) {
return getSubtypeParentType().isSubtypeOf(t);
}
@@ -291,7 +300,7 @@ TypeNode TypeNode::leastCommonTypeNode(TypeNode t0, TypeNode t1){
Assert(!t0.isNull());
Assert(!t1.isNull());
- if(EXPECT_TRUE(t0 == t1)) {
+ if(__builtin_expect( (t0 == t1), true )) {
return t0;
} else { // t0 != t1
if(t0.getKind()== kind::TYPE_CONSTANT) {
diff --git a/src/expr/type_node.h b/src/expr/type_node.h
index 35d630a91..145ca2aba 100644
--- a/src/expr/type_node.h
+++ b/src/expr/type_node.h
@@ -554,6 +554,9 @@ public:
/** Get the constituent types of a symbolic expression type */
std::vector<TypeNode> getSExprTypes() const;
+ /** Is this a regexp type */
+ bool isRegExp() const;
+
/** Is this a bit-vector type */
bool isBitVector() const;
@@ -619,7 +622,7 @@ public:
* If this is \top, i.e. there is no inhabited type that contains both,
* a TypeNode such that isNull() is true is returned.
*
- * For more information see: http://church.cims.nyu.edu/wiki/Cvc4_Type_Lattice
+ * For more information see: http://cvc4.cs.nyu.edu/wiki/Cvc4_Type_Lattice
*/
static TypeNode leastCommonTypeNode(TypeNode t0, TypeNode t1);
@@ -770,7 +773,7 @@ inline TypeNode& TypeNode::operator=(const TypeNode& typeNode) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(typeNode.d_nv != NULL,
"Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != typeNode.d_nv )) {
+ if(__builtin_expect( ( d_nv != typeNode.d_nv ), true )) {
d_nv->dec();
d_nv = typeNode.d_nv;
d_nv->inc();
@@ -842,6 +845,12 @@ inline bool TypeNode::isString() const {
getConst<TypeConstant>() == STRING_TYPE;
}
+/** Is this a regexp type */
+inline bool TypeNode::isRegExp() const {
+ return getKind() == kind::TYPE_CONSTANT &&
+ getConst<TypeConstant>() == REGEXP_TYPE;
+}
+
inline bool TypeNode::isArray() const {
return getKind() == kind::ARRAY_TYPE;
}
diff --git a/src/include/cvc4_private_library.h b/src/include/cvc4_private_library.h
index b04160a81..f7fd1b607 100644
--- a/src/include/cvc4_private_library.h
+++ b/src/include/cvc4_private_library.h
@@ -19,7 +19,7 @@
#ifndef __CVC4_PRIVATE_LIBRARY_H
#define __CVC4_PRIVATE_LIBRARY_H
-#if ! (defined(__BUILDING_CVC4LIB) || defined(__BUILDING_CVC4LIB_UNIT_TEST) || defined(__BUILDING_CVC4PARSERLIB) || defined(__BUILDING_CVC4PARSERLIB_UNIT_TEST) || defined(__BUILDING_CVC4DRIVER))
+#if ! (defined(__BUILDING_CVC4LIB) || defined(__BUILDING_CVC4LIB_UNIT_TEST) || defined(__BUILDING_CVC4PARSERLIB) || defined(__BUILDING_CVC4PARSERLIB_UNIT_TEST) || defined(__BUILDING_CVC4COMPATLIB) || defined(__BUILDING_CVC4DRIVER))
# warning A "private library" CVC4 header was included when not building the library, driver, or private unit test code.
#endif /* ! (__BUILDING_CVC4LIB || __BUILDING_CVC4LIB_UNIT_TEST || __BUILDING_CVC4PARSERLIB || __BUILDING_CVC4PARSERLIB_UNIT_TEST || __BUILDING_CVC4DRIVER) */
diff --git a/src/include/cvc4_public.h b/src/include/cvc4_public.h
index b8c30aeef..b7431ce1c 100644
--- a/src/include/cvc4_public.h
+++ b/src/include/cvc4_public.h
@@ -68,7 +68,4 @@
# define CVC4_WARN_UNUSED_RESULT
#endif /* __GNUC__ */
-#define EXPECT_TRUE(x) __builtin_expect( (x), true )
-#define EXPECT_FALSE(x) __builtin_expect( (x), false )
-
#endif /* __CVC4_PUBLIC_H */
diff --git a/src/lib/clock_gettime.h b/src/lib/clock_gettime.h
index 2d3455aed..43c3395a4 100644
--- a/src/lib/clock_gettime.h
+++ b/src/lib/clock_gettime.h
@@ -30,7 +30,7 @@
/* otherwise, we have to define it */
-#ifdef __WIN32__
+#if defined(__WIN32__) && !defined(__WIN64__)
#ifdef __cplusplus
extern "C" {
@@ -45,12 +45,12 @@ struct timespec {
}/* extern "C" */
#endif /* __cplusplus */
-#else /* ! __WIN32__ */
+#else /* !__WIN32__ || __WIN64__ */
/* get timespec from <time.h> */
#include <time.h>
-#endif /* __WIN32__ */
+#endif /* __WIN32__ && !__WIN64__ */
#ifdef __cplusplus
extern "C" {
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index f1742b549..9ee896107 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -19,14 +19,17 @@
#include "main/main.h"
+#include "smt/options.h"
+
namespace CVC4 {
namespace main {
-CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options):
+CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options) :
d_exprMgr(exprMgr),
d_smtEngine(SmtEngine(&exprMgr)),
d_options(options),
- d_stats("driver") {
+ d_stats("driver"),
+ d_result() {
}
bool CommandExecutor::doCommand(Command* cmd)
@@ -56,7 +59,7 @@ bool CommandExecutor::doCommand(Command* cmd)
}
}
-bool CommandExecutor::doCommandSingleton(Command *cmd)
+bool CommandExecutor::doCommandSingleton(Command* cmd)
{
bool status = true;
if(d_options[options::verbosity] >= -1) {
@@ -64,14 +67,27 @@ bool CommandExecutor::doCommandSingleton(Command *cmd)
} else {
status = smtEngineInvoke(&d_smtEngine, cmd, NULL);
}
+ Result res;
+ CheckSatCommand* cs = dynamic_cast<CheckSatCommand*>(cmd);
+ if(cs != NULL) {
+ d_result = res = cs->getResult();
+ }
+ QueryCommand* q = dynamic_cast<QueryCommand*>(cmd);
+ if(q != NULL) {
+ d_result = res = q->getResult();
+ }
+ // dump the model if option is set
+ if( status &&
+ d_options[options::produceModels] &&
+ d_options[options::dumpModels] &&
+ ( res.asSatisfiabilityResult() == Result::SAT ||
+ (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) {
+ Command* gm = new GetModelCommand();
+ status = doCommandSingleton(gm);
+ }
return status;
}
-std::string CommandExecutor::getSmtEngineStatus()
-{
- return d_smtEngine.getInfo("status").getValue();
-}
-
bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out)
{
if(out == NULL) {
diff --git a/src/main/command_executor.h b/src/main/command_executor.h
index f1b8d8f2f..cbc71b075 100644
--- a/src/main/command_executor.h
+++ b/src/main/command_executor.h
@@ -34,6 +34,7 @@ protected:
SmtEngine d_smtEngine;
Options& d_options;
StatisticsRegistry d_stats;
+ Result d_result;
public:
CommandExecutor(ExprManager &exprMgr, Options &options);
@@ -47,7 +48,7 @@ public:
*/
bool doCommand(CVC4::Command* cmd);
- virtual std::string getSmtEngineStatus();
+ Result getResult() const { return d_result; }
StatisticsRegistry& getStatisticsRegistry() {
return d_stats;
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 63f689d48..e58df5699 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -184,7 +184,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
// command
if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
- dynamic_cast<QueryCommand*>(cmd) != NULL) {
+ dynamic_cast<QueryCommand*>(cmd) != NULL) {
mode = 1;
} else if(dynamic_cast<GetValueCommand*>(cmd) != NULL ||
dynamic_cast<GetAssignmentCommand*>(cmd) != NULL ||
@@ -198,6 +198,10 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
mode = 2;
}
+ Debug("portfolio::outputmode") << "Mode is " << mode
+ << "lastWinner is " << d_lastWinner
+ << "d_seq is " << d_seq << std::endl;
+
if(mode == 0) {
d_seq->addCommand(cmd->clone());
Command* cmdExported =
@@ -214,7 +218,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
// We currently don't support changing number of threads for each
// command, but things have been architected in a way so that this
- // can be acheived with not a lot of work
+ // can be achieved without a lot of work.
Command *seqs[d_numThreads];
if(d_lastWinner == 0)
@@ -238,7 +242,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
int(i) == d_lastWinner ?
cmd->exportTo(d_exprMgrs[i], *(d_vmaps[i])) :
d_seq->exportTo(d_exprMgrs[i], *(d_vmaps[i]) );
- }catch(ExportUnsupportedException& e){
+ } catch(ExportUnsupportedException& e) {
if(d_options[options::fallbackSequential]) {
Notice() << "Unsupported theory encountered, switching to sequential mode.";
return CommandExecutor::doCommandSingleton(cmd);
@@ -292,11 +296,11 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
runPortfolio(d_numThreads, smFn, fns,
d_options[options::waitToJoin]);
- d_seq = NULL;
delete d_seq;
d_seq = new CommandSequence();
d_lastWinner = portfolioReturn.first;
+ d_result = d_smts[d_lastWinner]->getStatusOfLastCommand();
if(d_ostringstreams.size() != 0) {
assert(d_numThreads == d_options[options::threads]);
@@ -340,11 +344,6 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
}/* CommandExecutorPortfolio::doCommandSingleton() */
-std::string CommandExecutorPortfolio::getSmtEngineStatus()
-{
- return d_smts[d_lastWinner]->getInfo("status").getValue();
-}
-
void CommandExecutorPortfolio::flushStatistics(std::ostream& out) const {
assert(d_numThreads == d_exprMgrs.size() && d_exprMgrs.size() == d_smts.size());
for(size_t i = 0; i < d_numThreads; ++i) {
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index f57d4f2d7..d42f389c1 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -123,7 +123,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
exit(0);
}
- segvNoSpin = opts[options::segvNoSpin];
+ segvSpin = opts[options::segvSpin];
// If in competition mode, set output stream option to flush immediately
#ifdef CVC4_COMPETITION_MODE
@@ -297,13 +297,13 @@ int runCvc4(int argc, char* argv[], Options& opts) {
opts.set(options::replayStream, NULL);
}
- string result = "unknown";
+ Result result;
if(status) {
- result = pExecutor->getSmtEngineStatus();
+ result = pExecutor->getResult();
- if(result == "sat") {
+ if(result.asSatisfiabilityResult() == Result::SAT) {
returnValue = 10;
- } else if(result == "unsat") {
+ } else if(result.asSatisfiabilityResult() == Result::UNSAT) {
returnValue = 20;
} else {
returnValue = 0;
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
index 3376e9d0b..a8099ca30 100644
--- a/src/main/interactive_shell.cpp
+++ b/src/main/interactive_shell.cpp
@@ -33,6 +33,7 @@
#include "parser/parser_builder.h"
#include "options/options.h"
#include "util/language.h"
+#include "util/output.h"
#include <string.h>
#include <cassert>
@@ -313,7 +314,11 @@ restart:
line += "\n";
goto restart;
} catch(ParserException& pe) {
- d_out << pe << endl;
+ if(d_options[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ d_out << "(error \"" << pe << "\")" << endl;
+ } else {
+ d_out << pe << endl;
+ }
// We can't really clear out the sequence and abort the current line,
// because the parse error might be for the second command on the
// line. The first ones haven't yet been executed by the SmtEngine,
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 7b61b48aa..a4c4b9c0a 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -37,10 +37,12 @@
#include "util/output.h"
#include "util/result.h"
#include "util/statistics.h"
+#include "util/language.h"
using namespace std;
using namespace CVC4;
using namespace CVC4::main;
+using namespace CVC4::language;
/**
* CVC4's main() routine is just an exception-safe wrapper around CVC4.
@@ -64,7 +66,11 @@ int main(int argc, char* argv[]) {
#ifdef CVC4_COMPETITION_MODE
*opts[options::out] << "unknown" << endl;
#endif
- *opts[options::err] << "CVC4 Error:" << endl << e << endl;
+ if(opts[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ *opts[options::err] << "(error \"" << e << "\")" << endl;
+ } else {
+ *opts[options::err] << "CVC4 Error:" << endl << e << endl;
+ }
if(opts[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(*opts[options::err]);
diff --git a/src/main/main.h b/src/main/main.h
index 0180c34d2..154919aa9 100644
--- a/src/main/main.h
+++ b/src/main/main.h
@@ -51,7 +51,7 @@ extern CVC4::TimerStat* pTotalTime;
* Useful for nightly regressions, noninteractive performance runs
* etc. See util.cpp.
*/
-extern bool segvNoSpin;
+extern bool segvSpin;
/** A pointer to the options in play */
extern CVC4_THREADLOCAL(Options*) pOptions;
diff --git a/src/main/options b/src/main/options
index 14a7a9f3f..ba36e43ab 100644
--- a/src/main/options
+++ b/src/main/options
@@ -38,6 +38,10 @@ option fallbackSequential --fallback-sequential bool :default false
option incrementalParallel --incremental-parallel bool :default false :link --incremental
Use parallel solver even in incremental mode (may print 'unknown's at times)
+option segvSpin --segv-spin bool :default false
+ spin on segfault/other crash waiting for gdb
+undocumented-alias --segv-nospin = --no-segv-spin
+
expert-option waitToJoin --wait-to-join bool :default true
wait for other threads to join before quitting
diff --git a/src/main/portfolio.cpp b/src/main/portfolio.cpp
index 263458247..cf8bba1ba 100644
--- a/src/main/portfolio.cpp
+++ b/src/main/portfolio.cpp
@@ -38,6 +38,8 @@ int global_winner;
template<typename S>
void runThread(int thread_id, boost::function<S()> threadFn, S& returnValue)
{
+ /* Uncommment line to delay first thread, useful to unearth errors/debug */
+ // if(thread_id == 0) { sleep(1); }
returnValue = threadFn();
if( mutex_done.try_lock() ) {
diff --git a/src/main/portfolio_util.h b/src/main/portfolio_util.h
index 6f6e2f03b..d22ca07d9 100644
--- a/src/main/portfolio_util.h
+++ b/src/main/portfolio_util.h
@@ -21,6 +21,7 @@
#include "util/channel.h"
#include "util/lemma_input_channel.h"
#include "util/lemma_output_channel.h"
+#include "util/output.h"
#include "main/options.h"
namespace CVC4 {
diff --git a/src/main/util.cpp b/src/main/util.cpp
index 5bd0c9bd4..14ee82613 100644
--- a/src/main/util.cpp
+++ b/src/main/util.cpp
@@ -54,7 +54,7 @@ namespace main {
* Useful for nightly regressions, noninteractive performance runs
* etc.
*/
-bool segvNoSpin = false;
+bool segvSpin = false;
#ifndef __WIN32__
@@ -98,8 +98,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) {
cerr << "Looks like a NULL pointer was dereferenced." << endl;
}
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested, aborting...\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
@@ -133,8 +132,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) {
void ill_handler(int sig, siginfo_t* info, void*) {
#ifdef CVC4_DEBUG
fprintf(stderr, "CVC4 executed an illegal instruction in DEBUG mode.\n");
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested, aborting...\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
@@ -174,8 +172,7 @@ void cvc4unexpected() {
fprintf(stderr, "The exception is:\n%s\n\n",
static_cast<const char*>(CVC4::s_debugLastException));
}
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested.\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
diff --git a/src/options/Makefile.am b/src/options/Makefile.am
index 21988df56..5b0894680 100644
--- a/src/options/Makefile.am
+++ b/src/options/Makefile.am
@@ -23,6 +23,8 @@ OPTIONS_FILES_SRCS = \
../theory/quantifiers/options.h \
../theory/rewriterules/options.cpp \
../theory/rewriterules/options.h \
+ ../theory/strings/options.cpp \
+ ../theory/strings/options.h \
../prop/options.cpp \
../prop/options.h \
../proof/options.cpp \
@@ -36,7 +38,9 @@ OPTIONS_FILES_SRCS = \
../main/options.cpp \
../main/options.h \
../parser/options.cpp \
- ../parser/options.h
+ ../parser/options.h \
+ ../theory/idl/options.cpp \
+ ../theory/idl/options.h
OPTIONS_FILES = \
$(patsubst %.cpp,%,$(filter %.cpp,$(OPTIONS_FILES_SRCS)))
@@ -80,6 +84,8 @@ nodist_liboptions_la_SOURCES = \
../theory/quantifiers/options.h \
../theory/rewriterules/options.cpp \
../theory/rewriterules/options.h \
+ ../theory/strings/options.cpp \
+ ../theory/strings/options.h \
../prop/options.cpp \
../prop/options.h \
../proof/options.cpp \
@@ -93,7 +99,9 @@ nodist_liboptions_la_SOURCES = \
../main/options.cpp \
../main/options.h \
../parser/options.cpp \
- ../parser/options.h
+ ../parser/options.h \
+ ../theory/idl/options.cpp \
+ ../theory/idl/options.h
BUILT_SOURCES = \
exprs-builts \
diff --git a/src/options/base_options b/src/options/base_options
index 71754cca5..a6f24c7f3 100644
--- a/src/options/base_options
+++ b/src/options/base_options
@@ -103,7 +103,7 @@ common-option - -v --verbose void :handler CVC4::options::increaseVerbosity
common-option - -q --quiet void :handler CVC4::options::decreaseVerbosity
decrease verbosity (may be repeated)
-common-option statistics statistics --stats bool
+common-option statistics statistics --stats bool :predicate CVC4::smt::statsEnabledBuild :predicate-include "smt/options_handlers.h"
give statistics on exit
undocumented-alias --statistics = --stats
undocumented-alias --no-statistics = --no-stats
@@ -114,9 +114,6 @@ option parseOnly parse-only --parse-only bool :read-write
option preprocessOnly preprocess-only --preprocess-only bool
exit after preprocessing input
-option segvNoSpin --segv-nospin bool
- don't spin on segfault waiting for gdb
-
option - trace -t --trace=TAG argument :handler CVC4::options::addTraceTag
trace something (e.g. -t pushpop), can repeat
option - debug -d --debug=TAG argument :handler CVC4::options::addDebugTag
diff --git a/src/options/mkoptions b/src/options/mkoptions
index fa6c4c260..d856c7293 100755
--- a/src/options/mkoptions
+++ b/src/options/mkoptions
@@ -73,7 +73,9 @@ options_cpp_template="$1"; shift
all_modules_defaults=
all_modules_short_options=
all_modules_long_options=
+all_modules_smt_options=
all_modules_option_handlers=
+all_modules_get_options=
smt_getoption_handlers=
smt_setoption_handlers=
include_all_option_headers=
@@ -665,14 +667,64 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
fi
if [ -n "$smtname" ]; then
+ all_modules_smt_options="${all_modules_smt_options:+$all_modules_smt_options,}
+#line $lineno \"$kf\"
+ \"$smtname\""
if [ "$internal" != - ]; then
- smt_getoption_handlers="${smt_getoption_handlers}
+ case "$type" in
+ bool)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(SExpr::Keyword(d_holder->$internal ? \"true\" : \"false\")); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExprKeyword(options::$internal() ? \"true\" : \"false\");
+ }";;
+ int|unsigned|int*_t|uint*_t|unsigned\ long|long|CVC4::Integer)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(d_holder->$internal); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExpr(Integer(options::$internal()));
+ }";;
+ float|double)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(Rational::fromDouble(d_holder->$internal)); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ stringstream ss; ss << std::fixed << options::$internal();
+ return SExpr(Rational::fromDecimal(ss.str()));
+ }";;
+ CVC4::Rational)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(d_holder->$internal); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExpr(options::$internal());
+ }";;
+ *)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::stringstream ss; ss << d_holder->$internal; std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(ss.str()); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
stringstream ss; ss << options::$internal();
return SExpr(ss.str());
- }"
+ }";;
+ esac
fi
if [ "$type" = bool ]; then
@@ -731,6 +783,36 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
return;
}"
fi
+ elif [ -n "$long_option" -o "$long_option_alternate" ] && [ "$internal" != - ]; then
+ case "$type" in
+ bool)
+ getoption_name="$long_option"
+ inv=
+ # case where we have a --disable but no corresponding --enable
+ if [ -z "$getoption_name" ]; then
+ getoption_name="$long_option_alternate"
+ inv='!'
+ fi
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$getoption_name\"); v.push_back(SExpr::Keyword((${inv}d_holder->$internal) ? \"true\" : \"false\")); opts.push_back(v); }";;
+ int|unsigned|int*_t|uint*_t|unsigned\ long|long|CVC4::Integer)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(d_holder->$internal); opts.push_back(v); }";;
+ float|double)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(Rational::fromDouble(d_holder->$internal)); opts.push_back(v); }";;
+ CVC4::Rational)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(d_holder->$internal); opts.push_back(v); }";;
+ *)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::stringstream ss; ss << d_holder->$internal; std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(ss.str()); opts.push_back(v); }";;
+ esac
fi
if [ "$type" = bool ]; then
@@ -1446,7 +1528,9 @@ for var in \
all_modules_defaults \
all_modules_short_options \
all_modules_long_options \
+ all_modules_smt_options \
all_modules_option_handlers \
+ all_modules_get_options \
include_all_option_headers \
all_modules_contributions \
all_custom_handlers \
diff --git a/src/options/options.h b/src/options/options.h
index 2be0e7b51..eaafade93 100644
--- a/src/options/options.h
+++ b/src/options/options.h
@@ -27,6 +27,7 @@
#include "options/option_exception.h"
#include "util/language.h"
#include "util/tls.h"
+#include "util/sexpr.h"
namespace CVC4 {
@@ -118,12 +119,33 @@ public:
static void printLanguageHelp(std::ostream& out);
/**
+ * Look up long command-line option names that bear some similarity to
+ * the given name. Don't include the initial "--". This might be
+ * useful in case of typos. Can return an empty vector if there are
+ * no suggestions.
+ */
+ static std::vector<std::string> suggestCommandLineOptions(const std::string& optionName) throw();
+
+ /**
+ * Look up SMT option names that bear some similarity to
+ * the given name. Don't include the initial ":". This might be
+ * useful in case of typos. Can return an empty vector if there are
+ * no suggestions.
+ */
+ static std::vector<std::string> suggestSmtOptions(const std::string& optionName) throw();
+
+ /**
* Initialize the options based on the given command-line arguments.
* The return value is what's left of the command line (that is, the
* non-option arguments).
*/
std::vector<std::string> parseOptions(int argc, char* argv[]) throw(OptionException);
+ /**
+ * Get the setting for all options.
+ */
+ SExpr getOptions() const throw();
+
};/* class Options */
}/* CVC4 namespace */
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index 81ffe1b27..d97d11364 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -14,6 +14,26 @@
** Contains code for handling command-line options
**/
+#if !defined(_BSD_SOURCE) && defined(__MINGW32__) && !defined(__MINGW64__)
+// force use of optreset; mingw32 croaks on argv-switching otherwise
+# include "cvc4autoconfig.h"
+# define _BSD_SOURCE
+# undef HAVE_DECL_OPTRESET
+# define HAVE_DECL_OPTRESET 1
+# define CVC4_IS_NOT_REALLY_BSD
+#endif /* !_BSD_SOURCE && __MINGW32__ && !__MINGW64__ */
+
+#ifdef __MINGW64__
+extern int optreset;
+#endif /* __MINGW64__ */
+
+#include <getopt.h>
+
+// clean up
+#ifdef CVC4_IS_NOT_REALLY_BSD
+# undef _BSD_SOURCE
+#endif /* CVC4_IS_NOT_REALLY_BSD */
+
#include <cstdio>
#include <cstdlib>
#include <new>
@@ -25,8 +45,6 @@
#include <stdint.h>
#include <time.h>
-#include <getopt.h>
-
#include "expr/expr.h"
#include "util/configuration.h"
#include "util/exception.h"
@@ -35,7 +53,7 @@
${include_all_option_headers}
-#line 39 "${template}"
+#line 57 "${template}"
#include "util/output.h"
#include "options/options_holder.h"
@@ -44,7 +62,7 @@ ${include_all_option_headers}
${option_handler_includes}
-#line 48 "${template}"
+#line 66 "${template}"
using namespace CVC4;
using namespace CVC4::options;
@@ -181,7 +199,7 @@ void runBoolPredicates(T, std::string option, bool b, SmtEngine* smt) {
${all_custom_handlers}
-#line 185 "${template}"
+#line 203 "${template}"
#ifdef CVC4_DEBUG
# define USE_EARLY_TYPE_CHECKING_BY_DEFAULT true
@@ -211,18 +229,18 @@ options::OptionsHolder::OptionsHolder() : ${all_modules_defaults}
{
}
-#line 215 "${template}"
+#line 233 "${template}"
static const std::string mostCommonOptionsDescription = "\
Most commonly-used CVC4 options:${common_documentation}";
-#line 220 "${template}"
+#line 238 "${template}"
static const std::string optionsDescription = mostCommonOptionsDescription + "\n\
\n\
Additional CVC4 options:${remaining_documentation}";
-#line 226 "${template}"
+#line 244 "${template}"
static const std::string optionsFootnote = "\n\
[*] Each of these options has a --no-OPTIONNAME variant, which reverses the\n\
@@ -293,7 +311,7 @@ static struct option cmdlineOptions[] = {${all_modules_long_options}
{ NULL, no_argument, NULL, '\0' }
};/* cmdlineOptions */
-#line 297 "${template}"
+#line 315 "${template}"
static void preemptGetopt(int& argc, char**& argv, const char* opt) {
const size_t maxoptlen = 128;
@@ -352,6 +370,8 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
const char *progName = main_argv[0];
SmtEngine* const smt = NULL;
+ Debug("options") << "main_argv == " << main_argv << std::endl;
+
// Reset getopt(), in the case of multiple calls to parseOptions().
// This can be = 1 in newer GNU getopt, but older (< 2007) require = 0.
optind = 0;
@@ -443,10 +463,33 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
} while(main_optind < argc && main_argv[main_optind][0] != '-');
continue;
}
+ Debug("options") << "[ before, optind == " << optind << " ]" << std::endl;
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ if(optreset == 1 && optind > 1) {
+ // on mingw, optreset will reset the optind, so we have to
+ // manually advance argc, argv
+ main_argv[optind - 1] = main_argv[0];
+ argv = main_argv += optind - 1;
+ argc -= optind - 1;
+ old_optind = optind = main_optind = 1;
+ if(argc > 0) {
+ Debug("options") << "looking at : " << argv[0] << std::endl;
+ }
+ /*c = getopt_long(argc, main_argv,
+ "+:${all_modules_short_options}",
+ cmdlineOptions, NULL);
+ Debug("options") << "pre-emptory c is " << c << " (" << char(c) << ")" << std::endl;
+ Debug("options") << "optind was reset to " << optind << std::endl;
+ optind = main_optind;
+ Debug("options") << "I restored optind to " << optind << std::endl;*/
+ }
+#endif /* __MINGW32__ || __MINGW64__ */
+ Debug("options") << "[ argc == " << argc << ", main_argv == " << main_argv << " ]" << std::endl;
c = getopt_long(argc, main_argv,
"+:${all_modules_short_options}",
cmdlineOptions, NULL);
main_optind = optind;
+ Debug("options") << "[ got " << int(c) << " (" << char(c) << ") ]" << std::endl;
Debug("options") << "[ next option will be at pos: " << optind << " ]" << std::endl;
if(c == -1) {
Debug("options") << "done with option parsing" << std::endl;
@@ -461,7 +504,7 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
switch(c) {
${all_modules_option_handlers}
-#line 465 "${template}"
+#line 508 "${template}"
case ':':
// This can be a long or short option, and the way to get at the
@@ -518,6 +561,48 @@ ${all_modules_option_handlers}
return nonOptions;
}
+std::vector<std::string> Options::suggestCommandLineOptions(const std::string& optionName) throw() {
+ std::vector<std::string> suggestions;
+
+ const char* opt;
+ for(size_t i = 0; (opt = cmdlineOptions[i].name) != NULL; ++i) {
+ if(std::strstr(opt, optionName.c_str()) != NULL) {
+ suggestions.push_back(opt);
+ }
+ }
+
+ return suggestions;
+}
+
+static const char* smtOptions[] = {
+ ${all_modules_smt_options},
+#line 580 "${template}"
+ NULL
+};/* smtOptions[] */
+
+std::vector<std::string> Options::suggestSmtOptions(const std::string& optionName) throw() {
+ std::vector<std::string> suggestions;
+
+ const char* opt;
+ for(size_t i = 0; (opt = smtOptions[i]) != NULL; ++i) {
+ if(std::strstr(opt, optionName.c_str()) != NULL) {
+ suggestions.push_back(opt);
+ }
+ }
+
+ return suggestions;
+}
+
+SExpr Options::getOptions() const throw() {
+ std::vector<SExpr> opts;
+
+ ${all_modules_get_options}
+
+#line 602 "${template}"
+
+ return SExpr(opts);
+}
+
#undef USE_EARLY_TYPE_CHECKING_BY_DEFAULT
#undef DO_SEMANTIC_CHECKS_BY_DEFAULT
diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp
index cd622b8a6..d498d3c54 100644
--- a/src/parser/antlr_input.cpp
+++ b/src/parser/antlr_input.cpp
@@ -46,9 +46,10 @@ namespace parser {
AntlrInputStream::AntlrInputStream(std::string name,
pANTLR3_INPUT_STREAM input,
bool fileIsTemporary) :
- InputStream(name,fileIsTemporary),
+ InputStream(name, fileIsTemporary),
d_input(input) {
assert( input != NULL );
+ input->fileName = input->strFactory->newStr8(input->strFactory, (pANTLR3_UINT8)name.c_str());
}
AntlrInputStream::~AntlrInputStream() {
@@ -286,16 +287,18 @@ void AntlrInput::warning(const std::string& message) {
void AntlrInput::parseError(const std::string& message, bool eofException)
throw (ParserException) {
Debug("parser") << "Throwing exception: "
- << getInputStream()->getName() << ":"
+ << (const char*)d_lexer->rec->state->tokSource->fileName->chars << ":"
<< d_lexer->getLine(d_lexer) << "."
<< d_lexer->getCharPositionInLine(d_lexer) << ": "
<< message << endl;
if(eofException) {
- throw ParserEndOfFileException(message, getInputStream()->getName(),
+ throw ParserEndOfFileException(message,
+ (const char*)d_lexer->rec->state->tokSource->fileName->chars,
d_lexer->getLine(d_lexer),
d_lexer->getCharPositionInLine(d_lexer));
} else {
- throw ParserException(message, getInputStream()->getName(),
+ throw ParserException(message,
+ (const char*)d_lexer->rec->state->tokSource->fileName->chars,
d_lexer->getLine(d_lexer),
d_lexer->getCharPositionInLine(d_lexer));
}
diff --git a/src/parser/antlr_input.h b/src/parser/antlr_input.h
index 3b7d53be8..8763e8451 100644
--- a/src/parser/antlr_input.h
+++ b/src/parser/antlr_input.h
@@ -14,12 +14,21 @@
** Base for ANTLR parser classes.
**/
+#include <antlr3.h>
+
+// ANTLR3 headers define these in our space :(
+// undef them so that we don't get multiple-definition warnings
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
#include "cvc4parser_private.h"
#ifndef __CVC4__PARSER__ANTLR_INPUT_H
#define __CVC4__PARSER__ANTLR_INPUT_H
-#include <antlr3.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
@@ -34,6 +43,7 @@
#include "util/bitvector.h"
#include "util/integer.h"
#include "util/rational.h"
+#include "util/output.h"
namespace CVC4 {
diff --git a/src/parser/antlr_line_buffered_input.cpp b/src/parser/antlr_line_buffered_input.cpp
index c2f73d988..a59fb3531 100644
--- a/src/parser/antlr_line_buffered_input.cpp
+++ b/src/parser/antlr_line_buffered_input.cpp
@@ -16,6 +16,15 @@
**/
#include <antlr3.h>
+
+// ANTLR3 headers define these in our space :(
+// undef them so that we don't get multiple-definition warnings
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
#include <iostream>
#include <string>
#include <cassert>
diff --git a/src/parser/bounded_token_buffer.cpp b/src/parser/bounded_token_buffer.cpp
index 88a7c6463..112d9b0ed 100644
--- a/src/parser/bounded_token_buffer.cpp
+++ b/src/parser/bounded_token_buffer.cpp
@@ -241,7 +241,7 @@ static pANTLR3_COMMON_TOKEN tokLT(pANTLR3_TOKEN_STREAM ts, ANTLR3_INT32 k) {
}
/* Initialize the buffer on our first call. */
- if( EXPECT_FALSE(buffer->empty == ANTLR3_TRUE) ) {
+ if( __builtin_expect( (buffer->empty == ANTLR3_TRUE), false ) ) {
assert( buffer->tokenBuffer != NULL );
buffer->tokenBuffer[ 0 ] = nextToken(buffer);
buffer->maxIndex = 0;
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 217e7ab97..03d1e7a8a 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -150,6 +150,7 @@ tokens {
MOD_TOK = 'MOD';
INTDIV_TOK = 'DIV';
FLOOR_TOK = 'FLOOR';
+ DISTINCT_TOK = 'DISTINCT';
// Bitvectors
@@ -270,8 +271,7 @@ int getOperatorPrecedence(int type) {
case LEQ_TOK:
case LT_TOK:
case GEQ_TOK:
- case GT_TOK:
- case FLOOR_TOK: return 25;
+ case GT_TOK: return 25;
case EQUAL_TOK:
case DISEQUAL_TOK: return 26;
case NOT_TOK: return 27;
@@ -953,7 +953,7 @@ declareVariables[CVC4::Command*& cmd, CVC4::Type& t, const std::vector<std::stri
} else {
Debug("parser") << " " << *i << " not declared" << std::endl;
if(topLevel) {
- Expr func = PARSER_STATE->mkVar(*i, t, true);
+ Expr func = PARSER_STATE->mkVar(*i, t, ExprManager::VAR_FLAG_GLOBAL);
Command* decl = new DeclareFunctionCommand(*i, func, t);
seq->addCommand(decl);
} else {
@@ -968,13 +968,14 @@ declareVariables[CVC4::Command*& cmd, CVC4::Type& t, const std::vector<std::stri
// like e.g. FORALL(x:INT = 4): [...]
PARSER_STATE->parseError("cannot construct a definition here; maybe you want a LET");
}
- Debug("parser") << "made " << idList.front() << " = " << f << std::endl;
+ assert(!idList.empty());
for(std::vector<std::string>::const_iterator i = idList.begin(),
i_end = idList.end();
i != i_end;
++i) {
+ Debug("parser") << "making " << *i << " : " << t << " = " << f << std::endl;
PARSER_STATE->checkDeclaration(*i, CHECK_UNDECLARED, SYM_VARIABLE);
- Expr func = EXPR_MANAGER->mkVar(*i, t, true);
+ Expr func = EXPR_MANAGER->mkVar(*i, t, ExprManager::VAR_FLAG_GLOBAL | ExprManager::VAR_FLAG_DEFINED);
PARSER_STATE->defineFunction(*i, f);
Command* decl = new DefineFunctionCommand(*i, func, f);
seq->addCommand(decl);
@@ -1162,15 +1163,11 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
}
/* tuple types / old-style function types */
- | LBRACKET type[t,check] { types.push_back(t); }
- ( COMMA type[t,check] { types.push_back(t); } )* RBRACKET
- { if(types.size() == 1) {
- if(types.front().isFunction()) {
- // old style function syntax [ T -> U ]
- PARSER_STATE->parseError("old-style function type syntax not supported anymore; please use the new syntax");
- } else {
- PARSER_STATE->parseError("I'm not sure what you're trying to do here; tuples must have > 1 type");
- }
+ | LBRACKET ( type[t,check] { types.push_back(t); }
+ ( COMMA type[t,check] { types.push_back(t); } )* )? RBRACKET
+ { if(types.size() == 1 && types.front().isFunction()) {
+ // old style function syntax [ T -> U ]
+ PARSER_STATE->parseError("old-style function type syntax not supported anymore; please use the new syntax");
} else {
// tuple type [ T, U, V... ]
t = EXPR_MANAGER->mkTupleType(types);
@@ -1178,13 +1175,17 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
}
/* record types */
- | SQHASH identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); }
- ( COMMA identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); } )* HASHSQ
+ | SQHASH ( identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); }
+ ( COMMA identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); } )* )? HASHSQ
{ t = EXPR_MANAGER->mkRecordType(typeIds); }
/* bitvector types */
| BITVECTOR_TOK LPAREN k=numeral RPAREN
- { t = EXPR_MANAGER->mkBitVectorType(k); }
+ { if(k == 0) {
+ PARSER_STATE->parseError("Illegal bitvector size: 0");
+ }
+ t = EXPR_MANAGER->mkBitVectorType(k);
+ }
/* basic types */
| BOOLEAN_TOK { t = EXPR_MANAGER->booleanType(); }
@@ -1326,7 +1327,7 @@ prefixFormula[CVC4::Expr& f]
{ PARSER_STATE->popScope();
Type t = EXPR_MANAGER->mkFunctionType(types, f.getType());
std::string name = "lambda";
- Expr func = PARSER_STATE->mkAnonymousFunction(name, t);
+ Expr func = PARSER_STATE->mkAnonymousFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
Command* cmd = new DefineFunctionCommand(name, func, terms, f);
PARSER_STATE->preemptCommand(cmd);
f = func;
@@ -1337,7 +1338,7 @@ prefixFormula[CVC4::Expr& f]
boundVarDecl[ids,t] RPAREN COLON formula[f]
{ PARSER_STATE->popScope();
UNSUPPORTED("array literals not supported yet");
- f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()), true);
+ f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()), ExprManager::VAR_FLAG_GLOBAL);
}
;
@@ -1368,7 +1369,7 @@ letDecl
: identifier[name,CHECK_NONE,SYM_VARIABLE] EQUAL_TOK formula[e]
{ Debug("parser") << Expr::setlanguage(language::output::LANG_CVC4) << e.getType() << std::endl;
PARSER_STATE->defineVar(name, e);
- Debug("parser") << "LET[" << PARSER_STATE->getDeclarationLevel() << "]: "
+ Debug("parser") << "LET[" << PARSER_STATE->scopeLevel() << "]: "
<< name << std::endl
<< " ==>" << " " << e << std::endl;
}
@@ -1578,7 +1579,7 @@ postfixTerm[CVC4::Expr& f]
std::string id;
Type t;
}
- : bvTerm[f]
+ : ( bvTerm[f]
( /* array select / bitvector extract */
LBRACKET
( formula[f2] { extract = false; }
@@ -1659,6 +1660,13 @@ postfixTerm[CVC4::Expr& f]
}
)
)*
+ | FLOOR_TOK LPAREN formula[f] RPAREN
+ { f = MK_EXPR(CVC4::kind::TO_INTEGER, f); }
+ | DISTINCT_TOK LPAREN
+ formula[f] { args.push_back(f); }
+ ( COMMA formula[f] { args.push_back(f); } )* RPAREN
+ { f = (args.size() == 1) ? MK_CONST(bool(true)) : MK_EXPR(CVC4::kind::DISTINCT, args); }
+ )
( typeAscription[f, t]
{ if(f.getKind() == CVC4::kind::APPLY_CONSTRUCTOR && t.isDatatype()) {
std::vector<CVC4::Expr> v;
@@ -1834,6 +1842,10 @@ simpleTerm[CVC4::Expr& f]
}
}
+ /* empty tuple literal */
+ | LPAREN RPAREN
+ { f = MK_EXPR(kind::TUPLE, std::vector<Expr>()); }
+
/* boolean literals */
| TRUE_TOK { f = MK_CONST(bool(true)); }
| FALSE_TOK { f = MK_CONST(bool(false)); }
@@ -1939,15 +1951,15 @@ datatypeDef[std::vector<CVC4::Datatype>& datatypes]
* below. */
: identifier[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(); }
( LBRACKET identifier[id2,CHECK_UNDECLARED,SYM_SORT] {
- t = PARSER_STATE->mkSort(id2);
+ t = PARSER_STATE->mkSort(id2, ExprManager::SORT_FLAG_PLACEHOLDER);
params.push_back( t );
}
( COMMA identifier[id2,CHECK_UNDECLARED,SYM_SORT] {
- t = PARSER_STATE->mkSort(id2);
+ t = PARSER_STATE->mkSort(id2, ExprManager::SORT_FLAG_PLACEHOLDER);
params.push_back( t ); }
)* RBRACKET
)?
- { datatypes.push_back(Datatype(id,params));
+ { datatypes.push_back(Datatype(id, params));
if(!PARSER_STATE->isUnresolvedType(id)) {
// if not unresolved, must be undeclared
PARSER_STATE->checkDeclaration(id, CHECK_UNDECLARED, SYM_SORT);
diff --git a/src/parser/cvc/Makefile.am b/src/parser/cvc/Makefile.am
index 7c5d48c1c..b7066dd7e 100644
--- a/src/parser/cvc/Makefile.am
+++ b/src/parser/cvc/Makefile.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = \
-D__BUILDING_CVC4PARSERLIB \
-I@builddir@/../.. -I@srcdir@/../../include -I@srcdir@/../.. $(ANTLR_INCLUDES)
-AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) $(WNO_PARENTHESES) $(WNO_TAUTOLOGICAL_COMPARE) -Wno-unused-function -Wno-unused-variable $(WNO_CONVERSION_NULL)
+AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) $(WNO_PARENTHESES) $(WNO_TAUTOLOGICAL_COMPARE) -Wno-unused-function -Wno-unused-variable $(WNO_UNINITIALIZED) $(WNO_CONVERSION_NULL)
# Compile generated C files using C++ compiler
CC=$(CXX)
diff --git a/src/parser/options b/src/parser/options
index beae09823..f277b231d 100644
--- a/src/parser/options
+++ b/src/parser/options
@@ -14,4 +14,8 @@ option memoryMap --mmap bool
option semanticChecks /--no-checking bool :default DO_SEMANTIC_CHECKS_BY_DEFAULT :link /--no-type-checking
disable ALL semantic checks, including type checks
+# this is just to support security in the online version
+# (--no-include-file disables filesystem access in TPTP and SMT2 parsers)
+undocumented-option canIncludeFile /--no-include-file bool :default true
+
endmodule
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
index 198d1cc31..5d9b6c7ae 100644
--- a/src/parser/parser.cpp
+++ b/src/parser/parser.cpp
@@ -42,11 +42,13 @@ Parser::Parser(ExprManager* exprManager, Input* input, bool strictMode, bool par
d_input(input),
d_symtabAllocated(),
d_symtab(&d_symtabAllocated),
+ d_assertionLevel(0),
d_anonymousFunctionCount(0),
d_done(false),
d_checksEnabled(true),
d_strictMode(strictMode),
- d_parseOnly(parseOnly) {
+ d_parseOnly(parseOnly),
+ d_canIncludeFile(true) {
d_input->setParser(*this);
}
@@ -137,11 +139,10 @@ bool Parser::isPredicate(const std::string& name) {
}
Expr
-Parser::mkVar(const std::string& name, const Type& type,
- bool levelZero) {
- Debug("parser") << "mkVar(" << name << ", " << type << ", " << levelZero << ")" << std::endl;
- Expr expr = d_exprManager->mkVar(name, type, levelZero);
- defineVar(name, expr, levelZero);
+Parser::mkVar(const std::string& name, const Type& type, uint32_t flags) {
+ Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
+ Expr expr = d_exprManager->mkVar(name, type, flags);
+ defineVar(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
return expr;
}
@@ -154,35 +155,31 @@ Parser::mkBoundVar(const std::string& name, const Type& type) {
}
Expr
-Parser::mkFunction(const std::string& name, const Type& type,
- bool levelZero) {
+Parser::mkFunction(const std::string& name, const Type& type, uint32_t flags) {
Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
- Expr expr = d_exprManager->mkVar(name, type, levelZero);
- defineFunction(name, expr, levelZero);
+ Expr expr = d_exprManager->mkVar(name, type, flags);
+ defineFunction(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
return expr;
}
Expr
-Parser::mkAnonymousFunction(const std::string& prefix, const Type& type) {
+Parser::mkAnonymousFunction(const std::string& prefix, const Type& type, uint32_t flags) {
stringstream name;
name << prefix << "_anon_" << ++d_anonymousFunctionCount;
- return mkFunction(name.str(), type);
+ return d_exprManager->mkVar(name.str(), type, flags);
}
std::vector<Expr>
-Parser::mkVars(const std::vector<std::string> names,
- const Type& type,
- bool levelZero) {
+Parser::mkVars(const std::vector<std::string> names, const Type& type, uint32_t flags) {
std::vector<Expr> vars;
for(unsigned i = 0; i < names.size(); ++i) {
- vars.push_back(mkVar(names[i], type, levelZero));
+ vars.push_back(mkVar(names[i], type, flags));
}
return vars;
}
std::vector<Expr>
-Parser::mkBoundVars(const std::vector<std::string> names,
- const Type& type) {
+Parser::mkBoundVars(const std::vector<std::string> names, const Type& type) {
std::vector<Expr> vars;
for(unsigned i = 0; i < names.size(); ++i) {
vars.push_back(mkBoundVar(names[i], type));
@@ -191,16 +188,14 @@ Parser::mkBoundVars(const std::vector<std::string> names,
}
void
-Parser::defineVar(const std::string& name, const Expr& val,
- bool levelZero) {
- Debug("parser") << "defineVar( " << name << " := " << val << " , " << levelZero << ")" << std::endl;;
+Parser::defineVar(const std::string& name, const Expr& val, bool levelZero) {
+ Debug("parser") << "defineVar( " << name << " := " << val << ")" << std::endl;;
d_symtab->bind(name, val, levelZero);
assert( isDeclared(name) );
}
void
-Parser::defineFunction(const std::string& name, const Expr& val,
- bool levelZero) {
+Parser::defineFunction(const std::string& name, const Expr& val, bool levelZero) {
d_symtab->bindDefinedFunction(name, val, levelZero);
assert( isDeclared(name) );
}
@@ -236,9 +231,9 @@ Parser::defineParameterizedType(const std::string& name,
}
SortType
-Parser::mkSort(const std::string& name) {
+Parser::mkSort(const std::string& name, uint32_t flags) {
Debug("parser") << "newSort(" << name << ")" << std::endl;
- Type type = d_exprManager->mkSort(name);
+ Type type = d_exprManager->mkSort(name, flags);
defineType(name, type);
return type;
}
@@ -253,7 +248,7 @@ Parser::mkSortConstructor(const std::string& name, size_t arity) {
}
SortType Parser::mkUnresolvedType(const std::string& name) {
- SortType unresolved = mkSort(name);
+ SortType unresolved = mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER);
d_unresolved.insert(unresolved);
return unresolved;
}
@@ -357,7 +352,7 @@ Parser::mkMutualDatatypeTypes(const std::vector<Datatype>& datatypes) {
bool Parser::isDeclared(const std::string& name, SymbolType type) {
switch(type) {
case SYM_VARIABLE:
- return d_symtab->isBound(name);
+ return d_reservedSymbols.find(name) != d_reservedSymbols.end() || d_symtab->isBound(name);
case SYM_SORT:
return d_symtab->isBoundType(name);
}
@@ -365,9 +360,15 @@ bool Parser::isDeclared(const std::string& name, SymbolType type) {
return false;
}
+void Parser::reserveSymbolAtAssertionLevel(const std::string& varName) {
+ checkDeclaration(varName, CHECK_UNDECLARED, SYM_VARIABLE);
+ d_reservedSymbols.insert(varName);
+}
+
void Parser::checkDeclaration(const std::string& varName,
DeclarationCheck check,
- SymbolType type)
+ SymbolType type,
+ std::string notes)
throw(ParserException) {
if(!d_checksEnabled) {
return;
@@ -377,14 +378,16 @@ void Parser::checkDeclaration(const std::string& varName,
case CHECK_DECLARED:
if( !isDeclared(varName, type) ) {
parseError("Symbol " + varName + " not declared as a " +
- (type == SYM_VARIABLE ? "variable" : "type"));
+ (type == SYM_VARIABLE ? "variable" : "type") +
+ (notes.size() == 0 ? notes : "\n" + notes));
}
break;
case CHECK_UNDECLARED:
if( isDeclared(varName, type) ) {
parseError("Symbol " + varName + " previously declared as a " +
- (type == SYM_VARIABLE ? "variable" : "type"));
+ (type == SYM_VARIABLE ? "variable" : "type") +
+ (notes.size() == 0 ? notes : "\n" + notes));
}
break;
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 1ca56dc06..b6ba482b7 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -126,6 +126,23 @@ class CVC4_PUBLIC Parser {
*/
SymbolTable* d_symtab;
+ /**
+ * The level of the assertions in the declaration scope. Things declared
+ * after this level are bindings from e.g. a let, a quantifier, or a
+ * lambda.
+ */
+ size_t d_assertionLevel;
+
+ /**
+ * Maintains a list of reserved symbols at the assertion level that might
+ * not occur in our symbol table. This is necessary to e.g. support the
+ * proper behavior of the :named annotation in SMT-LIBv2 when used under
+ * a let or a quantifier, since inside a let/quant body the declaration
+ * scope is that of the let/quant body, but the defined name should be
+ * reserved at the assertion level.
+ */
+ std::set<std::string> d_reservedSymbols;
+
/** How many anonymous functions we've created. */
size_t d_anonymousFunctionCount;
@@ -141,6 +158,12 @@ class CVC4_PUBLIC Parser {
/** Are we only parsing? */
bool d_parseOnly;
+ /**
+ * Can we include files? (Set to false for security purposes in
+ * e.g. the online version.)
+ */
+ bool d_canIncludeFile;
+
/** The set of operators available in the current logic. */
std::set<Kind> d_logicOperators;
@@ -235,6 +258,10 @@ public:
bool strictModeEnabled() { return d_strictMode; }
+ void allowIncludeFile() { d_canIncludeFile = true; }
+ void disallowIncludeFile() { d_canIncludeFile = false; }
+ bool canIncludeFile() const { return d_canIncludeFile; }
+
/**
* Returns a variable, given a name.
*
@@ -285,7 +312,13 @@ public:
* @throws ParserException if checks are enabled and the check fails
*/
void checkDeclaration(const std::string& name, DeclarationCheck check,
- SymbolType type = SYM_VARIABLE) throw(ParserException);
+ SymbolType type = SYM_VARIABLE,
+ std::string notes = "") throw(ParserException);
+
+ /**
+ * Reserve a symbol at the assertion level.
+ */
+ void reserveSymbolAtAssertionLevel(const std::string& name);
/**
* Checks whether the given name is bound to a function.
@@ -326,14 +359,14 @@ public:
/** Create a new CVC4 variable expression of the given type. */
Expr mkVar(const std::string& name, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/**
* Create a set of new CVC4 variable expressions of the given type.
*/
std::vector<Expr>
mkVars(const std::vector<std::string> names, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a new CVC4 bound variable expression of the given type. */
Expr mkBoundVar(const std::string& name, const Type& type);
@@ -345,18 +378,19 @@ public:
/** Create a new CVC4 function expression of the given type. */
Expr mkFunction(const std::string& name, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/**
* Create a new CVC4 function expression of the given type,
* appending a unique index to its name. (That's the ONLY
* difference between mkAnonymousFunction() and mkFunction()).
*/
- Expr mkAnonymousFunction(const std::string& prefix, const Type& type);
+ Expr mkAnonymousFunction(const std::string& prefix, const Type& type,
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a new variable definition (e.g., from a let binding). */
void defineVar(const std::string& name, const Expr& val,
- bool levelZero = false);
+ bool levelZero = false);
/** Create a new function definition (e.g., from a define-fun). */
void defineFunction(const std::string& name, const Expr& val,
@@ -377,7 +411,8 @@ public:
/**
* Creates a new sort with the given name.
*/
- SortType mkSort(const std::string& name);
+ SortType mkSort(const std::string& name,
+ uint32_t flags = ExprManager::SORT_FLAG_NONE);
/**
* Creates a new sort constructor with the given name and arity.
@@ -462,6 +497,11 @@ public:
d_input->parseError(msg);
}
+ /** Unexpectedly encountered an EOF */
+ inline void unexpectedEOF(const std::string& msg) throw(ParserException) {
+ d_input->parseError(msg, true);
+ }
+
/**
* If we are parsing only, don't raise an exception; if we are not,
* raise a parse error with the given message. There is no actual
@@ -482,8 +522,25 @@ public:
}
}
- inline void pushScope() { d_symtab->pushScope(); }
- inline void popScope() { d_symtab->popScope(); }
+ /**
+ * Gets the current declaration level.
+ */
+ inline size_t scopeLevel() const { return d_symtab->getLevel(); }
+
+ inline void pushScope(bool bindingLevel = false) {
+ d_symtab->pushScope();
+ if(!bindingLevel) {
+ d_assertionLevel = scopeLevel();
+ }
+ }
+
+ inline void popScope() {
+ d_symtab->popScope();
+ if(scopeLevel() < d_assertionLevel) {
+ d_assertionLevel = scopeLevel();
+ d_reservedSymbols.clear();
+ }
+ }
/**
* Set the current symbol table used by this parser.
@@ -527,13 +584,6 @@ public:
}
/**
- * Gets the current declaration level.
- */
- inline size_t getDeclarationLevel() const throw() {
- return d_symtab->getLevel();
- }
-
- /**
* An expression stream interface for a parser. This stream simply
* pulls expressions from the given Parser object.
*
diff --git a/src/parser/parser_builder.cpp b/src/parser/parser_builder.cpp
index 721337c9e..cb8c0d4f6 100644
--- a/src/parser/parser_builder.cpp
+++ b/src/parser/parser_builder.cpp
@@ -54,6 +54,7 @@ void ParserBuilder::init(ExprManager* exprManager,
d_exprManager = exprManager;
d_checksEnabled = true;
d_strictMode = false;
+ d_canIncludeFile = true;
d_mmap = false;
d_parseOnly = false;
}
@@ -102,6 +103,12 @@ Parser* ParserBuilder::build()
parser->disableChecks();
}
+ if( d_canIncludeFile ) {
+ parser->allowIncludeFile();
+ } else {
+ parser->disallowIncludeFile();
+ }
+
return parser;
}
@@ -146,7 +153,8 @@ ParserBuilder& ParserBuilder::withOptions(const Options& options) {
.withMmap(options[options::memoryMap])
.withChecks(options[options::semanticChecks])
.withStrictMode(options[options::strictParsing])
- .withParseOnly(options[options::parseOnly]);
+ .withParseOnly(options[options::parseOnly])
+ .withIncludeFile(options[options::canIncludeFile]);
}
ParserBuilder& ParserBuilder::withStrictMode(bool flag) {
@@ -154,6 +162,11 @@ ParserBuilder& ParserBuilder::withStrictMode(bool flag) {
return *this;
}
+ParserBuilder& ParserBuilder::withIncludeFile(bool flag) {
+ d_canIncludeFile = flag;
+ return *this;
+}
+
ParserBuilder& ParserBuilder::withStreamInput(std::istream& input) {
d_inputType = STREAM_INPUT;
d_streamInput = &input;
diff --git a/src/parser/parser_builder.h b/src/parser/parser_builder.h
index 75e2b4fbe..b6e15b2ff 100644
--- a/src/parser/parser_builder.h
+++ b/src/parser/parser_builder.h
@@ -71,6 +71,9 @@ class CVC4_PUBLIC ParserBuilder {
/** Should we parse in strict mode? */
bool d_strictMode;
+ /** Should we allow include-file commands? */
+ bool d_canIncludeFile;
+
/** Should we memory-map a file input? */
bool d_mmap;
@@ -146,6 +149,13 @@ public:
*/
ParserBuilder& withStrictMode(bool flag = true);
+ /**
+ * Should the include-file commands be enabled?
+ *
+ * (Default: yes)
+ */
+ ParserBuilder& withIncludeFile(bool flag = true);
+
/** Set the parser to use the given stream for its input. */
ParserBuilder& withStreamInput(std::istream& input);
diff --git a/src/parser/smt1/smt1.cpp b/src/parser/smt1/smt1.cpp
index 41b0523bd..c9bbd3860 100644
--- a/src/parser/smt1/smt1.cpp
+++ b/src/parser/smt1/smt1.cpp
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: Christopher L. Conway
- ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Clark Barrett
+ ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Clark Barrett, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -39,6 +39,7 @@ std::hash_map<const std::string, Smt1::Logic, CVC4::StringHashFunction> Smt1::ne
logicMap["QF_NIA"] = QF_NIA;
logicMap["QF_NRA"] = QF_NRA;
logicMap["QF_RDL"] = QF_RDL;
+ logicMap["QF_S"] = QF_S;
logicMap["QF_SAT"] = QF_SAT;
logicMap["QF_UF"] = QF_UF;
logicMap["QF_UFIDL"] = QF_UFIDL;
@@ -180,6 +181,10 @@ void Smt1::setLogic(const std::string& name) {
d_logic = toLogic(name);
switch(d_logic) {
+ case QF_S:
+ throw ParserException("Strings theory unsupported in SMT-LIBv1 front-end; try SMT-LIBv2.");
+ break;
+
case QF_AX:
addTheory(THEORY_ARRAYS_EX);
break;
diff --git a/src/parser/smt1/smt1.h b/src/parser/smt1/smt1.h
index d6961371a..f96a4e810 100644
--- a/src/parser/smt1/smt1.h
+++ b/src/parser/smt1/smt1.h
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: Christopher L. Conway
- ** Minor contributors (to current version): Clark Barrett
+ ** Minor contributors (to current version): Clark Barrett, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -52,6 +52,7 @@ public:
QF_NIA,
QF_NRA,
QF_RDL,
+ QF_S, // nonstandard (for string theory)
QF_SAT,
QF_UF,
QF_UFIDL,
@@ -82,6 +83,7 @@ public:
THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX,
THEORY_REALS,
THEORY_REALS_INTS,
+ THEORY_STRINGS,
THEORY_QUANTIFIERS
};
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 8dcde2483..c84046570 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Christopher L. Conway
** Major contributors: Morgan Deters
- ** Minor contributors (to current version): Dejan Jovanovic, Andrew Reynolds, Francois Bobot
+ ** Minor contributors (to current version): Dejan Jovanovic, Andrew Reynolds, Francois Bobot, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -133,6 +133,41 @@ using namespace CVC4::parser;
#define MK_CONST EXPR_MANAGER->mkConst
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
+static bool isClosed(Expr e, std::set<Expr>& free, std::hash_set<Expr, ExprHashFunction>& closedCache) {
+ if(closedCache.find(e) != closedCache.end()) {
+ return true;
+ }
+
+ if(e.getKind() == kind::FORALL || e.getKind() == kind::EXISTS || e.getKind() == kind::LAMBDA) {
+ isClosed(e[1], free, closedCache);
+ for(Expr::const_iterator i = e[0].begin(); i != e[0].end(); ++i) {
+ free.erase((*i)[0]);
+ }
+ } else if(e.getKind() == kind::BOUND_VARIABLE) {
+ free.insert(e);
+ return false;
+ } else {
+ if(e.hasOperator()) {
+ isClosed(e.getOperator(), free, closedCache);
+ }
+ for(Expr::const_iterator i = e.begin(); i != e.end(); ++i) {
+ isClosed(*i, free, closedCache);
+ }
+ }
+
+ if(free.empty()) {
+ closedCache.insert(e);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static inline bool isClosed(Expr e, std::set<Expr>& free) {
+ std::hash_set<Expr, ExprHashFunction> cache;
+ return isClosed(e, free, cache);
+}
+
}/* parser::postinclude */
/**
@@ -153,7 +188,26 @@ parseExpr returns [CVC4::parser::smt2::myExpr expr]
* @return the parsed command, or NULL if we've reached the end of the input
*/
parseCommand returns [CVC4::Command* cmd = NULL]
+@declarations {
+ std::string name;
+}
: LPAREN_TOK c = command RPAREN_TOK { $cmd = c; }
+
+ /* This extended command has to be in the outermost production so that
+ * the RPAREN_TOK is properly eaten and we are in a good state to read
+ * the included file's tokens. */
+ | LPAREN_TOK INCLUDE_TOK str[name] RPAREN_TOK
+ { if(!PARSER_STATE->canIncludeFile()) {
+ PARSER_STATE->parseError("include-file feature was disabled for this run.");
+ }
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("Extended commands are not permitted while operating in strict compliance mode.");
+ }
+ PARSER_STATE->includeFile(name);
+ // The command of the included file will be produced at the next parseCommand() call
+ cmd = new EmptyCommand("include::" + name);
+ }
+
| EOF { $cmd = 0; }
;
@@ -188,9 +242,8 @@ command returns [CVC4::Command* cmd = NULL]
GET_INFO_TOK KEYWORD
{ cmd = new GetInfoCommand(AntlrInput::tokenText($KEYWORD).c_str() + 1); }
| /* set-option */
- SET_OPTION_TOK KEYWORD symbolicExpr[sexpr]
- { name = AntlrInput::tokenText($KEYWORD);
- PARSER_STATE->setOption(name.c_str() + 1, sexpr);
+ SET_OPTION_TOK keyword[name] symbolicExpr[sexpr]
+ { PARSER_STATE->setOption(name.c_str() + 1, sexpr);
cmd = new SetOptionCommand(name.c_str() + 1, sexpr); }
| /* get-option */
GET_OPTION_TOK KEYWORD
@@ -216,7 +269,7 @@ command returns [CVC4::Command* cmd = NULL]
symbol[name,CHECK_UNDECLARED,SYM_SORT]
{ PARSER_STATE->checkUserSymbol(name); }
LPAREN_TOK symbolList[names,CHECK_NONE,SYM_SORT] RPAREN_TOK
- { PARSER_STATE->pushScope();
+ { PARSER_STATE->pushScope(true);
for(std::vector<std::string>::const_iterator i = names.begin(),
iend = names.end();
i != iend;
@@ -262,7 +315,7 @@ command returns [CVC4::Command* cmd = NULL]
}
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -275,7 +328,7 @@ command returns [CVC4::Command* cmd = NULL]
// declare the name down here (while parsing term, signature
// must not be extended with the name itself; no recursion
// permitted)
- Expr func = PARSER_STATE->mkFunction(name, t);
+ Expr func = PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, terms, expr);
}
| /* value query */
@@ -284,23 +337,29 @@ command returns [CVC4::Command* cmd = NULL]
{ $cmd = new GetValueCommand(terms); }
| /* get-assignment */
GET_ASSIGNMENT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetAssignmentCommand; }
+ { cmd = new GetAssignmentCommand(); }
| /* assertion */
ASSERT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[expr, expr2]
{ cmd = new AssertCommand(expr); }
- | /* checksat */
+ | /* check-sat */
CHECKSAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new CheckSatCommand(MK_CONST(bool(true))); }
+ ( term[expr, expr2]
+ { if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("Extended commands (such as check-sat with an argument) are not permitted while operating in strict compliance mode.");
+ }
+ }
+ | { expr = MK_CONST(bool(true)); } )
+ { cmd = new CheckSatCommand(expr); }
| /* get-assertions */
GET_ASSERTIONS_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetAssertionsCommand; }
+ { cmd = new GetAssertionsCommand(); }
| /* get-proof */
GET_PROOF_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetProofCommand; }
+ { cmd = new GetProofCommand(); }
| /* get-unsat-core */
GET_UNSAT_CORE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetUnsatCoreCommand; }
+ { cmd = new GetUnsatCoreCommand(); }
| /* push */
PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
@@ -314,7 +373,9 @@ command returns [CVC4::Command* cmd = NULL]
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->pushScope();
- seq->addCommand(new PushCommand());
+ Command* c = new PushCommand();
+ c->setMuted(n > 1);
+ seq->addCommand(c);
} while(--n > 0);
cmd = seq;
}
@@ -322,12 +383,15 @@ command returns [CVC4::Command* cmd = NULL]
| { if(PARSER_STATE->strictModeEnabled()) {
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to PUSH. Maybe you want (push 1)?");
} else {
- cmd = new PushCommand;
+ cmd = new PushCommand();
}
} )
| POP_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
{ unsigned n = AntlrInput::tokenToUnsigned(k);
+ if(n > PARSER_STATE->scopeLevel()) {
+ PARSER_STATE->parseError("Attempted to pop above the top stack frame.");
+ }
if(n == 0) {
cmd = new EmptyCommand();
} else if(n == 1) {
@@ -337,7 +401,9 @@ command returns [CVC4::Command* cmd = NULL]
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->popScope();
- seq->addCommand(new PopCommand());
+ Command* c = new PopCommand();
+ c->setMuted(n > 1);
+ seq->addCommand(c);
} while(--n > 0);
cmd = seq;
}
@@ -345,11 +411,11 @@ command returns [CVC4::Command* cmd = NULL]
| { if(PARSER_STATE->strictModeEnabled()) {
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to POP. Maybe you want (pop 1)?");
} else {
- cmd = new PopCommand;
+ cmd = new PopCommand();
}
} )
| EXIT_TOK
- { cmd = new QuitCommand; }
+ { cmd = new QuitCommand(); }
/* CVC4-extended SMT-LIB commands */
| extendedCommand[cmd]
@@ -385,8 +451,8 @@ extendedCommand[CVC4::Command*& cmd]
* --smtlib2 compliance mode. */
: DECLARE_DATATYPES_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ /* open a scope to keep the UnresolvedTypes contained */
- PARSER_STATE->pushScope(); }
- LPAREN_TOK /* parametric sorts */
+ PARSER_STATE->pushScope(true); }
+ LPAREN_TOK /* parametric sorts */
( symbol[name,CHECK_UNDECLARED,SYM_SORT] {
sorts.push_back( PARSER_STATE->mkSort(name) ); }
)*
@@ -396,7 +462,7 @@ extendedCommand[CVC4::Command*& cmd]
cmd = new DatatypeDeclarationCommand(PARSER_STATE->mkMutualDatatypeTypes(dts)); }
| /* get model */
GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetModelCommand; }
+ { cmd = new GetModelCommand(); }
| ECHO_TOK
( simpleSymbolicExpr[sexpr]
{ std::stringstream ss;
@@ -465,7 +531,7 @@ extendedCommand[CVC4::Command*& cmd]
( symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
{ PARSER_STATE->checkUserSymbol(name); }
term[e,e2]
- { Expr func = PARSER_STATE->mkFunction(name, e.getType());
+ { Expr func = PARSER_STATE->mkFunction(name, e.getType(), ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, e);
}
| LPAREN_TOK
@@ -474,7 +540,7 @@ extendedCommand[CVC4::Command*& cmd]
sortedVarList[sortedVarNames] RPAREN_TOK
{ /* add variables to parser state before parsing term */
Debug("parser") << "define fun: '" << name << "'" << std::endl;
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -499,7 +565,7 @@ extendedCommand[CVC4::Command*& cmd]
}
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
- Expr func = PARSER_STATE->mkFunction(name, t);
+ Expr func = PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, terms, e);
}
)
@@ -521,7 +587,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
kind = CVC4::kind::RR_REWRITE;
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -562,7 +628,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
| rewritePropaKind[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -631,6 +697,7 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
@declarations {
CVC4::Kind k;
std::string s;
+ std::vector<unsigned int> s_vec;
}
: INTEGER_LITERAL
{ sexpr = SExpr(Integer(AntlrInput::tokenText($INTEGER_LITERAL))); }
@@ -638,8 +705,17 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
{ sexpr = SExpr(AntlrInput::tokenToRational($DECIMAL_LITERAL)); }
| str[s]
{ sexpr = SExpr(s); }
+// | LPAREN_TOK STRCST_TOK
+// ( INTEGER_LITERAL {
+// s_vec.push_back( atoi( AntlrInput::tokenText($INTEGER_LITERAL) ) + 65 );
+// } )* RPAREN_TOK
+// {
+// sexpr = SExpr( MK_CONST( ::CVC4::String(s_vec) ) );
+// }
| symbol[s,CHECK_NONE,SYM_SORT]
{ sexpr = SExpr(SExpr::Keyword(s)); }
+ | tok=(ASSERT_TOK | CHECKSAT_TOK | DECLARE_FUN_TOK | DECLARE_SORT_TOK | DEFINE_FUN_TOK | DEFINE_SORT_TOK | GET_VALUE_TOK | GET_ASSIGNMENT_TOK | GET_ASSERTIONS_TOK | GET_PROOF_TOK | GET_UNSAT_CORE_TOK | EXIT_TOK | SET_LOGIC_TOK | SET_INFO_TOK | GET_INFO_TOK | SET_OPTION_TOK | GET_OPTION_TOK | PUSH_TOK | POP_TOK | DECLARE_DATATYPES_TOK | GET_MODEL_TOK | ECHO_TOK | REWRITE_RULE_TOK | REDUCTION_RULE_TOK | PROPAGATION_RULE_TOK | SIMPLIFY_TOK)
+ { sexpr = SExpr(SExpr::Keyword(AntlrInput::tokenText($tok))); }
| builtinOp[k]
{ std::stringstream ss;
ss << Expr::setlanguage(CVC4::language::output::LANG_SMTLIB_V2) << EXPR_MANAGER->mkConst(k);
@@ -647,6 +723,11 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
}
;
+keyword[std::string& s]
+ : KEYWORD
+ { s = AntlrInput::tokenText($KEYWORD); }
+ ;
+
simpleSymbolicExpr[CVC4::SExpr& sexpr]
: simpleSymbolicExprNoKeyword[sexpr]
| KEYWORD
@@ -671,7 +752,7 @@ symbolicExpr[CVC4::SExpr& sexpr]
term[CVC4::Expr& expr, CVC4::Expr& expr2]
@init {
Debug("parser") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
- Kind kind;
+ Kind kind = kind::NULL_EXPR;
Expr op;
std::string name;
std::vector<Expr> args;
@@ -684,6 +765,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
std::hash_set<std::string, StringHashFunction> names;
std::vector< std::pair<std::string, Expr> > binders;
Type type;
+ std::string s;
}
: /* a built-in operator application */
LPAREN_TOK builtinOp[kind] termList[args,expr] RPAREN_TOK
@@ -699,19 +781,38 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
(kind == CVC4::kind::AND || kind == CVC4::kind::OR) &&
args.size() == 1) {
/* Unary AND/OR can be replaced with the argument.
- It just so happens expr should already by the only argument. */
+ * It just so happens expr should already be the only argument. */
assert( expr == args[0] );
} else if( CVC4::kind::isAssociative(kind) &&
args.size() > EXPR_MANAGER->maxArity(kind) ) {
/* Special treatment for associative operators with lots of children */
- expr = EXPR_MANAGER->mkAssociative(kind,args);
+ expr = EXPR_MANAGER->mkAssociative(kind, args);
} else if( kind == CVC4::kind::MINUS && args.size() == 1 ) {
expr = MK_EXPR(CVC4::kind::UMINUS, args[0]);
+ } else if( ( kind == CVC4::kind::XOR || kind == CVC4::kind::MINUS ) &&
+ args.size() > 2 ) {
+ /* left-associative, but CVC4 internally only supports 2 args */
+ expr = args[0];
+ for(size_t i = 1; i < args.size(); ++i) {
+ expr = MK_EXPR(kind, expr, args[i]);
+ }
+ } else if( kind == CVC4::kind::IMPLIES && args.size() > 2 ) {
+ /* right-associative, but CVC4 internally only supports 2 args */
+ expr = args[args.size() - 1];
+ for(size_t i = args.size() - 1; i > 0;) {
+ expr = MK_EXPR(kind, args[--i], expr);
+ }
} else if( ( kind == CVC4::kind::IFF || kind == CVC4::kind::EQUAL ||
kind == CVC4::kind::LT || kind == CVC4::kind::GT ||
kind == CVC4::kind::LEQ || kind == CVC4::kind::GEQ ) &&
args.size() > 2 ) {
- expr = MK_EXPR(CVC4::kind::CHAIN, MK_CONST(kind), args);
+ /* "chainable", but CVC4 internally only supports 2 args */
+ expr = MK_EXPR(MK_CONST(Chain(kind)), args);
+ } else if( PARSER_STATE->strictModeEnabled() && kind == CVC4::kind::ABS &&
+ args.size() == 1 && !args[0].getType().isInteger() ) {
+ /* first, check that ABS is even defined in this logic */
+ PARSER_STATE->checkOperator(kind, args.size());
+ PARSER_STATE->parseError("abs can only be applied to Int, not Real, while in strict SMT-LIB compliance mode");
} else {
PARSER_STATE->checkOperator(kind, args.size());
expr = MK_EXPR(kind, args);
@@ -726,7 +827,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
v.push_back(MK_EXPR( CVC4::kind::APPLY_TYPE_ASCRIPTION,
MK_CONST(AscriptionType(dtc.getSpecializedConstructorType(type))), f.getOperator() ));
v.insert(v.end(), f.begin(), f.end());
- f = MK_EXPR(CVC4::kind::APPLY_CONSTRUCTOR, v);
+ expr = MK_EXPR(CVC4::kind::APPLY_CONSTRUCTOR, v);
} else {
if(f.getType() != type) {
PARSER_STATE->parseError("Type ascription not satisfied.");
@@ -736,7 +837,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
| LPAREN_TOK quantOp[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -769,6 +870,10 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
expr = MK_EXPR(kind, args);
}
}
+ //| /* substring */
+ //LPAREN_TOK STRSUB_TOK n1=INTEGER_LITERAL n2=INTEGER_LITERAL RPAREN_TOK
+ //{
+ //}
| /* A non-built-in function application */
LPAREN_TOK
functionName[name, CHECK_DECLARED]
@@ -801,11 +906,12 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
| /* An indexed function application */
LPAREN_TOK indexedFunctionName[op] termList[args,expr] RPAREN_TOK
- { expr = MK_EXPR(op, args); }
-
+ { expr = MK_EXPR(op, args);
+ PARSER_STATE->checkOperator(expr.getKind(), args.size());
+ }
| /* a let binding */
LPAREN_TOK LET_TOK LPAREN_TOK
- { PARSER_STATE->pushScope(); }
+ { PARSER_STATE->pushScope(true); }
( LPAREN_TOK symbol[name,CHECK_NONE,SYM_VARIABLE] term[expr, f2] RPAREN_TOK
// this is a parallel let, so we have to save up all the contributions
// of the let and define them only later on
@@ -918,6 +1024,9 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
std::string binString = AntlrInput::tokenTextSubstr($BINARY_LITERAL, 2);
expr = MK_CONST( BitVector(binString, 2) ); }
+ | str[s]
+ { expr = MK_CONST( ::CVC4::String(s) ); }
+
// NOTE: Theory constants go here
;
@@ -971,10 +1080,24 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
| ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
{
attr = std::string(":named");
+ if(!sexpr.isKeyword()) {
+ PARSER_STATE->parseError("improperly formed :named annotation");
+ }
std::string name = sexpr.getValue();
- // FIXME ensure expr is a closed subterm
- // check that sexpr is a fresh function symbol
- PARSER_STATE->checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
+ PARSER_STATE->checkUserSymbol(name);
+ // ensure expr is a closed subterm
+ std::set<Expr> freeVars;
+ if(!isClosed(expr, freeVars)) {
+ assert(!freeVars.empty());
+ std::stringstream ss;
+ ss << ":named annotations can only name terms that are closed; this one contains free variables:";
+ for(std::set<Expr>::const_iterator i = freeVars.begin(); i != freeVars.end(); ++i) {
+ ss << " " << *i;
+ }
+ PARSER_STATE->parseError(ss.str());
+ }
+ // check that sexpr is a fresh function symbol, and reserve it
+ PARSER_STATE->reserveSymbolAtAssertionLevel(name);
// define it
Expr func = PARSER_STATE->mkFunction(name, expr.getType());
// bind name to expr with define-fun
@@ -1003,6 +1126,13 @@ indexedFunctionName[CVC4::Expr& op]
{ op = MK_CONST(BitVectorRotateLeft(AntlrInput::tokenToUnsigned($n))); }
| 'rotate_right' n=INTEGER_LITERAL
{ op = MK_CONST(BitVectorRotateRight(AntlrInput::tokenToUnsigned($n))); }
+ | DIVISIBLE_TOK n=INTEGER_LITERAL
+ { op = MK_CONST(Divisible(AntlrInput::tokenToUnsigned($n))); }
+ | INT2BV_TOK n=INTEGER_LITERAL
+ { op = MK_CONST(IntToBitVector(AntlrInput::tokenToUnsigned($n)));
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("bv2nat and int2bv are not part of SMT-LIB, and aren't available in SMT-LIB strict compliance mode");
+ } }
| badIndexedFunctionName
)
RPAREN_TOK
@@ -1075,6 +1205,10 @@ builtinOp[CVC4::Kind& kind]
| DIV_TOK { $kind = CVC4::kind::DIVISION; }
| INTS_DIV_TOK { $kind = CVC4::kind::INTS_DIVISION; }
| INTS_MOD_TOK { $kind = CVC4::kind::INTS_MODULUS; }
+ | ABS_TOK { $kind = CVC4::kind::ABS; }
+ | IS_INT_TOK { $kind = CVC4::kind::IS_INTEGER; }
+ | TO_INT_TOK { $kind = CVC4::kind::TO_INTEGER; }
+ | TO_REAL_TOK { $kind = CVC4::kind::TO_REAL; }
| SELECT_TOK { $kind = CVC4::kind::SELECT; }
| STORE_TOK { $kind = CVC4::kind::STORE; }
@@ -1109,6 +1243,22 @@ builtinOp[CVC4::Kind& kind]
| BVSGT_TOK { $kind = CVC4::kind::BITVECTOR_SGT; }
| BVSGE_TOK { $kind = CVC4::kind::BITVECTOR_SGE; }
+ | BV2NAT_TOK { $kind = CVC4::kind::BITVECTOR_TO_NAT;
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("bv2nat and int2bv are not part of SMT-LIB, and aren't available in SMT-LIB strict compliance mode");
+ } }
+
+ | STRCON_TOK { $kind = CVC4::kind::STRING_CONCAT; }
+ | STRLEN_TOK { $kind = CVC4::kind::STRING_LENGTH; }
+ | STRINRE_TOK { $kind = CVC4::kind::STRING_IN_REGEXP; }
+ | STRTORE_TOK { $kind = CVC4::kind::STRING_TO_REGEXP; }
+ | RECON_TOK { $kind = CVC4::kind::REGEXP_CONCAT; }
+ | REOR_TOK { $kind = CVC4::kind::REGEXP_OR; }
+ | REINTER_TOK { $kind = CVC4::kind::REGEXP_INTER; }
+ | RESTAR_TOK { $kind = CVC4::kind::REGEXP_STAR; }
+ | REPLUS_TOK { $kind = CVC4::kind::REGEXP_PLUS; }
+ | REOPT_TOK { $kind = CVC4::kind::REGEXP_OPT; }
+
// NOTE: Theory operators go here
;
@@ -1200,6 +1350,9 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
if( numerals.size() != 1 ) {
PARSER_STATE->parseError("Illegal bitvector type.");
}
+ if(numerals.front() == 0) {
+ PARSER_STATE->parseError("Illegal bitvector size: 0");
+ }
t = EXPR_MANAGER->mkBitVectorType(numerals.front());
} else {
std::stringstream ss;
@@ -1209,21 +1362,20 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
}
| LPAREN_TOK symbol[name,CHECK_NONE,SYM_SORT] sortList[args] RPAREN_TOK
{
- if( check == CHECK_DECLARED || PARSER_STATE->isDeclared(name, SYM_SORT)) {
- if( name == "Array" ) {
- if( args.size() != 2 ) {
- PARSER_STATE->parseError("Illegal array type.");
- }
- t = EXPR_MANAGER->mkArrayType( args[0], args[1] );
- } else {
- t = PARSER_STATE->getSort(name, args);
+ if(name == "Array") {
+ if(args.size() != 2) {
+ PARSER_STATE->parseError("Illegal array type.");
}
- }else{
- //make unresolved type
+ t = EXPR_MANAGER->mkArrayType( args[0], args[1] );
+ } else if(check == CHECK_DECLARED ||
+ PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ t = PARSER_STATE->getSort(name, args);
+ } else {
+ // make unresolved type
if(args.empty()) {
t = PARSER_STATE->mkUnresolvedType(name);
Debug("parser-param") << "param: make unres type " << name << std::endl;
- }else{
+ } else {
t = PARSER_STATE->mkUnresolvedTypeConstructor(name,args);
t = SortConstructorType(t).instantiate( args );
Debug("parser-param") << "param: make unres param type " << name << " " << args.size() << " "
@@ -1271,6 +1423,8 @@ symbol[std::string& id,
PARSER_STATE->checkDeclaration(id, check, type);
}
}
+ | UNTERMINATED_QUOTED_SYMBOL EOF
+ { PARSER_STATE->unexpectedEOF("unterminated |quoted| symbol"); }
;
/**
@@ -1294,7 +1448,7 @@ datatypeDef[std::vector<CVC4::Datatype>& datatypes, std::vector< CVC4::Type >& p
* datatypes won't work, because this type will already be
* "defined" as an unresolved type; don't worry, we check
* below. */
- : symbol[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(); }
+ : symbol[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(true); }
/* ( '[' symbol[id2,CHECK_UNDECLARED,SYM_SORT] {
t = PARSER_STATE->mkSort(id2);
params.push_back( t );
@@ -1344,7 +1498,8 @@ selector[CVC4::DatatypeConstructor& ctor]
}
: symbol[id,CHECK_UNDECLARED,SYM_SORT] sortSymbol[t,CHECK_NONE]
{ ctor.addArg(id, t);
- Debug("parser-idt") << "selector: " << id.c_str() << std::endl;
+ Debug("parser-idt") << "selector: " << id.c_str()
+ << " of type " << t << std::endl;
}
;
@@ -1389,6 +1544,7 @@ DECLARE_PREDS_TOK : 'declare-preds';
DEFINE_TOK : 'define';
DECLARE_CONST_TOK : 'declare-const';
SIMPLIFY_TOK : 'simplify';
+INCLUDE_TOK : 'include';
// attributes
ATTRIBUTE_PATTERN_TOK : ':pattern';
@@ -1407,6 +1563,7 @@ FORALL_TOK : 'forall';
GREATER_THAN_TOK : '>';
GREATER_THAN_EQUAL_TOK : '>=';
IMPLIES_TOK : '=>';
+IS_INT_TOK : 'is_int';
LESS_THAN_TOK : '<';
LESS_THAN_EQUAL_TOK : '<=';
MINUS_TOK : '-';
@@ -1419,10 +1576,15 @@ SELECT_TOK : 'select';
STAR_TOK : '*';
STORE_TOK : 'store';
// TILDE_TOK : '~';
+TO_INT_TOK : 'to_int';
+TO_REAL_TOK : 'to_real';
XOR_TOK : 'xor';
INTS_DIV_TOK : 'div';
INTS_MOD_TOK : 'mod';
+ABS_TOK : 'abs';
+
+DIVISIBLE_TOK : 'divisible';
CONCAT_TOK : 'concat';
BVNOT_TOK : 'bvnot';
@@ -1453,6 +1615,22 @@ BVSLT_TOK : 'bvslt';
BVSLE_TOK : 'bvsle';
BVSGT_TOK : 'bvsgt';
BVSGE_TOK : 'bvsge';
+BV2NAT_TOK : 'bv2nat';
+INT2BV_TOK : 'int2bv';
+
+//STRING
+//STRCST_TOK : 'str.cst';
+STRCON_TOK : 'str.++';
+STRLEN_TOK : 'str.len';
+//STRSUB_TOK : 'str.sub' ;
+STRINRE_TOK : 'str.in.re';
+STRTORE_TOK : 'str.to.re';
+RECON_TOK : 're.++';
+REOR_TOK : 're.or';
+REINTER_TOK : 're.itr';
+RESTAR_TOK : 're.*';
+REPLUS_TOK : 're.+';
+REOPT_TOK : 're.opt';
/**
* A sequence of printable ASCII characters (except backslash) that starts
@@ -1464,6 +1642,9 @@ BVSGE_TOK : 'bvsge';
QUOTED_SYMBOL
: '|' ~('|' | '\\')* '|'
;
+UNTERMINATED_QUOTED_SYMBOL
+ : '|' ~('|' | '\\')*
+ ;
/**
* Matches a keyword from the input. A keyword is a simple symbol prefixed
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index a7f7796cd..884502cf2 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -19,6 +19,11 @@
#include "parser/parser.h"
#include "parser/smt1/smt1.h"
#include "parser/smt2/smt2.h"
+#include "parser/antlr_input.h"
+
+// ANTLR defines these, which is really bad!
+#undef true
+#undef false
namespace CVC4 {
namespace parser {
@@ -36,7 +41,6 @@ void Smt2::addArithmeticOperators() {
addOperator(kind::MINUS);
addOperator(kind::UMINUS);
addOperator(kind::MULT);
- addOperator(kind::DIVISION);
addOperator(kind::LT);
addOperator(kind::LEQ);
addOperator(kind::GT);
@@ -80,6 +84,15 @@ void Smt2::addBitvectorOperators() {
addOperator(kind::BITVECTOR_SIGN_EXTEND);
addOperator(kind::BITVECTOR_ROTATE_LEFT);
addOperator(kind::BITVECTOR_ROTATE_RIGHT);
+
+ addOperator(kind::INT_TO_BITVECTOR);
+ addOperator(kind::BITVECTOR_TO_NAT);
+}
+
+void Smt2::addStringOperators() {
+ addOperator(kind::STRING_CONCAT);
+ addOperator(kind::STRING_LENGTH);
+ //addOperator(kind::STRING_IN_REGEXP);
}
void Smt2::addTheory(Theory theory) {
@@ -106,22 +119,36 @@ void Smt2::addTheory(Theory theory) {
case THEORY_REALS_INTS:
defineType("Real", getExprManager()->realType());
- // falling-through on purpose, to add Ints part of RealsInts
+ addOperator(kind::DIVISION);
+ addOperator(kind::TO_INTEGER);
+ addOperator(kind::IS_INTEGER);
+ addOperator(kind::TO_REAL);
+ // falling through on purpose, to add Ints part of Reals_Ints
case THEORY_INTS:
defineType("Int", getExprManager()->integerType());
addArithmeticOperators();
+ addOperator(kind::INTS_DIVISION);
+ addOperator(kind::INTS_MODULUS);
+ addOperator(kind::ABS);
+ addOperator(kind::DIVISIBLE);
break;
case THEORY_REALS:
defineType("Real", getExprManager()->realType());
addArithmeticOperators();
+ addOperator(kind::DIVISION);
break;
case THEORY_BITVECTORS:
addBitvectorOperators();
break;
+ case THEORY_STRINGS:
+ defineType("String", getExprManager()->stringType());
+ addStringOperators();
+ break;
+
case THEORY_QUANTIFIERS:
break;
@@ -138,135 +165,41 @@ bool Smt2::logicIsSet() {
void Smt2::setLogic(const std::string& name) {
d_logicSet = true;
- d_logic = Smt1::toLogic(name);
+ d_logic = name;
// Core theory belongs to every logic
addTheory(THEORY_CORE);
- switch(d_logic) {
- case Smt1::QF_SAT:
- /* No extra symbols necessary */
- break;
-
- case Smt1::QF_AX:
- addTheory(THEORY_ARRAYS);
- break;
-
- case Smt1::QF_IDL:
- case Smt1::QF_LIA:
- case Smt1::QF_NIA:
- addTheory(THEORY_INTS);
- break;
-
- case Smt1::QF_RDL:
- case Smt1::QF_LRA:
- case Smt1::QF_NRA:
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_UF:
- addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFIDL:
- case Smt1::QF_UFLIA:
- case Smt1::QF_UFNIA:// nonstandard logic
- addTheory(THEORY_INTS);
- addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFLRA:
- case Smt1::QF_UFNRA:
- addTheory(THEORY_REALS);
+ if(d_logic.isTheoryEnabled(theory::THEORY_UF)) {
addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFLIRA:// nonstandard logic
- case Smt1::QF_UFNIRA:// nonstandard logic
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_BV:
- addTheory(THEORY_BITVECTORS);
- break;
-
- case Smt1::QF_ABV:
- addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- break;
-
- case Smt1::QF_UFBV:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_BITVECTORS);
- break;
+ }
- case Smt1::QF_AUFBV:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- break;
+ if(d_logic.isTheoryEnabled(theory::THEORY_ARITH)) {
+ if(d_logic.areIntegersUsed()) {
+ if(d_logic.areRealsUsed()) {
+ addTheory(THEORY_REALS_INTS);
+ } else {
+ addTheory(THEORY_INTS);
+ }
+ } else if(d_logic.areRealsUsed()) {
+ addTheory(THEORY_REALS);
+ }
+ }
- case Smt1::QF_AUFBVLIA:
- addOperator(kind::APPLY_UF);
+ if(d_logic.isTheoryEnabled(theory::THEORY_ARRAY)) {
addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- addTheory(THEORY_INTS);
- break;
+ }
- case Smt1::QF_AUFBVLRA:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_ARRAYS);
+ if(d_logic.isTheoryEnabled(theory::THEORY_BV)) {
addTheory(THEORY_BITVECTORS);
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_AUFLIA:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- break;
-
- case Smt1::QF_AUFLIRA:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- break;
+ }
- case Smt1::ALL_SUPPORTED:
- addTheory(THEORY_QUANTIFIERS);
- /* fall through */
- case Smt1::QF_ALL_SUPPORTED:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- addTheory(THEORY_BITVECTORS);
- break;
+ if(d_logic.isTheoryEnabled(theory::THEORY_STRINGS)) {
+ addTheory(THEORY_STRINGS);
+ }
- case Smt1::AUFLIA:
- case Smt1::AUFLIRA:
- case Smt1::AUFNIRA:
- case Smt1::LRA:
- case Smt1::UFNIA:
- case Smt1::UFNIRA:
- case Smt1::UFLRA:
- if(d_logic != Smt1::AUFLIA && d_logic != Smt1::UFNIA) {
- addTheory(THEORY_REALS);
- }
- if(d_logic != Smt1::LRA) {
- addOperator(kind::APPLY_UF);
- if(d_logic != Smt1::UFLRA) {
- addTheory(THEORY_INTS);
- if(d_logic != Smt1::UFNIA && d_logic != Smt1::UFNIRA) {
- addTheory(THEORY_ARRAYS);
- }
- }
- }
+ if(d_logic.isQuantified()) {
addTheory(THEORY_QUANTIFIERS);
- break;
}
}/* Smt2::setLogic() */
@@ -297,5 +230,65 @@ void Smt2::checkThatLogicIsSet() {
}
}
+/* The include are managed in the lexer but called in the parser */
+// Inspired by http://www.antlr3.org/api/C/interop.html
+
+static bool newInputStream(const std::string& filename, pANTLR3_LEXER lexer) {
+ Debug("parser") << "Including " << filename << std::endl;
+ // Create a new input stream and take advantage of built in stream stacking
+ // in C target runtime.
+ //
+ pANTLR3_INPUT_STREAM in;
+#ifdef CVC4_ANTLR3_OLD_INPUT_STREAM
+ in = antlr3AsciiFileStreamNew((pANTLR3_UINT8) filename.c_str());
+#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
+ in = antlr3FileStreamNew((pANTLR3_UINT8) filename.c_str(), ANTLR3_ENC_8BIT);
+#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
+ if( in == NULL ) {
+ Debug("parser") << "Can't open " << filename << std::endl;
+ return false;
+ }
+ // Same thing as the predefined PUSHSTREAM(in);
+ lexer->pushCharStream(lexer, in);
+ // restart it
+ //lexer->rec->state->tokenStartCharIndex = -10;
+ //lexer->emit(lexer);
+
+ // Note that the input stream is not closed when it EOFs, I don't bother
+ // to do it here, but it is up to you to track streams created like this
+ // and destroy them when the whole parse session is complete. Remember that you
+ // don't want to do this until all tokens have been manipulated all the way through
+ // your tree parsers etc as the token does not store the text it just refers
+ // back to the input stream and trying to get the text for it will abort if you
+ // close the input stream too early.
+
+ //TODO what said before
+ return true;
+}
+
+void Smt2::includeFile(const std::string& filename) {
+ // security for online version
+ if(!canIncludeFile()) {
+ parseError("include-file feature was disabled for this run.");
+ }
+
+ // Get the lexer
+ AntlrInput* ai = static_cast<AntlrInput*>(getInput());
+ pANTLR3_LEXER lexer = ai->getAntlr3Lexer();
+ // get the name of the current stream "Does it work inside an include?"
+ const std::string inputName = ai->getInputStreamName();
+
+ // Find the directory of the current input file
+ std::string path;
+ size_t pos = inputName.rfind('/');
+ if(pos != std::string::npos) {
+ path = std::string(inputName, 0, pos + 1);
+ }
+ path.append(filename);
+ if(!newInputStream(path, lexer)) {
+ parseError("Couldn't open include file `" + path + "'");
+ }
+}
+
}/* CVC4::parser namespace */
}/* CVC4 namespace */
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 5762ff5f9..cc46efe07 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -21,6 +21,7 @@
#include "parser/parser.h"
#include "parser/smt1/smt1.h"
+#include "theory/logic_info.h"
#include "util/abstract_value.h"
#include <sstream>
@@ -43,11 +44,12 @@ public:
THEORY_REALS,
THEORY_REALS_INTS,
THEORY_QUANTIFIERS,
+ THEORY_STRINGS
};
private:
bool d_logicSet;
- Smt1::Logic d_logic;
+ LogicInfo d_logic;
protected:
Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -84,6 +86,8 @@ public:
}
}
+ void includeFile(const std::string& filename);
+
bool isAbstractValue(const std::string& name) {
return name.length() >= 2 && name[0] == '@' && name[1] != '0' &&
name.find_first_not_of("0123456789", 1) == std::string::npos;
@@ -94,12 +98,38 @@ public:
return getExprManager()->mkConst(AbstractValue(Integer(name.substr(1))));
}
+ /**
+ * Smt2 parser provides its own checkDeclaration, which does the
+ * same as the base, but with some more helpful errors.
+ */
+ void checkDeclaration(const std::string& name, DeclarationCheck check,
+ SymbolType type = SYM_VARIABLE,
+ std::string notes = "") throw(ParserException) {
+ // if the symbol is something like "-1", we'll give the user a helpful
+ // syntax hint. (-1 is a valid identifier in SMT-LIB, NOT unary minus.)
+ if( check != CHECK_DECLARED ||
+ name[0] != '-' ||
+ name.find_first_not_of("0123456789", 1) != std::string::npos ) {
+ this->Parser::checkDeclaration(name, check, type, notes);
+ return;
+ }
+
+ std::stringstream ss;
+ ss << notes
+ << "You may have intended to apply unary minus: `(- "
+ << name.substr(1)
+ << ")'\n";
+ this->Parser::checkDeclaration(name, check, type, ss.str());
+ }
+
private:
void addArithmeticOperators();
void addBitvectorOperators();
+ void addStringOperators();
+
};/* class Smt2 */
}/* CVC4::parser namespace */
diff --git a/src/parser/tptp/Tptp.g b/src/parser/tptp/Tptp.g
index 9e814b358..61e0999e9 100644
--- a/src/parser/tptp/Tptp.g
+++ b/src/parser/tptp/Tptp.g
@@ -27,7 +27,7 @@ options {
// Only lookahead of <= k requested (disable for LL* parsing)
// Note that CVC4's BoundedTokenBuffer requires a fixed k !
// If you change this k, change it also in tptp_input.cpp !
- k = 1;
+ k = 2;
}/* options */
@header {
@@ -102,6 +102,8 @@ using namespace CVC4::parser;
#include "util/output.h"
#include "util/rational.h"
#include <vector>
+#include <iterator>
+#include <algorithm>
using namespace CVC4;
using namespace CVC4::parser;
@@ -114,12 +116,12 @@ using namespace CVC4::parser;
#define EXPR_MANAGER PARSER_STATE->getExprManager()
#undef MK_EXPR
#define MK_EXPR EXPR_MANAGER->mkExpr
+#undef MK_EXPR_ASSOCIATIVE
+#define MK_EXPR_ASSOCIATIVE EXPR_MANAGER->mkAssociative
#undef MK_CONST
#define MK_CONST EXPR_MANAGER->mkConst
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
-
-
}/* parser::postinclude */
/**
@@ -139,46 +141,81 @@ parseCommand returns [CVC4::Command* cmd = NULL]
@declarations {
Expr expr;
Tptp::FormulaRole fr;
- std::string name;
- std::string incl_args;
+ std::string name, inclSymbol;
}
// : LPAREN_TOK c = command RPAREN_TOK { $cmd = c; }
: CNF_TOK LPAREN_TOK nameN[name] COMMA_TOK formulaRole[fr] COMMA_TOK
- { PARSER_STATE->cnf=true; PARSER_STATE->pushScope(); }
+ { PARSER_STATE->cnf = true; PARSER_STATE->fof = false; PARSER_STATE->pushScope(); }
cnfFormula[expr]
{ PARSER_STATE->popScope();
std::vector<Expr> bvl = PARSER_STATE->getFreeVar();
- if(!bvl.empty()){
+ if(!bvl.empty()) {
expr = MK_EXPR(kind::FORALL,MK_EXPR(kind::BOUND_VAR_LIST,bvl),expr);
};
}
(COMMA_TOK anything*)? RPAREN_TOK DOT_TOK
{
- cmd = PARSER_STATE->makeCommand(fr,expr);
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ true);
}
| FOF_TOK LPAREN_TOK nameN[name] COMMA_TOK formulaRole[fr] COMMA_TOK
- { PARSER_STATE->cnf=false; }
+ { PARSER_STATE->cnf = false; PARSER_STATE->fof = true; }
fofFormula[expr] (COMMA_TOK anything*)? RPAREN_TOK DOT_TOK
{
- cmd = PARSER_STATE->makeCommand(fr,expr);
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ false);
}
+ | TFF_TOK LPAREN_TOK nameN[name] COMMA_TOK
+ ( TYPE_TOK COMMA_TOK tffTypedAtom[cmd]
+ | formulaRole[fr] COMMA_TOK
+ { PARSER_STATE->cnf = false; PARSER_STATE->fof = false; }
+ tffFormula[expr] (COMMA_TOK anything*)?
+ {
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ false);
+ }
+ ) RPAREN_TOK DOT_TOK
| INCLUDE_TOK LPAREN_TOK unquotedFileName[name]
- ( COMMA_TOK LBRACK_TOK nameN[incl_args] ( COMMA_TOK nameN[incl_args] )* RBRACK_TOK )?
+ ( COMMA_TOK LBRACK_TOK nameN[inclSymbol]
+ ( COMMA_TOK nameN[inclSymbol] )* RBRACK_TOK )?
RPAREN_TOK DOT_TOK
- {
- PARSER_STATE->includeFile(name);
- // The command of the included file will be produce at the new parseCommand call
+ { /* TODO - implement symbol filtering for file inclusion.
+ * the following removes duplicates and "all", just need to pass it
+ * through to includeFile() and implement it there.
+ std::sort(inclArgs.begin(), inclArgs.end());
+ std::vector<std::string>::iterator it =
+ std::unique(inclArgs.begin(), inclArgs.end());
+ inclArgs.resize(std::distance(inclArgs.begin(), it));
+ it = std::lower_bound(inclArgs.begin(), inclArgs.end(), std::string("all"));
+ if(it != inclArgs.end() && *it == "all") {
+ inclArgs.erase(it);
+ }
+ */
+ PARSER_STATE->includeFile(name /* , inclArgs */ );
+ // The command of the included file will be produced at the next parseCommand() call
cmd = new EmptyCommand("include::" + name);
}
| EOF
{
- PARSER_STATE->preemptCommand(new CheckSatCommand(MK_CONST(bool(true))));
+ std::string filename = PARSER_STATE->getInput()->getInputStreamName();
+ size_t i = filename.find_last_of('/');
+ if(i != std::string::npos) {
+ filename = filename.substr(i + 1);
+ }
+ if(filename.substr(filename.length() - 2) == ".p") {
+ filename = filename.substr(0, filename.length() - 2);
+ }
+ CommandSequence* seq = new CommandSequence();
+ seq->addCommand(new SetInfoCommand("name", filename));
+ if(PARSER_STATE->hasConjecture()) {
+ seq->addCommand(new QueryCommand(MK_CONST(bool(false))));
+ } else {
+ seq->addCommand(new CheckSatCommand());
+ }
+ PARSER_STATE->preemptCommand(seq);
cmd = NULL;
}
;
/* Parse a formula Role */
-formulaRole[CVC4::parser::Tptp::FormulaRole & role]
+formulaRole[CVC4::parser::Tptp::FormulaRole& role]
: LOWER_WORD
{
std::string r = AntlrInput::tokenText($LOWER_WORD);
@@ -204,33 +241,30 @@ formulaRole[CVC4::parser::Tptp::FormulaRole & role]
/* CNF */
/* It can parse a little more than the cnf grammar: false and true can appear.
- Normally only false can appear and only at top level
-*/
+ * Normally only false can appear and only at top level. */
cnfFormula[CVC4::Expr& expr]
- :
- LPAREN_TOK disjunction[expr] RPAREN_TOK
-| disjunction[expr]
+ : LPAREN_TOK cnfDisjunction[expr] RPAREN_TOK
+ | cnfDisjunction[expr]
//| FALSE_TOK { expr = MK_CONST(bool(false)); }
;
-disjunction[CVC4::Expr& expr]
+cnfDisjunction[CVC4::Expr& expr]
@declarations {
std::vector<Expr> args;
}
- :
- literal[expr] {args.push_back(expr); } ( OR_TOK literal[expr] {args.push_back(expr); } )*
- {
- if(args.size() > 1){
- expr = MK_EXPR(kind::OR,args);
+ : cnfLiteral[expr] { args.push_back(expr); }
+ ( OR_TOK cnfLiteral[expr] { args.push_back(expr); } )*
+ { if(args.size() > 1) {
+ expr = MK_EXPR_ASSOCIATIVE(kind::OR, args);
} // else its already in the expr
}
;
-literal[CVC4::Expr& expr]
+cnfLiteral[CVC4::Expr& expr]
: atomicFormula[expr]
- | NOT_TOK atomicFormula[expr] { expr = MK_EXPR(kind::NOT,expr); }
-// | folInfixUnary[expr]
+ | NOT_TOK atomicFormula[expr] { expr = MK_EXPR(kind::NOT, expr); }
+//| folInfixUnary[expr]
;
atomicFormula[CVC4::Expr& expr]
@@ -241,28 +275,32 @@ atomicFormula[CVC4::Expr& expr]
bool equal;
}
: atomicWord[name] (LPAREN_TOK arguments[args] RPAREN_TOK)?
- ( ( equalOp[equal] //equality/disequality between terms
- {
- PARSER_STATE->makeApplication(expr,name,args,true);
- }
- term[expr2]
- {
- expr = MK_EXPR(kind::EQUAL, expr, expr2);
- if(!equal) expr = MK_EXPR(kind::NOT,expr);
- }
- )
- | //predicate
- {
- PARSER_STATE->makeApplication(expr,name,args,false);
+ ( equalOp[equal] term[expr2]
+ { // equality/disequality between terms
+ PARSER_STATE->makeApplication(expr, name, args, true);
+ expr = MK_EXPR(kind::EQUAL, expr, expr2);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
}
- )
- | simpleTerm[expr] equalOp[equal] term[expr2]
- {
+ | { // predicate
+ PARSER_STATE->makeApplication(expr, name, args, false);
+ }
+ )
+ | definedFun[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ equalOp[equal] term[expr2]
+ { expr = EXPR_MANAGER->mkExpr(expr, args);
+ expr = MK_EXPR(kind::EQUAL, expr, expr2);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
+ }
+ | (simpleTerm[expr] | letTerm[expr] | conditionalTerm[expr])
+ equalOp[equal] term[expr2]
+ { // equality/disequality between terms
expr = MK_EXPR(kind::EQUAL, expr, expr2);
- if(!equal) expr = MK_EXPR(kind::NOT,expr);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
}
+ | definedPred[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(expr, args); }
| definedProp[expr]
-;
+ ;
//%----Using <plain_term> removes a reduce/reduce ambiguity in lex/yacc.
//%----Note: "defined" means a word starting with one $ and "system" means $$.
@@ -270,35 +308,170 @@ definedProp[CVC4::Expr& expr]
: TRUE_TOK { expr = MK_CONST(bool(true)); }
| FALSE_TOK { expr = MK_CONST(bool(false)); }
;
+
+definedPred[CVC4::Expr& expr]
+ : '$less' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::LT); }
+ | '$lesseq' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::LEQ); }
+ | '$greater' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::GT); }
+ | '$greatereq' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::GEQ); }
+ | '$is_rat' // all "real" are actually "rat" in CVC4
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ n = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::LAMBDA, n, MK_CONST(bool(true)));
+ }
+ | '$is_int' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::IS_INTEGER); }
+ | '$distinct' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::DISTINCT); }
+ ;
+
+definedFun[CVC4::Expr& expr]
+@declarations {
+ bool remainder = false;
+}
+ : '$uminus' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::UMINUS); }
+ | '$sum' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::PLUS); }
+ | '$difference' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::MINUS); }
+ | '$product' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::MULT); }
+ | '$quotient' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::DIVISION_TOTAL); }
+ | ( '$quotient_e' { remainder = false; }
+ | '$remainder_e' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, d, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, expr),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, expr))));
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | ( '$quotient_t' { remainder = false; }
+ | '$remainder_t' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, expr, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, expr),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, expr))));
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | ( '$quotient_f' { remainder = false; }
+ | '$remainder_f' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::TO_INTEGER, expr);
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$floor' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_INTEGER); }
+ | '$ceiling'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, n)));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$truncate'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, n, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, n),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, n))));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$round'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ Expr decPart = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::TO_INTEGER, n));
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::LT, decPart, MK_CONST(Rational(1, 2))),
+ // if decPart < 0.5, round down
+ MK_EXPR(CVC4::kind::TO_INTEGER, n),
+ MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GT, decPart, MK_CONST(Rational(1, 2))),
+ // if decPart > 0.5, round up
+ MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::PLUS, n, MK_CONST(Rational(1)))),
+ // if decPart == 0.5, round to nearest even integer:
+ // result is: to_int(n/2 + .5) * 2
+ MK_EXPR(CVC4::kind::MULT, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::PLUS, MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, MK_CONST(Rational(2))), MK_CONST(Rational(1, 2)))), MK_CONST(Rational(2)))));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$to_int' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_INTEGER); }
+ | '$to_rat' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_REAL); }
+ | '$to_real' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_REAL); }
+ ;
+
//%----Pure CNF should not use $true or $false in problems, and use $false only
//%----at the roots of a refutation.
-equalOp[bool & equal]
- : EQUAL_TOK {equal = true;}
- | DISEQUAL_TOK {equal = false;}
+equalOp[bool& equal]
+ : EQUAL_TOK { equal = true; }
+ | DISEQUAL_TOK { equal = false; }
;
term[CVC4::Expr& expr]
- : functionTerm[expr]
+ : functionTerm[expr]
+ | conditionalTerm[expr]
| simpleTerm[expr]
-// | conditionalTerm
-// | let_term
+ | letTerm[expr]
+ ;
+
+letTerm[CVC4::Expr& expr]
+@declarations {
+ CVC4::Expr lhs, rhs;
+}
+ : '$let_ft' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetFormulaDefn[lhs, rhs] COMMA_TOK
+ term[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ | '$let_tt' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetTermDefn[lhs, rhs] COMMA_TOK
+ term[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
;
/* Not an application */
simpleTerm[CVC4::Expr& expr]
: variable[expr]
| NUMBER { expr = PARSER_STATE->d_tmp_expr; }
- | DISTINCT_OBJECT { expr = PARSER_STATE->convertStrToUnsorted(
- AntlrInput::tokenText($DISTINCT_OBJECT)); }
-;
+ | DISTINCT_OBJECT { expr = PARSER_STATE->convertStrToUnsorted(AntlrInput::tokenText($DISTINCT_OBJECT)); }
+ ;
functionTerm[CVC4::Expr& expr]
- : plainTerm[expr] // | <defined_term> | <system_term>
+@declarations {
+ std::vector<CVC4::Expr> args;
+}
+ : plainTerm[expr]
+ | definedFun[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(expr, args); }
+// | <system_term>
+ ;
+
+conditionalTerm[CVC4::Expr& expr]
+@declarations {
+ CVC4::Expr expr2, expr3;
+}
+ : '$ite_t' LPAREN_TOK tffLogicFormula[expr] COMMA_TOK term[expr2] COMMA_TOK term[expr3] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(CVC4::kind::ITE, expr, expr2, expr3); }
;
plainTerm[CVC4::Expr& expr]
-@declarations{
+@declarations {
std::string name;
std::vector<Expr> args;
}
@@ -308,19 +481,19 @@ plainTerm[CVC4::Expr& expr]
}
;
-arguments[std::vector<CVC4::Expr> & args]
-@declarations{
+arguments[std::vector<CVC4::Expr>& args]
+@declarations {
Expr expr;
}
:
term[expr] { args.push_back(expr); } ( COMMA_TOK term[expr] { args.push_back(expr); } )*
;
-variable[CVC4::Expr & expr]
+variable[CVC4::Expr& expr]
: UPPER_WORD
{
std::string name = AntlrInput::tokenText($UPPER_WORD);
- if(!PARSER_STATE->cnf || PARSER_STATE->isDeclared(name)){
+ if(!PARSER_STATE->cnf || PARSER_STATE->isDeclared(name)) {
expr = PARSER_STATE->getVariable(name);
} else {
expr = PARSER_STATE->mkBoundVar(name, PARSER_STATE->d_unsorted);
@@ -331,18 +504,18 @@ variable[CVC4::Expr & expr]
/*******/
/* FOF */
-fofFormula[CVC4::Expr & expr] : fofLogicFormula[expr] ;
+fofFormula[CVC4::Expr& expr] : fofLogicFormula[expr] ;
-fofLogicFormula[CVC4::Expr & expr]
-@declarations{
+fofLogicFormula[CVC4::Expr& expr]
+@declarations {
tptp::NonAssoc na;
std::vector< Expr > args;
Expr expr2;
}
: fofUnitaryFormula[expr]
- ( //Non Assoc <=> <~> ~& ~|
+ ( // Non-associative: <=> <~> ~& ~|
( fofBinaryNonAssoc[na] fofUnitaryFormula[expr2]
- { switch(na){
+ { switch(na) {
case tptp::NA_IFF:
expr = MK_EXPR(kind::IFF,expr,expr2);
break;
@@ -364,21 +537,21 @@ fofLogicFormula[CVC4::Expr & expr]
}
}
)
- | //And &
+ | // N-ary and &
( { args.push_back(expr); }
( AND_TOK fofUnitaryFormula[expr] { args.push_back(expr); } )+
- { expr = MK_EXPR(kind::AND,args); }
+ { expr = MK_EXPR_ASSOCIATIVE(kind::AND, args); }
)
- | //Or |
+ | // N-ary or |
( { args.push_back(expr); }
( OR_TOK fofUnitaryFormula[expr] { args.push_back(expr); } )+
- { expr = MK_EXPR(kind::OR,args); }
+ { expr = MK_EXPR_ASSOCIATIVE(kind::OR, args); }
)
- )?
+ )?
;
-fofUnitaryFormula[CVC4::Expr & expr]
-@declarations{
+fofUnitaryFormula[CVC4::Expr& expr]
+@declarations {
Kind kind;
std::vector< Expr > bv;
}
@@ -389,20 +562,20 @@ fofUnitaryFormula[CVC4::Expr & expr]
folQuantifier[kind] LBRACK_TOK {PARSER_STATE->pushScope();}
( bindvariable[expr] { bv.push_back(expr); }
( COMMA_TOK bindvariable[expr] { bv.push_back(expr); } )* ) RBRACK_TOK
- COLON_TOK fofUnitaryFormula[expr]
- { PARSER_STATE->popScope();
- expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
- } ;
+ COLON_TOK fofUnitaryFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
+ }
+ ;
-bindvariable[CVC4::Expr & expr]
+bindvariable[CVC4::Expr& expr]
: UPPER_WORD
- {
- std::string name = AntlrInput::tokenText($UPPER_WORD);
+ { std::string name = AntlrInput::tokenText($UPPER_WORD);
expr = PARSER_STATE->mkBoundVar(name, PARSER_STATE->d_unsorted);
}
- ;
+ ;
-fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc & na]
+fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc& na]
: IFF_TOK { na = tptp::NA_IFF; }
| REVIFF_TOK { na = tptp::NA_REVIFF; }
| REVOR_TOK { na = tptp::NA_REVOR; }
@@ -411,11 +584,229 @@ fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc & na]
| REVIMPLIES_TOK { na = tptp::NA_REVIMPLIES; }
;
-folQuantifier[CVC4::Kind & kind]
+folQuantifier[CVC4::Kind& kind]
: BANG_TOK { kind = kind::FORALL; }
| MARK_TOK { kind = kind::EXISTS; }
;
+/*******/
+/* TFF */
+tffFormula[CVC4::Expr& expr] : tffLogicFormula[expr];
+
+tffTypedAtom[CVC4::Command*& cmd]
+@declarations {
+ CVC4::Expr expr;
+ CVC4::Type type;
+ std::string name;
+}
+ : LPAREN_TOK tffTypedAtom[cmd] RPAREN_TOK
+ | nameN[name] COLON_TOK
+ ( '$tType'
+ { if(PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ // duplicate declaration is fine, they're compatible
+ cmd = new EmptyCommand("compatible redeclaration of sort " + name);
+ } else if(PARSER_STATE->isDeclared(name, SYM_VARIABLE)) {
+ // error: cannot be both sort and constant
+ PARSER_STATE->parseError("Symbol `" + name + "' previously declared as a constant; cannot also be a sort");
+ } else {
+ // as yet, it's undeclared
+ Type type = PARSER_STATE->mkSort(name);
+ cmd = new DeclareTypeCommand(name, 0, type);
+ }
+ }
+ | parseType[type]
+ { if(PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ // error: cannot be both sort and constant
+ PARSER_STATE->parseError("Symbol `" + name + "' previously declared as a sort");
+ cmd = new EmptyCommand("compatible redeclaration of sort " + name);
+ } else if(PARSER_STATE->isDeclared(name, SYM_VARIABLE)) {
+ if(type == PARSER_STATE->getVariable(name).getType()) {
+ // duplicate declaration is fine, they're compatible
+ cmd = new EmptyCommand("compatible redeclaration of constant " + name);
+ } else {
+ // error: sorts incompatible
+ PARSER_STATE->parseError("Symbol `" + name + "' declared previously with a different sort");
+ }
+ } else {
+ // as yet, it's undeclared
+ CVC4::Expr expr;
+ if(type.isFunction()) {
+ expr = PARSER_STATE->mkFunction(name, type);
+ } else {
+ expr = PARSER_STATE->mkVar(name, type);
+ }
+ cmd = new DeclareFunctionCommand(name, expr, type);
+ }
+ }
+ )
+ ;
+
+tffLogicFormula[CVC4::Expr& expr]
+@declarations {
+ tptp::NonAssoc na;
+ std::vector< Expr > args;
+ Expr expr2;
+}
+ : tffUnitaryFormula[expr]
+ ( // Non Assoc <=> <~> ~& ~|
+ ( fofBinaryNonAssoc[na] tffUnitaryFormula[expr2]
+ { switch(na) {
+ case tptp::NA_IFF:
+ expr = MK_EXPR(kind::IFF,expr,expr2);
+ break;
+ case tptp::NA_REVIFF:
+ expr = MK_EXPR(kind::XOR,expr,expr2);
+ break;
+ case tptp::NA_IMPLIES:
+ expr = MK_EXPR(kind::IMPLIES,expr,expr2);
+ break;
+ case tptp::NA_REVIMPLIES:
+ expr = MK_EXPR(kind::IMPLIES,expr2,expr);
+ break;
+ case tptp::NA_REVOR:
+ expr = MK_EXPR(kind::NOT,MK_EXPR(kind::OR,expr,expr2));
+ break;
+ case tptp::NA_REVAND:
+ expr = MK_EXPR(kind::NOT,MK_EXPR(kind::AND,expr,expr2));
+ break;
+ }
+ }
+ )
+ | // And &
+ ( { args.push_back(expr); }
+ ( AND_TOK tffUnitaryFormula[expr] { args.push_back(expr); } )+
+ { expr = MK_EXPR(kind::AND,args); }
+ )
+ | // Or |
+ ( { args.push_back(expr); }
+ ( OR_TOK tffUnitaryFormula[expr] { args.push_back(expr); } )+
+ { expr = MK_EXPR(kind::OR,args); }
+ )
+ )?
+ ;
+
+tffUnitaryFormula[CVC4::Expr& expr]
+@declarations {
+ Kind kind;
+ std::vector< Expr > bv;
+ Expr lhs, rhs;
+}
+ : atomicFormula[expr]
+ | LPAREN_TOK tffLogicFormula[expr] RPAREN_TOK
+ | NOT_TOK tffUnitaryFormula[expr] { expr = MK_EXPR(kind::NOT,expr); }
+ | // Quantified
+ folQuantifier[kind] LBRACK_TOK {PARSER_STATE->pushScope();}
+ ( tffbindvariable[expr] { bv.push_back(expr); }
+ ( COMMA_TOK tffbindvariable[expr] { bv.push_back(expr); } )* ) RBRACK_TOK
+ COLON_TOK tffUnitaryFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
+ }
+ | '$ite_f' LPAREN_TOK tffLogicFormula[expr] COMMA_TOK tffLogicFormula[lhs] COMMA_TOK tffLogicFormula[rhs] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(CVC4::kind::ITE, expr, lhs, rhs); }
+ | '$let_tf' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetTermDefn[lhs, rhs] COMMA_TOK
+ tffFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ | '$let_ff' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetFormulaDefn[lhs, rhs] COMMA_TOK
+ tffFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ ;
+
+tffLetTermDefn[CVC4::Expr& lhs, CVC4::Expr& rhs]
+@declarations {
+ std::vector<CVC4::Expr> bvlist;
+}
+ : (BANG_TOK LBRACK_TOK tffVariableList[bvlist] RBRACK_TOK COLON_TOK)*
+ tffLetTermBinding[bvlist, lhs, rhs]
+ ;
+
+tffLetTermBinding[std::vector<CVC4::Expr>& bvlist, CVC4::Expr& lhs, CVC4::Expr& rhs]
+ : term[lhs] EQUAL_TOK term[rhs]
+ { PARSER_STATE->checkLetBinding(bvlist, lhs, rhs, false);
+ rhs = MK_EXPR(CVC4::kind::LAMBDA, MK_EXPR(CVC4::kind::BOUND_VAR_LIST, lhs.getChildren()), rhs);
+ lhs = lhs.getOperator();
+ }
+ | LPAREN_TOK tffLetTermBinding[bvlist, lhs, rhs] RPAREN_TOK
+ ;
+
+tffLetFormulaDefn[CVC4::Expr& lhs, CVC4::Expr& rhs]
+@declarations {
+ std::vector<CVC4::Expr> bvlist;
+}
+ : (BANG_TOK LBRACK_TOK tffVariableList[bvlist] RBRACK_TOK COLON_TOK)*
+ tffLetFormulaBinding[bvlist, lhs, rhs]
+ ;
+
+tffLetFormulaBinding[std::vector<CVC4::Expr>& bvlist, CVC4::Expr& lhs, CVC4::Expr& rhs]
+ : atomicFormula[lhs] IFF_TOK tffUnitaryFormula[rhs]
+ { PARSER_STATE->checkLetBinding(bvlist, lhs, rhs, true);
+ rhs = MK_EXPR(CVC4::kind::LAMBDA, MK_EXPR(CVC4::kind::BOUND_VAR_LIST, lhs.getChildren()), rhs);
+ lhs = lhs.getOperator();
+ }
+ | LPAREN_TOK tffLetFormulaBinding[bvlist, lhs, rhs] RPAREN_TOK
+ ;
+
+tffbindvariable[CVC4::Expr& expr]
+@declarations {
+ CVC4::Type type = PARSER_STATE->d_unsorted;
+}
+ : UPPER_WORD
+ ( COLON_TOK parseType[type] )?
+ { std::string name = AntlrInput::tokenText($UPPER_WORD);
+ expr = PARSER_STATE->mkBoundVar(name, type);
+ }
+ ;
+
+// bvlist is accumulative; it can already contain elements
+// on the way in, which are left undisturbed
+tffVariableList[std::vector<CVC4::Expr>& bvlist]
+@declarations {
+ CVC4::Expr e;
+}
+ : tffbindvariable[e] { bvlist.push_back(e); }
+ ( COMMA_TOK tffbindvariable[e] { bvlist.push_back(e); } )*
+ ;
+
+parseType[CVC4::Type& type]
+@declarations {
+ std::vector<CVC4::Type> v;
+}
+ : simpleType[type]
+ | ( simpleType[type] { v.push_back(type); }
+ | LPAREN_TOK simpleType[type] { v.push_back(type); }
+ ( TIMES_TOK simpleType[type] { v.push_back(type); } )+
+ RPAREN_TOK
+ )
+ GREATER_TOK simpleType[type]
+ { v.push_back(type);
+ type = EXPR_MANAGER->mkFunctionType(v);
+ }
+ ;
+
+// non-function types
+simpleType[CVC4::Type& type]
+ : DEFINED_SYMBOL
+ { std::string s = AntlrInput::tokenText($DEFINED_SYMBOL);
+ if(s == "\$i") type = PARSER_STATE->d_unsorted;
+ else if(s == "\$o") type = EXPR_MANAGER->booleanType();
+ else if(s == "\$int") type = EXPR_MANAGER->integerType();
+ else if(s == "\$rat") type = EXPR_MANAGER->realType();
+ else if(s == "\$real") type = EXPR_MANAGER->realType();
+ else if(s == "\$tType") PARSER_STATE->parseError("Type of types `\$tType' cannot be used here");
+ else PARSER_STATE->parseError("unknown defined type `" + s + "'");
+ }
+ | LOWER_WORD
+ { type = PARSER_STATE->getSort(AntlrInput::tokenText($LOWER_WORD)); }
+ ;
+
/***********************************************/
/* Anything well parenthesis */
@@ -447,6 +838,7 @@ anything
| FOF_TOK
| THF_TOK
| TFF_TOK
+ | TYPE_TOK
| INCLUDE_TOK
| DISTINCT_OBJECT
| UPPER_WORD
@@ -467,6 +859,8 @@ LBRACK_TOK : '[';
RBRACK_TOK : ']';
COLON_TOK : ':';
+GREATER_TOK : '>';
+
//operator
OR_TOK : '|';
NOT_TOK : '~';
@@ -494,6 +888,7 @@ CNF_TOK : 'cnf';
FOF_TOK : 'fof';
THF_TOK : 'thf';
TFF_TOK : 'tff';
+TYPE_TOK : 'type';
INCLUDE_TOK : 'include';
//Other defined symbols, must be defined after all the other
@@ -533,30 +928,30 @@ UPPER_WORD : UPPER_ALPHA ALPHA_NUMERIC*;
LOWER_WORD : LOWER_ALPHA ALPHA_NUMERIC*;
/* filename */
-unquotedFileName[std::string & name] /* Beware fileName identifier is used by the backend ... */
+unquotedFileName[std::string& name] /* Beware fileName identifier is used by the backend ... */
: (s=LOWER_WORD_SINGLE_QUOTED | s=SINGLE_QUOTED)
{ name = AntlrInput::tokenText($s);
name = name.substr(1, name.size() - 2 );
};
/* axiom name */
-nameN[std::string & name]
+nameN[std::string& name]
: atomicWord[name]
| NUMBER { name = AntlrInput::tokenText($NUMBER); }
;
/* atomic word everything (fof, cnf, thf, tff, include must not be keyword at this position ) */
-atomicWord[std::string & name]
+atomicWord[std::string& name]
: FOF_TOK { name = "fof"; }
| CNF_TOK { name = "cnf"; }
| THF_TOK { name = "thf"; }
| TFF_TOK { name = "tff"; }
+ | TYPE_TOK { name = "type"; }
| INCLUDE_TOK { name = "include"; }
| LOWER_WORD { name = AntlrInput::tokenText($LOWER_WORD); }
- | LOWER_WORD_SINGLE_QUOTED //the lower word single quoted are considered without quote
- {
- /* strip off the quotes */
- name = AntlrInput::tokenTextSubstr($LOWER_WORD_SINGLE_QUOTED,1,
+ | LOWER_WORD_SINGLE_QUOTED // the lower word single quoted are considered without quote
+ { /* strip off the quotes */
+ name = AntlrInput::tokenTextSubstr($LOWER_WORD_SINGLE_QUOTED, 1 ,
($LOWER_WORD_SINGLE_QUOTED->stop - $LOWER_WORD_SINGLE_QUOTED->start) - 1);
}
| SINGLE_QUOTED {name = AntlrInput::tokenText($SINGLE_QUOTED); }; //for the others the quote remains
@@ -565,35 +960,34 @@ atomicWord[std::string & name]
/* Rational */
fragment DOT : '.';
-fragment EXPONENT : 'E'|'e';
+fragment EXPONENT : 'E' | 'e';
fragment SLASH : '/';
fragment DECIMAL : NUMERIC+;
-/* Currently we put all in the rationnal type */
-fragment SIGN[bool & pos] : PLUS_TOK | MINUS_TOK { pos = false; } ;
-
+/* Currently we put all in the rational type */
+fragment SIGN[bool& pos]
+ : PLUS_TOK { pos = true; }
+ | MINUS_TOK { pos = false; }
+ ;
NUMBER
-@declarations{
+@declarations {
bool pos = true;
bool posE = true;
}
- :
- ( SIGN[pos]? num=DECIMAL
- {
- Integer i (AntlrInput::tokenText($num));
- Rational r = ( pos ? i : -i );
- PARSER_STATE->d_tmp_expr = MK_CONST(r);
- }
- | SIGN[pos]? num=DECIMAL DOT den=DECIMAL (EXPONENT SIGN[posE]? e=DECIMAL)?
- {
- std::string snum = AntlrInput::tokenText($num);
+ : ( SIGN[pos]? num=DECIMAL
+ { Integer i(AntlrInput::tokenText($num));
+ Rational r = pos ? i : -i;
+ PARSER_STATE->d_tmp_expr = MK_CONST(r);
+ }
+ | SIGN[pos]? num=DECIMAL DOT den=DECIMAL (EXPONENT SIGN[posE]? e=DECIMAL)?
+ { std::string snum = AntlrInput::tokenText($num);
std::string sden = AntlrInput::tokenText($den);
/* compute the numerator */
- Integer inum( snum + sden );
+ Integer inum(snum + sden);
// The sign
- inum = pos ? inum : - inum;
+ inum = pos ? inum : -inum;
// The exponent
size_t exp = ($e == NULL ? 0 : AntlrInput::tokenToUnsigned($e));
// Decimal part
@@ -601,26 +995,25 @@ NUMBER
/* multiply it by 10 raised to the exponent reduced by the
* number of decimal place in den (dec) */
Rational r;
- if( !posE ) r = Rational(inum, Integer(10).pow(exp + dec));
- else if( exp == dec ) r = Rational(inum);
- else if( exp > dec ) r = Rational(inum * Integer(10).pow(exp - dec));
+ if(!posE) r = Rational(inum, Integer(10).pow(exp + dec));
+ else if(exp == dec) r = Rational(inum);
+ else if(exp > dec) r = Rational(inum * Integer(10).pow(exp - dec));
else r = Rational(inum, Integer(10).pow(dec - exp));
- PARSER_STATE->d_tmp_expr = MK_CONST( r );
+ PARSER_STATE->d_tmp_expr = MK_CONST(r);
+ }
+ | SIGN[pos]? num=DECIMAL SLASH den=DECIMAL
+ { Integer inum(AntlrInput::tokenText($num));
+ Integer iden(AntlrInput::tokenText($den));
+ PARSER_STATE->d_tmp_expr = MK_CONST(Rational(pos ? inum : -inum, iden));
+ }
+ )
+ { if(PARSER_STATE->cnf || PARSER_STATE->fof) {
+ // We're in an unsorted context, so put a conversion around it
+ PARSER_STATE->d_tmp_expr = PARSER_STATE->convertRatToUnsorted( PARSER_STATE->d_tmp_expr );
}
- | SIGN[pos]? num=DECIMAL SLASH den=DECIMAL
- {
- Integer inum(AntlrInput::tokenText($num));
- Integer iden(AntlrInput::tokenText($den));
- PARSER_STATE->d_tmp_expr = MK_CONST(
- Rational(pos ? inum : -inum, iden));
- }
- ) {
- //Put a convertion around it
- PARSER_STATE->d_tmp_expr = PARSER_STATE->convertRatToUnsorted( PARSER_STATE->d_tmp_expr );
}
;
-
/**
* Matches the comments and ignores them
*/
@@ -629,5 +1022,3 @@ COMMENT
| '/*' ( options {greedy=false;} : . )* '*/' { SKIP(); } //comment block
;
-
-
diff --git a/src/parser/tptp/tptp.cpp b/src/parser/tptp/tptp.cpp
index ee7ee4c61..edffaa01f 100644
--- a/src/parser/tptp/tptp.cpp
+++ b/src/parser/tptp/tptp.cpp
@@ -33,25 +33,26 @@ Tptp::Tptp(ExprManager* exprManager, Input* input, bool strictMode, bool parseOn
/* Try to find TPTP dir */
// From tptp4x FileUtilities
//----Try the TPTP directory, and TPTP variations
- char* home = getenv("TPTP");
- if (home == NULL) {
- home = getenv("TPTP_HOME");
+ char* home = getenv("TPTP");
+ if(home == NULL) {
+ home = getenv("TPTP_HOME");
// //----If no TPTP_HOME, try the tptp user (aaargh)
-// if (home == NULL && (PasswdEntry = getpwnam("tptp")) != NULL) {
-// home = PasswdEntry->pw_dir;
+// if(home == NULL && (PasswdEntry = getpwnam("tptp")) != NULL) {
+// home = PasswdEntry->pw_dir;
// }
//----Now look in the TPTP directory from there
- if (home != NULL) {
- d_tptpDir = home;
- d_tptpDir.append("/TPTP/");
- }
- } else {
+ if(home != NULL) {
d_tptpDir = home;
- //add trailing "/"
- if( d_tptpDir[d_tptpDir.size() - 1] != '/'){
- d_tptpDir.append("/");
- }
+ d_tptpDir.append("/TPTP/");
}
+ } else {
+ d_tptpDir = home;
+ //add trailing "/"
+ if(d_tptpDir[d_tptpDir.size() - 1] != '/') {
+ d_tptpDir.append("/");
+ }
+ }
+ d_hasConjecture = false;
}
void Tptp::addTheory(Theory theory) {
@@ -91,7 +92,7 @@ void Tptp::addTheory(Theory theory) {
/* The include are managed in the lexer but called in the parser */
// Inspired by http://www.antlr3.org/api/C/interop.html
-bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
+bool newInputStream(std::string fileName, pANTLR3_LEXER lexer) {
Debug("parser") << "Including " << fileName << std::endl;
// Create a new input stream and take advantage of built in stream stacking
// in C target runtime.
@@ -102,11 +103,11 @@ bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
in = antlr3FileStreamNew((pANTLR3_UINT8) fileName.c_str(), ANTLR3_ENC_8BIT);
#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
- if( in == NULL ) {
+ if(in == NULL) {
Debug("parser") << "Can't open " << fileName << std::endl;
return false;
}
- // Samething than the predefined PUSHSTREAM(in);
+ // Same thing as the predefined PUSHSTREAM(in);
lexer->pushCharStream(lexer,in);
// restart it
//lexer->rec->state->tokenStartCharIndex = -10;
@@ -125,41 +126,95 @@ bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
return true;
}
+/* overridden popCharStream for the lexer - necessary if we had symbol
+ * filtering in file inclusion.
+void Tptp::myPopCharStream(pANTLR3_LEXER lexer) {
+ ((Tptp*)lexer->super)->d_oldPopCharStream(lexer);
+ ((Tptp*)lexer->super)->popScope();
+}
+*/
+
+void Tptp::includeFile(std::string fileName) {
+ // security for online version
+ if(!canIncludeFile()) {
+ parseError("include-file feature was disabled for this run.");
+ }
-void Tptp::includeFile(std::string fileName){
// Get the lexer
AntlrInput * ai = static_cast<AntlrInput *>(getInput());
pANTLR3_LEXER lexer = ai->getAntlr3Lexer();
+
+ // set up popCharStream - would be necessary for handling symbol
+ // filtering in inclusions
+ /*
+ if(d_oldPopCharStream == NULL) {
+ d_oldPopCharStream = lexer->popCharStream;
+ lexer->popCharStream = myPopCharStream;
+ }
+ */
+
+ // push the inclusion scope; will be popped by our special popCharStream
+ // would be necessary for handling symbol filtering in inclusions
+ //pushScope();
+
// get the name of the current stream "Does it work inside an include?"
const std::string inputName = ai->getInputStreamName();
// Test in the directory of the actual parsed file
std::string currentDirFileName;
- if( inputName != "<stdin>"){
- // TODO: Use dirname ot Boost::filesystem?
+ if(inputName != "<stdin>") {
+ // TODO: Use dirname or Boost::filesystem?
size_t pos = inputName.rfind('/');
- if( pos != std::string::npos){
+ if(pos != std::string::npos) {
currentDirFileName = std::string(inputName, 0, pos + 1);
}
currentDirFileName.append(fileName);
- if( newInputStream(currentDirFileName,lexer) ){
+ if(newInputStream(currentDirFileName,lexer)) {
return;
}
} else {
currentDirFileName = "<unknown current directory for stdin>";
}
- if( d_tptpDir.empty() ){
+ if(d_tptpDir.empty()) {
parseError("Couldn't open included file: " + fileName
+ " at " + currentDirFileName + " and the TPTP directory is not specified (environment variable TPTP)");
};
std::string tptpDirFileName = d_tptpDir + fileName;
- if( !newInputStream(tptpDirFileName,lexer) ){
+ if(! newInputStream(tptpDirFileName,lexer)) {
parseError("Couldn't open included file: " + fileName
+ " at " + currentDirFileName + " or " + tptpDirFileName);
}
}
+void Tptp::checkLetBinding(std::vector<Expr>& bvlist, Expr lhs, Expr rhs, bool formula) {
+ if(lhs.getKind() != CVC4::kind::APPLY_UF) {
+ parseError("malformed let: LHS must be a flat function application");
+ }
+ std::vector<CVC4::Expr> v = lhs.getChildren();
+ if(formula && !lhs.getType().isBoolean()) {
+ parseError("malformed let: LHS must be formula");
+ }
+ for(size_t i = 0; i < v.size(); ++i) {
+ if(v[i].hasOperator()) {
+ parseError("malformed let: LHS must be flat, illegal child: " + v[i].toString());
+ }
+ }
+ std::sort(v.begin(), v.end());
+ std::sort(bvlist.begin(), bvlist.end());
+ // ensure all let-bound variables appear on the LHS, and appear only once
+ for(size_t i = 0; i < bvlist.size(); ++i) {
+ std::vector<CVC4::Expr>::const_iterator found = std::lower_bound(v.begin(), v.end(), bvlist[i]);
+ if(found == v.end() || *found != bvlist[i]) {
+ parseError("malformed let: LHS must make use of all quantified variables, missing `" + bvlist[i].toString() + "'");
+ }
+ std::vector<CVC4::Expr>::const_iterator found2 = found + 1;
+ if(found2 != v.end() && *found2 == *found) {
+ parseError("malformed let: LHS cannot use same bound variable twice: " + (*found).toString());
+ }
+ }
+}
+
}/* CVC4::parser namespace */
}/* CVC4 namespace */
diff --git a/src/parser/tptp/tptp.h b/src/parser/tptp/tptp.h
index 6b7adbbf7..e180d1524 100644
--- a/src/parser/tptp/tptp.h
+++ b/src/parser/tptp/tptp.h
@@ -24,6 +24,8 @@
#include "util/hash.h"
#include <ext/hash_set>
#include <cassert>
+#include "parser/options.h"
+#include "parser/antlr_input.h"
namespace CVC4 {
@@ -45,46 +47,57 @@ class Tptp : public Parser {
std::hash_set<Expr, ExprHashFunction> d_r_converted;
std::hash_map<std::string, Expr, StringHashFunction> d_distinct_objects;
- //TPTP directory where to find includes
+ // TPTP directory where to find includes;
// empty if none could be determined
std::string d_tptpDir;
+ // hack to make output SZS ontology-compliant
+ bool d_hasConjecture;
+
+ static void myPopCharStream(pANTLR3_LEXER lexer);
+ void (*d_oldPopCharStream)(pANTLR3_LEXER);
+
public:
- bool cnf; //in a cnf formula
- void addFreeVar(Expr var){assert(cnf); d_freeVar.push_back(var); };
- std::vector< Expr > getFreeVar(){
+ bool cnf; // in a cnf formula
+ bool fof; // in an fof formula
+
+ void addFreeVar(Expr var) {
+ assert(cnf);
+ d_freeVar.push_back(var);
+ }
+ std::vector< Expr > getFreeVar() {
assert(cnf);
std::vector< Expr > r;
r.swap(d_freeVar);
return r;
}
- inline Expr convertRatToUnsorted(Expr expr){
+ inline Expr convertRatToUnsorted(Expr expr) {
ExprManager * em = getExprManager();
// Create the conversion function If they doesn't exists
- if(d_rtu_op.isNull()){
+ if(d_rtu_op.isNull()) {
Type t;
- //Conversion from rational to unsorted
+ // Conversion from rational to unsorted
t = em->mkFunctionType(em->realType(), d_unsorted);
d_rtu_op = em->mkVar("$$rtu",t);
preemptCommand(new DeclareFunctionCommand("$$rtu", d_rtu_op, t));
- //Conversion from unsorted to rational
+ // Conversion from unsorted to rational
t = em->mkFunctionType(d_unsorted, em->realType());
d_utr_op = em->mkVar("$$utr",t);
- preemptCommand(new DeclareFunctionCommand("$$utur", d_utr_op, t));
+ preemptCommand(new DeclareFunctionCommand("$$utr", d_utr_op, t));
}
// Add the inverse in order to show that over the elements that
// appear in the problem there is a bijection between unsorted and
// rational
Expr ret = em->mkExpr(kind::APPLY_UF,d_rtu_op,expr);
- if ( d_r_converted.find(expr) == d_r_converted.end() ){
+ if(d_r_converted.find(expr) == d_r_converted.end()) {
d_r_converted.insert(expr);
- Expr eq = em->mkExpr(kind::EQUAL,expr,
- em->mkExpr(kind::APPLY_UF,d_utr_op,ret));
+ Expr eq = em->mkExpr(kind::EQUAL, expr,
+ em->mkExpr(kind::APPLY_UF, d_utr_op, ret));
preemptCommand(new AssertCommand(eq));
- };
+ }
return ret;
}
@@ -98,12 +111,13 @@ public:
public:
- //TPTP (CNF and FOF) is unsorted so we define this common type
+ // CNF and FOF are unsorted so we define this common type.
+ // This is also the Type of $i in TFF.
Type d_unsorted;
enum Theory {
THEORY_CORE,
- };
+ };/* enum Theory */
enum FormulaRole {
FR_AXIOM,
@@ -120,8 +134,9 @@ public:
FR_FI_FUNCTORS,
FR_FI_PREDICATES,
FR_TYPE,
- };
+ };/* enum FormulaRole */
+ bool hasConjecture() const { return d_hasConjecture; }
protected:
Tptp(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -134,10 +149,10 @@ public:
*/
void addTheory(Theory theory);
- inline void makeApplication(Expr & expr, std::string & name,
- std::vector<Expr> & args, bool term);
+ inline void makeApplication(Expr& expr, std::string& name,
+ std::vector<Expr>& args, bool term);
- inline Command* makeCommand(FormulaRole fr, Expr & expr);
+ inline Command* makeCommand(FormulaRole fr, Expr& expr, bool cnf);
/** Ugly hack because I don't know how to return an expression from a
token */
@@ -147,41 +162,53 @@ public:
is reused */
void includeFile(std::string fileName);
+ /** Check a TPTP let binding for well-formedness. */
+ void checkLetBinding(std::vector<Expr>& bvlist, Expr lhs, Expr rhs, bool formula);
+
private:
void addArithmeticOperators();
};/* class Tptp */
-inline void Tptp::makeApplication(Expr & expr, std::string & name,
- std::vector<Expr> & args, bool term){
- // We distinguish the symbols according to their arities
- std::stringstream ss;
- ss << name << "_" << args.size();
- name = ss.str();
- if(args.empty()){ // Its a constant
- if(isDeclared(name)){ //already appeared
+inline void Tptp::makeApplication(Expr& expr, std::string& name,
+ std::vector<Expr>& args, bool term) {
+ if(args.empty()) { // Its a constant
+ if(isDeclared(name)) { // already appeared
expr = getVariable(name);
} else {
Type t = term ? d_unsorted : getExprManager()->booleanType();
- expr = mkVar(name,t,true); //levelZero
+ expr = mkVar(name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
preemptCommand(new DeclareFunctionCommand(name, expr, t));
}
} else { // Its an application
- if(isDeclared(name)){ //already appeared
+ if(isDeclared(name)) { // already appeared
expr = getVariable(name);
} else {
std::vector<Type> sorts(args.size(), d_unsorted);
Type t = term ? d_unsorted : getExprManager()->booleanType();
t = getExprManager()->mkFunctionType(sorts, t);
- expr = mkVar(name,t,true); //levelZero
+ expr = mkVar(name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
preemptCommand(new DeclareFunctionCommand(name, expr, t));
}
+ // args might be rationals, in which case we need to create
+ // distinct constants of the "unsorted" sort to represent them
+ for(size_t i = 0; i < args.size(); ++i) {
+ if(args[i].getType().isReal() && FunctionType(expr.getType()).getArgTypes()[i] == d_unsorted) {
+ args[i] = convertRatToUnsorted(args[i]);
+ }
+ }
expr = getExprManager()->mkExpr(kind::APPLY_UF, expr, args);
}
-};
+}
-inline Command* Tptp::makeCommand(FormulaRole fr, Expr & expr){
- switch(fr){
+inline Command* Tptp::makeCommand(FormulaRole fr, Expr& expr, bool cnf) {
+ // For SZS ontology compliance.
+ // if we're in cnf() though, conjectures don't result in "Theorem" or
+ // "CounterSatisfiable".
+ if(!cnf && (fr == FR_NEGATED_CONJECTURE || fr == FR_CONJECTURE)) {
+ d_hasConjecture = true;
+ }
+ switch(fr) {
case FR_AXIOM:
case FR_HYPOTHESIS:
case FR_DEFINITION:
diff --git a/src/parser/tptp/tptp_input.cpp b/src/parser/tptp/tptp_input.cpp
index 34a620187..bfaeb07c9 100644
--- a/src/parser/tptp/tptp_input.cpp
+++ b/src/parser/tptp/tptp_input.cpp
@@ -28,9 +28,9 @@
namespace CVC4 {
namespace parser {
-/* Use lookahead=1 */
+/* Use lookahead=2 */
TptpInput::TptpInput(AntlrInputStream& inputStream) :
- AntlrInput(inputStream, 1) {
+ AntlrInput(inputStream, 2) {
pANTLR3_INPUT_STREAM input = inputStream.getAntlr3InputStream();
assert( input != NULL );
diff --git a/src/parser/tptp/tptp_input.h b/src/parser/tptp/tptp_input.h
index 19e928e7e..cb2bcd3a3 100644
--- a/src/parser/tptp/tptp_input.h
+++ b/src/parser/tptp/tptp_input.h
@@ -64,7 +64,7 @@ public:
/** Get the language that this Input is reading. */
InputLanguage getLanguage() const throw() {
- return language::input::LANG_SMTLIB_V2;
+ return language::input::LANG_TPTP;
}
protected:
diff --git a/src/printer/Makefile.am b/src/printer/Makefile.am
index fd48b8352..cd938088e 100644
--- a/src/printer/Makefile.am
+++ b/src/printer/Makefile.am
@@ -19,7 +19,9 @@ libprinter_la_SOURCES = \
smt2/smt2_printer.h \
smt2/smt2_printer.cpp \
cvc/cvc_printer.h \
- cvc/cvc_printer.cpp
+ cvc/cvc_printer.cpp \
+ tptp/tptp_printer.h \
+ tptp/tptp_printer.cpp
EXTRA_DIST = \
options_handlers.h
diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp
index 57462c9f7..88c769f26 100644
--- a/src/printer/ast/ast_printer.cpp
+++ b/src/printer/ast/ast_printer.cpp
@@ -185,11 +185,11 @@ void AstPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
}/* AstPrinter::toStream(CommandStatus*) */
-void AstPrinter::toStream(std::ostream& out, Model& m) const throw() {
+void AstPrinter::toStream(std::ostream& out, const Model& m) const throw() {
out << "Model()";
}
-void AstPrinter::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
+void AstPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
// shouldn't be called; only the non-Command* version above should be
Unreachable();
}
diff --git a/src/printer/ast/ast_printer.h b/src/printer/ast/ast_printer.h
index c9ee6071d..f09de9d00 100644
--- a/src/printer/ast/ast_printer.h
+++ b/src/printer/ast/ast_printer.h
@@ -29,13 +29,13 @@ namespace ast {
class AstPrinter : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
};/* class AstPrinter */
}/* CVC4::printer::ast namespace */
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 23c4727f3..513ff7276 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -813,8 +813,8 @@ void CvcPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
}/* CvcPrinter::toStream(CommandStatus*) */
-void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
- theory::TheoryModel& tm = (theory::TheoryModel&) m;
+void CvcPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ const theory::TheoryModel& tm = (const theory::TheoryModel&) m;
if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) {
TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() );
if( options::modelUninterpDtEnum() && tn.isSort() &&
diff --git a/src/printer/cvc/cvc_printer.h b/src/printer/cvc/cvc_printer.h
index 49b70b012..15b04488d 100644
--- a/src/printer/cvc/cvc_printer.h
+++ b/src/printer/cvc/cvc_printer.h
@@ -29,7 +29,7 @@ namespace cvc {
class CvcPrinter : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types, bool bracket) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp
index 2a10ae451..f9d7c2a38 100644
--- a/src/printer/printer.cpp
+++ b/src/printer/printer.cpp
@@ -20,6 +20,7 @@
#include "printer/smt1/smt1_printer.h"
#include "printer/smt2/smt2_printer.h"
+#include "printer/tptp/tptp_printer.h"
#include "printer/cvc/cvc_printer.h"
#include "printer/ast/ast_printer.h"
@@ -41,8 +42,8 @@ Printer* Printer::makePrinter(OutputLanguage lang) throw() {
case LANG_SMTLIB_V2:
return new printer::smt2::Smt2Printer();
- case LANG_TPTP: //TODO the printer
- return new printer::smt2::Smt2Printer();
+ case LANG_TPTP:
+ return new printer::tptp::TptpPrinter();
case LANG_CVC4:
return new printer::cvc::CvcPrinter();
@@ -125,7 +126,7 @@ void Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
}
}/* Printer::toStream(SExpr) */
-void Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Printer::toStream(std::ostream& out, const Model& m) const throw() {
for(size_t i = 0; i < m.getNumCommands(); ++i) {
toStream(out, m, m.getCommand(i));
}
diff --git a/src/printer/printer.h b/src/printer/printer.h
index 48a041d6a..d3a9201ee 100644
--- a/src/printer/printer.h
+++ b/src/printer/printer.h
@@ -43,7 +43,12 @@ protected:
Printer() throw() {}
/** write model response to command */
- virtual void toStream(std::ostream& out, Model& m, const Command* c) const throw() = 0;
+ virtual void toStream(std::ostream& out, const Model& m, const Command* c) const throw() = 0;
+
+ /** write model response to command using another language printer */
+ void toStreamUsing(OutputLanguage lang, std::ostream& out, const Model& m, const Command* c) const throw() {
+ getPrinter(lang)->toStream(out, m, c);
+ }
public:
/** Get the Printer for a given OutputLanguage */
@@ -79,7 +84,7 @@ public:
virtual void toStream(std::ostream& out, const Result& r) const throw();
/** Write a Model out to a stream with this Printer. */
- virtual void toStream(std::ostream& out, Model& m) const throw();
+ virtual void toStream(std::ostream& out, const Model& m) const throw();
};/* class Printer */
diff --git a/src/printer/smt1/smt1_printer.cpp b/src/printer/smt1/smt1_printer.cpp
index f62709988..c5c491cc0 100644
--- a/src/printer/smt1/smt1_printer.cpp
+++ b/src/printer/smt1/smt1_printer.cpp
@@ -49,11 +49,11 @@ void Smt1Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw()
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
}/* Smt1Printer::toStream() */
-void Smt1Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Smt1Printer::toStream(std::ostream& out, const Model& m) const throw() {
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, m);
}
-void Smt1Printer::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
+void Smt1Printer::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
// shouldn't be called; only the non-Command* version above should be
Unreachable();
}
diff --git a/src/printer/smt1/smt1_printer.h b/src/printer/smt1/smt1_printer.h
index 185d23699..9faf76cc0 100644
--- a/src/printer/smt1/smt1_printer.h
+++ b/src/printer/smt1/smt1_printer.h
@@ -28,14 +28,14 @@ namespace printer {
namespace smt1 {
class Smt1Printer : public CVC4::Printer {
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const SExpr& sexpr) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
};/* class Smt1Printer */
}/* CVC4::printer::smt1 namespace */
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index c59df6269..756e521a6 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -172,6 +172,12 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
break;
}
+ case kind::STORE_ALL: {
+ ArrayStoreAll asa = n.getConst<ArrayStoreAll>();
+ out << "(__array_store_all__ " << asa.getType() << " " << asa.getExpr() << ")";
+ break;
+ }
+
case kind::SUBRANGE_TYPE: {
const SubrangeBounds& bounds = n.getConst<SubrangeBounds>();
// No way to represent subranges in SMT-LIBv2; this is inspired
@@ -214,7 +220,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
bool stillNeedToPrintParams = true;
// operator
- if(n.getNumChildren() != 0) out << '(';
+ if(n.getNumChildren() != 0 && n.getKind()!=kind::INST_PATTERN_LIST) out << '(';
switch(Kind k = n.getKind()) {
// builtin theory
case kind::APPLY: break;
@@ -241,11 +247,25 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::MULT:
case kind::MINUS:
case kind::UMINUS:
- case kind::DIVISION:
case kind::LT:
case kind::LEQ:
case kind::GT:
- case kind::GEQ: out << smtKindString(k) << " "; break;
+ case kind::GEQ:
+ case kind::DIVISION:
+ case kind::DIVISION_TOTAL:
+ case kind::INTS_DIVISION:
+ case kind::INTS_DIVISION_TOTAL:
+ case kind::INTS_MODULUS:
+ case kind::INTS_MODULUS_TOTAL:
+ case kind::ABS:
+ case kind::IS_INTEGER:
+ case kind::TO_INTEGER:
+ case kind::TO_REAL: out << smtKindString(k) << " "; break;
+
+ case kind::DIVISIBLE:
+ out << "(_ divisible " << n.getOperator().getConst<Divisible>().k << ")";
+ stillNeedToPrintParams = false;
+ break;
// arrays theory
case kind::SELECT:
@@ -284,6 +304,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::BITVECTOR_SLE: out << "bvsle "; break;
case kind::BITVECTOR_SGT: out << "bvsgt "; break;
case kind::BITVECTOR_SGE: out << "bvsge "; break;
+ case kind::BITVECTOR_TO_NAT: out << "bv2nat "; break;
case kind::BITVECTOR_EXTRACT:
case kind::BITVECTOR_REPEAT:
@@ -291,6 +312,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::BITVECTOR_SIGN_EXTEND:
case kind::BITVECTOR_ROTATE_LEFT:
case kind::BITVECTOR_ROTATE_RIGHT:
+ case kind::INT_TO_BITVECTOR:
printBvParameterizedOp(out, n);
out << ' ';
stillNeedToPrintParams = false;
@@ -312,12 +334,29 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
break;
// quantifiers
- case kind::FORALL: out << "forall "; break;
- case kind::EXISTS: out << "exists "; break;
+ case kind::FORALL:
+ case kind::EXISTS:
+ if( k==kind::FORALL ){
+ out << "forall ";
+ }else{
+ out << "exists ";
+ }
+ for( unsigned i=0; i<2; i++) {
+ out << n[i] << " ";
+ if( i==0 && n.getNumChildren()==3 ){
+ out << "(! ";
+ }
+ }
+ if( n.getNumChildren()==3 ){
+ out << n[2];
+ out << ")";
+ }
+ out << ")";
+ return;
+ break;
case kind::BOUND_VAR_LIST:
// the left parenthesis is already printed (before the switch)
- for(TNode::iterator i = n.begin(),
- iend = n.end();
+ for(TNode::iterator i = n.begin(), iend = n.end();
i != iend; ) {
out << '(';
toStream(out, (*i), toDepth < 0 ? toDepth : toDepth - 1, types);
@@ -334,8 +373,13 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
out << ')';
return;
case kind::INST_PATTERN:
+ break;
case kind::INST_PATTERN_LIST:
// TODO user patterns
+ for(unsigned i=0; i<n.getNumChildren(); i++) {
+ out << ":pattern " << n[i];
+ }
+ return;
break;
default:
@@ -399,15 +443,25 @@ static string smtKindString(Kind k) throw() {
case kind::MULT: return "*";
case kind::MINUS: return "-";
case kind::UMINUS: return "-";
- case kind::DIVISION: return "/";
case kind::LT: return "<";
case kind::LEQ: return "<=";
case kind::GT: return ">";
case kind::GEQ: return ">=";
+ case kind::DIVISION:
+ case kind::DIVISION_TOTAL: return "/";
+ case kind::INTS_DIVISION: return "div";
+ case kind::INTS_DIVISION_TOTAL: return "INTS_DIVISION_TOTAL";
+ case kind::INTS_MODULUS: return "mod";
+ case kind::INTS_MODULUS_TOTAL: return "INTS_MODULUS_TOTAL";
+ case kind::ABS: return "abs";
+ case kind::IS_INTEGER: return "is_int";
+ case kind::TO_INTEGER: return "to_int";
+ case kind::TO_REAL: return "to_real";
// arrays theory
case kind::SELECT: return "select";
case kind::STORE: return "store";
+ case kind::STORE_ALL: return "__array_store_all__";
case kind::ARRAY_TYPE: return "Array";
// bv theory
@@ -483,6 +537,10 @@ static void printBvParameterizedOp(std::ostream& out, TNode n) throw() {
out << "rotate_right "
<< n.getOperator().getConst<BitVectorRotateRight>().rotateRightAmount;
break;
+ case kind::INT_TO_BITVECTOR:
+ out << "int2bv "
+ << n.getOperator().getConst<IntToBitVector>().size;
+ break;
default:
out << n.getKind();
}
@@ -504,6 +562,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
+ tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
tryToStream<DeclareFunctionCommand>(out, c) ||
tryToStream<DeclareTypeCommand>(out, c) ||
@@ -554,15 +613,15 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro
}/* Smt2Printer::toStream(CommandStatus*) */
-void Smt2Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Smt2Printer::toStream(std::ostream& out, const Model& m) const throw() {
out << "(model" << std::endl;
this->Printer::toStream(out, m);
out << ")" << std::endl;
}
-void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
- theory::TheoryModel& tm = (theory::TheoryModel&) m;
+void Smt2Printer::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ const theory::TheoryModel& tm = (const theory::TheoryModel&) m;
if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) {
TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() );
if( options::modelUninterpDtEnum() && tn.isSort() &&
@@ -644,7 +703,7 @@ void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const
}
void Smt2Printer::toStream(std::ostream& out, const Result& r) const throw() {
- if (r.getType() == Result::TYPE_SAT && r.isSat() == Result::SAT_UNKNOWN) {
+ if(r.getType() == Result::TYPE_SAT && r.isSat() == Result::SAT_UNKNOWN) {
out << "unknown";
} else {
Printer::toStream(out, r);
@@ -718,15 +777,26 @@ static void toStream(std::ostream& out, const DeclareFunctionCommand* c) throw()
static void toStream(std::ostream& out, const DefineFunctionCommand* c) throw() {
Expr func = c->getFunction();
- const vector<Expr>& formals = c->getFormals();
+ const vector<Expr>* formals = &c->getFormals();
out << "(define-fun " << func << " (";
Type type = func.getType();
+ Expr formula = c->getFormula();
if(type.isFunction()) {
- vector<Expr>::const_iterator i = formals.begin();
+ vector<Expr> f;
+ if(formals->empty()) {
+ const vector<Type>& params = FunctionType(type).getArgTypes();
+ for(vector<Type>::const_iterator j = params.begin(); j != params.end(); ++j) {
+ f.push_back(NodeManager::currentNM()->mkSkolem("a", TypeNode::fromType(*j), "",
+ NodeManager::SKOLEM_NO_NOTIFY).toExpr());
+ }
+ formula = NodeManager::currentNM()->toExprManager()->mkExpr(kind::APPLY_UF, formula, f);
+ formals = &f;
+ }
+ vector<Expr>::const_iterator i = formals->begin();
for(;;) {
out << "(" << (*i) << " " << (*i).getType() << ")";
++i;
- if(i != formals.end()) {
+ if(i != formals->end()) {
out << " ";
} else {
break;
@@ -734,7 +804,6 @@ static void toStream(std::ostream& out, const DefineFunctionCommand* c) throw()
}
type = FunctionType(type).getRangeType();
}
- Expr formula = c->getFormula();
out << ") " << type << " " << formula << ")";
}
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index 76ec39258..871b3823a 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -29,8 +29,8 @@ namespace smt2 {
class Smt2Printer : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
diff --git a/src/printer/tptp/tptp_printer.cpp b/src/printer/tptp/tptp_printer.cpp
new file mode 100644
index 000000000..ec2a8758b
--- /dev/null
+++ b/src/printer/tptp/tptp_printer.cpp
@@ -0,0 +1,83 @@
+/********************* */
+/*! \file tptp_printer.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief The pretty-printer interface for the TPTP output language
+ **
+ ** The pretty-printer interface for the TPTP output language.
+ **/
+
+#include "printer/tptp/tptp_printer.h"
+#include "expr/expr.h" // for ExprSetDepth etc..
+#include "util/language.h" // for LANG_AST
+#include "expr/node_manager.h" // for VarNameAttr
+#include "expr/command.h"
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <typeinfo>
+
+using namespace std;
+
+namespace CVC4 {
+namespace printer {
+namespace tptp {
+
+void TptpPrinter::toStream(std::ostream& out, TNode n,
+ int toDepth, bool types, size_t dag) const throw() {
+ n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const Command* c,
+ int toDepth, bool types, size_t dag) const throw() {
+ c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw() {
+ s->toStream(out, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const Model& m) const throw() {
+ out << "% SZS output start FiniteModel for " << m.getInputName() << endl;
+ for(size_t i = 0; i < m.getNumCommands(); ++i) {
+ this->Printer::toStreamUsing(language::output::LANG_SMTLIB_V2, out, m, m.getCommand(i));
+ }
+ out << "% SZS output end FiniteModel for " << m.getInputName() << endl;
+}
+
+void TptpPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ // shouldn't be called; only the non-Command* version above should be
+ Unreachable();
+}
+
+void TptpPrinter::toStream(std::ostream& out, const Result& r) const throw() {
+ out << "% SZS status ";
+ if(r.isSat() == Result::SAT) {
+ out << "Satisfiable";
+ } else if(r.isSat() == Result::UNSAT) {
+ out << "Unsatisfiable";
+ } else if(r.isValid() == Result::VALID) {
+ out << "Theorem";
+ } else if(r.isValid() == Result::INVALID) {
+ out << "CounterSatisfiable";
+ } else {
+ out << "GaveUp";
+ }
+ out << " for " << r.getInputName();
+}
+
+}/* CVC4::printer::tptp namespace */
+}/* CVC4::printer namespace */
+}/* CVC4 namespace */
diff --git a/src/printer/tptp/tptp_printer.h b/src/printer/tptp/tptp_printer.h
new file mode 100644
index 000000000..a0f3de62b
--- /dev/null
+++ b/src/printer/tptp/tptp_printer.h
@@ -0,0 +1,46 @@
+/********************* */
+/*! \file tptp_printer.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief The pretty-printer interface for the TPTP output language
+ **
+ ** The pretty-printer interface for the TPTP output language.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PRINTER__TPTP_PRINTER_H
+#define __CVC4__PRINTER__TPTP_PRINTER_H
+
+#include <iostream>
+
+#include "printer/printer.h"
+
+namespace CVC4 {
+namespace printer {
+namespace tptp {
+
+class TptpPrinter : public CVC4::Printer {
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
+public:
+ using CVC4::Printer::toStream;
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const CommandStatus* s) const throw();
+ void toStream(std::ostream& out, const SExpr& sexpr) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
+ void toStream(std::ostream& out, const Result& r) const throw();
+};/* class TptpPrinter */
+
+}/* CVC4::printer::tptp namespace */
+}/* CVC4::printer namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PRINTER__TPTP_PRINTER_H */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index d6e493c8d..5f03ef5cf 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -19,8 +19,8 @@
using namespace CVC4::prop;
namespace CVC4 {
+
CnfProof::CnfProof(CnfStream* stream) :
d_cnfStream(stream) {}
-
} /* CVC4 namespace */
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index c265e46df..984dc76c6 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -17,7 +17,7 @@
**/
#include "cvc4_private.h"
-
+#include "util/proof.h"
#ifndef __CVC4__CNF_PROOF_H
#define __CVC4__CNF_PROOF_H
diff --git a/src/proof/sat_proof.cpp b/src/proof/sat_proof.cpp
index df695c2d1..d9b57f87e 100644
--- a/src/proof/sat_proof.cpp
+++ b/src/proof/sat_proof.cpp
@@ -173,7 +173,10 @@ SatProof::SatProof(Minisat::Solver* solver, bool checkRes) :
d_emptyClauseId(-1),
d_nullId(-2),
d_temp_clauseId(),
- d_temp_idClause()
+ d_temp_idClause(),
+ d_unitConflictId(),
+ d_storedUnitConflict(false),
+ d_atomToVar()
{
d_proxy = new ProofProxy(this);
}
@@ -353,6 +356,7 @@ ClauseId SatProof::registerClause(::Minisat::CRef clause, bool isInput) {
d_inputClauses.insert(newId);
}
}
+ Debug("proof:sat:detailed") <<"registerClause " << d_clauseId[clause] << " " <<isInput << "\n";
return d_clauseId[clause];
}
@@ -367,6 +371,7 @@ ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, bool isInput) {
d_inputClauses.insert(newId);
}
}
+ Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << isInput <<"\n";
return d_unitId[toInt(lit)];
}
@@ -527,10 +532,25 @@ void SatProof::toStream(std::ostream& out) {
Unimplemented("native proof printing not supported yet");
}
+void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit) {
+ Assert (!d_storedUnitConflict);
+ d_unitConflictId = registerUnitClause(conflict_lit);
+ d_storedUnitConflict = true;
+ Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+}
+
void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
Assert(d_resStack.size() == 0);
- //ClauseId conflict_id = getClauseId(conflict_ref);
- ClauseId conflict_id = registerClause(conflict_ref); //FIXME
+ Assert (conflict_ref != ::Minisat::CRef_Undef);
+ ClauseId conflict_id;
+ if (conflict_ref == ::Minisat::CRef_Lazy) {
+ Assert (d_storedUnitConflict);
+ conflict_id = d_unitConflictId;
+ } else {
+ Assert (!d_storedUnitConflict);
+ conflict_id = registerClause(conflict_ref); //FIXME
+ }
+
Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
print(conflict_id);
@@ -573,6 +593,14 @@ void SatProof::markDeleted(CRef clause) {
}
}
+/// store mapping from theory atoms to new variables
+void SatProof::storeAtom(::Minisat::Lit literal, Expr atom) {
+ Assert(d_atomToVar.find(atom) == d_atomToVar.end());
+ d_atomToVar[atom] = literal;
+}
+
+
+
/// LFSCSatProof class
std::string LFSCSatProof::varName(::Minisat::Lit lit) {
@@ -613,6 +641,7 @@ void LFSCSatProof::collectLemmas(ClauseId id) {
d_seenLemmas.insert(id);
}
+ Assert (d_resChains.find(id) != d_resChains.end());
ResChain* res = d_resChains[id];
ClauseId start = res->getStart();
collectLemmas(start);
@@ -658,6 +687,14 @@ void LFSCSatProof::printResolution(ClauseId id) {
void LFSCSatProof::printInputClause(ClauseId id) {
+ if (isUnit(id)) {
+ ::Minisat::Lit lit = getUnit(id);
+ d_clauseSS << "(% " << clauseName(id) << " (holds (clc ";
+ d_clauseSS << varName(lit) << "cln ))";
+ d_paren << ")";
+ return;
+ }
+
ostringstream os;
CRef ref = getClauseRef(id);
Assert (ref != CRef_Undef);
@@ -692,6 +729,7 @@ void LFSCSatProof::printVariables() {
void LFSCSatProof::flush(std::ostream& out) {
+ out << d_atomsSS.str();
out << "(check \n";
d_paren <<")";
out << d_varSS.str();
@@ -705,7 +743,7 @@ void LFSCSatProof::flush(std::ostream& out) {
void LFSCSatProof::toStream(std::ostream& out) {
Debug("proof:sat") << " LFSCSatProof::printProof \n";
-
+
// first collect lemmas to print in reverse order
collectLemmas(d_emptyClauseId);
for(IdSet::iterator it = d_seenLemmas.begin(); it!= d_seenLemmas.end(); ++it) {
@@ -713,13 +751,22 @@ void LFSCSatProof::toStream(std::ostream& out) {
printResolution(*it);
}
}
+ printAtoms();
// last resolution to be printed is the empty clause
printResolution(d_emptyClauseId);
-
+
printClauses();
printVariables();
flush(out);
}
+void LFSCSatProof::printAtoms() {
+ d_atomsSS << "; Mapping between boolean variables and theory atoms \n";
+ for (AtomToVar::iterator it = d_atomToVar.begin(); it != d_atomToVar.end(); ++it) {
+ d_atomsSS << "; " << it->first << " => v" << var(it->second) << "\n";
+ }
+}
+
+
} /* CVC4 namespace */
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index d497a4eba..fb8966400 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -26,6 +26,8 @@
#include <ext/hash_map>
#include <ext/hash_set>
#include <sstream>
+#include "expr/expr.h"
+
namespace Minisat {
class Solver;
@@ -90,6 +92,8 @@ typedef std::vector < ResChain* > ResStack;
typedef std::hash_set < int > VarSet;
typedef std::set < ClauseId > IdSet;
typedef std::vector < ::Minisat::Lit > LitVector;
+typedef __gnu_cxx::hash_map<Expr, ::Minisat::Lit, ExprHashFunction > AtomToVar;
+
class SatProof;
class ProofProxy : public ProofProxyAbstract {
@@ -124,7 +128,14 @@ protected:
// temporary map for updating CRefs
ClauseIdMap d_temp_clauseId;
- IdClauseMap d_temp_idClause;
+ IdClauseMap d_temp_idClause;
+
+ // unit conflict
+ ClauseId d_unitConflictId;
+ bool d_storedUnitConflict;
+
+ // atom mapping
+ AtomToVar d_atomToVar;
public:
SatProof(::Minisat::Solver* solver, bool checkRes = false);
protected:
@@ -197,6 +208,9 @@ public:
/// clause registration methods
ClauseId registerClause(const ::Minisat::CRef clause, bool isInput = false);
ClauseId registerUnitClause(const ::Minisat::Lit lit, bool isInput = false);
+
+ void storeUnitConflict(::Minisat::Lit lit);
+
/**
* Marks the deleted clauses as deleted. Note we may still use them in the final
* resolution.
@@ -216,12 +230,20 @@ public:
*/
void storeUnitResolution(::Minisat::Lit lit);
- ProofProxy* getProxy() {return d_proxy; }
+ ProofProxy* getProxy() {return d_proxy; }
+ /**
+ * At mapping between literal and theory-atom it represents
+ *
+ * @param literal
+ * @param atom
+ */
+ void storeAtom(::Minisat::Lit literal, Expr atom);
};/* class SatProof */
class LFSCSatProof: public SatProof {
private:
- VarSet d_seenVars;
+ VarSet d_seenVars;
+ std::ostringstream d_atomsSS;
std::ostringstream d_varSS;
std::ostringstream d_lemmaSS;
std::ostringstream d_clauseSS;
@@ -239,11 +261,12 @@ private:
void printVariables();
void printClauses();
void flush(std::ostream& out);
-
+ void printAtoms();
public:
LFSCSatProof(::Minisat::Solver* solver, bool checkRes = false):
SatProof(solver, checkRes),
d_seenVars(),
+ d_atomsSS(),
d_varSS(),
d_lemmaSS(),
d_paren(),
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index 4be58bdef..8ebb461e5 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -27,7 +27,9 @@
#include "expr/expr.h"
#include "prop/theory_proxy.h"
#include "theory/bv/options.h"
-
+#include "proof/proof_manager.h"
+#include "proof/sat_proof.h"
+#include "prop/minisat/minisat.h"
#include <queue>
using namespace std;
@@ -236,7 +238,7 @@ SatLiteral CnfStream::convertAtom(TNode node) {
// Make a new literal (variables are not considered theory literals)
SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
-
+ PROOF (ProofManager::getSatProof()->storeAtom(MinisatSatSolver::toMinisatLit(lit), node.toExpr()); );
// Return the resulting literal
return lit;
}
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 6196ca357..36e196821 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -135,6 +135,8 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Assert the constants
uncheckedEnqueue(mkLit(varTrue, false));
uncheckedEnqueue(mkLit(varFalse, true));
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), true); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), true); )
}
@@ -229,7 +231,7 @@ CRef Solver::reason(Var x) {
int i, j;
Lit prev = lit_Undef;
for (i = 0, j = 0; i < explanation.size(); ++ i) {
- // This clause is valid theory propagation, so it's level is the level of the top literal
+ // This clause is valid theory propagation, so its level is the level of the top literal
explLevel = std::max(explLevel, intro_level(var(explanation[i])));
Assert(value(explanation[i]) != l_Undef);
@@ -261,6 +263,7 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
+ PROOF (ProofManager::getSatProof()->registerClause(real_reason, true); );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -297,9 +300,9 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
if (ps[i] == p) {
continue;
}
- // If a literals is false at 0 level (both sat and user level) we also ignore it
+ // If a literal is false at 0 level (both sat and user level) we also ignore it
if (value(ps[i]) == l_False) {
- if (level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
+ if (!PROOF_ON() && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
continue;
} else {
// If we decide to keep it, we count it into the false literals
@@ -345,7 +348,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
PROOF( if (ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], true); } )
- return ok = (propagate(CHECK_WITHOUTH_THEORY) == CRef_Undef);
+ return ok = (propagate(CHECK_WITHOUT_THEORY) == CRef_Undef);
} else return ok;
}
}
@@ -789,7 +792,8 @@ CRef Solver::propagate(TheoryCheckType type)
// If there are lemmas (or conflicts) update them
if (lemmas.size() > 0) {
recheck = true;
- return updateLemmas();
+ confl = updateLemmas();
+ return confl;
} else {
recheck = proxy->theoryNeedCheck();
return confl;
@@ -801,9 +805,8 @@ CRef Solver::propagate(TheoryCheckType type)
do {
// Propagate on the clauses
confl = propagateBool();
-
// If no conflict, do the theory check
- if (confl == CRef_Undef && type != CHECK_WITHOUTH_THEORY) {
+ if (confl == CRef_Undef && type != CHECK_WITHOUT_THEORY) {
// Do the theory check
if (type == CHECK_FINAL_FAKE) {
theoryCheck(CVC4::theory::Theory::EFFORT_FULL);
@@ -836,7 +839,6 @@ CRef Solver::propagate(TheoryCheckType type)
}
}
} while (confl == CRef_Undef && qhead < trail.size());
-
return confl;
}
@@ -1017,8 +1019,8 @@ void Solver::removeClausesAboveLevel(vec<CRef>& cs, int level)
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
if (c.level() > level) {
- assert(!locked(c));
- removeClause(cs[i]);
+ assert(!locked(c));
+ removeClause(cs[i]);
} else {
cs[j++] = cs[i];
}
@@ -1048,7 +1050,7 @@ bool Solver::simplify()
{
assert(decisionLevel() == 0);
- if (!ok || propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef)
+ if (!ok || propagate(CHECK_WITHOUT_THEORY) != CRef_Undef)
return ok = false;
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
@@ -1210,7 +1212,7 @@ lbool Solver::search(int nof_conflicts)
if (next == lit_Undef) {
// We need to do a full theory check to confirm
- Debug("minisat::search") << "Doing a full theoy check..."
+ Debug("minisat::search") << "Doing a full theory check..."
<< std::endl;
check_type = CHECK_FINAL;
continue;
@@ -1490,7 +1492,7 @@ void Solver::pop()
Debug("minisat") << "== unassigning " << trail.last() << std::endl;
Var x = var(trail.last());
if (user_level(x) > assertionLevel) {
- assigns [x] = l_Undef;
+ assigns[x] = l_Undef;
vardata[x] = VarData(CRef_Undef, -1, -1, intro_level(x), -1);
if(phase_saving >= 1 && (polarity[x] & 0x2) == 0)
polarity[x] = sign(trail.last());
@@ -1503,7 +1505,7 @@ void Solver::pop()
// The head should be at the trail top
qhead = trail.size();
- // Remove the clause
+ // Remove the clauses
removeClausesAboveLevel(clauses_persistent, assertionLevel);
removeClausesAboveLevel(clauses_removable, assertionLevel);
@@ -1579,6 +1581,7 @@ CRef Solver::updateLemmas() {
vec<Lit>& lemma = lemmas[i];
// If it's an empty lemma, we have a conflict at zero level
if (lemma.size() == 0) {
+ Assert (! PROOF_ON());
conflict = CRef_Lazy;
backtrackLevel = 0;
Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl;
@@ -1628,6 +1631,7 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
+ PROOF (ProofManager::getSatProof()->registerClause(lemma_ref, true); );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1647,6 +1651,7 @@ CRef Solver::updateLemmas() {
} else {
Debug("minisat::lemmas") << "Solver::updateLemmas(): unit conflict or empty clause" << std::endl;
conflict = CRef_Lazy;
+ PROOF(ProofManager::getSatProof()->storeUnitConflict(lemma[0]););
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 55780479a..30d72ac75 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -266,7 +266,7 @@ protected:
int level;
// User level when the literal was added to the trail
int user_level;
- // Use level at which this literal was introduced
+ // User level at which this literal was introduced
int intro_level;
// The index in the trail
int trail_index;
@@ -335,7 +335,7 @@ protected:
enum TheoryCheckType {
// Quick check, but don't perform theory reasoning
- CHECK_WITHOUTH_THEORY,
+ CHECK_WITHOUT_THEORY,
// Check and perform theory reasoning
CHECK_WITH_THEORY,
// The SAT abstraction of the problem is satisfiable, perform a full theory check
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 37e471846..ec49b5f71 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -30,16 +30,15 @@ class MinisatSatSolver : public DPLLSatSolverInterface {
/** The SatSolver used */
Minisat::SimpSolver* d_minisat;
-
/** The SatSolver uses this to communicate with the theories */
TheoryProxy* d_theoryProxy;
- /** Context we will be using to synchronzie the sat solver */
+ /** Context we will be using to synchronize the sat solver */
context::Context* d_context;
public:
- MinisatSatSolver ();
+ MinisatSatSolver();
~MinisatSatSolver();
static SatVariable toSatVariable(Minisat::Var var);
diff --git a/src/prop/minisat/mtl/Vec.h b/src/prop/minisat/mtl/Vec.h
index 5d8c2850e..5f85f6fcd 100644
--- a/src/prop/minisat/mtl/Vec.h
+++ b/src/prop/minisat/mtl/Vec.h
@@ -86,7 +86,7 @@ public:
const T& operator [] (int index) const { return data[index]; }
T& operator [] (int index) { return data[index]; }
- // Duplicatation (preferred instead):
+ // Duplication (preferred instead):
void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; }
void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
};
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index 0e0e5d3ae..6dcdb76c7 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -67,7 +67,7 @@ SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* c
if(options::minisatUseElim() &&
options::minisatUseElim.wasSetByUser() &&
enableIncremental) {
- WarningOnce() << "Incremental mode incompatible with --minisat-elimination" << std::endl;
+ WarningOnce() << "Incremental mode incompatible with --minisat-elim" << std::endl;
}
vec<Lit> dummy(1,lit_Undef);
@@ -239,7 +239,7 @@ bool SimpSolver::strengthenClause(CRef cr, Lit l)
updateElimHeap(var(l));
}
- return c.size() == 1 ? enqueue(c[0]) && propagate(CHECK_WITHOUTH_THEORY) == CRef_Undef : true;
+ return c.size() == 1 ? enqueue(c[0]) && propagate(CHECK_WITHOUT_THEORY) == CRef_Undef : true;
}
@@ -346,7 +346,7 @@ bool SimpSolver::implied(const vec<Lit>& c)
uncheckedEnqueue(~c[i]);
}
- bool result = propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef;
+ bool result = propagate(CHECK_WITHOUT_THEORY) != CRef_Undef;
cancelUntil(0);
return result;
}
@@ -435,7 +435,7 @@ bool SimpSolver::asymm(Var v, CRef cr)
else
l = c[i];
- if (propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef){
+ if (propagate(CHECK_WITHOUT_THEORY) != CRef_Undef){
cancelUntil(0);
asymm_lits++;
if (!strengthenClause(cr, l))
diff --git a/src/prop/options b/src/prop/options
index e3a0f814a..b300c3fb6 100644
--- a/src/prop/options
+++ b/src/prop/options
@@ -22,8 +22,8 @@ option satRestartFirst --restart-int-base=N unsigned :default 25
option satRestartInc --restart-int-inc=F double :default 3.0 :predicate greater_equal(0.0)
sets the restart interval increase factor for the sat solver (F=3.0 by default)
-option sat_refine_conflicts --refine-conflicts bool
- refine theory conflict clauses
+option sat_refine_conflicts --refine-conflicts bool :default false
+ refine theory conflict clauses (default false)
option minisatUseElim --minisat-elimination bool :default true :read-write
use Minisat elimination
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index c465ed97a..a169d31e6 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -83,7 +83,8 @@ PropEngine::PropEngine(TheoryEngine* te, DecisionEngine *de, Context* satContext
userContext,
// fullLitToNode Map =
options::threads() > 1 ||
- options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY);
+ options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY
+ );
d_satSolver->initialize(d_context, new TheoryProxy(this, d_theoryEngine, d_decisionEngine, d_context, d_cnfStream));
@@ -280,6 +281,7 @@ void PropEngine::interrupt() throw(ModalException) {
void PropEngine::spendResource() throw() {
// TODO implement me
+ checkTime();
}
bool PropEngine::properExplanation(TNode node, TNode expl) const {
diff --git a/src/smt/boolean_terms.cpp b/src/smt/boolean_terms.cpp
index 0063035ff..9f1b9c1a6 100644
--- a/src/smt/boolean_terms.cpp
+++ b/src/smt/boolean_terms.cpp
@@ -288,7 +288,7 @@ TypeNode BooleanTermConverter::convertType(TypeNode type, bool datatypesContext)
}
return newRec;
}
- if(type.getNumChildren() > 0) {
+ if(!type.isSort() && type.getNumChildren() > 0) {
Debug("boolean-terms") << "here at A for " << type << ":" << type.getId() << endl;
// This should handle tuples and arrays ok.
// Might handle function types too, but they can't go
@@ -487,7 +487,39 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
} else if(t.isArray()) {
TypeNode indexType = convertType(t.getArrayIndexType(), false);
TypeNode constituentType = convertType(t.getArrayConstituentType(), false);
- if(indexType != t.getArrayIndexType() || constituentType != t.getArrayConstituentType()) {
+ if(indexType != t.getArrayIndexType() && constituentType == t.getArrayConstituentType()) {
+ TypeNode newType = nm->mkArrayType(indexType, constituentType);
+ Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
+ newType, "an array variable introduced by Boolean-term conversion",
+ NodeManager::SKOLEM_EXACT_NAME);
+ top.setAttribute(BooleanTermAttr(), n);
+ Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
+ Node n_ff = nm->mkNode(kind::SELECT, n, d_ff);
+ Node n_tt = nm->mkNode(kind::SELECT, n, d_tt);
+ Node base = nm->mkConst(ArrayStoreAll(ArrayType(top.getType().toType()), (*TypeEnumerator(n_ff.getType())).toExpr()));
+ Node repl = nm->mkNode(kind::STORE,
+ nm->mkNode(kind::STORE, base, nm->mkConst(true),
+ n_tt),
+ nm->mkConst(false), n_ff);
+ Debug("boolean-terms") << "array replacement: " << top << " => " << repl << endl;
+ d_smt.d_theoryEngine->getModel()->addSubstitution(top, repl);
+ d_termCache[make_pair(top, parentTheory)] = n;
+ result.top() << n;
+ worklist.pop();
+ goto next_worklist;
+ } else if(indexType == t.getArrayIndexType() && constituentType != t.getArrayConstituentType()) {
+ TypeNode newType = nm->mkArrayType(indexType, constituentType);
+ Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
+ newType, "an array variable introduced by Boolean-term conversion",
+ NodeManager::SKOLEM_EXACT_NAME);
+ top.setAttribute(BooleanTermAttr(), n);
+ Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
+ d_smt.d_theoryEngine->getModel()->addSubstitution(top, n);
+ d_termCache[make_pair(top, parentTheory)] = n;
+ result.top() << n;
+ worklist.pop();
+ goto next_worklist;
+ } else if(indexType != t.getArrayIndexType() && constituentType != t.getArrayConstituentType()) {
TypeNode newType = nm->mkArrayType(indexType, constituentType);
Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
newType, "an array variable introduced by Boolean-term conversion",
@@ -594,7 +626,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
worklist.pop();
goto next_worklist;
}
- } else if(t.getNumChildren() > 0) {
+ } 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());
@@ -617,9 +649,6 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
goto next_worklist;
}
switch(k) {
- case kind::LAMBDA:
- Unreachable("not expecting a LAMBDA in boolean-term conversion: %s", top.toString().c_str());
-
case kind::BOUND_VAR_LIST:
result.top() << top;
worklist.pop();
@@ -704,7 +733,8 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
k != kind::TUPLE_SELECT &&
k != kind::TUPLE_UPDATE &&
k != kind::RECORD_SELECT &&
- k != kind::RECORD_UPDATE) {
+ k != kind::RECORD_UPDATE &&
+ k != kind::DIVISIBLE) {
Debug("bt") << "rewriting: " << top.getOperator() << endl;
result.top() << rewriteBooleanTermsRec(top.getOperator(), theory::THEORY_BUILTIN, quantBoolVars);
Debug("bt") << "got: " << result.top().getOperator() << endl;
@@ -715,7 +745,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
// push children
for(int i = top.getNumChildren() - 1; i >= 0; --i) {
Debug("bt") << "rewriting: " << top[i] << endl;
- worklist.push(triple<TNode, theory::TheoryId, bool>(top[i], isBoolean(top, i) ? theory::THEORY_BOOL : (top.getKind() == kind::APPLY_CONSTRUCTOR ? theory::THEORY_DATATYPES : theory::THEORY_BUILTIN), false));
+ worklist.push(triple<TNode, theory::TheoryId, bool>(top[i], top.getKind() == kind::CHAIN ? parentTheory : (isBoolean(top, i) ? theory::THEORY_BOOL : (top.getKind() == kind::APPLY_CONSTRUCTOR ? theory::THEORY_DATATYPES : theory::THEORY_BUILTIN)), false));
//b << rewriteBooleanTermsRec(top[i], isBoolean(top, i) ? , quantBoolVars);
//Debug("bt") << "got: " << b[b.getNumChildren() - 1] << endl;
}
diff --git a/src/smt/options b/src/smt/options
index 2680f4105..7a72881b4 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -24,6 +24,8 @@ common-option produceModels produce-models -m --produce-models bool :default fal
support the get-value and get-model commands
option checkModels check-models --check-models bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
after SAT/INVALID/UNKNOWN, check that the generated model satisfies user assertions
+option dumpModels --dump-models bool :default false
+ output models after every SAT/INVALID/UNKNOWN response
option proof produce-proofs --proof bool :default false :predicate CVC4::smt::proofEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
turn on proof generation
# this is just a placeholder for later; it doesn't show up in command-line options listings
@@ -46,7 +48,7 @@ option unconstrainedSimp --unconstrained-simp bool :default false :read-write
option repeatSimp --repeat-simp bool :read-write
make multiple passes with nonclausal simplifier
-option sortInference --sort-inference bool :default false
+option sortInference --sort-inference bool :read-write :default false
apply sort inference to input problem
common-option incrementalSolving incremental -i --incremental bool
@@ -67,7 +69,7 @@ common-option cumulativeMillisecondLimit tlimit --tlimit=MS "unsigned long"
common-option perCallMillisecondLimit tlimit-per --tlimit-per=MS "unsigned long"
enable time limiting per query (give milliseconds)
common-option cumulativeResourceLimit rlimit --rlimit=N "unsigned long"
- enable resource limiting
+ enable resource limiting (currently, roughly the number of SAT conflicts)
common-option perCallResourceLimit rlimit-per --rlimit-per=N "unsigned long"
enable resource limiting per query
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index 6b8d94c08..c631b8c84 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -186,6 +186,11 @@ inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
} else if(!strcmp(p, "ite-removal")) {
} else if(!strcmp(p, "repeat-simplify")) {
} else if(!strcmp(p, "theory-preprocessing")) {
+ } else if(!strcmp(p, "nonclausal")) {
+ } else if(!strcmp(p, "theorypp")) {
+ } else if(!strcmp(p, "itesimp")) {
+ } else if(!strcmp(p, "unconstrained")) {
+ } else if(!strcmp(p, "repeatsimp")) {
} else {
throw OptionException(std::string("don't know how to dump `") +
optargPtr + "'. Please consult --dump help.");
@@ -409,6 +414,17 @@ inline std::ostream* checkReplayLogFilename(std::string option, std::string opta
#endif /* CVC4_REPLAY */
}
+// ensure we are a stats-enabled build of CVC4
+inline void statsEnabledBuild(std::string option, bool value, SmtEngine* smt) throw(OptionException) {
+#ifndef CVC4_STATISTICS_ON
+ if(value) {
+ std::stringstream ss;
+ ss << "option `" << option << "' requires a statistics-enabled build of CVC4; this binary was not built with statistics support";
+ throw OptionException(ss.str());
+ }
+#endif /* CVC4_STATISTICS_ON */
+}
+
}/* CVC4::smt namespace */
}/* CVC4 namespace */
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 0d473a1a1..39ccc70c4 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -74,6 +74,8 @@
#include "util/sort_inference.h"
#include "theory/quantifiers/macros.h"
#include "theory/datatypes/options.h"
+#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/strings/theory_strings_preprocess.h"
using namespace std;
using namespace CVC4;
@@ -245,6 +247,15 @@ class SmtEnginePrivate : public NodeManagerListener {
/** Assertions to push to sat */
vector<Node> d_assertionsToCheck;
+ /** Whether any assertions have been processed */
+ CDO<bool> d_assertionsProcessed;
+
+ /** Index for where to store substitutions */
+ CDO<unsigned> d_substitutionsIndex;
+
+ // Cached true value
+ Node d_true;
+
/**
* A context that never pushes/pops, for use by CD structures (like
* SubstitutionMaps) that should be "global".
@@ -292,14 +303,13 @@ class SmtEnginePrivate : public NodeManagerListener {
*/
Node d_modZero;
+public:
/**
* Map from skolem variables to index in d_assertionsToCheck containing
* corresponding introduced Boolean ite
*/
IteSkolemMap d_iteSkolemMap;
-public:
-
/** Instance of the ITE remover */
RemoveITE d_iteRemover;
@@ -307,18 +317,6 @@ private:
/** The top level substitutions */
SubstitutionMap d_topLevelSubstitutions;
- /**
- * The last substitution that the SAT layer was told about.
- * In incremental settings, substitutions cannot be performed
- * "backward," only forward. So SAT needs to be told of all
- * substitutions that are going to be done. This iterator
- * holds the last substitution from d_topLevelSubstitutions
- * that was pushed out to SAT.
- * If d_lastSubstitutionPos == d_topLevelSubstitutions.end(),
- * then nothing has been pushed out yet.
- */
- context::CDO<SubstitutionMap::iterator> d_lastSubstitutionPos;
-
static const bool d_doConstantProp = true;
/**
@@ -350,8 +348,8 @@ private:
bool checkForBadSkolems(TNode n, TNode skolem, hash_map<Node, bool, NodeHashFunction>& cache);
// Lift bit-vectors of size 1 to booleans
- void bvToBool();
-
+ void bvToBool();
+
// Simplify ITE structure
void simpITE();
@@ -394,6 +392,8 @@ public:
d_propagator(d_nonClausalLearnedLiterals, true, true),
d_propagatorNeedsFinish(false),
d_assertionsToCheck(),
+ d_assertionsProcessed(smt.d_userContext, false),
+ d_substitutionsIndex(smt.d_userContext, 0),
d_fakeContext(),
d_abstractValueMap(&d_fakeContext),
d_abstractValues(),
@@ -402,9 +402,10 @@ public:
d_modZero(),
d_iteSkolemMap(),
d_iteRemover(smt.d_userContext),
- d_topLevelSubstitutions(smt.d_userContext),
- d_lastSubstitutionPos(smt.d_userContext, d_topLevelSubstitutions.end()) {
+ d_topLevelSubstitutions(smt.d_userContext)
+ {
d_smt.d_nodeManager->subscribeEvents(this);
+ d_true = NodeManager::currentNM()->mkConst(true);
}
~SmtEnginePrivate() {
@@ -419,11 +420,13 @@ public:
d_smt.d_nodeManager->unsubscribeEvents(this);
}
- void nmNotifyNewSort(TypeNode tn) {
+ void nmNotifyNewSort(TypeNode tn, uint32_t flags) {
DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
0,
tn.toType());
- d_smt.addToModelCommandAndDump(c);
+ if((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags);
+ }
}
void nmNotifyNewSortConstructor(TypeNode tn) {
@@ -438,17 +441,19 @@ public:
d_smt.addToModelCommandAndDump(c);
}
- void nmNotifyNewVar(TNode n, bool isGlobal) {
+ void nmNotifyNewVar(TNode n, uint32_t flags) {
DeclareFunctionCommand c(n.getAttribute(expr::VarNameAttr()),
n.toExpr(),
n.getType().toType());
- d_smt.addToModelCommandAndDump(c, isGlobal);
+ if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags);
+ }
if(n.getType().isBoolean() && !options::incrementalSolving()) {
d_boolVars.push_back(n);
}
}
- void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) {
+ void nmNotifyNewSkolem(TNode n, const std::string& comment, uint32_t flags) {
string id = n.getAttribute(expr::VarNameAttr());
DeclareFunctionCommand c(id,
n.toExpr(),
@@ -456,7 +461,9 @@ public:
if(Dump.isOn("skolems") && comment != "") {
Dump("skolems") << CommentCommand(id + " is " + comment);
}
- d_smt.addToModelCommandAndDump(c, isGlobal, false, "skolems");
+ if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags, false, "skolems");
+ }
if(n.getType().isBoolean() && !options::incrementalSolving()) {
d_boolVars.push_back(n);
}
@@ -678,7 +685,7 @@ void SmtEngine::finalOptionsAreSet() {
return;
}
- if (options::bitvectorEagerBitblast()) {
+ if(options::bitvectorEagerBitblast()) {
// Eager solver should use the internal decision strategy
options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
}
@@ -792,21 +799,24 @@ SmtEngine::~SmtEngine() throw() {
void SmtEngine::setLogic(const LogicInfo& logic) throw(ModalException) {
SmtScope smts(this);
-
+ if(d_fullyInited) {
+ throw ModalException("Cannot set logic in SmtEngine after the engine has finished initializing");
+ }
d_logic = logic;
setLogicInternal();
}
-void SmtEngine::setLogic(const std::string& s) throw(ModalException) {
+void SmtEngine::setLogic(const std::string& s) throw(ModalException, LogicException) {
SmtScope smts(this);
-
- setLogic(LogicInfo(s));
+ try {
+ setLogic(LogicInfo(s));
+ } catch(IllegalArgumentException& e) {
+ throw LogicException(e.what());
+ }
}
-void SmtEngine::setLogic(const char* logic) throw(ModalException){
- SmtScope smts(this);
-
- setLogic(LogicInfo(string(logic)));
+void SmtEngine::setLogic(const char* logic) throw(ModalException, LogicException) {
+ setLogic(string(logic));
}
LogicInfo SmtEngine::getLogicInfo() const {
@@ -823,24 +833,12 @@ void SmtEngine::setLogicInternal() throw() {
d_logic.lock();
- // may need to force uninterpreted functions to be on for non-linear
- if(((d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()) ||
- d_logic.isTheoryEnabled(THEORY_BV)) &&
- !d_logic.isTheoryEnabled(THEORY_UF)){
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableTheory(THEORY_UF);
- d_logic.lock();
- }
-
// Set the options for the theoryOf
if(!options::theoryOfMode.wasSetByUser()) {
if(d_logic.isSharingEnabled() && !d_logic.isTheoryEnabled(THEORY_BV)) {
- Theory::setTheoryOfMode(THEORY_OF_TERM_BASED);
- } else {
- Theory::setTheoryOfMode(THEORY_OF_TYPE_BASED);
+ Trace("smt") << "setting theoryof-mode to term-based" << endl;
+ options::theoryOfMode.set(THEORY_OF_TERM_BASED);
}
- } else {
- Theory::setTheoryOfMode(options::theoryOfMode());
}
// by default, symmetry breaker is on only for QF_UF
@@ -849,11 +847,10 @@ void SmtEngine::setLogicInternal() throw() {
Trace("smt") << "setting uf symmetry breaker to " << qf_uf << endl;
options::ufSymmetryBreaker.set(qf_uf);
}
- // by default, nonclausal simplification is off for QF_SAT and for quantifiers
+ // by default, nonclausal simplification is off for QF_SAT
if(! options::simplificationMode.wasSetByUser()) {
bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
- bool quantifiers = d_logic.isQuantified();
- Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << endl;
+ Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat) << endl;
//simplification=none works better for SMT LIB benchmarks with quantifiers, not others
//options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
@@ -990,14 +987,16 @@ void SmtEngine::setLogicInternal() throw() {
d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
) ||
// Quantifiers
- d_logic.isQuantified()
+ d_logic.isQuantified() ||
+ // Strings
+ d_logic.isTheoryEnabled(THEORY_STRINGS)
? decision::DECISION_STRATEGY_JUSTIFICATION
: decision::DECISION_STRATEGY_INTERNAL
);
bool stoponly =
// ALL_SUPPORTED
- d_logic.hasEverything() ? false :
+ d_logic.hasEverything() || d_logic.isTheoryEnabled(THEORY_STRINGS) ? false :
( // QF_AUFLIA
(not d_logic.isQuantified() &&
d_logic.isTheoryEnabled(THEORY_ARRAY) &&
@@ -1020,11 +1019,21 @@ void SmtEngine::setLogicInternal() throw() {
//for finite model finding
if( ! options::instWhenMode.wasSetByUser()){
+ //instantiate only on last call
if( options::fmfInstEngine() ){
Trace("smt") << "setting inst when mode to LAST_CALL" << endl;
options::instWhenMode.set( INST_WHEN_LAST_CALL );
}
}
+ if ( ! options::fmfInstGen.wasSetByUser()) {
+ //if full model checking is on, disable inst-gen techniques
+ if( options::fmfFullModelCheck() ){
+ options::fmfInstGen.set( false );
+ }
+ }
+ if( options::ufssSymBreak() ){
+ options::sortInference.set( true );
+ }
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
@@ -1108,13 +1117,15 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
}
// Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
- if(key == "name" ||
- key == "source" ||
+ if(key == "source" ||
key == "category" ||
key == "difficulty" ||
key == "notes") {
// ignore these
return;
+ } else if(key == "name") {
+ d_filename = value.getValue();
+ return;
} else if(key == "smt-lib-version") {
if( (value.isInteger() && value.getIntegerValue() == Integer(2)) ||
(value.isRational() && value.getRationalValue() == Rational(2)) ||
@@ -1133,7 +1144,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
throw OptionException("argument to (set-info :status ..) must be "
"`sat' or `unsat' or `unknown'");
}
- d_status = Result(s);
+ d_status = Result(s, d_filename);
return;
}
throw UnrecognizedOptionException();
@@ -1166,7 +1177,7 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
return stats;
} else if(key == "error-behavior") {
// immediate-exit | continued-execution
- return SExpr::Keyword("immediate-exit");
+ return SExpr::Keyword("continued-execution");
} else if(key == "name") {
return Configuration::getName();
} else if(key == "version") {
@@ -1194,6 +1205,9 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
throw ModalException("Can't get-info :reason-unknown when the "
"last result wasn't unknown!");
}
+ } else if(key == "all-options") {
+ // get the options, like all-statistics
+ return Options::current().getOptions();
} else {
throw UnrecognizedOptionException();
}
@@ -1213,13 +1227,13 @@ void SmtEngine::defineFunction(Expr func,
throw TypeCheckingException(func, ss.str());
}
}
- if(Dump.isOn("declarations")) {
- stringstream ss;
- ss << Expr::setlanguage(Expr::setlanguage::getLanguage(Dump.getStream()))
- << func;
- DefineFunctionCommand c(ss.str(), func, formals, formula);
- addToModelCommandAndDump(c, false, true, "declarations");
- }
+
+ stringstream ss;
+ ss << Expr::setlanguage(Expr::setlanguage::getLanguage(Dump.getStream()))
+ << func;
+ DefineFunctionCommand c(ss.str(), func, formals, formula);
+ addToModelCommandAndDump(c, ExprManager::VAR_FLAG_NONE, true, "declarations");
+
SmtScope smts(this);
// Substitute out any abstract values in formula
@@ -1316,6 +1330,11 @@ Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
Node divTotalNumDen = nm->mkNode(n.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
kind::BITVECTOR_UREM_TOTAL, num, den);
Node node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
return node;
}
@@ -1323,168 +1342,209 @@ Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
throw(TypeCheckingException, LogicException) {
- Kind k = n.getKind();
+ stack< triple<Node, Node, bool> > worklist;
+ stack<Node> result;
+ worklist.push(make_triple(Node(n), Node(n), false));
+
+ do {
+ n = worklist.top().first;
+ Node node = worklist.top().second;
+ bool childrenPushed = worklist.top().third;
+ worklist.pop();
- if(k != kind::APPLY && n.getNumChildren() == 0) {
- SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
- if(i != d_smt.d_definedFunctions->end()) {
- // replacement must be closed
- if((*i).second.getFormals().size() > 0) {
- return d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula());
+ if(!childrenPushed) {
+ Kind k = n.getKind();
+
+ if(k != kind::APPLY && n.getNumChildren() == 0) {
+ SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
+ if(i != d_smt.d_definedFunctions->end()) {
+ // replacement must be closed
+ if((*i).second.getFormals().size() > 0) {
+ result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push((*i).second.getFormula());
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push(n);
+ continue;
}
- // don't bother putting in the cache
- return (*i).second.getFormula();
- }
- // don't bother putting in the cache
- return n;
- }
- // maybe it's in the cache
- hash_map<Node, Node, NodeHashFunction>::iterator cacheHit = cache.find(n);
- if(cacheHit != cache.end()) {
- TNode ret = (*cacheHit).second;
- return ret.isNull() ? n : ret;
- }
+ // maybe it's in the cache
+ hash_map<Node, Node, NodeHashFunction>::iterator cacheHit = cache.find(n);
+ if(cacheHit != cache.end()) {
+ TNode ret = (*cacheHit).second;
+ result.push(ret.isNull() ? n : ret);
+ continue;
+ }
- // otherwise expand it
+ // otherwise expand it
- Node node = n;
- NodeManager* nm = d_smt.d_nodeManager;
- // FIXME: this theory specific code should be factored out of the SmtEngine, somehow
- switch(k) {
- case kind::BITVECTOR_SDIV:
- case kind::BITVECTOR_SREM:
- case kind::BITVECTOR_SMOD: {
- node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
- break;
- }
-
- case kind::BITVECTOR_UDIV:
- case kind::BITVECTOR_UREM: {
- node = expandBVDivByZero(node);
- break;
- }
- case kind::DIVISION: {
- // partial function: division
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_divByZero.isNull()) {
- d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
- "partial real division", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
- Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- break;
- }
-
- case kind::INTS_DIVISION: {
- // partial function: integer div
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_intDivByZero.isNull()) {
- d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
- Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
- break;
- }
-
- case kind::INTS_MODULUS: {
- // partial function: mod
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_modZero.isNull()) {
- d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
- Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
- break;
- }
-
- case kind::APPLY: {
- // application of a user-defined symbol
- TNode func = n.getOperator();
- SmtEngine::DefinedFunctionMap::const_iterator i =
- d_smt.d_definedFunctions->find(func);
- DefinedFunction def = (*i).second;
- vector<Node> formals = def.getFormals();
-
- if(Debug.isOn("expand")) {
- Debug("expand") << "found: " << n << endl;
- Debug("expand") << " func: " << func << endl;
- string name = func.getAttribute(expr::VarNameAttr());
- Debug("expand") << " : \"" << name << "\"" << endl;
- }
- if(i == d_smt.d_definedFunctions->end()) {
- throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'");
- }
- if(Debug.isOn("expand")) {
- Debug("expand") << " defn: " << def.getFunction() << endl
- << " [";
- if(formals.size() > 0) {
- copy( formals.begin(), formals.end() - 1,
- ostream_iterator<Node>(Debug("expand"), ", ") );
- Debug("expand") << formals.back();
+ NodeManager* nm = d_smt.d_nodeManager;
+ // FIXME: this theory-specific code should be factored out of the
+ // SmtEngine, somehow
+ switch(k) {
+ case kind::BITVECTOR_SDIV:
+ case kind::BITVECTOR_SREM:
+ case kind::BITVECTOR_SMOD:
+ node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
+ break;
+
+ case kind::BITVECTOR_UDIV:
+ case kind::BITVECTOR_UREM:
+ node = expandBVDivByZero(node);
+ break;
+
+ case kind::DIVISION: {
+ // partial function: division
+ if(d_divByZero.isNull()) {
+ d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
+ "partial real division", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
+ Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ break;
}
- Debug("expand") << "]" << endl
- << " " << def.getFunction().getType() << endl
- << " " << def.getFormula() << endl;
- }
- TNode fm = def.getFormula();
- Node instance = fm.substitute(formals.begin(), formals.end(),
- n.begin(), n.end());
- Debug("expand") << "made : " << instance << endl;
+ case kind::INTS_DIVISION: {
+ // partial function: integer div
+ if(d_intDivByZero.isNull()) {
+ d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
+ Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
+ break;
+ }
- Node expanded = expandDefinitions(instance, cache);
- cache[n] = (n == expanded ? Node::null() : expanded);
- return expanded;
- }
+ case kind::INTS_MODULUS: {
+ // partial function: mod
+ if(d_modZero.isNull()) {
+ d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
+ Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
+ break;
+ }
- default:
- // unknown kind for expansion, just iterate over the children
- node = n;
- }
+ case kind::ABS: {
+ Node out = nm->mkNode(kind::ITE, nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))), nm->mkNode(kind::UMINUS, node[0]), node[0]);
+ cache[n] = out;
+ result.push(out);
+ continue;
+ }
- // there should be children here, otherwise we short-circuited a return, above
- Assert(node.getNumChildren() > 0);
+ case kind::APPLY: {
+ // application of a user-defined symbol
+ TNode func = n.getOperator();
+ SmtEngine::DefinedFunctionMap::const_iterator i =
+ d_smt.d_definedFunctions->find(func);
+ DefinedFunction def = (*i).second;
+ vector<Node> formals = def.getFormals();
+
+ if(Debug.isOn("expand")) {
+ Debug("expand") << "found: " << n << endl;
+ Debug("expand") << " func: " << func << endl;
+ string name = func.getAttribute(expr::VarNameAttr());
+ Debug("expand") << " : \"" << name << "\"" << endl;
+ }
+ if(i == d_smt.d_definedFunctions->end()) {
+ throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'");
+ }
+ if(Debug.isOn("expand")) {
+ Debug("expand") << " defn: " << def.getFunction() << endl
+ << " [";
+ if(formals.size() > 0) {
+ copy( formals.begin(), formals.end() - 1,
+ ostream_iterator<Node>(Debug("expand"), ", ") );
+ Debug("expand") << formals.back();
+ }
+ Debug("expand") << "]" << endl
+ << " " << def.getFunction().getType() << endl
+ << " " << def.getFormula() << endl;
+ }
- // the partial functions can fall through, in which case we still
- // consider their children
- Debug("expand") << "cons : " << node << endl;
- NodeBuilder<> nb(node.getKind());
- if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- Debug("expand") << "op : " << node.getOperator() << endl;
- nb << node.getOperator();
- }
- for(Node::iterator i = node.begin(),
- iend = node.end();
- i != iend;
- ++i) {
- Node expanded = expandDefinitions(*i, cache);
- Debug("expand") << "exchld: " << expanded << endl;
- nb << expanded;
- }
- node = nb;
- cache[n] = n == node ? Node::null() : node;
- return node;
+ TNode fm = def.getFormula();
+ Node instance = fm.substitute(formals.begin(), formals.end(),
+ n.begin(), n.end());
+ Debug("expand") << "made : " << instance << endl;
+
+ Node expanded = expandDefinitions(instance, cache);
+ cache[n] = (n == expanded ? Node::null() : expanded);
+ result.push(expanded);
+ continue;
+ }
+
+ default:
+ // unknown kind for expansion, just iterate over the children
+ node = n;
+ }
+
+ // there should be children here, otherwise we short-circuited a result-push/continue, above
+ Assert(node.getNumChildren() > 0);
+
+ // the partial functions can fall through, in which case we still
+ // consider their children
+ worklist.push(make_triple(Node(n), node, true));
+
+ for(size_t i = 0; i < node.getNumChildren(); ++i) {
+ worklist.push(make_triple(node[i], node[i], false));
+ }
+
+ } else {
+
+ Debug("expand") << "cons : " << node << endl;
+ //cout << "cons : " << node << endl;
+ NodeBuilder<> nb(node.getKind());
+ if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ Debug("expand") << "op : " << node.getOperator() << endl;
+ //cout << "op : " << node.getOperator() << endl;
+ nb << node.getOperator();
+ }
+ for(size_t i = 0; i < node.getNumChildren(); ++i) {
+ Assert(!result.empty());
+ Node expanded = result.top();
+ result.pop();
+ //cout << "exchld : " << expanded << endl;
+ Debug("expand") << "exchld : " << expanded << endl;
+ nb << expanded;
+ }
+ node = nb;
+ cache[n] = n == node ? Node::null() : node;
+ result.push(node);
+ }
+ } while(!worklist.empty());
+
+ AlwaysAssert(result.size() == 1);
+
+ return result.top();
}
@@ -1666,6 +1726,10 @@ bool SmtEnginePrivate::nonClausalSimplify() {
<< "asserting to propagator" << endl;
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Assert(Rewriter::rewrite(d_assertionsToPreprocess[i]) == d_assertionsToPreprocess[i]);
+ // Don't reprocess substitutions
+ if (d_substitutionsIndex > 0 && i == d_substitutionsIndex) {
+ continue;
+ }
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertionsToPreprocess[i] << endl;
d_propagator.assertTrue(d_assertionsToPreprocess[i]);
}
@@ -1684,12 +1748,15 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// No, conflict, go through the literals and solve them
SubstitutionMap constantPropagations(d_smt.d_context);
+ SubstitutionMap newSubstitutions(d_smt.d_context);
+ SubstitutionMap::iterator pos;
unsigned j = 0;
for(unsigned i = 0, i_end = d_nonClausalLearnedLiterals.size(); i < i_end; ++ i) {
// Simplify the literal we learned wrt previous substitutions
Node learnedLiteral = d_nonClausalLearnedLiterals[i];
Assert(Rewriter::rewrite(learnedLiteral) == learnedLiteral);
- Node learnedLiteralNew = d_topLevelSubstitutions.apply(learnedLiteral);
+ Assert(d_topLevelSubstitutions.apply(learnedLiteral) == learnedLiteral);
+ Node learnedLiteralNew = newSubstitutions.apply(learnedLiteral);
if (learnedLiteral != learnedLiteralNew) {
learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
}
@@ -1717,18 +1784,21 @@ bool SmtEnginePrivate::nonClausalSimplify() {
return false;
}
}
- // Solve it with the corresponding theory
+
+ // Solve it with the corresponding theory, possibly adding new
+ // substitutions to newSubstitutions
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "solving " << learnedLiteral << endl;
+
Theory::PPAssertStatus solveStatus =
- d_smt.d_theoryEngine->solve(learnedLiteral, d_topLevelSubstitutions);
+ d_smt.d_theoryEngine->solve(learnedLiteral, newSubstitutions);
switch (solveStatus) {
case Theory::PP_ASSERT_STATUS_SOLVED: {
// The literal should rewrite to true
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "solved " << learnedLiteral << endl;
- Assert(Rewriter::rewrite(d_topLevelSubstitutions.apply(learnedLiteral)).isConst());
+ Assert(Rewriter::rewrite(newSubstitutions.apply(learnedLiteral)).isConst());
// vector<pair<Node, Node> > equations;
// constantPropagations.simplifyLHS(d_topLevelSubstitutions, equations, true);
// if (equations.empty()) {
@@ -1763,6 +1833,7 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Assert(!t.isConst());
Assert(constantPropagations.apply(t) == t);
Assert(d_topLevelSubstitutions.apply(t) == t);
+ Assert(newSubstitutions.apply(t) == t);
constantPropagations.addSubstitution(t, c);
// vector<pair<Node,Node> > equations;a
// constantPropagations.simplifyLHS(t, c, equations, true);
@@ -1788,10 +1859,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// 3. if l -> r is a constant propagation and l is a subterm of l' with l' -> r' another constant propagation, then l'[l/r] -> r' should be a
// constant propagation too
// 4. each lhs of constantPropagations is different from each rhs
- SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin();
- for (; pos != d_topLevelSubstitutions.end(); ++pos) {
+ for (pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
Assert((*pos).first.isVar());
- // Assert(d_topLevelSubstitutions.apply((*pos).second) == (*pos).second);
+ Assert(d_topLevelSubstitutions.apply((*pos).first) == (*pos).first);
+ Assert(d_topLevelSubstitutions.apply((*pos).second) == (*pos).second);
+ Assert(newSubstitutions.apply(newSubstitutions.apply((*pos).second)) == newSubstitutions.apply((*pos).second));
}
for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Assert((*pos).second.isConst());
@@ -1815,27 +1887,16 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// Resize the learnt
d_nonClausalLearnedLiterals.resize(j);
- //must add substitutions to model
- TheoryModel* m = d_smt.d_theoryEngine->getModel();
- if(m != NULL) {
- for( SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin(); pos != d_topLevelSubstitutions.end(); ++pos) {
- Node n = (*pos).first;
- Node v = (*pos).second;
- Trace("model") << "Add substitution : " << n << " " << v << endl;
- m->addSubstitution( n, v );
- }
- }
-
hash_set<TNode, TNodeHashFunction> s;
- Trace("debugging") << "NonClausal simplify pre-preprocess\n";
+ Trace("debugging") << "NonClausal simplify pre-preprocess\n";
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Node assertion = d_assertionsToPreprocess[i];
- Node assertionNew = d_topLevelSubstitutions.apply(assertion);
+ Node assertionNew = newSubstitutions.apply(assertion);
Trace("debugging") << "assertion = " << assertion << endl;
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
if (assertion != assertionNew) {
assertion = Rewriter::rewrite(assertionNew);
- Trace("debugging") << "rewrite(assertion) = " << assertion << endl;
+ Trace("debugging") << "rewrite(assertion) = " << assertion << endl;
}
Assert(Rewriter::rewrite(assertion) == assertion);
for (;;) {
@@ -1844,11 +1905,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
break;
}
++d_smt.d_stats->d_numConstantProps;
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
assertion = Rewriter::rewrite(assertionNew);
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
}
- Trace("debugging") << "\n";
+ Trace("debugging") << "\n";
s.insert(assertion);
d_assertionsToCheck.push_back(assertion);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -1857,34 +1918,44 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_assertionsToPreprocess.clear();
- NodeBuilder<> learnedBuilder(kind::AND);
- Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
- learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
-
- if( options::incrementalSolving() ||
- options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL ) {
- // Keep substitutions
- SubstitutionMap::iterator pos = d_lastSubstitutionPos;
- if(pos == d_topLevelSubstitutions.end()) {
- pos = d_topLevelSubstitutions.begin();
- } else {
- ++pos;
- }
-
- while(pos != d_topLevelSubstitutions.end()) {
- // Push out this substitution
- TNode lhs = (*pos).first, rhs = (*pos).second;
+ // If in incremental mode, add substitutions to the list of assertions
+ if (d_substitutionsIndex > 0) {
+ NodeBuilder<> substitutionsBuilder(kind::AND);
+ substitutionsBuilder << d_assertionsToCheck[d_substitutionsIndex];
+ pos = newSubstitutions.begin();
+ for (; pos != newSubstitutions.end(); ++pos) {
+ // Add back this substitution as an assertion
+ TNode lhs = (*pos).first, rhs = newSubstitutions.apply((*pos).second);
Node n = NodeManager::currentNM()->mkNode(lhs.getType().isBoolean() ? kind::IFF : kind::EQUAL, lhs, rhs);
- learnedBuilder << n;
+ substitutionsBuilder << n;
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n << endl;
- d_lastSubstitutionPos = pos;
- ++pos;
+ }
+ if (substitutionsBuilder.getNumChildren() > 1) {
+ d_assertionsToCheck[d_substitutionsIndex] =
+ Rewriter::rewrite(Node(substitutionsBuilder));
+ }
+ }
+ else {
+ // If not in incremental mode, must add substitutions to model
+ TheoryModel* m = d_smt.d_theoryEngine->getModel();
+ if(m != NULL) {
+ for(pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
+ Node n = (*pos).first;
+ Node v = newSubstitutions.apply((*pos).second);
+ Trace("model") << "Add substitution : " << n << " " << v << endl;
+ m->addSubstitution( n, v );
+ }
}
}
+ NodeBuilder<> learnedBuilder(kind::AND);
+ Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
+ learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+
for (unsigned i = 0; i < d_nonClausalLearnedLiterals.size(); ++ i) {
Node learned = d_nonClausalLearnedLiterals[i];
- Node learnedNew = d_topLevelSubstitutions.apply(learned);
+ Assert(d_topLevelSubstitutions.apply(learned) == learned);
+ Node learnedNew = newSubstitutions.apply(learned);
if (learned != learnedNew) {
learned = Rewriter::rewrite(learnedNew);
}
@@ -1908,10 +1979,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_nonClausalLearnedLiterals.clear();
- SubstitutionMap::iterator pos = constantPropagations.begin();
- for (; pos != constantPropagations.end(); ++pos) {
+
+ for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Node cProp = (*pos).first.eqNode((*pos).second);
- Node cPropNew = d_topLevelSubstitutions.apply(cProp);
+ Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
+ Node cPropNew = newSubstitutions.apply(cProp);
if (cProp != cPropNew) {
cProp = Rewriter::rewrite(cPropNew);
Assert(Rewriter::rewrite(cProp) == cProp);
@@ -1926,6 +1998,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
<< cProp << endl;
}
+ // Add new substitutions to topLevelSubstitutions
+ // Note that we don't have to keep rhs's in full solved form
+ // because SubstitutionMap::apply does a fixed-point iteration when substituting
+ d_topLevelSubstitutions.addSubstitutions(newSubstitutions);
+
if(learnedBuilder.getNumChildren() > 1) {
d_assertionsToCheck[d_realAssertionsEnd - 1] =
Rewriter::rewrite(Node(learnedBuilder));
@@ -1939,7 +2016,7 @@ bool SmtEnginePrivate::nonClausalSimplify() {
void SmtEnginePrivate::bvToBool() {
Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl;
std::vector<Node> new_assertions;
- d_smt.d_theoryEngine->ppBvToBool(d_assertionsToCheck, new_assertions);
+ d_smt.d_theoryEngine->ppBvToBool(d_assertionsToCheck, new_assertions);
for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
d_assertionsToCheck[i] = Rewriter::rewrite(new_assertions[i]);
}
@@ -1950,8 +2027,7 @@ void SmtEnginePrivate::simpITE() {
Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl;
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
-
+ for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
d_assertionsToCheck[i] = d_smt.d_theoryEngine->ppSimpITE(d_assertionsToCheck[i]);
}
}
@@ -2039,7 +2115,6 @@ void SmtEnginePrivate::traceBackToAssertions(const std::vector<Node>& nodes, std
size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove) {
Assert(n.getKind() == kind::AND);
- Node trueNode = NodeManager::currentNM()->mkConst(true);
size_t removals = 0;
for(Node::iterator j = n.begin(); j != n.end(); ++j) {
size_t subremovals = 0;
@@ -2070,7 +2145,7 @@ size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsi
}
}
if(b.getNumChildren() == 0) {
- n = trueNode;
+ n = d_true;
b.clear();
} else if(b.getNumChildren() == 1) {
n = b[0];
@@ -2383,11 +2458,10 @@ void SmtEnginePrivate::doMiplibTrick() {
}
if(!removeAssertions.empty()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl;
- Node trueNode = nm->mkConst(true);
for(size_t i = 0; i < d_realAssertionsEnd; ++i) {
if(removeAssertions.find(d_assertionsToCheck[i].getId()) != removeAssertions.end()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck[i] << endl;
- d_assertionsToCheck[i] = trueNode;
+ d_assertionsToCheck[i] = d_true;
++d_smt.d_stats->d_numMiplibAssertionsRemoved;
} else if(d_assertionsToCheck[i].getKind() == kind::AND) {
size_t removals = removeFromConjunction(d_assertionsToCheck[i], removeAssertions);
@@ -2453,6 +2527,7 @@ bool SmtEnginePrivate::simplifyAssertions()
d_assertionsToCheck.swap(d_assertionsToPreprocess);
}
+ dumpAssertions("post-nonclausal", d_assertionsToCheck);
Trace("smt") << "POST nonClausalSimplify" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2470,6 +2545,7 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
+ dumpAssertions("post-theorypp", d_assertionsToCheck);
Trace("smt") << "POST theoryPP" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2480,6 +2556,7 @@ bool SmtEnginePrivate::simplifyAssertions()
simpITE();
}
+ dumpAssertions("post-itesimp", d_assertionsToCheck);
Trace("smt") << "POST iteSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2490,6 +2567,7 @@ bool SmtEnginePrivate::simplifyAssertions()
unconstrainedSimp();
}
+ dumpAssertions("post-unconstrained", d_assertionsToCheck);
Trace("smt") << "POST unconstrainedSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2506,6 +2584,7 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
+ dumpAssertions("post-repeatsimp", d_assertionsToCheck);
Trace("smt") << "POST repeatSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2534,11 +2613,26 @@ Result SmtEngine::check() {
Trace("smt") << "SmtEngine::check(): processing assertions" << endl;
d_private->processAssertions();
+ // Turn off stop only for QF_LRA
+ // TODO: Bring up in a meeting where to put this
+ if(options::decisionStopOnly() && !options::decisionMode.wasSetByUser() ){
+ if( // QF_LRA
+ (not d_logic.isQuantified() &&
+ d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
+ )){
+ if(d_private->d_iteSkolemMap.empty()){
+ options::decisionStopOnly.set(false);
+ d_decisionEngine->clearStrategies();
+ Trace("smt") << "SmtEngine::check(): turning off stop only" << endl;
+ }
+ }
+ }
+
unsigned long millis = 0;
if(d_timeBudgetCumulative != 0) {
millis = getTimeRemaining();
if(millis == 0) {
- return Result(Result::VALIDITY_UNKNOWN, Result::TIMEOUT);
+ return Result(Result::VALIDITY_UNKNOWN, Result::TIMEOUT, d_filename);
}
}
if(d_timeBudgetPerCall != 0 && (millis == 0 || d_timeBudgetPerCall < millis)) {
@@ -2549,7 +2643,7 @@ Result SmtEngine::check() {
if(d_resourceBudgetCumulative != 0) {
resource = getResourceRemaining();
if(resource == 0) {
- return Result(Result::VALIDITY_UNKNOWN, Result::RESOURCEOUT);
+ return Result(Result::VALIDITY_UNKNOWN, Result::RESOURCEOUT, d_filename);
}
}
if(d_resourceBudgetPerCall != 0 && (resource == 0 || d_resourceBudgetPerCall < resource)) {
@@ -2570,13 +2664,13 @@ Result SmtEngine::check() {
Trace("limit") << "SmtEngine::check(): cumulative millis " << d_cumulativeTimeUsed
<< ", conflicts " << d_cumulativeResourceUsed << endl;
- return result;
+ return Result(result, d_filename);
}
Result SmtEngine::quickCheck() {
Assert(d_fullyInited);
Trace("smt") << "SMT quickCheck()" << endl;
- return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK);
+ return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
}
@@ -2655,14 +2749,26 @@ void SmtEnginePrivate::processAssertions() {
Assert(d_assertionsToCheck.size() == 0);
- // any assertions added beyond realAssertionsEnd must NOT affect the
- // equisatisfiability
- d_realAssertionsEnd = d_assertionsToPreprocess.size();
- if(d_realAssertionsEnd == 0) {
+ if (d_assertionsToPreprocess.size() == 0) {
// nothing to do
return;
}
+ if (d_assertionsProcessed &&
+ ( options::incrementalSolving() ||
+ options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL )) {
+ // Placeholder for storing substitutions
+ d_substitutionsIndex = d_assertionsToPreprocess.size();
+ d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ }
+
+ // Add dummy assertion in last position - to be used as a
+ // placeholder for any new assertions to get added
+ d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ // any assertions added beyond realAssertionsEnd must NOT affect the
+ // equisatisfiability
+ d_realAssertionsEnd = d_assertionsToPreprocess.size();
+
// Assertions are NOT guaranteed to be rewritten by this point
dumpAssertions("pre-definition-expansion", d_assertionsToPreprocess);
@@ -2671,7 +2777,7 @@ void SmtEnginePrivate::processAssertions() {
Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_definitionExpansionTime);
hash_map<Node, Node, NodeHashFunction> cache;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+ for(unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
d_assertionsToPreprocess[i] =
expandDefinitions(d_assertionsToPreprocess[i], cache);
}
@@ -2740,6 +2846,7 @@ void SmtEnginePrivate::processAssertions() {
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
dumpAssertions("pre-substitution", d_assertionsToPreprocess);
+
// Apply the substitutions we already have, and normalize
Chat() << "applying substitutions..." << endl;
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -2754,6 +2861,14 @@ void SmtEnginePrivate::processAssertions() {
// Assertions ARE guaranteed to be rewritten by this point
+ if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
+ CVC4::theory::strings::StringsPreprocess sp;
+ sp.simplify( d_assertionsToPreprocess );
+ for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ }
+ }
+
dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
@@ -2778,6 +2893,12 @@ void SmtEnginePrivate::processAssertions() {
}while( success );
}
+ Trace("fo-rsn-enable") << std::endl;
+ if( options::foPropQuant() ){
+ FirstOrderPropagation fop;
+ fop.simplify( d_assertionsToPreprocess );
+ }
+
if( options::sortInference() ){
//sort inference technique
d_smt.d_theoryEngine->getSortInference()->simplify( d_assertionsToPreprocess );
@@ -2798,7 +2919,7 @@ void SmtEnginePrivate::processAssertions() {
}
dumpAssertions("post-static-learning", d_assertionsToCheck);
- // Lift bit-vectors of size 1 to bool
+ // Lift bit-vectors of size 1 to bool
if(options::bvToBool()) {
Chat() << "...doing bvToBool..." << endl;
bvToBool();
@@ -2808,7 +2929,7 @@ void SmtEnginePrivate::processAssertions() {
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
-
+
dumpAssertions("pre-ite-removal", d_assertionsToCheck);
{
Chat() << "removing term ITEs..." << endl;
@@ -2883,7 +3004,7 @@ void SmtEnginePrivate::processAssertions() {
Rewriter::rewrite(Node(builder));
}
// For some reason this is needed for some benchmarks, such as
- // http://church.cims.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
+ // http://cvc4.cs.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
// Figure it out later
removeITEs();
// Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
@@ -2938,6 +3059,8 @@ void SmtEnginePrivate::processAssertions() {
}
}
+ d_assertionsProcessed = true;
+
d_assertionsToCheck.clear();
d_iteSkolemMap.clear();
}
@@ -2945,6 +3068,11 @@ void SmtEnginePrivate::processAssertions() {
void SmtEnginePrivate::addFormula(TNode n)
throw(TypeCheckingException, LogicException) {
+ if (n == d_true) {
+ // nothing to do
+ return;
+ }
+
Trace("smt") << "SmtEnginePrivate::addFormula(" << n << ")" << endl;
// Add the normalized formula to the queue
@@ -3130,7 +3258,7 @@ Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, Log
return quickCheck().asValidityResult();
}
-Node SmtEngine::postprocess(TNode node, TypeNode expectedType) {
+Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
ModelPostprocessor mpost;
NodeVisitor<ModelPostprocessor> visitor;
Node value = visitor.run(mpost, node);
@@ -3185,7 +3313,7 @@ Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException, L
return n.toExpr();
}
-Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, TypeCheckingException, LogicException) {
+Expr SmtEngine::getValue(const Expr& ex) const throw(ModalException, TypeCheckingException, LogicException) {
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
@@ -3300,7 +3428,7 @@ CVC4::SExpr SmtEngine::getAssignment() throw(ModalException) {
}
if(d_assignments == NULL) {
- return SExpr();
+ return SExpr(vector<SExpr>());
}
vector<SExpr> sexprs;
@@ -3340,7 +3468,7 @@ CVC4::SExpr SmtEngine::getAssignment() throw(ModalException) {
return SExpr(sexprs);
}
-void SmtEngine::addToModelCommandAndDump(const Command& c, bool isGlobal, bool userVisible, const char* dumpTag) {
+void SmtEngine::addToModelCommandAndDump(const Command& c, uint32_t flags, bool userVisible, const char* dumpTag) {
Trace("smt") << "SMT addToModelCommandAndDump(" << c << ")" << endl;
SmtScope smts(this);
// If we aren't yet fully inited, the user might still turn on
@@ -3353,7 +3481,7 @@ void SmtEngine::addToModelCommandAndDump(const Command& c, bool isGlobal, bool u
// and expects to find their cardinalities in the model.
if(/* userVisible && */ (!d_fullyInited || options::produceModels())) {
doPendingPops();
- if(isGlobal) {
+ if(flags & ExprManager::VAR_FLAG_GLOBAL) {
d_modelGlobalCommands.push_back(c.clone());
} else {
d_modelCommands->push_back(c.clone());
@@ -3391,7 +3519,9 @@ Model* SmtEngine::getModel() throw(ModalException) {
"Cannot get model when produce-models options is off.";
throw ModalException(msg);
}
- return d_theoryEngine->getModel();
+ TheoryModel* m = d_theoryEngine->getModel();
+ m->d_inputName = d_filename;
+ return m;
}
void SmtEngine::checkModel(bool hardFailure) {
@@ -3412,13 +3542,8 @@ void SmtEngine::checkModel(bool hardFailure) {
// Check individual theory assertions
d_theoryEngine->checkTheoryAssertionsWithModel();
- if(Notice.isOn()) {
- // This operator<< routine is non-const (i.e., takes a non-const Model&).
- // This confuses the Notice() output routines, so extract the ostream
- // from it and output it "manually." Should be fixed by making Model
- // accessors const.
- Notice.getStream() << *m;
- }
+ // Output the model
+ Notice() << *m;
// We have a "fake context" for the substitution map (we don't need it
// to be context-dependent)
@@ -3506,6 +3631,12 @@ void SmtEngine::checkModel(bool hardFailure) {
Debug("boolean-terms") << "++ got " << n << endl;
Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
+ if(Theory::theoryOf(n) != THEORY_REWRITERULES) {
+ // In case it's a quantifier (or contains one), look up its value before
+ // simplifying, or the quantifier might be irreparably altered.
+ n = m->getValue(n);
+ }
+
// Simplify the result.
n = d_private->simplify(n);
Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
@@ -3527,6 +3658,7 @@ void SmtEngine::checkModel(bool hardFailure) {
// but don't show up in our substitution map above.
n = m->getValue(n);
Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl;
+ AlwaysAssert(!hardFailure || n.isConst() || n.getKind() == kind::LAMBDA);
// The result should be == true.
if(n != NodeManager::currentNM()->mkConst(true)) {
@@ -3612,6 +3744,11 @@ void SmtEngine::push() throw(ModalException, LogicException) {
d_needPostsolve = false;
}
+ // The problem isn't really "extended" yet, but this disallows
+ // get-model after a push, simplifying our lives somewhat and
+ // staying symmtric with pop.
+ d_problemExtended = true;
+
d_userLevels.push_back(d_userContext->getLevel());
internalPush();
Trace("userpushpop") << "SmtEngine: pushed to level "
@@ -3638,6 +3775,14 @@ void SmtEngine::pop() throw(ModalException) {
d_needPostsolve = false;
}
+ // The problem isn't really "extended" yet, but this disallows
+ // get-model after a pop, simplifying our lives somewhat. It might
+ // not be strictly necessary to do so, since the pops occur lazily,
+ // but also it would be weird to have a legally-executed (get-model)
+ // that only returns a subset of the assignment (because the rest
+ // is no longer in scope!).
+ d_problemExtended = true;
+
AlwaysAssert(d_userContext->getLevel() > 0);
AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
while (d_userLevels.back() < d_userContext->getLevel()) {
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index a22e34c21..9655297b3 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -189,9 +189,9 @@ class CVC4_PUBLIC SmtEngine {
bool d_fullyInited;
/**
- * Whether or not we have added any assertions/declarations/definitions
- * since the last checkSat/query (and therefore we're not responsible
- * for an assignment).
+ * Whether or not we have added any assertions/declarations/definitions,
+ * or done push/pop, since the last checkSat/query, and therefore we're
+ * not responsible for models or proofs.
*/
bool d_problemExtended;
@@ -234,6 +234,16 @@ class CVC4_PUBLIC SmtEngine {
Result d_status;
/**
+ * The name of the input (if any).
+ */
+ std::string d_filename;
+
+ /**
+ * Verbosity of various commands.
+ */
+ std::map<std::string, Integer> d_commandVerbosity;
+
+ /**
* A private utility class to SmtEngine.
*/
smt::SmtEnginePrivate* d_private;
@@ -249,7 +259,7 @@ class CVC4_PUBLIC SmtEngine {
* like turning datatypes back into tuples, length-1-bitvectors back
* into booleans, etc.
*/
- Node postprocess(TNode n, TypeNode expectedType);
+ Node postprocess(TNode n, TypeNode expectedType) const;
/**
* This is something of an "init" procedure, but is idempotent; call
@@ -326,7 +336,7 @@ class CVC4_PUBLIC SmtEngine {
* Add to Model command. This is used for recording a command
* that should be reported during a get-model call.
*/
- void addToModelCommandAndDump(const Command& c, bool isGlobal = false, bool userVisible = true, const char* dumpTag = "declarations");
+ void addToModelCommandAndDump(const Command& c, uint32_t flags = 0, bool userVisible = true, const char* dumpTag = "declarations");
/**
* Get the model (only if immediately preceded by a SAT
@@ -350,12 +360,12 @@ public:
/**
* Set the logic of the script.
*/
- void setLogic(const std::string& logic) throw(ModalException);
+ void setLogic(const std::string& logic) throw(ModalException, LogicException);
/**
* Set the logic of the script.
*/
- void setLogic(const char* logic) throw(ModalException);
+ void setLogic(const char* logic) throw(ModalException, LogicException);
/**
* Set the logic of the script.
@@ -444,7 +454,7 @@ public:
* by a SAT or INVALID query). Only permitted if the SmtEngine is
* set to operate interactively and produce-models is on.
*/
- Expr getValue(const Expr& e) throw(ModalException, TypeCheckingException, LogicException);
+ Expr getValue(const Expr& e) const throw(ModalException, TypeCheckingException, LogicException);
/**
* Add a function to the set of expressions whose value is to be
@@ -497,9 +507,11 @@ public:
/**
* Set a resource limit for SmtEngine operations. This is like a time
* limit, but it's deterministic so that reproducible results can be
- * obtained. However, please note that it may not be deterministic
- * between different versions of CVC4, or even the same version on
- * different platforms.
+ * obtained. Currently, it's based on the number of conflicts.
+ * However, please note that the definition may change between different
+ * versions of CVC4 (as may the number of conflicts required, anyway),
+ * and it might even be different between instances of the same version
+ * of CVC4 on different platforms.
*
* A cumulative and non-cumulative (per-call) resource limit can be
* set at the same time. A call to setResourceLimit() with
diff --git a/src/smt/smt_options_template.cpp b/src/smt/smt_options_template.cpp
index 638cf2f83..4edd91a8d 100644
--- a/src/smt/smt_options_template.cpp
+++ b/src/smt/smt_options_template.cpp
@@ -44,11 +44,29 @@ void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
Dump("benchmark") << SetOptionCommand(key, value);
}
+ if(key == "command-verbosity") {
+ if(!value.isAtom()) {
+ const vector<SExpr>& cs = value.getChildren();
+ if(cs.size() == 2 &&
+ (cs[0].isKeyword() || cs[0].isString()) &&
+ cs[1].isInteger()) {
+ string c = cs[0].getValue();
+ const Integer& v = cs[1].getIntegerValue();
+ if(v < 0 || v > 2) {
+ throw OptionException("command-verbosity must be 0, 1, or 2");
+ }
+ d_commandVerbosity[c] = v;
+ return;
+ }
+ }
+ throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
+ }
+
string optionarg = value.getValue();
${smt_setoption_handlers}
-#line 52 "${template}"
+#line 70 "${template}"
throw UnrecognizedOptionException(key);
}
@@ -59,13 +77,56 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
NodeManagerScope nms(d_nodeManager);
Trace("smt") << "SMT getOption(" << key << ")" << endl;
+
+ if(key.length() >= 18 &&
+ key.compare(0, 18, "command-verbosity:") == 0) {
+ map<string, Integer>::const_iterator i = d_commandVerbosity.find(key.c_str() + 18);
+ if(i != d_commandVerbosity.end()) {
+ return (*i).second;
+ }
+ i = d_commandVerbosity.find("*");
+ if(i != d_commandVerbosity.end()) {
+ return (*i).second;
+ }
+ return Integer(2);
+ }
+
if(Dump.isOn("benchmark")) {
Dump("benchmark") << GetOptionCommand(key);
}
+ if(key == "command-verbosity") {
+ vector<SExpr> result;
+ SExpr defaultVerbosity;
+ for(map<string, Integer>::const_iterator i = d_commandVerbosity.begin();
+ i != d_commandVerbosity.end();
+ ++i) {
+ vector<SExpr> v;
+ v.push_back((*i).first);
+ v.push_back((*i).second);
+ if((*i).first == "*") {
+ // put the default at the end of the SExpr
+ defaultVerbosity = v;
+ } else {
+ result.push_back(v);
+ }
+ }
+ // put the default at the end of the SExpr
+ if(!defaultVerbosity.isAtom()) {
+ result.push_back(defaultVerbosity);
+ } else {
+ // ensure the default is always listed
+ vector<SExpr> v;
+ v.push_back("*");
+ v.push_back(Integer(2));
+ result.push_back(v);
+ }
+ return result;
+ }
+
${smt_getoption_handlers}
-#line 69 "${template}"
+#line 130 "${template}"
throw UnrecognizedOptionException(key);
}
diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am
index bd7b881e1..860075aa8 100644
--- a/src/theory/Makefile.am
+++ b/src/theory/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = \
-I@builddir@/.. -I@srcdir@/../include -I@srcdir@/..
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
-SUBDIRS = builtin booleans uf arith bv arrays datatypes quantifiers rewriterules
+SUBDIRS = builtin booleans uf arith bv arrays datatypes quantifiers rewriterules idl strings
DIST_SUBDIRS = $(SUBDIRS) example
noinst_LTLIBRARIES = libtheory.la
@@ -42,7 +42,9 @@ libtheory_la_SOURCES = \
model.h \
model.cpp \
rep_set.h \
- rep_set.cpp
+ rep_set.cpp \
+ atom_requests.h \
+ atom_requests.cpp
nodist_libtheory_la_SOURCES = \
rewriter_tables.h \
@@ -58,7 +60,9 @@ libtheory_la_LIBADD = \
@builddir@/bv/libbv.la \
@builddir@/datatypes/libdatatypes.la \
@builddir@/quantifiers/libquantifiers.la \
- @builddir@/rewriterules/librewriterules.la
+ @builddir@/rewriterules/librewriterules.la \
+ @builddir@/idl/libidl.la \
+ @builddir@/strings/libstrings.la
EXTRA_DIST = \
logic_info.i \
diff --git a/src/theory/arith/Makefile.am b/src/theory/arith/Makefile.am
index 3c664d806..620b8a121 100644
--- a/src/theory/arith/Makefile.am
+++ b/src/theory/arith/Makefile.am
@@ -51,8 +51,8 @@ libarith_la_SOURCES = \
soi_simplex.cpp \
approx_simplex.h \
approx_simplex.cpp \
- pure_update_simplex.h \
- pure_update_simplex.cpp \
+ attempt_solution_simplex.h \
+ attempt_solution_simplex.cpp \
theory_arith.h \
theory_arith.cpp \
theory_arith_private_forward.h \
diff --git a/src/theory/arith/approx_simplex.cpp b/src/theory/arith/approx_simplex.cpp
index d6be9f657..0f5a0fd4e 100644
--- a/src/theory/arith/approx_simplex.cpp
+++ b/src/theory/arith/approx_simplex.cpp
@@ -2,6 +2,7 @@
#include "theory/arith/approx_simplex.h"
#include "theory/arith/normal_form.h"
+#include "theory/arith/constraint.h"
#include <math.h>
#include <cmath>
@@ -94,6 +95,10 @@ public:
return Solution();
}
+ virtual ArithRatPairVec heuristicOptCoeffs() const{
+ return ArithRatPairVec();
+ }
+
virtual ApproxResult solveMIP(){
return ApproxError;
}
@@ -111,8 +116,14 @@ public:
/* Begin the declaration of GLPK specific code. */
#ifdef CVC4_USE_GLPK
extern "C" {
-#include <glpk.h>
-}
+/* Sometimes the header is in a subdirectory glpk/, sometimes not.
+ * The configure script figures it out. */
+#ifdef HAVE_GLPK_GLPK_H
+# include <glpk/glpk.h>
+#else /* HAVE_GLPK_GLPK_H */
+# include <glpk.h>
+#endif /* HAVE_GLPK_GLPK_H */
+}/* extern "C" */
namespace CVC4 {
namespace theory {
@@ -132,6 +143,8 @@ private:
bool d_solvedRelaxation;
bool d_solvedMIP;
+ static int s_verbosity;
+
public:
ApproxGLPK(const ArithVariables& vars);
~ApproxGLPK();
@@ -141,16 +154,22 @@ public:
return extractSolution(false);
}
+ virtual ArithRatPairVec heuristicOptCoeffs() const;
+
virtual ApproxResult solveMIP();
virtual Solution extractMIP() const{
return extractSolution(true);
}
virtual void setOptCoeffs(const ArithRatPairVec& ref);
+ static void printGLPKStatus(int status, std::ostream& out);
private:
Solution extractSolution(bool mip) const;
+ int guessDir(ArithVar v) const;
};
+int ApproxGLPK::s_verbosity = 0;
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
@@ -220,8 +239,10 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
ArithVar v = *vi;
- //cout << v << " ";
- //d_vars.printModel(v, cout);
+ if(s_verbosity >= 2){
+ Message() << v << " ";
+ d_vars.printModel(v, Message());
+ }
int type;
double lb = 0.0;
@@ -301,6 +322,189 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
delete[] ja;
delete[] ar;
}
+int ApproxGLPK::guessDir(ArithVar v) const{
+ if(d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ return -1;
+ }else if(!d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ return 1;
+ }else if(!d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ return 0;
+ }else{
+ int ubSgn = d_vars.getUpperBound(v).sgn();
+ int lbSgn = d_vars.getLowerBound(v).sgn();
+
+ if(ubSgn != 0 && lbSgn == 0){
+ return -1;
+ }else if(ubSgn == 0 && lbSgn != 0){
+ return 1;
+ }
+
+ return 1;
+ }
+}
+
+ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
+ ArithRatPairVec ret;
+
+ // Strategies are guess:
+ // 1 simple shared "ceiling" variable: danoint, pk1
+ // x1 >= c, x1 >= tmp1, x1 >= tmp2, ...
+ // 1 large row: fixnet, vpm2, pp08a
+ // (+ .......... ) <= c
+ // Not yet supported:
+ // 1 complex shared "ceiling" variable: opt1217
+ // x1 >= c, x1 >= (+ ..... ), x1 >= (+ ..... )
+ // and all of the ... are the same sign
+
+
+ // Candidates:
+ // 1) Upper and lower bounds are not equal.
+ // 2) The variable is not integer
+ // 3a) For columns look for a ceiling variable
+ // 3B) For rows look for a large row with
+
+ DenseMap<BoundCounts> d_colCandidates;
+ DenseMap<uint32_t> d_rowCandidates;
+
+ double sumRowLength = 0.0;
+ uint32_t maxRowLength = 0;
+ for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
+ ArithVar v = *vi;
+
+ if(s_verbosity >= 2){
+ Message() << v << " ";
+ d_vars.printModel(v, Message());
+ }
+
+ int type;
+ if(d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ if(d_vars.boundsAreEqual(v)){
+ type = GLP_FX;
+ }else{
+ type = GLP_DB;
+ }
+ }else if(d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ type = GLP_UP;
+ }else if(!d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ type = GLP_LO;
+ }else{
+ type = GLP_FR;
+ }
+
+ if(type != GLP_FX && type != GLP_FR){
+
+ if(d_vars.isSlack(v)){
+ Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
+ uint32_t len = p.size();
+ d_rowCandidates.set(v, len);
+ sumRowLength += len;
+ maxRowLength =std::max(maxRowLength, len);
+ }else if(!d_vars.isInteger(v)){
+ d_colCandidates.set(v, BoundCounts());
+ }
+ }
+ }
+
+ uint32_t maxCount = 0;
+ for(DenseMap<int>::const_iterator i = d_rowIndices.begin(), i_end = d_rowIndices.end(); i != i_end; ++i){
+ ArithVar v = *i;
+
+ bool lbCap = d_vars.hasLowerBound(v) && !d_vars.hasUpperBound(v);
+ bool ubCap = !d_vars.hasLowerBound(v) && d_vars.hasUpperBound(v);
+
+ if(lbCap || ubCap){
+ Constraint b = lbCap ? d_vars.getLowerBoundConstraint(v)
+ : d_vars.getUpperBoundConstraint(v);
+
+ if(!(b->getValue()).noninfinitesimalIsZero()){ continue; }
+
+ Polynomial poly = Polynomial::parsePolynomial(d_vars.asNode(v));
+ if(poly.size() != 2) { continue; }
+
+ Polynomial::iterator j = poly.begin();
+ Monomial first = *j;
+ ++j;
+ Monomial second = *j;
+
+ bool firstIsPos = first.constantIsPositive();
+ bool secondIsPos = second.constantIsPositive();
+
+ if(firstIsPos == secondIsPos){ continue; }
+
+ Monomial pos = firstIsPos == lbCap ? first : second;
+ Monomial neg = firstIsPos != lbCap ? first : second;
+ // pos >= neg
+ VarList p = pos.getVarList();
+ VarList n = neg.getVarList();
+ if(d_vars.hasArithVar(p.getNode())){
+ ArithVar ap = d_vars.asArithVar(p.getNode());
+ if( d_colCandidates.isKey(ap)){
+ BoundCounts bc = d_colCandidates.get(ap);
+ bc = BoundCounts(bc.lowerBoundCount(), bc.upperBoundCount()+1);
+ maxCount = std::max(maxCount, bc.upperBoundCount());
+ d_colCandidates.set(ap, bc);
+ }
+ }
+ if(d_vars.hasArithVar(n.getNode())){
+ ArithVar an = d_vars.asArithVar(n.getNode());
+ if( d_colCandidates.isKey(an)){
+ BoundCounts bc = d_colCandidates.get(an);
+ bc = BoundCounts(bc.lowerBoundCount()+1, bc.upperBoundCount());
+ maxCount = std::max(maxCount, bc.lowerBoundCount());
+ d_colCandidates.set(an, bc);
+ }
+ }
+ }
+ }
+
+ // Attempt row
+ double avgRowLength = d_rowCandidates.size() >= 1 ?
+ ( sumRowLength / d_rowCandidates.size() ) : 0.0;
+
+ // There is a large row among the candidates
+ bool guessARowCandidate = maxRowLength >= (10.0 * avgRowLength);
+
+ double rowLengthReq = (maxRowLength * .9);
+
+ if(guessARowCandidate){
+ for(DenseMap<uint32_t>::const_iterator i = d_rowCandidates.begin(), iend =d_rowCandidates.end(); i != iend; ++i ){
+ ArithVar r = *i;
+ uint32_t len = d_rowCandidates[r];
+
+ int dir = guessDir(r);
+ if(len >= rowLengthReq){
+ if(s_verbosity >= 1){
+ Message() << "high row " << r << " " << len << " " << avgRowLength << " " << dir<< endl;
+ d_vars.printModel(r, Message());
+ }
+ ret.push_back(ArithRatPair(r, Rational(dir)));
+ }
+ }
+ }
+
+ // Attempt columns
+ bool guessAColCandidate = maxCount >= 4;
+ if(guessAColCandidate){
+ for(DenseMap<BoundCounts>::const_iterator i = d_colCandidates.begin(), iend = d_colCandidates.end(); i != iend; ++i ){
+ ArithVar c = *i;
+ BoundCounts bc = d_colCandidates[c];
+
+ int dir = guessDir(c);
+ double ubScore = double(bc.upperBoundCount()) / maxCount;
+ double lbScore = double(bc.lowerBoundCount()) / maxCount;
+ if(ubScore >= .9 || lbScore >= .9){
+ if(s_verbosity >= 1){
+ Message() << "high col " << c << " " << bc << " " << ubScore << " " << lbScore << " " << dir << endl;
+ d_vars.printModel(c, Message());
+ }
+ ret.push_back(ArithRatPair(c, Rational(c)));
+ }
+ }
+ }
+
+
+ return ret;
+}
void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
DenseMap<double> nbCoeffs;
@@ -346,6 +550,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
}
}
+
/*
* rough strategy:
* real relaxation
@@ -361,7 +566,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
* check with FCSimplex
*/
-static void printGLPKStatus(int status, std::ostream& out){
+void ApproxGLPK::printGLPKStatus(int status, std::ostream& out){
switch(status){
case GLP_OPT:
out << "GLP_OPT" << endl;
@@ -406,77 +611,90 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
int glpk_index = isSlack ? d_rowIndices[vi] : d_colIndices[vi];
int status = isSlack ? glp_get_row_stat(d_prob, glpk_index) : glp_get_col_stat(d_prob, glpk_index);
- //cout << "assignment " << vi << endl;
+ if(s_verbosity >= 2){
+ Message() << "assignment " << vi << endl;
+ }
+
+ bool useDefaultAssignment = false;
switch(status){
case GLP_BS:
- //cout << "basic" << endl;
+ //Message() << "basic" << endl;
newBasis.add(vi);
+ useDefaultAssignment = true;
break;
case GLP_NL:
case GLP_NS:
if(!mip){
- //cout << "non-basic lb" << endl;
+ if(s_verbosity >= 2){ Message() << "non-basic lb" << endl; }
newValues.set(vi, d_vars.getLowerBound(vi));
- break;
- }// intentionally fall through otherwise
+ }else{// intentionally fall through otherwise
+ useDefaultAssignment = true;
+ }
+ break;
case GLP_NU:
if(!mip){
- // cout << "non-basic ub" << endl;
+ if(s_verbosity >= 2){ Message() << "non-basic ub" << endl; }
newValues.set(vi, d_vars.getUpperBound(vi));
- break;
- }// intentionally fall through otherwise
+ }else {// intentionally fall through otherwise
+ useDefaultAssignment = true;
+ }
+ break;
default:
{
- // cout << "non-basic other" << endl;
+ useDefaultAssignment = true;
+ }
+ break;
+ }
+
+ if(useDefaultAssignment){
+ if(s_verbosity >= 2){ Message() << "non-basic other" << endl; }
+
+ double newAssign =
+ mip ?
+ (isSlack ? glp_mip_row_val(d_prob, glpk_index) : glp_mip_col_val(d_prob, glpk_index))
+ : (isSlack ? glp_get_row_prim(d_prob, glpk_index) : glp_get_col_prim(d_prob, glpk_index));
+ const DeltaRational& oldAssign = d_vars.getAssignment(vi);
- double newAssign =
- mip ?
- (isSlack ? glp_mip_row_val(d_prob, glpk_index) : glp_mip_col_val(d_prob, glpk_index))
- : (isSlack ? glp_get_row_prim(d_prob, glpk_index) : glp_get_col_prim(d_prob, glpk_index));
- const DeltaRational& oldAssign = d_vars.getAssignment(vi);
+ if(d_vars.hasLowerBound(vi) &&
+ roughlyEqual(newAssign, d_vars.getLowerBound(vi).approx(SMALL_FIXED_DELTA))){
+ //Message() << " to lb" << endl;
- if(d_vars.hasLowerBound(vi) &&
- roughlyEqual(newAssign, d_vars.getLowerBound(vi).approx(SMALL_FIXED_DELTA))){
- //cout << " to lb" << endl;
+ newValues.set(vi, d_vars.getLowerBound(vi));
+ }else if(d_vars.hasUpperBound(vi) &&
+ roughlyEqual(newAssign, d_vars.getUpperBound(vi).approx(SMALL_FIXED_DELTA))){
+ newValues.set(vi, d_vars.getUpperBound(vi));
+ // Message() << " to ub" << endl;
+ }else{
- newValues.set(vi, d_vars.getLowerBound(vi));
- }else if(d_vars.hasUpperBound(vi) &&
- roughlyEqual(newAssign, d_vars.getUpperBound(vi).approx(SMALL_FIXED_DELTA))){
- newValues.set(vi, d_vars.getUpperBound(vi));
- // cout << " to ub" << endl;
+ double rounded = round(newAssign);
+ if(roughlyEqual(newAssign, rounded)){
+ // Message() << "roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
+ newAssign = rounded;
}else{
+ // Message() << "not roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
+ }
- double rounded = round(newAssign);
- if(roughlyEqual(newAssign, rounded)){
- // cout << "roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
- newAssign = rounded;
- }else{
- // cout << "not roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
- }
-
- DeltaRational proposal = estimateWithCFE(newAssign);
-
-
- if(roughlyEqual(newAssign, oldAssign.approx(SMALL_FIXED_DELTA))){
- // cout << " to prev value" << newAssign << " " << oldAssign << endl;
- proposal = d_vars.getAssignment(vi);
- }
-
-
- if(d_vars.strictlyLessThanLowerBound(vi, proposal)){
- //cout << " round to lb " << d_vars.getLowerBound(vi) << endl;
- proposal = d_vars.getLowerBound(vi);
- }else if(d_vars.strictlyGreaterThanUpperBound(vi, proposal)){
- //cout << " round to ub " << d_vars.getUpperBound(vi) << endl;
- proposal = d_vars.getUpperBound(vi);
- }else{
- //cout << " use proposal" << proposal << " " << oldAssign << endl;
- }
- newValues.set(vi, proposal);
+ DeltaRational proposal = estimateWithCFE(newAssign);
+
+
+ if(roughlyEqual(newAssign, oldAssign.approx(SMALL_FIXED_DELTA))){
+ // Message() << " to prev value" << newAssign << " " << oldAssign << endl;
+ proposal = d_vars.getAssignment(vi);
}
- break;
+
+
+ if(d_vars.strictlyLessThanLowerBound(vi, proposal)){
+ //Message() << " round to lb " << d_vars.getLowerBound(vi) << endl;
+ proposal = d_vars.getLowerBound(vi);
+ }else if(d_vars.strictlyGreaterThanUpperBound(vi, proposal)){
+ //Message() << " round to ub " << d_vars.getUpperBound(vi) << endl;
+ proposal = d_vars.getUpperBound(vi);
+ }else{
+ //Message() << " use proposal" << proposal << " " << oldAssign << endl;
+ }
+ newValues.set(vi, proposal);
}
}
}
@@ -492,8 +710,10 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
parm.meth = GLP_PRIMAL;
parm.pricing = GLP_PT_PSE;
parm.it_lim = d_pivotLimit;
- //parm.msg_lev = GLP_MSG_ALL;
parm.msg_lev = GLP_MSG_OFF;
+ if(s_verbosity >= 1){
+ parm.msg_lev = GLP_MSG_ALL;
+ }
int res = glp_simplex(d_prob, &parm);
switch(res){
@@ -550,8 +770,10 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
parm.cov_cuts = GLP_ON;
parm.cb_func = stopAtBingoOrPivotLimit;
parm.cb_info = &d_pivotLimit;
- //parm.msg_lev = GLP_MSG_ALL;
parm.msg_lev = GLP_MSG_OFF;
+ if(s_verbosity >= 1){
+ parm.msg_lev = GLP_MSG_ALL;
+ }
int res = glp_intopt(d_prob, &parm);
switch(res){
diff --git a/src/theory/arith/approx_simplex.h b/src/theory/arith/approx_simplex.h
index a2f3cde24..a34c8981d 100644
--- a/src/theory/arith/approx_simplex.h
+++ b/src/theory/arith/approx_simplex.h
@@ -24,7 +24,7 @@ public:
/**
* If glpk is enabled, return a subclass that can do something.
- * If glpk is disabled, return a sublass that does nothing.
+ * If glpk is disabled, return a subclass that does nothing.
*/
static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars);
ApproximateSimplex();
@@ -44,18 +44,15 @@ public:
/** Sets a maximization criteria for the approximate solver.*/
virtual void setOptCoeffs(const ArithRatPairVec& ref) = 0;
+ virtual ArithRatPairVec heuristicOptCoeffs() const = 0;
+
virtual ApproxResult solveRelaxation() = 0;
virtual Solution extractRelaxation() const = 0;
virtual ApproxResult solveMIP() = 0;
virtual Solution extractMIP() const = 0;
- static void applySolution(LinearEqualityModule& linEq, const Solution& sol){
- linEq.forceNewBasis(sol.newBasis);
- linEq.updateMany(sol.newValues);
- }
-
- /** UTILIES FOR DEALING WITH ESTIMATES */
+ /** UTILITIES FOR DEALING WITH ESTIMATES */
static const double SMALL_FIXED_DELTA;
static const double TOLERENCE;
diff --git a/src/theory/arith/arith_rewriter.cpp b/src/theory/arith/arith_rewriter.cpp
index aa5049ed4..247c09294 100644
--- a/src/theory/arith/arith_rewriter.cpp
+++ b/src/theory/arith/arith_rewriter.cpp
@@ -29,7 +29,8 @@ namespace theory {
namespace arith {
bool ArithRewriter::isAtom(TNode n) {
- return arith::isRelationOperator(n.getKind());
+ Kind k = n.getKind();
+ return arith::isRelationOperator(k) || k == kind::IS_INTEGER || k == kind::DIVISIBLE;
}
RewriteResponse ArithRewriter::rewriteConstant(TNode t){
@@ -98,11 +99,28 @@ RewriteResponse ArithRewriter::preRewriteTerm(TNode t){
return preRewritePlus(t);
case kind::MULT:
return preRewriteMult(t);
- //case kind::INTS_DIVISION:
- //case kind::INTS_MODULUS:
+ case kind::INTS_DIVISION:
+ case kind::INTS_MODULUS:
+ return RewriteResponse(REWRITE_DONE, t);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t,true);
+ case kind::ABS:
+ if(t[0].isConst()) {
+ const Rational& rat = t[0].getConst<Rational>();
+ if(rat >= 0) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ } else {
+ return RewriteResponse(REWRITE_DONE,
+ NodeManager::currentNM()->mkConst(-rat));
+ }
+ }
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::IS_INTEGER:
+ case kind::TO_INTEGER:
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::TO_REAL:
+ return RewriteResponse(REWRITE_DONE, t[0]);
default:
Unhandled(k);
}
@@ -126,11 +144,44 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
return postRewritePlus(t);
case kind::MULT:
return postRewriteMult(t);
- //case kind::INTS_DIVISION:
- //case kind::INTS_MODULUS:
+ case kind::INTS_DIVISION:
+ case kind::INTS_MODULUS:
+ return RewriteResponse(REWRITE_DONE, t);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t, false);
+ case kind::ABS:
+ if(t[0].isConst()) {
+ const Rational& rat = t[0].getConst<Rational>();
+ if(rat >= 0) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ } else {
+ return RewriteResponse(REWRITE_DONE,
+ NodeManager::currentNM()->mkConst(-rat));
+ }
+ }
+ case kind::TO_REAL:
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ case kind::TO_INTEGER:
+ if(t[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(Rational(t[0].getConst<Rational>().floor())));
+ }
+ if(t[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ }
+ //Unimplemented("TO_INTEGER, nonconstant");
+ //return rewriteToInteger(t);
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::IS_INTEGER:
+ if(t[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(t[0].getConst<Rational>().getDenominator() == 1));
+ }
+ if(t[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ //Unimplemented("IS_INTEGER, nonconstant");
+ //return rewriteIsInteger(t);
+ return RewriteResponse(REWRITE_DONE, t);
default:
Unreachable();
}
@@ -190,6 +241,25 @@ RewriteResponse ArithRewriter::postRewriteMult(TNode t){
}
RewriteResponse ArithRewriter::postRewriteAtom(TNode atom){
+ if(atom.getKind() == kind::IS_INTEGER) {
+ if(atom[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(atom[0].getConst<Rational>().isIntegral()));
+ }
+ if(atom[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ // not supported, but this isn't the right place to complain
+ return RewriteResponse(REWRITE_DONE, atom);
+ } else if(atom.getKind() == kind::DIVISIBLE) {
+ if(atom[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(bool((atom[0].getConst<Rational>() / atom.getOperator().getConst<Divisible>().k).isIntegral())));
+ }
+ if(atom.getOperator().getConst<Divisible>().k.isOne()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ return RewriteResponse(REWRITE_AGAIN, NodeManager::currentNM()->mkNode(kind::EQUAL, NodeManager::currentNM()->mkNode(kind::INTS_MODULUS_TOTAL, atom[0], NodeManager::currentNM()->mkConst(Rational(atom.getOperator().getConst<Divisible>().k))), NodeManager::currentNM()->mkConst(Rational(0))));
+ }
+
// left |><| right
TNode left = atom[0];
TNode right = atom[1];
@@ -217,6 +287,14 @@ RewriteResponse ArithRewriter::preRewriteAtom(TNode atom){
}else if(atom.getKind() == kind::LT){
Node geq = currNM->mkNode(kind::GEQ, atom[0], atom[1]);
return RewriteResponse(REWRITE_DONE, currNM->mkNode(kind::NOT, geq));
+ }else if(atom.getKind() == kind::IS_INTEGER){
+ if(atom[0].getType().isInteger()){
+ return RewriteResponse(REWRITE_DONE, currNM->mkConst(true));
+ }
+ }else if(atom.getKind() == kind::DIVISIBLE){
+ if(atom.getOperator().getConst<Divisible>().k.isOne()){
+ return RewriteResponse(REWRITE_DONE, currNM->mkConst(true));
+ }
}
return RewriteResponse(REWRITE_DONE, atom);
@@ -329,6 +407,13 @@ RewriteResponse ArithRewriter::rewriteIntsDivModTotal(TNode t, bool pre){
Assert(k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL);
return RewriteResponse(REWRITE_AGAIN, n);
}
+ }else if(dIsConstant && d.getConst<Rational>().isNegativeOne()){
+ if(k == kind::INTS_MODULUS || k == kind::INTS_MODULUS_TOTAL){
+ return RewriteResponse(REWRITE_DONE, mkRationalNode(0));
+ }else{
+ Assert(k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL);
+ return RewriteResponse(REWRITE_AGAIN, NodeManager::currentNM()->mkNode(kind::UMINUS, n));
+ }
}else if(dIsConstant && n.getKind() == kind::CONST_RATIONAL){
Assert(d.getConst<Rational>().isIntegral());
Assert(n.getConst<Rational>().isIntegral());
diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h
index c4bf92a16..d8407eeba 100644
--- a/src/theory/arith/arith_static_learner.h
+++ b/src/theory/arith/arith_static_learner.h
@@ -23,7 +23,6 @@
#include "util/statistics_registry.h"
#include "theory/arith/arith_utilities.h"
-#include "theory/substitutions.h"
#include "context/context.h"
#include "context/cdlist.h"
diff --git a/src/theory/arith/attempt_solution_simplex.cpp b/src/theory/arith/attempt_solution_simplex.cpp
new file mode 100644
index 000000000..f0cecc24b
--- /dev/null
+++ b/src/theory/arith/attempt_solution_simplex.cpp
@@ -0,0 +1,135 @@
+
+#include "theory/arith/attempt_solution_simplex.h"
+#include "theory/arith/options.h"
+#include "theory/arith/constraint.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+AttemptSolutionSDP::AttemptSolutionSDP(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc)
+ : SimplexDecisionProcedure(linEq, errors, conflictChannel, tvmalloc)
+ , d_statistics()
+{ }
+
+AttemptSolutionSDP::Statistics::Statistics():
+ d_searchTime("theory::arith::attempt::searchTime"),
+ d_queueTime("theory::arith::attempt::queueTime"),
+ d_conflicts("theory::arith::attempt::conflicts", 0)
+{
+ StatisticsRegistry::registerStat(&d_searchTime);
+ StatisticsRegistry::registerStat(&d_queueTime);
+ StatisticsRegistry::registerStat(&d_conflicts);
+}
+
+AttemptSolutionSDP::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_searchTime);
+ StatisticsRegistry::unregisterStat(&d_queueTime);
+ StatisticsRegistry::unregisterStat(&d_conflicts);
+}
+
+bool AttemptSolutionSDP::matchesNewValue(const DenseMap<DeltaRational>& nv, ArithVar v) const{
+ return nv[v] == d_variables.getAssignment(v);
+}
+
+Result::Sat AttemptSolutionSDP::attempt(const ApproximateSimplex::Solution& sol){
+ const DenseSet& newBasis = sol.newBasis;
+ const DenseMap<DeltaRational>& newValues = sol.newValues;
+
+ DenseSet needsToBeAdded;
+ for(DenseSet::const_iterator i = newBasis.begin(), i_end = newBasis.end(); i != i_end; ++i){
+ ArithVar b = *i;
+ if(!d_tableau.isBasic(b)){
+ needsToBeAdded.add(b);
+ }
+ }
+ DenseMap<DeltaRational>::const_iterator nvi = newValues.begin(), nvi_end = newValues.end();
+ for(; nvi != nvi_end; ++nvi){
+ ArithVar currentlyNb = *nvi;
+ if(!d_tableau.isBasic(currentlyNb)){
+ if(!matchesNewValue(newValues, currentlyNb)){
+ const DeltaRational& newValue = newValues[currentlyNb];
+ Trace("arith::updateMany")
+ << "updateMany:" << currentlyNb << " "
+ << d_variables.getAssignment(currentlyNb) << " to "<< newValue << endl;
+ d_linEq.update(currentlyNb, newValue);
+ Assert(d_variables.assignmentIsConsistent(currentlyNb));
+ }
+ }
+ }
+ d_errorSet.reduceToSignals();
+ d_errorSet.setSelectionRule(VAR_ORDER);
+
+ static int instance = 0;
+ ++instance;
+
+ if(processSignals()){
+ Debug("arith::findModel") << "attemptSolution("<< instance <<") early conflict" << endl;
+ d_conflictVariables.purge();
+ return Result::UNSAT;
+ }else if(d_errorSet.errorEmpty()){
+ Debug("arith::findModel") << "attemptSolution("<< instance <<") fixed itself" << endl;
+ return Result::SAT;
+ }
+
+ while(!needsToBeAdded.empty() && !d_errorSet.errorEmpty()){
+ ArithVar toRemove = ARITHVAR_SENTINEL;
+ ArithVar toAdd = ARITHVAR_SENTINEL;
+ DenseSet::const_iterator i = needsToBeAdded.begin(), i_end = needsToBeAdded.end();
+ for(; toAdd == ARITHVAR_SENTINEL && i != i_end; ++i){
+ ArithVar v = *i;
+
+ Tableau::ColIterator colIter = d_tableau.colIterator(v);
+ for(; !colIter.atEnd(); ++colIter){
+ const Tableau::Entry& entry = *colIter;
+ Assert(entry.getColVar() == v);
+ ArithVar b = d_tableau.rowIndexToBasic(entry.getRowIndex());
+ if(!newBasis.isMember(b)){
+ toAdd = v;
+
+ bool favorBOverToRemove =
+ (toRemove == ARITHVAR_SENTINEL) ||
+ (matchesNewValue(newValues, toRemove) && !matchesNewValue(newValues, b)) ||
+ (d_tableau.basicRowLength(toRemove) > d_tableau.basicRowLength(b));
+
+ if(favorBOverToRemove){
+ toRemove = b;
+ }
+ }
+ }
+ }
+ Assert(toRemove != ARITHVAR_SENTINEL);
+ Assert(toAdd != ARITHVAR_SENTINEL);
+
+ Trace("arith::forceNewBasis") << toRemove << " " << toAdd << endl;
+ //Message() << toRemove << " " << toAdd << endl;
+
+ d_linEq.pivotAndUpdate(toRemove, toAdd, newValues[toRemove]);
+
+ Trace("arith::forceNewBasis") << needsToBeAdded.size() << "to go" << endl;
+ //Message() << needsToBeAdded.size() << "to go" << endl;
+ needsToBeAdded.remove(toAdd);
+
+ bool conflict = processSignals();
+ if(conflict){
+ d_errorSet.reduceToSignals();
+ d_conflictVariables.purge();
+
+ return Result::UNSAT;
+ }
+ }
+ Assert( d_conflictVariables.empty() );
+
+ if(d_errorSet.errorEmpty()){
+ return Result::SAT;
+ }else{
+ d_errorSet.reduceToSignals();
+ return Result::SAT_UNKNOWN;
+ }
+}
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/pure_update_simplex.h b/src/theory/arith/attempt_solution_simplex.h
index 50b751d7b..5bcdc6aab 100644
--- a/src/theory/arith/pure_update_simplex.h
+++ b/src/theory/arith/attempt_solution_simplex.h
@@ -53,64 +53,43 @@
#pragma once
-#include "theory/arith/simplex.h"
-#include "util/dense_map.h"
#include "util/statistics_registry.h"
-#include <stdint.h>
-#include "theory/arith/arithvar.h"
-#include "theory/arith/delta_rational.h"
+#include "theory/arith/simplex.h"
+#include "theory/arith/approx_simplex.h"
namespace CVC4 {
namespace theory {
namespace arith {
-class PureUpdateSimplexDecisionProcedure : public SimplexDecisionProcedure{
+class AttemptSolutionSDP : public SimplexDecisionProcedure {
public:
- PureUpdateSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc);
+ AttemptSolutionSDP(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc);
- Result::Sat findModel(bool exactResult);
+ Result::Sat attempt(const ApproximateSimplex::Solution& sol);
-private:
- ArithVar d_focusErrorVar;
-
- bool attemptPureUpdates();
+ Result::Sat findModel(bool exactResult){
+ Unreachable();
+ }
- /**
- * This is the main simplex for DPLL(T) loop.
- * It runs for at most maxIterations.
- *
- * Returns true iff it has found a conflict.
- * d_conflictVariable will be set and the conflict for this row is reported.
- */
- bool searchForFeasibleSolution(uint32_t maxIterations);
+private:
+ bool matchesNewValue(const DenseMap<DeltaRational>& nv, ArithVar v) const;
bool processSignals(){
- TimerStat &timer = d_statistics.d_processSignalsTime;
- IntStat& conflictStat = d_statistics.d_foundConflicts;
+ TimerStat &timer = d_statistics.d_queueTime;
+ IntStat& conflictStat = d_statistics.d_conflicts;
return standardProcessSignals(timer, conflictStat);
}
-
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
- IntStat d_pureUpdateFoundUnsat;
- IntStat d_pureUpdateFoundSat;
- IntStat d_pureUpdateMissed;
- IntStat d_pureUpdates;
- IntStat d_pureUpdateDropped;
- IntStat d_pureUpdateConflicts;
-
- IntStat d_foundConflicts;
-
- TimerStat d_attemptPureUpdatesTimer;
- TimerStat d_processSignalsTime;
-
- TimerStat d_constructionTimer;
+ TimerStat d_searchTime;
+ TimerStat d_queueTime;
+ IntStat d_conflicts;
Statistics();
~Statistics();
} d_statistics;
-};/* class PureUpdateSimplexDecisionProcedure */
+};/* class AttemptSolutionSDP */
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/arith/bound_counts.h b/src/theory/arith/bound_counts.h
index 954cc056a..49c1a94ce 100644
--- a/src/theory/arith/bound_counts.h
+++ b/src/theory/arith/bound_counts.h
@@ -1,3 +1,20 @@
+/********************* */
+/*! \file bound_counts.h
+ ** \verbatim
+ ** Original author: Tim King
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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"
#pragma once
@@ -10,62 +27,92 @@ namespace CVC4 {
namespace theory {
namespace arith {
-/**
- * x = \sum_{a < 0} a_i i + \sum_{b > 0} b_j j
- *
- * AtUpperBound = {assignment(i) = lb(i)} \cup {assignment(j) = ub(j)}
- * AtLowerBound = {assignment(i) = ub(i)} \cup {assignment(j) = lb(j)}
- */
class BoundCounts {
private:
- uint32_t d_atLowerBounds;
- uint32_t d_atUpperBounds;
+ uint32_t d_lowerBoundCount;
+ uint32_t d_upperBoundCount;
public:
- BoundCounts() : d_atLowerBounds(0), d_atUpperBounds(0) {}
+ BoundCounts() : d_lowerBoundCount(0), d_upperBoundCount(0) {}
BoundCounts(uint32_t lbs, uint32_t ubs)
- : d_atLowerBounds(lbs), d_atUpperBounds(ubs) {}
+ : d_lowerBoundCount(lbs), d_upperBoundCount(ubs) {}
bool operator==(BoundCounts bc) const {
- return d_atLowerBounds == bc.d_atLowerBounds
- && d_atUpperBounds == bc.d_atUpperBounds;
+ return d_lowerBoundCount == bc.d_lowerBoundCount
+ && d_upperBoundCount == bc.d_upperBoundCount;
}
bool operator!=(BoundCounts bc) const {
- return d_atLowerBounds != bc.d_atLowerBounds
- || d_atUpperBounds != bc.d_atUpperBounds;
+ return d_lowerBoundCount != bc.d_lowerBoundCount
+ || d_upperBoundCount != bc.d_upperBoundCount;
+ }
+ /** This is not a total order! */
+ bool operator>=(BoundCounts bc) const {
+ return d_lowerBoundCount >= bc.d_lowerBoundCount &&
+ d_upperBoundCount >= bc.d_upperBoundCount;
}
- inline bool isZero() const{ return d_atLowerBounds == 0 && d_atUpperBounds == 0; }
- inline uint32_t atLowerBounds() const{
- return d_atLowerBounds;
+
+ inline bool isZero() const{ return d_lowerBoundCount == 0 && d_upperBoundCount == 0; }
+ inline uint32_t lowerBoundCount() const{
+ return d_lowerBoundCount;
}
- inline uint32_t atUpperBounds() const{
- return d_atUpperBounds;
+ inline uint32_t upperBoundCount() const{
+ return d_upperBoundCount;
}
inline BoundCounts operator+(BoundCounts bc) const{
- return BoundCounts(d_atLowerBounds + bc.d_atLowerBounds,
- d_atUpperBounds + bc.d_atUpperBounds);
+ return BoundCounts(d_lowerBoundCount + bc.d_lowerBoundCount,
+ d_upperBoundCount + bc.d_upperBoundCount);
}
inline BoundCounts operator-(BoundCounts bc) const {
- Assert(d_atLowerBounds >= bc.d_atLowerBounds);
- Assert(d_atUpperBounds >= bc.d_atUpperBounds);
- return BoundCounts(d_atLowerBounds - bc.d_atLowerBounds,
- d_atUpperBounds - bc.d_atUpperBounds);
+ Assert( *this >= bc );
+ return BoundCounts(d_lowerBoundCount - bc.d_lowerBoundCount,
+ d_upperBoundCount - bc.d_upperBoundCount);
+ }
+
+
+ inline BoundCounts& operator+=(BoundCounts bc) {
+ d_upperBoundCount += bc.d_upperBoundCount;
+ d_lowerBoundCount += bc.d_lowerBoundCount;
+ return *this;
+ }
+
+ inline BoundCounts& operator-=(BoundCounts bc) {
+ Assert(d_lowerBoundCount >= bc.d_lowerBoundCount);
+ Assert(d_upperBoundCount >= bc.d_upperBoundCount);
+ d_upperBoundCount -= bc.d_upperBoundCount;
+ d_lowerBoundCount -= bc.d_lowerBoundCount;
+
+ return *this;
+ }
+
+ /** Based on the sign coefficient a variable is multiplied by,
+ * the effects the bound counts either has no effect (sgn == 0),
+ * the lower bounds and upper bounds flip (sgn < 0), or nothing (sgn >0).
+ */
+ inline BoundCounts multiplyBySgn(int sgn) const{
+ if(sgn > 0){
+ return *this;
+ }else if(sgn == 0){
+ return BoundCounts(0,0);
+ }else{
+ return BoundCounts(d_upperBoundCount, d_lowerBoundCount);
+ }
}
inline void addInChange(int sgn, BoundCounts before, BoundCounts after){
- Assert(before != after);
- if(sgn < 0){
- Assert(d_atUpperBounds >= before.d_atLowerBounds);
- Assert(d_atLowerBounds >= before.d_atUpperBounds);
- d_atUpperBounds += after.d_atLowerBounds - before.d_atLowerBounds;
- d_atLowerBounds += after.d_atUpperBounds - before.d_atUpperBounds;
+ if(before == after){
+ return;
+ }else if(sgn < 0){
+ Assert(d_upperBoundCount >= before.d_lowerBoundCount);
+ Assert(d_lowerBoundCount >= before.d_upperBoundCount);
+ d_upperBoundCount += after.d_lowerBoundCount - before.d_lowerBoundCount;
+ d_lowerBoundCount += after.d_upperBoundCount - before.d_upperBoundCount;
}else if(sgn > 0){
- Assert(d_atUpperBounds >= before.d_atUpperBounds);
- Assert(d_atLowerBounds >= before.d_atLowerBounds);
- d_atUpperBounds += after.d_atUpperBounds - before.d_atUpperBounds;
- d_atLowerBounds += after.d_atLowerBounds - before.d_atLowerBounds;
+ Assert(d_upperBoundCount >= before.d_upperBoundCount);
+ Assert(d_lowerBoundCount >= before.d_lowerBoundCount);
+ d_upperBoundCount += after.d_upperBoundCount - before.d_upperBoundCount;
+ d_lowerBoundCount += after.d_lowerBoundCount - before.d_lowerBoundCount;
}
}
@@ -74,69 +121,112 @@ public:
Assert(!bc.isZero());
if(before < 0){
- d_atUpperBounds -= bc.d_atLowerBounds;
- d_atLowerBounds -= bc.d_atUpperBounds;
+ d_upperBoundCount -= bc.d_lowerBoundCount;
+ d_lowerBoundCount -= bc.d_upperBoundCount;
}else if(before > 0){
- d_atUpperBounds -= bc.d_atUpperBounds;
- d_atLowerBounds -= bc.d_atLowerBounds;
+ d_upperBoundCount -= bc.d_upperBoundCount;
+ d_lowerBoundCount -= bc.d_lowerBoundCount;
}
if(after < 0){
- d_atUpperBounds += bc.d_atLowerBounds;
- d_atLowerBounds += bc.d_atUpperBounds;
+ d_upperBoundCount += bc.d_lowerBoundCount;
+ d_lowerBoundCount += bc.d_upperBoundCount;
}else if(after > 0){
- d_atUpperBounds += bc.d_atUpperBounds;
- d_atLowerBounds += bc.d_atLowerBounds;
+ d_upperBoundCount += bc.d_upperBoundCount;
+ d_lowerBoundCount += bc.d_lowerBoundCount;
}
}
+};
- inline BoundCounts& operator+=(BoundCounts bc) {
- d_atUpperBounds += bc.d_atUpperBounds;
- d_atLowerBounds += bc.d_atLowerBounds;
- return *this;
- }
+class BoundsInfo {
+private:
- inline BoundCounts& operator-=(BoundCounts bc) {
- Assert(d_atLowerBounds >= bc.d_atLowerBounds);
- Assert(d_atUpperBounds >= bc.d_atUpperBounds);
- d_atUpperBounds -= bc.d_atUpperBounds;
- d_atLowerBounds -= bc.d_atLowerBounds;
+ /**
+ * x = \sum_{a < 0} a_i i + \sum_{b > 0} b_j j
+ *
+ * AtUpperBound = {assignment(i) = lb(i)} \cup {assignment(j) = ub(j)}
+ * AtLowerBound = {assignment(i) = ub(i)} \cup {assignment(j) = lb(j)}
+ */
+ BoundCounts d_atBounds;
- return *this;
+ /** This is for counting how many upper and lower bounds a row has. */
+ BoundCounts d_hasBounds;
+
+public:
+ BoundsInfo() : d_atBounds(), d_hasBounds() {}
+ BoundsInfo(BoundCounts atBounds, BoundCounts hasBounds)
+ : d_atBounds(atBounds), d_hasBounds(hasBounds) {}
+
+ BoundCounts atBounds() const { return d_atBounds; }
+ BoundCounts hasBounds() const { return d_hasBounds; }
+
+ /** This corresponds to adding in another variable to the row. */
+ inline BoundsInfo operator+(const BoundsInfo& bc) const{
+ return BoundsInfo(d_atBounds + bc.d_atBounds,
+ d_hasBounds + bc.d_hasBounds);
+ }
+ /** This corresponds to removing a variable from the row. */
+ inline BoundsInfo operator-(const BoundsInfo& bc) const {
+ Assert(*this >= bc);
+ return BoundsInfo(d_atBounds - bc.d_atBounds,
+ d_hasBounds - bc.d_hasBounds);
}
- inline BoundCounts multiplyBySgn(int sgn) const{
- if(sgn > 0){
- return *this;
- }else if(sgn == 0){
- return BoundCounts(0,0);
- }else{
- return BoundCounts(d_atUpperBounds, d_atLowerBounds);
- }
+ inline BoundsInfo& operator+=(const BoundsInfo& bc) {
+ d_atBounds += bc.d_atBounds;
+ d_hasBounds += bc.d_hasBounds;
+ return (*this);
}
-};
-typedef DenseMap<BoundCounts> BoundCountingVector;
+ /** Based on the sign coefficient a variable is multiplied by,
+ * the effects the bound counts either has no effect (sgn == 0),
+ * the lower bounds and upper bounds flip (sgn < 0), or nothing (sgn >0).
+ */
+ inline BoundsInfo multiplyBySgn(int sgn) const{
+ return BoundsInfo(d_atBounds.multiplyBySgn(sgn), d_hasBounds.multiplyBySgn(sgn));
+ }
-class BoundCountingLookup {
-private:
- BoundCountingVector* d_bc;
-public:
- BoundCountingLookup(BoundCountingVector* bc) : d_bc(bc) {}
- BoundCounts boundCounts(ArithVar v) const {
- Assert(d_bc->isKey(v));
- return (*d_bc)[v];
+ bool operator==(const BoundsInfo& other) const{
+ return d_atBounds == other.d_atBounds && d_hasBounds == other.d_hasBounds;
+ }
+ bool operator!=(const BoundsInfo& other) const{
+ return !(*this == other);
+ }
+ /** This is not a total order! */
+ bool operator>=(const BoundsInfo& other) const{
+ return d_atBounds >= other.d_atBounds && d_hasBounds >= other.d_hasBounds;
+ }
+ void addInChange(int sgn, const BoundsInfo& before, const BoundsInfo& after){
+ addInAtBoundChange(sgn, before.d_atBounds, after.d_atBounds);
+ addInHasBoundChange(sgn, before.d_hasBounds, after.d_hasBounds);
+ }
+ void addInAtBoundChange(int sgn, BoundCounts before, BoundCounts after){
+ d_atBounds.addInChange(sgn, before, after);
+ }
+ void addInHasBoundChange(int sgn, BoundCounts before, BoundCounts after){
+ d_hasBounds.addInChange(sgn, before, after);
+ }
+
+ inline void addInSgn(const BoundsInfo& bc, int before, int after){
+ if(!bc.d_atBounds.isZero()){ d_atBounds.addInSgn(bc.d_atBounds, before, after);}
+ if(!bc.d_hasBounds.isZero()){ d_hasBounds.addInSgn(bc.d_hasBounds, before, after);}
}
};
+/** This is intended to map each row to its relevant bound information. */
+typedef DenseMap<BoundsInfo> BoundInfoMap;
+
inline std::ostream& operator<<(std::ostream& os, const BoundCounts& bc){
- os << "[bc " << bc.atLowerBounds() << ", "
- << bc.atUpperBounds() << "]";
+ os << "[bc " << bc.lowerBoundCount() << ", " << bc.upperBoundCount() << "]";
return os;
}
-class BoundCountsCallback {
+inline std::ostream& operator<<(std::ostream& os, const BoundsInfo& inf){
+ os << "[bi : @ " << inf.atBounds() << ", " << inf.hasBounds() << "]";
+ return os;
+}
+class BoundUpdateCallback {
public:
- virtual void operator()(ArithVar v, BoundCounts bc) = 0;
+ virtual void operator()(ArithVar v, const BoundsInfo& up) = 0;
};
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/callbacks.cpp b/src/theory/arith/callbacks.cpp
index 6b6170b20..1e827d316 100644
--- a/src/theory/arith/callbacks.cpp
+++ b/src/theory/arith/callbacks.cpp
@@ -32,6 +32,10 @@ void RaiseConflict::operator()(Node n){
d_ta.raiseConflict(n);
}
+const BoundsInfo& BoundCountingLookup::boundsInfo(ArithVar basic) const{
+ return d_ta.boundsInfo(basic);
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/callbacks.h b/src/theory/arith/callbacks.h
index 0d754d159..718799e9f 100644
--- a/src/theory/arith/callbacks.h
+++ b/src/theory/arith/callbacks.h
@@ -3,10 +3,10 @@
#include "expr/node.h"
#include "util/rational.h"
-#include "context/cdlist.h"
#include "theory/arith/theory_arith_private_forward.h"
#include "theory/arith/arithvar.h"
+#include "theory/arith/bound_counts.h"
namespace CVC4 {
namespace theory {
@@ -87,6 +87,20 @@ public:
void operator()(Node n);
};
+class BoundCountingLookup {
+private:
+ TheoryArithPrivate& d_ta;
+public:
+ BoundCountingLookup(TheoryArithPrivate& ta) : d_ta(ta) {}
+ const BoundsInfo& boundsInfo(ArithVar basic) const;
+ BoundCounts atBounds(ArithVar basic) const{
+ return boundsInfo(basic).atBounds();
+ }
+ BoundCounts hasBounds(ArithVar basic) const {
+ return boundsInfo(basic).hasBounds();
+ }
+};
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp
index e26687bf1..78b9d3494 100644
--- a/src/theory/arith/constraint.cpp
+++ b/src/theory/arith/constraint.cpp
@@ -922,6 +922,28 @@ bool ConstraintValue::proofIsEmpty() const{
return result;
}
+Node ConstraintValue::makeImplication(const std::vector<Constraint>& b) const{
+ Node antecedent = makeConjunction(b);
+ Node implied = getLiteral();
+ return antecedent.impNode(implied);
+}
+
+
+Node ConstraintValue::makeConjunction(const std::vector<Constraint>& b){
+ NodeBuilder<> nb(kind::AND);
+ for(vector<Constraint>::const_iterator i = b.begin(), end = b.end(); i != end; ++i){
+ Constraint b_i = *i;
+ b_i->explainBefore(nb, AssertionOrderSentinel);
+ }
+ if(nb.getNumChildren() >= 2){
+ return nb;
+ }else if(nb.getNumChildren() == 1){
+ return nb[0];
+ }else{
+ return mkBoolNode(true);
+ }
+}
+
void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) const{
Assert(hasProof());
Assert(!isSelfExplaining() || assertedToTheTheory());
diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h
index a5d64a652..4966115d2 100644
--- a/src/theory/arith/constraint.h
+++ b/src/theory/arith/constraint.h
@@ -598,6 +598,8 @@ public:
void impliedBy(Constraint a, Constraint b);
void impliedBy(const std::vector<Constraint>& b);
+ Node makeImplication(const std::vector<Constraint>& b) const;
+ static Node makeConjunction(const std::vector<Constraint>& b);
/** The node must have a proof already and be eligible for propagation! */
void propagate();
diff --git a/src/theory/arith/dual_simplex.cpp b/src/theory/arith/dual_simplex.cpp
index 7caee6708..a9304ae76 100644
--- a/src/theory/arith/dual_simplex.cpp
+++ b/src/theory/arith/dual_simplex.cpp
@@ -196,19 +196,19 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
//DeltaRational beta_i = d_variables.getAssignment(x_i);
ArithVar x_j = ARITHVAR_SENTINEL;
- int32_t prevErrorSize = d_errorSet.errorSize();
+ int32_t prevErrorSize CVC4_UNUSED = d_errorSet.errorSize();
if(d_variables.cmpAssignmentLowerBound(x_i) < 0 ){
x_j = d_linEq.selectSlackUpperBound(x_i, pf);
if(x_j == ARITHVAR_SENTINEL ){
Unreachable();
- ++(d_statistics.d_statUpdateConflicts);
- reportConflict(x_i);
- ++(d_statistics.d_simplexConflicts);
+ // ++(d_statistics.d_statUpdateConflicts);
+ // reportConflict(x_i);
+ // ++(d_statistics.d_simplexConflicts);
// Node conflict = d_linEq.generateConflictBelowLowerBound(x_i); //unsat
// d_conflictVariable = x_i;
// reportConflict(conflict);
- return true;
+ // return true;
}else{
const DeltaRational& l_i = d_variables.getLowerBound(x_i);
d_linEq.pivotAndUpdate(x_i, x_j, l_i);
@@ -217,13 +217,13 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
x_j = d_linEq.selectSlackLowerBound(x_i, pf);
if(x_j == ARITHVAR_SENTINEL ){
Unreachable();
- ++(d_statistics.d_statUpdateConflicts);
- reportConflict(x_i);
- ++(d_statistics.d_simplexConflicts);
+ // ++(d_statistics.d_statUpdateConflicts);
+ // reportConflict(x_i);
+ // ++(d_statistics.d_simplexConflicts);
// Node conflict = d_linEq.generateConflictAboveUpperBound(x_i); //unsat
// d_conflictVariable = x_i;
// reportConflict(conflict);
- return true;
+ // return true;
}else{
const DeltaRational& u_i = d_variables.getUpperBound(x_i);
d_linEq.pivotAndUpdate(x_i, x_j, u_i);
@@ -232,16 +232,19 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
Assert(x_j != ARITHVAR_SENTINEL);
bool conflict = processSignals();
- int32_t currErrorSize = d_errorSet.errorSize();
+ int32_t currErrorSize CVC4_UNUSED = d_errorSet.errorSize();
d_pivots++;
- // cout << "#" << d_pivots
- // << " c" << conflict
- // << " d" << (prevErrorSize - currErrorSize)
- // << " f" << d_errorSet.inError(x_j)
- // << " h" << d_conflictVariables.isMember(x_j)
- // << " " << x_i << "->" << x_j
- // << endl;
+ if(Debug.isOn("arith::dual")){
+ Debug("arith::dual")
+ << "#" << d_pivots
+ << " c" << conflict
+ << " d" << (prevErrorSize - currErrorSize)
+ << " f" << d_errorSet.inError(x_j)
+ << " h" << d_conflictVariables.isMember(x_j)
+ << " " << x_i << "->" << x_j
+ << endl;
+ }
if(conflict){
return true;
diff --git a/src/theory/arith/error_set.cpp b/src/theory/arith/error_set.cpp
index ee72d1949..dea78acf7 100644
--- a/src/theory/arith/error_set.cpp
+++ b/src/theory/arith/error_set.cpp
@@ -1,11 +1,11 @@
/********************* */
-/*! \file arith_priority_queue.cpp
+/*! \file error_set.cpp
** \verbatim
- ** Original author: taking
- ** Major contributors: mdeters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** Original author: Tim King
+ ** Major contributors: none
+ ** Minor contributors (to current version): Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
diff --git a/src/theory/arith/error_set.h b/src/theory/arith/error_set.h
index 91d7e49ea..d1b692cb4 100644
--- a/src/theory/arith/error_set.h
+++ b/src/theory/arith/error_set.h
@@ -1,11 +1,11 @@
/********************* */
-/*! \file arith_priority_queue.h
+/*! \file error_set.h
** \verbatim
- ** Original author: taking
+ ** Original author: Tim King
** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** Minor contributors (to current version): Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
@@ -26,9 +26,9 @@
#include "theory/arith/partial_model.h"
#include "theory/arith/arith_heuristic_pivot_rule.h"
#include "theory/arith/tableau_sizes.h"
+#include "theory/arith/callbacks.h"
#include "util/statistics_registry.h"
-//#include <boost/heap/d_ary_heap.hpp>
#if CVC4_GCC_HAS_PB_DS_BUG
// Unfortunate bug in some older GCCs (e.g., v4.2):
@@ -377,8 +377,8 @@ public:
uint32_t sumMetric(ArithVar a) const{
Assert(inError(a));
- BoundCounts bcs = d_boundLookup.boundCounts(a);
- uint32_t count = getSgn(a) > 0 ? bcs.atUpperBounds() : bcs.atLowerBounds();
+ BoundCounts bcs = d_boundLookup.atBounds(a);
+ uint32_t count = getSgn(a) > 0 ? bcs.upperBoundCount() : bcs.lowerBoundCount();
uint32_t length = d_tableauSizes.getRowLength(a);
diff --git a/src/theory/arith/fc_simplex.cpp b/src/theory/arith/fc_simplex.cpp
index ac4625ba3..e99e62505 100644
--- a/src/theory/arith/fc_simplex.cpp
+++ b/src/theory/arith/fc_simplex.cpp
@@ -289,7 +289,7 @@ UpdateInfo FCSimplexDecisionProcedure::selectPrimalUpdate(ArithVar basic, Linear
Debug("arith::selectPrimalUpdate")
<< "selectPrimalUpdate " << instance << endl
<< basic << " " << d_tableau.basicRowLength(basic)
- << " " << d_linEq._countBounds(basic) << endl;
+ << " " << d_linEq.debugBasicAtBoundCount(basic) << endl;
static const int s_maxCandidatesAfterImprove = 3;
bool isFocus = basic == d_focusErrorVar;
@@ -358,18 +358,9 @@ UpdateInfo FCSimplexDecisionProcedure::selectPrimalUpdate(ArithVar basic, Linear
ArithVar curr = cand.d_nb;
const Rational& coeff = *cand.d_coeff;
-#warning "Who is using computeSafeUpdate?"
LinearEqualityModule::UpdatePreferenceFunction leavingPrefFunc = selectLeavingFunction(curr);
UpdateInfo currProposal = d_linEq.speculativeUpdate(curr, coeff, leavingPrefFunc);
- //int curr_movement = cand.d_sgn;
- // if(isFocus){
- // currProposal = d_linEq.speculativeUpdate(curr, coeff, upf);
- // }else{
- // currProposal = UpdateInfo(curr, curr_movement);
- // d_linEq.computeSafeUpdate(currProposal, bpf);
- // }
-
Debug("arith::selectPrimalUpdate")
<< "selected " << selected << endl
<< "currProp " << currProposal << endl
@@ -505,7 +496,7 @@ void FCSimplexDecisionProcedure::debugPrintSignal(ArithVar updated) const{
int dir = !d_variables.assignmentIsConsistent(updated) ?
d_errorSet.getSgn(updated) : 0;
Debug("updateAndSignal") << " dir " << dir;
- Debug("updateAndSignal") << " _countBounds " << d_linEq._countBounds(updated) << endl;
+ Debug("updateAndSignal") << " debugBasicAtBoundCount " << d_linEq.debugBasicAtBoundCount(updated) << endl;
}
bool debugUpdatedBasic(const UpdateInfo& selected, ArithVar updated){
@@ -530,7 +521,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
ArithVar leaving = selected.leaving();
ss << "leaving " << leaving
<< " " << d_tableau.basicRowLength(leaving)
- << " " << d_linEq._countBounds(leaving)
+ << " " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
if(degenerate(w) && selected.describesPivot()){
@@ -539,7 +530,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
<< "degenerate " << leaving
<< ", atBounds " << d_linEq.basicsAtBounds(selected)
<< ", len " << d_tableau.basicRowLength(leaving)
- << ", bc " << d_linEq._countBounds(leaving)
+ << ", bc " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
}
diff --git a/src/theory/arith/kinds b/src/theory/arith/kinds
index 07cfcc9e5..a8a4047ca 100644
--- a/src/theory/arith/kinds
+++ b/src/theory/arith/kinds
@@ -23,8 +23,16 @@ operator INTS_DIVISION 2 "ints division (user symbol)"
operator INTS_DIVISION_TOTAL 2 "ints division with interpreted division by 0 (internal symbol)"
operator INTS_MODULUS 2 "ints modulus (user symbol)"
operator INTS_MODULUS_TOTAL 2 "ints modulus with interpreted division by 0 (internal symbol)"
+operator ABS 1 "absolute value"
+parameterized DIVISIBLE DIVISIBLE_OP 1 "divisibility-by-k predicate"
operator POW 2 "arithmetic power"
+constant DIVISIBLE_OP \
+ ::CVC4::Divisible \
+ ::CVC4::DivisibleHashFunction \
+ "util/divisible.h" \
+ "operator for the divisibility-by-k predicate"
+
sort REAL_TYPE \
Cardinality::REALS \
well-founded \
@@ -72,6 +80,10 @@ operator LEQ 2 "less than or equal, x <= y"
operator GT 2 "greater than, x > y"
operator GEQ 2 "greater than or equal, x >= y"
+operator IS_INTEGER 1 "term is integer"
+operator TO_INTEGER 1 "cast term to integer"
+operator TO_REAL 1 "cast term to real"
+
typerule PLUS ::CVC4::theory::arith::ArithOperatorTypeRule
typerule MULT ::CVC4::theory::arith::ArithOperatorTypeRule
typerule MINUS ::CVC4::theory::arith::ArithOperatorTypeRule
@@ -86,11 +98,17 @@ typerule LEQ ::CVC4::theory::arith::ArithPredicateTypeRule
typerule GT ::CVC4::theory::arith::ArithPredicateTypeRule
typerule GEQ ::CVC4::theory::arith::ArithPredicateTypeRule
-typerule INTS_DIVISION ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_MODULUS ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule TO_REAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule TO_INTEGER ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule IS_INTEGER ::CVC4::theory::arith::ArithUnaryPredicateTypeRule
+
+typerule ABS ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_DIVISION ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_MODULUS ::CVC4::theory::arith::IntOperatorTypeRule
+typerule DIVISIBLE ::CVC4::theory::arith::IntUnaryPredicateTypeRule
typerule DIVISION_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_DIVISION_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_MODULUS_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule INTS_DIVISION_TOTAL ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_MODULUS_TOTAL ::CVC4::theory::arith::IntOperatorTypeRule
endtheory
diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp
index 42d8b41f8..5817a3629 100644
--- a/src/theory/arith/linear_equality.cpp
+++ b/src/theory/arith/linear_equality.cpp
@@ -25,18 +25,10 @@ namespace theory {
namespace arith {
/* Explicitly instatiate these functions. */
-template void LinearEqualityModule::propagateNonbasics<true>(ArithVar basic, Constraint c);
-template void LinearEqualityModule::propagateNonbasics<false>(ArithVar basic, Constraint c);
template ArithVar LinearEqualityModule::selectSlack<true>(ArithVar x_i, VarPreferenceFunction pf) const;
template ArithVar LinearEqualityModule::selectSlack<false>(ArithVar x_i, VarPreferenceFunction pf) const;
-// template bool LinearEqualityModule::preferNonDegenerate<true>(const UpdateInfo& a, const UpdateInfo& b) const;
-// template bool LinearEqualityModule::preferNonDegenerate<false>(const UpdateInfo& a, const UpdateInfo& b) const;
-
-// template bool LinearEqualityModule::preferErrorsFixed<true>(const UpdateInfo& a, const UpdateInfo& b) const;
-// template bool LinearEqualityModule::preferErrorsFixed<false>(const UpdateInfo& a, const UpdateInfo& b) const;
-
template bool LinearEqualityModule::preferWitness<true>(const UpdateInfo& a, const UpdateInfo& b) const;
template bool LinearEqualityModule::preferWitness<false>(const UpdateInfo& a, const UpdateInfo& b) const;
@@ -57,14 +49,13 @@ void Border::output(std::ostream& out) const{
<< "}";
}
-LinearEqualityModule::LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundCountingVector& boundTracking, BasicVarModelUpdateCallBack f):
+LinearEqualityModule::LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundsTracking, BasicVarModelUpdateCallBack f):
d_variables(vars),
d_tableau(t),
d_basicVariableUpdates(f),
d_increasing(1),
d_decreasing(-1),
- d_relevantErrorBuffer(),
- d_boundTracking(boundTracking),
+ d_btracking(boundsTracking),
d_areTracking(false),
d_trackCallback(this)
{}
@@ -77,7 +68,8 @@ LinearEqualityModule::Statistics::Statistics():
d_weakeningAttempts("theory::arith::weakening::attempts",0),
d_weakeningSuccesses("theory::arith::weakening::success",0),
d_weakenings("theory::arith::weakening::total",0),
- d_weakenTime("theory::arith::weakening::time")
+ d_weakenTime("theory::arith::weakening::time"),
+ d_forceTime("theory::arith::forcing::time")
{
StatisticsRegistry::registerStat(&d_statPivots);
StatisticsRegistry::registerStat(&d_statUpdates);
@@ -89,6 +81,7 @@ LinearEqualityModule::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_weakeningSuccesses);
StatisticsRegistry::registerStat(&d_weakenings);
StatisticsRegistry::registerStat(&d_weakenTime);
+ StatisticsRegistry::registerStat(&d_forceTime);
}
LinearEqualityModule::Statistics::~Statistics(){
@@ -102,50 +95,56 @@ LinearEqualityModule::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_weakeningSuccesses);
StatisticsRegistry::unregisterStat(&d_weakenings);
StatisticsRegistry::unregisterStat(&d_weakenTime);
+ StatisticsRegistry::unregisterStat(&d_forceTime);
}
-void LinearEqualityModule::includeBoundCountChange(ArithVar nb, BoundCounts prev){
- if(d_tableau.isBasic(nb)){
- return;
- }
- Assert(!d_tableau.isBasic(nb));
+
+void LinearEqualityModule::includeBoundUpdate(ArithVar v, const BoundsInfo& prev){
Assert(!d_areTracking);
- BoundCounts curr = d_variables.boundCounts(nb);
+ BoundsInfo curr = d_variables.boundsInfo(v);
Assert(prev != curr);
- Tableau::ColIterator basicIter = d_tableau.colIterator(nb);
+ Tableau::ColIterator basicIter = d_tableau.colIterator(v);
for(; !basicIter.atEnd(); ++basicIter){
const Tableau::Entry& entry = *basicIter;
- Assert(entry.getColVar() == nb);
+ Assert(entry.getColVar() == v);
int a_ijSgn = entry.getCoefficient().sgn();
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
-
- BoundCounts& counts = d_boundTracking.get(basic);
- Debug("includeBoundCountChange") << basic << " " << counts << " to " ;
- counts -= prev.multiplyBySgn(a_ijSgn);
- counts += curr.multiplyBySgn(a_ijSgn);
- Debug("includeBoundCountChange") << counts << " " << a_ijSgn << std::endl;
+ RowIndex ridx = entry.getRowIndex();
+ BoundsInfo& counts = d_btracking.get(ridx);
+ Debug("includeBoundUpdate") << d_tableau.rowIndexToBasic(ridx) << " " << counts << " to " ;
+ counts.addInChange(a_ijSgn, prev, curr);
+ Debug("includeBoundUpdate") << counts << " " << a_ijSgn << std::endl;
}
- d_boundTracking.set(nb, curr);
}
void LinearEqualityModule::updateMany(const DenseMap<DeltaRational>& many){
for(DenseMap<DeltaRational>::const_iterator i = many.begin(), i_end = many.end(); i != i_end; ++i){
ArithVar nb = *i;
- Assert(!d_tableau.isBasic(nb));
- const DeltaRational& newValue = many[nb];
- if(newValue != d_variables.getAssignment(nb)){
- Trace("arith::updateMany")
- << "updateMany:" << nb << " "
- << d_variables.getAssignment(nb) << " to "<< newValue << endl;
- update(nb, newValue);
+ if(!d_tableau.isBasic(nb)){
+ Assert(!d_tableau.isBasic(nb));
+ const DeltaRational& newValue = many[nb];
+ if(newValue != d_variables.getAssignment(nb)){
+ Trace("arith::updateMany")
+ << "updateMany:" << nb << " "
+ << d_variables.getAssignment(nb) << " to "<< newValue << endl;
+ update(nb, newValue);
+ }
}
}
}
+
+
+void LinearEqualityModule::applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues){
+ forceNewBasis(newBasis);
+ updateMany(newValues);
+}
+
void LinearEqualityModule::forceNewBasis(const DenseSet& newBasis){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_forceTime);
+ cout << "force begin" << endl;
DenseSet needsToBeAdded;
for(DenseSet::const_iterator i = newBasis.begin(), i_end = newBasis.end(); i != i_end; ++i){
ArithVar b = *i;
@@ -179,10 +178,12 @@ void LinearEqualityModule::forceNewBasis(const DenseSet& newBasis){
Assert(toAdd != ARITHVAR_SENTINEL);
Trace("arith::forceNewBasis") << toRemove << " " << toAdd << endl;
+ Message() << toRemove << " " << toAdd << endl;
d_tableau.pivot(toRemove, toAdd, d_trackCallback);
d_basicVariableUpdates(toAdd);
Trace("arith::forceNewBasis") << needsToBeAdded.size() << "to go" << endl;
+ Message() << needsToBeAdded.size() << "to go" << endl;
needsToBeAdded.remove(toAdd);
}
}
@@ -231,9 +232,9 @@ void LinearEqualityModule::updateTracked(ArithVar x_i, const DeltaRational& v){
<< d_variables.getAssignment(x_i) << "|-> " << v << endl;
- BoundCounts before = d_variables.boundCounts(x_i);
+ BoundCounts before = d_variables.atBoundCounts(x_i);
d_variables.setAssignment(x_i, v);
- BoundCounts after = d_variables.boundCounts(x_i);
+ BoundCounts after = d_variables.atBoundCounts(x_i);
bool anyChange = before != after;
@@ -242,17 +243,24 @@ void LinearEqualityModule::updateTracked(ArithVar x_i, const DeltaRational& v){
const Tableau::Entry& entry = *colIter;
Assert(entry.getColVar() == x_i);
- ArithVar x_j = d_tableau.rowIndexToBasic(entry.getRowIndex());
+ RowIndex ridx = entry.getRowIndex();
+ ArithVar x_j = d_tableau.rowIndexToBasic(ridx);
const Rational& a_ji = entry.getCoefficient();
const DeltaRational& assignment = d_variables.getAssignment(x_j);
DeltaRational nAssignment = assignment+(diff * a_ji);
Debug("update") << x_j << " " << a_ji << assignment << " -> " << nAssignment << endl;
+ BoundCounts xjBefore = d_variables.atBoundCounts(x_j);
d_variables.setAssignment(x_j, nAssignment);
+ BoundCounts xjAfter = d_variables.atBoundCounts(x_j);
- if(anyChange && basicIsTracked(x_j)){
- BoundCounts& next_bc_k = d_boundTracking.get(x_j);
- next_bc_k.addInChange(a_ji.sgn(), before, after);
+ Assert(rowIndexIsTracked(ridx));
+ BoundsInfo& next_bc_k = d_btracking.get(ridx);
+ if(anyChange){
+ next_bc_k.addInAtBoundChange(a_ji.sgn(), before, after);
+ }
+ if(xjBefore != xjAfter){
+ next_bc_k.addInAtBoundChange(-1, xjBefore, xjAfter);
}
d_basicVariableUpdates(x_j);
@@ -332,7 +340,7 @@ void LinearEqualityModule::debugCheckTracking(){
ArithVar var = entry.getColVar();
const Rational& coeff = entry.getCoefficient();
DeltaRational beta = d_variables.getAssignment(var);
- Debug("arith::tracking") << var << " " << d_variables.boundCounts(var)
+ Debug("arith::tracking") << var << " " << d_variables.boundsInfo(var)
<< " " << beta << coeff;
if(d_variables.hasLowerBound(var)){
Debug("arith::tracking") << "(lb " << d_variables.getLowerBound(var) << ")";
@@ -345,11 +353,12 @@ void LinearEqualityModule::debugCheckTracking(){
Debug("arith::tracking") << "end row"<< endl;
if(basicIsTracked(basic)){
- BoundCounts computed = computeBoundCounts(basic);
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ BoundsInfo computed = computeRowBoundInfo(ridx, false);
Debug("arith::tracking")
<< "computed " << computed
- << " tracking " << d_boundTracking[basic] << endl;
- Assert(computed == d_boundTracking[basic]);
+ << " tracking " << d_btracking[ridx] << endl;
+ Assert(computed == d_btracking[ridx]);
}
}
@@ -426,19 +435,19 @@ bool LinearEqualityModule::debugEntireLinEqIsConsistent(const string& s){
return result;
}
-DeltaRational LinearEqualityModule::computeBound(ArithVar basic, bool upperBound){
+DeltaRational LinearEqualityModule::computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const {
DeltaRational sum(0,0);
- for(Tableau::RowIterator i = d_tableau.basicRowIterator(basic); !i.atEnd(); ++i){
+ for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
const Tableau::Entry& entry = (*i);
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == basic) continue;
+ ArithVar v = entry.getColVar();
+ if(v == skip){ continue; }
+
const Rational& coeff = entry.getCoefficient();
- int sgn = coeff.sgn();
- bool ub = upperBound ? (sgn > 0) : (sgn < 0);
+ bool vUb = (rowUb == (coeff.sgn() > 0));
- const DeltaRational& bound = ub ?
- d_variables.getUpperBound(nonbasic):
- d_variables.getLowerBound(nonbasic);
+ const DeltaRational& bound = vUb ?
+ d_variables.getUpperBound(v):
+ d_variables.getLowerBound(v);
DeltaRational diff = bound * coeff;
sum = sum + diff;
@@ -449,7 +458,7 @@ DeltaRational LinearEqualityModule::computeBound(ArithVar basic, bool upperBound
/**
* Computes the value of a basic variable using the current assignment.
*/
-DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe){
+DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe) const{
Assert(d_tableau.isBasic(x));
DeltaRational sum(0);
@@ -465,76 +474,71 @@ DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe){
return sum;
}
-bool LinearEqualityModule::hasBounds(ArithVar basic, bool upperBound){
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(basic); !iter.atEnd(); ++iter){
+const Tableau::Entry* LinearEqualityModule::rowLacksBound(RowIndex ridx, bool rowUb, ArithVar skip){
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
+ for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
ArithVar var = entry.getColVar();
- if(var == basic) continue;
+ if(var == skip) { continue; }
+
int sgn = entry.getCoefficient().sgn();
- if(upperBound){
- if( (sgn < 0 && !d_variables.hasLowerBound(var)) ||
- (sgn > 0 && !d_variables.hasUpperBound(var))){
- return false;
- }
- }else{
- if( (sgn < 0 && !d_variables.hasUpperBound(var)) ||
- (sgn > 0 && !d_variables.hasLowerBound(var))){
- return false;
- }
+ bool selectUb = (rowUb == (sgn > 0));
+ bool hasBound = selectUb ?
+ d_variables.hasUpperBound(var):
+ d_variables.hasLowerBound(var);
+ if(!hasBound){
+ return &entry;
}
}
- return true;
+ return NULL;
}
-template <bool upperBound>
-void LinearEqualityModule::propagateNonbasics(ArithVar basic, Constraint c){
- Assert(d_tableau.isBasic(basic));
- Assert(c->getVariable() == basic);
+void LinearEqualityModule::propagateBasicFromRow(Constraint c){
+ Assert(c != NullConstraint);
+ Assert(c->isUpperBound() || c->isLowerBound());
Assert(!c->assertedToTheTheory());
- Assert(!upperBound || c->isUpperBound()); // upperbound implies c is an upperbound
- Assert(upperBound || c->isLowerBound()); // !upperbound implies c is a lowerbound
- //Assert(c->canBePropagated());
Assert(!c->hasProof());
- Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
- << basic <<") start" << endl;
+ bool upperBound = c->isUpperBound();
+ ArithVar basic = c->getVariable();
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
vector<Constraint> bounds;
+ propagateRow(bounds, ridx, upperBound, c);
+ c->impliedBy(bounds);
+}
+
+void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c){
+ Assert(!c->assertedToTheTheory());
+ Assert(c->canBePropagated());
+ Assert(!c->hasProof());
+
+ ArithVar v = c->getVariable();
+ Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
+ << v <<") start" << endl;
- Tableau::RowIterator iter = d_tableau.basicRowIterator(basic);
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
ArithVar nonbasic = entry.getColVar();
- if(nonbasic == basic) continue;
+ if(nonbasic == v){ continue; }
const Rational& a_ij = entry.getCoefficient();
int sgn = a_ij.sgn();
Assert(sgn != 0);
- Constraint bound = NullConstraint;
- if(upperBound){
- if(sgn < 0){
- bound = d_variables.getLowerBoundConstraint(nonbasic);
- }else{
- Assert(sgn > 0);
- bound = d_variables.getUpperBoundConstraint(nonbasic);
- }
- }else{
- if(sgn < 0){
- bound = d_variables.getUpperBoundConstraint(nonbasic);
- }else{
- Assert(sgn > 0);
- bound = d_variables.getLowerBoundConstraint(nonbasic);
- }
- }
+ bool selectUb = rowUp ? (sgn > 0) : (sgn < 0);
+ Constraint bound = selectUb
+ ? d_variables.getUpperBoundConstraint(nonbasic)
+ : d_variables.getLowerBoundConstraint(nonbasic);
+
Assert(bound != NullConstraint);
Debug("arith::explainNonbasics") << "explainNonbasics" << bound << " for " << c << endl;
- bounds.push_back(bound);
+ into.push_back(bound);
}
- c->impliedBy(bounds);
Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
- << basic << ") done" << endl;
+ << v << ") done" << endl;
}
Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
@@ -745,60 +749,35 @@ void LinearEqualityModule::stopTrackingBoundCounts(){
}
-void LinearEqualityModule::trackVariable(ArithVar x_i){
- Assert(!basicIsTracked(x_i));
- BoundCounts counts(0,0);
-
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
- const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
- const Rational& a_ij = entry.getCoefficient();
- counts += (d_variables.oldBoundCounts(nonbasic)).multiplyBySgn(a_ij.sgn());
- }
- d_boundTracking.set(x_i, counts);
+void LinearEqualityModule::trackRowIndex(RowIndex ridx){
+ Assert(!rowIndexIsTracked(ridx));
+ BoundsInfo bi = computeRowBoundInfo(ridx, true);
+ d_btracking.set(ridx, bi);
}
-BoundCounts LinearEqualityModule::computeBoundCounts(ArithVar x_i) const{
- BoundCounts counts(0,0);
+BoundsInfo LinearEqualityModule::computeRowBoundInfo(RowIndex ridx, bool inQueue) const{
+ BoundsInfo bi;
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
+ for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
+ ArithVar v = entry.getColVar();
const Rational& a_ij = entry.getCoefficient();
- counts += (d_variables.boundCounts(nonbasic)).multiplyBySgn(a_ij.sgn());
+ bi += (d_variables.selectBoundsInfo(v, inQueue)).multiplyBySgn(a_ij.sgn());
}
-
- return counts;
+ return bi;
}
-// BoundCounts LinearEqualityModule::cachingCountBounds(ArithVar x_i) const{
-// if(d_boundTracking.isKey(x_i)){
-// return d_boundTracking[x_i];
-// }else{
-// return computeBoundCounts(x_i);
-// }
-// }
-BoundCounts LinearEqualityModule::_countBounds(ArithVar x_i) const {
- Assert(d_boundTracking.isKey(x_i));
- return d_boundTracking[x_i];
+BoundCounts LinearEqualityModule::debugBasicAtBoundCount(ArithVar x_i) const {
+ return d_btracking[d_tableau.basicToRowIndex(x_i)].atBounds();
}
-// BoundCounts LinearEqualityModule::countBounds(ArithVar x_i){
-// if(d_boundTracking.isKey(x_i)){
-// return d_boundTracking[x_i];
-// }else{
-// BoundCounts bc = computeBoundCounts(x_i);
-// if(d_areTracking){
-// d_boundTracking.set(x_i,bc);
-// }
-// return bc;
-// }
-// }
-
+/**
+ * If the pivot described in u were performed,
+ * then the row would qualify as being either at the minimum/maximum
+ * to the non-basics being at their bounds.
+ * The minimum/maximum is determined by the direction the non-basic is changing.
+ */
bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
Assert(u.describesPivot());
@@ -814,289 +793,78 @@ bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
int toLB = (c->getType() == LowerBound ||
c->getType() == Equality) ? 1 : 0;
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
- BoundCounts bcs = d_boundTracking[basic];
+ BoundCounts bcs = d_btracking[ridx].atBounds();
// x = c*n + \sum d*m
- // n = 1/c * x + -1/c * (\sum d*m)
- BoundCounts nonb = bcs - d_variables.boundCounts(nonbasic).multiplyBySgn(coeffSgn);
+ // 0 = -x + c*n + \sum d*m
+ // n = 1/c * x + -1/c * (\sum d*m)
+ BoundCounts nonb = bcs - d_variables.atBoundCounts(nonbasic).multiplyBySgn(coeffSgn);
+ nonb.addInChange(-1, d_variables.atBoundCounts(basic), BoundCounts(toLB, toUB));
nonb = nonb.multiplyBySgn(-coeffSgn);
- nonb += BoundCounts(toLB, toUB).multiplyBySgn(coeffSgn);
uint32_t length = d_tableau.basicRowLength(basic);
Debug("basicsAtBounds")
<< "bcs " << bcs
<< "nonb " << nonb
<< "length " << length << endl;
-
+ // nonb has nb excluded.
if(nbdir < 0){
- return bcs.atLowerBounds() + 1 == length;
+ return nonb.lowerBoundCount() + 1 == length;
}else{
Assert(nbdir > 0);
- return bcs.atUpperBounds() + 1 == length;
+ return nonb.upperBoundCount() + 1 == length;
}
}
bool LinearEqualityModule::nonbasicsAtLowerBounds(ArithVar basic) const {
Assert(basicIsTracked(basic));
- BoundCounts bcs = d_boundTracking[basic];
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+
+ BoundCounts bcs = d_btracking[ridx].atBounds();
uint32_t length = d_tableau.basicRowLength(basic);
- return bcs.atLowerBounds() + 1 == length;
+ // return true if excluding the basic is every element is at its "lowerbound"
+ // The psuedo code is:
+ // bcs -= basic.count(basic, basic's sgn)
+ // return bcs.lowerBoundCount() + 1 == length
+ // As basic's sign is always -1, we can pull out the pieces of the count:
+ // bcs.lowerBoundCount() - basic.atUpperBoundInd() + 1 == length
+ // basic.atUpperBoundInd() is either 0 or 1
+ uint32_t lbc = bcs.lowerBoundCount();
+ return (lbc == length) ||
+ (lbc + 1 == length && d_variables.cmpAssignmentUpperBound(basic) != 0);
}
bool LinearEqualityModule::nonbasicsAtUpperBounds(ArithVar basic) const {
Assert(basicIsTracked(basic));
- BoundCounts bcs = d_boundTracking[basic];
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ BoundCounts bcs = d_btracking[ridx].atBounds();
uint32_t length = d_tableau.basicRowLength(basic);
+ uint32_t ubc = bcs.upperBoundCount();
+ // See the comment for nonbasicsAtLowerBounds()
- return bcs.atUpperBounds() + 1 == length;
-}
-
-void LinearEqualityModule::trackingSwap(ArithVar basic, ArithVar nb, int nbSgn) {
- Assert(basicIsTracked(basic));
-
- // z = a*x + \sum b*y
- // x = (1/a) z + \sum (-1/a)*b*y
- // basicCount(z) = bc(a*x) + bc(\sum b y)
- // basicCount(x) = bc(z/a) + bc(\sum -b/a * y)
-
- // sgn(1/a) = sgn(a)
- // bc(a*x) = bc(x).multiply(sgn(a))
- // bc(z/a) = bc(z).multiply(sgn(a))
- // bc(\sum -b/a * y) = bc(\sum b y).multiplyBySgn(-sgn(a))
- // bc(\sum b y) = basicCount(z) - bc(a*x)
- // basicCount(x) =
- // = bc(z).multiply(sgn(a)) + (basicCount(z) - bc(a*x)).multiplyBySgn(-sgn(a))
-
- BoundCounts bc = d_boundTracking[basic];
- bc -= (d_variables.boundCounts(nb)).multiplyBySgn(nbSgn);
- bc = bc.multiplyBySgn(-nbSgn);
- bc += d_variables.boundCounts(basic).multiplyBySgn(nbSgn);
- d_boundTracking.set(nb, bc);
- d_boundTracking.remove(basic);
-}
-
-void LinearEqualityModule::trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
- Assert(oldSgn != currSgn);
- BoundCounts nb_bc = d_variables.boundCounts(nb);
-
- if(!nb_bc.isZero()){
- ArithVar basic = d_tableau.rowIndexToBasic(ridx);
- Assert(basicIsTracked(basic));
-
- BoundCounts& basic_bc = d_boundTracking.get(basic);
- basic_bc.addInSgn(nb_bc, oldSgn, currSgn);
- }
+ return (ubc == length) ||
+ (ubc + 1 == length && d_variables.cmpAssignmentLowerBound(basic) != 0);
}
-void LinearEqualityModule::computeSafeUpdate(UpdateInfo& inf, VarPreferenceFunction pref){
- ArithVar nb = inf.nonbasic();
- int sgn = inf.nonbasicDirection();
+void LinearEqualityModule::trackingMultiplyRow(RowIndex ridx, int sgn) {
+ Assert(rowIndexIsTracked(ridx));
Assert(sgn != 0);
- Assert(!d_tableau.isBasic(nb));
-
- //inf.setErrorsChange(0);
- //inf.setlimiting = NullConstraint;
-
-
- // Error variables moving in the correct direction
- Assert(d_relevantErrorBuffer.empty());
-
- // phases :
- enum ComputeSafePhase {
- NoBoundSelected,
- NbsBoundSelected,
- BasicBoundSelected,
- DegenerateBoundSelected
- } phase;
-
- phase = NoBoundSelected;
-
- static int instance = 0;
- Debug("computeSafeUpdate") << "computeSafeUpdate " << (++instance) << endl;
-
- if(sgn > 0 && d_variables.hasUpperBound(nb)){
- Constraint ub = d_variables.getUpperBoundConstraint(nb);
- inf.updatePureFocus(ub->getValue() - d_variables.getAssignment(nb), ub);
-
- Assert(inf.nonbasicDelta().sgn() == sgn);
- Debug("computeSafeUpdate") << "computeSafeUpdate " << inf.limiting() << endl;
- phase = NbsBoundSelected;
- }else if(sgn < 0 && d_variables.hasLowerBound(nb)){
- Constraint lb = d_variables.getLowerBoundConstraint(nb);
- inf.updatePureFocus(lb->getValue() - d_variables.getAssignment(nb), lb);
-
- Assert(inf.nonbasicDelta().sgn() == sgn);
-
- Debug("computeSafeUpdate") << "computeSafeUpdate " << inf.limiting() << endl;
- phase = NbsBoundSelected;
- }
-
- Tableau::ColIterator basicIter = d_tableau.colIterator(nb);
- for(; !basicIter.atEnd(); ++basicIter){
- const Tableau::Entry& entry = *basicIter;
- Assert(entry.getColVar() == nb);
-
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- const Rational& a_ji = entry.getCoefficient();
- int basic_movement = sgn * a_ji.sgn();
-
- Debug("computeSafeUpdate")
- << "computeSafeUpdate: "
- << basic << ", "
- << basic_movement << ", "
- << d_variables.cmpAssignmentUpperBound(basic) << ", "
- << d_variables.cmpAssignmentLowerBound(basic) << ", "
- << a_ji << ", "
- << d_variables.getAssignment(basic) << endl;
-
- Constraint proposal = NullConstraint;
-
- if(basic_movement > 0){
- if(d_variables.cmpAssignmentLowerBound(basic) < 0){
- d_relevantErrorBuffer.push_back(&entry);
- }
- if(d_variables.hasUpperBound(basic) &&
- d_variables.cmpAssignmentUpperBound(basic) <= 0){
- proposal = d_variables.getUpperBoundConstraint(basic);
- }
- }else if(basic_movement < 0){
- if(d_variables.cmpAssignmentUpperBound(basic) > 0){
- d_relevantErrorBuffer.push_back(&entry);
- }
- if(d_variables.hasLowerBound(basic) &&
- d_variables.cmpAssignmentLowerBound(basic) >= 0){
- proposal = d_variables.getLowerBoundConstraint(basic);
- }
- }
- if(proposal != NullConstraint){
- const Rational& coeff = entry.getCoefficient();
- DeltaRational diff = proposal->getValue() - d_variables.getAssignment(basic);
- diff /= coeff;
- int cmp = phase == NoBoundSelected ? 0 : diff.cmp(inf.nonbasicDelta());
- Assert(diff.sgn() == sgn || diff.sgn() == 0);
- bool prefer = false;
- switch(phase){
- case NoBoundSelected:
- prefer = true;
- break;
- case NbsBoundSelected:
- prefer = (sgn > 0 && cmp < 0 ) || (sgn < 0 && cmp > 0);
- break;
- case BasicBoundSelected:
- prefer =
- (sgn > 0 && cmp < 0 ) ||
- (sgn < 0 && cmp > 0) ||
- (cmp == 0 && basic == (this->*pref)(basic, inf.leaving()));
- break;
- case DegenerateBoundSelected:
- prefer = cmp == 0 && basic == (this->*pref)(basic, inf.leaving());
- break;
- }
- if(prefer){
- inf.updatePivot(diff, coeff, proposal);
-
- phase = (diff.sgn() != 0) ? BasicBoundSelected : DegenerateBoundSelected;
- }
- }
+ if(sgn < 0){
+ BoundsInfo& bi = d_btracking.get(ridx);
+ bi = bi.multiplyBySgn(sgn);
}
-
- if(phase == DegenerateBoundSelected){
- inf.setErrorsChange(0);
- }else{
- computedFixed(inf);
- }
- inf.determineFocusDirection();
-
- d_relevantErrorBuffer.clear();
}
-void LinearEqualityModule::computedFixed(UpdateInfo& proposal){
- Assert(proposal.nonbasicDirection() != 0);
- Assert(!d_tableau.isBasic(proposal.nonbasic()));
-
- //bool unconstrained = (proposal.d_limiting == NullConstraint);
-
- Assert(!proposal.unbounded() || !d_relevantErrorBuffer.empty());
-
- Assert(proposal.unbounded() ||
- proposal.nonbasicDelta().sgn() == proposal.nonbasicDirection());
-
- // proposal.d_value is the max
-
- UpdateInfo max;
- int dropped = 0;
- //Constraint maxFix = NullConstraint;
- //DeltaRational maxAmount;
-
- EntryPointerVector::const_iterator i = d_relevantErrorBuffer.begin();
- EntryPointerVector::const_iterator i_end = d_relevantErrorBuffer.end();
- for(; i != i_end; ++i){
- const Tableau::Entry& entry = *(*i);
- Assert(entry.getColVar() == proposal.nonbasic());
-
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- const Rational& a_ji = entry.getCoefficient();
- int basic_movement = proposal.nonbasicDirection() * a_ji.sgn();
-
- DeltaRational theta;
- DeltaRational proposedValue;
- if(!proposal.unbounded()){
- theta = proposal.nonbasicDelta() * a_ji;
- proposedValue = theta + d_variables.getAssignment(basic);
- }
-
- Constraint fixed = NullConstraint;
-
- if(basic_movement < 0){
- Assert(d_variables.cmpAssignmentUpperBound(basic) > 0);
-
- if(proposal.unbounded() || d_variables.cmpToUpperBound(basic, proposedValue) <= 0){
- --dropped;
- fixed = d_variables.getUpperBoundConstraint(basic);
- }
- }else if(basic_movement > 0){
- Assert(d_variables.cmpAssignmentLowerBound(basic) < 0);
+void LinearEqualityModule::trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
+ Assert(oldSgn != currSgn);
+ BoundsInfo nb_inf = d_variables.boundsInfo(nb);
- if(proposal.unbounded() || d_variables.cmpToLowerBound(basic, proposedValue) >= 0){
- --dropped;
- fixed = d_variables.getLowerBoundConstraint(basic);
- }
- }
- if(fixed != NullConstraint){
- DeltaRational amount = fixed->getValue() - d_variables.getAssignment(basic);
- amount /= a_ji;
- Assert(amount.sgn() == proposal.nonbasicDirection());
-
- if(max.uninitialized()){
- max = UpdateInfo(proposal.nonbasic(), proposal.nonbasicDirection());
- max.updatePivot(amount, a_ji, fixed, dropped);
- }else{
- int cmp = amount.cmp(max.nonbasicDelta());
- bool prefer =
- (proposal.nonbasicDirection() < 0 && cmp < 0) ||
- (proposal.nonbasicDirection() > 0 && cmp > 0) ||
- (cmp == 0 && fixed->getVariable() < max.limiting()->getVariable());
-
- if(prefer){
- max.updatePivot(amount, a_ji, fixed, dropped);
- }else{
- max.setErrorsChange(dropped);
- }
- }
- }
- }
- Assert(dropped < 0 || !proposal.unbounded());
+ Assert(rowIndexIsTracked(ridx));
- if(dropped < 0){
- proposal = max;
- }else{
- Assert(dropped == 0);
- Assert(proposal.nonbasicDelta().sgn() != 0);
- Assert(proposal.nonbasicDirection() != 0);
- proposal.setErrorsChange(0);
- }
- Assert(proposal.errorsChange() == dropped);
+ BoundsInfo& row_bi = d_btracking.get(ridx);
+ row_bi.addInSgn(nb_inf, oldSgn, currSgn);
}
ArithVar LinearEqualityModule::minBy(const ArithVarVec& vec, VarPreferenceFunction pf) const{
@@ -1188,8 +956,9 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// Assume past this point, nb will be in error if this pivot is done
ArithVar nb = entry.getColVar();
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- Assert(basicIsTracked(basic));
+ RowIndex ridx = entry.getRowIndex();
+ ArithVar basic = d_tableau.rowIndexToBasic(ridx);
+ Assert(rowIndexIsTracked(ridx));
int coeffSgn = entry.getCoefficient().sgn();
@@ -1201,12 +970,11 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// 2) -a * x = -y + \sum b * z
// 3) x = (-1/a) * ( -y + \sum b * z)
- Assert(basicIsTracked(basic));
- BoundCounts bc = d_boundTracking[basic];
+ BoundCounts bc = d_btracking[ridx].atBounds();
// 1) y = a * x + \sum b * z
// Get bc(\sum b * z)
- BoundCounts sumOnly = bc - d_variables.boundCounts(nb).multiplyBySgn(coeffSgn);
+ BoundCounts sumOnly = bc - d_variables.atBoundCounts(nb).multiplyBySgn(coeffSgn);
// y's bounds in the proposed model
int yWillBeAtUb = (bToUB || d_variables.boundsAreEqual(basic)) ? 1 : 0;
@@ -1215,19 +983,19 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// 2) -a * x = -y + \sum b * z
// Get bc(-y + \sum b * z)
- BoundCounts withNegY = sumOnly + ysBounds.multiplyBySgn(-1);
+ sumOnly.addInChange(-1, d_variables.atBoundCounts(basic), ysBounds);
// 3) x = (-1/a) * ( -y + \sum b * z)
// Get bc((-1/a) * ( -y + \sum b * z))
- BoundCounts xsBoundsAfterPivot = withNegY.multiplyBySgn(-coeffSgn);
+ BoundCounts xsBoundsAfterPivot = sumOnly.multiplyBySgn(-coeffSgn);
uint32_t length = d_tableau.basicRowLength(basic);
if(nbSgn > 0){
// Only check for the upper bound being violated
- return xsBoundsAfterPivot.atLowerBounds() + 1 == length;
+ return xsBoundsAfterPivot.lowerBoundCount() + 1 == length;
}else{
// Only check for the lower bound being violated
- return xsBoundsAfterPivot.atUpperBounds() + 1 == length;
+ return xsBoundsAfterPivot.upperBoundCount() + 1 == length;
}
}
diff --git a/src/theory/arith/linear_equality.h b/src/theory/arith/linear_equality.h
index 8b9b888f2..293a0ddad 100644
--- a/src/theory/arith/linear_equality.h
+++ b/src/theory/arith/linear_equality.h
@@ -192,9 +192,6 @@ public:
};
-
-
-
class LinearEqualityModule {
public:
typedef ArithVar (LinearEqualityModule::*VarPreferenceFunction)(ArithVar, ArithVar) const;
@@ -226,14 +223,12 @@ public:
* Initializes a LinearEqualityModule with a partial model, a tableau,
* and a callback function for when basic variables update their values.
*/
- LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundCountingVector& boundTracking, BasicVarModelUpdateCallBack f);
+ LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundTracking, BasicVarModelUpdateCallBack f);
/**
* Updates the assignment of a nonbasic variable x_i to v.
* Also updates the assignment of basic variables accordingly.
*/
- void updateUntracked(ArithVar x_i, const DeltaRational& v);
- void updateTracked(ArithVar x_i, const DeltaRational& v);
void update(ArithVar x_i, const DeltaRational& v){
if(d_areTracking){
updateTracked(x_i,v);
@@ -241,7 +236,13 @@ public:
updateUntracked(x_i,v);
}
}
- void updateMany(const DenseMap<DeltaRational>& many);
+
+ /** Specialization of update if the module is not tracking yet (for Assert*). */
+ void updateUntracked(ArithVar x_i, const DeltaRational& v);
+
+ /** Specialization of update if the module is not tracking yet (for Simplex). */
+ void updateTracked(ArithVar x_i, const DeltaRational& v);
+
/**
* Updates the value of a basic variable x_i to v,
@@ -249,28 +250,34 @@ public:
* Updates the assignment of the other basic variables accordingly.
*/
void pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v);
- //void pivotAndUpdateAdj(ArithVar x_i, ArithVar x_j, const DeltaRational& v);
ArithVariables& getVariables() const{ return d_variables; }
Tableau& getTableau() const{ return d_tableau; }
+ /**
+ * Updates every non-basic to reflect the assignment in many.
+ * For use with ApproximateSimplex.
+ */
+ void updateMany(const DenseMap<DeltaRational>& many);
void forceNewBasis(const DenseSet& newBasis);
+ void applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues);
+
+
+ /**
+ * Returns a pointer to the first Tableau entry on the row ridx that does not
+ * have an either a lower bound/upper bound for proving a bound on skip.
+ * The variable skip is always excluded. Returns NULL if there is no such element.
+ *
+ * If skip == ARITHVAR_SENTINEL, this is equivalent to considering the whole row.
+ */
+ const Tableau::Entry* rowLacksBound(RowIndex ridx, bool upperBound, ArithVar skip);
- bool hasBounds(ArithVar basic, bool upperBound);
- bool hasLowerBounds(ArithVar basic){
- return hasBounds(basic, false);
- }
- bool hasUpperBounds(ArithVar basic){
- return hasBounds(basic, true);
- }
void startTrackingBoundCounts();
void stopTrackingBoundCounts();
- void includeBoundCountChange(ArithVar nb, BoundCounts prev);
-
- void computeSafeUpdate(UpdateInfo& inf, VarPreferenceFunction basic);
+ void includeBoundUpdate(ArithVar nb, const BoundsInfo& prev);
uint32_t updateProduct(const UpdateInfo& inf) const;
@@ -334,40 +341,6 @@ public:
}
}
- // template<bool heuristic>
- // bool preferNonDegenerate(const UpdateInfo& a, const UpdateInfo& b) const{
- // if(a.focusDirection() == b.focusDirection()){
- // if(heuristic){
- // return preferNeitherBound(a,b);
- // }else{
- // return minNonBasicVarOrder(a,b);
- // }
- // }else{
- // return a.focusDirection() < b.focusDirection();
- // }
- // }
-
- // template <bool heuristic>
- // bool preferErrorsFixed(const UpdateInfo& a, const UpdateInfo& b) const{
- // if( a.errorsChange() == b.errorsChange() ){
- // return preferNonDegenerate<heuristic>(a,b);
- // }else{
- // return a.errorsChange() > b.errorsChange();
- // }
- // }
-
- // template <bool heuristic>
- // bool preferConflictFound(const UpdateInfo& a, const UpdateInfo& b) const{
- // if(a.d_foundConflict && b.d_foundConflict){
- // // if both are true, determinize the preference
- // return minNonBasicVarOrder(a,b);
- // }else if( a.d_foundConflict || b.d_foundConflict ){
- // return b.d_foundConflict;
- // }else{
- // return preferErrorsFixed<heuristic>(a,b);
- // }
- // }
-
bool modifiedBlands(const UpdateInfo& a, const UpdateInfo& b) const {
Assert(a.focusDirection() == 0 && b.focusDirection() == 0);
Assert(a.describesPivot());
@@ -427,31 +400,27 @@ public:
}
private:
- typedef std::vector<const Tableau::Entry*> EntryPointerVector;
- EntryPointerVector d_relevantErrorBuffer;
-
- //uint32_t computeUnconstrainedUpdate(ArithVar nb, int sgn, DeltaRational& am);
- //uint32_t computedFixed(ArithVar nb, int sgn, const DeltaRational& am);
- void computedFixed(UpdateInfo&);
- // RowIndex -> BoundCount
- BoundCountingVector& d_boundTracking;
+ /**
+ * This maps each row index to its relevant bounds info.
+ * This tracks the count for how many variables on a row have bounds
+ * and how many are assigned at their bounds.
+ */
+ BoundInfoMap& d_btracking;
bool d_areTracking;
+public:
+ /**
+ * The constraint on a basic variable b is implied by the constraints
+ * on its row. This is a wrapper for propagateRow().
+ */
+ void propagateBasicFromRow(Constraint c);
+
/**
* Exports either the explanation of an upperbound or a lower bound
* of the basic variable basic, using the non-basic variables in the row.
*/
- template <bool upperBound>
- void propagateNonbasics(ArithVar basic, Constraint c);
-
-public:
- void propagateNonbasicsLowerBound(ArithVar basic, Constraint c){
- propagateNonbasics<false>(basic, c);
- }
- void propagateNonbasicsUpperBound(ArithVar basic, Constraint c){
- propagateNonbasics<true>(basic, c);
- }
+ void propagateRow(std::vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c);
/**
* Computes the value of a basic variable using the assignments
@@ -460,14 +429,7 @@ public:
* - the the current assignment (useSafe=false) or
* - the safe assignment (useSafe = true).
*/
- DeltaRational computeRowValue(ArithVar x, bool useSafe);
-
- inline DeltaRational computeLowerBound(ArithVar basic){
- return computeBound(basic, false);
- }
- inline DeltaRational computeUpperBound(ArithVar basic){
- return computeBound(basic, true);
- }
+ DeltaRational computeRowValue(ArithVar x, bool useSafe) const;
/**
* A PreferenceFunction takes a const ref to the SimplexDecisionProcedure,
@@ -548,41 +510,64 @@ public:
const Tableau::Entry* selectSlackEntry(ArithVar x_i, bool above) const;
+ inline bool rowIndexIsTracked(RowIndex ridx) const {
+ return d_btracking.isKey(ridx);
+ }
inline bool basicIsTracked(ArithVar v) const {
- return d_boundTracking.isKey(v);
+ return rowIndexIsTracked(d_tableau.basicToRowIndex(v));
}
- void trackVariable(ArithVar x_i);
-
- void maybeRemoveTracking(ArithVar v){
- Assert(!d_tableau.isBasic(v));
- if(d_boundTracking.isKey(v)){
- d_boundTracking.remove(v);
- }
+ void trackRowIndex(RowIndex ridx);
+ void stopTrackingRowIndex(RowIndex ridx){
+ Assert(rowIndexIsTracked(ridx));
+ d_btracking.remove(ridx);
}
- // void trackVariable(ArithVar x_i){
- // Assert(!basicIsTracked(x_i));
- // d_boundTracking.set(x_i,computeBoundCounts(x_i));
- // }
+ /**
+ * If the pivot described in u were performed,
+ * then the row would qualify as being either at the minimum/maximum
+ * to the non-basics being at their bounds.
+ * The minimum/maximum is determined by the direction the non-basic is changing.
+ */
bool basicsAtBounds(const UpdateInfo& u) const;
+
private:
- BoundCounts computeBoundCounts(ArithVar x_i) const;
+
+ /**
+ * Recomputes the bound info for a row using either the information
+ * in the bounds queue or the current information.
+ * O(row length of ridx)
+ */
+ BoundsInfo computeRowBoundInfo(RowIndex ridx, bool inQueue) const;
+
public:
- //BoundCounts cachingCountBounds(ArithVar x_i) const;
- BoundCounts _countBounds(ArithVar x_i) const;
+ /** Debug only routine. */
+ BoundCounts debugBasicAtBoundCount(ArithVar x_i) const;
+
+ /** Track the effect of the change of coefficient for bound counting. */
void trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
- void trackingSwap(ArithVar basic, ArithVar nb, int sgn);
+ /** Track the effect of multiplying a row by a sign for bound counting. */
+ void trackingMultiplyRow(RowIndex ridx, int sgn);
+
+ /** Count for how many on a row have *an* upper/lower bounds. */
+ BoundCounts hasBoundCount(RowIndex ri) const {
+ Assert(d_variables.boundsQueueEmpty());
+ return d_btracking[ri].hasBounds();
+ }
+ /**
+ * Are there any non-basics on x_i's row that are not at
+ * their respective lower bounds (mod sgns).
+ * O(1) time due to the atBound() count.
+ */
bool nonbasicsAtLowerBounds(ArithVar x_i) const;
- bool nonbasicsAtUpperBounds(ArithVar x_i) const;
- ArithVar _anySlackLowerBound(ArithVar x_i) const {
- return selectSlack<true>(x_i, &LinearEqualityModule::noPreference);
- }
- ArithVar _anySlackUpperBound(ArithVar x_i) const {
- return selectSlack<false>(x_i, &LinearEqualityModule::noPreference);
- }
+ /**
+ * Are there any non-basics on x_i's row that are not at
+ * their respective upper bounds (mod sgns).
+ * O(1) time due to the atBound() count.
+ */
+ bool nonbasicsAtUpperBounds(ArithVar x_i) const;
private:
class TrackingCallback : public CoefficientChangeCallback {
@@ -593,8 +578,8 @@ private:
void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
d_linEq->trackingCoefficientChange(ridx, nb, oldSgn, currSgn);
}
- void swap(ArithVar basic, ArithVar nb, int oldNbSgn){
- d_linEq->trackingSwap(basic, nb, oldNbSgn);
+ void multiplyRow(RowIndex ridx, int sgn){
+ d_linEq->trackingMultiplyRow(ridx, sgn);
}
bool canUseRow(RowIndex ridx) const {
ArithVar basic = d_linEq->getTableau().rowIndexToBasic(ridx);
@@ -629,8 +614,11 @@ public:
return minimallyWeakConflict(false, conflictVar);
}
-private:
- DeltaRational computeBound(ArithVar basic, bool upperBound);
+ /**
+ * Computes the sum of the upper/lower bound of row.
+ * The variable skip is not included in the sum.
+ */
+ DeltaRational computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const;
public:
void substitutePlusTimesConstant(ArithVar to, ArithVar from, const Rational& mult);
@@ -703,6 +691,7 @@ private:
IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
TimerStat d_weakenTime;
+ TimerStat d_forceTime;
Statistics();
~Statistics();
@@ -737,13 +726,13 @@ public:
}
};
-class UpdateTrackingCallback : public BoundCountsCallback {
+class UpdateTrackingCallback : public BoundUpdateCallback {
private:
LinearEqualityModule* d_mod;
public:
UpdateTrackingCallback(LinearEqualityModule* mod): d_mod(mod){}
- void operator()(ArithVar v, BoundCounts bc){
- d_mod->includeBoundCountChange(v, bc);
+ void operator()(ArithVar v, const BoundsInfo& bi){
+ d_mod->includeBoundUpdate(v, bi);
}
};
diff --git a/src/theory/arith/matrix.cpp b/src/theory/arith/matrix.cpp
index 7136c3fa8..b8bd68488 100644
--- a/src/theory/arith/matrix.cpp
+++ b/src/theory/arith/matrix.cpp
@@ -24,7 +24,7 @@ namespace theory {
namespace arith {
void NoEffectCCCB::update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) {}
-void NoEffectCCCB::swap(ArithVar basic, ArithVar nb, int nbSgn){}
+void NoEffectCCCB::multiplyRow(RowIndex ridx, int sgn){}
bool NoEffectCCCB::canUseRow(RowIndex ridx) const { return false; }
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/matrix.h b/src/theory/arith/matrix.h
index 100f999e0..d93b6986e 100644
--- a/src/theory/arith/matrix.h
+++ b/src/theory/arith/matrix.h
@@ -39,15 +39,15 @@ const RowIndex ROW_INDEX_SENTINEL = std::numeric_limits<RowIndex>::max();
class CoefficientChangeCallback {
public:
- virtual void update(RowIndex basic, ArithVar nb, int oldSgn, int currSgn) = 0;
- virtual void swap(ArithVar basic, ArithVar nb, int nbSgn) = 0;
+ virtual void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) = 0;
+ virtual void multiplyRow(RowIndex ridx, int Sgn) = 0;
virtual bool canUseRow(RowIndex ridx) const = 0;
};
class NoEffectCCCB : public CoefficientChangeCallback {
public:
void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
- void swap(ArithVar basic, ArithVar nb, int nbSgn);
+ void multiplyRow(RowIndex ridx, int Sgn);
bool canUseRow(RowIndex ridx) const;
};
diff --git a/src/theory/arith/normal_form.cpp b/src/theory/arith/normal_form.cpp
index 8454ca210..7cd202e53 100644
--- a/src/theory/arith/normal_form.cpp
+++ b/src/theory/arith/normal_form.cpp
@@ -22,7 +22,7 @@
using namespace std;
namespace CVC4 {
-namespace theory{
+namespace theory {
namespace arith {
bool Variable::isDivMember(Node n){
@@ -745,9 +745,8 @@ bool Comparison::isNormalGEQ() const {
return false;
}else{
if(left.isIntegral()){
- return left.denominatorLCMIsOne() && left.numeratorGCDIsOne();
+ return left.signNormalizedReducedSum();
}else{
- Debug("nf::tmp") << "imme sdfhkdjfh "<< left.leadingCoefficientIsAbsOne() << endl;
return left.leadingCoefficientIsAbsOne();
}
}
@@ -768,7 +767,7 @@ bool Comparison::isNormalLT() const {
return false;
}else{
if(left.isIntegral()){
- return left.denominatorLCMIsOne() && left.numeratorGCDIsOne();
+ return left.signNormalizedReducedSum();
}else{
return left.leadingCoefficientIsAbsOne();
}
@@ -889,6 +888,7 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
Polynomial left = sp.getPolynomial();
Rational right = - (sp.getConstant().getValue());
+
Monomial m = left.getHead();
Assert(!m.isConstant());
@@ -899,16 +899,31 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
Polynomial newLeft = left * mult;
Rational rightMult = right * mult;
+ bool negateResult = false;
+ if(!newLeft.leadingCoefficientIsPositive()){
+ // multiply by -1
+ // a: left >= right or b: left > right
+ // becomes
+ // a: -left <= -right or b: -left < -right
+ // a: not (-left > -right) or b: (not -left >= -right)
+ newLeft = -newLeft;
+ rightMult = -rightMult;
+ k = (kind::GT == k) ? kind::GEQ : kind::GT;
+ negateResult = true;
+ // the later stages handle:
+ // a: not (-left >= -right + 1) or b: (not -left >= -right)
+ }
+ Node result = Node::null();
if(rightMult.isIntegral()){
if(k == kind::GT){
// (> p z)
// (>= p (+ z 1))
Constant rightMultPlusOne = Constant::mkConstant(rightMult + 1);
- return toNode(kind::GEQ, newLeft, rightMultPlusOne);
+ result = toNode(kind::GEQ, newLeft, rightMultPlusOne);
}else{
Constant newRight = Constant::mkConstant(rightMult);
- return toNode(kind::GEQ, newLeft, newRight);
+ result = toNode(kind::GEQ, newLeft, newRight);
}
}else{
//(>= l (/ n d))
@@ -916,7 +931,13 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
//This also hold for GT as (ceil (/ n d)) > (/ n d)
Integer ceilr = rightMult.ceiling();
Constant ceilRight = Constant::mkConstant(ceilr);
- return toNode(kind::GEQ, newLeft, ceilRight);
+ result = toNode(kind::GEQ, newLeft, ceilRight);
+ }
+ Assert(!result.isNull());
+ if(negateResult){
+ return result.notNode();
+ }else{
+ return result;
}
}
diff --git a/src/theory/arith/normal_form.h b/src/theory/arith/normal_form.h
index bcf9cbfa4..1dddb5a5b 100644
--- a/src/theory/arith/normal_form.h
+++ b/src/theory/arith/normal_form.h
@@ -76,12 +76,13 @@ namespace arith {
* (exists realMonomial (monomialList qpolynomial))
* abs(monomialCoefficient (head (monomialList qpolynomial))) == 1
*
- * integer_cmp := (<= zpolynomial constant)
+ * integer_cmp := (>= zpolynomial constant)
* where
* not (exists constantMonomial (monomialList zpolynomial))
* (forall integerMonomial (monomialList zpolynomial))
* the gcd of all numerators of coefficients is 1
* the denominator of all coefficients and the constant is 1
+ * the leading coefficient is positive
*
* rational_eq := (= qvarlist qpolynomial)
* where
@@ -240,6 +241,11 @@ public:
case kind::INTS_MODULUS_TOTAL:
case kind::DIVISION_TOTAL:
return isDivMember(n);
+ case kind::ABS:
+ case kind::TO_INTEGER:
+ // Treat to_int as a variable; it is replaced in early preprocessing
+ // by a variable.
+ return true;
default:
return (!isRelationOperator(k)) &&
(Theory::isLeafOf(n, theory::THEORY_ARITH));
@@ -939,6 +945,10 @@ public:
bool denominatorLCMIsOne() const;
bool numeratorGCDIsOne() const;
+ bool signNormalizedReducedSum() const {
+ return leadingCoefficientIsPositive() && denominatorLCMIsOne() && numeratorGCDIsOne();
+ }
+
/**
* Returns the Least Common Multiple of the denominators of the coefficients
* of the monomials.
@@ -1265,7 +1275,7 @@ private:
* Creates a comparison equivalent to (k l 0).
* k is either GT or GEQ.
* It is not the case that all variables in l are integral.
- */
+ */
static Node mkRatInequality(Kind k, const Polynomial& l);
public:
diff --git a/src/theory/arith/options b/src/theory/arith/options
index 977d6cb32..43b582bc8 100644
--- a/src/theory/arith/options
+++ b/src/theory/arith/options
@@ -56,7 +56,7 @@ option arithMLTrick miplib-trick --enable-miplib-trick/--disable-miplib-trick bo
turns on the preprocessing step of attempting to infer bounds on miplib problems
/turns off the preprocessing step of attempting to infer bounds on miplib problems
-option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs unsigned :default 1
+option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs=N unsigned :default 1
do substitution for miplib 'tmp' vars if defined in <= N eliminated vars
option doCutAllBounded --cut-all-bounded bool :default false :read-write
@@ -67,11 +67,11 @@ option maxCutsInContext --maxCutsInContext unsigned :default 65535
maximum cuts in a given context before signalling a restart
option revertArithModels --revert-arith-models-on-unsat bool :default false
- Revert the arithmetic model to a known safe model on unsat if one is cached
+ revert the arithmetic model to a known safe model on unsat if one is cached
option havePenalties --fc-penalties bool :default false :read-write
turns on degenerate pivot penalties
-/ turns off degenerate pivot penalties
+/turns off degenerate pivot penalties
option useFC --use-fcsimplex bool :default false :read-write
use focusing and converging simplex (FMCAD 2013 submission)
@@ -80,15 +80,27 @@ option useSOI --use-soi bool :default false :read-write
use sum of infeasibility simplex (FMCAD 2013 submission)
option restrictedPivots --restrict-pivots bool :default true :read-write
- have a pivot cap for simplex at effort levels below fullEffort.
+ have a pivot cap for simplex at effort levels below fullEffort
option collectPivots --collect-pivot-stats bool :default false :read-write
collect the pivot history
option fancyFinal --fancy-final bool :default false :read-write
- Tuning how final check works for really hard problems.
+ tuning how final check works for really hard problems
option exportDioDecompositions --dio-decomps bool :default false :read-write
- Let skolem variables for integer divisibility constraints leak from the dio solver.
+ let skolem variables for integer divisibility constraints leak from the dio solver
+
+option newProp --new-prop bool :default false :read-write
+ use the new row propagation system
+
+option arithPropAsLemmaLength --arith-prop-clauses uint16_t :default 8 :read-write
+ rows shorter than this are propagated as clauses
+
+option soiQuickExplain --soi-qe bool :default false :read-write
+ use quick explain to minimize the sum of infeasibility conflicts
+
+option rewriteDivk rewrite-divk --rewrite-divk bool :default false
+ rewrite division and mod when by a constant into linear terms
endmodule
diff --git a/src/theory/arith/partial_model.cpp b/src/theory/arith/partial_model.cpp
index 695d9df25..3fae3751c 100644
--- a/src/theory/arith/partial_model.cpp
+++ b/src/theory/arith/partial_model.cpp
@@ -35,12 +35,13 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
d_released(),
d_releasedIterator(d_released.begin()),
d_nodeToArithVarMap(),
+ d_boundsQueue(),
+ d_enqueueingBoundCounts(true),
d_lbRevertHistory(c, true, LowerBoundCleanUp(this)),
d_ubRevertHistory(c, true, UpperBoundCleanUp(this)),
d_deltaIsSafe(false),
d_delta(-1,1),
- d_deltaComputingFunc(deltaComputingFunc),
- d_enqueueingBoundCounts(true)
+ d_deltaComputingFunc(deltaComputingFunc)
{ }
ArithVariables::VarInfo::VarInfo()
@@ -55,6 +56,10 @@ ArithVariables::VarInfo::VarInfo()
d_slack(false)
{ }
+bool ArithVariables::VarInfo::initialized() const {
+ return d_var != ARITHVAR_SENTINEL;
+}
+
void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
Assert(!initialized());
Assert(d_lb == NullConstraint);
@@ -82,7 +87,7 @@ void ArithVariables::VarInfo::uninitialize(){
d_node = Node::null();
}
-bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundCounts & prev){
+bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundsInfo& prev){
Assert(initialized());
d_assignment = a;
int cmpUB = (d_ub == NullConstraint) ? -1 :
@@ -97,7 +102,7 @@ bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundCounts
(cmpUB == 0 || d_cmpAssignmentUB == 0);
if(lbChanged || ubChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
d_cmpAssignmentUB = cmpUB;
@@ -119,33 +124,59 @@ void ArithVariables::releaseArithVar(ArithVar v){
}
}
-bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundCounts& prev){
+bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
Assert(initialized());
- d_ub = ub;
- int cmpUB = (d_ub == NullConstraint) ? -1 : d_assignment.cmp(d_ub->getValue());
- bool ubChanged = cmpUB != d_cmpAssignmentUB &&
- (cmpUB == 0 || d_cmpAssignmentUB == 0);
+ bool wasNull = d_ub == NullConstraint;
+ bool isNull = ub == NullConstraint;
+
+ int cmpUB = isNull ? -1 : d_assignment.cmp(ub->getValue());
+ bool ubChanged = (wasNull != isNull) ||
+ (cmpUB != d_cmpAssignmentUB && (cmpUB == 0 || d_cmpAssignmentUB == 0));
if(ubChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
+ d_ub = ub;
d_cmpAssignmentUB = cmpUB;
return ubChanged;
}
-bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundCounts& prev){
+bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundsInfo& prev){
Assert(initialized());
- d_lb = lb;
- int cmpLB = (d_lb == NullConstraint) ? 1 : d_assignment.cmp(d_lb->getValue());
+ bool wasNull = d_lb == NullConstraint;
+ bool isNull = lb == NullConstraint;
- bool lbChanged = cmpLB != d_cmpAssignmentLB &&
- (cmpLB == 0 || d_cmpAssignmentLB == 0);
+ int cmpLB = isNull ? 1 : d_assignment.cmp(lb->getValue());
+
+ bool lbChanged = (wasNull != isNull) ||
+ (cmpLB != d_cmpAssignmentLB && (cmpLB == 0 || d_cmpAssignmentLB == 0));
if(lbChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
+ d_lb = lb;
d_cmpAssignmentLB = cmpLB;
return lbChanged;
}
+BoundCounts ArithVariables::VarInfo::atBoundCounts() const {
+ uint32_t lbIndc = (d_cmpAssignmentLB == 0) ? 1 : 0;
+ uint32_t ubIndc = (d_cmpAssignmentUB == 0) ? 1 : 0;
+ return BoundCounts(lbIndc, ubIndc);
+}
+
+BoundCounts ArithVariables::VarInfo::hasBoundCounts() const {
+ uint32_t lbIndc = (d_lb != NullConstraint) ? 1 : 0;
+ uint32_t ubIndc = (d_ub != NullConstraint) ? 1 : 0;
+ return BoundCounts(lbIndc, ubIndc);
+}
+
+BoundsInfo ArithVariables::VarInfo::boundsInfo() const{
+ return BoundsInfo(atBoundCounts(), hasBoundCounts());
+}
+
+bool ArithVariables::VarInfo::canBeReclaimed() const{
+ return d_pushCount == 0;
+}
+
void ArithVariables::attemptToReclaimReleased(){
std::list<ArithVar>::iterator i_end = d_released.end();
for(int iter = 0; iter < 20 && d_releasedIterator != i_end; ++d_releasedIterator){
@@ -170,7 +201,7 @@ ArithVar ArithVariables::allocateVariable(){
attemptToReclaimReleased();
}
bool reclaim = !d_pool.empty();
-
+
ArithVar varX;
if(reclaim){
varX = d_pool.back();
@@ -210,7 +241,7 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& r){
}
invalidateDelta();
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(r, prev)){
addToBoundQueue(x, prev);
}
@@ -229,7 +260,7 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& safe, const
invalidateDelta();
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(r, prev)){
addToBoundQueue(x, prev);
}
@@ -314,7 +345,7 @@ void ArithVariables::setLowerBoundConstraint(Constraint c){
invalidateDelta();
VarInfo& vi = d_vars.get(x);
pushLowerBound(vi);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setLowerBound(c, prev)){
addToBoundQueue(x, prev);
}
@@ -333,37 +364,12 @@ void ArithVariables::setUpperBoundConstraint(Constraint c){
invalidateDelta();
VarInfo& vi = d_vars.get(x);
pushUpperBound(vi);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setUpperBound(c, prev)){
addToBoundQueue(x, prev);
}
}
-// void ArithVariables::forceRelaxLowerBound(ArithVar v){
-// AssertArgument(inMaps(v), "Calling forceRelaxLowerBound on a variable that is not properly setup.");
-// AssertArgument(hasLowerBound(v), "Calling forceRelaxLowerBound on a variable without a lowerbound.");
-
-// Debug("partial_model") << "forceRelaxLowerBound(" << v << ") dropping :" << getLowerBoundConstraint(v) << endl;
-
-// invalidateDelta();
-// VarInfo& vi = d_vars.get(v);
-// pushLowerBound(vi);
-// vi.setLowerBound(NullConstraint);
-// }
-
-
-// void ArithVariables::forceRelaxUpperBound(ArithVar v){
-// AssertArgument(inMaps(v), "Calling forceRelaxUpperBound on a variable that is not properly setup.");
-// AssertArgument(hasUpperBound(v), "Calling forceRelaxUpperBound on a variable without an upper bound.");
-
-// Debug("partial_model") << "forceRelaxUpperBound(" << v << ") dropping :" << getUpperBoundConstraint(v) << endl;
-
-// invalidateDelta();
-// VarInfo& vi = d_vars.get(v);
-// pushUpperBound(vi);
-// vi.setUpperBound(NullConstraint);
-// }
-
int ArithVariables::cmpToLowerBound(ArithVar x, const DeltaRational& c) const{
if(!hasLowerBound(x)){
// l = -\intfy
@@ -405,30 +411,16 @@ bool ArithVariables::hasEitherBound(ArithVar x) const{
bool ArithVariables::strictlyBelowUpperBound(ArithVar x) const{
return d_vars[x].d_cmpAssignmentUB < 0;
- // if(!hasUpperBound(x)){ // u = \infty
- // return true;
- // }else{
- // return d_assignment[x] < getUpperBound(x);
- // }
}
bool ArithVariables::strictlyAboveLowerBound(ArithVar x) const{
return d_vars[x].d_cmpAssignmentLB > 0;
- // if(!hasLowerBound(x)){ // l = -\infty
- // return true;
- // }else{
- // return getLowerBound(x) < d_assignment[x];
- // }
}
bool ArithVariables::assignmentIsConsistent(ArithVar x) const{
return
d_vars[x].d_cmpAssignmentLB >= 0 &&
d_vars[x].d_cmpAssignmentUB <= 0;
- // const DeltaRational& beta = getAssignment(x);
-
- // //l_i <= beta(x_i) <= u_i
- // return greaterThanLowerBound(x,beta) && lessThanUpperBound(x,beta);
}
@@ -442,7 +434,7 @@ void ArithVariables::clearSafeAssignments(bool revert){
ArithVar atBack = d_safeAssignment.back();
if(revert){
VarInfo& vi = d_vars.get(atBack);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(d_safeAssignment[atBack], prev)){
addToBoundQueue(atBack, prev);
}
@@ -489,33 +481,6 @@ void ArithVariables::printModel(ArithVar x) const{
printModel(x, Debug("model"));
}
-// BoundRelationship ArithVariables::boundRelationship(Constraint lb, const DeltaRational& d, Constraint ub){
-// if(lb == NullConstraint && ub == NullConstraint){
-// return BetweenBounds;
-// }else if(lb == NullConstraint){
-// int cmp = d.cmp(ub->getValue());
-// return (cmp < 0) ? BetweenBounds :
-// (cmp == 0 ? AtUpperBound : AboveUpperBound);
-// }else if(ub == NullConstraint){
-// int cmp = d.cmp(lb->getValue());
-// return (cmp > 0) ? BetweenBounds :
-// (cmp == 0 ? AtLowerBound : BelowLowerBound);
-// }else{
-// Assert(lb->getValue() <= ub->getValue());
-// int cmpToLB = d.cmp(lb->getValue());
-// if(cmpToLB < 0){
-// return BelowLowerBound;
-// }else if(cmpToLB == 0){
-// return (d == ub->getValue()) ? AtBothBounds : AtLowerBound;
-// }else{
-// // d > 0
-// int cmpToUB = d.cmp(ub->getValue());
-// return (cmpToUB > 0) ? BetweenBounds :
-// (cmpToUB == 0 ? AtLowerBound : BelowLowerBound);
-// }
-// }
-// }
-
void ArithVariables::pushUpperBound(VarInfo& vi){
++vi.d_pushCount;
d_ubRevertHistory.push_back(make_pair(vi.d_var, vi.d_ub));
@@ -528,7 +493,7 @@ void ArithVariables::pushLowerBound(VarInfo& vi){
void ArithVariables::popUpperBound(AVCPair* c){
ArithVar x = c->first;
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setUpperBound(c->second, prev)){
addToBoundQueue(x, prev);
}
@@ -538,62 +503,42 @@ void ArithVariables::popUpperBound(AVCPair* c){
void ArithVariables::popLowerBound(AVCPair* c){
ArithVar x = c->first;
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setLowerBound(c->second, prev)){
addToBoundQueue(x, prev);
}
--vi.d_pushCount;
}
-/* To ensure that the final deallocation stuff works,
- * we need to ensure that we need to not reference any of the other vectors
- */
-// void ArithVariables::relaxUpperBound(Constraint curr, Constraint afterPop){
-// BoundRelation next = Undefined;
-// switch(d_boundRel[x]){
-// case BelowLowerBound:
-// case BetweenBounds:
-// case AtLowerBound:
-// return; // do nothing
-// case AtUpperBound:
-// if(afterPop != NullConstraint
-// && curr->getValue() == afterPop->getValue()){
-// next = AtUpperBound;
-// }else{
-// next = BetweenBounds;
-// }
-// break;
-// case AtBothBounds:
-// if(afterPop != NullConstraint
-// && curr->getValue() == afterPop->getValue()){
-// next = AtUpperBound;
-// }else{
-// next = AtLowerBound;
-// }
-// break;
-// case AboveUpperBound:
-// if(afterPop == NullConstraint){
-// next = BetweenBounds;
-// }else{
-// int cmp = d_assignment[x].cmp(afterPop->getValue());
-// next = (cmp < 0) ? BetweenBounds :
-// (cmp == 0) ? AtUpperBound : AboveUpperBound;
-// }
-// break;
-// default:
-// Unreachable();
-// }
-// d_boundRel[x] = next;
-// }
+void ArithVariables::addToBoundQueue(ArithVar v, const BoundsInfo& prev){
+ if(d_enqueueingBoundCounts && !d_boundsQueue.isKey(v)){
+ d_boundsQueue.set(v, prev);
+ }
+}
+BoundsInfo ArithVariables::selectBoundsInfo(ArithVar v, bool old) const {
+ if(old && d_boundsQueue.isKey(v)){
+ return d_boundsQueue[v];
+ }else{
+ return boundsInfo(v);
+ }
+}
+bool ArithVariables::boundsQueueEmpty() const {
+ return d_boundsQueue.empty();
+}
-// void ArithVariables::relaxLowerBound(Constraint curr, Constraint afterPop){
-// // TODO this can be optimized using the automata induced by d_boundRel and
-// // the knowledge that lb <= ub
-// ArithVar x = curr->getVariable();
-// d_boundRel[x] = boundRelationship(afterPop, d_assignment[x], d_ubc[x]);
-// }
+void ArithVariables::processBoundsQueue(BoundUpdateCallback& changed){
+ while(!boundsQueueEmpty()){
+ ArithVar v = d_boundsQueue.back();
+ BoundsInfo prev = d_boundsQueue[v];
+ d_boundsQueue.pop_back();
+ BoundsInfo curr = boundsInfo(v);
+ if(prev != curr){
+ changed(v, prev);
+ }
+ }
+}
void ArithVariables::LowerBoundCleanUp::operator()(AVCPair* p){
d_pm->popLowerBound(p);
diff --git a/src/theory/arith/partial_model.h b/src/theory/arith/partial_model.h
index dcfe97079..deafb559a 100644
--- a/src/theory/arith/partial_model.h
+++ b/src/theory/arith/partial_model.h
@@ -44,6 +44,7 @@ namespace arith {
class ArithVariables {
private:
+
class VarInfo {
friend class ArithVariables;
ArithVar d_var;
@@ -62,29 +63,36 @@ private:
public:
VarInfo();
- bool setAssignment(const DeltaRational& r, BoundCounts& prev);
- bool setLowerBound(Constraint c, BoundCounts& prev);
- bool setUpperBound(Constraint c, BoundCounts& prev);
+ bool setAssignment(const DeltaRational& r, BoundsInfo& prev);
+ bool setLowerBound(Constraint c, BoundsInfo& prev);
+ bool setUpperBound(Constraint c, BoundsInfo& prev);
- bool initialized() const {
- return d_var != ARITHVAR_SENTINEL;
- }
+ /** Returns true if this VarInfo has been initialized. */
+ bool initialized() const;
+
+ /**
+ * Initializes the VarInfo with the ArithVar index it is associated with,
+ * the node that the variable represents, and whether it is a slack variable.
+ */
void initialize(ArithVar v, Node n, bool slack);
+ /** Uninitializes the VarInfo. */
void uninitialize();
- bool canBeReclaimed() const{
- return d_pushCount == 0;
- }
+ bool canBeReclaimed() const;
- BoundCounts boundCounts() const {
- uint32_t lbIndc = (d_cmpAssignmentLB == 0) ? 1 : 0;
- uint32_t ubIndc = (d_cmpAssignmentUB == 0) ? 1 : 0;
- return BoundCounts(lbIndc, ubIndc);
- }
+ /** Indicator variables for if the assignment is equal to the upper and lower bounds. */
+ BoundCounts atBoundCounts() const;
+
+ /** Combination of indicator variables for whether it has upper and lower bounds. */
+ BoundCounts hasBoundCounts() const;
+
+ /** Stores both atBoundCounts() and hasBoundCounts(). */
+ BoundsInfo boundsInfo() const;
};
- //Maps from ArithVar -> VarInfo
+ /**Maps from ArithVar -> VarInfo */
typedef DenseMap<VarInfo> VarInfoVec;
+ /** This maps an ArithVar to its Variable information.*/
VarInfoVec d_vars;
// Partial Map from Arithvar -> PreviousAssignment
@@ -104,7 +112,15 @@ private:
// Inverse of d_vars[x].d_node
NodeToArithVarMap d_nodeToArithVarMap;
- DenseMap<BoundCounts> d_atBoundsQueue;
+
+ /** The queue of constraints where the assignment is at the bound.*/
+ DenseMap<BoundsInfo> d_boundsQueue;
+
+ /**
+ * If this is true, record the incoming changes to the bound information.
+ * If this is false, the responsibility of recording the changes is LinearEqualities's.
+ */
+ bool d_enqueueingBoundCounts;
public:
@@ -188,6 +204,11 @@ private:
bool isSlack(ArithVar x) const {
return d_vars[x].d_slack;
}
+
+ bool integralAssignment(ArithVar x) const {
+ return getAssignment(x).isIntegral();
+ }
+
private:
typedef std::pair<ArithVar, Constraint> AVCPair;
@@ -225,7 +246,6 @@ private:
// Function to call if the value of delta needs to be recomputed.
DeltaComputeCallback d_deltaComputingFunc;
- bool d_enqueueingBoundCounts;
public:
@@ -252,22 +272,7 @@ public:
return d_vars[x].d_lb;
}
- /**
- * This forces the lower bound for a variable to be relaxed in the current context.
- * This is done by forcing the lower bound to be NullConstraint.
- * This is an expert only operation! (See primal simplex for an example.)
- */
- //void forceRelaxLowerBound(ArithVar x);
-
- /**
- * This forces the upper bound for a variable to be relaxed in the current context.
- * This is done by forcing the upper bound to be NullConstraint.
- * This is an expert only operation! (See primal simplex for an example.)
- */
- //void forceRelaxUpperBound(ArithVar x);
-
/* Initializes a variable to a safe value.*/
- //void initialize(ArithVar x, const DeltaRational& r);
void initialize(ArithVar x, Node n, bool slack);
ArithVar allocate(Node n, bool slack = false);
@@ -360,8 +365,14 @@ public:
return d_vars[x].d_cmpAssignmentUB;
}
- inline BoundCounts boundCounts(ArithVar x) const {
- return d_vars[x].boundCounts();
+ inline BoundCounts atBoundCounts(ArithVar x) const {
+ return d_vars[x].atBoundCounts();
+ }
+ inline BoundCounts hasBoundCounts(ArithVar x) const {
+ return d_vars[x].hasBoundCounts();
+ }
+ inline BoundsInfo boundsInfo(ArithVar x) const{
+ return d_vars[x].boundsInfo();
}
bool strictlyBelowUpperBound(ArithVar x) const;
@@ -391,38 +402,14 @@ public:
d_deltaIsSafe = true;
}
- // inline bool initialized(ArithVar x) const {
- // return d_vars[x].initialized();
- // }
-
- void addToBoundQueue(ArithVar v, BoundCounts prev){
- if(d_enqueueingBoundCounts && !d_atBoundsQueue.isKey(v)){
- d_atBoundsQueue.set(v, prev);
- }
- }
-
- BoundCounts oldBoundCounts(ArithVar v) const {
- if(d_atBoundsQueue.isKey(v)){
- return d_atBoundsQueue[v];
- }else{
- return boundCounts(v);
- }
- }
+ void startQueueingBoundCounts(){ d_enqueueingBoundCounts = true; }
+ void stopQueueingBoundCounts(){ d_enqueueingBoundCounts = false; }
+ void addToBoundQueue(ArithVar v, const BoundsInfo& prev);
- void startQueueingAtBoundQueue(){ d_enqueueingBoundCounts = true; }
- void stopQueueingAtBoundQueue(){ d_enqueueingBoundCounts = false; }
+ BoundsInfo selectBoundsInfo(ArithVar v, bool old) const;
- void processAtBoundQueue(BoundCountsCallback& changed){
- while(!d_atBoundsQueue.empty()){
- ArithVar v = d_atBoundsQueue.back();
- BoundCounts prev = d_atBoundsQueue[v];
- d_atBoundsQueue.pop_back();
- BoundCounts curr = boundCounts(v);
- if(prev != curr){
- changed(v, prev);
- }
- }
- }
+ bool boundsQueueEmpty() const;
+ void processBoundsQueue(BoundUpdateCallback& changed);
void printEntireModel(std::ostream& out) const;
diff --git a/src/theory/arith/pure_update_simplex.cpp b/src/theory/arith/pure_update_simplex.cpp
deleted file mode 100644
index 9b3edfa6f..000000000
--- a/src/theory/arith/pure_update_simplex.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/********************* */
-/*! \file simplex.cpp
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 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 "theory/arith/pure_update_simplex.h"
-#include "theory/arith/options.h"
-#include "theory/arith/constraint.h"
-
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-
-PureUpdateSimplexDecisionProcedure::PureUpdateSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc)
- : SimplexDecisionProcedure(linEq, errors, conflictChannel, tvmalloc)
-{ }
-
-Result::Sat PureUpdateSimplexDecisionProcedure::findModel(bool exactResult){
- Assert(d_conflictVariables.empty());
-
- static CVC4_THREADLOCAL(unsigned int) instance = 0;
- instance = instance + 1;
-
- if(d_errorSet.errorEmpty() && !d_errorSet.moreSignals()){
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "trivial" << endl;
- return Result::SAT;
- }
-
- // We need to reduce this because of
- d_errorSet.reduceToSignals();
- d_errorSet.setSelectionRule(VAR_ORDER);
-
- if(processSignals()){
- d_conflictVariables.purge();
-
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "early conflict" << endl;
- return Result::UNSAT;
- }else if(d_errorSet.errorEmpty()){
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "fixed itself" << endl;
- Assert(!d_errorSet.moreSignals());
- return Result::SAT;
- }
-
- Debug("arith::findModel") << "puFindModel(" << instance <<") "
- << "start non-trivial" << endl;
-
- static const bool verbose = false;
- Result::Sat result = Result::SAT_UNKNOWN;
-
- if(result == Result::SAT_UNKNOWN){
- if(attemptPureUpdates()){
- result = Result::UNSAT;
- }
- if(result == Result::UNSAT){
- ++(d_statistics.d_pureUpdateFoundUnsat);
- if(verbose){ Message() << "pure updates found unsat" << endl; }
- }else if(d_errorSet.errorEmpty()){
- ++(d_statistics.d_pureUpdateFoundSat);
- if(verbose){ Message() << "pure updates found model" << endl; }
- }else{
- ++(d_statistics.d_pureUpdateMissed);
- if(verbose){ Message() << "pure updates missed" << endl; }
- }
- }
-
- Assert(!d_errorSet.moreSignals());
- if(result == Result::SAT_UNKNOWN && d_errorSet.errorEmpty()){
- result = Result::SAT;
- }
-
- // ensure that the conflict variable is still in the queue.
- d_conflictVariables.purge();
-
- Assert(d_focusErrorVar == ARITHVAR_SENTINEL);
- Debug("arith::findModel") << "end findModel() " << instance << " "
- << result << endl;
-
- return result;
-}
-
-
-
-PureUpdateSimplexDecisionProcedure::Statistics::Statistics():
- d_pureUpdateFoundUnsat("theory::arith::PureUpdate::FoundUnsat", 0),
- d_pureUpdateFoundSat("theory::arith::PureUpdate::FoundSat", 0),
- d_pureUpdateMissed("theory::arith::PureUpdate::Missed", 0),
- d_pureUpdates("theory::arith::PureUpdate::updates", 0),
- d_pureUpdateDropped("theory::arith::PureUpdate::dropped", 0),
- d_pureUpdateConflicts("theory::arith::PureUpdate::conflicts", 0),
- d_foundConflicts("theory::arith::PureUpdate::foundConflicts", 0),
- d_attemptPureUpdatesTimer("theory::arith::PureUpdate::timer"),
- d_processSignalsTime("theory::arith::PureUpdate::process::timer"),
- d_constructionTimer("theory::arith::PureUpdate::construction::timer")
-{
- StatisticsRegistry::registerStat(&d_pureUpdateFoundUnsat);
- StatisticsRegistry::registerStat(&d_pureUpdateFoundSat);
- StatisticsRegistry::registerStat(&d_pureUpdateMissed);
- StatisticsRegistry::registerStat(&d_pureUpdates);
- StatisticsRegistry::registerStat(&d_pureUpdateDropped);
- StatisticsRegistry::registerStat(&d_pureUpdateConflicts);
-
- StatisticsRegistry::registerStat(&d_foundConflicts);
-
- StatisticsRegistry::registerStat(&d_attemptPureUpdatesTimer);
- StatisticsRegistry::registerStat(&d_processSignalsTime);
- StatisticsRegistry::registerStat(&d_constructionTimer);
-}
-
-PureUpdateSimplexDecisionProcedure::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_pureUpdateFoundUnsat);
- StatisticsRegistry::unregisterStat(&d_pureUpdateFoundSat);
- StatisticsRegistry::unregisterStat(&d_pureUpdateMissed);
- StatisticsRegistry::unregisterStat(&d_pureUpdates);
- StatisticsRegistry::unregisterStat(&d_pureUpdateDropped);
- StatisticsRegistry::unregisterStat(&d_pureUpdateConflicts);
-
- StatisticsRegistry::unregisterStat(&d_foundConflicts);
-
- StatisticsRegistry::unregisterStat(&d_attemptPureUpdatesTimer);
- StatisticsRegistry::unregisterStat(&d_processSignalsTime);
- StatisticsRegistry::unregisterStat(&d_constructionTimer);
-}
-
-bool PureUpdateSimplexDecisionProcedure::attemptPureUpdates(){
- TimerStat::CodeTimer codeTimer(d_statistics.d_attemptPureUpdatesTimer);
-
- Assert(!d_errorSet.focusEmpty());
- Assert(d_errorSet.noSignals());
-
- d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_constructionTimer);
-
- UpdateInfo proposal;
- int boundImprovements = 0;
- int dropped = 0;
- int computations = 0;
-
- for( Tableau::RowIterator ri = d_tableau.basicRowIterator(d_focusErrorVar); !ri.atEnd(); ++ri){
- const Tableau::Entry& e = *ri;
-
- ArithVar curr = e.getColVar();
- if(curr == d_focusErrorVar){ continue; }
-
- int dir = e.getCoefficient().sgn();
- Assert(dir != 0);
-
- bool worthwhile = false;
-
- if( (dir > 0 && d_variables.cmpAssignmentUpperBound(curr) < 0) ||
- (dir < 0 && d_variables.cmpAssignmentLowerBound(curr) > 0) ){
-
- ++computations;
- proposal = UpdateInfo(curr, dir);
- d_linEq.computeSafeUpdate(proposal, &LinearEqualityModule::noPreference);
-
- Assert(proposal.errorsChange() <= 0);
- Assert(proposal.focusDirection() >= 0);
-
- worthwhile = proposal.errorsChange() < 0 ||
- (proposal.focusDirection() > 0 &&
- d_variables.boundCounts(curr).isZero() &&
- !proposal.describesPivot());
-
- Debug("pu::refined")
- << "pure update proposal "
- << curr << " "
- << worthwhile << " "
- << proposal
- << endl;
- }
- if(worthwhile){
- Debug("pu") << d_variables.getAssignment(d_focusErrorVar) << endl;
-
- BoundCounts before = d_variables.boundCounts(curr);
- DeltaRational newAssignment =
- d_variables.getAssignment(curr) + proposal.nonbasicDelta();
- d_linEq.updateTracked(curr, newAssignment);
- BoundCounts after = d_variables.boundCounts(curr);
-
- ++d_statistics.d_pureUpdates;
- ++boundImprovements;
- Debug("pu") << boundImprovements << ": " << curr
- << " before: " << before
- << " after: " << after
- << e.getCoefficient()
- << d_variables.getAssignment(d_focusErrorVar) << endl;
-
- uint32_t prevSize = d_errorSet.errorSize();
- Assert(d_errorSet.moreSignals());
- if(Debug.isOn("pu")){ d_errorSet.debugPrint(Debug("pu")); }
- while(d_errorSet.moreSignals()){
- ArithVar updated = d_errorSet.topSignal();
- bool wasInError = d_errorSet.inError(updated);
- d_errorSet.popSignal();
- if(updated == curr){ continue; }
- Assert(d_tableau.isBasic(updated));
- if(!d_linEq.basicIsTracked(updated)){continue;}
-
-
- Assert(d_linEq.basicIsTracked(updated));
- Assert(wasInError || d_variables.assignmentIsConsistent(updated));
-
- if(!d_variables.assignmentIsConsistent(updated)
- && checkBasicForConflict(updated)){
- Assert(!d_conflictVariables.isMember(updated) );
- Debug("pu")
- << "It worked? "
- << d_statistics.d_pureUpdateConflicts.getData()
- << " " << curr
- << " " << checkBasicForConflict(updated) << endl;
- reportConflict(updated);
- ++(d_statistics.d_foundConflicts);
- ++(d_statistics.d_pureUpdateConflicts);
- }
- }
- if(d_conflictVariables.empty()){
- if(Debug.isOn("pu")){ d_errorSet.debugPrint(Debug("pu")); }
- uint32_t currSize = d_errorSet.errorSize();
- Assert(currSize <= prevSize);
- if(currSize < prevSize){
- dropped+= prevSize - currSize;
- if(currSize == 0){
- break;
- }
- }
- }else{
- break;
- }
- }
- }
-
- tearDownInfeasiblityFunction(d_statistics.d_constructionTimer, d_focusErrorVar);
- d_focusErrorVar = ARITHVAR_SENTINEL;
-
- (d_statistics.d_pureUpdateDropped) += dropped;
-
- Assert(d_errorSet.noSignals());
- return !d_conflictVariables.empty();
-}
-
-
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/arith/simplex-converge.cpp b/src/theory/arith/simplex-converge.cpp
deleted file mode 100644
index decce3882..000000000
--- a/src/theory/arith/simplex-converge.cpp
+++ /dev/null
@@ -1,1674 +0,0 @@
-/********************* */
-/*! \file simplex.cpp
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-
-#include "theory/arith/simplex.h"
-#include "theory/arith/options.h"
-
-using namespace std;
-
-using namespace CVC4;
-using namespace CVC4::kind;
-
-using namespace CVC4::theory;
-using namespace CVC4::theory::arith;
-
-static const bool CHECK_AFTER_PIVOT = true;
-
-SimplexDecisionProcedure::SimplexDecisionProcedure(LinearEqualityModule& linEq, NodeCallBack& conflictChannel, ArithVarMalloc& malloc, ConstraintDatabase& cd) :
- d_conflictVariable(ARITHVAR_SENTINEL),
- d_linEq(linEq),
- d_partialModel(d_linEq.getPartialModel()),
- d_tableau(d_linEq.getTableau()),
- d_queue(d_partialModel, d_tableau),
- d_numVariables(0),
- d_conflictChannel(conflictChannel),
- d_pivotsInRound(),
- d_DELTA_ZERO(0,0),
- d_arithVarMalloc(malloc),
- d_constraintDatabase(cd),
- d_optRow(ARITHVAR_SENTINEL),
- d_negOptConstant(d_DELTA_ZERO)
-{
- switch(ArithHeuristicPivotRule rule = options::arithHeuristicPivotRule()) {
- case MINIMUM:
- d_queue.setPivotRule(ArithPriorityQueue::MINIMUM);
- break;
- case BREAK_TIES:
- d_queue.setPivotRule(ArithPriorityQueue::BREAK_TIES);
- break;
- case MAXIMUM:
- d_queue.setPivotRule(ArithPriorityQueue::MAXIMUM);
- break;
- default:
- Unhandled(rule);
- }
-
- srand(62047);
-}
-
-SimplexDecisionProcedure::Statistics::Statistics():
- d_statUpdateConflicts("theory::arith::UpdateConflicts", 0),
- d_findConflictOnTheQueueTime("theory::arith::findConflictOnTheQueueTime"),
- d_attemptBeforeDiffSearch("theory::arith::qi::BeforeDiffSearch::attempt",0),
- d_successBeforeDiffSearch("theory::arith::qi::BeforeDiffSearch::success",0),
- d_attemptAfterDiffSearch("theory::arith::qi::AfterDiffSearch::attempt",0),
- d_successAfterDiffSearch("theory::arith::qi::AfterDiffSearch::success",0),
- d_attemptDuringDiffSearch("theory::arith::qi::DuringDiffSearch::attempt",0),
- d_successDuringDiffSearch("theory::arith::qi::DuringDiffSearch::success",0),
- d_attemptDuringVarOrderSearch("theory::arith::qi::DuringVarOrderSearch::attempt",0),
- d_successDuringVarOrderSearch("theory::arith::qi::DuringVarOrderSearch::success",0),
- d_attemptAfterVarOrderSearch("theory::arith::qi::AfterVarOrderSearch::attempt",0),
- d_successAfterVarOrderSearch("theory::arith::qi::AfterVarOrderSearch::success",0),
- d_weakeningAttempts("theory::arith::weakening::attempts",0),
- d_weakeningSuccesses("theory::arith::weakening::success",0),
- d_weakenings("theory::arith::weakening::total",0),
- d_weakenTime("theory::arith::weakening::time"),
- d_simplexConflicts("theory::arith::simplexConflicts",0),
- // primal
- d_primalTimer("theory::arith::primal::overall::timer"),
- d_internalTimer("theory::arith::primal::internal::timer"),
- d_primalCalls("theory::arith::primal::calls",0),
- d_primalSatCalls("theory::arith::primal::calls::sat",0),
- d_primalUnsatCalls("theory::arith::primal::calls::unsat",0),
- d_primalPivots("theory::arith::primal::pivots",0),
- d_primalImprovingPivots("theory::arith::primal::pivots::improving",0),
- d_primalThresholdReachedPivot("theory::arith::primal::thresholds",0),
- d_primalThresholdReachedPivot_dropped("theory::arith::primal::thresholds::dropped",0),
- d_primalReachedMaxPivots("theory::arith::primal::maxpivots",0),
- d_primalReachedMaxPivots_contractMadeProgress("theory::arith::primal::maxpivots::contract",0),
- d_primalReachedMaxPivots_checkForConflictWorked("theory::arith::primal::maxpivots::checkworked",0),
- d_primalGlobalMinimum("theory::arith::primal::minimum",0),
- d_primalGlobalMinimum_rowConflictWorked("theory::arith::primal::minimum::checkworked",0),
- d_primalGlobalMinimum_firstHalfWasSat("theory::arith::primal::minimum::firsthalf::sat",0),
- d_primalGlobalMinimum_firstHalfWasUnsat("theory::arith::primal::minimum::firsthalf::unsat",0),
- d_primalGlobalMinimum_contractMadeProgress("theory::arith::primal::minimum::progress",0),
- d_unboundedFound("theory::arith::primal::unbounded",0),
- d_unboundedFound_drive("theory::arith::primal::unbounded::drive",0),
- d_unboundedFound_dropped("theory::arith::primal::unbounded::dropped",0)
-{
- StatisticsRegistry::registerStat(&d_statUpdateConflicts);
-
- StatisticsRegistry::registerStat(&d_findConflictOnTheQueueTime);
-
- StatisticsRegistry::registerStat(&d_attemptBeforeDiffSearch);
- StatisticsRegistry::registerStat(&d_successBeforeDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptAfterDiffSearch);
- StatisticsRegistry::registerStat(&d_successAfterDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptDuringDiffSearch);
- StatisticsRegistry::registerStat(&d_successDuringDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptDuringVarOrderSearch);
- StatisticsRegistry::registerStat(&d_successDuringVarOrderSearch);
- StatisticsRegistry::registerStat(&d_attemptAfterVarOrderSearch);
- StatisticsRegistry::registerStat(&d_successAfterVarOrderSearch);
-
- StatisticsRegistry::registerStat(&d_weakeningAttempts);
- StatisticsRegistry::registerStat(&d_weakeningSuccesses);
- StatisticsRegistry::registerStat(&d_weakenings);
- StatisticsRegistry::registerStat(&d_weakenTime);
-
- StatisticsRegistry::registerStat(&d_simplexConflicts);
-
- //primal
- StatisticsRegistry::registerStat(&d_primalTimer);
- StatisticsRegistry::registerStat(&d_internalTimer);
-
- StatisticsRegistry::registerStat(&d_primalCalls);
- StatisticsRegistry::registerStat(&d_primalSatCalls);
- StatisticsRegistry::registerStat(&d_primalUnsatCalls);
-
- StatisticsRegistry::registerStat(&d_primalPivots);
- StatisticsRegistry::registerStat(&d_primalImprovingPivots);
-
- StatisticsRegistry::registerStat(&d_primalThresholdReachedPivot);
- StatisticsRegistry::registerStat(&d_primalThresholdReachedPivot_dropped);
-
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots);
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots_contractMadeProgress);
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots_checkForConflictWorked);
-
-
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_rowConflictWorked);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_firstHalfWasSat);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_firstHalfWasUnsat);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_contractMadeProgress);
-
-
- StatisticsRegistry::registerStat(&d_unboundedFound);
- StatisticsRegistry::registerStat(&d_unboundedFound_drive);
- StatisticsRegistry::registerStat(&d_unboundedFound_dropped);
-
-}
-
-SimplexDecisionProcedure::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_statUpdateConflicts);
-
- StatisticsRegistry::unregisterStat(&d_findConflictOnTheQueueTime);
-
- StatisticsRegistry::unregisterStat(&d_attemptBeforeDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successBeforeDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptAfterDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successAfterDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptDuringDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successDuringDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptDuringVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_successDuringVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_attemptAfterVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_successAfterVarOrderSearch);
-
- StatisticsRegistry::unregisterStat(&d_weakeningAttempts);
- StatisticsRegistry::unregisterStat(&d_weakeningSuccesses);
- StatisticsRegistry::unregisterStat(&d_weakenings);
- StatisticsRegistry::unregisterStat(&d_weakenTime);
-
- StatisticsRegistry::unregisterStat(&d_simplexConflicts);
-
- //primal
- StatisticsRegistry::unregisterStat(&d_primalTimer);
- StatisticsRegistry::unregisterStat(&d_internalTimer);
-
- StatisticsRegistry::unregisterStat(&d_primalCalls);
- StatisticsRegistry::unregisterStat(&d_primalSatCalls);
- StatisticsRegistry::unregisterStat(&d_primalUnsatCalls);
-
- StatisticsRegistry::unregisterStat(&d_primalPivots);
- StatisticsRegistry::unregisterStat(&d_primalImprovingPivots);
-
- StatisticsRegistry::unregisterStat(&d_primalThresholdReachedPivot);
- StatisticsRegistry::unregisterStat(&d_primalThresholdReachedPivot_dropped);
-
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots);
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots_contractMadeProgress);
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots_checkForConflictWorked);
-
-
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_rowConflictWorked);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_firstHalfWasSat);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_firstHalfWasUnsat);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_contractMadeProgress);
-
- StatisticsRegistry::unregisterStat(&d_unboundedFound);
- StatisticsRegistry::unregisterStat(&d_unboundedFound_drive);
- StatisticsRegistry::unregisterStat(&d_unboundedFound_dropped);
-}
-
-
-
-
-ArithVar SimplexDecisionProcedure::minVarOrder(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- // Assert(!simp.d_tableau.isBasic(x));
- // Assert(!simp.d_tableau.isBasic(y));
- if(x <= y){
- return x;
- } else {
- return y;
- }
-}
-
-ArithVar SimplexDecisionProcedure::minColLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(!simp.d_tableau.isBasic(x));
- Assert(!simp.d_tableau.isBasic(y));
- uint32_t xLen = simp.d_tableau.getColLength(x);
- uint32_t yLen = simp.d_tableau.getColLength(y);
- if( xLen > yLen){
- return y;
- } else if( xLen== yLen ){
- return minVarOrder(simp,x,y);
- }else{
- return x;
- }
-}
-
-ArithVar SimplexDecisionProcedure::minRowLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(simp.d_tableau.isBasic(x));
- Assert(simp.d_tableau.isBasic(y));
- uint32_t xLen = simp.d_tableau.getRowLength(simp.d_tableau.basicToRowIndex(x));
- uint32_t yLen = simp.d_tableau.getRowLength(simp.d_tableau.basicToRowIndex(y));
- if( xLen > yLen){
- return y;
- } else if( xLen == yLen ){
- return minVarOrder(simp,x,y);
- }else{
- return x;
- }
-}
-ArithVar SimplexDecisionProcedure::minBoundAndRowCount(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(!simp.d_tableau.isBasic(x));
- Assert(!simp.d_tableau.isBasic(y));
- if(simp.d_partialModel.hasEitherBound(x) && !simp.d_partialModel.hasEitherBound(y)){
- return y;
- }else if(!simp.d_partialModel.hasEitherBound(x) && simp.d_partialModel.hasEitherBound(y)){
- return x;
- }else {
- return minColLength(simp, x, y);
- }
-}
-
-template <bool above>
-ArithVar SimplexDecisionProcedure::selectSlack(ArithVar x_i, SimplexDecisionProcedure::PreferenceFunction pref){
- ArithVar slack = ARITHVAR_SENTINEL;
-
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
- const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
- const Rational& a_ij = entry.getCoefficient();
- int sgn = a_ij.sgn();
- if(isAcceptableSlack<above>(sgn, nonbasic)){
- //If one of the above conditions is met, we have found an acceptable
- //nonbasic variable to pivot x_i with. We can now choose which one we
- //prefer the most.
- slack = (slack == ARITHVAR_SENTINEL) ? nonbasic : pref(*this, slack, nonbasic);
- }
- }
-
- return slack;
-}
-
-Node betterConflict(TNode x, TNode y){
- if(x.isNull()) return y;
- else if(y.isNull()) return x;
- else if(x.getNumChildren() <= y.getNumChildren()) return x;
- else return y;
-}
-
-bool SimplexDecisionProcedure::findConflictOnTheQueue(SearchPeriod type) {
- TimerStat::CodeTimer codeTimer(d_statistics.d_findConflictOnTheQueueTime);
- Assert(d_successes.empty());
-
- switch(type){
- case BeforeDiffSearch: ++(d_statistics.d_attemptBeforeDiffSearch); break;
- case DuringDiffSearch: ++(d_statistics.d_attemptDuringDiffSearch); break;
- case AfterDiffSearch: ++(d_statistics.d_attemptAfterDiffSearch); break;
- case DuringVarOrderSearch: ++(d_statistics.d_attemptDuringVarOrderSearch); break;
- case AfterVarOrderSearch: ++(d_statistics.d_attemptAfterVarOrderSearch); break;
- }
-
- ArithPriorityQueue::const_iterator i = d_queue.begin();
- ArithPriorityQueue::const_iterator end = d_queue.end();
- for(; i != end; ++i){
- ArithVar x_i = *i;
-
- if(x_i != d_conflictVariable && d_tableau.isBasic(x_i) && !d_successes.isMember(x_i)){
- Node possibleConflict = checkBasicForConflict(x_i);
- if(!possibleConflict.isNull()){
- d_successes.add(x_i);
- reportConflict(possibleConflict);
- }
- }
- }
- if(!d_successes.empty()){
- switch(type){
- case BeforeDiffSearch: ++(d_statistics.d_successBeforeDiffSearch); break;
- case DuringDiffSearch: ++(d_statistics.d_successDuringDiffSearch); break;
- case AfterDiffSearch: ++(d_statistics.d_successAfterDiffSearch); break;
- case DuringVarOrderSearch: ++(d_statistics.d_successDuringVarOrderSearch); break;
- case AfterVarOrderSearch: ++(d_statistics.d_successAfterVarOrderSearch); break;
- }
- d_successes.purge();
- return true;
- }else{
- return false;
- }
-}
-
-Result::Sat SimplexDecisionProcedure::dualFindModel(bool exactResult){
- Assert(d_conflictVariable == ARITHVAR_SENTINEL);
- Assert(d_queue.inCollectionMode());
-
- if(d_queue.empty()){
- return Result::SAT;
- }
- static CVC4_THREADLOCAL(unsigned int) instance = 0;
- instance = instance + 1;
- Debug("arith::findModel") << "begin findModel()" << instance << endl;
-
- d_queue.transitionToDifferenceMode();
-
- Result::Sat result = Result::SAT_UNKNOWN;
-
- if(d_queue.empty()){
- result = Result::SAT;
- }else if(d_queue.size() > 1){
- if(findConflictOnTheQueue(BeforeDiffSearch)){
- result = Result::UNSAT;
- }
- }
- static const bool verbose = false;
- exactResult |= options::arithStandardCheckVarOrderPivots() < 0;
- const uint32_t inexactResultsVarOrderPivots = exactResult ? 0 : options::arithStandardCheckVarOrderPivots();
-
- uint32_t checkPeriod = options::arithSimplexCheckPeriod();
- if(result == Result::SAT_UNKNOWN){
- uint32_t numDifferencePivots = options::arithHeuristicPivots() < 0 ?
- d_numVariables + 1 : options::arithHeuristicPivots();
- // The signed to unsigned conversion is safe.
- uint32_t pivotsRemaining = numDifferencePivots;
- while(!d_queue.empty() &&
- result != Result::UNSAT &&
- pivotsRemaining > 0){
- uint32_t pivotsToDo = min(checkPeriod, pivotsRemaining);
- pivotsRemaining -= pivotsToDo;
- if(searchForFeasibleSolution(pivotsToDo)){
- result = Result::UNSAT;
- }//Once every CHECK_PERIOD examine the entire queue for conflicts
- if(result != Result::UNSAT){
- if(findConflictOnTheQueue(DuringDiffSearch)) { result = Result::UNSAT; }
- }else{
- findConflictOnTheQueue(AfterDiffSearch); // already unsat
- }
- }
-
- if(verbose && numDifferencePivots > 0){
- if(result == Result::UNSAT){
- Message() << "diff order found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "diff order found model" << endl;
- }else{
- Message() << "diff order missed" << endl;
- }
- }
- }
-
- if(!d_queue.empty() && result != Result::UNSAT){
- if(exactResult){
- d_queue.transitionToVariableOrderMode();
-
- while(!d_queue.empty() && result != Result::UNSAT){
- if(searchForFeasibleSolution(checkPeriod)){
- result = Result::UNSAT;
- }
-
- //Once every CHECK_PERIOD examine the entire queue for conflicts
- if(result != Result::UNSAT){
- if(findConflictOnTheQueue(DuringVarOrderSearch)){
- result = Result::UNSAT;
- }
- } else{
- findConflictOnTheQueue(AfterVarOrderSearch);
- }
- }
- if(verbose){
- if(result == Result::UNSAT){
- Message() << "bland found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "bland found model" << endl;
- }else{
- Message() << "bland order missed" << endl;
- }
- }
- }else{
- d_queue.transitionToVariableOrderMode();
-
- if(searchForFeasibleSolution(inexactResultsVarOrderPivots)){
- result = Result::UNSAT;
- findConflictOnTheQueue(AfterVarOrderSearch); // already unsat
- }else{
- if(findConflictOnTheQueue(AfterVarOrderSearch)) { result = Result::UNSAT; }
- }
-
- if(verbose){
- if(result == Result::UNSAT){
- Message() << "restricted var order found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "restricted var order found model" << endl;
- }else{
- Message() << "restricted var order missed" << endl;
- }
- }
- }
- }
-
- if(result == Result::SAT_UNKNOWN && d_queue.empty()){
- result = Result::SAT;
- }
-
-
-
- d_pivotsInRound.purge();
- // ensure that the conflict variable is still in the queue.
- if(d_conflictVariable != ARITHVAR_SENTINEL){
- d_queue.enqueueIfInconsistent(d_conflictVariable);
- }
- d_conflictVariable = ARITHVAR_SENTINEL;
-
- d_queue.transitionToCollectionMode();
- Assert(d_queue.inCollectionMode());
- Debug("arith::findModel") << "end findModel() " << instance << " " << result << endl;
- return result;
-
-
- // Assert(foundConflict || d_queue.empty());
-
- // // Curiously the invariant that we always do a full check
- // // means that the assignment we can always empty these queues.
- // d_queue.clear();
- // d_pivotsInRound.purge();
- // d_conflictVariable = ARITHVAR_SENTINEL;
-
- // Assert(!d_queue.inCollectionMode());
- // d_queue.transitionToCollectionMode();
-
-
- // Assert(d_queue.inCollectionMode());
-
- // Debug("arith::findModel") << "end findModel() " << instance << endl;
-
- // return foundConflict;
-}
-
-
-
-Node SimplexDecisionProcedure::checkBasicForConflict(ArithVar basic){
-
- Assert(d_tableau.isBasic(basic));
- const DeltaRational& beta = d_partialModel.getAssignment(basic);
-
- if(d_partialModel.strictlyLessThanLowerBound(basic, beta)){
- ArithVar x_j = selectSlackUpperBound(basic);
- if(x_j == ARITHVAR_SENTINEL ){
- return generateConflictBelowLowerBound(basic);
- }
- }else if(d_partialModel.strictlyGreaterThanUpperBound(basic, beta)){
- ArithVar x_j = selectSlackLowerBound(basic);
- if(x_j == ARITHVAR_SENTINEL ){
- return generateConflictAboveUpperBound(basic);
- }
- }
- return Node::null();
-}
-
-//corresponds to Check() in dM06
-//template <SimplexDecisionProcedure::PreferenceFunction pf>
-bool SimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingIterations){
- Debug("arith") << "searchForFeasibleSolution" << endl;
- Assert(remainingIterations > 0);
-
- while(remainingIterations > 0){
- if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
-
- ArithVar x_i = d_queue.dequeueInconsistentBasicVariable();
- Debug("arith::update::select") << "selectSmallestInconsistentVar()=" << x_i << endl;
- if(x_i == ARITHVAR_SENTINEL){
- Debug("arith_update") << "No inconsistent variables" << endl;
- return false; //sat
- }
-
- --remainingIterations;
-
- bool useVarOrderPivot = d_pivotsInRound.count(x_i) >= options::arithPivotThreshold();
- if(!useVarOrderPivot){
- d_pivotsInRound.add(x_i);
- }
-
-
- Debug("playground") << "pivots in rounds: " << d_pivotsInRound.count(x_i)
- << " use " << useVarOrderPivot
- << " threshold " << options::arithPivotThreshold()
- << endl;
-
- PreferenceFunction pf = useVarOrderPivot ? minVarOrder : minBoundAndRowCount;
-
- DeltaRational beta_i = d_partialModel.getAssignment(x_i);
- ArithVar x_j = ARITHVAR_SENTINEL;
-
- if(d_partialModel.strictlyLessThanLowerBound(x_i, beta_i)){
- x_j = selectSlackUpperBound(x_i, pf);
- if(x_j == ARITHVAR_SENTINEL ){
- ++(d_statistics.d_statUpdateConflicts);
- Node conflict = generateConflictBelowLowerBound(x_i); //unsat
- d_conflictVariable = x_i;
- reportConflict(conflict);
- return true;
- }
- DeltaRational l_i = d_partialModel.getLowerBound(x_i);
- d_linEq.pivotAndUpdate(x_i, x_j, l_i);
-
- }else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, beta_i)){
- x_j = selectSlackLowerBound(x_i, pf);
- if(x_j == ARITHVAR_SENTINEL ){
- ++(d_statistics.d_statUpdateConflicts);
- Node conflict = generateConflictAboveUpperBound(x_i); //unsat
-
- d_conflictVariable = x_i;
- reportConflict(conflict);
- return true;
- }
- DeltaRational u_i = d_partialModel.getUpperBound(x_i);
- d_linEq.pivotAndUpdate(x_i, x_j, u_i);
- }
- Assert(x_j != ARITHVAR_SENTINEL);
-
- //Check to see if we already have a conflict with x_j to prevent wasteful work
- if(CHECK_AFTER_PIVOT){
- Node possibleConflict = checkBasicForConflict(x_j);
- if(!possibleConflict.isNull()){
- d_conflictVariable = x_j;
- reportConflict(possibleConflict);
- return true; // unsat
- }
- }
- }
- Assert(remainingIterations == 0);
-
- return false;
-}
-
-
-
-Constraint SimplexDecisionProcedure::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic){
-
- int sgn = coeff.sgn();
- bool ub = aboveUpper?(sgn < 0) : (sgn > 0);
-
- Constraint c = ub ?
- d_partialModel.getUpperBoundConstraint(v) :
- d_partialModel.getLowerBoundConstraint(v);
-
-// #warning "revisit"
-// Node exp = ub ?
-// d_partialModel.explainUpperBound(v) :
-// d_partialModel.explainLowerBound(v);
-
- bool weakened;
- do{
- const DeltaRational& bound = c->getValue();
-
- weakened = false;
-
- Constraint weaker = ub?
- c->getStrictlyWeakerUpperBound(true, true):
- c->getStrictlyWeakerLowerBound(true, true);
-
- // Node weaker = ub?
- // d_propManager.strictlyWeakerAssertedUpperBound(v, bound):
- // d_propManager.strictlyWeakerAssertedLowerBound(v, bound);
-
- if(weaker != NullConstraint){
- //if(!weaker.isNull()){
- const DeltaRational& weakerBound = weaker->getValue();
- //DeltaRational weakerBound = asDeltaRational(weaker);
-
- DeltaRational diff = aboveUpper ? bound - weakerBound : weakerBound - bound;
- //if var == basic,
- // if aboveUpper, weakerBound > bound, multiply by -1
- // if !aboveUpper, weakerBound < bound, multiply by -1
- diff = diff * coeff;
- if(surplus > diff){
- ++d_statistics.d_weakenings;
- weakened = true;
- anyWeakening = true;
- surplus = surplus - diff;
-
- Debug("weak") << "found:" << endl;
- if(v == basic){
- Debug("weak") << " basic: ";
- }
- Debug("weak") << " " << surplus << " "<< diff << endl
- << " " << bound << c << endl
- << " " << weakerBound << weaker << endl;
-
- Assert(diff > d_DELTA_ZERO);
- c = weaker;
- }
- }
- }while(weakened);
-
- return c;
-}
-
-Node SimplexDecisionProcedure::weakenConflict(bool aboveUpper, ArithVar basicVar){
- TimerStat::CodeTimer codeTimer(d_statistics.d_weakenTime);
-
- const DeltaRational& assignment = d_partialModel.getAssignment(basicVar);
- DeltaRational surplus;
- if(aboveUpper){
- Assert(d_partialModel.hasUpperBound(basicVar));
- Assert(assignment > d_partialModel.getUpperBound(basicVar));
- surplus = assignment - d_partialModel.getUpperBound(basicVar);
- }else{
- Assert(d_partialModel.hasLowerBound(basicVar));
- Assert(assignment < d_partialModel.getLowerBound(basicVar));
- surplus = d_partialModel.getLowerBound(basicVar) - assignment;
- }
-
- NodeBuilder<> conflict(kind::AND);
- bool anyWeakenings = false;
- for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){
- const Tableau::Entry& entry = *i;
- ArithVar v = entry.getColVar();
- const Rational& coeff = entry.getCoefficient();
- bool weakening = false;
- Constraint c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
- Debug("weak") << "weak : " << weakening << " "
- << c->assertedToTheTheory() << " "
- << d_partialModel.getAssignment(v) << " "
- << c << endl
- << c->explainForConflict() << endl;
- anyWeakenings = anyWeakenings || weakening;
-
- Debug("weak") << "weak : " << c->explainForConflict() << endl;
- c->explainForConflict(conflict);
- }
- ++d_statistics.d_weakeningAttempts;
- if(anyWeakenings){
- ++d_statistics.d_weakeningSuccesses;
- }
- return conflict;
-}
-
-
-Node SimplexDecisionProcedure::generateConflictAboveUpperBound(ArithVar conflictVar){
- return weakenConflict(true, conflictVar);
-}
-
-Node SimplexDecisionProcedure::generateConflictBelowLowerBound(ArithVar conflictVar){
- return weakenConflict(false, conflictVar);
-}
-
-
-// responses
-// unbounded below(arithvar)
-// reached threshold
-// reached maxpivots
-// reached GlobalMinimumd
-//
-SimplexDecisionProcedure::PrimalResponse SimplexDecisionProcedure::primal(uint32_t maxIterations)
-{
- Assert(d_optRow != ARITHVAR_SENTINEL);
-
- for(uint32_t iteration = 0; iteration < maxIterations; iteration++){
- if(belowThreshold()){
- return ReachedThresholdValue;
- }
-
- PrimalResponse res = primalCheck();
- switch(res){
- case GlobalMinimum:
- case FoundUnboundedVariable:
- return res;
- case NoProgressOnLeaving:
- ++d_statistics.d_primalPivots;
- ++d_pivotsSinceOptProgress;
- ++d_pivotsSinceLastCheck;
- ++d_pivotsSinceErrorProgress;
-
- d_linEq.pivotAndUpdate(d_primalCarry.d_entering, d_primalCarry.d_leaving, d_partialModel.getAssignment(d_primalCarry.d_entering));
-
- if(Debug.isOn("primal::tableau")){
- d_linEq.debugCheckTableau();
- }
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("MakeProgressOnLeaving")); }
-
- break;
- case MakeProgressOnLeaving:
- {
- ++d_statistics.d_primalPivots;
- ++d_statistics.d_primalImprovingPivots;
-
- d_pivotsSinceOptProgress = 0;
- ++d_pivotsSinceErrorProgress;
- ++d_pivotsSinceLastCheck;
-
- d_linEq.pivotAndUpdate(d_primalCarry.d_entering, d_primalCarry.d_leaving, d_primalCarry.d_nextEnteringValue);
-
- static int helpful = 0;
- static int hurtful = 0;
- static int penguin = 0;
- if(d_currentErrorVariables.isKey(d_primalCarry.d_entering)){
- cout << "entering is error " << d_primalCarry.d_entering;
- if(d_currentErrorVariables[d_primalCarry.d_entering].errorIsLeqZero(d_partialModel)){
- cout << " now below threshold (" << (++helpful) << ") " << d_pivotsSinceErrorProgress << endl;
- }else{
- cout << "ouch (" << (++hurtful) << ")"<< d_pivotsSinceErrorProgress << endl;
- }
- }else if(d_currentErrorVariables.isKey(d_primalCarry.d_leaving)){
- cout << "leaving is error " << d_primalCarry.d_leaving;
- if(d_currentErrorVariables[d_primalCarry.d_leaving].errorIsLeqZero(d_partialModel)){
- cout << " now below threshold(" << (++helpful) << ")" << d_pivotsSinceErrorProgress << endl;
- }else{
- cout << "ouch (" << (++hurtful) << ")" << d_pivotsSinceErrorProgress<< endl;
- }
- }else{
- cout << " penguin (" << (++penguin) << ")" << d_pivotsSinceErrorProgress<< endl;
- }
-
- if(Debug.isOn("primal::tableau")){
- d_linEq.debugCheckTableau();
- }
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("MakeProgressOnLeaving")); }
- }
- break;
- default:
- Unreachable();
- }
- }
- return UsedMaxPivots;
-}
-
-
-/**
- * Error set
- * ErrorVariable |-> {ErrorVariable, InputVariable, InputConstraint}
- */
-
-/**
- * Returns SAT if it was able to satisfy all of the constraints in the error set
- * Returns UNSAT if it was able to able to find an error
- */
-Result::Sat SimplexDecisionProcedure::primalConverge(int depth){
- d_pivotsSinceLastCheck = 0;
-
- while(!d_currentErrorVariables.empty()){
- PrimalResponse res = primal(MAX_ITERATIONS - d_pivotsSinceLastCheck);
-
- switch(res){
- case FoundUnboundedVariable:
-
- // Drive the variable to at least 0
- // TODO This variable should be driven to a value that makes all of the error functions including it 0
- // It'll or another unbounded will be selected in the next round anyways so ignore for now.
- ++d_statistics.d_unboundedFound;
- if( !belowThreshold() ){
- driveOptToZero(d_primalCarry.d_unbounded);
- d_linEq.debugCheckTableau();
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("primalConverge")); }
-
- ++d_statistics.d_unboundedFound_drive;
- }
- Assert(belowThreshold());
- {
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> FoundUnboundedVariable -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- d_statistics.d_unboundedFound_dropped += dropped;
- }
- break;
- case ReachedThresholdValue:
- ++d_statistics.d_primalThresholdReachedPivot;
-
- Assert(belowThreshold());
- {
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> ReachedThresholdValue -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- d_statistics.d_primalThresholdReachedPivot_dropped += dropped;
- }
- break;
- case UsedMaxPivots:
- {
- d_pivotsSinceLastCheck = 0;
- ++d_statistics.d_primalReachedMaxPivots;
-
- // periodically attempt to do the following :
- // contract the error variable
- // check for a conflict on an error variable
- uint32_t dropped = contractErrorVariables(false);
-
- if( checkForRowConflicts() ){ // try to periodically look for a row
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> unsat " << endl;
-
- ++d_statistics.d_primalReachedMaxPivots_checkForConflictWorked;
- return Result::UNSAT; // row conflicts are minimal so stop.
- }
-
- if(dropped > 0){
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- ++d_statistics.d_primalReachedMaxPivots_contractMadeProgress;
- }else{
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> nothing " << endl;
- }
- }
- break;
- case GlobalMinimum:
- ++d_statistics.d_primalGlobalMinimum;
-
- // If the minimum is positive, this is unsat.
- // However, the optimization row is not necessarily a minimal conflict
- if(!belowThreshold()){
-
- if(d_currentErrorVariables.size() == 1){
- // The optimization function is exactly the same as the last remaining variable
- // The conflict for the row is the same as the conflict for the optimization function.
- bool foundConflict = checkForRowConflicts();
- Assert(foundConflict);
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> one variable" << endl;
-
- return Result::UNSAT;
- }else{
- // There are at least 2 error variables.
- // Look for a minimal conflict
-
-
- if(checkForRowConflicts() ){
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> postitive -> rowconflict " << endl;
-
- ++d_statistics.d_primalGlobalMinimum_rowConflictWorked;
- return Result::UNSAT;
- }
-
- uint32_t dropped = contractErrorVariables(false);
-
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> postitive -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- if(dropped > 0){
- ++d_statistics.d_primalGlobalMinimum_contractMadeProgress;
- }
-
- ErrorMap half;
- d_currentErrorVariables.splitInto(half);
-
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << endl;
-
-
- reconstructOptimizationFunction();
- Result::Sat resultOnRemaining = primalConverge(depth + 1);
-
- if(resultOnRemaining == Result::UNSAT){
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << " was unsat " << endl;
- ++d_statistics.d_primalGlobalMinimum_firstHalfWasUnsat;
- restoreErrorVariables(half);
- return Result::UNSAT;
- }else{
- ++d_statistics.d_primalGlobalMinimum_firstHalfWasSat;
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << " was sat " << endl;
-
- Assert(resultOnRemaining == Result::SAT);
- Assert(d_currentErrorVariables.empty());
- d_currentErrorVariables.addAll(half);
- reconstructOptimizationFunction();
- return primalConverge(depth + 1);
- }
- }
-
- }else{
-
- // if the optimum is <= 0
- // drop all of the satisfied variables and continue;
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> negative -> dropped "<< dropped << " to " << d_currentErrorVariables.size() << endl;
-
- ++d_statistics.d_primalGlobalMinimum_contractMadeProgress;
- }
- break;
- default:
- Unreachable();
- }
- }
-
- return Result::SAT;
-}
-
-
-Result::Sat SimplexDecisionProcedure::primalFindModel(){
- Assert(d_primalCarry.isClear());
-
- // Reduce the queue to only contain violations
- reduceQueue();
-
- if(d_queue.empty()){
- return Result::SAT;
- }
- TimerStat::CodeTimer codeTimer(d_statistics.d_primalTimer);
-
- ++d_statistics.d_primalCalls;
-
- Debug("primalFindModel") << "primalFindModel() begin" << endl;
-
- const int PAUSE_RATE = 100;
- if(Debug.isOn("primal::pause") && d_statistics.d_primalCalls.getData() % PAUSE_RATE == 0){
- Debug("primal::pause") << "waiting for input: ";
- std::string dummy;
- std::getline(std::cin, dummy);
- }
-
- // TODO restore the tableau by ejecting variables
- // Tableau copy(d_tableau);
-
- Result::Sat answer;
- {
- TimerStat::CodeTimer codeTimer(d_statistics.d_internalTimer);
-
- // This is needed because of the fiddling with the partial model
- //context::Context::ScopedPush speculativePush(satContext);
-
- constructErrorVariables();
- constructOptimizationFunction();
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("primalFindModel 1"); }
- answer = primalConverge(0);
- }
- removeOptimizationFunction();
-
-
- // exit
- uint32_t nc = d_tableau.getNumColumns();
- //d_tableau = copy;
- while(d_tableau.getNumColumns() < nc){
- d_tableau.increaseSize();
- }
- restoreErrorVariables(d_currentErrorVariables);
-
- reduceQueue();
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
-
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("primalFindModel2"); }
- Debug("primalFindModel") << "primalFindModel() end " << answer << endl;
-
- // The set of variables in conflict with their bounds will still be a subset of the
- // variables that are in conflict with their bounds in the beginning.
- // The basic variables are the same because of the copy.
- // Thus it is safe to not try to not recompute the queue of violating variables
-
- if(answer == Result::UNSAT){
- // This needs to be done in a different context level than the push
- ++d_statistics.d_primalUnsatCalls;
- }else{
- ++d_statistics.d_primalSatCalls;
- }
-
- d_primalCarry.clear();
-
- return answer;
-}
-
-/** Clears the ErrorMap and relase the resources associated with it.
- * There are a couple of error maps around
- */
-void SimplexDecisionProcedure::restoreErrorVariables(SimplexDecisionProcedure::ErrorMap& es){
- while(!es.empty()){
- ArithVar e = es.back();
-
- reassertErrorConstraint(e, es, false, false);
- es.pop_back();
- }
-}
-
-void SimplexDecisionProcedure::constructErrorVariables(){
- Assert(d_currentErrorVariables.empty());
- Assert(!d_queue.empty());
-
- for(ArithPriorityQueue::const_iterator iter = d_queue.begin(), end = d_queue.end(); iter != end; ++iter){
- ArithVar input = *iter;
-
- Assert(d_tableau.isBasic(input));
- Assert(!d_partialModel.assignmentIsConsistent(input));
-
- Assert(!d_currentErrorVariables.isKey(input));
-
- bool ub = d_partialModel.strictlyGreaterThanUpperBound(input, d_partialModel.getAssignment(input));
-
- Constraint original = ub ? d_partialModel.getUpperBoundConstraint(input)
- : d_partialModel.getLowerBoundConstraint(input);
-
- d_currentErrorVariables.set(input, ErrorInfo(input, ub, original));
-
- if(ub){
- d_partialModel.forceRelaxUpperBound(input);
- }else{
- d_partialModel.forceRelaxLowerBound(input);
- }
- Debug("primal") << "adding error variable (" << input << ", " << ", " << original <<") ";
- Debug("primal") << "ub "<< ub << " " << d_partialModel.getAssignment(input) << " " << original->getValue() <<")" << endl;
- d_currentErrorVariables.set(input, ErrorInfo(input, ub, original));
-
- // Constraint boundIsValue = d_constraintDatabase.getConstraint(bound, Equality, original->getValue());
- // boundIsValue->setPsuedoConstraint();
-
- // d_partialModel.setAssignment(bound, boundIsValue->getValue());
- // d_partialModel.setUpperBoundConstraint(boundIsValue);
- // d_partialModel.setLowerBoundConstraint(boundIsValue);
-
- // // if ub
- // // then error = x - boundIsValue
- // // else error = boundIsValue - x
-
- // ArithVar error = requestVariable();
-
- // DeltaRational diff = ub ?
- // d_partialModel.getAssignment(input) - boundIsValue->getValue() :
- // boundIsValue->getValue() - d_partialModel.getAssignment(input);
-
- // d_partialModel.setAssignment(error, diff);
-
- // vector<Rational> coeffs;
- // vector<ArithVar> variables;
- // variables.push_back(input);
- // coeffs.push_back(ub ? Rational(1) : Rational(-1));
- // variables.push_back(bound);
- // coeffs.push_back(ub ? Rational(-1) : Rational(1));
-
- // d_tableau.addRow(error, coeffs, variables);
-
-
- }
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("constructErrorVariables");}
- Assert(!d_currentErrorVariables.empty());
-}
-
-
-
-/** Returns true if it has found a row conflict for any of the error variables. */
-bool SimplexDecisionProcedure::checkForRowConflicts(){
- vector<ArithVar> inConflict;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar error = *iter;
- const ErrorInfo& info = d_currentErrorVariables[error];
- if(d_tableau.isBasic(error) && !info.errorIsLeqZero(d_partialModel)){
-
- ArithVar x_j = info.isUpperbound() ?
- selectSlackLowerBound(error) :
- selectSlackUpperBound(error);
-
- if(x_j == ARITHVAR_SENTINEL ){
- inConflict.push_back(error);
- }
- }
- }
-
- if(!inConflict.empty()){
- while(!inConflict.empty()){
- ArithVar error = inConflict.back();
- inConflict.pop_back();
-
- reassertErrorConstraint(error, d_currentErrorVariables, false, true);
-
- Node conflict = d_currentErrorVariables[error].isUpperbound() ?
- generateConflictAboveUpperBound(error) :
- generateConflictBelowLowerBound(error);
- Assert(!conflict.isNull());
-
- d_currentErrorVariables.remove(error);
-
- reportConflict(conflict);
- }
- reconstructOptimizationFunction();
- return true;
- }else{
- return false;
- }
-}
-
-void SimplexDecisionProcedure::reassertErrorConstraint(ArithVar e, SimplexDecisionProcedure::ErrorMap& es, bool definitelyTrue, bool definitelyFalse){
- Assert(es.isKey(e));
- const ErrorInfo& info = es.get(e);
- Constraint original = info.getConstraint();
-
- if(info.isUpperbound()){
- d_partialModel.setUpperBoundConstraint(original);
- }else if(original->isLowerBound()){
- d_partialModel.setLowerBoundConstraint(original);
- }
-
- Assert(!definitelyTrue || d_partialModel.assignmentIsConsistent(e));
- Assert(!definitelyFalse || !d_partialModel.assignmentIsConsistent(e));
-}
-
-uint32_t SimplexDecisionProcedure::contractErrorVariables(bool guaranteedSuccess){
- uint32_t entrySize = d_currentErrorVariables.size();
- Debug("primal::contract") << "contractErrorVariables() begin : " << d_currentErrorVariables.size() << endl;
-
- std::vector<ArithVar> toRemove;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar e = *iter;
- if(d_currentErrorVariables[e].errorIsLeqZero(d_partialModel)){
- toRemove.push_back(e);
- }
- }
-
- Assert(!guaranteedSuccess || !toRemove.empty());
-
- if(!toRemove.empty()){
- while(!toRemove.empty()){
- ArithVar e = toRemove.back();
- toRemove.pop_back();
- reassertErrorConstraint(e, d_currentErrorVariables, true, false);
- d_currentErrorVariables.remove(e);
- }
-
- reconstructOptimizationFunction();
- }
-
- Debug("primal::contract") << "contractErrorVariables() end : " << d_currentErrorVariables.size() << endl;
-
- uint32_t exitSize = d_currentErrorVariables.size();
-
- Assert(exitSize <= entrySize);
- Assert(!guaranteedSuccess|| exitSize < entrySize);
- return entrySize - exitSize;
-}
-
-void SimplexDecisionProcedure::removeOptimizationFunction(){
- Assert(d_optRow != ARITHVAR_SENTINEL);
- Assert(d_tableau.isBasic(d_optRow));
-
- d_tableau.removeBasicRow(d_optRow);
- releaseVariable(d_optRow);
-
- d_optRow = ARITHVAR_SENTINEL;
- d_negOptConstant = d_DELTA_ZERO;
-
- Assert(d_optRow == ARITHVAR_SENTINEL);
-}
-
-void SimplexDecisionProcedure::constructOptimizationFunction(){
- Assert(d_optRow == ARITHVAR_SENTINEL);
- Assert(d_negOptConstant == d_DELTA_ZERO);
-
- d_optRow = requestVariable();
-
-
- std::vector<Rational> coeffs;
- std::vector<ArithVar> variables;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar e = *iter;
-
- if(d_currentErrorVariables[e].isUpperbound()){
- coeffs.push_back(Rational(1));
- variables.push_back(e);
- d_negOptConstant = d_negOptConstant + (d_currentErrorVariables[e].getConstraint()->getValue());
- }else{
- coeffs.push_back(Rational(-1));
- variables.push_back(e);
- d_negOptConstant = d_negOptConstant - (d_currentErrorVariables[e].getConstraint()->getValue());
- }
- }
- d_tableau.addRow(d_optRow, coeffs, variables);
-
- DeltaRational newAssignment = d_linEq.computeRowValue(d_optRow, false);
- d_partialModel.setAssignment(d_optRow, newAssignment);
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
-
-
- if(Debug.isOn("primal::consistent")){
- d_linEq.debugEntireLinEqIsConsistent("constructOptimizationFunction");
- }
-
- d_pivotsSinceOptProgress = 0;
- d_pivotsSinceErrorProgress = 0;
-
- Assert(d_optRow != ARITHVAR_SENTINEL);
-}
-
-void SimplexDecisionProcedure::reconstructOptimizationFunction(){
- removeOptimizationFunction();
- constructOptimizationFunction();
-}
-
-
-
-/* TODO:
- * Very naive implementation. Recomputes everything every time.
- * Currently looks for the variable that can decrease the optimization function the most.
- *
- */
-SimplexDecisionProcedure::PrimalResponse SimplexDecisionProcedure::primalCheck()
-{
- Debug("primal") << "primalCheck() begin" << endl;
-
- ArithVar leaving = ARITHVAR_SENTINEL;
- ArithVar entering = ARITHVAR_SENTINEL;
- DeltaRational leavingShift = d_DELTA_ZERO; // The amount the leaving variable can change by without making the tableau inconsistent
- DeltaRational leavingDelta = d_DELTA_ZERO; // The amount the optimization function changes by selecting leaving
-
- Assert(d_improvementCandidates.empty());
-
- for( Tableau::RowIterator ri = d_tableau.basicRowIterator(d_optRow); !ri.atEnd(); ++ri){
- const Tableau::Entry& e = *ri;
-
- ArithVar curr = e.getColVar();
- if(curr == d_optRow){ continue; }
-
-
- int sgn = e.getCoefficient().sgn();
- Assert(sgn != 0);
- if( (sgn < 0 && d_partialModel.strictlyBelowUpperBound(curr)) ||
- (sgn > 0 && d_partialModel.strictlyAboveLowerBound(curr)) ){
-
- d_improvementCandidates.push_back(&e);
- }
- }
-
- if(d_improvementCandidates.empty()){
- Debug("primal") << "primalCheck() end : global" << endl;
- return GlobalMinimum; // No variable in the optimization function can be improved
- }
-
- DeltaRational minimumShift;
- DeltaRational currShift;
- for(EntryVector::const_iterator ci = d_improvementCandidates.begin(), end_ci = d_improvementCandidates.end(); ci != end_ci; ++ci){
- const Tableau::Entry& e = *(*ci);
- ArithVar curr = e.getColVar();
-
- ArithVar currEntering;
- bool progress;
-
- minimumShift = (leaving == ARITHVAR_SENTINEL ) ? leavingDelta/(e.getCoefficient().abs()) : d_DELTA_ZERO;
- int sgn = e.getCoefficient().sgn();
- computeShift(curr, sgn < 0, progress, currEntering, currShift, minimumShift);
-
- if(currEntering == ARITHVAR_SENTINEL){
- d_improvementCandidates.clear();
-
- Debug("primal") << "primalCheck() end : unbounded" << endl;
- d_primalCarry.d_unbounded = curr;
- return FoundUnboundedVariable;
- }else if(progress) {
- leaving = curr;
- leavingShift = currShift;
- leavingDelta = currShift * e.getCoefficient();
- entering = currEntering;
-
- Assert(leavingDelta < d_DELTA_ZERO);
-
- const int RECHECK_PERIOD = 10;
- if(d_pivotsSinceErrorProgress % RECHECK_PERIOD != 0){
- // we can make progress, stop
- break;
- }
- }
- }
-
- if(leaving == ARITHVAR_SENTINEL){
- cout << "Nothing can make progress " << endl;
-
- const uint32_t THRESHOLD = 20;
- if(d_pivotsSinceOptProgress <= THRESHOLD){
-
- int index = rand() % d_improvementCandidates.size();
- leaving = (*d_improvementCandidates[index]).getColVar();
- entering = selectFirstValid(leaving, (*d_improvementCandidates[index]).getCoefficient().sgn() < 0);
- }else{ // Bland's rule
- bool increasing;
- for(EntryVector::const_iterator ci = d_improvementCandidates.begin(), end_ci = d_improvementCandidates.end(); ci != end_ci; ++ci){
- const Tableau::Entry& e = *(*ci);
- ArithVar curr = e.getColVar();
- leaving = (leaving == ARITHVAR_SENTINEL) ? curr : minVarOrder(*this, curr, leaving);
- if(leaving == curr){
- increasing = (e.getCoefficient().sgn() < 0);
- }
- }
-
- entering = selectMinimumValid(leaving, increasing);
- }
- Assert(leaving != ARITHVAR_SENTINEL);
- Assert(entering != ARITHVAR_SENTINEL);
-
- d_primalCarry.d_leaving = leaving;
- d_primalCarry.d_entering = entering;
-
- d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering);
-
- Debug("primal") << "primalCheck() end : no progress made " << leaving << " to " << entering << " (" << d_pivotsSinceOptProgress << ")"<< endl;
- d_improvementCandidates.clear();
- return NoProgressOnLeaving;
- }else{
- const Tableau::Entry& enterLeavingEntry = d_tableau.findEntry(d_tableau.basicToRowIndex(entering), leaving);
- Assert(!enterLeavingEntry.blank());
-
- d_primalCarry.d_leaving = leaving;
- d_primalCarry.d_entering = entering;
- d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering)
- + leavingShift * enterLeavingEntry.getCoefficient();
-
- Debug("primal") << "primalCheck() end : progress" << endl
- << leaving << " to " << entering << " ~ "
- << d_partialModel.getAssignment(leaving) << " ~ " << leavingShift
- << " ~ " << enterLeavingEntry.getCoefficient()
- << " ~ " << d_primalCarry.d_nextEnteringValue << endl;
-
- d_improvementCandidates.clear();
- return MakeProgressOnLeaving;
- }
-
- // anyProgress = true;
-
- // DeltaRational currDelta = currShift * e.getCoefficient();
-
- // int cmp = currDelta.cmp(leavingDelta);
-
- // // Cases:
- // // 1) No candidate yet,
- // // 2) there is a candidate with a strictly better update, or
- // // 3) there is a candidate with the same update value that has a smaller value in the variable ordering.
- // //
- // // Case 3 covers Bland's rule.
- // if(entering == ARITHVAR_SENTINEL || cmp < 0){
- // leaving = curr;
- // }else if( cmp == 0 ){
- // leaving = minVarOrder(*this, curr, leaving);
- // }
-
- // if(leaving == curr){
- // leavingShift = currShift;
- // leavingDelta = currDelta;
- // entering = currEntering;
- // }
- // }
- // }
-
- // if(leaving == ARITHVAR_SENTINEL){
- // Debug("primal") << "primalCheck() end : global" << endl;
- // return GlobalMinimum; // No variable in the optimization function can be improved
- // }else{
- // const Tableau::Entry& enterLeavingEntry = d_tableau.findEntry(d_tableau.basicToRowIndex(entering), leaving);
- // Assert(!enterLeavingEntry.blank());
-
- // d_primalCarry.d_leaving = leaving;
- // d_primalCarry.d_entering = entering;
- // d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering)
- // + leavingShift * enterLeavingEntry.getCoefficient();
-
- // Debug("primal") << "primalCheck() end : progress" << endl
- // << leaving << " to " << entering << " ~ "
- // << d_partialModel.getAssignment(leaving) << " ~ " << leavingShift
- // << " ~ " << enterLeavingEntry.getCoefficient()
- // << " ~ " << d_primalCarry.d_nextEnteringValue << endl;
- // return MakeProgressOnLeaving;
- // }
-}
-
-ArithVar SimplexDecisionProcedure::selectMinimumValid(ArithVar v, bool increasing){
- ArithVar minimum = ARITHVAR_SENTINEL;
- for(Tableau::ColIterator colIter = d_tableau.colIterator(v);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- if(minimum == ARITHVAR_SENTINEL){
- minimum = basic;
- }else{
- minimum = minVarOrder(*this, basic, minimum);
- }
- }
- }
- return minimum;
-}
-
-ArithVar SimplexDecisionProcedure::selectFirstValid(ArithVar v, bool increasing){
- ArithVar minimum = ARITHVAR_SENTINEL;
-
- for(Tableau::ColIterator colIter = d_tableau.colIterator(v);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- if(minimum == ARITHVAR_SENTINEL){
- minimum = basic;
- }else{
- minimum = minRowLength(*this, basic, minimum);
- }
- }
- }
- return minimum;
-}
-
-
-
-void SimplexDecisionProcedure::computeShift(ArithVar leaving, bool increasing, bool& progress, ArithVar& entering, DeltaRational& shift, const DeltaRational& minimumShift){
- Assert(increasing ? (minimumShift >= d_DELTA_ZERO) : (minimumShift <= d_DELTA_ZERO) );
-
- static int instance = 0;
- Debug("primal") << "computeshift " << ++instance << " " << leaving << endl;
-
- // The selection for the leaving variable
- entering = ARITHVAR_SENTINEL;
-
- // no progress is initially made
- progress = false;
-
- bool bounded = false;
-
- if(increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving)){
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
-
- bounded = true;
-
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- Assert(increasing ? diff.sgn() >=0 : diff.sgn() <= 0);
- if((increasing) ? (diff < minimumShift) : ( diff > minimumShift)){
- Assert(!progress);
- entering = leaving; // My my my, what an ugly hack
- return; // no progress is possible stop
- }
- }
-
- // shift has a meaningful value once entering has a meaningful value
- // if increasing,
- // then shift > minimumShift >= 0
- // else shift < minimumShift <= 0
- //
- // Maintain the following invariant:
- //
- // if increasing,
- // if e_ij > 0, diff >= shift > minimumShift >= 0
- // if e_ij < 0, diff >= shift > minimumShift >= 0
- // if !increasing,
- // if e_ij > 0, diff <= shift < minimumShift <= 0
- // if e_ij < 0, diff <= shift < minimumShift <= 0
- // if increasing == (e_ij > 0), diff = (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient()
- // if increasing != (e_ij > 0), diff = (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient()
-
- for(Tableau::ColIterator colIter = d_tableau.colIterator(leaving);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
-
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
- // If both are true, increasing the variable entering increases the basic variable
- // If both are false, the entering variable is decreasing, but the coefficient is negative and the basic variable is increasing
- // If exactly one is false, the basic variable is decreasing.
-
- Debug("primal::shift") << basic << " " << d_partialModel.hasUpperBound(basic) << " "
- << d_partialModel.hasLowerBound(basic) << " "
- << e.getCoefficient() << endl;
-
- if( (basicInc && d_partialModel.hasUpperBound(basic))||
- (!basicInc && d_partialModel.hasLowerBound(basic))){
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- // diff == 0, as diff > minimumShift >= 0 or diff < minimumShift <= 0
- Assert(!progress);
- entering = basic;
- return;
- }else{
- DeltaRational diff = basicInc ?
- (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient() :
- (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient();
-
- if( entering == ARITHVAR_SENTINEL ){
- if(increasing ? (diff <= minimumShift) : (diff >= minimumShift)){
- Assert(!progress);
- entering = basic;
- return;
- }else{
- Assert(increasing ? (diff > minimumShift) : (diff < minimumShift));
- shift = diff;
- entering = basic;
- bounded = true;
- }
- }else{
- if( increasing ? (diff < shift) : diff > shift){
- // a new min for increasing
- // a new max for decreasing
-
- if(increasing ? (diff <= minimumShift) : (diff >= minimumShift)){
- Assert(!progress);
- entering = basic;
- return;
- }else{
- Assert(increasing ? (diff > minimumShift) : (diff < minimumShift));
- shift = diff;
- entering = basic;
- }
- }
- }
- }
- }
- }
-
- if(!bounded){
- // A totally unbounded variable
- Assert(entering == ARITHVAR_SENTINEL);
- progress = true;
- return;
- }else if(entering == ARITHVAR_SENTINEL){
- // We have a variable that is bounded only by its maximum
- for(Tableau::ColIterator colIter = d_tableau.colIterator(leaving);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
-
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow){
- continue;
- } else{
- entering = basic;
- break;
- }
- }
- Assert(entering != ARITHVAR_SENTINEL);
-
- Assert(increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving));
-
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
-
- shift = diff;
-
- Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
- Assert(increasing ? shift > minimumShift : shift < minimumShift);
-
- progress = true;
- return;
- }else{
- Assert(bounded);
- progress = true;
-
- if((increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving) )){
- Assert(entering != ARITHVAR_SENTINEL);
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- if((increasing) ? (diff < shift) : ( diff > shift)){
- shift = diff;
- }
- }
-
- Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
- Assert(increasing ? shift > minimumShift : shift < minimumShift);
- return;
- }
-
-
- // if(! bounded ||
- // (increasing && diff < shift) || // a new min for increasing
- // (!increasing && diff > shift)){ // a new max for decreasing
- // bounded = true;
- // shift = diff;
- // entering = basic;
- // }
- // }
-
- // if(notAtTheBound && !blandMode){
- // DeltaRational diff = basicInc ?
- // (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient() :
- // (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient();
-
- // if(! bounded ||
- // (increasing && diff < shift) || // a new min for increasing
- // (!increasing && diff > shift)){ // a new max for decreasing
- // bounded = true;
- // shift = diff;
- // entering = basic;
- // }
- // }else if (!notAtTheBound) { // basic is already exactly at the bound
- // if(!blandMode){ // Enter into using Bland's rule
- // blandMode = true;
- // bounded = true;
- // shift = d_DELTA_ZERO;
- // entering = basic;
- // }else{
- // entering = minVarOrder(*this, entering, basic); // Bland's rule.
- // }
- // }
- // else this basic variable cannot be violated by increasing/decreasing entering
-
-
-
-
- // if(!blandMode && (increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving) )){
- // Assert(entering != ARITHVAR_SENTINEL);
- // bounded = true;
- // DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- // if((increasing) ? (diff < shift) : ( diff > shift)){
- // shift = diff;
- // }
- // }
-
- // Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
-
- // return shift;
-}
-
-
-/**
- * Given an variable on the optimization row that can be used to decrease the value of the optimization function
- * arbitrarily and an optimization function that is strictly positive in the current model,
- * driveOptToZero updates the value of unbounded s.t. the value of d_opt is exactly 0.
- */
-void SimplexDecisionProcedure::driveOptToZero(ArithVar unbounded){
- Assert(!belowThreshold());
-
- const Tableau::Entry& e = d_tableau.findEntry(d_tableau.basicToRowIndex(d_optRow), unbounded);
- Assert(!e.blank());
-
- DeltaRational theta = (d_negOptConstant-d_partialModel.getAssignment(d_optRow))/ (e.getCoefficient());
- Assert((e.getCoefficient().sgn() > 0) ? (theta.sgn() < 0) : (theta.sgn() > 0));
-
- DeltaRational newAssignment = d_partialModel.getAssignment(unbounded) + theta;
- d_linEq.update(unbounded, newAssignment);
-
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("driveOptToZero")); }
-
- Assert(belowThreshold());
-}
diff --git a/src/theory/arith/simplex-converge.h b/src/theory/arith/simplex-converge.h
deleted file mode 100644
index dac3a9b49..000000000
--- a/src/theory/arith/simplex-converge.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/********************* */
-/*! \file simplex.h
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 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 This is an implementation of the Simplex Module for the Simplex for DPLL(T) decision procedure.
- **
- ** This implements the Simplex module for the Simpelx for DPLL(T) decision procedure.
- ** See the Simplex for DPLL(T) technical report for more background.(citation?)
- ** This shares with the theory a Tableau, and a PartialModel that:
- ** - satisfies the equalities in the Tableau, and
- ** - the assignment for the non-basic variables satisfies their bounds.
- ** This is required to either produce a conflict or satisifying PartialModel.
- ** Further, we require being told when a basic variable updates its value.
- **
- ** During the Simplex search we maintain a queue of variables.
- ** The queue is required to contain all of the basic variables that voilate their bounds.
- ** As elimination from the queue is more efficient to be done lazily,
- ** we do not maintain that the queue of variables needs to be only basic variables or only variables that satisfy their bounds.
- **
- ** The simplex procedure roughly follows Alberto's thesis. (citation?)
- ** There is one round of selecting using a heuristic pivoting rule. (See PreferenceFunction Documentation for the available options.)
- ** The non-basic variable is the one that appears in the fewest pivots. (Bruno says that Leonardo invented this first.)
- ** After this, Bland's pivot rule is invoked.
- **
- ** During this proccess, we periodically inspect the queue of variables to
- ** 1) remove now extraneous extries,
- ** 2) detect conflicts that are "waiting" on the queue but may not be detected by the current queue heuristics, and
- ** 3) detect multiple conflicts.
- **
- ** Conflicts are greedily slackened to use the weakest bounds that still produce the conflict.
- **
- ** Extra things tracked atm: (Subject to change at Tim's whims)
- ** - A superset of all of the newly pivoted variables.
- ** - A queue of additional conflicts that were discovered by Simplex.
- ** These are theory valid and are currently turned into lemmas
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__ARITH__SIMPLEX_H
-#define __CVC4__THEORY__ARITH__SIMPLEX_H
-
-#include "theory/arith/arithvar.h"
-#include "theory/arith/arith_priority_queue.h"
-#include "theory/arith/delta_rational.h"
-#include "theory/arith/matrix.h"
-#include "theory/arith/partial_model.h"
-#include "theory/arith/linear_equality.h"
-
-#include "context/cdlist.h"
-
-#include "util/dense_map.h"
-#include "options/options.h"
-#include "util/stats.h"
-#include "util/result.h"
-
-#include <queue>
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-
-class SimplexDecisionProcedure {
-private:
- ArithVar d_conflictVariable;
- DenseSet d_successes;
-
- /** Linear equality module. */
- LinearEqualityModule& d_linEq;
-
- /**
- * Manages information about the assignment and upper and lower bounds on
- * variables.
- * Partial model matches that in LinearEqualityModule.
- */
- ArithPartialModel& d_partialModel;
-
- /**
- * Stores the linear equalities used by Simplex.
- * Tableau from the LinearEquality module.
- */
- Tableau& d_tableau;
-
- /** Contains a superset of the basic variables in violation of their bounds. */
- ArithPriorityQueue d_queue;
-
- /** Number of variables in the system. This is used for tuning heuristics. */
- ArithVar d_numVariables;
-
- /** This is the call back channel for Simplex to report conflicts. */
- NodeCallBack& d_conflictChannel;
-
- /** Maps a variable to how many times they have been used as a pivot in the simplex search. */
- DenseMultiset d_pivotsInRound;
-
- /** Stores to the DeltaRational constant 0. */
- DeltaRational d_DELTA_ZERO;
-
- //TODO make an option
- const static uint32_t MAX_ITERATIONS = 20;
-
-
- /** Used for requesting d_opt, bound and error variables for primal.*/
- ArithVarMalloc& d_arithVarMalloc;
-
- /** Used for constructing temporary variables, bound and error variables for primal.*/
- ConstraintDatabase& d_constraintDatabase;
-
-public:
- SimplexDecisionProcedure(LinearEqualityModule& linEq,
- NodeCallBack& conflictChannel,
- ArithVarMalloc& variables,
- ConstraintDatabase& constraintDatabase);
-
- /**
- * This must be called when the value of a basic variable may now voilate one
- * of its bounds.
- */
- void updateBasic(ArithVar x){
- d_queue.enqueueIfInconsistent(x);
- }
-
- /**
- * Tries to update the assignments of variables such that all of the
- * assignments are consistent with their bounds.
- * This is done by a simplex search through the possible bases of the tableau.
- *
- * If all of the variables can be made consistent with their bounds
- * SAT is returned. Otherwise UNSAT is returned, and at least 1 conflict
- * was reported on the conflictCallback passed to the Module.
- *
- * Tableau pivoting is performed so variables may switch from being basic to
- * nonbasic and vice versa.
- *
- * Corresponds to the "check()" procedure in [Cav06].
- */
- Result::Sat dualFindModel(bool exactResult);
-
-
- /**
- * Tries to update the assignments of the variables s.t. all of the assignments
- * are consistent with their bounds.
- *
- * This is a REALLY heavy hammer consider calling dualFindModel(false) first.
- *
- * !!!!!!!!!!!!!IMPORTANT!!!!!!!!!!!!!!
- * This procedure needs to temporarily relax contraints to contruct a satisfiable system.
- * To do this, it is going to do a sat push.
- */
- Result::Sat primalFindModel();
-
-private:
-
-
- /**
- * A PreferenceFunction takes a const ref to the SimplexDecisionProcedure,
- * and 2 ArithVar variables and returns one of the ArithVar variables potentially
- * using the internals of the SimplexDecisionProcedure.
- *
- * Both ArithVar must be non-basic in d_tableau.
- */
- typedef ArithVar (*PreferenceFunction)(const SimplexDecisionProcedure&, ArithVar, ArithVar);
-
- /**
- * minVarOrder is a PreferenceFunction for selecting the smaller of the 2 ArithVars.
- * This PreferenceFunction is used during the VarOrder stage of
- * findModel.
- */
- static ArithVar minVarOrder(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
- /**
- * minRowCount is a PreferenceFunction for selecting the variable with the smaller
- * row count in the tableau.
- *
- * This is a heuristic rule and should not be used
- * during the VarOrder stage of findModel.
- */
- static ArithVar minColLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
- static ArithVar minRowLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
- /**
- * minBoundAndRowCount is a PreferenceFunction for preferring a variable
- * without an asserted bound over variables with an asserted bound.
- * If both have bounds or both do not have bounds,
- * the rule falls back to minRowCount(...).
- *
- * This is a heuristic rule and should not be used
- * during the VarOrder stage of findModel.
- */
- static ArithVar minBoundAndRowCount(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
-
- /**
- * This is the main simplex for DPLL(T) loop.
- * It runs for at most maxIterations.
- *
- * Returns true iff it has found a conflict.
- * d_conflictVariable will be set and the conflict for this row is reported.
- */
- bool searchForFeasibleSolution(uint32_t maxIterations);
-
- enum SearchPeriod {BeforeDiffSearch, DuringDiffSearch, AfterDiffSearch, DuringVarOrderSearch, AfterVarOrderSearch};
-
- bool findConflictOnTheQueue(SearchPeriod period);
-
-
- /**
- * Given the basic variable x_i,
- * this function finds the smallest nonbasic variable x_j in the row of x_i
- * in the tableau that can "take up the slack" to let x_i satisfy its bounds.
- * This returns ARITHVAR_SENTINEL if none exists.
- *
- * More formally one of the following conditions must be satisfied:
- * - lowerBound && a_ij < 0 && assignment(x_j) < upperbound(x_j)
- * - lowerBound && a_ij > 0 && assignment(x_j) > lowerbound(x_j)
- * - !lowerBound && a_ij > 0 && assignment(x_j) < upperbound(x_j)
- * - !lowerBound && a_ij < 0 && assignment(x_j) > lowerbound(x_j)
- *
- */
- template <bool lowerBound> ArithVar selectSlack(ArithVar x_i, PreferenceFunction pf);
- ArithVar selectSlackLowerBound(ArithVar x_i, PreferenceFunction pf = minVarOrder) {
- return selectSlack<true>(x_i, pf);
- }
- ArithVar selectSlackUpperBound(ArithVar x_i, PreferenceFunction pf = minVarOrder) {
- return selectSlack<false>(x_i, pf);
- }
- /**
- * Returns the smallest basic variable whose assignment is not consistent
- * with its upper and lower bounds.
- */
- ArithVar selectSmallestInconsistentVar();
-
- /**
- * Given a non-basic variable that is know to not be updatable
- * to a consistent value, construct and return a conflict.
- * Follows section 4.2 in the CAV06 paper.
- */
- Node generateConflictAboveUpperBound(ArithVar conflictVar);
- Node generateConflictBelowLowerBound(ArithVar conflictVar);
-
-public:
- void increaseMax() {d_numVariables++;}
-
-
- void clearQueue() {
- d_queue.clear();
- }
-
-
- bool debugIsInCollectionQueue(ArithVar var) const{
- Assert(d_queue.inCollectionMode());
- return d_queue.collectionModeContains(var);
- }
-
- void reduceQueue(){
- d_queue.reduce();
- }
-
- ArithPriorityQueue::const_iterator queueBegin() const{
- return d_queue.begin();
- }
-
- ArithPriorityQueue::const_iterator queueEnd() const{
- return d_queue.end();
- }
-
-private:
-
- /** Reports a conflict to on the output channel. */
- void reportConflict(Node conflict){
- d_conflictChannel(conflict);
- ++(d_statistics.d_simplexConflicts);
- }
-
- template <bool above>
- inline bool isAcceptableSlack(int sgn, ArithVar nonbasic){
- return
- ( above && sgn < 0 && d_partialModel.strictlyBelowUpperBound(nonbasic)) ||
- ( above && sgn > 0 && d_partialModel.strictlyAboveLowerBound(nonbasic)) ||
- (!above && sgn > 0 && d_partialModel.strictlyBelowUpperBound(nonbasic)) ||
- (!above && sgn < 0 && d_partialModel.strictlyAboveLowerBound(nonbasic));
- }
-
- /**
- * Checks a basic variable, b, to see if it is in conflict.
- * If a conflict is discovered a node summarizing the conflict is returned.
- * Otherwise, Node::null() is returned.
- */
- Node checkBasicForConflict(ArithVar b);
-
- Node weakenConflict(bool aboveUpper, ArithVar basicVar);
- Constraint weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic);
-
- /** Gets a fresh variable from TheoryArith. */
- ArithVar requestVariable(){
- return d_arithVarMalloc.request();
- }
-
- /** Releases a requested variable from TheoryArith.*/
- void releaseVariable(ArithVar v){
- d_arithVarMalloc.release(v);
- }
-
-
- /** An error info keeps the information associated with the construction of an ErrorVariable. */
- class ErrorInfo {
- private:
- /** The variable for which the error variable was constructed.*/
- ArithVar d_variable;
-
- // If false -> lowerbound
- bool d_upperbound;
-
- /** The violated constraint this was constructed to try to satisfy.*/
- Constraint d_violated;
-
- public:
- ErrorInfo(ArithVar error, bool ub, const Constraint original)
- : d_variable(error), d_upperbound(ub), d_violated(original) {}
-
- ErrorInfo() :
- d_variable(ARITHVAR_SENTINEL), d_upperbound(false), d_violated(NullConstraint){}
-
- inline ArithVar getVariable() const {
- return d_variable;
- }
-
- inline bool isUpperbound() const {
- return d_upperbound;
- }
-
- inline bool errorIsLeqZero(const ArithPartialModel& d_pm) const{
- return isUpperbound() ?
- (d_pm.getAssignment(d_variable) <= d_violated->getValue()) :
- (d_pm.getAssignment(d_variable) >= d_violated->getValue());
- }
-
- inline Constraint getConstraint() const {
- return d_violated;
- }
-
- inline DeltaRational getErrorAmount(const ArithPartialModel& d_pm) const {
- return isUpperbound() ?
- (d_pm.getAssignment(d_variable) - d_violated->getValue()) :
- (d_violated->getValue() - d_pm.getAssignment(d_variable));
- }
- };
-
- typedef DenseMap<ErrorInfo> ErrorMap;
-
- /** A map from the error variables to the associated ErrorInfo.*/
- ErrorMap d_currentErrorVariables;
-
- /** The optimization function is implicitly defined as
- * f_i = d_optRow - d_negOptConstant
- *
- * d_optRow is a basic variable in the tableau.
- * The tableau maintains that it is equal to the sum of -1^{!ub} * the error variables in
- * d_currentErrorVariables.
- *
- * d_negOptConstant is explicitly the negation of the sum of the bounds that were violated
- *
- * assignment(f_i) <= 0 iff assignment(d_optRow) <= d_negOptConstant
- */
- /** The variable for the variable part of the optimization function.*/
- ArithVar d_optRow;
-
- /** The constant part of the optimization function.*/
- DeltaRational d_negOptConstant;
-
- inline bool belowThreshold() const {
- return d_partialModel.getAssignment(d_optRow) <= d_negOptConstant;
- }
-
- /**
- * A PrimalResponse represents the state that the primal simplex solver is in.
- */
- enum PrimalResponse {
- // The optimization can decrease arbitrarily on some variable in the function
- FoundUnboundedVariable,
-
- // The optimization function has reached a threshold value and is checking back in
- ReachedThresholdValue,
-
- // Simplex has used up its pivot bound and is checking back in with its caller
- UsedMaxPivots,
-
- //Simplex can make progress on the pair of entering and leaving variables
- MakeProgressOnLeaving,
-
- //Simplex is not at a minimum but no leaving variable can be changed to help
- NoProgressOnLeaving,
-
- // Simplex has reached a minimum for its optimization function
- GlobalMinimum
- };
-
- /**
- * These fields are for sticking information for passing information back with the PrimalRespones.
- * These fields should be ignored as unsafe/unknown unless you have a PrimalResponse that states
- * the field makes sense.
- */
- struct PrimalPassBack {
- public:
- /**
- * A variable s.t. its value can be increased/decreased arbitrarily to change the optimization function
- * arbitrarily low.
- */
- ArithVar d_unbounded;
-
- /** The leaving variable selection for primal simplex. */
- ArithVar d_leaving;
-
- /** The entering variable selection for primal simplex. */
- ArithVar d_entering;
-
- /** The new value for the leaving variable value for primal simplex.*/
- DeltaRational d_nextEnteringValue;
-
- PrimalPassBack() { clear(); }
- void clear(){
- d_unbounded = (d_leaving = (d_entering = ARITHVAR_SENTINEL));
- d_nextEnteringValue = DeltaRational();
- }
-
- bool isClear() const {
- return d_unbounded == ARITHVAR_SENTINEL &&
- d_leaving == ARITHVAR_SENTINEL &&
- d_entering == ARITHVAR_SENTINEL &&
- d_nextEnteringValue.sgn() == 0;
- }
- } d_primalCarry;
-
- uint32_t d_pivotsSinceErrorProgress;
- uint32_t d_pivotsSinceOptProgress;
- uint32_t d_pivotsSinceLastCheck;
-
- typedef std::vector< const Tableau::Entry* > EntryVector;
- EntryVector d_improvementCandidates;
-
- PrimalResponse primal(uint32_t maxIterations);
- PrimalResponse primalCheck();
- Result::Sat primalConverge(int depth);
- void driveOptToZero(ArithVar unbounded);
- uint32_t contractErrorVariables(bool guaranteedSuccess);
- bool checkForRowConflicts();
- void restoreErrorVariables(ErrorMap& es);
- void constructErrorVariables();
- void constructOptimizationFunction();
- void removeOptimizationFunction();
- void reconstructOptimizationFunction();
- ArithVar selectMinimumValid(ArithVar v, bool increasing);
- ArithVar selectFirstValid(ArithVar v, bool increasing);
-
- void reassertErrorConstraint(ArithVar e, ErrorMap& es, bool definitelyTrue, bool definitelyFalse);
- void computeShift(ArithVar leaving, bool increasing, bool& progress, ArithVar& entering, DeltaRational& shift, const DeltaRational& minimumShift);
-
- /** These fields are designed to be accessible to TheoryArith methods. */
- class Statistics {
- public:
- IntStat d_statUpdateConflicts;
-
- TimerStat d_findConflictOnTheQueueTime;
-
- IntStat d_attemptBeforeDiffSearch, d_successBeforeDiffSearch;
- IntStat d_attemptAfterDiffSearch, d_successAfterDiffSearch;
- IntStat d_attemptDuringDiffSearch, d_successDuringDiffSearch;
- IntStat d_attemptDuringVarOrderSearch, d_successDuringVarOrderSearch;
- IntStat d_attemptAfterVarOrderSearch, d_successAfterVarOrderSearch;
-
- IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
- TimerStat d_weakenTime;
-
-
- IntStat d_simplexConflicts;
-
- // Primal stuffs
- TimerStat d_primalTimer;
- TimerStat d_internalTimer;
-
- IntStat d_primalCalls;
- IntStat d_primalSatCalls;
- IntStat d_primalUnsatCalls;
-
- IntStat d_primalPivots;
- IntStat d_primalImprovingPivots;
-
- IntStat d_primalThresholdReachedPivot;
- IntStat d_primalThresholdReachedPivot_dropped;
-
- IntStat d_primalReachedMaxPivots;
- IntStat d_primalReachedMaxPivots_contractMadeProgress;
- IntStat d_primalReachedMaxPivots_checkForConflictWorked;
-
-
- IntStat d_primalGlobalMinimum;
- IntStat d_primalGlobalMinimum_rowConflictWorked;
- IntStat d_primalGlobalMinimum_firstHalfWasSat;
- IntStat d_primalGlobalMinimum_firstHalfWasUnsat;
- IntStat d_primalGlobalMinimum_contractMadeProgress;
-
-
- IntStat d_unboundedFound;
- IntStat d_unboundedFound_drive;
- IntStat d_unboundedFound_dropped;
-
-
- Statistics();
- ~Statistics();
- };
-
- Statistics d_statistics;
-
-};/* class SimplexDecisionProcedure */
-
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__ARITH__SIMPLEX_H */
-
diff --git a/src/theory/arith/simplex.cpp b/src/theory/arith/simplex.cpp
index 02e49258c..a160f4fe2 100644
--- a/src/theory/arith/simplex.cpp
+++ b/src/theory/arith/simplex.cpp
@@ -130,6 +130,8 @@ void SimplexDecisionProcedure::tearDownInfeasiblityFunction(TimerStat& timer, Ar
Assert(tmp != ARITHVAR_SENTINEL);
Assert(d_tableau.isBasic(tmp));
+ RowIndex ri = d_tableau.basicToRowIndex(tmp);
+ d_linEq.stopTrackingRowIndex(ri);
d_tableau.removeBasicRow(tmp);
releaseVariable(tmp);
}
@@ -168,6 +170,12 @@ void SimplexDecisionProcedure::addToInfeasFunc(TimerStat& timer, ArithVar inf, A
adjustInfeasFunc(timer, inf, justE);
}
+void SimplexDecisionProcedure::removeFromInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e){
+ AVIntPairVec justE;
+ int opSgn = -d_errorSet.getSgn(e);
+ justE.push_back(make_pair(e, opSgn));
+ adjustInfeasFunc(timer, inf, justE);
+}
ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& timer, const ArithVarVec& set){
TimerStat::CodeTimer codeTimer(timer);
@@ -193,9 +201,10 @@ ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& time
DeltaRational newAssignment = d_linEq.computeRowValue(inf, false);
d_variables.setAssignment(inf, newAssignment);
- d_linEq.trackVariable(inf);
+ //d_linEq.trackVariable(inf);
+ d_linEq.trackRowIndex(d_tableau.basicToRowIndex(inf));
- Debug("Inf") << inf << " " << newAssignment << endl;
+ Debug("constructInfeasiblityFunction") << inf << " " << newAssignment << endl;
return inf;
}
@@ -226,7 +235,7 @@ void SimplexDecisionProcedure::addRowSgns(sgn_table& sgns, ArithVar basic, int n
}
}
-ArithVar SimplexDecisionProcedure::find_basic_outside(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m){
+ArithVar SimplexDecisionProcedure::find_basic_in_sgns(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m, bool inside){
pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
sgn_table::const_iterator i = sgns.find(p);
@@ -234,7 +243,7 @@ ArithVar SimplexDecisionProcedure::find_basic_outside(const sgn_table& sgns, Ari
const ArithVarVec& vec = (*i).second;
for(ArithVarVec::const_iterator viter = vec.begin(), vend = vec.end(); viter != vend; ++viter){
ArithVar curr = *viter;
- if(!m.isMember(curr)){
+ if(inside == m.isMember(curr)){
return curr;
}
}
diff --git a/src/theory/arith/simplex.h b/src/theory/arith/simplex.h
index bc47a128a..d646ca889 100644
--- a/src/theory/arith/simplex.h
+++ b/src/theory/arith/simplex.h
@@ -121,6 +121,7 @@ protected:
void tearDownInfeasiblityFunction(TimerStat& timer, ArithVar inf);
void adjustInfeasFunc(TimerStat& timer, ArithVar inf, const AVIntPairVec& focusChanges);
void addToInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e);
+ void removeFromInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e);
void shrinkInfeasFunc(TimerStat& timer, ArithVar inf, const ArithVarVec& dropped);
public:
@@ -197,7 +198,8 @@ protected:
void addSgn(sgn_table& sgns, ArithVar col, int sgn, ArithVar basic);
void addRowSgns(sgn_table& sgns, ArithVar basic, int norm);
- ArithVar find_basic_outside(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m);
+ ArithVar find_basic_in_sgns(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m, bool inside);
+
sgn_table::const_iterator find_sgns(const sgn_table& sgns, ArithVar col, int sgn);
};/* class SimplexDecisionProcedure */
diff --git a/src/theory/arith/simplex_update.h b/src/theory/arith/simplex_update.h
index 516586568..64aa193dd 100644
--- a/src/theory/arith/simplex_update.h
+++ b/src/theory/arith/simplex_update.h
@@ -318,7 +318,7 @@ private:
}
/**
- * Determines the appropraite WitnessImprovement for the update.
+ * Determines the appropriate WitnessImprovement for the update.
* useBlands breaks ties for degenerate pivots.
*
* This is safe if:
diff --git a/src/theory/arith/soi_simplex.cpp b/src/theory/arith/soi_simplex.cpp
index 7255d92ef..c0ee7ad20 100644
--- a/src/theory/arith/soi_simplex.cpp
+++ b/src/theory/arith/soi_simplex.cpp
@@ -22,6 +22,8 @@
#include "util/statistics_registry.h"
+#include <algorithm>
+
using namespace std;
namespace CVC4 {
@@ -237,7 +239,7 @@ UpdateInfo SumOfInfeasibilitiesSPD::selectUpdate(LinearEqualityModule::UpdatePre
Debug("soi::selectPrimalUpdate")
<< "selectPrimalUpdate " << instance << endl
<< d_soiVar << " " << d_tableau.basicRowLength(d_soiVar)
- << " " << d_linEq._countBounds(d_soiVar) << endl;
+ << " " << d_linEq.debugBasicAtBoundCount(d_soiVar) << endl;
typedef std::vector<Cand> CandVector;
CandVector candidates;
@@ -284,7 +286,6 @@ UpdateInfo SumOfInfeasibilitiesSPD::selectUpdate(LinearEqualityModule::UpdatePre
ArithVar curr = cand.d_nb;
const Rational& coeff = *cand.d_coeff;
-#warning "Who is using computeSafeUpdate?"
LinearEqualityModule::UpdatePreferenceFunction leavingPrefFunc = selectLeavingFunction(curr);
UpdateInfo currProposal = d_linEq.speculativeUpdate(curr, coeff, leavingPrefFunc);
@@ -349,7 +350,7 @@ void SumOfInfeasibilitiesSPD::debugPrintSignal(ArithVar updated) const{
int dir = !d_variables.assignmentIsConsistent(updated) ?
d_errorSet.getSgn(updated) : 0;
Debug("updateAndSignal") << " dir " << dir;
- Debug("updateAndSignal") << " _countBounds " << d_linEq._countBounds(updated) << endl;
+ Debug("updateAndSignal") << " debugBasicAtBoundCount " << d_linEq.debugBasicAtBoundCount(updated) << endl;
}
@@ -367,7 +368,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
ArithVar leaving = selected.leaving();
ss << "leaving " << leaving
<< " " << d_tableau.basicRowLength(leaving)
- << " " << d_linEq._countBounds(leaving)
+ << " " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
if(degenerate(w) && selected.describesPivot()){
@@ -376,7 +377,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
<< "degenerate " << leaving
<< ", atBounds " << d_linEq.basicsAtBounds(selected)
<< ", len " << d_tableau.basicRowLength(leaving)
- << ", bc " << d_linEq._countBounds(leaving)
+ << ", bc " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
}
@@ -433,6 +434,192 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
adjustFocusAndError(selected, focusChanges);
}
+void SumOfInfeasibilitiesSPD::qeAddRange(uint32_t begin, uint32_t end){
+ Assert(!d_qeInSoi.empty());
+ for(uint32_t i = begin; i != end; ++i){
+ ArithVar v = d_qeConflict[i];
+ addToInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, v);
+ d_qeInSoi.add(v);
+ }
+}
+
+void SumOfInfeasibilitiesSPD::qeRemoveRange(uint32_t begin, uint32_t end){
+ for(uint32_t i = begin; i != end; ++i){
+ ArithVar v = d_qeConflict[i];
+ removeFromInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, v);
+ d_qeInSoi.remove(v);
+ }
+ Assert(!d_qeInSoi.empty());
+}
+
+void SumOfInfeasibilitiesSPD::qeSwapRange(uint32_t N, uint32_t r, uint32_t s){
+ for(uint32_t i = 0; i < N; ++i){
+ std::swap(d_qeConflict[r+i], d_qeConflict[s+i]);
+ }
+}
+
+/**
+ * Region notation:
+ * A region is either
+ * - A single element X@i with the name X at the position i
+ * - A sequence of indices X@[i,j) with the name X and the elements between i [inclusive] and j exclusive
+ * - A concatenation of regions R1 and R2, R1;R2
+ *
+ * Given the fixed assumptions C @ [0,cEnd) and a set of candidate minimizations U@[cEnd, uEnd)
+ * s.t. C \cup U is known to be in conflict ([0,uEnd) has a conflict), find a minimal
+ * subset of U, Delta, s.t. C \cup Delta is in conflict.
+ *
+ * Pre:
+ * [0, uEnd) is a set and is in conflict.
+ * uEnd <= assumptions.size()
+ * [0, cEnd) is in d_inSoi.
+ *
+ * Invariants: [0,cEnd) is never modified
+ *
+ * Post:
+ * [0, cEnd); [cEnd, deltaEnd) is in conflict
+ * [0, deltaEnd) is a set
+ * [0, deltaEnd) is in d_inSoi
+ */
+uint32_t SumOfInfeasibilitiesSPD::quickExplainRec(uint32_t cEnd, uint32_t uEnd){
+ Assert(cEnd <= uEnd);
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+
+ const Tableau::Entry* spoiler = NULL;
+
+ if(d_soiVar != ARITHVAR_SENTINEL && d_linEq.selectSlackEntry(d_soiVar, false) == NULL){
+ // already in conflict
+ return cEnd;
+ }
+
+ Assert(cEnd < uEnd);
+
+ // Phase 1 : Construct the conflict greedily
+
+ for(uint32_t i = cEnd; i < uEnd; ++i){
+ d_qeInUAndNotInSoi.add(d_qeConflict[i]);
+ }
+ if(d_soiVar == ARITHVAR_SENTINEL){ // special case for d_soiVar being empty
+ ArithVar first = d_qeConflict[cEnd];
+ d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, first);
+ d_qeInSoi.add(first);
+ d_qeInUAndNotInSoi.remove(first);
+ d_qeGreedyOrder.push_back(first);
+ }
+ while((spoiler = d_linEq.selectSlackEntry(d_soiVar, false)) != NULL){
+ Assert(!d_qeInUAndNotInSoi.empty());
+
+ ArithVar nb = spoiler->getColVar();
+ int oppositeSgn = -(spoiler->getCoefficient().sgn());
+ Assert(oppositeSgn != 0);
+
+ ArithVar basicWithOp = find_basic_in_sgns(d_qeSgns, nb, oppositeSgn, d_qeInUAndNotInSoi, true);
+ Assert(basicWithOp != ARITHVAR_SENTINEL);
+
+ addToInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, basicWithOp);
+ d_qeInSoi.add(basicWithOp);
+ d_qeInUAndNotInSoi.remove(basicWithOp);
+ d_qeGreedyOrder.push_back(basicWithOp);
+ }
+ Assert(spoiler == NULL);
+
+ // Compact the set u
+ uint32_t newEnd = cEnd + d_qeGreedyOrder.size();
+ std::copy(d_qeGreedyOrder.begin(), d_qeGreedyOrder.end(), d_qeConflict.begin()+cEnd);
+
+ d_qeInUAndNotInSoi.purge();
+ d_qeGreedyOrder.clear();
+
+ // Phase 2 : Recursively determine the minimal set of rows
+
+ uint32_t xPos = cEnd;
+ std::swap(d_qeGreedyOrder[xPos], d_qeGreedyOrder[newEnd - 1]);
+ uint32_t uBegin = xPos + 1;
+ uint32_t split = (newEnd - uBegin)/2 + uBegin;
+
+ //assumptions : C @ [0, cEnd); X @ xPos; U1 @ [u1Begin, split); U2 @ [split, newEnd)
+ // [0, newEnd) == d_inSoi
+
+ uint32_t compactU2;
+ if(split == newEnd){ // U2 is empty
+ compactU2 = newEnd;
+ }else{
+ // Remove U2 from Soi
+ qeRemoveRange(split, newEnd);
+ // [0, split) == d_inSoi
+
+ // pre assumptions: C + X + U1 @ [0,split); U2 [split, newEnd)
+ compactU2 = quickExplainRec(split, newEnd);
+ // post:
+ // assumptions: C + X + U1 @ [0, split); delta2 @ [split - compactU2)
+ // d_inSoi = [0, compactU2)
+ }
+ uint32_t deltaSize = compactU2 - split;
+ qeSwapRange(deltaSize, uBegin, split);
+ uint32_t d2End = uBegin+deltaSize;
+ // assumptions : C @ [0, cEnd); X @ xPos; delta2 @ [uBegin, d2End); U1 @ [d2End, compactU2)
+ // d_inSoi == [0, compactU2)
+
+ uint32_t d1End;
+ if(d2End == compactU2){ // U1 is empty
+ d1End = d2End;
+ }else{
+ qeRemoveRange(d2End, compactU2);
+
+ //pre assumptions : C + X + delta2 @ [0, d2End); U1 @ [d2End, compactU2);
+ d1End = quickExplainRec(d2End, compactU2);
+ //post:
+ // assumptions : C + X + delta2 @ [0, d2End); delta1 @ [d2End, d1End);
+ // d_inSoi = [0, d1End)
+ }
+ //After both:
+ // d_inSoi == [0, d1End), C @ [0, cEnd); X + delta2 + delta 1 @ [xPos, d1End);
+
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ return d1End;
+}
+
+void SumOfInfeasibilitiesSPD::quickExplain(){
+ Assert(d_qeInSoi.empty());
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ Assert(d_soiVar == ARITHVAR_SENTINEL);
+ Assert(d_qeSgns.empty());
+
+ d_qeConflict.clear();
+ d_errorSet.pushFocusInto(d_qeConflict);
+
+ //cout << d_qeConflict.size() << " ";
+ uint32_t size = d_qeConflict.size();
+
+ if(size > 2){
+ for(ErrorSet::focus_iterator iter = d_errorSet.focusBegin(), end = d_errorSet.focusEnd(); iter != end; ++iter){
+ ArithVar e = *iter;
+ addRowSgns(d_qeSgns, e, d_errorSet.getSgn(e));
+ }
+ uint32_t end = quickExplainRec(0u, size);
+ Assert(end <= d_qeConflict.size());
+ Assert(d_soiVar != ARITHVAR_SENTINEL);
+ Assert(!d_qeInSoi.empty());
+
+ d_qeConflict.resize(end);
+ tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
+ d_soiVar = ARITHVAR_SENTINEL;
+ d_qeInSoi.purge();
+ d_qeSgns.clear();
+ }
+
+ //cout << d_qeConflict.size() << endl;
+
+ Assert(d_qeInSoi.empty());
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ Assert(d_soiVar == ARITHVAR_SENTINEL);
+ Assert(d_qeSgns.empty());
+}
+
unsigned SumOfInfeasibilitiesSPD::trySet(const ArithVarVec& set){
Assert(d_soiVar == ARITHVAR_SENTINEL);
bool success = false;
@@ -446,30 +633,6 @@ unsigned SumOfInfeasibilitiesSPD::trySet(const ArithVarVec& set){
return success ? set.size() : std::numeric_limits<int>::max();
}
-unsigned SumOfInfeasibilitiesSPD::tryAllSubsets(const ArithVarVec& set, unsigned depth, ArithVarVec& tmp) {
- if(depth < set.size()){
- unsigned resWithout = tryAllSubsets(set, depth+1, tmp);
- if(resWithout == tmp.size() && resWithout < set.size()){
- for(unsigned i = 0; i < tmp.size(); ++i){
- cout << tmp[i] << " ";
- }
- cout << endl;
- }
- tmp.push_back(set[depth]);
- unsigned resWith = tryAllSubsets(set, depth+1, tmp);
- if(resWith == tmp.size() && resWith < set.size()){
- for(unsigned i = 0; i < tmp.size(); ++i){
- cout << tmp[i] << " ";
- }
- cout << endl;
- }
- tmp.pop_back();
- return std::min(resWith, resWithout);
- }else{
- return trySet(tmp);
- }
-}
-
std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
std::vector< ArithVarVec > subsets;
Assert(d_soiVar == ARITHVAR_SENTINEL);
@@ -547,8 +710,6 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
underConstruction.push_back(v);
d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, v);
- bool uniqueChoices = true;
-
//cout << "trying " << v << endl;
const Tableau::Entry* spoiler = NULL;
@@ -559,7 +720,7 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
//cout << "looking for " << nb << " " << oppositeSgn << endl;
- ArithVar basicWithOp = find_basic_outside(sgns, nb, oppositeSgn, hasParticipated);
+ ArithVar basicWithOp = find_basic_in_sgns(sgns, nb, oppositeSgn, hasParticipated, false);
if(basicWithOp == ARITHVAR_SENTINEL){
//cout << "search did not work for " << nb << endl;
@@ -648,17 +809,26 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
d_soiVar = ARITHVAR_SENTINEL;
- vector<ArithVarVec> subsets = greedyConflictSubsets();
- Assert( d_soiVar == ARITHVAR_SENTINEL);
- Assert(!subsets.empty());
- for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
- const ArithVarVec& subset = *i;
- Node conflict = generateSOIConflict(subset);
+ if(options::soiQuickExplain()){
+ quickExplain();
+ Node conflict = generateSOIConflict(d_qeConflict);
//cout << conflict << endl;
-
- //reportConflict(conf); do not do this. We need a custom explanations!
d_conflictChannel(conflict);
+ }else{
+
+ vector<ArithVarVec> subsets = greedyConflictSubsets();
+ Assert( d_soiVar == ARITHVAR_SENTINEL);
+
+ Assert(!subsets.empty());
+ for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
+ const ArithVarVec& subset = *i;
+ Node conflict = generateSOIConflict(subset);
+ //cout << conflict << endl;
+
+ //reportConflict(conf); do not do this. We need a custom explanations!
+ d_conflictChannel(conflict);
+ }
}
Assert( d_soiVar == ARITHVAR_SENTINEL);
d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization);
@@ -703,7 +873,7 @@ WitnessImprovement SumOfInfeasibilitiesSPD::soiRound() {
}
bool SumOfInfeasibilitiesSPD::debugSOI(WitnessImprovement w, ostream& out, int instance) const{
-#warning "Redo SOI"
+//#warning "Redo SOI"
return true;
// out << "DLV("<<instance<<") ";
// switch(w){
diff --git a/src/theory/arith/soi_simplex.h b/src/theory/arith/soi_simplex.h
index 006839a55..de565df64 100644
--- a/src/theory/arith/soi_simplex.h
+++ b/src/theory/arith/soi_simplex.h
@@ -195,6 +195,19 @@ private:
IntStat& conflictStat = d_statistics.d_initialConflicts;
return standardProcessSignals(timer, conflictStat);
}
+
+ void quickExplain();
+ DenseSet d_qeInSoi;
+ DenseSet d_qeInUAndNotInSoi;
+ ArithVarVec d_qeConflict;
+ ArithVarVec d_qeGreedyOrder;
+ sgn_table d_qeSgns;
+
+ uint32_t quickExplainRec(uint32_t cEnd, uint32_t uEnd);
+ void qeAddRange(uint32_t begin, uint32_t end);
+ void qeRemoveRange(uint32_t begin, uint32_t end);
+ void qeSwapRange(uint32_t N, uint32_t r, uint32_t s);
+
unsigned trySet(const ArithVarVec& set);
unsigned tryAllSubsets(const ArithVarVec& set, unsigned depth, ArithVarVec& tmp);
diff --git a/src/theory/arith/tableau.cpp b/src/theory/arith/tableau.cpp
index c54b0857a..9d06fadc4 100644
--- a/src/theory/arith/tableau.cpp
+++ b/src/theory/arith/tableau.cpp
@@ -75,7 +75,7 @@ void Tableau::rowPivot(ArithVar basicOld, ArithVar basicNew, CoefficientChangeCa
d_basic2RowIndex.set(basicNew, rid);
d_rowIndex2basic.set(rid, basicNew);
- cb.swap(basicOld, basicNew, a_rs_sgn);
+ cb.multiplyRow(rid, -a_rs_sgn);
}
diff --git a/src/theory/arith/tableau.h b/src/theory/arith/tableau.h
index 8b6ef1df6..deed7e7be 100644
--- a/src/theory/arith/tableau.h
+++ b/src/theory/arith/tableau.h
@@ -72,8 +72,12 @@ public:
return getColumn(x).begin();
}
+ RowIterator ridRowIterator(RowIndex rid) const {
+ return getRow(rid).begin();
+ }
+
RowIterator basicRowIterator(ArithVar basic) const {
- return getRow(basicToRowIndex(basic)).begin();
+ return ridRowIterator(basicToRowIndex(basic));
}
const Entry& basicFindEntry(ArithVar basic, ArithVar col) const {
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index c0442da90..6c7f622ec 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -47,6 +47,7 @@ void TheoryArith::addSharedTerm(TNode n){
}
Node TheoryArith::ppRewrite(TNode atom) {
+ CodeTimer timer(d_ppRewriteTimer);
return d_internal->ppRewrite(atom);
}
@@ -86,6 +87,10 @@ EqualityStatus TheoryArith::getEqualityStatus(TNode a, TNode b) {
return d_internal->getEqualityStatus(a,b);
}
+Node TheoryArith::getModelValue(TNode var) {
+ return d_internal->getModelValue( var );
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index 10c79b293..451f1e8ff 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -42,6 +42,7 @@ private:
TheoryArithPrivate* d_internal;
+ KEEP_STATISTIC(TimerStat, d_ppRewriteTimer, "theory::arith::ppRewriteTimer");
public:
TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
@@ -73,6 +74,8 @@ public:
EqualityStatus getEqualityStatus(TNode a, TNode b);
void addSharedTerm(TNode n);
+
+ Node getModelValue(TNode var);
};/* class TheoryArith */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 263f9536b..9d13dccb7 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -67,6 +67,8 @@
#include "theory/arith/options.h"
+#include "theory/quantifiers/bounded_integers.h"
+
#include <stdint.h>
#include <vector>
@@ -83,12 +85,13 @@ namespace arith {
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
d_containing(containing),
d_nlIncomplete( false),
- d_boundTracking(),
+ d_rowTracking(),
d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
d_qflraStatus(Result::SAT_UNKNOWN),
d_unknownsInARow(0),
d_hasDoneWorkSinceCut(false),
d_learner(u),
+ d_quantEngine(qe),
d_assertionsThatDoNotMatchTheirLiterals(c),
d_nextIntegerCheckVar(0),
d_constantIntegerVariables(c),
@@ -96,9 +99,9 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
d_currentPropagationList(),
d_learnedBounds(c),
d_partialModel(c, DeltaComputeCallback(*this)),
- d_errorSet(d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(&d_boundTracking)),
+ d_errorSet(d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
d_tableau(),
- d_linEq(d_partialModel, d_tableau, d_boundTracking, BasicVarModelUpdateCallBack(*this)),
+ d_linEq(d_partialModel, d_tableau, d_rowTracking, BasicVarModelUpdateCallBack(*this)),
d_diosolver(c),
d_restartsCounter(0),
d_tableauSizeHasBeenModified(false),
@@ -107,15 +110,19 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
d_conflicts(c),
d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this)),
d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_pureUpdate(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
+ d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_DELTA_ZERO(0),
d_fullCheckCounter(0),
d_cutCount(c, 0),
d_cutInContext(c),
+ d_likelyIntegerInfeasible(c, false),
+ d_guessedCoeffSet(c, false),
+ d_guessedCoeffs(),
d_statistics()
{
+ srand(79);
}
TheoryArithPrivate::~TheoryArithPrivate(){ }
@@ -489,9 +496,7 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
}else if(!lb->negationHasProof()){
Constraint negLb = lb->getNegation();
negLb->impliedBy(constraint, diseq);
- //if(!negLb->canBePropagated()){
d_learnedBounds.push_back(negLb);
- //}//otherwise let this be propagated/asserted later
}
}
}
@@ -732,19 +737,155 @@ void TheoryArithPrivate::addSharedTerm(TNode n){
}
}
+Node TheoryArithPrivate::getModelValue(TNode term) {
+ try{
+ DeltaRational drv = getDeltaValue(term);
+ const Rational& delta = d_partialModel.getDelta();
+ Rational qmodel = drv.substituteDelta( delta );
+ return mkRationalNode( qmodel );
+ } catch (DeltaRationalException& dr) {
+ return Node::null();
+ } catch (ModelException& me) {
+ return Node::null();
+ }
+}
+
+namespace attr {
+ struct ToIntegerTag { };
+ struct LinearIntDivTag { };
+}/* CVC4::theory::arith::attr namespace */
+
+/**
+ * This attribute maps the child of a to_int / is_int to the
+ * corresponding integer skolem.
+ */
+typedef expr::Attribute<attr::ToIntegerTag, Node> ToIntegerAttr;
+
+/**
+ * This attribute maps division-by-constant-k terms to a variable
+ * used to eliminate them.
+ */
+typedef expr::Attribute<attr::LinearIntDivTag, Node> LinearIntDivAttr;
+
+Node TheoryArithPrivate::ppRewriteTerms(TNode n) {
+ if(Theory::theoryOf(n) != THEORY_ARITH) {
+ return n;
+ }
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ switch(Kind k = n.getKind()) {
+
+ case kind::TO_INTEGER:
+ case kind::IS_INTEGER: {
+ Node intVar;
+ if(!n[0].getAttribute(ToIntegerAttr(), intVar)) {
+ intVar = nm->mkSkolem("toInt", nm->integerType(), "a conversion of a Real term to its Integer part");
+ n[0].setAttribute(ToIntegerAttr(), intVar);
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LT, nm->mkNode(kind::MINUS, n[0], nm->mkConst(Rational(1))), intVar), nm->mkNode(kind::LEQ, intVar, n[0])));
+ }
+ if(n.getKind() == kind::TO_INTEGER) {
+ Node node = intVar;
+ return node;
+ } else {
+ Node node = nm->mkNode(kind::EQUAL, n[0], intVar);
+ return node;
+ }
+ Unreachable();
+ }
+
+ case kind::INTS_DIVISION:
+ case kind::INTS_DIVISION_TOTAL: {
+ if(!options::rewriteDivk()) {
+ return n;
+ }
+ Node num = Rewriter::rewrite(n[0]);
+ Node den = Rewriter::rewrite(n[1]);
+ if(den.isConst()) {
+ const Rational& rat = den.getConst<Rational>();
+ Assert(!num.isConst());
+ if(rat != 0) {
+ Node intVar;
+ Node rw = nm->mkNode(k, num, den);
+ if(!rw.getAttribute(LinearIntDivAttr(), intVar)) {
+ intVar = nm->mkSkolem("linearIntDiv", nm->integerType(), "the result of an intdiv-by-k term");
+ rw.setAttribute(LinearIntDivAttr(), intVar);
+ if(rat > 0) {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1)))))));
+ } else {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1)))))));
+ }
+ }
+ return intVar;
+ }
+ }
+ break;
+ }
+
+ case kind::INTS_MODULUS:
+ case kind::INTS_MODULUS_TOTAL: {
+ if(!options::rewriteDivk()) {
+ return n;
+ }
+ Node num = Rewriter::rewrite(n[0]);
+ Node den = Rewriter::rewrite(n[1]);
+ if(den.isConst()) {
+ const Rational& rat = den.getConst<Rational>();
+ Assert(!num.isConst());
+ if(rat != 0) {
+ Node intVar;
+ Node rw = nm->mkNode(k, num, den);
+ if(!rw.getAttribute(LinearIntDivAttr(), intVar)) {
+ intVar = nm->mkSkolem("linearIntDiv", nm->integerType(), "the result of an intdiv-by-k term");
+ rw.setAttribute(LinearIntDivAttr(), intVar);
+ if(rat > 0) {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1)))))));
+ } else {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1)))))));
+ }
+ }
+ Node node = nm->mkNode(kind::MINUS, num, nm->mkNode(kind::MULT, den, intVar));
+ return node;
+ }
+ }
+ break;
+ }
+
+ default:
+ ;
+ }
+
+ for(TNode::const_iterator i = n.begin(); i != n.end(); ++i) {
+ Node rewritten = ppRewriteTerms(*i);
+ if(rewritten != *i) {
+ NodeBuilder<> b(n.getKind());
+ b.append(n.begin(), i);
+ b << rewritten;
+ for(++i; i != n.end(); ++i) {
+ b << ppRewriteTerms(*i);
+ }
+ rewritten = b;
+ return rewritten;
+ }
+ }
+
+ return n;
+}
+
Node TheoryArithPrivate::ppRewrite(TNode atom) {
Debug("arith::preprocess") << "arith::preprocess() : " << atom << endl;
-
if (atom.getKind() == kind::EQUAL && options::arithRewriteEq()) {
Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
+ leq = ppRewriteTerms(leq);
+ geq = ppRewriteTerms(geq);
Node rewritten = Rewriter::rewrite(leq.andNode(geq));
Debug("arith::preprocess") << "arith::preprocess() : returning "
<< rewritten << endl;
return rewritten;
} else {
- return atom;
+ return ppRewriteTerms(atom);
}
}
@@ -897,7 +1038,7 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
// vl is the product of at least 2 variables
// vl : (* v1 v2 ...)
if(getLogicInfo().isLinear()){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic.");
}
setIncomplete();
@@ -934,7 +1075,7 @@ void TheoryArithPrivate::setupDivLike(const Variable& v){
Assert(v.isDivLike());
if(getLogicInfo().isLinear()){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ throw LogicException("A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic;\nif you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.");
}
Node vnode = v.getNode();
@@ -1100,7 +1241,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
ArithVar varSlack = requestArithVar(polyNode, true);
d_tableau.addRow(varSlack, coefficients, variables);
setupBasicValue(varSlack);
- d_linEq.trackVariable(varSlack);
+ d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
//Add differences to the difference manager
Polynomial::iterator i = poly.begin(), end = poly.end();
@@ -1156,16 +1297,22 @@ void TheoryArithPrivate::setupAtom(TNode atom) {
void TheoryArithPrivate::preRegisterTerm(TNode n) {
Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
- if(isRelationOperator(n.getKind())){
- if(!isSetup(n)){
- setupAtom(n);
+ try {
+ if(isRelationOperator(n.getKind())){
+ if(!isSetup(n)){
+ setupAtom(n);
+ }
+ Constraint c = d_constraintDatabase.lookup(n);
+ Assert(c != NullConstraint);
+
+ Debug("arith::preregister") << "setup constraint" << c << endl;
+ Assert(!c->canBePropagated());
+ c->setPreregistered();
}
- Constraint c = d_constraintDatabase.lookup(n);
- Assert(c != NullConstraint);
-
- Debug("arith::preregister") << "setup constraint" << c << endl;
- Assert(!c->canBePropagated());
- c->setPreregistered();
+ } catch(LogicException& le) {
+ std::stringstream ss;
+ ss << le.getMessage() << endl << "The fact in question: " << n << endl;
+ throw LogicException(ss.str());
}
Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl;
@@ -1176,82 +1323,33 @@ void TheoryArithPrivate::releaseArithVar(ArithVar v){
d_constraintDatabase.removeVariable(v);
d_partialModel.releaseArithVar(v);
- d_linEq.maybeRemoveTracking(v);
}
ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
//TODO : The VarList trick is good enough?
Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS);
if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ stringstream ss;
+ ss << "A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic: " << x << endl
+ << "if you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.";
+ throw LogicException(ss.str());
}
Assert(!d_partialModel.hasArithVar(x));
Assert(x.getType().isReal()); // real or integer
- // ArithVar varX = d_variables.size();
- // d_variables.push_back(Node(x));
-
ArithVar max = d_partialModel.getNumberOfVariables();
ArithVar varX = d_partialModel.allocate(x, slack);
bool reclaim = max >= d_partialModel.getNumberOfVariables();;
- if(reclaim){
- // varX = d_pool.back();
- // d_pool.pop_back();
-
- // d_partialModel.setAssignment(varX, d_DELTA_ZERO, d_DELTA_ZERO);
- }else{
- // varX = d_numberOfVariables;
- // ++d_numberOfVariables;
-
- // d_slackVars.push_back(true);
- // d_variableTypes.push_back(ATReal);
-
+ if(!reclaim){
d_dualSimplex.increaseMax();
d_tableau.increaseSize();
d_tableauSizeHasBeenModified = true;
-
- //d_partialModel.initialize(varX, d_DELTA_ZERO);
}
-
- // ArithType type;
- // if(slack){
- // //The type computation is not quite accurate for Rationals that are integral.
- // //We'll use the isIntegral check from the polynomial package instead.
- // Polynomial p = Polynomial::parsePolynomial(x);
- // type = p.isIntegral() ? ATInteger : ATReal;
- // }else{
- // type = nodeToArithType(x);
- // }
- // d_variableTypes[varX] = type;
- // d_slackVars[varX] = slack;
-
d_constraintDatabase.addVariable(varX);
- //d_partialModel.setArithVar(x,varX);
-
- // Debug("integers") << "isInteger[[" << x << "]]: " << x.getType().isInteger() << endl;
-
- // if(slack){
- // //The type computation is not quite accurate for Rationals that are integral.
- // //We'll use the isIntegral check from the polynomial package instead.
- // Polynomial p = Polynomial::parsePolynomial(x);
- // d_variableTypes.push_back(p.isIntegral() ? ATInteger : ATReal);
- // }else{
- // d_variableTypes.push_back(nodeToArithType(x));
- // }
-
- // d_slackVars.push_back(slack);
-
- // d_simplex.increaseMax();
-
- // d_tableau.increaseSize();
- // d_tableauSizeHasBeenModified = true;
-
- // d_constraintDatabase.addVariable(varX);
-
Debug("arith::arithvar") << x << " |-> " << varX << endl;
Assert(!d_partialModel.hasUpperBound(varX));
@@ -1423,6 +1521,10 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
Assert(!done());
TNode assertion = get();
+ if( options::finiteModelFind() && d_quantEngine && d_quantEngine->getBoundedIntegers() ){
+ d_quantEngine->getBoundedIntegers()->assertNode(assertion);
+ }
+
Kind simpleKind = Comparison::comparisonKind(assertion);
Constraint constraint = d_constraintDatabase.lookup(assertion);
if(constraint == NullConstraint){
@@ -1454,20 +1556,6 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
}
}
- // Kind simpleKind = Comparison::comparisonKind(assertion);
- // Assert(simpleKind != UNDEFINED_KIND);
- // Assert(constraint != NullConstraint ||
- // simpleKind == EQUAL ||
- // simpleKind == DISTINCT );
- // if(simpleKind == EQUAL || simpleKind == DISTINCT){
- // Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion;
-
- // if(!isSetup(eq)){
- // //The previous code was equivalent to:
- // setupAtom(eq);
- // constraint = d_constraintDatabase.lookup(assertion);
- // }
- // }
Assert(constraint != NullConstraint);
if(constraint->negationHasProof()){
@@ -1609,9 +1697,9 @@ void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
Assert(d_qflraStatus != Result::SAT);
- d_partialModel.stopQueueingAtBoundQueue();
+ d_partialModel.stopQueueingBoundCounts();
UpdateTrackingCallback utcb(&d_linEq);
- d_partialModel.processAtBoundQueue(utcb);
+ d_partialModel.processBoundsQueue(utcb);
d_linEq.startTrackingBoundCounts();
bool noPivotLimit = Theory::fullEffort(effortLevel) ||
@@ -1641,13 +1729,23 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
static const int32_t relaxationLimit = 10000;
static const int32_t mipLimit = 200000;
+ //cout << "start" << endl;
d_qflraStatus = simplex.findModel(false);
+ //cout << "end" << endl;
if(d_qflraStatus == Result::SAT_UNKNOWN ||
- (d_qflraStatus == Result::SAT && !hasIntegerModel())){
+ (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel);
approxSolver->setPivotLimit(relaxationLimit);
+ if(!d_guessedCoeffSet){
+ d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+ d_guessedCoeffSet = true;
+ }
+ if(!d_guessedCoeffs.empty()){
+ approxSolver->setOptCoeffs(d_guessedCoeffs);
+ }
+
ApproximateSimplex::ApproxResult relaxRes, mipRes;
ApproximateSimplex::Solution relaxSolution, mipSolution;
relaxRes = approxSolver->solveRelaxation();
@@ -1655,30 +1753,37 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
case ApproximateSimplex::ApproxSat:
{
relaxSolution = approxSolver->extractRelaxation();
- approxSolver->setPivotLimit(mipLimit);
- mipRes = approxSolver->solveMIP();
- d_errorSet.reduceToSignals();
- if(mipRes == ApproximateSimplex::ApproxSat){
- mipSolution = approxSolver->extractMIP();
- ApproximateSimplex::applySolution(d_linEq, mipSolution);
+
+ if(d_likelyIntegerInfeasible){
+ d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
}else{
- ApproximateSimplex::applySolution(d_linEq, relaxSolution);
- // if(d_qflraStatus != UNSAT){
- // d_likelyIntegerUnsat = true;
- // }
+ approxSolver->setPivotLimit(mipLimit);
+ mipRes = approxSolver->solveMIP();
+ d_errorSet.reduceToSignals();
+ //Message() << "here" << endl;
+ if(mipRes == ApproximateSimplex::ApproxSat){
+ mipSolution = approxSolver->extractMIP();
+ d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+ }else{
+ if(mipRes == ApproximateSimplex::ApproxUnsat){
+ d_likelyIntegerInfeasible = true;
+ }
+ d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+ }
}
options::arithStandardCheckVarOrderPivots.set(pass2Limit);
- d_qflraStatus = simplex.findModel(false);
+ if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+ //Message() << "done" << endl;
}
break;
case ApproximateSimplex::ApproxUnsat:
{
ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
- d_errorSet.reduceToSignals();
- ApproximateSimplex::applySolution(d_linEq, sol);
- options::arithStandardCheckVarOrderPivots.set(100);
- d_qflraStatus = simplex.findModel(false);
+ d_qflraStatus = d_attemptSolSimplex.attempt(sol);
+ options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+
+ if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
}
break;
default:
@@ -1688,11 +1793,14 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
}
if(d_qflraStatus == Result::SAT_UNKNOWN){
+ //Message() << "got sat unknown" << endl;
vector<ArithVar> toCut = cutAllBounded();
if(toCut.size() > 0){
branchVector(toCut);
emmittedConflictOrSplit = true;
}else{
+ //Message() << "splitting" << endl;
+
d_qflraStatus = simplex.findModel(noPivotLimit);
}
}
@@ -1701,7 +1809,7 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
// TODO Save zeroes with no conflicts
d_linEq.stopTrackingBoundCounts();
- d_partialModel.startQueueingAtBoundQueue();
+ d_partialModel.startQueueingBoundCounts();
return emmittedConflictOrSplit;
}
@@ -1765,7 +1873,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(Debug.isOn("arith::print_assertions")) {
- debugPrintAssertions();
+ debugPrintAssertions(Debug("arith::print_assertions"));
}
bool emmittedConflictOrSplit = false;
@@ -1911,7 +2019,6 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
emmittedConflictOrSplit = splitDisequalities();
}
- emmittedConflictOrSplit = false;
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
Node possibleConflict = Node::null();
@@ -1967,7 +2074,9 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("arith::print_model")) { debugPrintModel(); }
+ if(Debug.isOn("arith::print_model")) {
+ debugPrintModel(Debug("arith::print_model"));
+ }
Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
}
@@ -2088,37 +2197,38 @@ bool TheoryArithPrivate::splitDisequalities(){
* Should be guarded by at least Debug.isOn("arith::print_assertions").
* Prints to Debug("arith::print_assertions")
*/
-void TheoryArithPrivate::debugPrintAssertions() {
- Debug("arith::print_assertions") << "Assertions:" << endl;
+void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
+ out << "Assertions:" << endl;
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar i = *vi;
if (d_partialModel.hasLowerBound(i)) {
Constraint lConstr = d_partialModel.getLowerBoundConstraint(i);
- Debug("arith::print_assertions") << lConstr << endl;
+ out << lConstr << endl;
}
if (d_partialModel.hasUpperBound(i)) {
Constraint uConstr = d_partialModel.getUpperBoundConstraint(i);
- Debug("arith::print_assertions") << uConstr << endl;
+ out << uConstr << endl;
}
}
context::CDQueue<Constraint>::const_iterator it = d_diseqQueue.begin();
context::CDQueue<Constraint>::const_iterator it_end = d_diseqQueue.end();
for(; it != it_end; ++ it) {
- Debug("arith::print_assertions") << *it << endl;
+ out << *it << endl;
}
}
-void TheoryArithPrivate::debugPrintModel(){
- Debug("arith::print_model") << "Model:" << endl;
+void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
+ out << "Model:" << endl;
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar i = *vi;
if(d_partialModel.hasNode(i)){
- Debug("arith::print_model") << d_partialModel.asNode(i) << " : " <<
+ out << d_partialModel.asNode(i) << " : " <<
d_partialModel.getAssignment(i);
- if(d_tableau.isBasic(i))
- Debug("arith::print_model") << " (basic)";
- Debug("arith::print_model") << endl;
+ if(d_tableau.isBasic(i)){
+ out << " (basic)";
+ }
+ out << endl;
}
}
}
@@ -2161,7 +2271,11 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
(options::arithPropagationMode() == BOUND_INFERENCE_PROP ||
options::arithPropagationMode() == BOTH_PROP)
&& hasAnyUpdates()){
- propagateCandidates();
+ if(options::newProp()){
+ propagateCandidatesNew();
+ }else{
+ propagateCandidates();
+ }
}else{
clearUpdates();
}
@@ -2432,37 +2546,6 @@ void TheoryArithPrivate::notifyRestart(){
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
++d_restartsCounter;
-#warning "removing restart"
- // return;
-
- // uint32_t currSize = d_tableau.size();
- // uint32_t copySize = d_smallTableauCopy.size();
-
- // Debug("arith::reset") << "resetting" << d_restartsCounter << endl;
- // Debug("arith::reset") << "curr " << currSize << " copy " << copySize << endl;
- // Debug("arith::reset") << "tableauSizeHasBeenModified " << d_tableauSizeHasBeenModified << endl;
-
- // if(d_tableauSizeHasBeenModified){
- // Debug("arith::reset") << "row has been added must copy " << d_restartsCounter << endl;
- // d_smallTableauCopy = d_tableau;
- // d_tableauSizeHasBeenModified = false;
- // }else if( d_restartsCounter >= RESET_START){
- // if(copySize >= currSize * 1.1 ){
- // Debug("arith::reset") << "size has shrunk " << d_restartsCounter << endl;
- // ++d_statistics.d_smallerSetToCurr;
- // d_smallTableauCopy = d_tableau;
- // }else if(d_tableauResetDensity * copySize <= currSize){
- // d_errorSet.popAllSignals();
- // if(safeToReset()){
- // Debug("arith::reset") << "resetting " << d_restartsCounter << endl;
- // ++d_statistics.d_currSetToSmaller;
- // d_tableau = d_smallTableauCopy;
- // }else{
- // Debug("arith::reset") << "not safe to reset at the moment " << d_restartsCounter << endl;
- // }
- // }
- // }
- // Assert(unenqueuedVariablesAreConsistent());
}
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
@@ -2478,6 +2561,14 @@ bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
}
Warning() << endl;
result = false;
+ }else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){
+ d_partialModel.printModel(var);
+ Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var);
+ if(d_tableau.isBasic(var)){
+ Warning() << " (basic)";
+ }
+ Warning() << endl;
+ result = false;
}
}
return result;
@@ -2570,9 +2661,8 @@ EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) {
bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){
++d_statistics.d_boundComputations;
- DeltaRational bound = upperBound ?
- d_linEq.computeUpperBound(basic):
- d_linEq.computeLowerBound(basic);
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic);
if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) ||
(!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){
@@ -2620,28 +2710,44 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
}
if(!assertedToTheTheory && canBePropagated && !hasProof ){
- if(upperBound){
- Assert(bestImplied != d_partialModel.getUpperBoundConstraint(basic));
- d_linEq.propagateNonbasicsUpperBound(basic, bestImplied);
- }else{
- Assert(bestImplied != d_partialModel.getLowerBoundConstraint(basic));
- d_linEq.propagateNonbasicsLowerBound(basic, bestImplied);
- }
+ d_linEq.propagateBasicFromRow(bestImplied);
// I think this can be skipped if canBePropagated is true
//d_learnedBounds.push(bestImplied);
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "success " << bestImplied << endl;
+ d_partialModel.printModel(basic, Debug("arith::prop"));
+ }
return true;
}
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "failed " << basic << " " << bound << assertedToTheTheory << " " <<
+ canBePropagated << " " << hasProof << endl;
+ d_partialModel.printModel(basic, Debug("arith::prop"));
+ }
}
+ }else if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "false " << bound << " ";
+ d_partialModel.printModel(basic, Debug("arith::prop"));
}
return false;
}
void TheoryArithPrivate::propagateCandidate(ArithVar basic){
bool success = false;
- if(d_partialModel.strictlyAboveLowerBound(basic) && d_linEq.hasLowerBounds(basic)){
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+
+ bool tryLowerBound =
+ d_partialModel.strictlyAboveLowerBound(basic) &&
+ d_linEq.rowLacksBound(ridx, false, basic) == NULL;
+
+ bool tryUpperBound =
+ d_partialModel.strictlyBelowUpperBound(basic) &&
+ d_linEq.rowLacksBound(ridx, true, basic) == NULL;
+
+ if(tryLowerBound){
success |= propagateCandidateLowerBound(basic);
}
- if(d_partialModel.strictlyBelowUpperBound(basic) && d_linEq.hasUpperBounds(basic)){
+ if(tryUpperBound){
success |= propagateCandidateUpperBound(basic);
}
if(success){
@@ -2652,6 +2758,8 @@ void TheoryArithPrivate::propagateCandidate(ArithVar basic){
void TheoryArithPrivate::propagateCandidates(){
TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
+ Debug("arith::prop") << "propagateCandidates begin" << endl;
+
Assert(d_candidateBasics.empty());
if(d_updatedBounds.empty()){ return; }
@@ -2685,6 +2793,292 @@ void TheoryArithPrivate::propagateCandidates(){
Assert(d_tableau.isBasic(candidate));
propagateCandidate(candidate);
}
+ Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl;
+}
+
+void TheoryArithPrivate::propagateCandidatesNew(){
+ /* Four criteria must be met for progagation on a variable to happen using a row:
+ * 0: A new bound has to have been added to the row.
+ * 1: The hasBoundsCount for the row must be "full" or be full minus one variable
+ * (This is O(1) to check, but requires book keeping.)
+ * 2: The current assignment must be strictly smaller/greater than the current bound.
+ * assign(x) < upper(x)
+ * (This is O(1) to compute.)
+ * 3: There is a bound that is strictly smaller/greater than the current assignment.
+ * assign(x) < c for some x <= c literal
+ * (This is O(log n) to compute.)
+ * 4: The implied bound on x is strictly smaller/greater than the current bound.
+ * (This is O(n) to compute.)
+ */
+
+ TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
+ Debug("arith::prop") << "propagateCandidatesNew begin" << endl;
+
+ Assert(d_qflraStatus == Result::SAT);
+ if(d_updatedBounds.empty()){ return; }
+ dumpUpdatedBoundsToRows();
+ Assert(d_updatedBounds.empty());
+
+ if(!d_candidateRows.empty()){
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ }
+
+ while(!d_candidateRows.empty()){
+ RowIndex candidate = d_candidateRows.back();
+ d_candidateRows.pop_back();
+ propagateCandidateRow(candidate);
+ }
+ Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl;
+}
+
+bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
+ int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v)
+ : d_partialModel.cmpAssignmentLowerBound(v);
+ bool hasSlack = ub ? cmp < 0 : cmp > 0;
+ if(hasSlack){
+ ConstraintType t = ub ? UpperBound : LowerBound;
+ const DeltaRational& a = d_partialModel.getAssignment(v);
+
+ if(isInteger(v) && !a.isIntegral()){
+ return true;
+ }
+
+ Constraint strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
+ if(strongestPossible == NullConstraint){
+ return false;
+ }else{
+ bool assertedToTheTheory = strongestPossible->assertedToTheTheory();
+ bool canBePropagated = strongestPossible->canBePropagated();
+ bool hasProof = strongestPossible->hasProof();
+
+ return !assertedToTheTheory && canBePropagated && !hasProof;
+ }
+ }else{
+ return false;
+ }
+}
+
+bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){
+ Debug("arith::prop") << " attemptSingleton" << ridx;
+
+ const Tableau::Entry* ep;
+ ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL);
+ Assert(ep != NULL);
+
+ ArithVar v = ep->getColVar();
+ const Rational& coeff = ep->getCoefficient();
+
+ // 0 = c * v + \sum rest
+ // Suppose rowUp
+ // - c * v = \sum rest \leq D
+ // if c > 0, v \geq -D/c so !vUp
+ // if c < 0, v \leq -D/c so vUp
+ // Suppose not rowUp
+ // - c * v = \sum rest \geq D
+ // if c > 0, v \leq -D/c so vUp
+ // if c < 0, v \geq -D/c so !vUp
+ bool vUp = (rowUp == ( coeff.sgn() < 0));
+
+ Debug("arith::prop") << " " << rowUp << " " << v << " " << coeff << " " << vUp << endl;
+ Debug("arith::prop") << " " << propagateMightSucceed(v, vUp) << endl;
+
+ if(propagateMightSucceed(v, vUp)){
+ DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v);
+ DeltaRational bound = dr / (- coeff);
+ return tryToPropagate(ridx, rowUp, v, vUp, bound);
+ }
+ return false;
+}
+
+bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){
+ Debug("arith::prop") << " attemptFull" << ridx << endl;
+
+ vector<const Tableau::Entry*> candidates;
+
+ for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
+ const Tableau::Entry& e =*i;
+ const Rational& c = e.getCoefficient();
+ ArithVar v = e.getColVar();
+ bool vUp = (rowUp == (c.sgn() < 0));
+ if(propagateMightSucceed(v, vUp)){
+ candidates.push_back(&e);
+ }
+ }
+ if(candidates.empty()){ return false; }
+
+ const DeltaRational slack =
+ d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL);
+ bool any = false;
+ vector<const Tableau::Entry*>::const_iterator i, iend;
+ for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){
+ const Tableau::Entry* ep = *i;
+ const Rational& c = ep->getCoefficient();
+ ArithVar v = ep->getColVar();
+
+ // See the comment for attemptSingleton()
+ bool activeUp = (rowUp == (c.sgn() > 0));
+ bool vUb = (rowUp == (c.sgn() < 0));
+
+ const DeltaRational& activeBound = activeUp ?
+ d_partialModel.getUpperBound(v):
+ d_partialModel.getLowerBound(v);
+
+ DeltaRational contribution = activeBound * c;
+ DeltaRational impliedBound = (slack - contribution)/(-c);
+
+ bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound);
+ any |= success;
+ }
+ return any;
+}
+
+bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){
+
+ bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound):
+ d_partialModel.strictlyGreaterThanLowerBound(v, bound);
+ if(weaker){
+ ConstraintType t = vUb ? UpperBound : LowerBound;
+
+ if(isInteger(v)){
+ //cout << "maybe" << endl;
+ //cout << bound << endl;
+ }
+ Constraint implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
+ if(implied != NullConstraint){
+ return rowImplicationCanBeApplied(ridx, rowUp, implied);
+ }
+ }
+ return false;
+}
+
+Node flattenImplication(Node imp){
+ NodeBuilder<> nb(kind::OR);
+ Node left = imp[0];
+ Node right = imp[1];
+
+ if(left.getKind() == kind::AND){
+ for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) {
+ nb << (*i).negate();
+ }
+ }else{
+ nb << left.negate();
+ }
+
+ if(right.getKind() == kind::OR){
+ for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
+ nb << *i;
+ }
+ }else{
+ nb << right;
+ }
+
+ return nb;
+}
+
+bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint implied){
+ Assert(implied != NullConstraint);
+ ArithVar v = implied->getVariable();
+
+ bool assertedToTheTheory = implied->assertedToTheTheory();
+ bool canBePropagated = implied->canBePropagated();
+ bool hasProof = implied->hasProof();
+
+ Debug("arith::prop") << "arith::prop" << v
+ << " " << assertedToTheTheory
+ << " " << canBePropagated
+ << " " << hasProof
+ << endl;
+
+ if(implied->negationHasProof()){
+ Warning() << "the negation of " << implied << " : " << endl
+ << "has proof " << implied->getNegation() << endl
+ << implied->getNegation()->explainForConflict() << endl;
+ }
+
+ if(!assertedToTheTheory && canBePropagated && !hasProof ){
+ vector<Constraint> explain;
+ d_linEq.propagateRow(explain, ridx, rowUp, implied);
+ if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
+ Node implication = implied->makeImplication(explain);
+ Node clause = flattenImplication(implication);
+ outputLemma(clause);
+ }else{
+ implied->impliedBy(explain);
+ }
+ return true;
+ }
+
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop")
+ << "failed " << v << " " << assertedToTheTheory << " "
+ << canBePropagated << " " << hasProof << " " << implied << endl;
+ d_partialModel.printModel(v, Debug("arith::prop"));
+ }
+ return false;
+}
+
+double fRand(double fMin, double fMax)
+{
+ double f = (double)rand() / RAND_MAX;
+ return fMin + f * (fMax - fMin);
+}
+
+bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){
+ BoundCounts hasCount = d_linEq.hasBoundCount(ridx);
+ uint32_t rowLength = d_tableau.getRowLength(ridx);
+
+ bool success = false;
+ static int instance = 0;
+ ++instance;
+
+ Debug("arith::prop")
+ << "propagateCandidateRow " << instance << " attempt " << rowLength << " " << hasCount << endl;
+
+ if(rowLength >= options::arithPropagateMaxLength()){
+ if(fRand(0.0,1.0) >= double(options::arithPropagateMaxLength())/rowLength){
+ return false;
+ }
+ }
+
+ if(hasCount.lowerBoundCount() == rowLength){
+ success |= attemptFull(ridx, false);
+ }else if(hasCount.lowerBoundCount() + 1 == rowLength){
+ success |= attemptSingleton(ridx, false);
+ }
+
+ if(hasCount.upperBoundCount() == rowLength){
+ success |= attemptFull(ridx, true);
+ }else if(hasCount.upperBoundCount() + 1 == rowLength){
+ success |= attemptSingleton(ridx, true);
+ }
+ return success;
+}
+
+void TheoryArithPrivate::dumpUpdatedBoundsToRows(){
+ Assert(d_candidateRows.empty());
+ DenseSet::const_iterator i = d_updatedBounds.begin();
+ DenseSet::const_iterator end = d_updatedBounds.end();
+ for(; i != end; ++i){
+ ArithVar var = *i;
+ if(d_tableau.isBasic(var)){
+ RowIndex ridx = d_tableau.basicToRowIndex(var);
+ d_candidateRows.softAdd(ridx);
+ }else{
+ Tableau::ColIterator basicIter = d_tableau.colIterator(var);
+ for(; !basicIter.atEnd(); ++basicIter){
+ const Tableau::Entry& entry = *basicIter;
+ RowIndex ridx = entry.getRowIndex();
+ d_candidateRows.softAdd(ridx);
+ }
+ }
+ }
+ d_updatedBounds.purge();
+}
+
+const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ return d_rowTracking[ridx];
}
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h
index 7b37a813f..22fc8d4a7 100644
--- a/src/theory/arith/theory_arith_private.h
+++ b/src/theory/arith/theory_arith_private.h
@@ -58,7 +58,7 @@
#include "theory/arith/dual_simplex.h"
#include "theory/arith/fc_simplex.h"
#include "theory/arith/soi_simplex.h"
-#include "theory/arith/pure_update_simplex.h"
+#include "theory/arith/attempt_solution_simplex.h"
#include "theory/arith/constraint.h"
@@ -105,7 +105,7 @@ private:
// TODO A better would be:
//context::CDO<bool> d_nlIncomplete;
- BoundCountingVector d_boundTracking;
+ BoundInfoMap d_rowTracking;
/**
* The constraint database associated with the theory.
@@ -132,7 +132,8 @@ private:
/** Static learner. */
ArithStaticLearner d_learner;
-
+ /** quantifiers engine */
+ QuantifiersEngine * d_quantEngine;
//std::vector<ArithVar> d_pool;
public:
void releaseArithVar(ArithVar v);
@@ -316,9 +317,9 @@ private:
/** This implements the Simplex decision procedure. */
DualSimplexDecisionProcedure d_dualSimplex;
- PureUpdateSimplexDecisionProcedure d_pureUpdate;
FCSimplexDecisionProcedure d_fcSimplex;
SumOfInfeasibilitiesSPD d_soiSimplex;
+ AttemptSolutionSDP d_attemptSolSimplex;
bool solveRealRelaxation(Theory::Effort effortLevel);
@@ -345,7 +346,8 @@ private:
Node axiomIteForTotalDivision(Node div_tot);
Node axiomIteForTotalIntDivision(Node int_div_like);
-
+ // handle linear /, div, mod, and also is_int, to_int
+ Node ppRewriteTerms(TNode atom);
public:
TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
@@ -381,6 +383,8 @@ public:
void addSharedTerm(TNode n);
+ Node getModelValue(TNode var);
+
private:
/** The constant zero. */
@@ -430,6 +434,10 @@ public:
*/
ArithVar requestArithVar(TNode x, bool slack);
+public:
+ const BoundsInfo& boundsInfo(ArithVar basic) const;
+
+
private:
/** Initial (not context dependent) sets up for a variable.*/
void setupBasicValue(ArithVar x);
@@ -463,12 +471,25 @@ private:
/** Tracks the basic variables where propagation might be possible. */
DenseSet d_candidateBasics;
+ DenseSet d_candidateRows;
bool hasAnyUpdates() { return !d_updatedBounds.empty(); }
void clearUpdates();
void revertOutOfConflict();
+ void propagateCandidatesNew();
+ void dumpUpdatedBoundsToRows();
+ bool propagateCandidateRow(RowIndex rid);
+ bool propagateMightSucceed(ArithVar v, bool ub) const;
+ /** Attempt to perform a row propagation where there is at most 1 possible variable.*/
+ bool attemptSingleton(RowIndex ridx, bool rowUp);
+ /** Attempt to perform a row propagation where every variable is a potential candidate.*/
+ bool attemptFull(RowIndex ridx, bool rowUp);
+ bool tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUp, const DeltaRational& bound);
+ bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint bestImplied);
+
+
void propagateCandidates();
void propagateCandidate(ArithVar basic);
bool propagateCandidateBound(ArithVar basic, bool upperBound);
@@ -517,9 +538,9 @@ private:
std::vector<ArithVar>& variables);
/** Routine for debugging. Print the assertions the theory is aware of. */
- void debugPrintAssertions();
+ void debugPrintAssertions(std::ostream& out) const;
/** Debugging only routine. Prints the model. */
- void debugPrintModel();
+ void debugPrintModel(std::ostream& out) const;
inline LogicInfo getLogicInfo() const { return d_containing.getLogicInfo(); }
inline bool done() const { return d_containing.done(); }
@@ -553,6 +574,12 @@ private:
context::CDO<unsigned> d_cutCount;
context::CDHashSet<ArithVar, std::hash<ArithVar> > d_cutInContext;
+ context::CDO<bool> d_likelyIntegerInfeasible;
+
+
+ context::CDO<bool> d_guessedCoeffSet;
+ ArithRatPairVec d_guessedCoeffs;
+
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
diff --git a/src/theory/arith/theory_arith_type_rules.h b/src/theory/arith/theory_arith_type_rules.h
index cc8451f8b..45e18fe0d 100644
--- a/src/theory/arith/theory_arith_type_rules.h
+++ b/src/theory/arith/theory_arith_type_rules.h
@@ -62,12 +62,37 @@ public:
}
}
}
- Kind k = n.getKind();
- bool isDivision = k == kind::DIVISION || k == kind::DIVISION_TOTAL;
- return (isInteger && !isDivision ? integerType : realType);
+ switch(Kind k = n.getKind()) {
+ case kind::TO_REAL:
+ return realType;
+ case kind::TO_INTEGER:
+ return integerType;
+ default: {
+ bool isDivision = k == kind::DIVISION || k == kind::DIVISION_TOTAL;
+ return (isInteger && !isDivision ? integerType : realType);
+ }
+ }
}
};/* class ArithOperatorTypeRule */
+class IntOperatorTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator child_it = n.begin();
+ TNode::iterator child_it_end = n.end();
+ if(check) {
+ for(; child_it != child_it_end; ++child_it) {
+ TypeNode childType = (*child_it).getType(check);
+ if (!childType.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer subterm");
+ }
+ }
+ }
+ return nodeManager->integerType();
+ }
+};/* class IntOperatorTypeRule */
+
class ArithPredicateTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -87,6 +112,34 @@ public:
}
};/* class ArithPredicateTypeRule */
+class ArithUnaryPredicateTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isReal()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an arithmetic term");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class ArithUnaryPredicateTypeRule */
+
+class IntUnaryPredicateTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer term");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class IntUnaryPredicateTypeRule */
+
class SubrangeProperties {
public:
inline static Cardinality computeCardinality(TypeNode type) {
diff --git a/src/theory/arrays/Makefile.am b/src/theory/arrays/Makefile.am
index ec834522f..77f102cf8 100644
--- a/src/theory/arrays/Makefile.am
+++ b/src/theory/arrays/Makefile.am
@@ -16,9 +16,7 @@ libarrays_la_SOURCES = \
array_info.h \
array_info.cpp \
static_fact_manager.h \
- static_fact_manager.cpp \
- theory_arrays_model.h \
- theory_arrays_model.cpp
+ static_fact_manager.cpp
EXTRA_DIST = \
kinds
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 801893107..98346d0e3 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -21,7 +21,6 @@
#include <map>
#include "theory/rewriter.h"
#include "expr/command.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/model.h"
#include "theory/arrays/options.h"
#include "smt/logic_exception.h"
@@ -464,7 +463,9 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
case kind::STORE: {
// Invariant: array terms should be preregistered before being added to the equality engine
- Assert(!d_equalityEngine.hasTerm(node));
+ if (d_equalityEngine.hasTerm(node)) {
+ break;
+ }
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
TNode a = d_equalityEngine.getRepresentative(node[0]);
@@ -493,7 +494,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
case kind::STORE_ALL: {
throw LogicException("Array theory solver does not yet support assertions using constant array value");
- }
+ }
default:
// Variables etc
if (node.getType().isArray()) {
@@ -588,7 +589,10 @@ void TheoryArrays::computeCareGraph()
}
}
}
- if (options::arraysModelBased()) return;
+ if (options::arraysModelBased()) {
+ checkModel(EFFORT_COMBINATION);
+ return;
+ }
if (d_sharedTerms) {
vector< pair<TNode, TNode> > currentPairs;
@@ -1009,7 +1013,7 @@ void TheoryArrays::checkModel(Effort e)
Assert(d_skolemAssertions.empty());
Assert(d_lemmas.empty());
- if (fullEffort(e)) {
+ if (combination(e)) {
// Add constraints for shared terms
context::CDList<TNode>::const_iterator shared_it = shared_terms_begin(), shared_it_end = shared_terms_end(), shared_it2;
Node modelVal, modelVal2, d;
@@ -1061,9 +1065,10 @@ void TheoryArrays::checkModel(Effort e)
unsigned constraintIdx;
Node assertion, assertionToCheck;
vector<TNode> assumptions;
- // int numrestarts = 0;
- while (true) {
- // ++numrestarts;
+ int numrestarts = 0;
+ while (true || numrestarts < 1 || fullEffort(e) || combination(e)) {
+ ++numrestarts;
+ d_out->safePoint();
int level = getSatContext()->getLevel();
d_getModelValCache.clear();
for (constraintIdx = 0; constraintIdx < d_modelConstraints.size(); ++constraintIdx) {
@@ -1076,7 +1081,7 @@ void TheoryArrays::checkModel(Effort e)
if (constraintIdx == d_modelConstraints.size()) {
break;
}
-
+
if (assertion.getKind() == kind::EQUAL && assertion[0].getType().isArray()) {
assertionToCheck = solveWrite(expandStores(assertion[0], assumptions).eqNode(expandStores(assertion[1], assumptions)), true, true, false);
if (assertionToCheck.getKind() == kind::AND &&
@@ -1202,20 +1207,20 @@ void TheoryArrays::checkModel(Effort e)
}
{
// generate lemma
- // if (all.size() == 0) {
- // d_lemmas.push_back(decision.negate());
- // }
- // else {
- // NodeBuilder<> disjunction(kind::OR);
- // std::set<TNode>::const_iterator it = all.begin();
- // std::set<TNode>::const_iterator it_end = all.end();
- // while (it != it_end) {
- // disjunction << (*it).negate();
- // ++it;
- // }
- // disjunction << decision.negate();
- // d_lemmas.push_back(disjunction);
- // }
+ if (all.size() == 0) {
+ d_lemmas.push_back(decision.negate());
+ }
+ else {
+ NodeBuilder<> disjunction(kind::OR);
+ std::set<TNode>::const_iterator it = all.begin();
+ std::set<TNode>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ disjunction << (*it).negate();
+ ++it;
+ }
+ disjunction << decision.negate();
+ d_lemmas.push_back(disjunction);
+ }
}
d_equalityEngine.assertEquality(decision, eq, explanation);
if (!eq) decision = decision.notNode();
@@ -1268,6 +1273,13 @@ void TheoryArrays::checkModel(Effort e)
}
d_skolemIndex = d_skolemIndex + 1;
}
+ // Reregister stores
+ if (assertionToCheck != assertion &&
+ assertionToCheck.getKind() == kind::AND &&
+ assertionToCheck[assertionToCheck.getNumChildren()-1].getKind() == kind::EQUAL) {
+ TNode s = assertionToCheck[assertionToCheck.getNumChildren()-1][0];
+ preRegisterStores(s);
+ }
}
if (d_conflict) {
break;
@@ -1294,10 +1306,10 @@ void TheoryArrays::checkModel(Effort e)
d_skolemIndex = 0;
while (!d_lemmas.empty()) {
Debug("arrays-model-based") << "Sending lemma: " << d_lemmas.back() << endl;
- d_out->lemma(d_lemmas.back());
+ d_out->splitLemma(d_lemmas.back());
#ifdef CVC4_ASSERTIONS
- Assert(d_lemmasSaved.find(d_lemmas.back()) == d_lemmasSaved.end());
- d_lemmasSaved.insert(d_lemmas.back());
+ // Assert(d_lemmasSaved.find(d_lemmas.back()) == d_lemmasSaved.end());
+ // d_lemmasSaved.insert(d_lemmas.back());
#endif
d_lemmas.pop_back();
}
@@ -1416,7 +1428,7 @@ Node TheoryArrays::getModelValRec(TNode node)
}
++d_numGetModelValConflicts;
getSatContext()->pop();
- }
+ }
++te;
if (te.isFinished()) {
Assert(false);
@@ -1453,7 +1465,7 @@ bool TheoryArrays::hasLoop(TNode node, TNode target)
return true;
}
}
-
+
return false;
}
@@ -1633,9 +1645,14 @@ bool TheoryArrays::setModelVal(TNode node, TNode val, bool invert, bool explain,
return true;
}
}
- getSatContext()->push();
Node d = node.eqNode(val);
- d_decisions.push_back(invert ? d.notNode() : d);
+ Node r = Rewriter::rewrite(d);
+ if (r.isConst()) {
+ d_equalityEngine.assertEquality(d, r == d_true, d_true);
+ return ((r == d_true) == (!invert));
+ }
+ getSatContext()->push();
+ d_decisions.push_back(invert ? d.negate() : d);
d_equalityEngine.assertEquality(d, !invert, d_decisions.back());
Debug("arrays-model-based") << "Asserting " << d_decisions.back() << " with explanation " << d_decisions.back() << endl;
++d_numSetModelValSplits;
@@ -1667,7 +1684,7 @@ bool TheoryArrays::setModelVal(TNode node, TNode val, bool invert, bool explain,
d_decisions.pop_back();
d_permRef.push_back(explanation);
d = d.negate();
- Debug("arrays-model-based") << "Asserting learned literal " << d << " with explanation " << explanation << endl;
+ Debug("arrays-model-based") << "Asserting learned literal2 " << d << " with explanation " << explanation << endl;
bool eq = true;
if (d.getKind() == kind::NOT) {
d = d[0];
diff --git a/src/theory/arrays/theory_arrays_model.cpp b/src/theory/arrays/theory_arrays_model.cpp
deleted file mode 100644
index b5c81ef69..000000000
--- a/src/theory/arrays/theory_arrays_model.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/********************* */
-/*! \file theory_arrays_model.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 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 theory_arrays_model class
- **/
-
-#include "theory/theory_engine.h"
-#include "theory/arrays/theory_arrays_model.h"
-#include "theory/model.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::arrays;
-
-ArrayModel::ArrayModel( Node arr, TheoryModel* m ) : d_arr( arr ){
- d_base_arr = arr;
- while( d_base_arr.getKind()==STORE ){
- Node ri = m->getRepresentative( d_base_arr[1] );
- if( d_values.find( ri )==d_values.end() ){
- d_values[ ri ] = m->getRepresentative( d_base_arr[2] );
- }
- d_base_arr = d_base_arr[0];
- }
-}
-
-Node ArrayModel::getValue( TheoryModel* m, Node i ){
- i = m->getRepresentative( i );
- std::map< Node, Node >::iterator it = d_values.find( i );
- if( it!=d_values.end() ){
- return it->second;
- }else{
- return NodeManager::currentNM()->mkNode( SELECT, getArrayValue(), i );
- //return d_default_value; //TODO: guarantee I can return this here
- }
-}
-
-void ArrayModel::setValue( TheoryModel* m, Node i, Node e ){
- Node ri = m->getRepresentative( i );
- if( d_values.find( ri )==d_values.end() ){
- d_values[ ri ] = m->getRepresentative( e );
- }
-}
-
-void ArrayModel::setDefaultArray( Node arr ){
- d_base_arr = arr;
-}
-
-Node ArrayModel::getArrayValue(){
- Node curr = d_base_arr;
- for( std::map< Node, Node >::iterator it = d_values.begin(); it != d_values.end(); ++it ){
- curr = NodeManager::currentNM()->mkNode( STORE, curr, it->first, it->second );
- }
- return curr;
-}
diff --git a/src/theory/arrays/theory_arrays_model.h b/src/theory/arrays/theory_arrays_model.h
deleted file mode 100644
index 66dc80568..000000000
--- a/src/theory/arrays/theory_arrays_model.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/********************* */
-/*! \file theory_arrays_model.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief MODEL for theory of arrays
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY_ARRAYS_MODEL_H
-#define __CVC4__THEORY_ARRAYS_MODEL_H
-
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-class TheoryModel;
-
-namespace arrays {
-
-class ArrayModel{
-protected:
- /** the array this model is for */
- Node d_arr;
-public:
- ArrayModel(){}
- ArrayModel( Node arr, TheoryModel* m );
- ~ArrayModel() {}
-public:
- /** pre-defined values */
- std::map< Node, Node > d_values;
- /** base array */
- Node d_base_arr;
- /** get value, return arguments that the value depends on */
- Node getValue( TheoryModel* m, Node i );
- /** set value */
- void setValue( TheoryModel* m, Node i, Node e );
- /** set default */
- void setDefaultArray( Node arr );
-public:
- /** get array value */
- Node getArrayValue();
-};/* class ArrayModel */
-
-}
-}
-}
-
-#endif \ No newline at end of file
diff --git a/src/theory/arrays/theory_arrays_rewriter.h b/src/theory/arrays/theory_arrays_rewriter.h
index 18bbef8cf..5df06bda8 100644
--- a/src/theory/arrays/theory_arrays_rewriter.h
+++ b/src/theory/arrays/theory_arrays_rewriter.h
@@ -36,6 +36,10 @@ namespace attr {
typedef expr::Attribute<attr::ArrayConstantMostFrequentValueCountTag, uint64_t> ArrayConstantMostFrequentValueCountAttr;
typedef expr::Attribute<attr::ArrayConstantMostFrequentValueTag, Node> ArrayConstantMostFrequentValueAttr;
+static inline Node mkEqNode(Node a, Node b) {
+ return a.getType().isBoolean() ? a.iffNode(b) : a.eqNode(b);
+}
+
class TheoryArraysRewriter {
static Node normalizeConstant(TNode node) {
return normalizeConstant(node, node[1].getType().getCardinality());
@@ -244,7 +248,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -301,7 +305,7 @@ public:
val = false;
}
else {
- Node eqRewritten = Rewriter::rewrite(store[1].eqNode(index));
+ Node eqRewritten = Rewriter::rewrite(mkEqNode(store[1], index));
if (eqRewritten.getKind() != kind::CONST_BOOLEAN) {
Trace("arrays-postrewrite") << "Arrays::postRewrite returning " << node << std::endl;
return RewriteResponse(REWRITE_DONE, node);
@@ -340,7 +344,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -416,7 +420,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -466,7 +470,7 @@ public:
val = false;
}
else {
- Node eqRewritten = Rewriter::rewrite(store[1].eqNode(index));
+ Node eqRewritten = Rewriter::rewrite(mkEqNode(store[1], index));
if (eqRewritten.getKind() != kind::CONST_BOOLEAN) {
break;
}
diff --git a/src/theory/atom_requests.cpp b/src/theory/atom_requests.cpp
new file mode 100644
index 000000000..3d111f9f8
--- /dev/null
+++ b/src/theory/atom_requests.cpp
@@ -0,0 +1,62 @@
+#include "theory/atom_requests.h"
+
+using namespace CVC4;
+
+AtomRequests::AtomRequests(context::Context* context)
+: d_allRequests(context)
+, d_requests(context)
+, d_triggerToRequestMap(context)
+{}
+
+AtomRequests::element_index AtomRequests::getList(TNode trigger) const {
+ trigger_to_list_map::const_iterator find = d_triggerToRequestMap.find(trigger);
+ if (find == d_triggerToRequestMap.end()) {
+ return null_index;
+ } else {
+ return (*find).second;
+ }
+}
+
+bool AtomRequests::isTrigger(TNode atom) const {
+ return getList(atom) != null_index;
+}
+
+AtomRequests::atom_iterator AtomRequests::getAtomIterator(TNode trigger) const {
+ return atom_iterator(*this, getList(trigger));
+}
+
+void AtomRequests::add(TNode triggerAtom, TNode atomToSend, theory::TheoryId toTheory) {
+
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << ")" << std::endl;
+
+ Request request(atomToSend, toTheory);
+
+ if (d_allRequests.find(request) != d_allRequests.end()) {
+ // Have it already
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << "): already there" << std::endl;
+ return;
+ }
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << "): adding" << std::endl;
+
+ /// Mark the new request
+ d_allRequests.insert(request);
+
+ // Index of the new request in the list of trigger
+ element_index index = d_requests.size();
+ element_index previous = getList(triggerAtom);
+ d_requests.push_back(Element(request, previous));
+ d_triggerToRequestMap[triggerAtom] = index;
+}
+
+bool AtomRequests::atom_iterator::done() const {
+ return index == null_index;
+}
+
+void AtomRequests::atom_iterator::next() {
+ index = requests.d_requests[index].previous;
+}
+
+const AtomRequests::Request& AtomRequests::atom_iterator::get() const {
+ return requests.d_requests[index].request;
+}
+
diff --git a/src/theory/atom_requests.h b/src/theory/atom_requests.h
new file mode 100644
index 000000000..99878125a
--- /dev/null
+++ b/src/theory/atom_requests.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "expr/node.h"
+#include "theory/theory.h"
+#include "context/cdlist.h"
+#include "context/cdhashset.h"
+#include "context/cdhashmap.h"
+
+namespace CVC4 {
+
+class AtomRequests {
+
+public:
+
+ /** Which atom and where to send it */
+ struct Request {
+ /** Atom */
+ Node atom;
+ /** Where to send it */
+ theory::TheoryId toTheory;
+
+ Request(TNode atom, theory::TheoryId toTheory)
+ : atom(atom), toTheory(toTheory) {}
+ Request()
+ : toTheory(theory::THEORY_LAST)
+ {}
+
+ bool operator == (const Request& other) const {
+ return atom == other.atom && toTheory == other.toTheory;
+ }
+
+ size_t hash() const {
+ return atom.getId();
+ }
+
+ };
+
+ AtomRequests(context::Context* context);
+
+ /** Mark the atom to be sent to a theory, when the trigger atom gets assigned */
+ void add(TNode triggerAtom, TNode atomToSend, theory::TheoryId toTheory);
+
+ /** Returns true if the node is a trigger and has a list of atoms to send */
+ bool isTrigger(TNode atom) const;
+
+ /** Indices in lists */
+ typedef size_t element_index;
+
+ class atom_iterator {
+ const AtomRequests& requests;
+ element_index index;
+ friend class AtomRequests;
+ atom_iterator(const AtomRequests& requests, element_index start)
+ : requests(requests), index(start) {}
+ public:
+ /** Is this iterator done */
+ bool done() const;
+ /** Go to the next element */
+ void next();
+ /** Get the actual request */
+ const Request& get() const;
+ };
+
+ atom_iterator getAtomIterator(TNode trigger) const;
+
+private:
+
+ struct RequestHashFunction {
+ size_t operator () (const Request& r) const {
+ return r.hash();
+ }
+ };
+
+ /** Set of all requests so we don't add twice */
+ context::CDHashSet<Request, RequestHashFunction> d_allRequests;
+
+ static const element_index null_index = -1;
+
+ struct Element {
+ /** Current request */
+ Request request;
+ /** Previous request */
+ element_index previous;
+
+ Element(const Request& request, element_index previous)
+ : request(request), previous(previous)
+ {}
+ };
+
+ /** We index the requests in this vector, it's a list */
+ context::CDList<Element> d_requests;
+
+ typedef context::CDHashMap<Node, element_index, NodeHashFunction> trigger_to_list_map;
+
+ /** Map from triggers, to the list of elements they trigger */
+ trigger_to_list_map d_triggerToRequestMap;
+
+ /** Get the list index of the trigger */
+ element_index getList(TNode trigger) const;
+
+};
+
+}
+
+
+
+
diff --git a/src/theory/booleans/theory_bool.cpp b/src/theory/booleans/theory_bool.cpp
index 3e75dd258..895f4a279 100644
--- a/src/theory/booleans/theory_bool.cpp
+++ b/src/theory/booleans/theory_bool.cpp
@@ -19,6 +19,7 @@
#include "theory/booleans/circuit_propagator.h"
#include "theory/valuation.h"
#include "util/boolean_simplification.h"
+#include "theory/substitutions.h"
#include <vector>
#include <stack>
diff --git a/src/theory/builtin/kinds b/src/theory/builtin/kinds
index fca79aff0..b51feea6d 100644
--- a/src/theory/builtin/kinds
+++ b/src/theory/builtin/kinds
@@ -300,7 +300,12 @@ operator SEXPR 0: "a symbolic expression"
operator LAMBDA 2 "lambda"
-parameterized CHAIN BUILTIN 2: "chain operator"
+parameterized CHAIN CHAIN_OP 2: "chained operator"
+constant CHAIN_OP \
+ ::CVC4::Chain \
+ ::CVC4::ChainHashFunction \
+ "util/chain.h" \
+ "the chained operator"
constant TYPE_CONSTANT \
::CVC4::TypeConstant \
@@ -321,29 +326,13 @@ well-founded SEXPR_TYPE \
"::CVC4::theory::builtin::SExprProperties::mkGroundTerm(%TYPE%)" \
"theory/builtin/theory_builtin_type_rules.h"
-# These will eventually move to a theory of strings.
-#
-# For now these are unbounded strings over a fixed, finite alphabet
-# (this may change).
-sort STRING_TYPE \
- Cardinality::INTEGERS \
- well-founded \
- "NodeManager::currentNM()->mkConst(::std::string())" \
- "string" \
- "String type"
-constant CONST_STRING \
- ::std::string \
- ::CVC4::StringHashFunction \
- "util/hash.h" \
- "a string of characters"
-typerule CONST_STRING ::CVC4::theory::builtin::StringConstantTypeRule
-
typerule APPLY ::CVC4::theory::builtin::ApplyTypeRule
typerule EQUAL ::CVC4::theory::builtin::EqualityTypeRule
typerule DISTINCT ::CVC4::theory::builtin::DistinctTypeRule
typerule SEXPR ::CVC4::theory::builtin::SExprTypeRule
typerule LAMBDA ::CVC4::theory::builtin::LambdaTypeRule
typerule CHAIN ::CVC4::theory::builtin::ChainTypeRule
+typerule CHAIN_OP ::CVC4::theory::builtin::ChainedOperatorTypeRule
constant SUBTYPE_TYPE \
::CVC4::Predicate \
diff --git a/src/theory/builtin/theory_builtin_rewriter.cpp b/src/theory/builtin/theory_builtin_rewriter.cpp
index 4d62ce511..392e146ba 100644
--- a/src/theory/builtin/theory_builtin_rewriter.cpp
+++ b/src/theory/builtin/theory_builtin_rewriter.cpp
@@ -16,6 +16,7 @@
**/
#include "theory/builtin/theory_builtin_rewriter.h"
+#include "util/chain.h"
using namespace std;
@@ -53,7 +54,7 @@ Node TheoryBuiltinRewriter::blastChain(TNode in) {
Assert(in.getKind() == kind::CHAIN);
- Kind chainedOp = in.getOperator().getConst<Kind>();
+ Kind chainedOp = in.getOperator().getConst<Chain>().getOperator();
if(in.getNumChildren() == 2) {
// if this is the case exactly 1 pair will be generated so the
diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h
index 2a4e07528..c7143bdeb 100644
--- a/src/theory/builtin/theory_builtin_type_rules.h
+++ b/src/theory/builtin/theory_builtin_type_rules.h
@@ -146,14 +146,6 @@ public:
}
};/* class AbstractValueTypeRule */
-class StringConstantTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
- Assert(n.getKind() == kind::CONST_STRING);
- return nodeManager->stringType();
- }
-};/* class StringConstantTypeRule */
-
class LambdaTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
@@ -220,6 +212,14 @@ public:
}
};/* class ChainTypeRule */
+class ChainedOperatorTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
+ Assert(n.getKind() == kind::CHAIN_OP);
+ return nodeManager->getType(nodeManager->operatorOf(n.getConst<Chain>().getOperator()), check);
+ }
+};/* class ChainedOperatorTypeRule */
+
class SortProperties {
public:
inline static bool isWellFounded(TypeNode type) {
diff --git a/src/theory/bv/bitblaster.cpp b/src/theory/bv/bitblaster.cpp
index 8579012ab..d17dd588f 100644
--- a/src/theory/bv/bitblaster.cpp
+++ b/src/theory/bv/bitblaster.cpp
@@ -12,7 +12,7 @@
** \brief [[ Add one-line brief description here ]]
**
** [[ Add lengthier description here ]]
- **
+ **
**/
#include "bitblaster.h"
@@ -29,7 +29,7 @@
using namespace std;
using namespace CVC4::theory::bv::utils;
-using namespace CVC4::context;
+using namespace CVC4::context;
using namespace CVC4::prop;
namespace CVC4 {
@@ -37,20 +37,20 @@ namespace theory {
namespace bv{
std::string toString(Bits& bits) {
- ostringstream os;
+ ostringstream os;
for (int i = bits.size() - 1; i >= 0; --i) {
TNode bit = bits[i];
if (bit.getKind() == kind::CONST_BOOLEAN) {
os << (bit.getConst<bool>() ? "1" : "0");
} else {
- os << bit<< " ";
+ os << bit<< " ";
}
}
os <<"\n";
-
- return os.str();
+
+ return os.str();
}
-/////// Bitblaster
+/////// Bitblaster
Bitblaster::Bitblaster(context::Context* c, bv::TheoryBV* bv) :
d_bv(bv),
@@ -64,38 +64,41 @@ Bitblaster::Bitblaster(context::Context* c, bv::TheoryBV* bv) :
d_cnfStream = new TseitinCnfStream(d_satSolver, new NullRegistrar(), new Context());
MinisatNotify* notify = new MinisatNotify(d_cnfStream, bv);
- d_satSolver->setNotify(notify);
+ d_satSolver->setNotify(notify);
// initializing the bit-blasting strategies
- initAtomBBStrategies();
- initTermBBStrategies();
+ initAtomBBStrategies();
+ initTermBBStrategies();
}
Bitblaster::~Bitblaster() {
delete d_cnfStream;
- delete d_satSolver;
+ delete d_satSolver;
}
-/**
+/**
* Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
* NOTE: duplicate clauses are not detected because of marker literal
* @param node the atom to be bitblasted
- *
+ *
*/
void Bitblaster::bbAtom(TNode node) {
node = node.getKind() == kind::NOT? node[0] : node;
-
+
if (hasBBAtom(node)) {
- return;
+ return;
}
// make sure it is marked as an atom
- addAtom(node);
+ addAtom(node);
- Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+ Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
++d_statistics.d_numAtoms;
// the bitblasted definition of the atom
- Node atom_bb = Rewriter::rewrite(d_atomBBStrategies[node.getKind()](node, this));
+ Node normalized = Rewriter::rewrite(node);
+ Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
+ Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
+ normalized;
// asserting that the atom is true iff the definition holds
Node atom_definition = mkNode(kind::IFF, node, atom_bb);
@@ -123,14 +126,14 @@ void Bitblaster::bbTerm(TNode node, Bits& bits) {
return;
}
- Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+ Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
++d_statistics.d_numTerms;
d_termBBStrategies[node.getKind()] (node, bits,this);
-
+
Assert (bits.size() == utils::getSize(node));
- cacheTermDef(node, bits);
+ cacheTermDef(node, bits);
}
Node Bitblaster::bbOptimize(TNode node) {
@@ -139,21 +142,21 @@ Node Bitblaster::bbOptimize(TNode node) {
if (node.getKind() == kind::BITVECTOR_PLUS) {
if (RewriteRule<BBPlusNeg>::applies(node)) {
Node res = RewriteRule<BBPlusNeg>::run<false>(node);
- return res;
+ return res;
}
// if (RewriteRule<BBFactorOut>::applies(node)) {
// Node res = RewriteRule<BBFactorOut>::run<false>(node);
- // return res;
- // }
+ // return res;
+ // }
} else if (node.getKind() == kind::BITVECTOR_MULT) {
if (RewriteRule<MultPow2>::applies(node)) {
Node res = RewriteRule<MultPow2>::run<false>(node);
- return res;
+ return res;
}
}
-
- return node;
+
+ return node;
}
/// Public methods
@@ -170,31 +173,31 @@ void Bitblaster::explain(TNode atom, std::vector<TNode>& explanation) {
std::vector<SatLiteral> literal_explanation;
d_satSolver->explain(d_cnfStream->getLiteral(atom), literal_explanation);
for (unsigned i = 0; i < literal_explanation.size(); ++i) {
- explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
+ explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
}
}
-/**
+/*
* Asserts the clauses corresponding to the atom to the Sat Solver
* by turning on the marker literal (i.e. setting it to false)
* @param node the atom to be asserted
- *
+ *
*/
-
+
bool Bitblaster::propagate() {
return d_satSolver->propagate() == prop::SAT_VALUE_TRUE;
}
bool Bitblaster::assertToSat(TNode lit, bool propagate) {
// strip the not
- TNode atom;
+ TNode atom;
if (lit.getKind() == kind::NOT) {
- atom = lit[0];
+ atom = lit[0];
} else {
- atom = lit;
+ atom = lit;
}
-
+
Assert (hasBBAtom(atom));
SatLiteral markerLit = d_cnfStream->getLiteral(atom);
@@ -202,9 +205,9 @@ bool Bitblaster::assertToSat(TNode lit, bool propagate) {
if(lit.getKind() == kind::NOT) {
markerLit = ~markerLit;
}
-
+
Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat asserting node: " << atom <<"\n";
- Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat with literal: " << markerLit << "\n";
+ Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat with literal: " << markerLit << "\n";
SatValue ret = d_satSolver->assertAssumption(markerLit, propagate);
@@ -214,13 +217,13 @@ bool Bitblaster::assertToSat(TNode lit, bool propagate) {
return ret == prop::SAT_VALUE_TRUE;
}
-/**
- * Calls the solve method for the Sat Solver.
+/**
+ * Calls the solve method for the Sat Solver.
* passing it the marker literals to be asserted
- *
+ *
* @return true for sat, and false for unsat
*/
-
+
bool Bitblaster::solve(bool quick_solve) {
if (Trace.isOn("bitvector")) {
Trace("bitvector") << "Bitblaster::solve() asserted atoms ";
@@ -229,24 +232,24 @@ bool Bitblaster::solve(bool quick_solve) {
Trace("bitvector") << " " << d_cnfStream->getNode(*it) << "\n";
}
}
- Debug("bitvector") << "Bitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
- return SAT_VALUE_TRUE == d_satSolver->solve();
+ Debug("bitvector") << "Bitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
+ return SAT_VALUE_TRUE == d_satSolver->solve();
}
void Bitblaster::getConflict(std::vector<TNode>& conflict) {
SatClause conflictClause;
d_satSolver->getUnsatCore(conflictClause);
-
+
for (unsigned i = 0; i < conflictClause.size(); i++) {
- SatLiteral lit = conflictClause[i];
+ SatLiteral lit = conflictClause[i];
TNode atom = d_cnfStream->getNode(lit);
- Node not_atom;
+ Node not_atom;
if (atom.getKind() == kind::NOT) {
not_atom = atom[0];
} else {
- not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
+ not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
}
- conflict.push_back(not_atom);
+ conflict.push_back(not_atom);
}
}
@@ -256,9 +259,9 @@ void Bitblaster::getConflict(std::vector<TNode>& conflict) {
void Bitblaster::initAtomBBStrategies() {
for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
- d_atomBBStrategies[i] = UndefinedAtomBBStrategy;
+ d_atomBBStrategies[i] = UndefinedAtomBBStrategy;
}
-
+
/// setting default bb strategies for atoms
d_atomBBStrategies [ kind::EQUAL ] = DefaultEqBB;
d_atomBBStrategies [ kind::BITVECTOR_ULT ] = DefaultUltBB;
@@ -269,7 +272,7 @@ void Bitblaster::initAtomBBStrategies() {
d_atomBBStrategies [ kind::BITVECTOR_SLE ] = DefaultSleBB;
d_atomBBStrategies [ kind::BITVECTOR_SGT ] = DefaultSgtBB;
d_atomBBStrategies [ kind::BITVECTOR_SGE ] = DefaultSgeBB;
-
+
}
void Bitblaster::initTermBBStrategies() {
@@ -278,7 +281,7 @@ void Bitblaster::initTermBBStrategies() {
for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
d_termBBStrategies[i] = DefaultVarBB;
}
-
+
/// setting default bb strategies for terms:
// d_termBBStrategies [ kind::VARIABLE ] = DefaultVarBB;
d_termBBStrategies [ kind::CONST_BITVECTOR ] = DefaultConstBB;
@@ -295,13 +298,13 @@ void Bitblaster::initTermBBStrategies() {
d_termBBStrategies [ kind::BITVECTOR_PLUS ] = DefaultPlusBB;
d_termBBStrategies [ kind::BITVECTOR_SUB ] = DefaultSubBB;
d_termBBStrategies [ kind::BITVECTOR_NEG ] = DefaultNegBB;
- d_termBBStrategies [ kind::BITVECTOR_UDIV ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_UREM ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_UDIV ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_UREM ] = UndefinedTermBBStrategy;
d_termBBStrategies [ kind::BITVECTOR_UDIV_TOTAL ] = DefaultUdivBB;
d_termBBStrategies [ kind::BITVECTOR_UREM_TOTAL ] = DefaultUremBB;
- d_termBBStrategies [ kind::BITVECTOR_SDIV ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_SREM ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_SMOD ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SDIV ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SREM ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SMOD ] = UndefinedTermBBStrategy;
d_termBBStrategies [ kind::BITVECTOR_SHL ] = DefaultShlBB;
d_termBBStrategies [ kind::BITVECTOR_LSHR ] = DefaultLshrBB;
d_termBBStrategies [ kind::BITVECTOR_ASHR ] = DefaultAshrBB;
@@ -313,22 +316,22 @@ void Bitblaster::initTermBBStrategies() {
d_termBBStrategies [ kind::BITVECTOR_ROTATE_LEFT ] = DefaultRotateLeftBB;
}
-
+
bool Bitblaster::hasBBAtom(TNode atom) const {
return d_bitblastedAtoms.find(atom) != d_bitblastedAtoms.end();
}
void Bitblaster::cacheTermDef(TNode term, Bits def) {
Assert (d_termCache.find(term) == d_termCache.end());
- d_termCache[term] = def;
+ d_termCache[term] = def;
}
bool Bitblaster::hasBBTerm(TNode node) const {
- return d_termCache.find(node) != d_termCache.end();
+ return d_termCache.find(node) != d_termCache.end();
}
void Bitblaster::getBBTerm(TNode node, Bits& bits) const {
- Assert (hasBBTerm(node));
+ Assert (hasBBTerm(node));
// copy?
bits = d_termCache.find(node)->second;
}
@@ -337,7 +340,7 @@ Bitblaster::Statistics::Statistics() :
d_numTermClauses("theory::bv::NumberOfTermSatClauses", 0),
d_numAtomClauses("theory::bv::NumberOfAtomSatClauses", 0),
d_numTerms("theory::bv::NumberOfBitblastedTerms", 0),
- d_numAtoms("theory::bv::NumberOfBitblastedAtoms", 0),
+ d_numAtoms("theory::bv::NumberOfBitblastedAtoms", 0),
d_bitblastTimer("theory::bv::BitblastTimer")
{
StatisticsRegistry::registerStat(&d_numTermClauses);
@@ -374,7 +377,7 @@ void Bitblaster::MinisatNotify::notify(prop::SatClause& clause) {
};
void Bitblaster::MinisatNotify::safePoint() {
- d_bv->d_out->safePoint();
+ d_bv->d_out->safePoint();
}
EqualityStatus Bitblaster::getEqualityStatus(TNode a, TNode b) {
@@ -417,70 +420,77 @@ EqualityStatus Bitblaster::getEqualityStatus(TNode a, TNode b) {
bool Bitblaster::isSharedTerm(TNode node) {
- return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
+ return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
}
bool Bitblaster::hasValue(TNode a) {
- Assert (d_termCache.find(a) != d_termCache.end());
+ Assert (d_termCache.find(a) != d_termCache.end());
Bits bits = d_termCache[a];
for (int i = bits.size() -1; i >= 0; --i) {
- SatValue bit_value;
- if (d_cnfStream->hasLiteral(bits[i])) {
+ SatValue bit_value;
+ if (d_cnfStream->hasLiteral(bits[i])) {
SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
bit_value = d_satSolver->value(bit);
if (bit_value == SAT_VALUE_UNKNOWN)
- return false;
+ return false;
} else {
- return false;
+ return false;
}
}
- return true;
+ return true;
}
-/**
+/**
* Returns the value a is currently assigned to in the SAT solver
- * or null if the value is completely unassigned.
- *
- * @param a
- *
- * @return
+ * or null if the value is completely unassigned.
+ *
+ * @param a
+ * @param fullModel whether to create a "full model," i.e., add
+ * constants to equivalence classes that don't already have them
+ *
+ * @return
*/
-Node Bitblaster::getVarValue(TNode a) {
+Node Bitblaster::getVarValue(TNode a, bool fullModel) {
if (d_termCache.find(a) == d_termCache.end()) {
Assert(isSharedTerm(a));
- return Node();
+ return Node();
}
Bits bits = d_termCache[a];
- Integer value(0);
+ Integer value(0);
for (int i = bits.size() -1; i >= 0; --i) {
SatValue bit_value;
- if (d_cnfStream->hasLiteral(bits[i])) {
+ if (d_cnfStream->hasLiteral(bits[i])) {
SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
bit_value = d_satSolver->value(bit);
- Assert (bit_value != SAT_VALUE_UNKNOWN);
+ Assert (bit_value != SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ //TODO: return Node() if fullModel=false?
+ // the bit is unconstrainted so we can give it an arbitrary value
bit_value = SAT_VALUE_FALSE;
}
- Integer bit_int = bit_value == SAT_VALUE_TRUE ? Integer(1) : Integer(0);
- value = value * 2 + bit_int;
+ Integer bit_int = bit_value == SAT_VALUE_TRUE ? Integer(1) : Integer(0);
+ value = value * 2 + bit_int;
}
- return utils::mkConst(BitVector(bits.size(), value));
+ return utils::mkConst(BitVector(bits.size(), value));
}
-void Bitblaster::collectModelInfo(TheoryModel* m) {
+void Bitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
__gnu_cxx::hash_set<TNode, TNodeHashFunction>::iterator it = d_variables.begin();
for (; it!= d_variables.end(); ++it) {
TNode var = *it;
if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) {
- Node const_value = getVarValue(var);
+ Node const_value = getVarValue(var, fullModel);
if(const_value == Node()) {
- // if the value is unassigned just set it to zero
- const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
+ if( fullModel ){
+ // if the value is unassigned just set it to zero
+ const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
+ }
+ }
+ if(const_value != Node()) {
+ Debug("bitvector-model") << "Bitblaster::collectModelInfo (assert (= "
+ << var << " "
+ << const_value << "))\n";
+ m->assertEquality(var, const_value, true);
}
- Debug("bitvector-model") << "Bitblaster::collectModelInfo (assert (= "
- << var << " "
- << const_value << "))\n";
- m->assertEquality(var, const_value, true);
}
}
}
diff --git a/src/theory/bv/bitblaster.h b/src/theory/bv/bitblaster.h
index c122c407d..6fab0369c 100644
--- a/src/theory/bv/bitblaster.h
+++ b/src/theory/bv/bitblaster.h
@@ -55,14 +55,14 @@ namespace bv {
typedef std::vector<Node> Bits;
-std::string toString (Bits& bits);
+std::string toString (Bits& bits);
class TheoryBV;
-/**
- * The Bitblaster that manages the mapping between Nodes
- * and their bitwise definition
- *
+/**
+ * The Bitblaster that manages the mapping between Nodes
+ * and their bitwise definition
+ *
*/
class Bitblaster {
@@ -79,26 +79,26 @@ class Bitblaster {
void notify(prop::SatClause& clause);
void safePoint();
};
-
-
+
+
typedef __gnu_cxx::hash_map <Node, Bits, TNodeHashFunction > TermDefMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> AtomSet;
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> VarSet;
-
- typedef void (*TermBBStrategy) (TNode, Bits&, Bitblaster*);
- typedef Node (*AtomBBStrategy) (TNode, Bitblaster*);
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> VarSet;
+
+ typedef void (*TermBBStrategy) (TNode, Bits&, Bitblaster*);
+ typedef Node (*AtomBBStrategy) (TNode, Bitblaster*);
TheoryBV *d_bv;
-
+
// sat solver used for bitblasting and associated CnfStream
theory::OutputChannel* d_bvOutput;
- prop::BVSatSolverInterface* d_satSolver;
+ prop::BVSatSolverInterface* d_satSolver;
prop::CnfStream* d_cnfStream;
// caches and mappings
TermDefMap d_termCache;
AtomSet d_bitblastedAtoms;
- VarSet d_variables;
+ VarSet d_variables;
context::CDList<prop::SatLiteral> d_assertedAtoms; /**< context dependent list storing the atoms
currently asserted by the DPLL SAT solver. */
@@ -111,79 +111,80 @@ class Bitblaster {
/// function tables for the various bitblasting strategies indexed by node kind
TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
- AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
+ AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
// helper methods to initialize function tables
void initAtomBBStrategies();
- void initTermBBStrategies();
+ void initTermBBStrategies();
// returns a node that might be easier to bitblast
- Node bbOptimize(TNode node);
-
- void addAtom(TNode atom);
+ Node bbOptimize(TNode node);
+
+ void addAtom(TNode atom);
// division is bitblasted in terms of constraints
// so it needs to use private bitblaster interface
void bbUdiv(TNode node, Bits& bits);
void bbUrem(TNode node, Bits& bits);
- bool hasValue(TNode a);
+ bool hasValue(TNode a);
public:
void cacheTermDef(TNode node, Bits def); // public so we can cache remainder for division
void bbTerm(TNode node, Bits& bits);
void bbAtom(TNode node);
-
- Bitblaster(context::Context* c, bv::TheoryBV* bv);
+
+ Bitblaster(context::Context* c, bv::TheoryBV* bv);
~Bitblaster();
bool assertToSat(TNode node, bool propagate = true);
bool propagate();
bool solve(bool quick_solve = false);
- void getConflict(std::vector<TNode>& conflict);
+ void getConflict(std::vector<TNode>& conflict);
void explain(TNode atom, std::vector<TNode>& explanation);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- /**
+ /**
* Return a constant Node representing the value of a variable
- * in the current model.
- * @param a
- *
- * @return
+ * in the current model.
+ * @param a
+ *
+ * @return
*/
- Node getVarValue(TNode a);
- /**
- * Adds a constant value for each bit-blasted variable in the model.
- *
- * @param m the model
+ Node getVarValue(TNode a, bool fullModel=true);
+ /**
+ * Adds a constant value for each bit-blasted variable in the model.
+ *
+ * @param m the model
+ * @param fullModel whether to create a "full model," i.e., add
+ * constants to equivalence classes that don't already have them
*/
- void collectModelInfo(TheoryModel* m);
- /**
- * Stores the variable (or non-bv term) and its corresponding bits.
- *
- * @param var
- * @param bits
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ /**
+ * Stores the variable (or non-bv term) and its corresponding bits.
+ *
+ * @param var
*/
void storeVariable(TNode var) {
- d_variables.insert(var);
+ d_variables.insert(var);
}
bool isSharedTerm(TNode node);
uint64_t computeAtomWeight(TNode node);
private:
-
+
class Statistics {
public:
IntStat d_numTermClauses, d_numAtomClauses;
- IntStat d_numTerms, d_numAtoms;
+ IntStat d_numTerms, d_numAtoms;
TimerStat d_bitblastTimer;
Statistics();
- ~Statistics();
- };
-
+ ~Statistics();
+ };
+
Statistics d_statistics;
};
-} /* bv namespace */
+} /* bv namespace */
} /* theory namespace */
diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h
index 8374a3f75..0b0551283 100644
--- a/src/theory/bv/bv_subtheory.h
+++ b/src/theory/bv/bv_subtheory.h
@@ -9,7 +9,7 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Algebraic solver.
+ ** \brief Algebraic solver.
**
** Algebraic solver.
**/
@@ -46,7 +46,7 @@ inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
out << "BV_CORE_SUBTHEORY";
break;
case SUB_INEQUALITY:
- out << "BV_INEQUALITY_SUBTHEORY";
+ out << "BV_INEQUALITY_SUBTHEORY";
default:
Unreachable();
break;
@@ -55,13 +55,10 @@ inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
}
-const bool d_useEqualityEngine = true;
-const bool d_useSatPropagation = true;
+// forward declaration
+class TheoryBV;
-// forward declaration
-class TheoryBV;
-
-typedef context::CDQueue<Node> AssertionQueue;
+typedef context::CDQueue<Node> AssertionQueue;
/**
* Abstract base class for bit-vector subtheory solvers
*
@@ -78,7 +75,7 @@ protected:
AssertionQueue d_assertionQueue;
context::CDO<uint32_t> d_assertionIndex;
public:
-
+
SubtheorySolver(context::Context* c, TheoryBV* bv) :
d_context(c),
d_bv(bv),
@@ -86,24 +83,24 @@ public:
d_assertionIndex(c, 0)
{}
virtual ~SubtheorySolver() {}
- virtual bool check(Theory::Effort e) = 0;
+ virtual bool check(Theory::Effort e) = 0;
virtual void explain(TNode literal, std::vector<TNode>& assumptions) = 0;
virtual void preRegister(TNode node) {}
virtual void propagate(Theory::Effort e) {}
- virtual void collectModelInfo(TheoryModel* m) = 0;
- virtual Node getModelValue(TNode var) = 0;
+ virtual void collectModelInfo(TheoryModel* m, bool fullModel) = 0;
+ virtual Node getModelValue(TNode var) = 0;
virtual bool isComplete() = 0;
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) = 0;
- virtual void addSharedTerm(TNode node) {}
+ virtual void addSharedTerm(TNode node) {}
bool done() { return d_assertionQueue.size() == d_assertionIndex; }
TNode get() {
- Assert (!done());
+ Assert (!done());
TNode res = d_assertionQueue[d_assertionIndex];
d_assertionIndex = d_assertionIndex + 1;
- return res;
+ return res;
}
virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); }
-};
+};
}
}
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index 2308f36a3..5a0c17134 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -34,7 +34,8 @@ BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
d_bitblaster(new Bitblaster(c, bv)),
d_bitblastQueue(c),
d_statistics(),
- d_validModelCache(c, true)
+ d_validModelCache(c, true),
+ d_useSatPropagation(options::bvPropagate())
{}
BitblastSolver::~BitblastSolver() {
@@ -83,20 +84,20 @@ void BitblastSolver::bitblastQueue() {
}
bool BitblastSolver::check(Theory::Effort e) {
- Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
+ Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
Assert(!options::bitvectorEagerBitblast());
- ++(d_statistics.d_numCallstoCheck);
+ ++(d_statistics.d_numCallstoCheck);
//// Lazy bit-blasting
// bit-blast enqueued nodes
bitblastQueue();
- // Processing assertions
+ // Processing assertions
while (!done()) {
TNode fact = get();
d_validModelCache = false;
- Debug("bv-bitblast") << " fact " << fact << ")\n";
+ Debug("bv-bitblast") << " fact " << fact << ")\n";
if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
// Some atoms have not been bit-blasted yet
d_bitblaster->bbAtom(fact);
@@ -143,8 +144,8 @@ EqualityStatus BitblastSolver::getEqualityStatus(TNode a, TNode b) {
return d_bitblaster->getEqualityStatus(a, b);
}
-void BitblastSolver::collectModelInfo(TheoryModel* m) {
- return d_bitblaster->collectModelInfo(m);
+void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
+ return d_bitblaster->collectModelInfo(m, fullModel);
}
Node BitblastSolver::getModelValue(TNode node)
@@ -188,5 +189,5 @@ Node BitblastSolver::getModelValueRec(TNode node)
Assert(val.isConst());
d_modelCache[node] = val;
Debug("bitvector-model") << node << " => " << val <<"\n";
- return val;
+ return val;
}
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index 819b3d62c..f1204dbdf 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -19,7 +19,6 @@
#pragma once
#include "theory/bv/bv_subtheory.h"
-#include "theory/substitutions.h"
namespace CVC4 {
namespace theory {
namespace bv {
@@ -33,20 +32,21 @@ class BitblastSolver : public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
+ ~Statistics();
+ };
/** Bitblaster */
Bitblaster* d_bitblaster;
/** Nodes that still need to be bit-blasted */
context::CDQueue<TNode> d_bitblastQueue;
- Statistics d_statistics;
+ Statistics d_statistics;
typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
NodeMap d_modelCache;
context::CDO<bool> d_validModelCache;
Node getModelValueRec(TNode node);
+ bool d_useSatPropagation;
public:
BitblastSolver(context::Context* c, TheoryBV* bv);
~BitblastSolver();
@@ -55,7 +55,7 @@ public:
bool check(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- void collectModelInfo(TheoryModel* m);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
Node getModelValue(TNode node);
bool isComplete() { return true; }
void bitblastQueue();
diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp
index c0546f892..45946b8c8 100644
--- a/src/theory/bv/bv_subtheory_core.cpp
+++ b/src/theory/bv/bv_subtheory_core.cpp
@@ -37,53 +37,48 @@ CoreSolver::CoreSolver(context::Context* c, TheoryBV* bv)
d_isCoreTheory(c, true),
d_reasons(c)
{
- if (d_useEqualityEngine) {
-
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_CONCAT, true);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_AND);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_OR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NAND);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XNOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_COMP);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_MULT, true);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_PLUS, true);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_EXTRACT, true);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SUB);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NEG);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UDIV);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UREM);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SDIV);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SREM);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SMOD);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SHL);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_LSHR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ASHR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGE);
- }
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_CONCAT, true);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_AND);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_OR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NAND);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XNOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_COMP);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_MULT, true);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_PLUS, true);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_EXTRACT, true);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SUB);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NEG);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UDIV);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UREM);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SDIV);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SREM);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SMOD);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SHL);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_LSHR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ASHR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGE);
}
CoreSolver::~CoreSolver() {
- delete d_slicer;
+ delete d_slicer;
}
void CoreSolver::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
void CoreSolver::preRegister(TNode node) {
- if (!d_useEqualityEngine)
- return;
-
if (node.getKind() == kind::EQUAL) {
d_equalityEngine.addTriggerEquality(node);
if (options::bitvectorCoreSolver()) {
@@ -109,51 +104,51 @@ Node CoreSolver::getBaseDecomposition(TNode a) {
std::vector<Node> a_decomp;
d_slicer->getBaseDecomposition(a, a_decomp);
Node new_a = utils::mkConcat(a_decomp);
- Debug("bv-slicer") << "CoreSolver::getBaseDecomposition " << a <<" => " << new_a << "\n";
- return new_a;
+ Debug("bv-slicer") << "CoreSolver::getBaseDecomposition " << a <<" => " << new_a << "\n";
+ return new_a;
}
bool CoreSolver::decomposeFact(TNode fact) {
- Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
+ Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
// assert decompositions since the equality engine does not know the semantics of
// concat:
// a == a_1 concat ... concat a_k
// b == b_1 concat ... concat b_k
- Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
- // FIXME: are this the right things to assert?
+ Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
+ // FIXME: are this the right things to assert?
// assert decompositions since the equality engine does not know the semantics of
// concat:
// a == a_1 concat ... concat a_k
// b == b_1 concat ... concat b_k
- TNode eq = fact.getKind() == kind::NOT? fact[0] : fact;
+ TNode eq = fact.getKind() == kind::NOT? fact[0] : fact;
TNode a = eq[0];
TNode b = eq[1];
Node new_a = getBaseDecomposition(a);
- Node new_b = getBaseDecomposition(b);
-
+ Node new_b = getBaseDecomposition(b);
+
Assert (utils::getSize(new_a) == utils::getSize(new_b) &&
- utils::getSize(new_a) == utils::getSize(a));
-
+ utils::getSize(new_a) == utils::getSize(a));
+
NodeManager* nm = NodeManager::currentNM();
Node a_eq_new_a = nm->mkNode(kind::EQUAL, a, new_a);
Node b_eq_new_b = nm->mkNode(kind::EQUAL, b, new_b);
bool ok = true;
ok = assertFactToEqualityEngine(a_eq_new_a, utils::mkTrue());
- if (!ok) return false;
+ if (!ok) return false;
ok = assertFactToEqualityEngine(b_eq_new_b, utils::mkTrue());
- if (!ok) return false;
+ if (!ok) return false;
ok = assertFactToEqualityEngine(fact, fact);
if (!ok) return false;
-
+
if (fact.getKind() == kind::EQUAL) {
// assert the individual equalities as well
// a_i == b_i
if (new_a.getKind() == kind::BITVECTOR_CONCAT &&
new_b.getKind() == kind::BITVECTOR_CONCAT) {
-
- Assert (new_a.getNumChildren() == new_b.getNumChildren());
+
+ Assert (new_a.getNumChildren() == new_b.getNumChildren());
for (unsigned i = 0; i < new_a.getNumChildren(); ++i) {
Node eq_i = nm->mkNode(kind::EQUAL, new_a[i], new_b[i]);
ok = assertFactToEqualityEngine(eq_i, fact);
@@ -161,23 +156,23 @@ bool CoreSolver::decomposeFact(TNode fact) {
}
}
}
- return true;
+ return true;
}
bool CoreSolver::check(Theory::Effort e) {
Trace("bitvector::core") << "CoreSolver::check \n";
Assert (!d_bv->inConflict());
- ++(d_statistics.d_numCallstoCheck);
- bool ok = true;
+ ++(d_statistics.d_numCallstoCheck);
+ bool ok = true;
std::vector<Node> core_eqs;
while (! done()) {
- TNode fact = get();
-
+ TNode fact = get();
+
// update whether we are in the core fragment
if (d_isCoreTheory && !d_slicer->isCoreTerm(fact)) {
- d_isCoreTheory = false;
+ d_isCoreTheory = false;
}
-
+
// only reason about equalities
if (fact.getKind() == kind::EQUAL || (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL)) {
if (options::bitvectorCoreSolver()) {
@@ -186,31 +181,31 @@ bool CoreSolver::check(Theory::Effort e) {
ok = assertFactToEqualityEngine(fact, fact);
}
} else {
- ok = assertFactToEqualityEngine(fact, fact);
+ ok = assertFactToEqualityEngine(fact, fact);
}
if (!ok)
- return false;
+ return false;
}
-
+
if (Theory::fullEffort(e) && isComplete()) {
buildModel();
}
-
+
return true;
}
void CoreSolver::buildModel() {
if (options::bitvectorCoreSolver()) {
// FIXME
- Unreachable();
- return;
+ Unreachable();
+ return;
}
- Debug("bv-core") << "CoreSolver::buildModel() \n";
- d_modelValues.clear();
+ Debug("bv-core") << "CoreSolver::buildModel() \n";
+ d_modelValues.clear();
TNodeSet constants;
- TNodeSet constants_in_eq_engine;
+ TNodeSet constants_in_eq_engine;
// collect constants in equality engine
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
while (!eqcs_i.isFinished()) {
TNode repr = *eqcs_i;
if (repr.getKind() == kind::CONST_BITVECTOR) {
@@ -218,39 +213,39 @@ void CoreSolver::buildModel() {
eq::EqClassIterator it(repr, &d_equalityEngine);
if (!(++it).isFinished() || true) {
constants.insert(repr);
- constants_in_eq_engine.insert(repr);
+ constants_in_eq_engine.insert(repr);
}
}
- ++eqcs_i;
+ ++eqcs_i;
}
// build repr to value map
-
+
eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
while (!eqcs_i.isFinished()) {
TNode repr = *eqcs_i;
++eqcs_i;
-
+
if (repr.getKind() != kind::VARIABLE &&
repr.getKind() != kind::SKOLEM &&
repr.getKind() != kind::CONST_BITVECTOR &&
!d_bv->isSharedTerm(repr)) {
- continue;
+ continue;
}
-
- TypeNode type = repr.getType();
+
+ TypeNode type = repr.getType();
if (type.isBitVector() && repr.getKind()!= kind::CONST_BITVECTOR) {
- Debug("bv-core-model") << " processing " << repr <<"\n";
+ Debug("bv-core-model") << " processing " << repr <<"\n";
// we need to assign a value for it
TypeEnumerator te(type);
- Node val;
+ Node val;
do {
- val = *te;
+ val = *te;
++te;
// Debug("bv-core-model") << " trying value " << val << "\n";
// Debug("bv-core-model") << " is in set? " << constants.count(val) << "\n";
- // Debug("bv-core-model") << " enumerator done? " << te.isFinished() << "\n";
+ // Debug("bv-core-model") << " enumerator done? " << te.isFinished() << "\n";
} while (constants.count(val) != 0 && !(te.isFinished()));
-
+
if (te.isFinished() && constants.count(val) != 0) {
// if we cannot enumerate anymore values we just return the lemma stating that
// at least two of the representatives are equal.
@@ -259,15 +254,15 @@ void CoreSolver::buildModel() {
for (TNodeSet::const_iterator it = constants_in_eq_engine.begin();
it != constants_in_eq_engine.end(); ++it) {
- TNode constant = *it;
+ TNode constant = *it;
if (utils::getSize(constant) == utils::getSize(repr)) {
- representatives.push_back(constant);
+ representatives.push_back(constant);
}
}
for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
representatives.push_back(it->first);
}
- std::vector<Node> equalities;
+ std::vector<Node> equalities;
for (unsigned i = 0; i < representatives.size(); ++i) {
for (unsigned j = i + 1; j < representatives.size(); ++j) {
TNode a = representatives[i];
@@ -279,19 +274,19 @@ void CoreSolver::buildModel() {
}
Node lemma = utils::mkOr(equalities);
d_bv->lemma(lemma);
- Debug("bv-core") << " lemma: " << lemma << "\n";
- return;
+ Debug("bv-core") << " lemma: " << lemma << "\n";
+ return;
}
Debug("bv-core-model") << " " << repr << " => " << val <<"\n" ;
constants.insert(val);
- d_modelValues[repr] = val;
+ d_modelValues[repr] = val;
}
}
}
bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
- // Notify the equality engine
- if (d_useEqualityEngine && !d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || !d_bv->getPropagatingSubtheory(fact) == SUB_CORE)) {
+ // Notify the equality engine
+ if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || !d_bv->getPropagatingSubtheory(fact) == SUB_CORE)) {
Debug("bv-slicer-eq") << "CoreSolver::assertFactToEqualityEngine fact=" << fact << endl;
// Debug("bv-slicer-eq") << " reason=" << reason << endl;
bool negated = fact.getKind() == kind::NOT;
@@ -315,8 +310,8 @@ bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
// checking for a conflict
if (d_bv->inConflict()) {
return false;
- }
- return true;
+ }
+ return true;
}
bool CoreSolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) {
@@ -361,10 +356,10 @@ void CoreSolver::conflict(TNode a, TNode b) {
d_bv->setConflict(conflict);
}
-void CoreSolver::collectModelInfo(TheoryModel* m) {
+void CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
if (options::bitvectorCoreSolver()) {
Unreachable();
- return;
+ return;
}
if (Debug.isOn("bitvector-model")) {
context::CDQueue<Node>::const_iterator it = d_assertionQueue.begin();
@@ -377,11 +372,11 @@ void CoreSolver::collectModelInfo(TheoryModel* m) {
d_bv->computeRelevantTerms(termSet);
m->assertEqualityEngine(&d_equalityEngine, &termSet);
if (isComplete()) {
- Debug("bitvector-model") << "CoreSolver::collectModelInfo complete.";
+ Debug("bitvector-model") << "CoreSolver::collectModelInfo complete.";
for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
Node a = it->first;
Node b = it->second;
- m->assertEquality(a, b, true);
+ m->assertEquality(a, b, true);
}
}
}
@@ -390,23 +385,23 @@ Node CoreSolver::getModelValue(TNode var) {
// we don't need to evaluate bv expressions and only look at variable values
// because this only gets called when the core theory is complete (i.e. no other bv
// function symbols are currently asserted)
- Assert (d_slicer->isCoreTerm(var));
-
- Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")";
+ Assert (d_slicer->isCoreTerm(var));
+
+ Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")";
Assert (isComplete());
TNode repr = d_equalityEngine.getRepresentative(var);
- Node result = Node();
+ Node result = Node();
if (repr.getKind() == kind::CONST_BITVECTOR) {
- result = repr;
+ result = repr;
} else if (d_modelValues.find(repr) == d_modelValues.end()) {
// it may be a shared term that never gets asserted
// result is just Null
Assert(d_bv->isSharedTerm(var));
} else {
- result = d_modelValues[repr];
+ result = d_modelValues[repr];
}
- Debug("bitvector-model") << " => " << result <<"\n";
- return result;
+ Debug("bitvector-model") << " => " << result <<"\n";
+ return result;
}
CoreSolver::Statistics::Statistics()
diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h
index 423408a7c..b886bbdd5 100644
--- a/src/theory/bv/bv_subtheory_core.h
+++ b/src/theory/bv/bv_subtheory_core.h
@@ -25,21 +25,21 @@ namespace CVC4 {
namespace theory {
namespace bv {
-class Slicer;
-class Base;
+class Slicer;
+class Base;
/**
* Bitvector equality solver
*/
class CoreSolver : public SubtheorySolver {
typedef __gnu_cxx::hash_map<TNode, Node, TNodeHashFunction> ModelValue;
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
-
+ ~Statistics();
+ };
+
// NotifyClass: handles call-back from congruence closure module
class NotifyClass : public eq::EqualityEngineNotify {
CoreSolver& d_solver;
@@ -59,13 +59,13 @@ class CoreSolver : public SubtheorySolver {
/** The notify class for d_equalityEngine */
NotifyClass d_notify;
-
+
/** Equality engine */
eq::EqualityEngine d_equalityEngine;
/** Store a propagation to the bv solver */
bool storePropagation(TNode literal);
-
+
/** Store a conflict from merging two constants */
void conflict(TNode a, TNode b);
@@ -74,12 +74,12 @@ class CoreSolver : public SubtheorySolver {
/** To make sure we keep the explanations */
context::CDHashSet<Node, NodeHashFunction> d_reasons;
ModelValue d_modelValues;
- void buildModel();
- bool assertFactToEqualityEngine(TNode fact, TNode reason);
+ void buildModel();
+ bool assertFactToEqualityEngine(TNode fact, TNode reason);
bool decomposeFact(TNode fact);
Node getBaseDecomposition(TNode a);
- Statistics d_statistics;
-public:
+ Statistics d_statistics;
+public:
CoreSolver(context::Context* c, TheoryBV* bv);
~CoreSolver();
bool isComplete() { return d_isCoreTheory; }
@@ -87,8 +87,8 @@ public:
void preRegister(TNode node);
bool check(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
- void collectModelInfo(TheoryModel* m);
- Node getModelValue(TNode var);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ Node getModelValue(TNode var);
void addSharedTerm(TNode t) {
d_equalityEngine.addTriggerTerm(t, THEORY_BV);
}
diff --git a/src/theory/bv/bv_subtheory_inequality.cpp b/src/theory/bv/bv_subtheory_inequality.cpp
index f45250f5b..a3970c9e3 100644
--- a/src/theory/bv/bv_subtheory_inequality.cpp
+++ b/src/theory/bv/bv_subtheory_inequality.cpp
@@ -29,17 +29,17 @@ using namespace CVC4::theory::bv::utils;
bool InequalitySolver::check(Theory::Effort e) {
Debug("bv-subtheory-inequality") << "InequalitySolveR::check("<< e <<")\n";
++(d_statistics.d_numCallstoCheck);
-
- bool ok = true;
+
+ bool ok = true;
while (!done() && ok) {
TNode fact = get();
- Debug("bv-subtheory-inequality") << " "<< fact <<"\n";
+ Debug("bv-subtheory-inequality") << " "<< fact <<"\n";
if (fact.getKind() == kind::EQUAL) {
TNode a = fact[0];
TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
if (ok)
- ok = d_inequalityGraph.addInequality(b, a, false, fact);
+ ok = d_inequalityGraph.addInequality(b, a, false, fact);
} else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL) {
TNode a = fact[0][0];
TNode b = fact[0][1];
@@ -47,40 +47,40 @@ bool InequalitySolver::check(Theory::Effort e) {
}
if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULE) {
TNode a = fact[0][1];
- TNode b = fact[0][0];
+ TNode b = fact[0][0];
ok = d_inequalityGraph.addInequality(a, b, true, fact);
// propagate
// if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) {
- // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
+ // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
// d_bv->storePropagation(neq, SUB_INEQUALITY);
// d_explanations[neq] = fact;
// }
} else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULT) {
TNode a = fact[0][1];
- TNode b = fact[0][0];
+ TNode b = fact[0][0];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
} else if (fact.getKind() == kind::BITVECTOR_ULT) {
TNode a = fact[0];
- TNode b = fact[1];
+ TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, true, fact);
// propagate
// if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) {
- // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
+ // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
// d_bv->storePropagation(neq, SUB_INEQUALITY);
// d_explanations[neq] = fact;
// }
} else if (fact.getKind() == kind::BITVECTOR_ULE) {
TNode a = fact[0];
- TNode b = fact[1];
+ TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
}
}
-
+
if (!ok) {
std::vector<TNode> conflict;
- d_inequalityGraph.getConflict(conflict);
+ d_inequalityGraph.getConflict(conflict);
d_bv->setConflict(utils::flattenAnd(conflict));
- return false;
+ return false;
}
if (isComplete() && Theory::fullEffort(e)) {
@@ -89,36 +89,39 @@ bool InequalitySolver::check(Theory::Effort e) {
std::vector<Node> lemmas;
d_inequalityGraph.checkDisequalities(lemmas);
for(unsigned i = 0; i < lemmas.size(); ++i) {
- d_bv->lemma(lemmas[i]);
+ d_bv->lemma(lemmas[i]);
}
}
- return true;
+ return true;
}
EqualityStatus InequalitySolver::getEqualityStatus(TNode a, TNode b) {
+ if (!isComplete())
+ return EQUALITY_UNKNOWN;
+
Node a_lt_b = utils::mkNode(kind::BITVECTOR_ULT, a, b);
Node b_lt_a = utils::mkNode(kind::BITVECTOR_ULT, b, a);
// if an inequality containing the terms has been asserted then we know
// the equality is false
if (d_assertionSet.contains(a_lt_b) || d_assertionSet.contains(b_lt_a)) {
- return EQUALITY_FALSE;
+ return EQUALITY_FALSE;
}
-
+
if (!d_inequalityGraph.hasValueInModel(a) ||
!d_inequalityGraph.hasValueInModel(b)) {
- return EQUALITY_UNKNOWN;
+ return EQUALITY_UNKNOWN;
}
// TODO: check if this disequality is entailed by inequalities via transitivity
-
+
BitVector a_val = d_inequalityGraph.getValueInModel(a);
BitVector b_val = d_inequalityGraph.getValueInModel(b);
-
+
if (a_val == b_val) {
- return EQUALITY_TRUE_IN_MODEL;
+ return EQUALITY_TRUE_IN_MODEL;
} else {
- return EQUALITY_FALSE_IN_MODEL;
+ return EQUALITY_FALSE_IN_MODEL;
}
}
@@ -126,19 +129,19 @@ void InequalitySolver::assertFact(TNode fact) {
d_assertionQueue.push_back(fact);
d_assertionSet.insert(fact);
if (!isInequalityOnly(fact)) {
- d_isComplete = false;
+ d_isComplete = false;
}
}
bool InequalitySolver::isInequalityOnly(TNode node) {
if (d_ineqTermCache.find(node) != d_ineqTermCache.end()) {
- return d_ineqTermCache[node];
+ return d_ineqTermCache[node];
}
-
+
if (node.getKind() == kind::NOT) {
- node = node[0];
+ node = node[0];
}
-
+
if (node.getKind() != kind::EQUAL &&
node.getKind() != kind::BITVECTOR_ULT &&
node.getKind() != kind::BITVECTOR_ULE &&
@@ -146,50 +149,50 @@ bool InequalitySolver::isInequalityOnly(TNode node) {
node.getKind() != kind::SELECT &&
node.getKind() != kind::STORE &&
node.getMetaKind() != kind::metakind::VARIABLE) {
- return false;
+ return false;
}
- bool res = true;
+ bool res = true;
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
res = res && isInequalityOnly(node[i]);
}
- d_ineqTermCache[node] = res;
- return res;
+ d_ineqTermCache[node] = res;
+ return res;
}
void InequalitySolver::explain(TNode literal, std::vector<TNode>& assumptions) {
Assert (d_explanations.find(literal) != d_explanations.end());
TNode explanation = d_explanations[literal];
assumptions.push_back(explanation);
- Debug("bv-inequality-explain") << "InequalitySolver::explain " << literal << " with " << explanation <<"\n";
+ Debug("bv-inequality-explain") << "InequalitySolver::explain " << literal << " with " << explanation <<"\n";
}
void InequalitySolver::propagate(Theory::Effort e) {
- Assert (false);
+ Assert (false);
}
-void InequalitySolver::collectModelInfo(TheoryModel* m) {
- Debug("bitvector-model") << "InequalitySolver::collectModelInfo \n";
+void InequalitySolver::collectModelInfo(TheoryModel* m, bool fullModel) {
+ Debug("bitvector-model") << "InequalitySolver::collectModelInfo \n";
std::vector<Node> model;
d_inequalityGraph.getAllValuesInModel(model);
for (unsigned i = 0; i < model.size(); ++i) {
- Assert (model[i].getKind() == kind::EQUAL);
- m->assertEquality(model[i][0], model[i][1], true);
+ Assert (model[i].getKind() == kind::EQUAL);
+ m->assertEquality(model[i][0], model[i][1], true);
}
}
Node InequalitySolver::getModelValue(TNode var) {
- Assert (isInequalityOnly(var));
- Debug("bitvector-model") << "InequalitySolver::getModelValue (" << var <<")";
+ Assert (isInequalityOnly(var));
+ Debug("bitvector-model") << "InequalitySolver::getModelValue (" << var <<")";
Assert (isComplete());
- Node result = Node();
+ Node result = Node();
if (!d_inequalityGraph.hasValueInModel(var)) {
Assert (d_bv->isSharedTerm(var));
} else {
BitVector val = d_inequalityGraph.getValueInModel(var);
result = utils::mkConst(val);
}
- Debug("bitvector-model") << " => " << result <<"\n";
- return result;
+ Debug("bitvector-model") << " => " << result <<"\n";
+ return result;
}
InequalitySolver::Statistics::Statistics()
diff --git a/src/theory/bv/bv_subtheory_inequality.h b/src/theory/bv/bv_subtheory_inequality.h
index 390a329ff..6e0139e09 100644
--- a/src/theory/bv/bv_subtheory_inequality.h
+++ b/src/theory/bv/bv_subtheory_inequality.h
@@ -9,7 +9,7 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Algebraic solver.
+ ** \brief Algebraic solver.
**
** Algebraic solver.
**/
@@ -31,16 +31,16 @@ class InequalitySolver: public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
+ ~Statistics();
+ };
- context::CDHashSet<Node, NodeHashFunction> d_assertionSet;
+ context::CDHashSet<Node, NodeHashFunction> d_assertionSet;
InequalityGraph d_inequalityGraph;
- context::CDHashMap<Node, TNode, NodeHashFunction> d_explanations;
+ context::CDHashMap<Node, TNode, NodeHashFunction> d_explanations;
context::CDO<bool> d_isComplete;
- __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> d_ineqTermCache;
- bool isInequalityOnly(TNode node);
- Statistics d_statistics;
+ __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> d_ineqTermCache;
+ bool isInequalityOnly(TNode node);
+ Statistics d_statistics;
public:
InequalitySolver(context::Context* c, TheoryBV* bv)
: SubtheorySolver(c, bv),
@@ -51,19 +51,19 @@ public:
d_ineqTermCache(),
d_statistics()
{}
-
+
bool check(Theory::Effort e);
- void propagate(Theory::Effort e);
+ void propagate(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
bool isComplete() { return d_isComplete; }
- void collectModelInfo(TheoryModel* m);
- Node getModelValue(TNode var);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ Node getModelValue(TNode var);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- void assertFact(TNode fact);
-};
+ void assertFact(TNode fact);
+};
}
}
}
-#endif /* __CVC4__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */
+#endif /* __CVC4__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */
diff --git a/src/theory/bv/kinds b/src/theory/bv/kinds
index 052e477ea..aeae1073e 100644
--- a/src/theory/bv/kinds
+++ b/src/theory/bv/kinds
@@ -120,6 +120,14 @@ parameterized BITVECTOR_SIGN_EXTEND BITVECTOR_SIGN_EXTEND_OP 1 "bit-vector sign-
parameterized BITVECTOR_ROTATE_LEFT BITVECTOR_ROTATE_LEFT_OP 1 "bit-vector rotate left"
parameterized BITVECTOR_ROTATE_RIGHT BITVECTOR_ROTATE_RIGHT_OP 1 "bit-vector rotate right"
+constant INT_TO_BITVECTOR_OP \
+ ::CVC4::IntToBitVector \
+ "::CVC4::UnsignedHashFunction< ::CVC4::IntToBitVector >" \
+ "util/bitvector.h" \
+ "operator for the integer conversion to bit-vector"
+parameterized INT_TO_BITVECTOR INT_TO_BITVECTOR_OP 1 "integer conversion to bit-vector"
+operator BITVECTOR_TO_NAT 1 "bit-vector conversion to (nonnegative) integer"
+
typerule CONST_BITVECTOR ::CVC4::theory::bv::BitVectorConstantTypeRule
typerule BITVECTOR_AND ::CVC4::theory::bv::BitVectorFixedWidthTypeRule
@@ -166,4 +174,7 @@ typerule BITVECTOR_REPEAT ::CVC4::theory::bv::BitVectorRepeatTypeRule
typerule BITVECTOR_ZERO_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule
typerule BITVECTOR_SIGN_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule
+typerule BITVECTOR_TO_NAT ::CVC4::theory::bv::BitVectorConversionTypeRule
+typerule INT_TO_BITVECTOR ::CVC4::theory::bv::BitVectorConversionTypeRule
+
endtheory
diff --git a/src/theory/bv/options b/src/theory/bv/options
index 7b87baa21..077299d1f 100644
--- a/src/theory/bv/options
+++ b/src/theory/bv/options
@@ -22,5 +22,11 @@ option bitvectorCoreSolver --bv-core-solver bool
option bvToBool --bv-to-bool bool
lift bit-vectors of size 1 to booleans when possible
+
+option bvPropagate --bv-propagate bool :default true
+ use bit-vector propagation in the bit-blaster
+
+option bvEquality --bv-eq bool :default true
+ use the equality engine for the bit-vector theory
endmodule
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index cb68a0f65..a2de951aa 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -49,29 +49,32 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel&
d_literalsToPropagateIndex(c, 0),
d_propagatedBy(c)
{
- SubtheorySolver* core_solver = new CoreSolver(c, this);
- d_subtheories.push_back(core_solver);
- d_subtheoryMap[SUB_CORE] = core_solver;
-
+ if (options::bvEquality()) {
+ SubtheorySolver* core_solver = new CoreSolver(c, this);
+ d_subtheories.push_back(core_solver);
+ d_subtheoryMap[SUB_CORE] = core_solver;
+ }
if (options::bitvectorInequalitySolver()) {
- SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
+ SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
d_subtheories.push_back(ineq_solver);
d_subtheoryMap[SUB_INEQUALITY] = ineq_solver;
}
-
- SubtheorySolver* bb_solver = new BitblastSolver(c, this);
+
+ SubtheorySolver* bb_solver = new BitblastSolver(c, this);
d_subtheories.push_back(bb_solver);
d_subtheoryMap[SUB_BITBLAST] = bb_solver;
}
TheoryBV::~TheoryBV() {
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- delete d_subtheories[i];
+ delete d_subtheories[i];
}
}
void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
+ if (options::bvEquality()) {
+ dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
+ }
}
TheoryBV::Statistics::Statistics():
@@ -110,7 +113,7 @@ void TheoryBV::preRegisterTerm(TNode node) {
return;
}
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->preRegister(node);
+ d_subtheories[i]->preRegister(node);
}
}
@@ -131,22 +134,22 @@ void TheoryBV::checkForLemma(TNode fact) {
if (fact[0].getKind() == kind::BITVECTOR_UREM_TOTAL) {
TNode urem = fact[0];
TNode result = fact[1];
- TNode divisor = urem[1];
+ TNode divisor = urem[1];
Node result_ult_div = mkNode(kind::BITVECTOR_ULT, result, divisor);
Node divisor_eq_0 = mkNode(kind::EQUAL,
divisor,
- mkConst(BitVector(getSize(divisor), 0u)));
+ mkConst(BitVector(getSize(divisor), 0u)));
Node split = utils::mkNode(kind::OR, divisor_eq_0, mkNode(kind::NOT, fact), result_ult_div);
lemma(split);
}
if (fact[1].getKind() == kind::BITVECTOR_UREM_TOTAL) {
TNode urem = fact[1];
TNode result = fact[0];
- TNode divisor = urem[1];
+ TNode divisor = urem[1];
Node result_ult_div = mkNode(kind::BITVECTOR_ULT, result, divisor);
Node divisor_eq_0 = mkNode(kind::EQUAL,
divisor,
- mkConst(BitVector(getSize(divisor), 0u)));
+ mkConst(BitVector(getSize(divisor), 0u)));
Node split = utils::mkNode(kind::OR, divisor_eq_0, mkNode(kind::NOT, fact), result_ult_div);
lemma(split);
}
@@ -162,9 +165,9 @@ void TheoryBV::check(Effort e)
}
if (Theory::fullEffort(e)) {
- ++(d_statistics.d_numCallsToCheckFullEffort);
+ ++(d_statistics.d_numCallsToCheckFullEffort);
} else {
- ++(d_statistics.d_numCallsToCheckStandardEffort);
+ ++(d_statistics.d_numCallsToCheckStandardEffort);
}
// if we are already in conflict just return the conflict
if (inConflict()) {
@@ -174,28 +177,29 @@ void TheoryBV::check(Effort e)
while (!done()) {
TNode fact = get().assertion;
- checkForLemma(fact);
+ checkForLemma(fact);
+
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->assertFact(fact);
+ d_subtheories[i]->assertFact(fact);
}
}
bool ok = true;
bool complete = false;
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- Assert (!inConflict());
+ Assert (!inConflict());
ok = d_subtheories[i]->check(e);
- complete = d_subtheories[i]->isComplete();
+ complete = d_subtheories[i]->isComplete();
if (!ok) {
// if we are in a conflict no need to check with other theories
Assert (inConflict());
sendConflict();
- return;
+ return;
}
if (complete) {
// if the last subtheory was complete we stop
- return;
+ return;
}
}
}
@@ -205,8 +209,8 @@ void TheoryBV::collectModelInfo( TheoryModel* m, bool fullModel ){
// Assert (fullModel); // can only query full model
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
if (d_subtheories[i]->isComplete()) {
- d_subtheories[i]->collectModelInfo(m);
- return;
+ d_subtheories[i]->collectModelInfo(m, fullModel);
+ return;
}
}
}
@@ -215,10 +219,10 @@ Node TheoryBV::getModelValue(TNode var) {
Assert(!inConflict());
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
if (d_subtheories[i]->isComplete()) {
- return d_subtheories[i]->getModelValue(var);
+ return d_subtheories[i]->getModelValue(var);
}
}
- Unreachable();
+ Unreachable();
}
void TheoryBV::propagate(Effort e) {
@@ -236,7 +240,7 @@ void TheoryBV::propagate(Effort e) {
bool ok = true;
for (; d_literalsToPropagateIndex < d_literalsToPropagate.size() && ok; d_literalsToPropagateIndex = d_literalsToPropagateIndex + 1) {
TNode literal = d_literalsToPropagate[d_literalsToPropagateIndex];
- // temporary fix for incremental bit-blasting
+ // temporary fix for incremental bit-blasting
if (d_valuation.isSatLiteral(literal)) {
Debug("bitvector::propagate") << "TheoryBV:: propagating " << literal <<"\n";
ok = d_out->propagate(literal);
@@ -286,14 +290,14 @@ Node TheoryBV::ppRewrite(TNode t)
if (options::bitvectorCoreSolver() && t.getKind() == kind::EQUAL) {
std::vector<Node> equalities;
Slicer::splitEqualities(t, equalities);
- return utils::mkAnd(equalities);
+ return utils::mkAnd(equalities);
}
-
+
return t;
}
void TheoryBV::presolve() {
- Debug("bitvector") << "TheoryBV::presolve" << endl;
+ Debug("bitvector") << "TheoryBV::presolve" << endl;
}
bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
@@ -318,7 +322,7 @@ bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
// Safe to ignore this one, subtheory should produce a conflict
return true;
}
-
+
d_propagatedBy[literal] = subtheory;
}
@@ -366,7 +370,7 @@ Node TheoryBV::explain(TNode node) {
void TheoryBV::addSharedTerm(TNode t) {
Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl;
d_sharedTermsSet.insert(t);
- if (!options::bitvectorEagerBitblast() && d_useEqualityEngine) {
+ if (!options::bitvectorEagerBitblast() && options::bvEquality()) {
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
d_subtheories[i]->addSharedTerm(t);
}
@@ -379,11 +383,11 @@ EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
if (options::bitvectorEagerBitblast()) {
return EQUALITY_UNKNOWN;
}
-
+
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
if (status != EQUALITY_UNKNOWN) {
- return status;
+ return status;
}
}
return EQUALITY_UNKNOWN; ;
diff --git a/src/theory/bv/theory_bv_rewrite_rules.h b/src/theory/bv/theory_bv_rewrite_rules.h
index baaf7e133..8426afb59 100644
--- a/src/theory/bv/theory_bv_rewrite_rules.h
+++ b/src/theory/bv/theory_bv_rewrite_rules.h
@@ -66,6 +66,9 @@ enum RewriteRuleId {
SremEliminate,
ZeroExtendEliminate,
SignExtendEliminate,
+ BVToNatEliminate,
+ IntToBVEliminate,
+
/// ground term evaluation
EvalEquals,
EvalConcat,
@@ -173,13 +176,15 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case FailEq: out << "FailEq"; return out;
case SimplifyEq: out << "SimplifyEq"; return out;
case ReflexivityEq: out << "ReflexivityEq"; return out;
- case UgtEliminate: out << "UgtEliminate"; return out;
- case SgtEliminate: out << "SgtEliminate"; return out;
- case UgeEliminate: out << "UgeEliminate"; return out;
- case SgeEliminate: out << "SgeEliminate"; return out;
+ case UgtEliminate: out << "UgtEliminate"; return out;
+ case SgtEliminate: out << "SgtEliminate"; return out;
+ case UgeEliminate: out << "UgeEliminate"; return out;
+ case SgeEliminate: out << "SgeEliminate"; return out;
case RepeatEliminate: out << "RepeatEliminate"; return out;
case RotateLeftEliminate: out << "RotateLeftEliminate"; return out;
case RotateRightEliminate:out << "RotateRightEliminate";return out;
+ case BVToNatEliminate: out << "BVToNatEliminate"; return out;
+ case IntToBVEliminate: out << "IntToBVEliminate"; return out;
case NandEliminate: out << "NandEliminate"; return out;
case NorEliminate : out << "NorEliminate"; return out;
case SdivEliminate : out << "SdivEliminate"; return out;
@@ -214,7 +219,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case ExtractBitwise : out << "ExtractBitwise"; return out;
case ExtractNot : out << "ExtractNot"; return out;
case ExtractArith : out << "ExtractArith"; return out;
- case ExtractArith2 : out << "ExtractArith2"; return out;
+ case ExtractArith2 : out << "ExtractArith2"; return out;
case DoubleNeg : out << "DoubleNeg"; return out;
case NotConcat : out << "NotConcat"; return out;
case NotAnd : out << "NotAnd"; return out;
@@ -226,7 +231,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case BitwiseNotOr : out << "BitwiseNotOr"; return out;
case XorNot : out << "XorNot"; return out;
case LtSelf : out << "LtSelf"; return out;
- case LteSelf : out << "LteSelf"; return out;
+ case LteSelf : out << "LteSelf"; return out;
case UltZero : out << "UltZero"; return out;
case UleZero : out << "UleZero"; return out;
case ZeroUle : out << "ZeroUle"; return out;
@@ -491,7 +496,8 @@ struct AllRewriteRules {
RewriteRule<BitwiseEq> rule113;
RewriteRule<UltOne> rule114;
RewriteRule<SltZero> rule115;
-
+ RewriteRule<BVToNatEliminate> rule116;
+ RewriteRule<IntToBVEliminate> rule117;
};
template<> inline
diff --git a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
index a5368d2c9..9f3d12415 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
@@ -198,8 +198,9 @@ Node RewriteRule<EvalNeg>::apply(TNode node) {
}
template<> inline
bool RewriteRule<EvalUdiv>::applies(TNode node) {
- return (node.getKind() == kind::BITVECTOR_UDIV_TOTAL &&
- utils::isBVGroundTerm(node));
+ return (utils::isBVGroundTerm(node) &&
+ (node.getKind() == kind::BITVECTOR_UDIV_TOTAL ||
+ (node.getKind() == kind::BITVECTOR_UDIV && node[1].isConst())));
}
template<> inline
@@ -213,8 +214,9 @@ Node RewriteRule<EvalUdiv>::apply(TNode node) {
}
template<> inline
bool RewriteRule<EvalUrem>::applies(TNode node) {
- return (node.getKind() == kind::BITVECTOR_UREM_TOTAL &&
- utils::isBVGroundTerm(node));
+ return (utils::isBVGroundTerm(node) &&
+ (node.getKind() == kind::BITVECTOR_UREM_TOTAL ||
+ (node.getKind() == kind::BITVECTOR_UREM && node[1].isConst())));
}
template<> inline
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 cf36633fa..b513dbf90 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -231,6 +231,57 @@ Node RewriteRule<RotateRightEliminate>::apply(TNode node) {
}
template<>
+bool RewriteRule<BVToNatEliminate>::applies(TNode node) {
+ return (node.getKind() == kind::BITVECTOR_TO_NAT);
+}
+
+template<>
+Node RewriteRule<BVToNatEliminate>::apply(TNode node) {
+ Debug("bv-rewrite") << "RewriteRule<BVToNatEliminate>(" << node << ")" << std::endl;
+
+ const unsigned size = utils::getSize(node[0]);
+ NodeManager* const nm = NodeManager::currentNM();
+ const Node z = nm->mkConst(Rational(0));
+ const Node bvone = nm->mkConst(BitVector(1u, 1u));
+
+ NodeBuilder<> result(kind::PLUS);
+ Integer i = 1;
+ for(unsigned bit = 0; bit < size; ++bit, i *= 2) {
+ Node cond = nm->mkNode(kind::EQUAL, nm->mkNode(nm->mkConst(BitVectorExtract(bit, bit)), node[0]), bvone);
+ result << nm->mkNode(kind::ITE, cond, nm->mkConst(Rational(i)), z);
+ }
+
+ return Node(result);
+}
+
+template<>
+bool RewriteRule<IntToBVEliminate>::applies(TNode node) {
+ return (node.getKind() == kind::INT_TO_BITVECTOR);
+}
+
+template<>
+Node RewriteRule<IntToBVEliminate>::apply(TNode node) {
+ Debug("bv-rewrite") << "RewriteRule<IntToBVEliminate>(" << node << ")" << std::endl;
+
+ const unsigned size = node.getOperator().getConst<IntToBitVector>().size;
+ NodeManager* const nm = NodeManager::currentNM();
+ const Node bvzero = nm->mkConst(BitVector(1u, 0u));
+ const Node bvone = nm->mkConst(BitVector(1u, 1u));
+
+ std::vector<Node> v;
+ Integer i = 2;
+ while(v.size() < size) {
+ Node cond = nm->mkNode(kind::GEQ, nm->mkNode(kind::INTS_MODULUS_TOTAL, node[0], nm->mkConst(Rational(i))), nm->mkConst(Rational(i, 2)));
+ v.push_back(nm->mkNode(kind::ITE, cond, bvone, bvzero));
+ i *= 2;
+ }
+
+ NodeBuilder<> result(kind::BITVECTOR_CONCAT);
+ result.append(v.rbegin(), v.rend());
+ return Node(result);
+}
+
+template<>
bool RewriteRule<NandEliminate>::applies(TNode node) {
return (node.getKind() == kind::BITVECTOR_NAND &&
node.getNumChildren() == 2);
diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
index d660dde29..ff7d67cb0 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
@@ -45,7 +45,9 @@ template<> inline
Node RewriteRule<ShlByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<ShlByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
-
+ if (amount == 0) {
+ return node[0];
+ }
Node a = node[0];
uint32_t size = utils::getSize(a);
@@ -59,6 +61,7 @@ Node RewriteRule<ShlByConst>::apply(TNode node) {
Assert(amount < Integer(1).multiplyByPow2(32));
uint32_t uint32_amount = amount.toUnsignedInt();
+
Node left = utils::mkExtract(a, size - 1 - uint32_amount, 0);
Node right = utils::mkConst(BitVector(uint32_amount, Integer(0)));
return utils::mkConcat(left, right);
@@ -81,6 +84,9 @@ template<> inline
Node RewriteRule<LshrByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<LshrByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
+ if (amount == 0) {
+ return node[0];
+ }
Node a = node[0];
uint32_t size = utils::getSize(a);
@@ -117,7 +123,10 @@ template<> inline
Node RewriteRule<AshrByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<AshrByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
-
+ if (amount == 0) {
+ return node[0];
+ }
+
Node a = node[0];
uint32_t size = utils::getSize(a);
Node sign_bit = utils::mkExtract(a, size-1, size-1);
@@ -812,7 +821,9 @@ Node RewriteRule<UdivPow2>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<UdivPow2>(" << node << ")" << std::endl;
Node a = node[0];
unsigned power = utils::isPow2Const(node[1]) -1;
-
+ if (power == 0) {
+ return a;
+ }
Node extract = utils::mkExtract(a, utils::getSize(node) - 1, power);
Node zeros = utils::mkConst(power, 0);
diff --git a/src/theory/bv/theory_bv_rewriter.cpp b/src/theory/bv/theory_bv_rewriter.cpp
index 7844e5b92..2467ae3f1 100644
--- a/src/theory/bv/theory_bv_rewriter.cpp
+++ b/src/theory/bv/theory_bv_rewriter.cpp
@@ -70,7 +70,7 @@ RewriteResponse TheoryBVRewriter::postRewrite(TNode node) {
return res;
}
-RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) {
// reduce common subexpressions on both sides
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalUlt>,
@@ -82,7 +82,7 @@ RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule < EvalSlt >
>::apply(node);
@@ -97,7 +97,7 @@ RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool preregister){
// return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalUle>,
RewriteRule<UleMax>,
@@ -109,7 +109,7 @@ RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool preregister){
return RewriteResponse(resultNode == node ? REWRITE_DONE : REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule <EvalSle>,
RewriteRule <SleEliminate>
@@ -117,7 +117,7 @@ RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool preregister){
return RewriteResponse(resultNode == node? REWRITE_DONE : REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<UgtEliminate>
>::apply(node);
@@ -125,7 +125,7 @@ RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<SgtEliminate>
//RewriteRule<SltEliminate>
@@ -134,7 +134,7 @@ RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<UgeEliminate>
>::apply(node);
@@ -142,7 +142,7 @@ RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<SgeEliminate>
// RewriteRule<SleEliminate>
@@ -151,7 +151,7 @@ RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite){
Node resultNode = node;
if(RewriteRule<NotXor>::applies(node)) {
@@ -166,7 +166,7 @@ RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool preregister){
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool prerewrite) {
Node resultNode = node;
if (RewriteRule<ExtractConcat>::applies(node)) {
@@ -206,7 +206,7 @@ RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool preregister) {
}
-RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<ConcatFlatten>,
@@ -220,63 +220,70 @@ RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool prerewrite) {
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>,
- RewriteRule<AndSimplify>,
- RewriteRule<BitwiseSlicing>
+ RewriteRule<AndSimplify>
>::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteOr(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteOr(TNode node, bool prerewrite){
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>,
- RewriteRule<OrSimplify>,
- RewriteRule<BitwiseSlicing>
- >::apply(node);
+ RewriteRule<OrSimplify>
+ >::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteXor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteXor(TNode node, bool prerewrite) {
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>, // flatten the expression
RewriteRule<XorSimplify>, // simplify duplicates and constants
RewriteRule<XorZero>, // checks if the constant part is zero and eliminates it
RewriteRule<BitwiseSlicing>
- >::apply(node);
-
- // this simplification introduces new terms and might require further
- // rewriting
- if (RewriteRule<XorOne>::applies(resultNode)) {
- resultNode = RewriteRule<XorOne>::run<false> (resultNode);
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
- }
+ >::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<XorOne>,
+ RewriteRule <BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<XnorEliminate>
>::apply(node);
@@ -284,7 +291,7 @@ RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<NandEliminate>
>::apply(node);
@@ -292,7 +299,7 @@ RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<NorEliminate>
>::apply(node);
@@ -300,7 +307,7 @@ RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<CompEliminate>
>::apply(node);
@@ -308,7 +315,7 @@ RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) {
Node resultNode = node;
resultNode = LinearRewriteStrategy
@@ -318,7 +325,7 @@ RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
>::apply(node);
// only apply if every subterm was already rewritten
- if (!preregister) {
+ if (!prerewrite) {
// distributes multiplication by constant over +, - and unary -
if(RewriteRule<MultDistribConst>::applies(resultNode)) {
resultNode = RewriteRule<MultDistribConst>::run<false>(resultNode);
@@ -333,23 +340,28 @@ RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewritePlus(TNode node, bool preregister) {
- if (preregister) {
- return RewriteResponse(REWRITE_DONE, node);
+RewriteResponse TheoryBVRewriter::RewritePlus(TNode node, bool prerewrite) {
+ Node resultNode = node;
+ if (prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<FlattenAssocCommut>
+ >::apply(node);
+ return RewriteResponse(REWRITE_DONE, resultNode);
}
- Node resultNode = LinearRewriteStrategy
- < RewriteRule<FlattenAssocCommut>,
+
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<FlattenAssocCommut>,
RewriteRule<PlusCombineLikeTerms>
- // RewriteRule<PlusLiftConcat>
>::apply(node);
- if (resultNode == node) {
- return RewriteResponse(REWRITE_DONE, resultNode);
- } else {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+
+ if (node != resultNode) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
+
+ return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool prerewrite){
// return RewriteResponse(REWRITE_DONE, node);
Node resultNode = LinearRewriteStrategy
< RewriteRule<SubEliminate>
@@ -358,7 +370,7 @@ RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) {
Node resultNode = node;
resultNode = LinearRewriteStrategy
@@ -372,7 +384,7 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
- if(!preregister) {
+ if(!prerewrite) {
if (RewriteRule<NegMult>::applies(node)) {
resultNode = RewriteRule<NegMult>::run<false>(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
@@ -382,8 +394,27 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
+RewriteResponse TheoryBVRewriter::RewriteUdiv(TNode node, bool prerewrite){
+ Node resultNode = node;
+
+ if(node[1].isConst() && node[1].getConst<BitVector>().getValue() != 0) {
+ return RewriteUdivTotal(node, prerewrite);
+ }
-RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool preregister){
+ return RewriteResponse(REWRITE_DONE, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteUrem(TNode node, bool prerewrite){
+ Node resultNode = node;
+
+ if(node[1].isConst() && node[1].getConst<BitVector>().getValue() != 0) {
+ return RewriteUremTotal(node, prerewrite);
+ }
+
+ return RewriteResponse(REWRITE_DONE, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool prerewrite){
Node resultNode = node;
if(RewriteRule<UdivPow2>::applies(node)) {
@@ -400,7 +431,7 @@ RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool preregister)
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<UremPow2>::applies(node)) {
@@ -416,7 +447,7 @@ RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool preregister)
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SmodEliminate>
>::apply(node);
@@ -424,7 +455,7 @@ RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SdivEliminate>
>::apply(node);
@@ -432,14 +463,14 @@ RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SremEliminate>
>::apply(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<ShlByConst>::applies(node)) {
resultNode = RewriteRule<ShlByConst>::run <false> (node);
@@ -454,7 +485,7 @@ RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<LshrByConst>::applies(node)) {
resultNode = RewriteRule<LshrByConst>::run <false> (node);
@@ -469,7 +500,7 @@ RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<AshrByConst>::applies(node)) {
resultNode = RewriteRule<AshrByConst>::run <false> (node);
@@ -485,7 +516,7 @@ RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool preregister) {
}
-RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<RepeatEliminate >
>::apply(node);
@@ -493,7 +524,7 @@ RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<ZeroExtendEliminate >
>::apply(node);
@@ -501,7 +532,7 @@ RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool preregister
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalSignExtend>
>::apply(node);
@@ -511,7 +542,7 @@ RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool preregister
}
-RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<RotateRightEliminate >
>::apply(node);
@@ -519,16 +550,32 @@ RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool preregiste
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<RotateLeftEliminate >
- >::apply(node);
+ >::apply(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool preregister) {
- if (preregister) {
+RewriteResponse TheoryBVRewriter::RewriteBVToNat(TNode node, bool prerewrite) {
+ Node resultNode = LinearRewriteStrategy
+ < RewriteRule<BVToNatEliminate>
+ >::apply(node);
+
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteIntToBV(TNode node, bool prerewrite) {
+ Node resultNode = LinearRewriteStrategy
+ < RewriteRule<IntToBVEliminate>
+ >::apply(node);
+
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool prerewrite) {
+ if (prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<FailEq>,
RewriteRule<SimplifyEq>,
@@ -593,8 +640,8 @@ void TheoryBVRewriter::initializeRewrites() {
d_rewriteTable [ kind::BITVECTOR_PLUS ] = RewritePlus;
d_rewriteTable [ kind::BITVECTOR_SUB ] = RewriteSub;
d_rewriteTable [ kind::BITVECTOR_NEG ] = RewriteNeg;
- // d_rewriteTable [ kind::BITVECTOR_UDIV ] = RewriteUdiv;
- // d_rewriteTable [ kind::BITVECTOR_UREM ] = RewriteUrem;
+ d_rewriteTable [ kind::BITVECTOR_UDIV ] = RewriteUdiv;
+ d_rewriteTable [ kind::BITVECTOR_UREM ] = RewriteUrem;
d_rewriteTable [ kind::BITVECTOR_UDIV_TOTAL ] = RewriteUdivTotal;
d_rewriteTable [ kind::BITVECTOR_UREM_TOTAL ] = RewriteUremTotal;
d_rewriteTable [ kind::BITVECTOR_SMOD ] = RewriteSmod;
@@ -609,6 +656,9 @@ void TheoryBVRewriter::initializeRewrites() {
d_rewriteTable [ kind::BITVECTOR_SIGN_EXTEND ] = RewriteSignExtend;
d_rewriteTable [ kind::BITVECTOR_ROTATE_RIGHT ] = RewriteRotateRight;
d_rewriteTable [ kind::BITVECTOR_ROTATE_LEFT ] = RewriteRotateLeft;
+
+ d_rewriteTable [ kind::BITVECTOR_TO_NAT ] = RewriteBVToNat;
+ d_rewriteTable [ kind::INT_TO_BITVECTOR ] = RewriteIntToBV;
}
Node TheoryBVRewriter::eliminateBVSDiv(TNode node) {
diff --git a/src/theory/bv/theory_bv_rewriter.h b/src/theory/bv/theory_bv_rewriter.h
index 183b5e8d5..def8e24fe 100644
--- a/src/theory/bv/theory_bv_rewriter.h
+++ b/src/theory/bv/theory_bv_rewriter.h
@@ -78,6 +78,9 @@ class TheoryBVRewriter {
static RewriteResponse RewriteRotateRight(TNode node, bool prerewrite = false);
static RewriteResponse RewriteRotateLeft(TNode node, bool prerewrite = false);
+ static RewriteResponse RewriteBVToNat(TNode node, bool prerewrite = false);
+ static RewriteResponse RewriteIntToBV(TNode node, bool prerewrite = false);
+
public:
static RewriteResponse postRewrite(TNode node);
diff --git a/src/theory/bv/theory_bv_type_rules.h b/src/theory/bv/theory_bv_type_rules.h
index 00284e7ae..67dae0cfa 100644
--- a/src/theory/bv/theory_bv_type_rules.h
+++ b/src/theory/bv/theory_bv_type_rules.h
@@ -29,6 +29,11 @@ class BitVectorConstantTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if (check) {
+ if (n.getConst<BitVector>().getSize() == 0) {
+ throw TypeCheckingExceptionPrivate(n, "constant of size 0");
+ }
+ }
return nodeManager->mkBitVectorType(n.getConst<BitVector>().getSize());
}
};
@@ -190,6 +195,29 @@ public:
}
};
+class BitVectorConversionTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if(n.getKind() == kind::BITVECTOR_TO_NAT) {
+ if(check && !n[0].getType(check).isBitVector()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term");
+ }
+ return nodeManager->integerType();
+ }
+
+ if(n.getKind() == kind::INT_TO_BITVECTOR) {
+ size_t bvSize = n.getOperator().getConst<IntToBitVector>();
+ if(check && !n[0].getType(check).isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting integer term");
+ }
+ return nodeManager->mkBitVectorType(bvSize);
+ }
+
+ InternalError("bv-conversion typerule invoked for non-bv-conversion kind");
+ }
+};
+
class CardinalityComputer {
public:
inline static Cardinality computeCardinality(TypeNode type) {
diff --git a/src/theory/bv/theory_bv_utils.h b/src/theory/bv/theory_bv_utils.h
index 5847bac3e..ab6a615a2 100644
--- a/src/theory/bv/theory_bv_utils.h
+++ b/src/theory/bv/theory_bv_utils.h
@@ -357,7 +357,7 @@ inline Node flattenAnd(std::vector<TNode>& queue) {
}
-// neeed a better name, this is not technically a ground term
+// need a better name, this is not technically a ground term
inline bool isBVGroundTerm(TNode node) {
if (node.getNumChildren() == 0) {
return node.isConst();
diff --git a/src/theory/datatypes/datatypes_rewriter.h b/src/theory/datatypes/datatypes_rewriter.h
index bc6d1f839..186444e0a 100644
--- a/src/theory/datatypes/datatypes_rewriter.h
+++ b/src/theory/datatypes/datatypes_rewriter.h
@@ -21,6 +21,7 @@
#include "theory/rewriter.h"
#include "theory/datatypes/options.h"
+#include "theory/type_enumerator.h"
namespace CVC4 {
namespace theory {
@@ -137,10 +138,16 @@ public:
return RewriteResponse(REWRITE_DONE, in[0][selectorIndex]);
}else{
if( options::dtRewriteErrorSel() ){
- Node gt = in.getType().mkGroundTerm();
+ Node gt;
+ if( in.getType().isSort() ){
+ TypeEnumerator te(in.getType());
+ gt = *te;
+ }else{
+ gt = in.getType().mkGroundTerm();
+ }
TypeNode gtt = gt.getType();
//Assert( gtt.isDatatype() || gtt.isParametricDatatype() );
- if( !gtt.isInstantiatedDatatype() ){
+ if( gtt.isDatatype() && !gtt.isInstantiatedDatatype() ){
gt = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
NodeManager::currentNM()->mkConst(AscriptionType(in.getType().toType())), gt);
}
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index 2e58677df..81ef32b32 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -88,7 +88,7 @@ typerule APPLY_TYPE_ASCRIPTION ::CVC4::theory::datatypes::DatatypeAscriptionType
# constructor applications are constant if they are applied only to constants
construle APPLY_CONSTRUCTOR ::CVC4::theory::datatypes::DatatypeConstructorTypeRule
-operator TUPLE_TYPE 1: "tuple type"
+operator TUPLE_TYPE 0: "tuple type"
cardinality TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleProperties::computeCardinality(%TYPE%)" \
"theory/datatypes/theory_datatypes_type_rules.h"
@@ -100,7 +100,7 @@ enumerator TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleEnumerator" \
"theory/datatypes/type_enumerator.h"
-operator TUPLE 1: "a tuple"
+operator TUPLE 0: "a tuple"
typerule TUPLE ::CVC4::theory::datatypes::TupleTypeRule
construle TUPLE ::CVC4::theory::datatypes::TupleProperties
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 7f96232d6..a0651efb4 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -91,7 +91,7 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( Node n, bool doMake
}
void TheoryDatatypes::check(Effort e) {
-
+ Trace("datatypes-debug") << "Check effort " << e << std::endl;
while(!done() && !d_conflict) {
// Get all the assertions
Assertion assertion = get();
@@ -117,80 +117,95 @@ void TheoryDatatypes::check(Effort e) {
if( e == EFFORT_FULL ) {
Debug("datatypes-split") << "Check for splits " << e << endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- if( DatatypesRewriter::isTermDatatype( n ) ){
- EqcInfo* eqc = getOrMakeEqcInfo( n, true );
- //if there are more than 1 possible constructors for eqc
- if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- //if only one constructor, then this term must be this constructor
- if( dt.getNumConstructors()==1 ){
- Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
- d_pending.push_back( t );
- d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
- Trace("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
- d_infer.push_back( t );
- }else{
- std::vector< bool > pcons;
- getPossibleCons( eqc, n, pcons );
- //std::cout << "pcons " << n << " = ";
- //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
- //std::cout << std::endl;
- //check if we do not need to resolve the constructor type for this equivalence class.
- // this is if there are no selectors for this equivalence class, its possible values are infinite,
- // and we are not producing a model, then do not split.
- int consIndex = -1;
- bool needSplit = true;
- for( unsigned int j=0; j<pcons.size(); j++ ) {
- if( pcons[j] ) {
- if( consIndex==-1 ){
- consIndex = j;
+ bool addedFact = false;
+ do {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ if( DatatypesRewriter::isTermDatatype( n ) ){
+ Trace("datatypes-debug") << "Process equivalence class " << n << std::endl;
+ EqcInfo* eqc = getOrMakeEqcInfo( n, true );
+ //if there are more than 1 possible constructors for eqc
+ if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
+ Trace("datatypes-debug") << "No constructor..." << std::endl;
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ //if only one constructor, then this term must be this constructor
+ if( dt.getNumConstructors()==1 ){
+ Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
+ d_pending.push_back( t );
+ d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
+ Trace("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
+ d_infer.push_back( t );
+ }else{
+ std::vector< bool > pcons;
+ getPossibleCons( eqc, n, pcons );
+ //std::cout << "pcons " << n << " = ";
+ //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
+ //std::cout << std::endl;
+ //check if we do not need to resolve the constructor type for this equivalence class.
+ // this is if there are no selectors for this equivalence class, its possible values are infinite,
+ // and we are not producing a model, then do not split.
+ int consIndex = -1;
+ bool needSplit = true;
+ for( unsigned int j=0; j<pcons.size(); j++ ) {
+ if( pcons[j] ) {
+ if( consIndex==-1 ){
+ consIndex = j;
+ }
+ if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
+ needSplit = false;
+ }
}
- if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
- needSplit = false;
+ }
+ if( !needSplit && mustSpecifyAssignment() ){
+ //for the sake of termination, we must choose the constructor of a ground term
+ //NEED GUARENTEE: groundTerm should not contain any subterms of the same type
+ //** TODO: this is probably not good enough, actually need fair enumeration strategy
+ Node groundTerm = n.getType().mkGroundTerm();
+ int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
+ if( pcons[index] ){
+ consIndex = index;
}
+ needSplit = true;
}
- }
- if( !needSplit && mustSpecifyAssignment() ){
- //for the sake of termination, we must choose the constructor of a ground term
- //NEED GUARENTEE: groundTerm should not contain any subterms of the same type
- //** TODO: this is probably not good enough, actually need fair enumeration strategy
- Node groundTerm = n.getType().mkGroundTerm();
- int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
- if( pcons[index] ){
- consIndex = index;
+ if( needSplit && consIndex!=-1 ) {
+ Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
+ Trace("dt-split") << "*************Split for possible constructor " << dt[consIndex] << " for " << n << endl;
+ test = Rewriter::rewrite( test );
+ NodeBuilder<> nb(kind::OR);
+ nb << test << test.notNode();
+ Node lemma = nb;
+ d_out->lemma( lemma );
+ d_out->requirePhase( test, true );
+ return;
+ }else{
+ Trace("dt-split") << "Do not split constructor for " << n << std::endl;
}
- needSplit = true;
- }
- if( needSplit && consIndex!=-1 ) {
- Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
- Trace("dt-split") << "*************Split for possible constructor " << dt[consIndex] << " for " << n << endl;
- test = Rewriter::rewrite( test );
- NodeBuilder<> nb(kind::OR);
- nb << test << test.notNode();
- Node lemma = nb;
- d_out->lemma( lemma );
- d_out->requirePhase( test, true );
- return;
- }else{
- Trace("dt-split") << "Do not split constructor for " << n << std::endl;
}
+ }else{
+ Trace("datatypes-debug") << "Has constructor " << eqc->d_constructor.get() << std::endl;
}
}
+ ++eqcs_i;
}
- ++eqcs_i;
- }
- flushPendingFacts();
- if( !d_conflict ){
- if( options::dtRewriteErrorSel() ){
- collapseSelectors();
- flushPendingFacts();
+ Trace("datatypes-debug") << "Flush pending facts..." << std::endl;
+ addedFact = !d_pending.empty() || !d_pending_merge.empty();
+ flushPendingFacts();
+ if( !d_conflict ){
+ if( options::dtRewriteErrorSel() ){
+ bool innerAddedFact = false;
+ do {
+ collapseSelectors();
+ innerAddedFact = !d_pending.empty() || !d_pending_merge.empty();
+ flushPendingFacts();
+ }while( !d_conflict && innerAddedFact );
+ }
}
- }
+ }while( !d_conflict && addedFact );
+ Trace("datatypes-debug") << "Finished. " << d_conflict << std::endl;
if( !d_conflict ){
- // printModelDebug();
+ Trace("dt-model-test") << std::endl;
+ printModelDebug("dt-model-test");
}
}
@@ -1003,8 +1018,8 @@ bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
// (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
//We may need to communicate (3) outwards if the conclusions involve other theories
Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl;
+ bool addLemma = false;
if( ( n.getKind()==EQUAL || n.getKind()==IFF) && n[1].getKind()==APPLY_CONSTRUCTOR && exp.getKind()!=EQUAL ){
- bool addLemma = false;
#if 1
const Datatype& dt = ((DatatypeType)(n[1].getType()).toType()).getDatatype();
addLemma = dt.involvesExternalType();
@@ -1028,6 +1043,11 @@ bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
}
}
}
+ //else if( exp.getKind()==APPLY_TESTER ){
+ //if( n.getKind()==EQUAL && !DatatypesRewriter::isTermDatatype( n[0] ) ){
+ // return true;
+ //}
+ //}
Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl;
return false;
}
@@ -1066,6 +1086,10 @@ Node TheoryDatatypes::getRepresentative( Node a ){
void TheoryDatatypes::printModelDebug( const char* c ){
+ if(! (Trace.isOn(c))) {
+ return;
+ }
+
Trace( c ) << "Datatypes model : " << std::endl;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
diff --git a/src/theory/idl/Makefile b/src/theory/idl/Makefile
new file mode 100644
index 000000000..75ae33c7e
--- /dev/null
+++ b/src/theory/idl/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/idl
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/idl/Makefile.am b/src/theory/idl/Makefile.am
new file mode 100644
index 000000000..4297e3bdb
--- /dev/null
+++ b/src/theory/idl/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@builddir@/../.. -I@srcdir@/../../include -I@srcdir@/../..
+AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = libidl.la
+
+libidl_la_SOURCES = \
+ idl_model.h \
+ idl_model.cpp \
+ idl_assertion.h \
+ idl_assertion.cpp \
+ idl_assertion_db.h \
+ idl_assertion_db.cpp \
+ theory_idl.h \
+ theory_idl.cpp
+
+EXTRA_DIST = \
+ kinds
diff --git a/src/theory/idl/idl_assertion.cpp b/src/theory/idl/idl_assertion.cpp
new file mode 100644
index 000000000..1e725932b
--- /dev/null
+++ b/src/theory/idl/idl_assertion.cpp
@@ -0,0 +1,213 @@
+/********************* */
+/*! \file idl_assertion.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 "theory/idl/idl_assertion.h"
+
+using namespace CVC4;
+using namespace theory;
+using namespace idl;
+
+IDLAssertion::IDLAssertion()
+: d_op(kind::LAST_KIND)
+{}
+
+IDLAssertion::IDLAssertion(TNode node) {
+ bool ok = parse(node, 1, false);
+ if (!ok) {
+ d_x = d_y = TNode::null();
+ } else {
+ if (d_op == kind::GT) {
+ // Turn GT into LT x - y > c is the same as y - x < -c
+ std::swap(d_x, d_y);
+ d_c = -d_c;
+ d_op = kind::LT;
+ }
+ if (d_op == kind::GEQ) {
+ // Turn GT into LT x - y >= c is the same as y - x <= -c
+ std::swap(d_x, d_y);
+ d_c = -d_c;
+ d_op = kind::LEQ;
+ }
+ if (d_op == kind::LT) {
+ // Turn strict into non-strict x - y < c is the same as x - y <= c-1
+ d_c = d_c - 1;
+ d_op = kind::LEQ;
+ }
+ }
+ d_original = node;
+}
+
+IDLAssertion::IDLAssertion(const IDLAssertion& other)
+: d_x(other.d_x)
+, d_y(other.d_y)
+, d_op(other.d_op)
+, d_c(other.d_c)
+, d_original(other.d_original)
+{}
+
+bool IDLAssertion::propagate(IDLModel& model) const {
+ Debug("theory::idl::model") << model << std::endl;
+ Assert(ok());
+ // Should be d_x - d_y <= d_c, or d_x - d_c <= d_y
+ Integer x_value = model.getValue(d_x);
+ Integer y_value = model.getValue(d_y);
+ if (x_value - y_value > d_c) {
+ model.setValue(d_y, x_value - d_c, IDLReason(d_x, d_original));
+ Debug("theory::idl::model") << model << std::endl;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void IDLAssertion::toStream(std::ostream& out) const {
+ out << "IDL[" << d_x << " - " << d_y << " " << d_op << " " << d_c << "]";
+}
+
+/** Negates the given arithmetic kind */
+static Kind negateOp(Kind op) {
+ switch (op) {
+ case kind::LT:
+ // not (a < b) = (a >= b)
+ return kind::GEQ;
+ case kind::LEQ:
+ // not (a <= b) = (a > b)
+ return kind::GT;
+ case kind::GT:
+ // not (a > b) = (a <= b)
+ return kind::LEQ;
+ case kind::GEQ:
+ // not (a >= b) = (a < b)
+ return kind::LT;
+ case kind::EQUAL:
+ // not (a = b) = (a != b)
+ return kind::DISTINCT;
+ case kind::DISTINCT:
+ // not (a != b) = (a = b)
+ return kind::EQUAL;
+ default:
+ Unreachable();
+ break;
+ }
+ return kind::LAST_KIND;
+}
+
+bool IDLAssertion::parse(TNode node, int c, bool negated) {
+
+ // Only unit coefficients allowed
+ if (c != 1 && c != -1) {
+ return false;
+ }
+
+ // Assume we're ok
+ bool ok = true;
+
+ // The kind of the node
+ switch(node.getKind()) {
+
+ case kind::NOT:
+ // We parse the negation
+ ok = parse(node[0], c, true);
+ // Setup the kind
+ if (ok) {
+ d_op = negateOp(d_op);
+ }
+ break;
+
+ case kind::EQUAL:
+ case kind::LT:
+ case kind::LEQ:
+ case kind::GT:
+ case kind::GEQ: {
+ // All relation operators are parsed on both sides
+ d_op = node.getKind();
+ ok = parse(node[0], c, negated);
+ if (ok) {
+ ok = parse(node[1],-c, negated);
+ }
+ break;
+ }
+
+ case kind::CONST_RATIONAL: {
+ // Constants
+ Rational m = node.getConst<Rational>();
+ if (m.isIntegral()) {
+ d_c += m.getNumerator() * (-c);
+ } else {
+ ok = false;
+ }
+ break;
+ }
+ case kind::MULT: {
+ // Only unit multiplication of variables
+ if (node.getNumChildren() == 2 && node[0].isConst()) {
+ Rational a = node[0].getConst<Rational>();
+ if (a == 1 || a == -1) {
+ ok = parse(node[1], c * a.sgn(), negated);
+ } else {
+ ok = false;
+ }
+ } else {
+ ok = false;
+ }
+ break;
+ }
+
+ case kind::PLUS: {
+ for(unsigned i = 0; i < node.getNumChildren(); ++i) {
+ ok = parse(node[i], c, negated);
+ if(!ok) {
+ break;
+ }
+ }
+ break;
+ }
+
+ case kind::MINUS: {
+ ok = parse(node[0], c, negated);
+ if (ok) {
+ ok = parse(node[1], -c, negated);
+ }
+ break;
+ }
+
+ case kind::UMINUS: {
+ ok = parse(node[0], -c, negated);
+ break;
+ }
+
+ default: {
+ if (c > 0) {
+ if (d_x.isNull()) {
+ d_x = node;
+ } else {
+ ok = false;
+ }
+ } else {
+ if (d_y.isNull()) {
+ d_y = node;
+ } else {
+ ok = false;
+ }
+ }
+ break;
+ }
+ } // End case
+
+ // Difference logic OK
+ return ok;
+}
diff --git a/src/theory/idl/idl_assertion.h b/src/theory/idl/idl_assertion.h
new file mode 100644
index 000000000..8ce0e93b2
--- /dev/null
+++ b/src/theory/idl/idl_assertion.h
@@ -0,0 +1,91 @@
+/********************* */
+/*! \file idl_assertion.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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
+ **/
+
+#pragma once
+
+#include "theory/idl/idl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace idl {
+
+/**
+ * An internal representation of the IDL assertions. Each IDL assertions is
+ * of the form (x - y op c) where op is one of (<=, =, !=). IDL assertion
+ * can be constructed from an expression.
+ */
+class IDLAssertion {
+
+ /** The positive variable */
+ TNode d_x;
+ /** The negative variable */
+ TNode d_y;
+ /** The relation */
+ Kind d_op;
+ /** The RHS constant */
+ Integer d_c;
+
+ /** Original assertion we got this one from */
+ TNode d_original;
+
+ /** Parses the given node into an assertion, and return true if OK. */
+ bool parse(TNode node, int c = 1, bool negated = false);
+
+public:
+
+ /** Null assertion */
+ IDLAssertion();
+ /** Create the assertion from given node */
+ IDLAssertion(TNode node);
+ /** Copy constructor */
+ IDLAssertion(const IDLAssertion& other);
+
+ TNode getX() const { return d_x; }
+ TNode getY() const { return d_y; }
+ Kind getOp() const { return d_op;}
+ Integer getC() const { return d_c; }
+
+ /**
+ * Propagate the constraint using the model. For example, if the constraint
+ * is of the form x - y <= -1, and the value of x in the model is 0, then
+ *
+ * (x - y <= -1) and (x = 0) implies y >= x + 1 = 1
+ *
+ * If the value of y is less then 1, is is set to 1 and true is returned. If
+ * the value of y is 1 or more, than false is return.
+ *
+ * @return true if value of y was updated
+ */
+ bool propagate(IDLModel& model) const;
+
+ /** Is this constraint proper */
+ bool ok() const {
+ return !d_x.isNull() || !d_y.isNull();
+ }
+
+ /** Output to the stream */
+ void toStream(std::ostream& out) const;
+};
+
+inline std::ostream& operator << (std::ostream& out, const IDLAssertion& assertion) {
+ assertion.toStream(out);
+ return out;
+}
+
+}
+}
+}
diff --git a/src/theory/idl/idl_assertion_db.cpp b/src/theory/idl/idl_assertion_db.cpp
new file mode 100644
index 000000000..697c70c02
--- /dev/null
+++ b/src/theory/idl/idl_assertion_db.cpp
@@ -0,0 +1,59 @@
+/********************* */
+/*! \file idl_assertion_db.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 "theory/idl/idl_assertion_db.h"
+
+using namespace CVC4;
+using namespace theory;
+using namespace idl;
+
+IDLAssertionDB::IDLAssertionDB(context::Context* c)
+: d_assertions(c)
+, d_variableLists(c)
+{}
+
+void IDLAssertionDB::add(const IDLAssertion& assertion, TNode var) {
+ // Is there a list for the variable already?
+ unsigned previous = -1;
+ var_to_unsigned_map::iterator find = d_variableLists.find(var);
+ if (find != d_variableLists.end()) {
+ previous = (*find).second;
+ }
+ // Add to the DB
+ d_variableLists[var] = d_assertions.size();
+ d_assertions.push_back(IDLAssertionListElement(assertion, previous));
+}
+
+IDLAssertionDB::iterator::iterator(IDLAssertionDB& db, TNode var)
+: d_db(db)
+, d_current(-1)
+{
+ var_to_unsigned_map::const_iterator find = d_db.d_variableLists.find(var);
+ if (find != d_db.d_variableLists.end()) {
+ d_current = (*find).second;
+ }
+}
+
+void IDLAssertionDB::iterator::next() {
+ if (d_current != (unsigned)(-1)) {
+ d_current = d_db.d_assertions[d_current].d_previous;
+ }
+}
+
+IDLAssertion IDLAssertionDB::iterator::get() const {
+ return d_db.d_assertions[d_current].d_assertion;
+}
diff --git a/src/theory/idl/idl_assertion_db.h b/src/theory/idl/idl_assertion_db.h
new file mode 100644
index 000000000..0501bc6bf
--- /dev/null
+++ b/src/theory/idl/idl_assertion_db.h
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file idl_assertion_db.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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
+ **/
+
+#pragma once
+
+#include "theory/idl/idl_assertion.h"
+#include "context/cdlist.h"
+
+namespace CVC4 {
+namespace theory {
+namespace idl {
+
+/**
+ * Context-dependent database assertions, organized by variable. Each variable
+ * can be associated a list of IDL assertions. The list of assertions can
+ * be iterated over using the provided iterator class.
+ */
+class IDLAssertionDB {
+
+ /** Elements of the assertion lists */
+ struct IDLAssertionListElement {
+ /** The assertion itself */
+ IDLAssertion d_assertion;
+ /** The inndex of the previous element (-1 for null) */
+ unsigned d_previous;
+
+ IDLAssertionListElement(const IDLAssertion& assertion, unsigned previous)
+ : d_assertion(assertion), d_previous(previous)
+ {}
+ };
+
+ /** All assertions in a context dependent stack */
+ context::CDList<IDLAssertionListElement> d_assertions;
+
+ typedef context::CDHashMap<TNode, unsigned, TNodeHashFunction> var_to_unsigned_map;
+
+ /** Map from variables to the first element of their list */
+ var_to_unsigned_map d_variableLists;
+
+public:
+
+ /** Create a new assertion database */
+ IDLAssertionDB(context::Context* c);
+
+ /** Add a new assertion, attach to the list of the given variable */
+ void add(const IDLAssertion& assertion, TNode var);
+
+ /** Iteration over the constraints of a variable */
+ class iterator {
+ /** The database */
+ const IDLAssertionDB& d_db;
+ /** Index of the current constraint */
+ unsigned d_current;
+ public:
+ /** Construct the iterator for the variable */
+ iterator(IDLAssertionDB& db, TNode var);
+ /** Is this iterator done */
+ bool done() const { return d_current == (unsigned)(-1); }
+ /** Next element */
+ void next();
+ /** Get the assertion */
+ IDLAssertion get() const;
+ };
+};
+
+}
+}
+}
+
+
+
+
diff --git a/src/theory/idl/idl_model.cpp b/src/theory/idl/idl_model.cpp
new file mode 100644
index 000000000..75f4834ea
--- /dev/null
+++ b/src/theory/idl/idl_model.cpp
@@ -0,0 +1,64 @@
+/********************* */
+/*! \file idl_model.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 "theory/idl/idl_model.h"
+
+using namespace CVC4;
+using namespace theory;
+using namespace idl;
+
+IDLModel::IDLModel(context::Context* context)
+: d_model(context)
+, d_reason(context)
+{}
+
+Integer IDLModel::getValue(TNode var) const {
+ model_value_map::const_iterator find = d_model.find(var);
+ if (find != d_model.end()) {
+ return (*find).second;
+ } else {
+ return 0;
+ }
+}
+
+void IDLModel::setValue(TNode var, Integer value, IDLReason reason) {
+ Assert(!reason.constraint.isNull());
+ d_model[var] = value;
+ d_reason[var] = reason;
+}
+
+void IDLModel::getReasonCycle(TNode var, std::vector<TNode>& reasons) {
+ TNode current = var;
+ do {
+ Debug("theory::idl::model") << "processing: " << var << std::endl;
+ Assert(d_reason.find(current) != d_reason.end());
+ IDLReason reason = d_reason[current];
+ Debug("theory::idl::model") << "adding reason: " << reason.constraint << std::endl;
+ reasons.push_back(reason.constraint);
+ current = reason.x;
+ } while (current != var);
+}
+
+void IDLModel::toStream(std::ostream& out) const {
+ model_value_map::const_iterator it = d_model.begin();
+ model_value_map::const_iterator it_end = d_model.end();
+ out << "Model[" << std::endl;
+ for (; it != it_end; ++ it) {
+ out << (*it).first << " -> " << (*it).second << std::endl;
+ }
+ out << "]";
+}
diff --git a/src/theory/idl/idl_model.h b/src/theory/idl/idl_model.h
new file mode 100644
index 000000000..64407684b
--- /dev/null
+++ b/src/theory/idl/idl_model.h
@@ -0,0 +1,84 @@
+/********************* */
+/*! \file idl_model.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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
+ **/
+
+#pragma once
+
+#include "expr/node.h"
+#include "context/cdhashmap.h"
+
+namespace CVC4 {
+namespace theory {
+namespace idl {
+
+/**
+ * A reason for a value of a variable in the model is a constraint that implies
+ * this value by means of the value of another variable. For example, if the
+ * value of x is 0, then the variable x and the constraint (y > 0) are a reason
+ * for the y taking the value 1.
+ */
+struct IDLReason {
+ /** The variable of the reason */
+ TNode x;
+ /** The constraint of the reaason */
+ TNode constraint;
+
+ IDLReason(TNode x, TNode constraint)
+ : x(x), constraint(constraint) {}
+ IDLReason() {}
+};
+
+/**
+ * A model maps variables to integer values and backs them up with reasons.
+ * Default values (if not set with setValue) for all variables are 0.
+ */
+class IDLModel {
+
+ typedef context::CDHashMap<TNode, Integer, TNodeHashFunction> model_value_map;
+ typedef context::CDHashMap<TNode, IDLReason, TNodeHashFunction> model_reason_map;
+
+ /** Values assigned to individual variables */
+ model_value_map d_model;
+
+ /** Reasons constraining the individual variables */
+ model_reason_map d_reason;
+
+public:
+
+ IDLModel(context::Context* context);
+
+ /** Get the model value of the variable */
+ Integer getValue(TNode var) const;
+
+ /** Set the value of the variable */
+ void setValue(TNode var, Integer value, IDLReason reason);
+
+ /** Get the cycle of reasons behind the variable var */
+ void getReasonCycle(TNode var, std::vector<TNode>& reasons);
+
+ /** Output to the given stream */
+ void toStream(std::ostream& out) const;
+
+};
+
+inline std::ostream& operator << (std::ostream& out, const IDLModel& model) {
+ model.toStream(out);
+ return out;
+}
+
+}
+}
+}
diff --git a/src/theory/idl/kinds b/src/theory/idl/kinds
new file mode 100644
index 000000000..6bf0218b0
--- /dev/null
+++ b/src/theory/idl/kinds
@@ -0,0 +1,8 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+alternate THEORY_ARITH "idl" ::CVC4::theory::idl::TheoryIdl "theory/idl/theory_idl.h"
+
diff --git a/src/theory/idl/options b/src/theory/idl/options
new file mode 100644
index 000000000..c1c9edcef
--- /dev/null
+++ b/src/theory/idl/options
@@ -0,0 +1,12 @@
+#
+# Option specification file for CVC4
+# See src/options/base_options for a description of this file format
+#
+
+module IDL "theory/idl/options.h" Idl
+
+option idlRewriteEq --enable-idl-rewrite-equalities/--disable-idl-rewrite-equalities bool :default false :read-write
+ enable rewriting equalities into two inequalities in IDL solver (default is disabled)
+/disable rewriting equalities into two inequalities in IDL solver (default is disabled)
+
+endmodule
diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp
new file mode 100644
index 000000000..e5100fc71
--- /dev/null
+++ b/src/theory/idl/theory_idl.cpp
@@ -0,0 +1,143 @@
+/********************* */
+/*! \file theory_idl.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 "theory/idl/theory_idl.h"
+#include "theory/idl/options.h"
+#include "theory/rewriter.h"
+
+#include <set>
+#include <queue>
+
+using namespace std;
+
+using namespace CVC4;
+using namespace theory;
+using namespace idl;
+
+TheoryIdl::TheoryIdl(context::Context* c, context::UserContext* u, OutputChannel& out,
+ Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
+: Theory(THEORY_ARITH, c, u, out, valuation, logicInfo, qe)
+, d_model(c)
+, d_assertionsDB(c)
+{}
+
+Node TheoryIdl::ppRewrite(TNode atom) {
+ if (atom.getKind() == kind::EQUAL && options::idlRewriteEq()) {
+ // If the option is turned on, each equality into two inequalities. This in
+ // effect removes equalities, and theorefore dis-equalities too.
+ Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
+ Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
+ Node rewritten = Rewriter::rewrite(leq.andNode(geq));
+ return rewritten;
+ } else {
+ return atom;
+ }
+}
+
+void TheoryIdl::check(Effort level) {
+
+ while(!done()) {
+
+ // Get the next assertion
+ Assertion assertion = get();
+ Debug("theory::idl") << "TheoryIdl::check(): processing " << assertion.assertion << std::endl;
+
+ // Convert the assertion into the internal representation
+ IDLAssertion idlAssertion(assertion.assertion);
+ Debug("theory::idl") << "TheoryIdl::check(): got " << idlAssertion << std::endl;
+
+ if (idlAssertion.ok()) {
+ if (idlAssertion.getOp() == kind::DISTINCT) {
+ // We don't handle dis-equalities
+ d_out->setIncomplete();
+ } else {
+ // Process the convex assertions immediately
+ bool ok = processAssertion(idlAssertion);
+ if (!ok) {
+ // In conflict, we're done
+ return;
+ }
+ }
+ } else {
+ // Not an IDL assertion, set incomplete
+ d_out->setIncomplete();
+ }
+ }
+
+}
+
+bool TheoryIdl::processAssertion(const IDLAssertion& assertion) {
+
+ Debug("theory::idl") << "TheoryIdl::processAssertion(" << assertion << ")" << std::endl;
+
+ // Add the constraint (x - y op c) to the list assertions of x
+ d_assertionsDB.add(assertion, assertion.getX());
+
+ // Update the model, if forced by the assertion
+ bool y_updated = assertion.propagate(d_model);
+
+ // If the value of y was updated, we might need to update further
+ if (y_updated) {
+
+ std::queue<TNode> queue; // Queue of variables to consider
+ std::set<TNode> inQueue; // Current elements of the queue
+
+ // Add the first updated variable to the queue
+ queue.push(assertion.getY());
+ inQueue.insert(assertion.getY());
+
+ while (!queue.empty()) {
+ // Pop a new variable x off the queue
+ TNode x = queue.front();
+ queue.pop();
+ inQueue.erase(x);
+
+ // Go through the constraint (x - y op c), and update values of y
+ IDLAssertionDB::iterator it(d_assertionsDB, x);
+ while (!it.done()) {
+ // Get the assertion and update y
+ IDLAssertion x_y_assertion = it.get();
+ y_updated = x_y_assertion.propagate(d_model);
+ // If updated add to the queue
+ if (y_updated) {
+ // If the variable that we updated is the same as the first
+ // variable that we updated, it's a cycle of updates => conflict
+ if (x_y_assertion.getY() == assertion.getX()) {
+ std::vector<TNode> reasons;
+ d_model.getReasonCycle(x_y_assertion.getY(), reasons);
+ // Construct the reason of the conflict
+ Node conflict = NodeManager::currentNM()->mkNode(kind::AND, reasons);
+ d_out->conflict(conflict);
+ return false;
+ } else {
+ // No cycle, just a model update, so we add to the queue
+ TNode y = x_y_assertion.getY();
+ if (inQueue.count(y) == 0) {
+ queue.push(y);
+ inQueue.insert(x_y_assertion.getY());
+ }
+ }
+ }
+ // Go to the next constraint
+ it.next();
+ }
+ }
+ }
+
+ // Everything fine, no conflict
+ return true;
+}
diff --git a/src/theory/idl/theory_idl.h b/src/theory/idl/theory_idl.h
new file mode 100644
index 000000000..c629ad2b0
--- /dev/null
+++ b/src/theory/idl/theory_idl.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file theory_idl.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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
+ **/
+
+#pragma once
+
+#include "cvc4_private.h"
+
+#include "theory/theory.h"
+#include "theory/idl/idl_model.h"
+#include "theory/idl/idl_assertion_db.h"
+
+namespace CVC4 {
+namespace theory {
+namespace idl {
+
+/**
+ * Handles integer difference logic (IDL) constraints.
+ */
+class TheoryIdl : public Theory {
+
+ /** The current model */
+ IDLModel d_model;
+
+ /** The asserted constraints, organized by variable */
+ IDLAssertionDB d_assertionsDB;
+
+ /** Process a new assertion, returns false if in conflict */
+ bool processAssertion(const IDLAssertion& assertion);
+
+public:
+
+ /** Theory constructor. */
+ TheoryIdl(context::Context* c, context::UserContext* u, OutputChannel& out,
+ Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+
+ /** Pre-processing of input atoms */
+ Node ppRewrite(TNode atom);
+
+ /** Check the assertions for satisfiability */
+ void check(Effort effort);
+
+ /** Identity string */
+ std::string identify() const { return "THEORY_IDL"; }
+
+};/* class TheoryIdl */
+
+}/* CVC4::theory::idl namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/ite_simplifier.cpp b/src/theory/ite_simplifier.cpp
index ec9eb27d4..463a9c41a 100644
--- a/src/theory/ite_simplifier.cpp
+++ b/src/theory/ite_simplifier.cpp
@@ -33,7 +33,7 @@ bool ITESimplifier::containsTermITE(TNode e)
}
hash_map<Node, bool, NodeHashFunction>::iterator it;
- it = d_containsTermITECache.find(e);
+ it = d_containsTermITECache.find(e);
if (it != d_containsTermITECache.end()) {
return (*it).second;
}
@@ -60,7 +60,7 @@ bool ITESimplifier::leavesAreConst(TNode e, TheoryId tid)
}
hash_map<Node, bool, NodeHashFunction>::iterator it;
- it = d_leavesConstCache.find(e);
+ it = d_leavesConstCache.find(e);
if (it != d_leavesConstCache.end()) {
return (*it).second;
}
diff --git a/src/theory/ite_simplifier.h b/src/theory/ite_simplifier.h
index 0f648f91d..07fa0dedb 100644
--- a/src/theory/ite_simplifier.h
+++ b/src/theory/ite_simplifier.h
@@ -31,9 +31,7 @@
#include "prop/prop_engine.h"
#include "context/cdhashset.h"
#include "theory/theory.h"
-#include "theory/substitutions.h"
#include "theory/rewriter.h"
-#include "theory/substitutions.h"
#include "theory/shared_terms_database.h"
#include "theory/term_registration_visitor.h"
#include "theory/valuation.h"
@@ -43,6 +41,7 @@
#include "util/ite_removal.h"
namespace CVC4 {
+namespace theory {
class ITESimplifier {
Node d_true;
@@ -160,6 +159,7 @@ public:
};
-}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
#endif
diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp
index dc9de8662..d74f36069 100644
--- a/src/theory/logic_info.cpp
+++ b/src/theory/logic_info.cpp
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic
+ ** Minor contributors (to current version): Dejan Jovanovic, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -105,6 +105,10 @@ std::string LogicInfo::getLogicString() const {
ss << "DT";
++seen;
}
+ if(d_theories[THEORY_STRINGS]) {
+ ss << "S";
+ ++seen;
+ }
if(d_theories[THEORY_ARITH]) {
if(isDifferenceLogic()) {
ss << (areIntegersUsed() ? "I" : "");
@@ -177,10 +181,21 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_ARRAY);
++p;
}
+ if(*p == 'S') {
+ // Strings requires arith for length constraints,
+ // and UF for equality (?)
+ enableTheory(THEORY_STRINGS);
+ enableTheory(THEORY_UF);
+ enableTheory(THEORY_ARITH);
+ enableIntegers();
+ arithOnlyLinear();
+ ++p;
+ }
if(!strncmp(p, "UF", 2)) {
enableTheory(THEORY_UF);
p += 2;
}
+ // allow BV or DT in either order
if(!strncmp(p, "BV", 2)) {
enableTheory(THEORY_BV);
p += 2;
@@ -189,6 +204,10 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_DATATYPES);
p += 2;
}
+ if(!d_theories[THEORY_BV] && !strncmp(p, "BV", 2)) {
+ enableTheory(THEORY_BV);
+ p += 2;
+ }
if(!strncmp(p, "IDL", 3)) {
enableIntegers();
disableReals();
@@ -241,7 +260,12 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
}
if(*p != '\0') {
stringstream err;
- err << "LogicInfo::setLogicString(): junk (\"" << p << "\") at end of logic string: " << logicString;
+ err << "LogicInfo::setLogicString(): ";
+ if(p == logicString) {
+ err << "cannot parse logic string: " << logicString;
+ } else {
+ err << "junk (\"" << p << "\") at end of logic string: " << logicString;
+ }
IllegalArgument(logicString, err.str().c_str());
}
diff --git a/src/theory/logic_info.h b/src/theory/logic_info.h
index c7b5c58f9..2448898c0 100644
--- a/src/theory/logic_info.h
+++ b/src/theory/logic_info.h
@@ -155,21 +155,25 @@ public:
/** Are integers in this logic? */
bool areIntegersUsed() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether integers are used");
return d_integers;
}
/** Are reals in this logic? */
bool areRealsUsed() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether reals are used");
return d_reals;
}
/** Does this logic only linear arithmetic? */
bool isLinear() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether it's linear");
return d_linear || d_differenceLogic;
}
/** Does this logic only permit difference reasoning? (implies linear) */
bool isDifferenceLogic() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether it's difference logic");
return d_differenceLogic;
}
diff --git a/src/theory/model.cpp b/src/theory/model.cpp
index 1c511be30..840c8bc3a 100644
--- a/src/theory/model.cpp
+++ b/src/theory/model.cpp
@@ -19,6 +19,7 @@
#include "smt/options.h"
#include "smt/smt_engine.h"
#include "theory/uf/theory_uf_model.h"
+#include "theory/uf/options.h"
using namespace std;
using namespace CVC4;
@@ -27,7 +28,7 @@ using namespace CVC4::context;
using namespace CVC4::theory;
TheoryModel::TheoryModel( context::Context* c, std::string name, bool enableFuncModels) :
- d_substitutions(c), d_equalityEngine(c, name), d_modelBuilt(c, false), d_enableFuncModels(enableFuncModels)
+ d_substitutions(c, false), d_equalityEngine(c, name), d_modelBuilt(c, false), d_enableFuncModels(enableFuncModels)
{
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
@@ -47,12 +48,15 @@ void TheoryModel::reset(){
d_uf_models.clear();
}
-Node TheoryModel::getValue( TNode n ) const{
+Node TheoryModel::getValue(TNode n) const {
//apply substitutions
- Node nn = d_substitutions.apply( n );
+ Node nn = d_substitutions.apply(n);
//get value in model
- nn = getModelValue( nn );
- Assert(nn.isConst() || nn.getKind() == kind::LAMBDA);
+ nn = getModelValue(nn);
+ if(options::condenseFunctionValues() || nn.getKind() != kind::LAMBDA) {
+ //normalize
+ nn = Rewriter::rewrite(nn);
+ }
return nn;
}
@@ -94,16 +98,15 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
// no good. Instead, return the quantifier itself. If we're in
// checkModel(), and the quantifier actually matters, we'll get an
// assert-fail since the quantifier isn't a constant.
- if(!d_equalityEngine.hasTerm(n)) {
+ if(!d_equalityEngine.hasTerm(Rewriter::rewrite(n))) {
return n;
+ } else {
+ n = Rewriter::rewrite(n);
}
} else {
if(n.getKind() == kind::LAMBDA) {
NodeManager* nm = NodeManager::currentNM();
Node body = getModelValue(n[1], true);
- // This is a bit ugly, but cache inside simplifier can change, so can't be const
- // The ite simplifier is needed to get rid of artifacts created by Boolean terms
- body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body);
body = Rewriter::rewrite(body);
return nm->mkNode(kind::LAMBDA, n[0], body);
}
@@ -430,6 +433,7 @@ void TheoryEngineModelBuilder::checkTerms(TNode n, TheoryModel* tm, NodeSet& cac
void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
{
+ Trace("model-builder") << "TheoryEngineModelBuilder: buildModel, fullModel = " << fullModel << std::endl;
TheoryModel* tm = (TheoryModel*)m;
// buildModel with fullModel = true should only be called once in any context
@@ -718,6 +722,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
}
if (!fullModel) {
+ Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
// Make sure every EC has a rep
for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap ) {
tm->d_reps[itMap->first] = itMap->second;
@@ -851,8 +856,10 @@ void TheoryEngineModelBuilder::processBuildModel(TheoryModel* m, bool fullModel)
default_v = (*te);
}
ufmt.setDefaultValue( m, default_v );
- ufmt.simplify();
- Node val = ufmt.getFunctionValue( "_ufmt_" );
+ if(options::condenseFunctionValues()) {
+ ufmt.simplify();
+ }
+ Node val = ufmt.getFunctionValue( "_ufmt_", options::condenseFunctionValues() );
Trace("model-builder") << " Assigning (" << n << ") to (" << val << ")" << endl;
m->d_uf_models[n] = val;
//ufmt.debugPrint( std::cout, m );
diff --git a/src/theory/options b/src/theory/options
index 5d752fca1..9944264c8 100644
--- a/src/theory/options
+++ b/src/theory/options
@@ -5,8 +5,8 @@
module THEORY "theory/options.h" Theory layer
-expert-option theoryOfMode --theoryof-mode=MODE CVC4::theory::TheoryOfMode :handler CVC4::theory::stringToTheoryOfMode :handler-include "theory/options_handlers.h" :default CVC4::theory::THEORY_OF_TYPE_BASED :include "theory/theoryof_mode.h"
- mode for theoryof
+expert-option theoryOfMode theoryof-mode --theoryof-mode=MODE CVC4::theory::TheoryOfMode :handler CVC4::theory::stringToTheoryOfMode :handler-include "theory/options_handlers.h" :default CVC4::theory::THEORY_OF_TYPE_BASED :include "theory/theoryof_mode.h" :read-write
+ mode for Theory::theoryof()
option - use-theory --use-theory=NAME argument :handler CVC4::theory::useTheory :handler-include "theory/options_handlers.h"
use alternate theory implementation NAME (--use-theory=help for a list)
diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h
index af3065404..44b89e8cb 100644
--- a/src/theory/output_channel.h
+++ b/src/theory/output_channel.h
@@ -127,9 +127,12 @@ public:
*/
LemmaStatus split(TNode n)
throw(TypeCheckingExceptionPrivate, AssertionException) {
- return lemma(n.orNode(n.notNode()));
+ return splitLemma(n.orNode(n.notNode()));
}
+ virtual LemmaStatus splitLemma(TNode n, bool removable = false)
+ throw(TypeCheckingExceptionPrivate, AssertionException) = 0;
+
/**
* If a decision is made on n, it must be in the phase specified.
* Note that this is enforced *globally*, i.e., it is completely
@@ -219,7 +222,7 @@ public:
/** Demands that the search restart from sat search level 0.
* Using this leads to non-termination issues.
- * It is appropraite for prototyping for theories.
+ * It is appropriate for prototyping for theories.
*/
virtual void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException) {}
diff --git a/src/theory/quantifiers/Makefile.am b/src/theory/quantifiers/Makefile.am
index 7fea8cf3a..be24d6c67 100644
--- a/src/theory/quantifiers/Makefile.am
+++ b/src/theory/quantifiers/Makefile.am
@@ -23,8 +23,6 @@ libquantifiers_la_SOURCES = \
model_engine.cpp \
modes.cpp \
modes.h \
- relevant_domain.h \
- relevant_domain.cpp \
term_database.h \
term_database.cpp \
first_order_model.h \
@@ -44,7 +42,20 @@ libquantifiers_la_SOURCES = \
inst_strategy_e_matching.h \
inst_strategy_e_matching.cpp \
inst_strategy_cbqi.h \
- inst_strategy_cbqi.cpp
+ inst_strategy_cbqi.cpp \
+ full_model_check.h \
+ full_model_check.cpp \
+ bounded_integers.h \
+ bounded_integers.cpp \
+ first_order_reasoning.h \
+ first_order_reasoning.cpp \
+ rewrite_engine.h \
+ rewrite_engine.cpp \
+ relevant_domain.h \
+ relevant_domain.cpp \
+ symmetry_breaking.h \
+ symmetry_breaking.cpp
+
EXTRA_DIST = \
kinds \
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
new file mode 100644
index 000000000..30ff5242b
--- /dev/null
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -0,0 +1,372 @@
+/********************* */
+/*! \file bounded_integers.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Bounded integers module
+ **
+ ** This class manages integer bounds for quantifiers
+ **/
+
+#include "theory/quantifiers/bounded_integers.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/model_engine.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+void BoundedIntegers::RangeModel::initialize() {
+ //add initial split lemma
+ Node ltr = NodeManager::currentNM()->mkNode( LT, d_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
+ ltr = Rewriter::rewrite( ltr );
+ Trace("bound-int-lemma") << " *** bound int: initial split on " << ltr << std::endl;
+ d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+ Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+ d_range_literal[-1] = ltr_lit;
+ d_lit_to_range[ltr_lit] = -1;
+ d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+ //register with bounded integers
+ Trace("bound-int-debug") << "Literal " << ltr_lit << " is literal for " << d_range << std::endl;
+ d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+void BoundedIntegers::RangeModel::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() ){
+ Trace("bound-int-assert") << "With polarity = " << pol << " (req "<< d_lit_to_pol[nlit] << ")";
+ Trace("bound-int-assert") << ", found literal " << nlit;
+ Trace("bound-int-assert") << ", it is bound literal " << d_lit_to_range[nlit] << " for " << d_range << std::endl;
+ d_range_assertions[nlit] = (pol==d_lit_to_pol[nlit]);
+ if( pol!=d_lit_to_pol[nlit] ){
+ //check if we need a new split?
+ if( !d_has_range ){
+ bool needsRange = true;
+ for( std::map< Node, int >::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+ if( d_range_assertions.find( it->first )==d_range_assertions.end() ){
+ needsRange = false;
+ break;
+ }
+ }
+ if( needsRange ){
+ allocateRange();
+ }
+ }
+ }else{
+ if (!d_has_range || d_lit_to_range[nlit]<d_curr_range ){
+ Trace("bound-int-bound") << "Successfully bound " << d_range << " to " << d_lit_to_range[nlit] << std::endl;
+ d_curr_range = d_lit_to_range[nlit];
+ }
+ //set the range
+ d_has_range = true;
+ }
+ }else{
+ Message() << "Could not find literal " << nlit << " for range " << d_range << std::endl;
+ exit(0);
+ }
+}
+
+void BoundedIntegers::RangeModel::allocateRange() {
+ d_curr_max++;
+ int newBound = d_curr_max;
+ Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
+ //TODO: newBound should be chosen in a smarter way
+ Node ltr = NodeManager::currentNM()->mkNode( LEQ, d_range, NodeManager::currentNM()->mkConst( Rational(newBound) ) );
+ ltr = Rewriter::rewrite( ltr );
+ Trace("bound-int-lemma") << " *** bound int: split on " << ltr << std::endl;
+ d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+ Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+ d_range_literal[newBound] = ltr_lit;
+ d_lit_to_range[ltr_lit] = newBound;
+ d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+ //register with bounded integers
+ d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
+ //request the current cardinality as a decision literal, if not already asserted
+ for( std::map< Node, int >::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+ int i = it->second;
+ if( !d_has_range || i<d_curr_range ){
+ Node rn = it->first;
+ Assert( !rn.isNull() );
+ if( d_range_assertions.find( rn )==d_range_assertions.end() ){
+ if (!d_lit_to_pol[it->first]) {
+ rn = rn.negate();
+ }
+ Trace("bound-int-dec") << "For " << d_range << ", make decision " << rn << " to make range " << i << std::endl;
+ return rn;
+ }
+ }
+ }
+ return Node::null();
+}
+
+
+BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
+QuantifiersModule(qe), d_assertions(c){
+
+}
+
+bool BoundedIntegers::isBound( Node f, Node v ) {
+ return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
+}
+
+bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
+ if( b.getKind()==BOUND_VARIABLE ){
+ if( !isBound( f, b ) ){
+ return true;
+ }
+ }else{
+ for( unsigned i=0; i<b.getNumChildren(); i++ ){
+ if( hasNonBoundVar( f, b[i] ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void BoundedIntegers::processLiteral( Node f, Node lit, bool pol,
+ 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;
+ for(std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ Trace("bound-int-debug") << " ";
+ if( !it->second.isNull() ){
+ Trace("bound-int-debug") << it->second;
+ if( !it->first.isNull() ){
+ Trace("bound-int-debug") << " * ";
+ }
+ }
+ if( !it->first.isNull() ){
+ Trace("bound-int-debug") << it->first;
+ }
+ Trace("bound-int-debug") << std::endl;
+ }
+ Trace("bound-int-debug") << std::endl;
+ 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 ) ){
+ 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 bv = n1.getKind()==BOUND_VARIABLE ? n1 : n2;
+ if( !isBound( f, bv ) ){
+ if( !hasNonBoundVar( f, n1.getKind()==BOUND_VARIABLE ? n2 : n1 ) ) {
+ Trace("bound-int-debug") << "The bound is relevant." << std::endl;
+ int loru = n1.getKind()==BOUND_VARIABLE ? 0 : 1;
+ d_bounds[loru][f][bv] = (n1.getKind()==BOUND_VARIABLE ? n2 : n1);
+ bound_lit_map[loru][bv] = lit;
+ bound_lit_pol_map[loru][bv] = pol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }else if( lit.getKind()==LEQ || lit.getKind()==LT || lit.getKind()==GT ) {
+ Message() << "BoundedIntegers : Bad kind for literal : " << lit << std::endl;
+ exit(0);
+ }
+}
+
+void BoundedIntegers::process( Node f, Node n, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){
+ if( (( n.getKind()==IMPLIES || n.getKind()==OR) && pol) || (n.getKind()==AND && !pol) ){
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ bool newPol = n.getKind()==IMPLIES && i==0 ? !pol : pol;
+ process( f, n[i], newPol, bound_lit_map, bound_lit_pol_map );
+ }
+ }else if( n.getKind()==NOT ){
+ process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map );
+ }else {
+ processLiteral( f, n, pol, bound_lit_map, bound_lit_pol_map );
+ }
+}
+
+void BoundedIntegers::check( Theory::Effort e ) {
+
+}
+
+
+void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
+ d_lit_to_ranges[lit].push_back(r);
+ //check if it is already asserted?
+ if(d_assertions.find(lit)!=d_assertions.end()){
+ d_rms[r]->assertNode( d_assertions[lit] ? lit : lit.negate() );
+ }
+}
+
+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() ){
+ 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]);
+ 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() );
+ 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 );
+ }
+ 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 );
+ Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
+ }
+ 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( quantifiers::TermDb::hasBoundVarAttr(r) ){
+ //introduce a new bound
+ Node new_range = NodeManager::currentNM()->mkSkolem( "bir_$$", r.getType(), "bound for term" );
+ d_nground_range[f][v] = d_range[f][v];
+ d_range[f][v] = new_range;
+ r = new_range;
+ }
+ if( r.getKind()!=CONST_RATIONAL ){
+ 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;
+ d_ranges.push_back( r );
+ d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext() );
+ d_rms[r]->initialize();
+ }
+ }
+ }
+ }else{
+ Trace("bound-int-warn") << "Warning : Bounded Integers : Could not find bounds for " << f << std::endl;
+ }
+ }
+}
+
+void BoundedIntegers::assertNode( Node n ) {
+ Trace("bound-int-assert") << "Assert " << n << std::endl;
+ Node nlit = n.getKind()==NOT ? n[0] : n;
+ if( d_lit_to_ranges.find(nlit)!=d_lit_to_ranges.end() ){
+ Trace("bound-int-assert") << "This is the bounding literal for " << d_lit_to_ranges[nlit].size() << " ranges." << std::endl;
+ for( unsigned i=0; i<d_lit_to_ranges[nlit].size(); i++) {
+ Node r = d_lit_to_ranges[nlit][i];
+ Trace("bound-int-assert") << " ...this is a bounding literal for " << r << std::endl;
+ d_rms[r]->assertNode( n );
+ }
+ }
+ d_assertions[nlit] = n.getKind()!=NOT;
+}
+
+Node BoundedIntegers::getNextDecisionRequest() {
+ Trace("bound-int-dec") << "bi: Get next decision request?" << std::endl;
+ for( unsigned i=0; i<d_ranges.size(); i++) {
+ Node d = d_rms[d_ranges[i]]->getNextDecisionRequest();
+ if (!d.isNull()) {
+ return d;
+ }
+ }
+ return Node::null();
+}
+
+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
+ 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);
+ l = Node::null();
+ u = Node::null();
+ return;
+ }else{
+ u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }
+ }
+}
+
+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 );
+ Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
+ return;
+}
+
+bool BoundedIntegers::isGroundRange(Node f, Node v) {
+ return isBoundVar(f,v) && !quantifiers::TermDb::hasBoundVarAttr(getLowerBound(f,v)) && !quantifiers::TermDb::hasBoundVarAttr(getUpperBound(f,v));
+}
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
new file mode 100644
index 000000000..3da938d31
--- /dev/null
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -0,0 +1,127 @@
+/********************* */
+/*! \file bounded_integers.h
+** \verbatim
+** Original author: Andrew Reynolds
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2013 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief This class manages integer bounds for quantifiers
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BOUNDED_INTEGERS_H
+#define __CVC4__BOUNDED_INTEGERS_H
+
+
+#include "theory/quantifiers_engine.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+
+class RepSetIterator;
+
+namespace quantifiers {
+
+
+class BoundedIntegers : public QuantifiersModule
+{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+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];
+ std::map< Node, std::vector< Node > > d_set;
+ std::map< Node, std::vector< int > > d_set_nums;
+ std::map< Node, std::map< Node, Node > > d_range;
+ std::map< Node, std::map< Node, Node > > d_nground_range;
+ void hasFreeVar( Node f, Node n );
+ void process( Node f, Node n, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ void processLiteral( Node f, Node lit, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::vector< Node > d_bound_quants;
+private:
+ class RangeModel {
+ private:
+ BoundedIntegers * d_bi;
+ void allocateRange();
+ public:
+ RangeModel(BoundedIntegers * bi, Node r, context::Context* c) : d_bi(bi),
+ d_range(r), d_curr_max(-1), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1) {}
+ Node d_range;
+ int d_curr_max;
+ std::map< int, Node > d_range_literal;
+ std::map< Node, bool > d_lit_to_pol;
+ std::map< Node, int > d_lit_to_range;
+ NodeBoolMap d_range_assertions;
+ context::CDO< bool > d_has_range;
+ context::CDO< int > d_curr_range;
+ void initialize();
+ void assertNode(Node n);
+ Node getNextDecisionRequest();
+ };
+private:
+ //information for minimizing ranges
+ std::vector< Node > d_ranges;
+ //map to range model objects
+ std::map< Node, RangeModel * > d_rms;
+ //literal to range
+ std::map< Node, std::vector< Node > > d_lit_to_ranges;
+ //list of currently asserted arithmetic literals
+ NodeBoolMap d_assertions;
+private:
+ //class to store whether bounding lemmas have been added
+ class BoundInstTrie
+ {
+ public:
+ std::map< Node, BoundInstTrie > d_children;
+ bool hasInstantiated( std::vector< Node > & vals, int index = 0, bool madeNew = false ){
+ if( index>=(int)vals.size() ){
+ return !madeNew;
+ }else{
+ Node n = vals[index];
+ if( d_children.find(n)==d_children.end() ){
+ madeNew = true;
+ }
+ return d_children[n].hasInstantiated(vals,index+1,madeNew);
+ }
+ }
+ };
+ std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
+private:
+ void addLiteralFromRange( Node lit, Node r );
+public:
+ BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
+
+ void check( Theory::Effort 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]; }
+ 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);
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 0c423de19..42b49cf01 100644
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -27,7 +27,7 @@ using namespace CVC4::theory;
using namespace CVC4::theory::inst;
bool CandidateGenerator::isLegalCandidate( Node n ){
- return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute()) ) );
+ return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ) );
}
void CandidateGeneratorQueue::addCandidate( Node n ) {
@@ -149,7 +149,7 @@ void CandidateGeneratorQELitEq::reset( Node eqc ){
d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );
}
Node CandidateGeneratorQELitEq::getNextCandidate(){
- while( d_eq.isFinished() ){
+ while( !d_eq.isFinished() ){
Node n = (*d_eq);
++d_eq;
if( n.getType()==d_match_pattern[0].getType() ){
@@ -186,3 +186,29 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
}
return Node::null();
}
+
+
+CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
+ d_match_pattern( mpat ), d_qe( qe ){
+
+}
+
+void CandidateGeneratorQEAll::resetInstantiationRound() {
+
+}
+
+void CandidateGeneratorQEAll::reset( Node eqc ) {
+ d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );
+}
+
+Node CandidateGeneratorQEAll::getNextCandidate() {
+ while( !d_eq.isFinished() ){
+ Node n = (*d_eq);
+ ++d_eq;
+ if( n.getType()==d_match_pattern.getType() ){
+ //an equivalence class with the same type as the pattern, return it
+ return n;
+ }
+ }
+ return Node::null();
+}
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 81b98ce0a..402a29848 100644
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -69,8 +69,7 @@ public:
Node getNextCandidate();
};/* class CandidateGeneratorQueue */
-class CandidateGeneratorQEDisequal;
-
+//the default generator
class CandidateGeneratorQE : public CandidateGenerator
{
friend class CandidateGeneratorQEDisequal;
@@ -93,27 +92,6 @@ public:
Node getNextCandidate();
};
-
-//class CandidateGeneratorQEDisequal : public CandidateGenerator
-//{
-//private:
-// //equivalence class
-// Node d_eq_class;
-// //equivalence class info
-// EqClassInfo* d_eci;
-// //equivalence class iterator
-// EqClassInfo::BoolMap::const_iterator d_eqci_iter;
-// //instantiator pointer
-// QuantifiersEngine* d_qe;
-//public:
-// CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc );
-// ~CandidateGeneratorQEDisequal(){}
-//
-// void resetInstantiationRound();
-// void reset( Node eqc ); //should be what you want to be disequal from
-// Node getNextCandidate();
-//};
-
class CandidateGeneratorQELitEq : public CandidateGenerator
{
private:
@@ -150,6 +128,24 @@ public:
Node getNextCandidate();
};
+class CandidateGeneratorQEAll : public CandidateGenerator
+{
+private:
+ //the equality classes iterator
+ eq::EqClassesIterator d_eq;
+ //equality you are trying to match equalities for
+ Node d_match_pattern;
+ //einstantiator pointer
+ QuantifiersEngine* d_qe;
+public:
+ CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat );
+ ~CandidateGeneratorQEAll(){}
+
+ void resetInstantiationRound();
+ void reset( Node eqc );
+ Node getNextCandidate();
+};
+
}/* CVC4::theory::inst namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index bba9c0163..63cac9c15 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -25,6 +25,7 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::quantifiers::fmcheck;
FirstOrderModel::FirstOrderModel( context::Context* c, std::string name ) : TheoryModel( c, name, true ),
d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
@@ -38,15 +39,34 @@ void FirstOrderModel::assertQuantifier( Node n ){
}
}
-void FirstOrderModel::reset(){
- TheoryModel::reset();
+Node FirstOrderModel::getCurrentModelValue( Node n, bool partial ) {
+ std::vector< Node > children;
+ if( n.getNumChildren()>0 ){
+ if( n.getKind()!=APPLY_UF && n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for (unsigned i=0; i<n.getNumChildren(); i++) {
+ Node nc = getCurrentModelValue( n[i], partial );
+ if (nc.isNull()) {
+ return Node::null();
+ }else{
+ children.push_back( nc );
+ }
+ }
+ if( n.getKind()==APPLY_UF ){
+ return getCurrentUfModelValue( n, children, partial );
+ }else{
+ Node nn = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ nn = Rewriter::rewrite( nn );
+ return nn;
+ }
+ }else{
+ return getRepresentative(n);
+ }
}
-void FirstOrderModel::initialize( bool considerAxioms ){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
- d_array_model.clear();
+void FirstOrderModel::initialize( bool considerAxioms ) {
+ processInitialize();
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){
@@ -59,6 +79,23 @@ void FirstOrderModel::initialize( bool considerAxioms ){
}
void FirstOrderModel::initializeModelForTerm( Node n ){
+ processInitializeModelForTerm( n );
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ initializeModelForTerm( n[i] );
+ }
+}
+
+FirstOrderModelIG::FirstOrderModelIG(context::Context* c, std::string name) : FirstOrderModel(c,name) {
+
+}
+
+void FirstOrderModelIG::processInitialize(){
+ //rebuild models
+ d_uf_model_tree.clear();
+ d_uf_model_gen.clear();
+}
+
+void FirstOrderModelIG::processInitializeModelForTerm( Node n ){
if( n.getKind()==APPLY_UF ){
Node op = n.getOperator();
if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){
@@ -82,14 +119,11 @@ void FirstOrderModel::initializeModelForTerm( Node n ){
}
}
*/
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- initializeModelForTerm( n[i] );
- }
}
//for evaluation of quantifier bodies
-void FirstOrderModel::resetEvaluate(){
+void FirstOrderModelIG::resetEvaluate(){
d_eval_uf_use_default.clear();
d_eval_uf_model.clear();
d_eval_term_index_order.clear();
@@ -107,7 +141,7 @@ void FirstOrderModel::resetEvaluate(){
// if eVal = 0, then n' cannot be proven to be equal to phaseReq
// if eVal is not 0, then
// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
-int FirstOrderModel::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
+int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
++d_eval_formulas;
//Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
//Notice() << "Eval " << n << std::endl;
@@ -226,7 +260,7 @@ int FirstOrderModel::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
}
}
-Node FirstOrderModel::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
+Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
//Message() << "Eval term " << n << std::endl;
Node val;
depIndex = ri->getNumTerms()-1;
@@ -342,7 +376,7 @@ Node FirstOrderModel::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
return val;
}
-Node FirstOrderModel::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
+Node FirstOrderModelIG::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
depIndex = -1;
if( n.getNumChildren()==0 ){
return n;
@@ -372,14 +406,14 @@ Node FirstOrderModel::evaluateTermDefault( Node n, int& depIndex, std::vector< i
}
}
-void FirstOrderModel::clearEvalFailed( int index ){
+void FirstOrderModelIG::clearEvalFailed( int index ){
for( int i=0; i<(int)d_eval_failed_lits[index].size(); i++ ){
d_eval_failed[ d_eval_failed_lits[index][i] ] = false;
}
d_eval_failed_lits[index].clear();
}
-void FirstOrderModel::makeEvalUfModel( Node n ){
+void FirstOrderModelIG::makeEvalUfModel( Node n ){
if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){
makeEvalUfIndexOrder( n );
if( !d_eval_uf_use_default[n] ){
@@ -397,7 +431,7 @@ struct sortGetMaxVariableNum {
int computeMaxVariableNum( Node n ){
if( n.getKind()==INST_CONSTANT ){
return n.getAttribute(InstVarNumAttribute());
- }else if( n.hasAttribute(InstConstantAttribute()) ){
+ }else if( TermDb::hasInstConstAttr(n) ){
int maxVal = -1;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
int val = getMaxVariableNum( n[i] );
@@ -423,7 +457,7 @@ struct sortGetMaxVariableNum {
bool operator() (Node i,Node j) { return (getMaxVariableNum(i)<getMaxVariableNum(j));}
};
-void FirstOrderModel::makeEvalUfIndexOrder( Node n ){
+void FirstOrderModelIG::makeEvalUfIndexOrder( Node n ){
if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
#ifdef USE_INDEX_ORDERING
//sort arguments in order of least significant vs. most significant variable in default ordering
@@ -460,3 +494,187 @@ void FirstOrderModel::makeEvalUfIndexOrder( Node n ){
#endif
}
}
+
+Node FirstOrderModelIG::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ std::vector< Node > children;
+ children.push_back(n.getOperator());
+ children.insert(children.end(), args.begin(), args.end());
+ Node nv = NodeManager::currentNM()->mkNode(APPLY_UF, children);
+ //make the term model specifically for nv
+ makeEvalUfModel( nv );
+ int argDepIndex;
+ if( d_eval_uf_use_default[nv] ){
+ return d_uf_model_tree[ n.getOperator() ].getValue( this, nv, argDepIndex );
+ }else{
+ return d_eval_uf_model[ nv ].getValue( this, nv, argDepIndex );
+ }
+}
+
+
+
+
+
+
+FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(c, name), d_qe(qe){
+
+}
+
+Node FirstOrderModelFmc::getUsedRepresentative(Node n, bool strict) {
+ //Assert( fm->hasTerm(n) );
+ TypeNode tn = n.getType();
+ if( tn.isBoolean() ){
+ return areEqual(n, d_true) ? d_true : d_false;
+ }else{
+ if( !hasTerm(n) ){
+ if( strict ){
+ return Node::null();
+ }else{
+ Trace("fmc-warn") << "WARNING : no representative for " << n << std::endl;
+ }
+ }
+ Node r = getRepresentative(n);
+ if( d_model_basis_rep.find(tn)!=d_model_basis_rep.end() ){
+ if (r==d_model_basis_rep[tn]) {
+ r = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ }
+ }
+ return r;
+ }
+}
+
+Node FirstOrderModelFmc::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ Trace("fmc-uf-model") << "Get model value for " << n << " " << n.getKind() << std::endl;
+ for(unsigned i=0; i<args.size(); i++) {
+ args[i] = getUsedRepresentative(args[i]);
+ }
+ Assert( n.getKind()==APPLY_UF );
+ return d_models[n.getOperator()]->evaluate(this, args);
+}
+
+void FirstOrderModelFmc::processInitialize() {
+ if( options::fmfFmcInterval() && intervalOp.isNull() ){
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<2; i++){
+ types.push_back(NodeManager::currentNM()->integerType());
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
+ intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
+ }
+ for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
+ it->second->reset();
+ }
+ d_model_basis_rep.clear();
+}
+
+void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
+ if( n.getKind()==APPLY_UF ){
+ if( d_models.find(n.getOperator())==d_models.end()) {
+ d_models[n.getOperator()] = new Def;
+ }
+ }
+}
+
+Node FirstOrderModelFmc::getSomeDomainElement(TypeNode tn){
+ //check if there is even any domain elements at all
+ if (!d_rep_set.hasType(tn)) {
+ Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ d_rep_set.d_type_reps[tn].push_back(mbt);
+ }else if( d_rep_set.d_type_reps[tn].size()==0 ){
+ Message() << "empty reps" << std::endl;
+ exit(0);
+ }
+ return d_rep_set.d_type_reps[tn][0];
+}
+
+
+bool FirstOrderModelFmc::isStar(Node n) {
+ return n==getStar(n.getType());
+}
+
+Node FirstOrderModelFmc::getStar(TypeNode tn) {
+ if( d_type_star.find(tn)==d_type_star.end() ){
+ Node st = NodeManager::currentNM()->mkSkolem( "star_$$", tn, "skolem created for full-model checking" );
+ d_type_star[tn] = st;
+ }
+ return d_type_star[tn];
+}
+
+Node FirstOrderModelFmc::getStarElement(TypeNode tn) {
+ Node st = getStar(tn);
+ if( options::fmfFmcInterval() && tn.isInteger() ){
+ st = getInterval( st, st );
+ }
+ return st;
+}
+
+bool FirstOrderModelFmc::isModelBasisTerm(Node n) {
+ return n==getModelBasisTerm(n.getType());
+}
+
+Node FirstOrderModelFmc::getModelBasisTerm(TypeNode tn) {
+ return d_qe->getTermDatabase()->getModelBasisTerm(tn);
+}
+
+Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) {
+ Trace("fmc-model") << "Get function value for " << op << std::endl;
+ TypeNode type = op.getType();
+ std::vector< Node > vars;
+ for( size_t i=0; i<type.getNumChildren()-1; i++ ){
+ std::stringstream ss;
+ ss << argPrefix << (i+1);
+ Node b = NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] );
+ vars.push_back( b );
+ }
+ Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars);
+ Node curr;
+ for( int i=(d_models[op]->d_cond.size()-1); i>=0; i--) {
+ Node v = getRepresentative( d_models[op]->d_value[i] );
+ if( curr.isNull() ){
+ curr = v;
+ }else{
+ //make the condition
+ Node cond = d_models[op]->d_cond[i];
+ std::vector< Node > children;
+ for( unsigned j=0; j<cond.getNumChildren(); j++) {
+ if (isInterval(cond[j])){
+ if( !isStar(cond[j][0]) ){
+ children.push_back( NodeManager::currentNM()->mkNode( GEQ, vars[j], cond[j][0] ) );
+ }
+ if( !isStar(cond[j][1]) ){
+ children.push_back( NodeManager::currentNM()->mkNode( LT, vars[j], cond[j][1] ) );
+ }
+ }else if (!isStar(cond[j])){
+ Node c = getUsedRepresentative( cond[j] );
+ children.push_back( NodeManager::currentNM()->mkNode( EQUAL, vars[j], c ) );
+ }
+ }
+ Assert( !children.empty() );
+ Node cc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( AND, children );
+ curr = NodeManager::currentNM()->mkNode( ITE, cc, v, curr );
+ }
+ }
+ curr = Rewriter::rewrite( curr );
+ return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
+}
+
+bool FirstOrderModelFmc::isInterval(Node n) {
+ return n.getKind()==APPLY_UF && n.getOperator()==intervalOp;
+}
+
+Node FirstOrderModelFmc::getInterval( Node lb, Node ub ){
+ return NodeManager::currentNM()->mkNode( APPLY_UF, intervalOp, lb, ub );
+}
+
+bool FirstOrderModelFmc::isInRange( Node v, Node i ) {
+ for( unsigned b=0; b<2; b++ ){
+ if( !isStar( i[b] ) ){
+ if( ( b==0 && i[b].getConst<Rational>() > v.getConst<Rational>() ) ||
+ ( b==1 && i[b].getConst<Rational>() <= v.getConst<Rational>() ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 76f21e19c..f6e012660 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -19,7 +19,6 @@
#include "theory/model.h"
#include "theory/uf/theory_uf_model.h"
-#include "theory/arrays/theory_arrays_model.h"
namespace CVC4 {
namespace theory {
@@ -30,33 +29,22 @@ namespace quantifiers{
class TermDb;
+class FirstOrderModelIG;
+namespace fmcheck {
+ class FirstOrderModelFmc;
+}
+
class FirstOrderModel : public TheoryModel
{
private:
- //for initialize model
- void initializeModelForTerm( Node n );
/** whether an axiom is asserted */
context::CDO< bool > d_axiom_asserted;
/** list of quantifiers asserted in the current context */
context::CDList<Node> d_forall_asserts;
/** is model set */
context::CDO< bool > d_isModelSet;
-public: //for Theory UF:
- //models for each UF operator
- std::map< Node, uf::UfModelTree > d_uf_model_tree;
- //model generators
- std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;
-private:
- //map from terms to the models used to calculate their value
- std::map< Node, bool > d_eval_uf_use_default;
- std::map< Node, uf::UfModelTree > d_eval_uf_model;
- void makeEvalUfModel( Node n );
- //index ordering to use for each term
- std::map< Node, std::vector< int > > d_eval_term_index_order;
- void makeEvalUfIndexOrder( Node n );
-public: //for Theory Arrays:
- //default value for each non-store array
- std::map< Node, arrays::ArrayModel > d_array_model;
+ /** get current model value */
+ virtual Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) = 0;
public: //for Theory Quantifiers:
/** assert quantifier */
void assertQuantifier( Node n );
@@ -66,19 +54,51 @@ public: //for Theory Quantifiers:
Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; }
/** bool axiom asserted */
bool isAxiomAsserted() { return d_axiom_asserted; }
+ /** initialize model for term */
+ void initializeModelForTerm( Node n );
+ virtual void processInitializeModelForTerm( Node n ) = 0;
public:
FirstOrderModel( context::Context* c, std::string name );
virtual ~FirstOrderModel(){}
- // reset the model
- void reset();
+ virtual FirstOrderModelIG * asFirstOrderModelIG() { return NULL; }
+ virtual fmcheck::FirstOrderModelFmc * asFirstOrderModelFmc() { return NULL; }
// initialize the model
void initialize( bool considerAxioms = true );
+ virtual void processInitialize() = 0;
/** mark model set */
void markModelSet() { d_isModelSet = true; }
/** is model set */
bool isModelSet() { return d_isModelSet; }
+ /** get current model value */
+ Node getCurrentModelValue( Node n, bool partial = false );
+};/* class FirstOrderModel */
+
+
+class FirstOrderModelIG : public FirstOrderModel
+{
+public: //for Theory UF:
+ //models for each UF operator
+ std::map< Node, uf::UfModelTree > d_uf_model_tree;
+ //model generators
+ std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;
+private:
+ //map from terms to the models used to calculate their value
+ std::map< Node, bool > d_eval_uf_use_default;
+ std::map< Node, uf::UfModelTree > d_eval_uf_model;
+ void makeEvalUfModel( Node n );
+ //index ordering to use for each term
+ std::map< Node, std::vector< int > > d_eval_term_index_order;
+ void makeEvalUfIndexOrder( Node n );
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
//the following functions are for evaluating quantifier bodies
public:
+ FirstOrderModelIG(context::Context* c, std::string name);
+ FirstOrderModelIG * asFirstOrderModelIG() { return this; }
+ // initialize the model
+ void processInitialize();
+ //for initialize model
+ void processInitializeModelForTerm( Node n );
/** reset evaluation */
void resetEvaluate();
/** evaluate functions */
@@ -97,7 +117,49 @@ private:
void clearEvalFailed( int index );
std::map< Node, bool > d_eval_failed;
std::map< int, std::vector< Node > > d_eval_failed_lits;
-};/* class FirstOrderModel */
+};
+
+
+namespace fmcheck {
+
+class Def;
+
+class FirstOrderModelFmc : public FirstOrderModel
+{
+ friend class FullModelChecker;
+private:
+ /** quant engine */
+ QuantifiersEngine * d_qe;
+ /** models for UF */
+ std::map<Node, Def * > d_models;
+ std::map<TypeNode, Node > d_model_basis_rep;
+ std::map<TypeNode, Node > d_type_star;
+ Node intervalOp;
+ Node getUsedRepresentative(Node n, bool strict = false);
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
+ void processInitializeModelForTerm(Node n);
+public:
+ FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name);
+ FirstOrderModelFmc * asFirstOrderModelFmc() { return this; }
+ // initialize the model
+ void processInitialize();
+
+ Node getFunctionValue(Node op, const char* argPrefix );
+
+ bool isStar(Node n);
+ Node getStar(TypeNode tn);
+ Node getStarElement(TypeNode tn);
+ bool isModelBasisTerm(Node n);
+ Node getModelBasisTerm(TypeNode tn);
+ Node getSomeDomainElement(TypeNode tn);
+ bool isInterval(Node n);
+ Node getInterval( Node lb, Node ub );
+ bool isInRange( Node v, Node i );
+};
+
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/first_order_reasoning.cpp b/src/theory/quantifiers/first_order_reasoning.cpp
new file mode 100644
index 000000000..ebfb55f08
--- /dev/null
+++ b/src/theory/quantifiers/first_order_reasoning.cpp
@@ -0,0 +1,171 @@
+/********************* */
+/*! \file first_order_reasoning.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief first order reasoning module
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/rewriter.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+
+
+void FirstOrderPropagation::collectLits( Node n, std::vector<Node> & lits ){
+ if( n.getKind()==FORALL ){
+ collectLits( n[1], lits );
+ }else if( n.getKind()==OR ){
+ for(unsigned j=0; j<n.getNumChildren(); j++) {
+ collectLits(n[j], lits );
+ }
+ }else{
+ lits.push_back( n );
+ }
+}
+
+void FirstOrderPropagation::simplify( std::vector< Node >& assertions ){
+ for( unsigned i=0; i<assertions.size(); i++) {
+ Trace("fo-rsn") << "Assert : " << assertions[i] << std::endl;
+ }
+
+ //process all assertions
+ int num_processed;
+ int num_true = 0;
+ int num_rounds = 0;
+ do {
+ num_processed = 0;
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ if( d_assertion_true.find(assertions[i])==d_assertion_true.end() ){
+ std::vector< Node > fo_lits;
+ collectLits( assertions[i], fo_lits );
+ Node unitLit = process( assertions[i], fo_lits );
+ if( !unitLit.isNull() ){
+ Trace("fo-rsn-debug") << "...possible unit literal : " << unitLit << " from " << assertions[i] << std::endl;
+ bool pol = unitLit.getKind()!=NOT;
+ unitLit = unitLit.getKind()==NOT ? unitLit[0] : unitLit;
+ if( unitLit.getKind()==EQUAL ){
+
+ }else if( unitLit.getKind()==APPLY_UF ){
+ //make sure all are unique vars;
+ bool success = true;
+ std::vector< Node > unique_vars;
+ for( unsigned j=0; j<unitLit.getNumChildren(); j++) {
+ if( unitLit[j].getKind()==BOUND_VARIABLE ){
+ if( std::find(unique_vars.begin(), unique_vars.end(), unitLit[j])==unique_vars.end() ){
+ unique_vars.push_back( unitLit[j] );
+ }else{
+ success = false;
+ break;
+ }
+ }else{
+ success = false;
+ break;
+ }
+ }
+ if( success ){
+ d_const_def[unitLit.getOperator()] = NodeManager::currentNM()->mkConst(pol);
+ Trace("fo-rsn") << "Propagate : " << unitLit.getOperator() << " == " << pol << std::endl;
+ Trace("fo-rsn") << " from : " << assertions[i] << std::endl;
+ d_assertion_true[assertions[i]] = true;
+ num_processed++;
+ }
+ }else if( unitLit.getKind()==VARIABLE ){
+ d_const_def[unitLit] = NodeManager::currentNM()->mkConst(pol);
+ Trace("fo-rsn") << "Propagate variable : " << unitLit << " == " << pol << std::endl;
+ Trace("fo-rsn") << " from : " << assertions[i] << std::endl;
+ d_assertion_true[assertions[i]] = true;
+ num_processed++;
+ }
+ }
+ if( d_assertion_true.find(assertions[i])!=d_assertion_true.end() ){
+ num_true++;
+ }
+ }
+ }
+ num_rounds++;
+ }while( num_processed>0 );
+ Trace("fo-rsn-sum") << "Simplified " << num_true << " / " << assertions.size() << " in " << num_rounds << " rounds." << std::endl;
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ assertions[i] = theory::Rewriter::rewrite( simplify( assertions[i] ) );
+ }
+}
+
+Node FirstOrderPropagation::process(Node a, std::vector< Node > & lits) {
+ int index = -1;
+ for( unsigned i=0; i<lits.size(); i++) {
+ bool pol = lits[i].getKind()!=NOT;
+ Node n = lits[i].getKind()==NOT ? lits[i][0] : lits[i];
+ Node litDef;
+ if( n.getKind()==APPLY_UF ){
+ if( d_const_def.find(n.getOperator())!=d_const_def.end() ){
+ litDef = d_const_def[n.getOperator()];
+ }
+ }else if( n.getKind()==VARIABLE ){
+ if( d_const_def.find(n)!=d_const_def.end() ){
+ litDef = d_const_def[n];
+ }
+ }
+ if( !litDef.isNull() ){
+ Node poln = NodeManager::currentNM()->mkConst( pol );
+ if( litDef==poln ){
+ Trace("fo-rsn-debug") << "Assertion " << a << " is true because of " << lits[i] << std::endl;
+ d_assertion_true[a] = true;
+ return Node::null();
+ }
+ }
+ if( litDef.isNull() ){
+ if( index==-1 ){
+ //store undefined index
+ index = i;
+ }else{
+ //two undefined, return null
+ return Node::null();
+ }
+ }
+ }
+ if( index!=-1 ){
+ return lits[index];
+ }else{
+ return Node::null();
+ }
+}
+
+Node FirstOrderPropagation::simplify( Node n ) {
+ if( n.getKind()==VARIABLE ){
+ if( d_const_def.find(n)!=d_const_def.end() ){
+ return d_const_def[n];
+ }
+ }else if( n.getKind()==APPLY_UF ){
+ if( d_const_def.find(n.getOperator())!=d_const_def.end() ){
+ return d_const_def[n.getOperator()];
+ }
+ }
+ if( n.getNumChildren()==0 ){
+ return n;
+ }else{
+ std::vector< Node > children;
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for(unsigned i=0; i<n.getNumChildren(); i++) {
+ children.push_back( simplify(n[i]) );
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+}
+
+}
diff --git a/src/theory/quantifiers/first_order_reasoning.h b/src/theory/quantifiers/first_order_reasoning.h
new file mode 100644
index 000000000..5f217050c
--- /dev/null
+++ b/src/theory/quantifiers/first_order_reasoning.h
@@ -0,0 +1,45 @@
+/********************* */
+/*! \file first_order_reasoning.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Pre-process step for first-order reasoning
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__FIRST_ORDER_REASONING_H
+#define __CVC4__FIRST_ORDER_REASONING_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+class FirstOrderPropagation {
+private:
+ std::map< Node, Node > d_const_def;
+ std::map< Node, bool > d_assertion_true;
+ Node process(Node a, std::vector< Node > & lits);
+ void collectLits( Node n, std::vector<Node> & lits );
+ Node simplify( Node n );
+public:
+ FirstOrderPropagation(){}
+ ~FirstOrderPropagation(){}
+
+ void simplify( std::vector< Node >& assertions );
+};
+
+}
+
+#endif
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
new file mode 100644
index 000000000..bf10369e6
--- /dev/null
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -0,0 +1,1409 @@
+/********************* */
+/*! \file full_model_check.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 full model check class
+ **/
+
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/options.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
+using namespace CVC4::theory::quantifiers::fmcheck;
+
+struct ModelBasisArgSort
+{
+ std::vector< Node > d_terms;
+ bool operator() (int i,int j) {
+ return (d_terms[i].getAttribute(ModelBasisArgAttribute()) <
+ d_terms[j].getAttribute(ModelBasisArgAttribute()) );
+ }
+};
+
+
+struct ConstRationalSort
+{
+ std::vector< Node > d_terms;
+ bool operator() (int i, int j) {
+ return (d_terms[i].getConst<Rational>() < d_terms[j].getConst<Rational>() );
+ }
+};
+
+
+bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
+ if (index==(int)c.getNumChildren()) {
+ return d_data!=-1;
+ }else{
+ TypeNode tn = c[index].getType();
+ Node st = m->getStar(tn);
+ if(d_child.find(st)!=d_child.end()) {
+ if( d_child[st].hasGeneralization(m, c, index+1) ){
+ return true;
+ }
+ }
+ if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
+ if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
+ return true;
+ }
+ }
+ if( !options::fmfFmcInterval() || !c[index].getType().isInteger() ){
+ //for star: check if all children are defined and have generalizations
+ if( options::fmfFmcCoverSimplify() && c[index]==st ){
+ //check if all children exist and are complete
+ int num_child_def = d_child.size() - (d_child.find(st)!=d_child.end() ? 1 : 0);
+ if( num_child_def==m->d_rep_set.getNumRepresentatives(tn) ){
+ bool complete = true;
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( !m->isStar(it->first) ){
+ if( !it->second.hasGeneralization(m, c, index+1) ){
+ complete = false;
+ break;
+ }
+ }
+ }
+ if( complete ){
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
+
+int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
+ Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
+ if (index==(int)inst.size()) {
+ return d_data;
+ }else{
+ int minIndex = -1;
+ if( options::fmfFmcInterval() && inst[index].getType().isInteger() ){
+ for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( !m->isInterval( it->first ) ){
+ std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
+ exit( 11 );
+ }
+ //check if it is in the range
+ if( m->isInRange(inst[index], it->first ) ){
+ int gindex = it->second.getGeneralizationIndex(m, inst, index+1);
+ if( minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+ minIndex = gindex;
+ }
+ }
+ }
+ }else{
+ Node st = m->getStar(inst[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ minIndex = d_child[st].getGeneralizationIndex(m, inst, index+1);
+ }
+ Node cc = inst[index];
+ if( cc!=st && d_child.find( cc )!=d_child.end() ){
+ int gindex = d_child[ cc ].getGeneralizationIndex(m, inst, index+1);
+ if (minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+ minIndex = gindex;
+ }
+ }
+ }
+ return minIndex;
+ }
+}
+
+void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
+ if (index==(int)c.getNumChildren()) {
+ if(d_data==-1) {
+ d_data = data;
+ }
+ }
+ else {
+ d_child[ c[index] ].addEntry(m,c,v,data,index+1);
+ if( d_complete==0 ){
+ d_complete = -1;
+ }
+ }
+}
+
+void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
+ if (index==(int)c.getNumChildren()) {
+ if( d_data!=-1) {
+ if( is_gen ){
+ gen.push_back(d_data);
+ }
+ compat.push_back(d_data);
+ }
+ }else{
+ if (m->isStar(c[index])) {
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ it->second.getEntries(m, c, compat, gen, index+1, is_gen );
+ }
+ }else{
+ Node st = m->getStar(c[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ d_child[st].getEntries(m, c, compat, gen, index+1, false);
+ }
+ if( d_child.find( c[index] )!=d_child.end() ){
+ d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
+ }
+ }
+
+ }
+}
+
+void EntryTrie::collectIndices(Node c, int index, std::vector< int >& indices ) {
+ if (index==(int)c.getNumChildren()) {
+ if( d_data!=-1 ){
+ indices.push_back( d_data );
+ }
+ }else{
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ it->second.collectIndices(c, index+1, indices );
+ }
+ }
+}
+
+bool EntryTrie::isComplete(FirstOrderModelFmc * m, Node c, int index) {
+ if( d_complete==-1 ){
+ d_complete = 1;
+ if (index<(int)c.getNumChildren()) {
+ Node st = m->getStar(c[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ if (!d_child[st].isComplete(m, c, index+1)) {
+ d_complete = 0;
+ }
+ }else{
+ d_complete = 0;
+ }
+ }
+ }
+ return d_complete==1;
+}
+
+bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
+ if (d_et.hasGeneralization(m, c)) {
+ Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
+ return false;
+ }
+ int newIndex = (int)d_cond.size();
+ if (!d_has_simplified) {
+ std::vector<int> compat;
+ std::vector<int> gen;
+ d_et.getEntries(m, c, compat, gen);
+ for( unsigned i=0; i<compat.size(); i++) {
+ if( d_status[compat[i]]==status_unk ){
+ if( d_value[compat[i]]!=v ){
+ d_status[compat[i]] = status_non_redundant;
+ }
+ }
+ }
+ for( unsigned i=0; i<gen.size(); i++) {
+ if( d_status[gen[i]]==status_unk ){
+ if( d_value[gen[i]]==v ){
+ d_status[gen[i]] = status_redundant;
+ }
+ }
+ }
+ d_status.push_back( status_unk );
+ }
+ d_et.addEntry(m, c, v, newIndex);
+ d_cond.push_back(c);
+ d_value.push_back(v);
+ return true;
+}
+
+Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+ int gindex = d_et.getGeneralizationIndex(m, inst);
+ if (gindex!=-1) {
+ return d_value[gindex];
+ }else{
+ Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
+ return Node::null();
+ }
+}
+
+int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+ return d_et.getGeneralizationIndex(m, inst);
+}
+
+void Def::basic_simplify( FirstOrderModelFmc * m ) {
+ d_has_simplified = true;
+ std::vector< Node > cond;
+ cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+ d_cond.clear();
+ std::vector< Node > value;
+ value.insert( value.end(), d_value.begin(), d_value.end() );
+ d_value.clear();
+ d_et.reset();
+ for (unsigned i=0; i<d_status.size(); i++) {
+ if( d_status[i]!=status_redundant ){
+ addEntry(m, cond[i], value[i]);
+ }
+ }
+ d_status.clear();
+}
+
+void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
+ basic_simplify( m );
+
+ //check if the last entry is not all star, if so, we can make the last entry all stars
+ if( !d_cond.empty() ){
+ bool last_all_stars = true;
+ Node cc = d_cond[d_cond.size()-1];
+ for( unsigned i=0; i<cc.getNumChildren(); i++ ){
+ if( !m->isInterval(cc[i]) && !m->isStar(cc[i]) ){
+ last_all_stars = false;
+ break;
+ }
+ }
+ if( !last_all_stars ){
+ Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
+ Trace("fmc-cover-simplify") << "Before: " << std::endl;
+ debugPrint("fmc-cover-simplify",Node::null(), mc);
+ Trace("fmc-cover-simplify") << std::endl;
+ std::vector< Node > cond;
+ cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+ d_cond.clear();
+ std::vector< Node > value;
+ value.insert( value.end(), d_value.begin(), d_value.end() );
+ d_value.clear();
+ d_et.reset();
+ d_has_simplified = false;
+ //change the last to all star
+ std::vector< Node > nc;
+ nc.push_back( cc.getOperator() );
+ for( unsigned j=0; j< cc.getNumChildren(); j++){
+ nc.push_back(m->getStarElement(cc[j].getType()));
+ }
+ cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
+ //re-add the entries
+ for (unsigned i=0; i<cond.size(); i++) {
+ addEntry(m, cond[i], value[i]);
+ }
+ Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
+ basic_simplify( m );
+ Trace("fmc-cover-simplify") << "After: " << std::endl;
+ debugPrint("fmc-cover-simplify",Node::null(), mc);
+ Trace("fmc-cover-simplify") << std::endl;
+ }
+ }
+}
+
+void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
+ if (!op.isNull()) {
+ Trace(tr) << "Model for " << op << " : " << std::endl;
+ }
+ for( unsigned i=0; i<d_cond.size(); i++) {
+ //print the condition
+ if (!op.isNull()) {
+ Trace(tr) << op;
+ }
+ m->debugPrintCond(tr, d_cond[i], true);
+ Trace(tr) << " -> ";
+ m->debugPrint(tr, d_value[i]);
+ Trace(tr) << std::endl;
+ }
+}
+
+
+FullModelChecker::FullModelChecker(context::Context* c, QuantifiersEngine* qe) :
+QModelBuilder( c, qe ){
+ d_true = NodeManager::currentNM()->mkConst(true);
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+bool FullModelChecker::optBuildAtFullModel() {
+ //need to build after full model has taken effect if we are constructing interval models
+ // this is because we need to have a constant in all integer equivalence classes
+ return options::fmfFmcInterval();
+}
+
+void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
+ FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
+ if( fullModel==optBuildAtFullModel() ){
+ Trace("fmc") << "---Full Model Check reset() " << std::endl;
+ fm->initialize( d_considerAxioms );
+ d_quant_models.clear();
+ d_rep_ids.clear();
+ d_star_insts.clear();
+ //process representatives
+ 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("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(it->first);
+ Node rmbt = fm->getUsedRepresentative( mbt);
+ int mbt_index = -1;
+ Trace("fmc") << " Model basis term : " << mbt << std::endl;
+ for( size_t a=0; a<it->second.size(); a++ ){
+ Node r = fm->getUsedRepresentative( it->second[a] );
+ std::vector< Node > eqc;
+ ((EqualityQueryQuantifiersEngine*)d_qe->getEqualityQuery())->getEquivalenceClass( r, eqc );
+ Trace("fmc-model-debug") << " " << (it->second[a]==r) << (r==mbt);
+ Trace("fmc-model-debug") << " : " << it->second[a] << " : " << r << " : ";
+ //Trace("fmc-model-debug") << r2 << " : " << ir << " : ";
+ Trace("fmc-model-debug") << " {";
+ //find best selection for representative
+ for( size_t i=0; i<eqc.size(); i++ ){
+ Trace("fmc-model-debug") << eqc[i] << ", ";
+ }
+ Trace("fmc-model-debug") << "}" << std::endl;
+
+ //if this is the model basis eqc, replace with actual model basis term
+ if (r==rmbt || (mbt_index==-1 && a==(it->second.size()-1))) {
+ fm->d_model_basis_rep[it->first] = r;
+ r = mbt;
+ mbt_index = a;
+ }
+ d_rep_ids[it->first][r] = (int)a;
+ }
+ Trace("fmc-model-debug") << std::endl;
+
+ if (mbt_index==-1) {
+ std::cout << " WARNING: model basis term is not a representative!" << std::endl;
+ exit(0);
+ }else{
+ Trace("fmc") << "Star index for " << it->first << " is " << mbt_index << std::endl;
+ }
+ }
+ }
+ //also process non-rep set sorts
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node op = it->first;
+ TypeNode tno = op.getType();
+ for( unsigned i=0; i<tno.getNumChildren(); i++) {
+ initializeType( fm, tno[i] );
+ }
+ }
+ //now, make models
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node op = it->first;
+ //reset the model
+ fm->d_models[op]->reset();
+
+ Trace("fmc-model-debug") << fm->d_uf_terms[op].size() << " model values for " << op << " ... " << std::endl;
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node r = fm->getUsedRepresentative(fm->d_uf_terms[op][i]);
+ Trace("fmc-model-debug") << fm->d_uf_terms[op][i] << " -> " << r << std::endl;
+ }
+ Trace("fmc-model-debug") << std::endl;
+
+
+ std::vector< Node > add_conds;
+ std::vector< Node > add_values;
+ 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()) ){
+ add_conds.push_back( n );
+ add_values.push_back( n );
+ }
+ }
+ //possibly get default
+ if( needsDefault ){
+ Node nmb = d_qe->getTermDatabase()->getModelBasisOpTerm(op);
+ //add default value if necessary
+ if( fm->hasTerm( nmb ) ){
+ Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
+ add_conds.push_back( nmb );
+ add_values.push_back( nmb );
+ }else{
+ Node vmb = getSomeDomainElement(fm, nmb.getType());
+ Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
+ Trace("fmc-model-debug") << fm->d_rep_set.d_type_reps[nmb.getType()].size() << std::endl;
+ add_conds.push_back( nmb );
+ add_values.push_back( vmb );
+ }
+ }
+
+ std::vector< Node > conds;
+ std::vector< Node > values;
+ std::vector< Node > entry_conds;
+ //get the entries for the mdoel
+ for( size_t i=0; i<add_conds.size(); i++ ){
+ Node c = add_conds[i];
+ Node v = add_values[i];
+ std::vector< Node > children;
+ std::vector< Node > entry_children;
+ children.push_back(op);
+ entry_children.push_back(op);
+ bool hasNonStar = false;
+ for( unsigned i=0; i<c.getNumChildren(); i++) {
+ Node ri = fm->getUsedRepresentative( c[i]);
+ if( !ri.getType().isSort() && !ri.isConst() ){
+ Trace("fmc-warn") << "Warning : model has non-constant argument in model " << ri << std::endl;
+ }
+ children.push_back(ri);
+ if( !options::fmfFmcInterval() || !ri.getType().isInteger() ){
+ if (fm->isModelBasisTerm(ri) ) {
+ ri = fm->getStar( ri.getType() );
+ }else{
+ hasNonStar = true;
+ }
+ }
+ entry_children.push_back(ri);
+ }
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Node nv = fm->getUsedRepresentative( v );
+ if( !nv.getType().isSort() && !nv.isConst() ){
+ Trace("fmc-warn") << "Warning : model has non-constant value in model " << nv << std::endl;
+ }
+ Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
+ if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
+ Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+ conds.push_back(n);
+ values.push_back(nv);
+ entry_conds.push_back(en);
+ }
+ else {
+ Trace("fmc-model-debug") << "Already have entry for : " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+ }
+ }
+
+
+ //sort based on # default arguments
+ std::vector< int > indices;
+ ModelBasisArgSort mbas;
+ for (int i=0; i<(int)conds.size(); i++) {
+ d_qe->getTermDatabase()->computeModelBasisArgAttribute( conds[i] );
+ mbas.d_terms.push_back(conds[i]);
+ indices.push_back(i);
+ }
+ std::sort( indices.begin(), indices.end(), mbas );
+
+ for (int i=0; i<(int)indices.size(); i++) {
+ fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
+ }
+
+
+ if( options::fmfFmcInterval() ){
+ Trace("fmc-interval-model") << "Changing to interval model, Before : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-interval-model", op, this);
+ Trace("fmc-interval-model") << std::endl;
+ std::vector< int > indices;
+ for( int i=0; i<(int)fm->d_models[op]->d_cond.size(); i++ ){
+ indices.push_back( i );
+ }
+ std::map< int, std::map< int, Node > > changed_vals;
+ makeIntervalModel( fm, op, indices, 0, changed_vals );
+
+ std::vector< Node > conds;
+ std::vector< Node > values;
+ for( unsigned i=0; i<fm->d_models[op]->d_cond.size(); i++ ){
+ if( changed_vals.find(i)==changed_vals.end() ){
+ conds.push_back( fm->d_models[op]->d_cond[i] );
+ }else{
+ std::vector< Node > children;
+ children.push_back( op );
+ for( unsigned j=0; j<fm->d_models[op]->d_cond[i].getNumChildren(); j++ ){
+ if( changed_vals[i].find(j)==changed_vals[i].end() ){
+ children.push_back( fm->d_models[op]->d_cond[i][j] );
+ }else{
+ children.push_back( changed_vals[i][j] );
+ }
+ }
+ Node nc = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ conds.push_back( nc );
+ Trace("fmc-interval-model") << "Interval : Entry #" << i << " changed to ";
+ debugPrintCond("fmc-interval-model", nc, true );
+ Trace("fmc-interval-model") << std::endl;
+ }
+ values.push_back( fm->d_models[op]->d_value[i] );
+ }
+ fm->d_models[op]->reset();
+ for( unsigned i=0; i<conds.size(); i++ ){
+ fm->d_models[op]->addEntry(fm, conds[i], values[i] );
+ }
+ }
+
+ Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
+ Trace("fmc-model-simplify") << std::endl;
+
+ Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
+ fm->d_models[op]->simplify( this, fm );
+
+ fm->d_models[op]->debugPrint("fmc-model", op, this);
+ Trace("fmc-model") << std::endl;
+ }
+ }
+ if( fullModel ){
+ //make function values
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
+ m->d_uf_models[ it->first ] = getFunctionValue( fm, it->first, "$x" );
+ }
+ TheoryEngineModelBuilder::processBuildModel( m, fullModel );
+ //mark that the model has been set
+ fm->markModelSet();
+ //debug the model
+ debugModel( fm );
+ }
+}
+
+void FullModelChecker::initializeType( FirstOrderModelFmc * fm, TypeNode tn ){
+ if( fm->d_model_basis_rep.find( tn )==fm->d_model_basis_rep.end() ){
+ Trace("fmc") << "Initialize type " << tn << " hasType = " << fm->d_rep_set.hasType(tn) << std::endl;
+ Node mbn;
+ if (!fm->d_rep_set.hasType(tn)) {
+ mbn = fm->getSomeDomainElement(tn);
+ }else{
+ mbn = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ }
+ Node mbnr = fm->getUsedRepresentative( mbn );
+ fm->d_model_basis_rep[tn] = mbnr;
+ Trace("fmc") << "Add model basis for type " << tn << " : " << mbn << " " << mbnr << std::endl;
+ }
+}
+
+void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
+ Trace(tr) << "(";
+ for( unsigned j=0; j<n.getNumChildren(); j++) {
+ if( j>0 ) Trace(tr) << ", ";
+ debugPrint(tr, n[j], dispStar);
+ }
+ Trace(tr) << ")";
+}
+
+void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
+ FirstOrderModelFmc * fm = (FirstOrderModelFmc *)d_qe->getModel();
+ if( n.isNull() ){
+ Trace(tr) << "null";
+ }
+ else if(fm->isStar(n) && dispStar) {
+ Trace(tr) << "*";
+ }
+ else if(fm->isInterval(n)) {
+ debugPrint(tr, n[0], dispStar );
+ Trace(tr) << "...";
+ debugPrint(tr, n[1], dispStar );
+ }else{
+ TypeNode tn = n.getType();
+ if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
+ if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
+ Trace(tr) << d_rep_ids[tn][n];
+ }else{
+ Trace(tr) << n;
+ }
+ }else{
+ Trace(tr) << n;
+ }
+ }
+}
+
+
+bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+ Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
+ if( optUseModel() ){
+ FirstOrderModelFmc * fmfmc = fm->asFirstOrderModelFmc();
+ if (effort==0) {
+ //register the quantifier
+ if (d_quant_cond.find(f)==d_quant_cond.end()) {
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<f[0].getNumChildren(); i++){
+ types.push_back(f[0][i].getType());
+ d_quant_var_id[f][f[0][i]] = i;
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
+ d_quant_cond[f] = op;
+ }
+ //make sure all types are set
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ initializeType( fmfmc, f[0][i].getType() );
+ }
+
+ //model check the quantifier
+ doCheck(fmfmc, f, d_quant_models[f], f[1]);
+ Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
+ d_quant_models[f].debugPrint("fmc", Node::null(), this);
+ Trace("fmc") << std::endl;
+
+ //consider all entries going to non-true
+ for (unsigned i=0; i<d_quant_models[f].d_cond.size(); i++) {
+ if( d_quant_models[f].d_value[i]!=d_true) {
+ Trace("fmc-inst") << "Instantiate based on " << d_quant_models[f].d_cond[i] << "..." << std::endl;
+ bool hasStar = false;
+ std::vector< Node > inst;
+ for (unsigned j=0; j<d_quant_models[f].d_cond[i].getNumChildren(); j++) {
+ if (fmfmc->isStar(d_quant_models[f].d_cond[i][j])) {
+ hasStar = true;
+ inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j].getType()));
+ }else if( fmfmc->isInterval(d_quant_models[f].d_cond[i][j])){
+ hasStar = true;
+ //if interval, find a sample point
+ if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][0]) ){
+ if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][1]) ){
+ inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j][1].getType()));
+ }else{
+ Node nn = NodeManager::currentNM()->mkNode( MINUS, d_quant_models[f].d_cond[i][j][1],
+ NodeManager::currentNM()->mkConst( Rational(1) ) );
+ nn = Rewriter::rewrite( nn );
+ inst.push_back( nn );
+ }
+ }else{
+ inst.push_back(d_quant_models[f].d_cond[i][j][0]);
+ }
+ }else{
+ inst.push_back(d_quant_models[f].d_cond[i][j]);
+ }
+ }
+ bool addInst = true;
+ if( hasStar ){
+ //try obvious (specified by inst)
+ Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+ if (ev==d_true) {
+ addInst = false;
+ }
+ }else{
+ //for debugging
+ if (Trace.isOn("fmc-test-inst")) {
+ Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+ if( ev==d_true ){
+ std::cout << "WARNING: instantiation was true! " << f << " " << d_quant_models[f].d_cond[i] << std::endl;
+ exit(0);
+ }else{
+ Trace("fmc-test-inst") << "...instantiation evaluated to false." << std::endl;
+ }
+ }
+ }
+ if( addInst ){
+ InstMatch m;
+ for( unsigned j=0; j<inst.size(); j++) {
+ m.set( d_qe, f, j, inst[j] );
+ }
+ d_triedLemmas++;
+ if( d_qe->addInstantiation( f, m ) ){
+ Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
+ d_addedLemmas++;
+ }else{
+ Trace("fmc-debug-inst") << "** Instantiation was duplicate." << std::endl;
+ //this can happen if evaluation is unknown
+ //might try it next effort level
+ d_star_insts[f].push_back(i);
+ }
+ }else{
+ Trace("fmc-debug-inst") << "** Instantiation was already true." << std::endl;
+ //might try it next effort level
+ d_star_insts[f].push_back(i);
+ }
+ }
+ }
+ }else{
+ if (!d_star_insts[f].empty()) {
+ Trace("fmc-exh") << "Exhaustive instantiate " << f << std::endl;
+ Trace("fmc-exh") << "Definition was : " << std::endl;
+ d_quant_models[f].debugPrint("fmc-exh", Node::null(), this);
+ Trace("fmc-exh") << std::endl;
+ Def temp;
+ //simplify the exceptions?
+ for( int i=(d_star_insts[f].size()-1); i>=0; i--) {
+ //get witness for d_star_insts[f][i]
+ int j = d_star_insts[f][i];
+ if( temp.addEntry(fmfmc, d_quant_models[f].d_cond[j], d_quant_models[f].d_value[j] ) ){
+ if( !exhaustiveInstantiate(fmfmc, f, d_quant_models[f].d_cond[j], j ) ){
+ //something went wrong, resort to exhaustive instantiation
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index) {
+ RepSetIterator riter( d_qe, &(fm->d_rep_set) );
+ Trace("fmc-exh") << "Exhaustive instantiate based on index " << c_index << " : " << c << " ";
+ debugPrintCond("fmc-exh", c, true);
+ Trace("fmc-exh")<< std::endl;
+ Trace("fmc-exh-debug") << "Set interval domains..." << std::endl;
+ //set the bounds on the iterator based on intervals
+ for( unsigned i=0; i<c.getNumChildren(); i++ ){
+ if( c[i].getType().isInteger() ){
+ if( fm->isInterval(c[i]) ){
+ for( unsigned b=0; b<2; b++ ){
+ if( !fm->isStar(c[i][b]) ){
+ riter.d_bounds[b][i] = c[i][b];
+ }
+ }
+ }else if( !fm->isStar(c[i]) ){
+ riter.d_bounds[0][i] = c[i];
+ riter.d_bounds[1][i] = QuantArith::offset( c[i], 1 );
+ }
+ }
+ }
+ Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
+ //initialize
+ if( riter.setQuantifier( f ) ){
+ 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) {
+ TypeNode tn = c[i].getType();
+ if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
+ if( fm->isInterval(c[i]) || fm->isStar(c[i]) ){
+ //add the full range
+ }else{
+ 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]]);
+ }else{
+ return false;
+ }
+ }
+ }else{
+ return false;
+ }
+ }
+ }
+ int addedLemmas = 0;
+ //now do full iteration
+ while( !riter.isFinished() ){
+ d_triedLemmas++;
+ Trace("fmc-exh-debug") << "Inst : ";
+ std::vector< Node > inst;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ //m.set( d_quantEngine, f, riter.d_index_order[i], riter.getTerm( i ) );
+ Node r = fm->getUsedRepresentative( riter.getTerm( i ) );
+ debugPrint("fmc-exh-debug", r);
+ Trace("fmc-exh-debug") << " ";
+ inst.push_back(r);
+ }
+ int ev_index = d_quant_models[f].getGeneralizationIndex(fm, inst);
+ Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
+ Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
+ if (ev!=d_true) {
+ InstMatch m;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ m.set( d_qe, f, i, riter.getTerm( i ) );
+ }
+ Trace("fmc-exh-debug") << ", add!";
+ //add as instantiation
+ if( d_qe->addInstantiation( f, m ) ){
+ Trace("fmc-exh-debug") << " ...success.";
+ addedLemmas++;
+ }
+ }else{
+ Trace("fmc-exh-debug") << ", already true";
+ }
+ Trace("fmc-exh-debug") << std::endl;
+ int index = riter.increment();
+ Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
+ if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
+ Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
+ riter.increment2( index-1 );
+ }
+ }
+ d_addedLemmas += addedLemmas;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
+ Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
+ //first check if it is a bounding literal
+ if( n.hasAttribute(BoundIntLitAttribute()) ){
+ Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
+ }else if( n.getKind() == kind::BOUND_VARIABLE ){
+ Trace("fmc-debug") << "Add default entry..." << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), n);
+ }
+ else if( n.getKind() == kind::NOT ){
+ //just do directly
+ doCheck( fm, f, d, n[0] );
+ doNegate( d );
+ }
+ else if( n.getKind() == kind::FORALL ){
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+ }
+ else if( n.getType().isArray() ){
+ //make the definition
+ Node r = fm->getRepresentative(n);
+ Trace("fmc-debug") << "Representative for array is " << r << std::endl;
+ while( r.getKind() == kind::STORE ){
+ Node i = fm->getUsedRepresentative( r[1] );
+ Node e = fm->getUsedRepresentative( r[2] );
+ d.addEntry(fm, mkArrayCond(i), e );
+ r = fm->getRepresentative( r[0] );
+ }
+ Node defC = mkArrayCond(fm->getStar(n.getType().getArrayIndexType()));
+ bool success = false;
+ Node odefaultValue;
+ if( r.getKind() == kind::STORE_ALL ){
+ ArrayStoreAll storeAll = r.getConst<ArrayStoreAll>();
+ odefaultValue = Node::fromExpr(storeAll.getExpr());
+ Node defaultValue = fm->getUsedRepresentative( odefaultValue, true );
+ if( !defaultValue.isNull() ){
+ d.addEntry(fm, defC, defaultValue);
+ success = true;
+ }
+ }
+ if( !success ){
+ Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl;
+ Trace("fmc-warn") << " Default value was : " << odefaultValue << std::endl;
+ Trace("fmc-debug") << "Can't process base array " << r << std::endl;
+ //can't process this array
+ d.reset();
+ d.addEntry(fm, defC, Node::null());
+ }
+ }
+ else if( n.getNumChildren()==0 ){
+ Node r = n;
+ if( !n.isConst() ){
+ if( !fm->hasTerm(n) ){
+ r = getSomeDomainElement(fm, n.getType() );
+ }
+ r = fm->getUsedRepresentative( r );
+ }
+ Trace("fmc-debug") << "Add constant entry..." << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), r);
+ }
+ else{
+ std::vector< int > var_ch;
+ std::vector< Def > children;
+ for( int i=0; i<(int)n.getNumChildren(); i++) {
+ Def dc;
+ doCheck(fm, f, dc, n[i]);
+ children.push_back(dc);
+ if( n[i].getKind() == kind::BOUND_VARIABLE ){
+ var_ch.push_back(i);
+ }
+ }
+
+ if( n.getKind()==APPLY_UF ){
+ Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
+ //uninterpreted compose
+ doUninterpretedCompose( fm, f, d, n.getOperator(), children );
+ } else if( n.getKind()==SELECT ){
+ Trace("fmc-debug") << "Do select compose " << n << std::endl;
+ std::vector< Def > children2;
+ children2.push_back( children[1] );
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ doUninterpretedCompose(fm, f, d, children[0], children2, 0, cond, val );
+ } else {
+ if( !var_ch.empty() ){
+ if( n.getKind()==EQUAL ){
+ if( var_ch.size()==2 ){
+ Trace("fmc-debug") << "Do variable equality " << n << std::endl;
+ doVariableEquality( fm, f, d, n );
+ }else{
+ Trace("fmc-debug") << "Do variable relation " << n << std::endl;
+ doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
+ }
+ }else{
+ Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+ }
+ }else{
+ Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ //interpreted compose
+ doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
+ }
+ }
+ Trace("fmc-debug") << "Simplify the definition..." << std::endl;
+ d.debugPrint("fmc-debug", Node::null(), this);
+ d.simplify(this, fm);
+ Trace("fmc-debug") << "Done simplifying" << std::endl;
+ }
+ Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
+ d.debugPrint("fmc-debug", Node::null(), this);
+ Trace("fmc-debug") << std::endl;
+}
+
+void FullModelChecker::doNegate( Def & dc ) {
+ for (unsigned i=0; i<dc.d_cond.size(); i++) {
+ if (!dc.d_value[i].isNull()) {
+ dc.d_value[i] = dc.d_value[i]==d_true ? d_false : d_true;
+ }
+ }
+}
+
+void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
+ std::vector<Node> cond;
+ mkCondDefaultVec(fm, f, cond);
+ if (eq[0]==eq[1]){
+ d.addEntry(fm, mkCond(cond), d_true);
+ }else{
+ TypeNode tn = eq[0].getType();
+ if( tn.isSort() ){
+ int j = getVariableId(f, eq[0]);
+ int k = getVariableId(f, eq[1]);
+ if( !fm->d_rep_set.hasType( tn ) ){
+ getSomeDomainElement( fm, tn ); //to verify the type is initialized
+ }
+ for (unsigned i=0; i<fm->d_rep_set.d_type_reps[tn].size(); i++) {
+ Node r = fm->getUsedRepresentative( fm->d_rep_set.d_type_reps[tn][i] );
+ cond[j+1] = r;
+ cond[k+1] = r;
+ d.addEntry( fm, mkCond(cond), d_true);
+ }
+ d.addEntry( fm, mkCondDefault(fm, f), d_false);
+ }else{
+ d.addEntry( fm, mkCondDefault(fm, f), Node::null());
+ }
+ }
+}
+
+void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
+ int j = getVariableId(f, v);
+ for (unsigned i=0; i<dc.d_cond.size(); i++) {
+ Node val = dc.d_value[i];
+ if( val.isNull() ){
+ d.addEntry( fm, dc.d_cond[i], val);
+ }else{
+ if( dc.d_cond[i][j]!=val ){
+ if (fm->isStar(dc.d_cond[i][j])) {
+ std::vector<Node> cond;
+ mkCondVec(dc.d_cond[i],cond);
+ cond[j+1] = val;
+ d.addEntry(fm, mkCond(cond), d_true);
+ cond[j+1] = fm->getStar(val.getType());
+ d.addEntry(fm, mkCond(cond), d_false);
+ }else{
+ d.addEntry( fm, dc.d_cond[i], d_false);
+ }
+ }else{
+ d.addEntry( fm, dc.d_cond[i], d_true);
+ }
+ }
+ }
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
+ Trace("fmc-uf-debug") << "Definition : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
+ Trace("fmc-uf-debug") << std::endl;
+
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+ Def & df, std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val ) {
+ Trace("fmc-uf-process") << "process at " << index << std::endl;
+ for( unsigned i=1; i<cond.size(); i++) {
+ debugPrint("fmc-uf-process", cond[i], true);
+ Trace("fmc-uf-process") << " ";
+ }
+ Trace("fmc-uf-process") << std::endl;
+ if (index==(int)dc.size()) {
+ //we have an entry, now do actual compose
+ std::map< int, Node > entries;
+ doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
+ if( entries.empty() ){
+ d.addEntry(fm, mkCond(cond), Node::null());
+ }else{
+ //add them to the definition
+ for( unsigned e=0; e<df.d_cond.size(); e++ ){
+ if ( entries.find(e)!=entries.end() ){
+ Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
+ d.addEntry(fm, entries[e], df.d_value[e] );
+ Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
+ }
+ }
+ }
+ }else{
+ for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+ if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+ std::vector< Node > new_cond;
+ new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+ if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+ Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
+ val.push_back(dc[index].d_value[i]);
+ doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
+ val.pop_back();
+ }else{
+ Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
+ }
+ }
+ }
+ }
+}
+
+void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+ std::map< int, Node > & entries, int index,
+ std::vector< Node > & cond, std::vector< Node > & val,
+ EntryTrie & curr ) {
+ Trace("fmc-uf-process") << "compose " << index << std::endl;
+ for( unsigned i=1; i<cond.size(); i++) {
+ debugPrint("fmc-uf-process", cond[i], true);
+ Trace("fmc-uf-process") << " ";
+ }
+ Trace("fmc-uf-process") << std::endl;
+ if (index==(int)val.size()) {
+ Node c = mkCond(cond);
+ Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
+ entries[curr.d_data] = c;
+ }else{
+ Node v = val[index];
+ bool bind_var = false;
+ if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
+ int j = getVariableId(f, v);
+ Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
+ if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
+ v = cond[j+1];
+ }else{
+ bind_var = true;
+ }
+ }
+ if (bind_var) {
+ Trace("fmc-uf-process") << "bind variable..." << std::endl;
+ int j = getVariableId(f, v);
+ if( fm->isStar(cond[j+1]) ){
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ cond[j+1] = it->first;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ cond[j+1] = fm->getStar(v.getType());
+ }else{
+ Node orig = cond[j+1];
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ Node nw = doIntervalMeet( fm, it->first, orig );
+ if( !nw.isNull() ){
+ cond[j+1] = nw;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ }
+ cond[j+1] = orig;
+ }
+ }else{
+ if( !v.isNull() ){
+ if( options::fmfFmcInterval() && v.getType().isInteger() ){
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ if( fm->isInRange( v, it->first ) ){
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ }
+ }else{
+ if (curr.d_child.find(v)!=curr.d_child.end()) {
+ Trace("fmc-uf-process") << "follow value..." << std::endl;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[v]);
+ }
+ Node st = fm->getStarElement(v.getType());
+ if (curr.d_child.find(st)!=curr.d_child.end()) {
+ Trace("fmc-uf-process") << "follow star..." << std::endl;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[st]);
+ }
+ }
+ }
+ }
+ }
+}
+
+void FullModelChecker::doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+ std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val ) {
+ if ( index==(int)dc.size() ){
+ Node c = mkCond(cond);
+ Node v = evaluateInterpreted(n, val);
+ d.addEntry(fm, c, v);
+ }
+ else {
+ TypeNode vtn = n.getType();
+ for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+ if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+ std::vector< Node > new_cond;
+ new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+ if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+ bool process = true;
+ if (vtn.isBoolean()) {
+ //short circuit
+ if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
+ (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
+ Node c = mkCond(new_cond);
+ d.addEntry(fm, c, dc[index].d_value[i]);
+ process = false;
+ }
+ }
+ if (process) {
+ val.push_back(dc[index].d_value[i]);
+ doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
+ val.pop_back();
+ }
+ }
+ }
+ }
+ }
+}
+
+int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+ Trace("fmc-debug3") << "isCompat " << c << std::endl;
+ Assert(cond.size()==c.getNumChildren()+1);
+ for (unsigned i=1; i<cond.size(); i++) {
+ if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
+ if( iv.isNull() ){
+ return 0;
+ }
+ }else{
+ if( cond[i]!=c[i-1] && !fm->isStar(cond[i]) && !fm->isStar(c[i-1]) ) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+ Trace("fmc-debug3") << "doMeet " << c << std::endl;
+ Assert(cond.size()==c.getNumChildren()+1);
+ for (unsigned i=1; i<cond.size(); i++) {
+ if( cond[i]!=c[i-1] ) {
+ if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
+ if( !iv.isNull() ){
+ cond[i] = iv;
+ }else{
+ return false;
+ }
+ }else{
+ if( fm->isStar(cond[i]) ){
+ cond[i] = c[i-1];
+ }else if( !fm->isStar(c[i-1]) ){
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+Node FullModelChecker::doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk ) {
+ if( fm->isStar( i1 ) ){
+ return i2;
+ }else if( fm->isStar( i2 ) ){
+ return i1;
+ }else{
+ if( !fm->isInterval( i1 ) || !fm->isInterval( i2 ) ){
+ std::cout << "Not interval during meet! " << i1 << " " << i2 << std::endl;
+ exit( 0 );
+ }
+ Node b[2];
+ for( unsigned j=0; j<2; j++ ){
+ Node b1 = i1[j];
+ Node b2 = i2[j];
+ if( fm->isStar( b1 ) ){
+ b[j] = b2;
+ }else if( fm->isStar( b2 ) ){
+ b[j] = b1;
+ }else if( b1.getConst<Rational>() < b2.getConst<Rational>() ){
+ b[j] = j==0 ? b2 : b1;
+ }else{
+ b[j] = j==0 ? b1 : b2;
+ }
+ }
+ if( fm->isStar( b[0] ) || fm->isStar( b[1] ) || b[0].getConst<Rational>() < b[1].getConst<Rational>() ){
+ return mk ? fm->getInterval( b[0], b[1] ) : i1;
+ }else{
+ return Node::null();
+ }
+ }
+}
+
+Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
+ return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
+}
+
+Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ return mkCond(cond);
+}
+
+void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
+ Trace("fmc-debug") << "Make default vec, intervals = " << options::fmfFmcInterval() << std::endl;
+ //get function symbol for f
+ cond.push_back(d_quant_cond[f]);
+ for (unsigned i=0; i<f[0].getNumChildren(); i++) {
+ Node ts = fm->getStarElement( f[0][i].getType() );
+ cond.push_back(ts);
+ }
+}
+
+void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
+ cond.push_back(n.getOperator());
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ cond.push_back( n[i] );
+ }
+}
+
+Node FullModelChecker::mkArrayCond( Node a ) {
+ if( d_array_term_cond.find(a)==d_array_term_cond.end() ){
+ if( d_array_cond.find(a.getType())==d_array_cond.end() ){
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( a.getType(), NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
+ d_array_cond[a.getType()] = op;
+ }
+ std::vector< Node > cond;
+ cond.push_back(d_array_cond[a.getType()]);
+ cond.push_back(a);
+ d_array_term_cond[a] = NodeManager::currentNM()->mkNode(APPLY_UF, cond );
+ }
+ return d_array_term_cond[a];
+}
+
+Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
+ if( n.getKind()==EQUAL ){
+ if (!vals[0].isNull() && !vals[1].isNull()) {
+ return vals[0]==vals[1] ? d_true : d_false;
+ }else{
+ return Node::null();
+ }
+ }else if( n.getKind()==ITE ){
+ if( vals[0]==d_true ){
+ return vals[1];
+ }else if( vals[0]==d_false ){
+ return vals[2];
+ }else{
+ return vals[1]==vals[2] ? vals[1] : Node::null();
+ }
+ }else if( n.getKind()==AND || n.getKind()==OR ){
+ bool isNull = false;
+ for (unsigned i=0; i<vals.size(); i++) {
+ if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
+ return vals[i];
+ }else if( vals[i].isNull() ){
+ isNull = true;
+ }
+ }
+ return isNull ? Node::null() : vals[0];
+ }else{
+ std::vector<Node> children;
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for (unsigned i=0; i<vals.size(); i++) {
+ if( vals[i].isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( vals[i] );
+ }
+ }
+ Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
+ Trace("fmc-eval") << "Evaluate " << nc << " to ";
+ nc = Rewriter::rewrite(nc);
+ Trace("fmc-eval") << nc << std::endl;
+ return nc;
+ }
+}
+
+Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
+ bool addRepId = !fm->d_rep_set.hasType( tn );
+ Node de = fm->getSomeDomainElement(tn);
+ if( addRepId ){
+ d_rep_ids[tn][de] = 0;
+ }
+ return de;
+}
+
+Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
+ return fm->getFunctionValue(op, argPrefix);
+}
+
+
+bool FullModelChecker::useSimpleModels() {
+ return options::fmfFmcSimple();
+}
+
+void FullModelChecker::makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals ) {
+ if( index==(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+ makeIntervalModel2( fm, op, indices, 0, changed_vals );
+ }else{
+ TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+ if( tn.isInteger() ){
+ makeIntervalModel(fm,op,indices,index+1, changed_vals );
+ }else{
+ std::map< Node, std::vector< int > > new_indices;
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Node v = fm->d_models[op]->d_cond[indices[i]][index];
+ new_indices[v].push_back( indices[i] );
+ }
+
+ for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+ makeIntervalModel( fm, op, it->second, index+1, changed_vals );
+ }
+ }
+ }
+}
+
+void FullModelChecker::makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals ) {
+ Debug("fmc-interval-model-debug") << "Process " << index << " with indicies : ";
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Debug("fmc-interval-model-debug") << indices[i] << " ";
+ }
+ Debug("fmc-interval-model-debug") << std::endl;
+
+ if( index<(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+ TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+ if( tn.isInteger() ){
+ std::map< Node, std::vector< int > > new_indices;
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Node v = fm->d_models[op]->d_cond[indices[i]][index];
+ new_indices[v].push_back( indices[i] );
+ if( !v.isConst() ){
+ Trace("fmc-warn") << "WARNING: for interval, model has non-constant : " << v << std::endl;
+ Trace("fmc-warn") << "From condition : " << fm->d_models[op]->d_cond[indices[i]] << std::endl;
+ }
+ }
+
+ std::vector< Node > values;
+ for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+ makeIntervalModel2( fm, op, it->second, index+1, changed_vals );
+ values.push_back( it->first );
+ }
+
+ if( tn.isInteger() ){
+ //sort values by size
+ ConstRationalSort crs;
+ std::vector< int > sindices;
+ for( unsigned i=0; i<values.size(); i++ ){
+ sindices.push_back( (int)i );
+ crs.d_terms.push_back( values[i] );
+ }
+ std::sort( sindices.begin(), sindices.end(), crs );
+
+ Node ub = fm->getStar( tn );
+ for( int i=(int)(sindices.size()-1); i>=0; i-- ){
+ Node lb = fm->getStar( tn );
+ if( i>0 ){
+ lb = values[sindices[i]];
+ }
+ Node interval = fm->getInterval( lb, ub );
+ for( unsigned j=0; j<new_indices[values[sindices[i]]].size(); j++ ){
+ Debug("fmc-interval-model-debug") << "Change " << new_indices[values[sindices[i]]][j] << ", " << index << " to " << interval << std::endl;
+ changed_vals[new_indices[values[sindices[i]]][j]][index] = interval;
+ }
+ ub = lb;
+ }
+ }
+ }else{
+ makeIntervalModel2( fm, op, indices, index+1, changed_vals );
+ }
+ }
+}
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
new file mode 100644
index 000000000..6bb375c34
--- /dev/null
+++ b/src/theory/quantifiers/full_model_check.h
@@ -0,0 +1,160 @@
+/********************* */
+/*! \file full_model_check.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Full model check class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef FULL_MODEL_CHECK
+#define FULL_MODEL_CHECK
+
+#include "theory/quantifiers/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+namespace fmcheck {
+
+
+class FirstOrderModelFmc;
+class FullModelChecker;
+
+class EntryTrie
+{
+private:
+ int d_complete;
+public:
+ EntryTrie() : d_complete(-1), d_data(-1){}
+ std::map<Node,EntryTrie> d_child;
+ int d_data;
+ void reset() { d_data = -1; d_child.clear(); d_complete = -1; }
+ void addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index = 0 );
+ bool hasGeneralization( FirstOrderModelFmc * m, Node c, int index = 0 );
+ int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index = 0 );
+ void getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index = 0, bool is_gen = true );
+
+ void collectIndices(Node c, int index, std::vector< int >& indices );
+ bool isComplete(FirstOrderModelFmc * m, Node c, int index);
+};
+
+
+class Def
+{
+public:
+ EntryTrie d_et;
+ //cond is APPLY_UF whose arguments are returned by FullModelChecker::getRepresentative
+ std::vector< Node > d_cond;
+ //value is returned by FullModelChecker::getRepresentative
+ std::vector< Node > d_value;
+ void basic_simplify( FirstOrderModelFmc * m );
+private:
+ enum {
+ status_unk,
+ status_redundant,
+ status_non_redundant
+ };
+ std::vector< int > d_status;
+ bool d_has_simplified;
+public:
+ Def() : d_has_simplified(false){}
+ void reset() {
+ d_et.reset();
+ d_cond.clear();
+ d_value.clear();
+ d_status.clear();
+ d_has_simplified = false;
+ }
+ bool addEntry( FirstOrderModelFmc * m, Node c, Node v);
+ Node evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst );
+ int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst );
+ void simplify( FullModelChecker * mc, FirstOrderModelFmc * m );
+ void debugPrint(const char * tr, Node op, FullModelChecker * m);
+};
+
+
+class FullModelChecker : public QModelBuilder
+{
+protected:
+ Node d_true;
+ Node d_false;
+ std::map<TypeNode, std::map< Node, int > > d_rep_ids;
+ std::map<Node, Def > d_quant_models;
+ std::map<Node, Node > d_quant_cond;
+ std::map< TypeNode, Node > d_array_cond;
+ std::map< Node, Node > d_array_term_cond;
+ std::map<Node, std::map< Node, int > > d_quant_var_id;
+ std::map<Node, std::vector< int > > d_star_insts;
+ void initializeType( FirstOrderModelFmc * fm, TypeNode tn );
+ Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
+ bool exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index);
+protected:
+ void makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals );
+ void makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals );
+private:
+ void doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n );
+
+ void doNegate( Def & dc );
+ void doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq );
+ void doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v);
+ void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n, std::vector< Def > & dc );
+
+ void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+ Def & df, std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val );
+ void doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+ std::map< int, Node > & entries, int index,
+ std::vector< Node > & cond, std::vector< Node > & val,
+ EntryTrie & curr);
+
+ void doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+ std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val );
+ int isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+ Node doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk = true );
+ bool doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+ Node mkCond( std::vector< Node > & cond );
+ Node mkCondDefault( FirstOrderModelFmc * fm, Node f );
+ void mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond );
+ void mkCondVec( Node n, std::vector< Node > & cond );
+ Node mkArrayCond( Node a );
+ Node evaluateInterpreted( Node n, std::vector< Node > & vals );
+ Node getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn );
+public:
+ FullModelChecker( context::Context* c, QuantifiersEngine* qe );
+ ~FullModelChecker(){}
+
+ bool optBuildAtFullModel();
+
+ int getVariableId(Node f, Node n) { return d_quant_var_id[f][n]; }
+
+ void debugPrintCond(const char * tr, Node n, bool dispStar = false);
+ void debugPrint(const char * tr, Node n, bool dispStar = false);
+
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
+
+ Node getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix );
+
+ /** process build model */
+ void processBuildModel(TheoryModel* m, bool fullModel);
+ /** get current model value */
+ Node getCurrentUfModelValue( FirstOrderModelFmc* fm, Node n, std::vector< Node > & args, bool partial );
+
+ bool useSimpleModels();
+};
+
+}
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp
index e495b39c0..157861670 100644
--- a/src/theory/quantifiers/inst_gen.cpp
+++ b/src/theory/quantifiers/inst_gen.cpp
@@ -29,10 +29,10 @@ using namespace CVC4::theory::quantifiers;
InstGenProcess::InstGenProcess( Node n ) : d_node( n ){
- Assert( n.hasAttribute(InstConstantAttribute()) );
+ Assert( TermDb::hasInstConstAttr(n) );
int count = 0;
for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && TermDb::hasInstConstAttr(n[i]) ){
d_children.push_back( InstGenProcess( n[i] ) );
d_children_index.push_back( i );
d_children_map[ i ] = count;
@@ -47,7 +47,7 @@ void InstGenProcess::addMatchValue( QuantifiersEngine* qe, Node f, Node val, Ins
if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){
d_match_values.push_back( val );
d_matches.push_back( InstMatch( &m ) );
- qe->getModelEngine()->getModelBuilder()->d_instGenMatches++;
+ ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->d_instGenMatches++;
}
}
}
@@ -92,7 +92,7 @@ void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vecto
//for each term we consider, calculate a current match
for( size_t i=0; i<considerTerms.size(); i++ ){
Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
bool hadSuccess CVC4_UNUSED = false;
for( int t=(isSelected ? 0 : 1); t<2; t++ ){
if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
@@ -193,7 +193,7 @@ void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vecto
//process all values
for( size_t i=0; i<considerTerms.size(); i++ ){
Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
for( int t=(isSelected ? 0 : 1); t<2; t++ ){
//do not consider ground case if it is already congruent to another ground term
if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index f6a0dad11..d55f72a88 100644
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
@@ -134,18 +134,27 @@ Node InstMatch::getValue( Node var ) const{
}
}
+Node InstMatch::get( QuantifiersEngine* qe, Node f, int i ) {
+ return get( qe->getTermDatabase()->getInstantiationConstant( f, i ) );
+}
+
void InstMatch::set(TNode var, TNode n){
Assert( !var.isNull() );
- if( !n.isNull() &&// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations
- //var.getType() == n.getType()
- !n.getType().isSubtypeOf( var.getType() ) ){
- Trace("inst-match-warn") << var.getAttribute(InstConstantAttribute()) << std::endl;
- Trace("inst-match-warn") << var << " " << var.getType() << " " << n << " " << n.getType() << std::endl ;
- Assert(false);
+ if (Trace.isOn("inst-match-warn")) {
+ // For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations
+ if( !n.isNull() && !n.getType().isSubtypeOf( var.getType() ) ){
+ Trace("inst-match-warn") << quantifiers::TermDb::getInstConstAttr(var) << std::endl;
+ Trace("inst-match-warn") << var << " " << var.getType() << " " << n << " " << n.getType() << std::endl ;
+ }
}
+ Assert( n.isNull() || n.getType().isSubtypeOf( var.getType() ) );
d_map[var] = n;
}
+void InstMatch::set( QuantifiersEngine* qe, Node f, int i, TNode n ) {
+ set( qe->getTermDatabase()->getInstantiationConstant( f, i ), n );
+}
+
/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){
if( long(index)<long(f[0].getNumChildren()) && ( !imtio || long(index)<long(imtio->d_order.size()) ) ){
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index 127f83c60..72447fd66 100644
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
@@ -92,8 +92,11 @@ public:
void erase(Node node){ d_map.erase(node); }
/** get */
Node get( TNode var ) { return d_map[var]; }
+ Node get( QuantifiersEngine* qe, Node f, int i );
/** set */
void set(TNode var, TNode n);
+ void set( QuantifiersEngine* qe, Node f, int i, TNode n );
+ /** size */
size_t size(){ return d_map.size(); }
/* iterator */
std::map< Node, Node >::iterator begin(){ return d_map.begin(); };
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index de7f2f373..bf4bb15a6 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -32,16 +32,16 @@ namespace inst {
InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){
d_active_add = false;
- Assert( pat.hasAttribute(InstConstantAttribute()) );
+ Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
d_pattern = pat;
d_match_pattern = pat;
d_next = NULL;
}
-void InstMatchGenerator::setActiveAdd(){
- d_active_add = true;
+void InstMatchGenerator::setActiveAdd(bool val){
+ d_active_add = val;
if( d_next!=NULL ){
- d_next->setActiveAdd();
+ d_next->setActiveAdd(val);
}
}
@@ -52,28 +52,43 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
//we want to add the children of the NOT
d_match_pattern = d_pattern[0];
}
- if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){
- if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) );
- //swap sides
- Node pat = d_pattern;
- d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
- d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern;
- if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[1];
- }else{
- d_match_pattern = d_pattern[0][0];
+ if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==GEQ ){
+ //make sure the matching portion of the equality is on the LHS of d_pattern
+ // and record what d_match_pattern is
+ if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) ||
+ d_match_pattern[0].getKind()==INST_CONSTANT ){
+ if( d_match_pattern[1].getKind()!=INST_CONSTANT ){
+ Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) );
+ Node mp = d_match_pattern[1];
+ //swap sides
+ Node pat = d_pattern;
+ if(d_match_pattern.getKind()==GEQ){
+ d_pattern = NodeManager::currentNM()->mkNode( kind::GT, d_match_pattern[1], d_match_pattern[0] );
+ d_pattern = d_pattern.negate();
+ }else{
+ d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
+ }
+ d_pattern = pat.getKind()==NOT ? d_pattern.negate() : d_pattern;
+ d_match_pattern = mp;
}
- }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) );
- if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[0];
+ }else if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) ||
+ d_match_pattern[1].getKind()==INST_CONSTANT ){
+ if( d_match_pattern[0].getKind()!=INST_CONSTANT ){
+ Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) );
+ if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
+ d_match_pattern = d_match_pattern[0];
+ }else if( d_match_pattern[1].getKind()==INST_CONSTANT ){
+ d_match_pattern = d_match_pattern[0];
+ }
}
}
}
+ Trace("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
+
+ //now, collect children of d_match_pattern
int childMatchPolicy = MATCH_GEN_DEFAULT;
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
if( d_match_pattern[i].getKind()!=INST_CONSTANT && !Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy );
d_children.push_back( cimg );
@@ -83,10 +98,11 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
}
}
- Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
-
//create candidate generator
- if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern );
+ }
+ else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
@@ -96,50 +112,40 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
//candidates will be all disequalities
d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
}
- }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
+ }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF ||
+ d_pattern.getKind()==GEQ || d_pattern.getKind()==GT || d_pattern.getKind()==NOT ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
if( d_pattern.getKind()==NOT ){
- Unimplemented("Disequal generator unimplemented");
+ if (d_pattern[0][1].getKind()!=INST_CONSTANT) {
+ Unimplemented("Disequal generator unimplemented");
+ }else{
+ d_eq_class = d_pattern[0][1];
+ }
}else{
- Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
- //we are matching only in a particular equivalence class
- d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
//store the equivalence class that we will call d_cg->reset( ... ) on
d_eq_class = d_pattern[1];
}
+ Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
+ //we are matching only in a particular equivalence class
+ d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
}else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
- //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){
- //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl;
- //}
//we will be scanning lists trying to find d_match_pattern.getOperator()
d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
}else{
d_cg = new CandidateGeneratorQueue;
- if( !Trigger::isArithmeticTrigger( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
- Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- //we will treat this as match gen internal arithmetic
- d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC;
- }
+ Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
+ d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
}
}
/** get match (not modulo equality) */
bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
- << m << ")" << ", " << d_children.size() << std::endl;
+ Trace("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
+ << m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
Assert( !d_match_pattern.isNull() );
if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){
return true;
- }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){
- return getMatchArithmetic( t, m, qe );
}else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
return false;
}else{
@@ -149,12 +155,12 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
InstMatch prev( &m );
//if t is null
Assert( !t.isNull() );
- Assert( !t.hasAttribute(InstConstantAttribute()) );
+ Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
Assert( t.getKind()==d_match_pattern.getKind() );
Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() );
//first, check if ground arguments are not equal, or a match is in conflict
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
Node vv = d_match_pattern[i];
Node tt = t[i];
@@ -164,24 +170,54 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
if( !m.setMatch( q, vv, tt ) ){
//match is in conflict
- Debug("matching-debug") << "Match in conflict " << tt << " and "
+ Trace("matching-debug") << "Match in conflict " << tt << " and "
<< vv << " because "
<< m.get(vv)
<< std::endl;
- Debug("matching-fail") << "Match fail: " << m.get(vv) << " and " << tt << std::endl;
+ Trace("matching-fail") << "Match fail: " << m.get(vv) << " and " << tt << std::endl;
success = false;
break;
}
}
}else{
if( !q->areEqual( d_match_pattern[i], t[i] ) ){
- Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
+ Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
//ground arguments are not equal
success = false;
break;
}
}
}
+ //for relational matching
+ if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
+ //also must fit match to equivalence class
+ bool pol = d_pattern.getKind()!=NOT;
+ Node pat = d_pattern.getKind()==NOT ? d_pattern[0] : d_pattern;
+ Node t_match;
+ if( pol ){
+ if (pat.getKind()==GT) {
+ Node r = NodeManager::currentNM()->mkConst( Rational(-1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else{
+ t_match = t;
+ }
+ }else{
+ if(pat.getKind()==EQUAL) {
+ Node r = NodeManager::currentNM()->mkConst( Rational(1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else if( pat.getKind()==IFF ){
+ t_match = NodeManager::currentNM()->mkConst( !q->areEqual( NodeManager::currentNM()->mkConst(true), t ) );
+ }else if( pat.getKind()==GEQ ){
+ Node r = NodeManager::currentNM()->mkConst( Rational(1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else if( pat.getKind()==GT ){
+ t_match = t;
+ }
+ }
+ if( !t_match.isNull() && !m.setMatch( q, d_eq_class, t_match ) ){
+ success = false;
+ }
+ }
if( success ){
//now, fit children into match
//we will be requesting candidates for matching terms for each child
@@ -208,95 +244,45 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
-bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl;
- if( !d_arith_coeffs.empty() ){
- NodeBuilder<> tb(kind::PLUS);
- Node ic = Node::null();
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << it->first << " -> " << it->second << std::endl;
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- //see if we can choose this to set
- if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){
- ic = it->first;
- }
- }else{
- Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl;
- Node tm = m.get( it->first );
- if( !it->second.isNull() ){
- tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm );
- }
- tb << tm;
- }
- }else{
- tb << it->second;
- }
- }
- if( !ic.isNull() ){
- Node tm;
- if( tb.getNumChildren()==0 ){
- tm = t;
- }else{
- tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- tm = NodeManager::currentNM()->mkNode( MINUS, t, tm );
- }
- if( !d_arith_coeffs[ ic ].isNull() ){
- Assert( !ic.getType().isInteger() );
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
- tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
- }
- m.set( ic, Rewriter::rewrite( tm ));
- //set the rest to zeros
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) );
- }
- }
- }
- Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl;
- return true;
- }else{
- return false;
- }
- }else{
- return false;
- }
-}
-
-
/** reset instantiation round */
void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
- if( d_match_pattern.isNull() ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->resetInstantiationRound( qe );
- }
- }else{
+ if( !d_match_pattern.isNull() ){
+ Trace("matching-debug2") << this << " reset instantiation round." << std::endl;
+ d_needsReset = true;
if( d_cg ){
d_cg->resetInstantiationRound();
}
}
+ if( d_next ){
+ d_next->resetInstantiationRound( qe );
+ }
}
void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+ Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
if( !eqc.isNull() ){
d_eq_class = eqc;
}
//we have a specific equivalence class in mind
//we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
//just look in equivalence class of the RHS
- d_cg->reset( d_eq_class );
+ d_cg->reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class );
+ d_needsReset = false;
}
bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){
+ if( d_needsReset ){
+ Trace("matching") << "Reset not done yet, must do the reset..." << std::endl;
+ reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class, qe );
+ }
m.d_matched = Node::null();
- //Debug("matching") << this << " " << d_pattern << " get next match 2 " << m << " in eq class " << d_eq_class << std::endl;
+ Trace("matching") << this << " " << d_match_pattern << " get next match " << m << " in eq class " << d_eq_class << std::endl;
bool success = false;
Node t;
do{
//get the next candidate term t
t = d_cg->getNextCandidate();
+ Trace("matching-debug2") << "Matching candidate : " << t << std::endl;
//if t not null, try to fit it into match m
if( !t.isNull() && t.getType()==d_match_pattern.getType() ){
success = getMatch( f, t, m, qe );
@@ -304,9 +290,9 @@ bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine*
}while( !success && !t.isNull() );
m.d_matched = t;
if( !success ){
- //Debug("matching") << this << " failed, reset " << d_eq_class << std::endl;
+ Trace("matching") << this << " failed, reset " << d_eq_class << std::endl;
//we failed, must reset
- reset( d_eq_class, qe );
+ reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class, qe );
}
return success;
}
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index 4c954fa81..5d2128922 100644
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -44,13 +44,14 @@ public:
/** add ground term t, called when t is added to term db */
virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0;
/** set active add */
- virtual void setActiveAdd() {}
+ virtual void setActiveAdd( bool val ) {}
};/* class IMGenerator */
class CandidateGenerator;
class InstMatchGenerator : public IMGenerator {
private:
+ bool d_needsReset;
/** candidate generator */
CandidateGenerator* d_cg;
/** policy to use for matching */
@@ -72,12 +73,8 @@ public:
MATCH_GEN_DEFAULT = 0,
MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers
//others (internally used)
- MATCH_GEN_INTERNAL_ARITHMETIC,
MATCH_GEN_INTERNAL_ERROR,
};
-private:
- /** for arithmetic */
- bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe );
public:
/** get the match against ground term or formula t.
d_match_pattern and t should have the same shape.
@@ -108,7 +105,7 @@ public:
int addTerm( Node f, Node t, QuantifiersEngine* qe );
bool d_active_add;
- void setActiveAdd();
+ void setActiveAdd( bool val );
static InstMatchGenerator* mkInstMatchGenerator( Node pat, QuantifiersEngine* qe );
static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe );
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index dbdf95613..4fe4072a3 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -41,6 +41,19 @@ bool InstStrategySimplex::calculateShouldProcess( Node f ){
return false;
}
+void getInstantiationConstants( Node n, std::vector< Node >& ics ){
+ if( n.getKind()==INST_CONSTANT ){
+ if( std::find( ics.begin(), ics.end(), n )==ics.end() ){
+ ics.push_back( n );
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getInstantiationConstants( n[i], ics );
+ }
+ }
+}
+
+
void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){
Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl;
d_instRows.clear();
@@ -54,37 +67,69 @@ void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort
ArithVar x = *vi;
if( d_th->d_internal->d_partialModel.hasEitherBound( x ) ){
Node n = avnm.asNode(x);
- Node f;
- NodeBuilder<> t(kind::PLUS);
- if( n.getKind()==PLUS ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- addTermToRow( x, n[i], f, t );
+
+ //collect instantiation constants
+ std::vector< Node > ics;
+ getInstantiationConstants( n, ics );
+ for( unsigned i=0; i<ics.size(); i++ ){
+
+ NodeBuilder<> t(kind::PLUS);
+ if( n.getKind()==PLUS ){
+ for( int j=0; j<(int)n.getNumChildren(); j++ ){
+ addTermToRow( ics[i], x, n[j], t );
+ }
+ }else{
+ addTermToRow( ics[i], x, n, t );
}
- }else{
- addTermToRow( x, n, f, t );
- }
- if( f!=Node::null() ){
- d_instRows[f].push_back( x );
+ d_instRows[ics[i]].push_back( x );
//this theory has constraints from f
+ Node f = TermDb::getInstConstAttr(ics[i]);
Debug("quant-arith") << "Has constraints from " << f << std::endl;
//set that we should process it
d_quantActive[ f ] = true;
//set tableaux term
if( t.getNumChildren()==0 ){
- d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) );
+ d_tableaux_term[ics[i]][x] = NodeManager::currentNM()->mkConst( Rational(0) );
}else if( t.getNumChildren()==1 ){
- d_tableaux_term[x] = t.getChild( 0 );
+ d_tableaux_term[ics[i]][x] = t.getChild( 0 );
}else{
- d_tableaux_term[x] = t;
+ d_tableaux_term[ics[i]][x] = t;
}
}
}
}
//print debug
+ Debug("quant-arith-debug") << std::endl;
debugPrint( "quant-arith-debug" );
d_counter++;
}
+void InstStrategySimplex::addTermToRow( Node i, ArithVar x, Node n, NodeBuilder<>& t ){
+ if( n.getKind()==MULT ){
+ if( TermDb::hasInstConstAttr(n[1]) ){
+ if( n[1]==i ){
+ d_ceTableaux[i][x][ n[1] ] = n[0];
+ }else{
+ d_tableaux_ce_term[i][x][ n[1] ] = n[0];
+ }
+ }else{
+ d_tableaux[i][x][ n[1] ] = n[0];
+ t << n;
+ }
+ }else{
+ if( TermDb::hasInstConstAttr(n) ){
+ if( n==i ){
+ d_ceTableaux[i][x][ n ] = Node::null();
+ }else{
+ d_tableaux_ce_term[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ }
+ }else{
+ d_tableaux[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ t << n;
+ }
+ }
+}
+
int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
if( e<2 ){
return STATUS_UNFINISHED;
@@ -92,48 +137,51 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
//Notice() << f << std::endl;
//Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl;
//Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl;
- Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl;
- for( int j=0; j<(int)d_instRows[f].size(); j++ ){
- ArithVar x = d_instRows[f][j];
- if( !d_ceTableaux[x].empty() ){
- Debug("quant-arith-simplex") << "Check row " << x << std::endl;
- //instantiation row will be A*e + B*t = beta,
- // where e is a vector of terms , and t is vector of ground terms.
- // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
- // We will construct the term ( beta - B*t)/coeff to use for e_i.
- InstMatch m;
- //By default, choose the first instantiation constant to be e_i.
- Node var = d_ceTableaux[x].begin()->first;
- if( var.getType().isInteger() ){
- std::map< Node, Node >::iterator it = d_ceTableaux[x].begin();
- //try to find coefficent that is +/- 1
- while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){
- ++it;
- if( it==d_ceTableaux[x].end() ){
- var = Node::null();
- }else{
- var = it->first;
+ for( int i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
+ Debug("quant-arith-simplex") << "InstStrategySimplex check " << ic << ", rows = " << d_instRows[ic].size() << std::endl;
+ for( int j=0; j<(int)d_instRows[ic].size(); j++ ){
+ ArithVar x = d_instRows[ic][j];
+ if( !d_ceTableaux[ic][x].empty() ){
+ Debug("quant-arith-simplex") << "Check row " << ic << " " << x << std::endl;
+ //instantiation row will be A*e + B*t = beta,
+ // where e is a vector of terms , and t is vector of ground terms.
+ // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
+ // We will construct the term ( beta - B*t)/coeff to use for e_i.
+ InstMatch m;
+ //By default, choose the first instantiation constant to be e_i.
+ Node var = d_ceTableaux[ic][x].begin()->first;
+ if( var.getType().isInteger() ){
+ std::map< Node, Node >::iterator it = d_ceTableaux[ic][x].begin();
+ //try to find coefficent that is +/- 1
+ while( !var.isNull() && !d_ceTableaux[ic][x][var].isNull() && d_ceTableaux[ic][x][var]!=d_negOne ){
+ ++it;
+ if( it==d_ceTableaux[ic][x].end() ){
+ var = Node::null();
+ }else{
+ var = it->first;
+ }
}
+ //otherwise, try one that divides all ground term coefficients? DO_THIS
}
- //otherwise, try one that divides all ground term coefficients? DO_THIS
- }
- if( !var.isNull() ){
- Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
- doInstantiation( f, d_tableaux_term[x], x, m, var );
- }else{
- Debug("quant-arith-simplex") << "Could not find var." << std::endl;
+ if( !var.isNull() ){
+ Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
+ doInstantiation( f, ic, d_tableaux_term[ic][x], x, m, var );
+ }else{
+ Debug("quant-arith-simplex") << "Could not find var." << std::endl;
+ }
+ ////choose a new variable based on alternation strategy
+ //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
+ //Node var;
+ //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
+ // if( index==0 ){
+ // var = it->first;
+ // break;
+ // }
+ // index--;
+ //}
+ //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
}
- ////choose a new variable based on alternation strategy
- //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
- //Node var;
- //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
- // if( index==0 ){
- // var = it->first;
- // break;
- // }
- // index--;
- //}
- //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
}
}
}
@@ -141,34 +189,6 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
}
-void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){
- if( n.getKind()==MULT ){
- if( n[1].hasAttribute(InstConstantAttribute()) ){
- f = n[1].getAttribute(InstConstantAttribute());
- if( n[1].getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n[1] ] = n[0];
- }else{
- d_tableaux_ce_term[x][ n[1] ] = n[0];
- }
- }else{
- d_tableaux[x][ n[1] ] = n[0];
- t << n;
- }
- }else{
- if( n.hasAttribute(InstConstantAttribute()) ){
- f = n.getAttribute(InstConstantAttribute());
- if( n.getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n ] = Node::null();
- }else{
- d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- }
- }else{
- d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- t << n;
- }
- }
-}
-
void InstStrategySimplex::debugPrint( const char* c ){
ArithVariables& avnm = d_th->d_internal->d_partialModel;
ArithVariables::var_iterator vi, vend;
@@ -218,14 +238,17 @@ void InstStrategySimplex::debugPrint( const char* c ){
Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
}
Debug(c) << std::endl;
- Debug(c) << " Instantiation rows: ";
- for( int i=0; i<(int)d_instRows[f].size(); i++ ){
- if( i>0 ){
- Debug(c) << ", ";
+ for( int j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
+ Debug(c) << " Instantiation rows for " << ic << " : ";
+ for( int i=0; i<(int)d_instRows[ic].size(); i++ ){
+ if( i>0 ){
+ Debug(c) << ", ";
+ }
+ Debug(c) << d_instRows[ic][i];
}
- Debug(c) << d_instRows[f][i];
+ Debug(c) << std::endl;
}
- Debug(c) << std::endl;
}
}
@@ -234,15 +257,15 @@ void InstStrategySimplex::debugPrint( const char* c ){
// t[e] is a vector of terms containing instantiation constants from f,
// and term is a ground term (c1*t1 + ... + cn*tn).
// We construct the term ( beta - term )/coeff to use as an instantiation for var.
-bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){
+bool InstStrategySimplex::doInstantiation( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var ){
//first try +delta
- if( doInstantiation2( f, term, x, m, var ) ){
+ if( doInstantiation2( f, ic, term, x, m, var ) ){
++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith);
return true;
}else{
#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA
//otherwise try -delta
- if( doInstantiation2( f, term, x, m, var, true ) ){
+ if( doInstantiation2( f, ic, term, x, m, var, true ) ){
++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus);
return true;
}else{
@@ -254,16 +277,16 @@ bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMa
}
}
-bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
+bool InstStrategySimplex::doInstantiation2( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
// make term ( beta - term )/coeff
Node beta = getTableauxValue( x, minus_delta );
Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term );
- if( !d_ceTableaux[x][var].isNull() ){
+ if( !d_ceTableaux[ic][x][var].isNull() ){
if( var.getType().isInteger() ){
- Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
- instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal );
+ Assert( d_ceTableaux[ic][x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
+ instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[ic][x][var], instVal );
}else{
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst<Rational>() );
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[ic][x][var].getConst<Rational>() );
instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal );
}
}
@@ -327,81 +350,9 @@ int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){
Node InstStrategyDatatypesValue::getValueFor( Node n ){
//simply get the ground value for n in the current model, if it exists,
// or return an arbitrary ground term otherwise
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( !TermDb::hasInstConstAttr(n) ){
return n;
}else{
return n;
}
- /* FIXME
-
- Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
- if( !n.hasAttribute(InstConstantAttribute()) ){
- return n;
- }else{
- Assert( n.getType().isDatatype() );
- //check if in equivalence class with ground term
- Node rep = getRepresentative( n );
- Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl;
- if( !rep.hasAttribute(InstConstantAttribute()) ){
- return rep;
- }else{
- if( !n.getType().isDatatype() ){
- return n.getType().mkGroundTerm();
- }else{
- if( n.getKind()==APPLY_CONSTRUCTOR ){
- std::vector< Node > children;
- children.push_back( n.getOperator() );
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- children.push_back( getValueFor( n[i] ) );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels;
- //otherwise, use which constructor the inst constant is current chosen to be
- if( labels->find( n )!=labels->end() ){
- TheoryDatatypes::EqList* lbl = (*labels->find( n )).second;
- int tIndex = -1;
- if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){
- Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl;
- tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr());
- }else{
- Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl;
- //must find a possible choice
- vector< bool > possibleCons;
- possibleCons.resize( dt.getNumConstructors(), true );
- for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) {
- Node leqn = (*j);
- possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false;
- }
- for( unsigned int j=0; j<possibleCons.size(); j++ ) {
- if( possibleCons[j] ){
- tIndex = j;
- break;
- }
- }
- }
- Assert( tIndex!=-1 );
- Node cons = Node::fromExpr( dt[ tIndex ].getConstructor() );
- Debug("quant-datatypes-debug") << n << " cons is " << cons << std::endl;
- std::vector< Node > children;
- children.push_back( cons );
- for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) {
- Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n );
- if( n.hasAttribute(InstConstantAttribute()) ){
- InstConstantAttribute ica;
- sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) );
- }
- Node snn = getValueFor( sn );
- children.push_back( snn );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- return n.getType().mkGroundTerm();
- }
- }
- }
- }
- }
- */
}
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
index a45318489..821beeae0 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.h
+++ b/src/theory/quantifiers/inst_strategy_cbqi.h
@@ -49,19 +49,19 @@ private:
/** for each quantifier, simplex rows */
std::map< Node, std::vector< arith::ArithVar > > d_instRows;
/** tableaux */
- std::map< arith::ArithVar, Node > d_tableaux_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux;
+ std::map< Node, std::map< arith::ArithVar, Node > > d_tableaux_term;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux_ce_term;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux;
/** ce tableaux */
- std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_ceTableaux;
/** get value */
Node getTableauxValue( Node n, bool minus_delta = false );
Node getTableauxValue( arith::ArithVar v, bool minus_delta = false );
/** do instantiation */
- bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var );
- bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
+ bool doInstantiation( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var );
+ bool doInstantiation2( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
/** add term to row */
- void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t );
+ void addTermToRow( Node ic, arith::ArithVar x, Node n, NodeBuilder<>& t );
/** print debug */
void debugPrint( const char* c );
private:
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 0e1266e0d..ef81d55a1 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -144,7 +144,11 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
}
if( gen ){
generateTriggers( f, effort, e, status );
+ if( d_auto_gen_trigger[f].empty() && f.getNumChildren()==2 ){
+ Trace("no-trigger") << "Could not find trigger for " << f << std::endl;
+ }
}
+
//if( e==4 ){
// d_processed_trigger.clear();
// d_quantEngine->getEqualityQuery()->setLiberal( true );
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 77df69456..628f8b14a 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -92,7 +92,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
NodeBuilder<> nb(kind::OR);
nb << f << ceLit;
Node lem = nb;
- Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl;
+ Trace("cbqi") << "Counterexample lemma : " << lem << std::endl;
d_quantEngine->getOutputChannel().lemma( lem );
addedLemma = true;
}
@@ -197,7 +197,10 @@ void InstantiationEngine::check( Theory::Effort e ){
<< d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node n = d_quantEngine->getModel()->getAssertedQuantifier( i );
- if( options::cbqi() && hasAddedCbqiLemma( n ) ){
+ //it is not active if we have found the skolemized negation is unsat
+ if( n.hasAttribute(QRewriteRuleAttribute()) ){
+ d_quant_active[n] = false;
+ }else if( options::cbqi() && hasAddedCbqiLemma( n ) ){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n );
bool active, value;
bool ceValue = false;
@@ -210,7 +213,9 @@ void InstantiationEngine::check( Theory::Effort e ){
d_quant_active[n] = active;
if( active ){
Debug("quantifiers") << " Active : " << n;
- quantActive = true;
+ if( !TermDb::hasInstConstAttr(n) ){
+ quantActive = true;
+ }
}else{
Debug("quantifiers") << " NOT active : " << n;
if( d_quantEngine->getValuation().isDecision( cel ) ){
@@ -226,14 +231,18 @@ void InstantiationEngine::check( Theory::Effort e ){
Debug("quantifiers") << ", ce is asserted";
}
Debug("quantifiers") << std::endl;
+ //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
}else{
d_quant_active[n] = true;
- quantActive = true;
+ if( !TermDb::hasInstConstAttr(n) ){
+ quantActive = true;
+ }
Debug("quantifiers") << " Active : " << n << ", no ce assigned." << std::endl;
}
Debug("quantifiers-relevance") << "Quantifier : " << n << std::endl;
Debug("quantifiers-relevance") << " Relevance : " << d_quantEngine->getQuantifierRelevance()->getRelevance( n ) << std::endl;
Debug("quantifiers") << " Relevance : " << d_quantEngine->getQuantifierRelevance()->getRelevance( n ) << std::endl;
+ Trace("inst-engine-debug") << "Process : " << n << " " << d_quant_active[n] << std::endl;
}
if( quantActive ){
bool addedLemmas = doInstantiationRound( e );
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 0b74cfc5e..5edf2de96 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -18,7 +18,6 @@
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_model.h"
#include "theory/uf/theory_uf_strong_solver.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/model_builder.h"
@@ -33,6 +32,65 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+
+QModelBuilder::QModelBuilder( context::Context* c, QuantifiersEngine* qe ) :
+TheoryEngineModelBuilder( qe->getTheoryEngine() ), d_curr_model( c, NULL ), d_qe( qe ){
+ d_considerAxioms = true;
+}
+
+bool QModelBuilder::isQuantifierActive( Node f ) {
+ return !f.hasAttribute(QRewriteRuleAttribute());
+}
+
+
+bool QModelBuilder::optUseModel() {
+ return options::fmfModelBasedInst();
+}
+
+void QModelBuilder::debugModel( FirstOrderModel* fm ){
+ //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
+ if( Trace.isOn("quant-model-warn") ){
+ Trace("quant-model-warn") << "Testing quantifier instantiations..." << std::endl;
+ int tests = 0;
+ int bad = 0;
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ std::vector< Node > vars;
+ for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
+ vars.push_back( f[0][j] );
+ }
+ RepSetIterator riter( d_qe, &(fm->d_rep_set) );
+ if( riter.setQuantifier( f ) ){
+ while( !riter.isFinished() ){
+ tests++;
+ std::vector< Node > terms;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ terms.push_back( riter.getTerm( i ) );
+ }
+ Node n = d_qe->getInstantiation( f, vars, terms );
+ Node val = fm->getValue( n );
+ if( val!=fm->d_true ){
+ Trace("quant-model-warn") << "******* Instantiation " << n << " for " << std::endl;
+ Trace("quant-model-warn") << " " << f << std::endl;
+ Trace("quant-model-warn") << " Evaluates to " << val << std::endl;
+ bad++;
+ }
+ riter.increment();
+ }
+ Trace("quant-model-warn") << "Tested " << tests << " instantiations";
+ if( bad>0 ){
+ Trace("quant-model-warn") << ", " << bad << " failed" << std::endl;
+ }
+ Trace("quant-model-warn") << "." << std::endl;
+ }else{
+ Trace("quant-model-warn") << "Warning: Could not test quantifier " << f << std::endl;
+ }
+ }
+ }
+}
+
+
+
bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
if( argIndex<(int)n.getNumChildren() ){
Node r;
@@ -53,49 +111,25 @@ bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
}
}
-ModelEngineBuilder::ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe ) :
-TheoryEngineModelBuilder( qe->getTheoryEngine() ),
-d_qe( qe ), d_curr_model( c, NULL ){
- d_considerAxioms = true;
+
+QModelBuilderIG::QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ) :
+QModelBuilder( c, qe ) {
+
}
-void ModelEngineBuilder::debugModel( FirstOrderModel* fm ){
- //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
- if( Trace.isOn("quant-model-warn") ){
- for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- std::vector< Node > vars;
- for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
- vars.push_back( f[0][j] );
- }
- RepSetIterator riter( &(fm->d_rep_set) );
- riter.setQuantifier( f );
- while( !riter.isFinished() ){
- std::vector< Node > terms;
- for( int i=0; i<riter.getNumTerms(); i++ ){
- terms.push_back( riter.getTerm( i ) );
- }
- Node n = d_qe->getInstantiation( f, vars, terms );
- Node val = fm->getValue( n );
- if( val!=fm->d_true ){
- Trace("quant-model-warn") << "******* Instantiation " << n << " for " << std::endl;
- Trace("quant-model-warn") << " " << f << std::endl;
- Trace("quant-model-warn") << " Evaluates to " << val << std::endl;
- }
- riter.increment();
- }
- }
- }
+Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) {
+ return n;
}
-void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
- FirstOrderModel* fm = (FirstOrderModel*)m;
+void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
+ FirstOrderModel* f = (FirstOrderModel*)m;
+ FirstOrderModelIG* fm = f->asFirstOrderModelIG();
if( fullModel ){
Assert( d_curr_model==fm );
//update models
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
it->second.update( fm );
- Trace("model-func") << "ModelEngineBuilder: Make function value from tree " << it->first << std::endl;
+ Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl;
//construct function values
fm->d_uf_models[ it->first ] = it->second.getFunctionValue( "$x" );
}
@@ -106,7 +140,6 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
debugModel( fm );
}else{
d_curr_model = fm;
- d_addedLemmas = 0;
d_didInstGen = false;
//reset the internal information
reset( fm );
@@ -186,12 +219,13 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
}
}
//construct the model if necessary
- if( d_addedLemmas==0 || optExhInstNonInstGenQuant() ){
+ if( d_addedLemmas==0 ){
//if no immediate exceptions, build the model
// this model will be an approximation that will need to be tested via exhaustive instantiation
Trace("model-engine-debug") << "Building model..." << std::endl;
//build model for UF
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl;
constructModelUf( fm, it->first );
}
/*
@@ -211,7 +245,7 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
}
}
-int ModelEngineBuilder::initializeQuantifier( Node f, Node fp ){
+int QModelBuilderIG::initializeQuantifier( Node f, Node fp ){
if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){
//create the basis match if necessary
if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){
@@ -254,17 +288,18 @@ int ModelEngineBuilder::initializeQuantifier( Node f, Node fp ){
return 0;
}
-void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
+void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
d_uf_model_constructed.clear();
//determine if any functions are constant
- for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){
Node op = it->first;
TermArgBasisTrie tabt;
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ 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()) ){
- Node v = fm->getRepresentative( n );
+ Node v = fmig->getRepresentative( n );
if( i==0 ){
d_uf_prefs[op].d_const_val = v;
}else if( v!=d_uf_prefs[op].d_const_val ){
@@ -273,10 +308,10 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
//for calculating terms that we don't need to consider
- if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
if( !n.getAttribute(BasisNoMatchAttribute()) ){
//need to consider if it is not congruent modulo model basis
- if( !tabt.addTerm( fm, n ) ){
+ if( !tabt.addTerm( fmig, n ) ){
BasisNoMatchAttribute bnma;
n.setAttribute(bnma,true);
}
@@ -284,10 +319,10 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
if( !d_uf_prefs[op].d_const_val.isNull() ){
- fm->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
- fm->d_uf_model_gen[op].makeModel( fm, it->second );
+ fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
+ fmig->d_uf_model_gen[op].makeModel( fmig, it->second );
Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
- fm->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
+ fmig->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
Debug("fmf-model-cons") << std::endl;
d_uf_model_constructed[op] = true;
}else{
@@ -296,7 +331,7 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
-bool ModelEngineBuilder::hasConstantDefinition( Node n ){
+bool QModelBuilderIG::hasConstantDefinition( Node n ){
Node lit = n.getKind()==NOT ? n[0] : n;
if( lit.getKind()==APPLY_UF ){
Node op = lit.getOperator();
@@ -307,60 +342,141 @@ bool ModelEngineBuilder::hasConstantDefinition( Node n ){
return false;
}
-bool ModelEngineBuilder::optUseModel() {
- return options::fmfModelBasedInst();
-}
-
-bool ModelEngineBuilder::optInstGen(){
+bool QModelBuilderIG::optInstGen(){
return options::fmfInstGen();
}
-bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){
+bool QModelBuilderIG::optOneQuantPerRoundInstGen(){
return options::fmfInstGenOneQuantPerRound();
}
-bool ModelEngineBuilder::optExhInstNonInstGenQuant(){
- return options::fmfNewInstGen();
-}
-
-void ModelEngineBuilder::setEffort( int effort ){
- d_considerAxioms = effort>=1;
-}
-
-ModelEngineBuilder::Statistics::Statistics():
- d_num_quants_init("ModelEngineBuilder::Number_Quantifiers", 0),
- d_num_partial_quants_init("ModelEngineBuilder::Number_Partial_Quantifiers", 0),
- d_init_inst_gen_lemmas("ModelEngineBuilder::Initialize_Inst_Gen_Lemmas", 0 ),
- d_inst_gen_lemmas("ModelEngineBuilder::Inst_Gen_Lemmas", 0 )
+QModelBuilderIG::Statistics::Statistics():
+ d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0),
+ d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers", 0),
+ d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0 ),
+ d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0 ),
+ d_eval_formulas("QModelBuilderIG::Eval_Formulas", 0 ),
+ d_eval_uf_terms("QModelBuilderIG::Eval_Uf_Terms", 0 ),
+ d_eval_lits("QModelBuilderIG::Eval_Lits", 0 ),
+ d_eval_lits_unknown("QModelBuilderIG::Eval_Lits_Unknown", 0 )
{
StatisticsRegistry::registerStat(&d_num_quants_init);
StatisticsRegistry::registerStat(&d_num_partial_quants_init);
StatisticsRegistry::registerStat(&d_init_inst_gen_lemmas);
StatisticsRegistry::registerStat(&d_inst_gen_lemmas);
+ StatisticsRegistry::registerStat(&d_eval_formulas);
+ StatisticsRegistry::registerStat(&d_eval_uf_terms);
+ StatisticsRegistry::registerStat(&d_eval_lits);
+ StatisticsRegistry::registerStat(&d_eval_lits_unknown);
}
-ModelEngineBuilder::Statistics::~Statistics(){
+QModelBuilderIG::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_num_quants_init);
StatisticsRegistry::unregisterStat(&d_num_partial_quants_init);
StatisticsRegistry::unregisterStat(&d_init_inst_gen_lemmas);
StatisticsRegistry::unregisterStat(&d_inst_gen_lemmas);
+ StatisticsRegistry::unregisterStat(&d_eval_formulas);
+ StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
+ StatisticsRegistry::unregisterStat(&d_eval_lits);
+ StatisticsRegistry::unregisterStat(&d_eval_lits_unknown);
}
-bool ModelEngineBuilder::isQuantifierActive( Node f ){
- return ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
+bool QModelBuilderIG::isQuantifierActive( Node f ){
+ return !f.hasAttribute(QRewriteRuleAttribute()) &&
+ ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
}
-bool ModelEngineBuilder::isTermActive( Node n ){
+bool QModelBuilderIG::isTermActive( Node n ){
return !n.getAttribute(NoMatchAttribute()) || //it is not congruent to another active term
- ( n.getAttribute(ModelBasisArgAttribute())==1 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
+ ( n.getAttribute(ModelBasisArgAttribute())!=0 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
//and is not congruent modulo model basis
//to another active term
}
+//do exhaustive instantiation
+bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+ if( optUseModel() ){
+
+ RepSetIterator riter( d_qe, &(d_qe->getModel()->d_rep_set) );
+ if( riter.setQuantifier( f ) ){
+ FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
+ Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl;
+ fmig->resetEvaluate();
+ 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;
+ }
+ 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 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;
+ eval = fmig->evaluate( d_qe->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
+ if( eval==1 ){
+ Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
+ }else{
+ Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
+ }
+ if( eval==1 ){
+ //instantiation is already true -> skip
+ riter.increment2( depIndex );
+ }else{
+ //instantiation was not shown to be true, construct the match
+ InstMatch m;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ m.set( d_qe, f, riter.d_index_order[i], riter.getTerm( i ) );
+ }
+ Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
+ //add as instantiation
+ if( d_qe->addInstantiation( f, m ) ){
+ d_addedLemmas++;
+ //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
+ if( eval==-1 ){
+ riter.increment2( depIndex );
+ }else{
+ riter.increment();
+ }
+ }else{
+ Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
+ riter.increment();
+ }
+ }
+ }
+ //print debugging information
+ if( fmig ){
+ d_statistics.d_eval_formulas += fmig->d_eval_formulas;
+ d_statistics.d_eval_uf_terms += fmig->d_eval_uf_terms;
+ d_statistics.d_eval_lits += fmig->d_eval_lits;
+ d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
+ }
+ Trace("inst-fmf-ei") << "Finished: " << std::endl;
+ Trace("inst-fmf-ei") << " Inst Tried: " << d_triedLemmas << std::endl;
+ Trace("inst-fmf-ei") << " Inst Added: " << d_addedLemmas << std::endl;
+ if( d_addedLemmas>1000 ){
+ Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
+ Trace("model-engine-warn") << " Inst Tried: " << d_triedLemmas << std::endl;
+ Trace("model-engine-warn") << " Inst Added: " << d_addedLemmas << std::endl;
+ 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;
+ return true;
+ }else{
+ return false;
+ }
+}
+
-void ModelEngineBuilderDefault::reset( FirstOrderModel* fm ){
+void QModelBuilderDefault::reset( FirstOrderModel* fm ){
d_quant_selection_lit.clear();
d_quant_selection_lit_candidates.clear();
d_quant_selection_lit_terms.clear();
@@ -369,7 +485,7 @@ void ModelEngineBuilderDefault::reset( FirstOrderModel* fm ){
}
-int ModelEngineBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
+int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
/*
size_t maxChildren = 0;
for( size_t i=0; i<uf_terms.size(); i++ ){
@@ -383,7 +499,8 @@ int ModelEngineBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms
return 0;
}
-void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
//the pro/con preferences for this quantifier
std::vector< Node > pro_con[2];
@@ -408,7 +525,7 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
// constant definitions.
bool isConst = true;
std::vector< Node > uf_terms;
- if( n.hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(n) ){
isConst = false;
if( gn.getKind()==APPLY_UF ){
uf_terms.push_back( gn );
@@ -416,9 +533,9 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
}else if( gn.getKind()==EQUAL ){
isConst = true;
for( int j=0; j<2; j++ ){
- if( n[j].hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(n[j]) ){
if( n[j].getKind()==APPLY_UF &&
- fm->d_uf_model_tree.find( gn[j].getOperator() )!=fm->d_uf_model_tree.end() ){
+ fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){
uf_terms.push_back( gn[j] );
isConst = isConst && hasConstantDefinition( gn[j] );
}else{
@@ -506,14 +623,14 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
for( int k=0; k<2; k++ ){
for( int j=0; j<(int)pro_con[k].size(); j++ ){
Node op = pro_con[k][j].getOperator();
- Node r = fm->getRepresentative( pro_con[k][j] );
+ Node r = fmig->getRepresentative( pro_con[k][j] );
d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
}
}
}
}
-int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
+int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
int addedLemmas = 0;
//we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
//This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
@@ -523,17 +640,16 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
- Assert( lit.hasAttribute(InstConstantAttribute()) );
+ Assert( TermDb::hasInstConstAttr(lit) );
std::vector< Node > tr_terms;
if( lit.getKind()==APPLY_UF ){
//only match predicates that are contrary to this one, use literal matching
Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
- d_qe->getTermDatabase()->setInstantiationConstantAttr( eq, f );
tr_terms.push_back( eq );
}else if( lit.getKind()==EQUAL ){
//collect trigger terms
for( int j=0; j<2; j++ ){
- if( lit[j].hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(lit[j]) ){
if( lit[j].getKind()==APPLY_UF ){
tr_terms.push_back( lit[j] );
}else{
@@ -564,7 +680,8 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
return addedLemmas;
}
-void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
+void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
if( optReconsiderFuncConstants() ){
//reconsider constant functions that weren't necessary
if( d_uf_model_constructed[op] ){
@@ -573,8 +690,8 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Node v = d_uf_prefs[op].d_const_val;
if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
- fm->d_uf_model_tree[op].clear();
- fm->d_uf_model_gen[op].clear();
+ fmig->d_uf_model_tree[op].clear();
+ fmig->d_uf_model_gen[op].clear();
d_uf_model_constructed[op] = false;
}
}
@@ -586,20 +703,20 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
//set the values in the model
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
+ Node n = fmig->d_uf_terms[op][i];
if( isTermActive( n ) ){
- Node v = fm->getRepresentative( n );
- Trace("fmf-model-cons") << "Set term " << n << " : " << fm->d_rep_set.getIndexFor( v ) << " " << v << std::endl;
+ Node v = fmig->getRepresentative( n );
+ Trace("fmf-model-cons") << "Set term " << n << " : " << fmig->d_rep_set.getIndexFor( v ) << " " << v << std::endl;
//if this assertion did not help the model, just consider it ground
//set n = v in the model tree
//set it as ground value
- fm->d_uf_model_gen[op].setValue( fm, n, v );
- if( fm->d_uf_model_gen[op].optUsePartialDefaults() ){
+ fmig->d_uf_model_gen[op].setValue( fm, n, v );
+ if( fmig->d_uf_model_gen[op].optUsePartialDefaults() ){
//also set as default value if necessary
- if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())!=0 ){
Trace("fmf-model-cons") << " Set as default." << std::endl;
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
if( n==defaultTerm ){
//incidentally already set, we will not need to find a default value
setDefaultVal = false;
@@ -607,7 +724,7 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
}
}else{
if( n==defaultTerm ){
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
//incidentally already set, we will not need to find a default value
setDefaultVal = false;
}
@@ -619,12 +736,19 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Trace("fmf-model-cons") << " Choose default value..." << std::endl;
//chose defaultVal based on heuristic, currently the best ratio of "pro" responses
Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
+ if( defaultVal.isNull() ){
+ if (!fmig->d_rep_set.hasType(defaultTerm.getType())) {
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(defaultTerm.getType());
+ fmig->d_rep_set.d_type_reps[defaultTerm.getType()].push_back(mbt);
+ }
+ defaultVal = fmig->d_rep_set.d_type_reps[defaultTerm.getType()][0];
+ }
Assert( !defaultVal.isNull() );
- Trace("fmf-model-cons") << "Set default term : " << fm->d_rep_set.getIndexFor( defaultVal ) << std::endl;
- fm->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+ Trace("fmf-model-cons") << "Set default term : " << fmig->d_rep_set.getIndexFor( defaultVal ) << std::endl;
+ fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
}
Debug("fmf-model-cons") << " Making model...";
- fm->d_uf_model_gen[op].makeModel( fm, fm->d_uf_model_tree[op] );
+ fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
d_uf_model_constructed[op] = true;
Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl;
}
@@ -635,7 +759,7 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
////////////////////// Inst-Gen style Model Builder ///////////
-void ModelEngineBuilderInstGen::reset( FirstOrderModel* fm ){
+void QModelBuilderInstGen::reset( FirstOrderModel* fm ){
//for new inst gen
d_quant_selection_formula.clear();
d_term_selected.clear();
@@ -643,15 +767,15 @@ void ModelEngineBuilderInstGen::reset( FirstOrderModel* fm ){
//d_sub_quant_inst_trie.clear();//*
}
-int ModelEngineBuilderInstGen::initializeQuantifier( Node f, Node fp ){
- int addedLemmas = ModelEngineBuilder::initializeQuantifier( f, fp );
+int QModelBuilderInstGen::initializeQuantifier( Node f, Node fp ){
+ int addedLemmas = QModelBuilderIG::initializeQuantifier( f, fp );
for( size_t i=0; i<d_sub_quants[f].size(); i++ ){
addedLemmas += initializeQuantifier( d_sub_quants[f][i], fp );
}
return addedLemmas;
}
-void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+void QModelBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f ){
//Node fp = getParentQuantifier( f );//*
//bool quantRedundant = ( f!=fp && d_sub_quant_inst_trie[fp].addInstMatch( d_qe, fp, d_sub_quant_inst[ f ], true ) );
//if( f==fp || d_sub_quant_inst_trie[fp].addInstMatch( d_qe, fp, d_sub_quant_inst[ f ], true ) ){//*
@@ -662,7 +786,6 @@ void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f )
//if( !s.isNull() ){
// s = Rewriter::rewrite( s );
//}
- d_qe->getTermDatabase()->setInstantiationConstantAttr( s, f );
Trace("sel-form-debug") << "Selection formula " << f << std::endl;
Trace("sel-form-debug") << " " << s << std::endl;
if( !s.isNull() ){
@@ -685,7 +808,7 @@ void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f )
}
-int ModelEngineBuilderInstGen::doInstGen( FirstOrderModel* fm, Node f ){
+int QModelBuilderInstGen::doInstGen( FirstOrderModel* fm, Node f ){
int addedLemmas = 0;
if( d_quant_sat.find( f )==d_quant_sat.end() ){
Node fp = d_sub_quant_parent.find( f )==d_sub_quant_parent.end() ? f : d_sub_quant_parent[f];
@@ -802,7 +925,7 @@ Node mkAndSelectionFormula( Node n1, Node n2 ){
//if possible, returns a formula n' such that n' => ( n <=> polarity ), and n' is true in the current context,
// and NULL otherwise
-Node ModelEngineBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity, int useOption ){
+Node QModelBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity, int useOption ){
Trace("sel-form-debug") << "Looking for selection formula " << n << " " << polarity << std::endl;
Node ret;
if( n.getKind()==NOT ){
@@ -911,7 +1034,7 @@ Node ModelEngineBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polar
return ret;
}
-int ModelEngineBuilderInstGen::getSelectionFormulaScore( Node fn ){
+int QModelBuilderInstGen::getSelectionFormulaScore( Node fn ){
if( fn.getType().isBoolean() ){
if( fn.getKind()==APPLY_UF ){
Node op = fn.getOperator();
@@ -929,13 +1052,13 @@ int ModelEngineBuilderInstGen::getSelectionFormulaScore( Node fn ){
}
}
-void ModelEngineBuilderInstGen::setSelectedTerms( Node s ){
+void QModelBuilderInstGen::setSelectedTerms( Node s ){
//if it is apply uf and has model basis arguments, then mark term as being "selected"
if( s.getKind()==APPLY_UF ){
Assert( s.hasAttribute(ModelBasisArgAttribute()) );
if( !s.hasAttribute(ModelBasisArgAttribute()) ) std::cout << "no mba!! " << s << std::endl;
- if( s.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( s.getAttribute(ModelBasisArgAttribute())!=0 ){
d_term_selected[ s ] = true;
Trace("sel-form-term") << " " << s << " is a selected term." << std::endl;
}
@@ -945,7 +1068,7 @@ void ModelEngineBuilderInstGen::setSelectedTerms( Node s ){
}
}
-bool ModelEngineBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption ){
+bool QModelBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption ){
if( n.getKind()==FORALL ){
return false;
}else if( n.getKind()!=APPLY_UF ){
@@ -964,7 +1087,7 @@ bool ModelEngineBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption
return true;
}
-void ModelEngineBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp, InstMatch& m, Node f ){
+void QModelBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp, InstMatch& m, Node f ){
if( f!=fp ){
//std::cout << "gpqm " << fp << " " << f << " " << m << std::endl;
//std::cout << " " << fp[0].getNumChildren() << " " << f[0].getNumChildren() << std::endl;
@@ -988,20 +1111,21 @@ void ModelEngineBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp
}
}
-void ModelEngineBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op ){
+void QModelBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
bool setDefaultVal = true;
Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
//set the values in the model
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
+ Node n = fmig->d_uf_terms[op][i];
if( isTermActive( n ) ){
- Node v = fm->getRepresentative( n );
- fm->d_uf_model_gen[op].setValue( fm, n, v );
+ Node v = fmig->getRepresentative( n );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v );
}
//also possible set as default
if( d_term_selected.find( n )!=d_term_selected.end() || n==defaultTerm ){
- Node v = fm->getRepresentative( n );
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ Node v = fmig->getRepresentative( n );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
if( n==defaultTerm ){
setDefaultVal = false;
}
@@ -1010,12 +1134,12 @@ void ModelEngineBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op )
//set the overall default value if not set already (is this necessary??)
if( setDefaultVal ){
Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
- fm->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+ fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
}
- fm->d_uf_model_gen[op].makeModel( fm, fm->d_uf_model_tree[op] );
+ fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
d_uf_model_constructed[op] = true;
}
-bool ModelEngineBuilderInstGen::existsInstantiation( Node f, InstMatch& m, bool modEq, bool modInst ){
+bool QModelBuilderInstGen::existsInstantiation( Node f, InstMatch& m, bool modEq, bool modInst ){
return d_child_sub_quant_inst_trie[f].existsInstMatch( d_qe, f, m, modEq, true );
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
index 31448acee..b96c58767 100644
--- a/src/theory/quantifiers/model_builder.h
+++ b/src/theory/quantifiers/model_builder.h
@@ -25,6 +25,42 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
+
+class QModelBuilder : public TheoryEngineModelBuilder
+{
+protected:
+ //the model we are working with
+ context::CDO< FirstOrderModel* > d_curr_model;
+ //quantifiers engine
+ QuantifiersEngine* d_qe;
+public:
+ QModelBuilder( context::Context* c, QuantifiersEngine* qe );
+ virtual ~QModelBuilder(){}
+ // is quantifier active?
+ virtual bool isQuantifierActive( Node f );
+ //do exhaustive instantiation
+ virtual bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; }
+ //whether to construct model
+ virtual bool optUseModel();
+ //whether to construct model at fullModel = true
+ virtual bool optBuildAtFullModel() { return false; }
+ //consider axioms
+ bool d_considerAxioms;
+ /** number of lemmas generated while building model */
+ //is the exhaustive instantiation incomplete?
+ bool d_incomplete_check;
+ int d_addedLemmas;
+ int d_triedLemmas;
+ /** exist instantiation ? */
+ virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
+ //debug model
+ void debugModel( FirstOrderModel* fm );
+};
+
+
+
+
+
/** Attribute true for nodes that should not be used when considered for inst-gen basis */
struct BasisNoMatchAttributeId {};
/** use the special for boolean flag */
@@ -47,17 +83,13 @@ public:
/** model builder class
* This class is capable of building candidate models based on the current quantified formulas
* that are asserted. Use:
- * (1) call ModelEngineBuilder::buildModel( m, false );, where m is a FirstOrderModel
+ * (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel
* (2) if candidate model is determined to be a real model,
- then call ModelEngineBuilder::buildModel( m, true );
+ then call QModelBuilder::buildModel( m, true );
*/
-class ModelEngineBuilder : public TheoryEngineModelBuilder
+class QModelBuilderIG : public QModelBuilder
{
protected:
- //quantifiers engine
- QuantifiersEngine* d_qe;
- //the model we are working with
- context::CDO< FirstOrderModel* > d_curr_model;
//map from operators to model preference data
std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
//built model uf
@@ -66,6 +98,8 @@ protected:
bool d_didInstGen;
/** process build model */
virtual void processBuildModel( TheoryModel* m, bool fullModel );
+ /** get current model value */
+ Node getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial );
protected:
//reset
virtual void reset( FirstOrderModel* fm ) = 0;
@@ -90,25 +124,13 @@ protected: //helper functions
/** term has constant definition */
bool hasConstantDefinition( Node n );
public:
- ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe );
- virtual ~ModelEngineBuilder(){}
- /** number of lemmas generated while building model */
- int d_addedLemmas;
- //consider axioms
- bool d_considerAxioms;
- // set effort
- void setEffort( int effort );
- //debug model
- void debugModel( FirstOrderModel* fm );
+ QModelBuilderIG( context::Context* c, QuantifiersEngine* qe );
+ virtual ~QModelBuilderIG(){}
public:
- //whether to construct model
- virtual bool optUseModel();
//whether to add inst-gen lemmas
virtual bool optInstGen();
//whether to only consider only quantifier per round of inst-gen
virtual bool optOneQuantPerRoundInstGen();
- //whether we should exhaustively instantiate quantifiers where inst-gen is not working
- virtual bool optExhInstNonInstGenQuant();
/** statistics class */
class Statistics {
public:
@@ -116,22 +138,26 @@ public:
IntStat d_num_partial_quants_init;
IntStat d_init_inst_gen_lemmas;
IntStat d_inst_gen_lemmas;
+ IntStat d_eval_formulas;
+ IntStat d_eval_uf_terms;
+ IntStat d_eval_lits;
+ IntStat d_eval_lits_unknown;
Statistics();
~Statistics();
};
Statistics d_statistics;
- // is quantifier active?
- bool isQuantifierActive( Node f );
// is term active
bool isTermActive( Node n );
// is term selected
virtual bool isTermSelected( Node n ) { return false; }
- /** exist instantiation ? */
- virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
/** quantifier has inst-gen definition */
virtual bool hasInstGen( Node f ) = 0;
/** did inst gen this round? */
bool didInstGen() { return d_didInstGen; }
+ // is quantifier active?
+ bool isQuantifierActive( Node f );
+ //do exhaustive instantiation
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
//temporary stats
int d_numQuantSat;
@@ -140,10 +166,10 @@ public:
int d_numQuantNoSelForm;
//temporary stat
int d_instGenMatches;
-};/* class ModelEngineBuilder */
+};/* class QModelBuilder */
-class ModelEngineBuilderDefault : public ModelEngineBuilder
+class QModelBuilderDefault : public QModelBuilderIG
{
private: ///information for (old) InstGen
//map from quantifiers to their selection literals
@@ -167,15 +193,15 @@ protected:
//theory-specific build models
void constructModelUf( FirstOrderModel* fm, Node op );
public:
- ModelEngineBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : ModelEngineBuilder( c, qe ){}
- ~ModelEngineBuilderDefault(){}
+ QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
+ ~QModelBuilderDefault(){}
//options
bool optReconsiderFuncConstants() { return true; }
//has inst gen
bool hasInstGen( Node f ) { return !d_quant_selection_lit[f].isNull(); }
};
-class ModelEngineBuilderInstGen : public ModelEngineBuilder
+class QModelBuilderInstGen : public QModelBuilderIG
{
private: ///information for (new) InstGen
//map from quantifiers to their selection formulas
@@ -217,8 +243,8 @@ private:
//get parent quantifier
Node getParentQuantifier( Node f ) { return d_sub_quant_parent.find( f )==d_sub_quant_parent.end() ? f : d_sub_quant_parent[f]; }
public:
- ModelEngineBuilderInstGen( context::Context* c, QuantifiersEngine* qe ) : ModelEngineBuilder( c, qe ){}
- ~ModelEngineBuilderInstGen(){}
+ QModelBuilderInstGen( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
+ ~QModelBuilderInstGen(){}
// is term selected
bool isTermSelected( Node n ) { return d_term_selected.find( n )!=d_term_selected.end(); }
/** exist instantiation ? */
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index a69b278c0..cb8cb8154 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -18,13 +18,10 @@
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_strong_solver.h"
#include "theory/quantifiers/options.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
-#define EVAL_FAIL_SKIP_MULTIPLE
-
using namespace std;
using namespace CVC4;
using namespace CVC4::kind;
@@ -35,15 +32,21 @@ using namespace CVC4::theory::inst;
//Model Engine constructor
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
-QuantifiersModule( qe ),
-d_rel_domain( qe, qe->getModel() ){
+QuantifiersModule( qe ){
- if( options::fmfNewInstGen() ){
- d_builder = new ModelEngineBuilderInstGen( c, qe );
+ if( options::fmfFullModelCheck() ){
+ d_builder = new fmcheck::FullModelChecker( c, qe );
+ }else if( options::fmfNewInstGen() ){
+ d_builder = new QModelBuilderInstGen( c, qe );
}else{
- d_builder = new ModelEngineBuilderDefault( c, qe );
+ d_builder = new QModelBuilderDefault( c, qe );
}
+ if( options::fmfRelevantDomain() ){
+ d_rel_dom = new RelevantDomain( qe, qe->getModel() );
+ }else{
+ d_rel_dom = NULL;
+ }
}
void ModelEngine::check( Theory::Effort e ){
@@ -57,6 +60,7 @@ void ModelEngine::check( Theory::Effort e ){
clSet = double(clock())/double(CLOCKS_PER_SEC);
}
++(d_statistics.d_inst_rounds);
+ bool buildAtFullModel = d_builder->optBuildAtFullModel();
//two effort levels: first try exhaustive instantiation without axioms, then with.
int startEffort = ( !fm->isAxiomAsserted() || options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT ) ? 1 : 0;
for( int effort=startEffort; effort<2; effort++ ){
@@ -66,8 +70,9 @@ void ModelEngine::check( Theory::Effort e ){
Trace("model-engine") << "---Model Engine Round---" << std::endl;
//initialize the model
Trace("model-engine-debug") << "Build model..." << std::endl;
- d_builder->setEffort( effort );
- d_builder->buildModel( fm, false );
+ d_builder->d_considerAxioms = effort>=1;
+ d_builder->d_addedLemmas = 0;
+ d_builder->buildModel( fm, buildAtFullModel );
addedLemmas += (int)d_builder->d_addedLemmas;
//if builder has lemmas, add and return
if( addedLemmas==0 ){
@@ -81,11 +86,7 @@ void ModelEngine::check( Theory::Effort e ){
Debug("fmf-model-complete") << std::endl;
debugPrint("fmf-model-complete");
//successfully built an acceptable model, now check it
- addedLemmas += checkModel( check_model_full );
- }else if( d_builder->didInstGen() && d_builder->optExhInstNonInstGenQuant() ){
- Trace("model-engine-debug") << "Check model for non-inst gen quantifiers..." << std::endl;
- //check quantifiers that inst-gen didn't apply to
- addedLemmas += checkModel( check_model_no_inst_gen );
+ addedLemmas += checkModel();
}
}
if( addedLemmas==0 ){
@@ -108,7 +109,7 @@ void ModelEngine::check( Theory::Effort e ){
//CVC4 will answer SAT or unknown
Trace("fmf-consistent") << std::endl;
debugPrint("fmf-consistent");
- if( options::produceModels() ){
+ if( options::produceModels() && !buildAtFullModel ){
// finish building the model
d_builder->buildModel( fm, true );
}
@@ -131,28 +132,12 @@ void ModelEngine::assertNode( Node f ){
}
-bool ModelEngine::optOneInstPerQuantRound(){
- return options::fmfOneInstPerRound();
-}
-
-bool ModelEngine::optUseRelevantDomain(){
- return options::fmfRelevantDomain();
-}
-
bool ModelEngine::optOneQuantPerRound(){
return options::fmfOneQuantPerRound();
}
-bool ModelEngine::optExhInstEvalSkipMultiple(){
-#ifdef EVAL_FAIL_SKIP_MULTIPLE
- return true;
-#else
- return false;
-#endif
-}
-int ModelEngine::checkModel( int checkOption ){
- int addedLemmas = 0;
+int ModelEngine::checkModel(){
FirstOrderModel* fm = d_quantEngine->getModel();
//for debugging
if( Trace.isOn("model-engine") || Trace.isOn("model-engine-debug") ){
@@ -161,27 +146,28 @@ int ModelEngine::checkModel( int checkOption ){
if( it->first.isSort() ){
Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
Trace("model-engine-debug") << " ";
+ Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
for( size_t i=0; i<it->second.size(); i++ ){
//Trace("model-engine-debug") << it->second[i] << " ";
Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getRepresentative( it->second[i] );
Trace("model-engine-debug") << r << " ";
}
Trace("model-engine-debug") << std::endl;
+ Trace("model-engine-debug") << " Model basis term : " << mbt << std::endl;
}
}
}
- //compute the relevant domain if necessary
- if( optUseRelevantDomain() ){
- d_rel_domain.compute();
+ //relevant domain?
+ if( d_rel_dom ){
+ d_rel_dom->compute();
}
+
d_triedLemmas = 0;
- d_testLemmas = 0;
- d_relevantLemmas = 0;
+ d_addedLemmas = 0;
d_totalLemmas = 0;
- Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
+ //for statistics
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
Node f = fm->getAssertedQuantifier( i );
- //keep track of total instantiations for statistics
int totalInst = 1;
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
TypeNode tn = f[0][i].getType();
@@ -190,133 +176,85 @@ int ModelEngine::checkModel( int checkOption ){
}
}
d_totalLemmas += totalInst;
- //determine if we should check this quantifiers
- bool checkQuant = false;
- if( checkOption==check_model_full ){
- checkQuant = d_builder->isQuantifierActive( f );
- }else if( checkOption==check_model_no_inst_gen ){
- checkQuant = !d_builder->hasInstGen( f );
- }
- //if we need to consider this quantifier on this iteration
- if( checkQuant ){
- addedLemmas += exhaustiveInstantiate( f, optUseRelevantDomain() );
- if( Trace.isOn("model-engine-warn") ){
- if( addedLemmas>10000 ){
- Debug("fmf-exit") << std::endl;
- debugPrint("fmf-exit");
- exit( 0 );
+ }
+
+ Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
+ int e_max = options::fmfFullModelCheck() && options::fmfModelBasedInst() ? 2 : 1;
+ for( int e=0; e<e_max; e++) {
+ if (d_addedLemmas==0) {
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ //determine if we should check this quantifier
+ if( d_builder->isQuantifierActive( f ) ){
+ exhaustiveInstantiate( f, e );
+ if( Trace.isOn("model-engine-warn") ){
+ if( d_addedLemmas>10000 ){
+ Debug("fmf-exit") << std::endl;
+ debugPrint("fmf-exit");
+ exit( 0 );
+ }
+ }
+ if( optOneQuantPerRound() && d_addedLemmas>0 ){
+ break;
+ }
}
}
- if( optOneQuantPerRound() && addedLemmas>0 ){
- break;
- }
}
}
//print debug information
if( Trace.isOn("model-engine") ){
Trace("model-engine") << "Instantiate axioms : " << ( d_builder->d_considerAxioms ? "yes" : "no" ) << std::endl;
- Trace("model-engine") << "Added Lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
- Trace("model-engine") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
+ Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
+ Trace("model-engine") << d_totalLemmas << std::endl;
}
- d_statistics.d_exh_inst_lemmas += addedLemmas;
- return addedLemmas;
+ d_statistics.d_exh_inst_lemmas += d_addedLemmas;
+ return d_addedLemmas;
}
-int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){
- int addedLemmas = 0;
- Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << "..." << std::endl;
- Debug("inst-fmf-ei") << " Instantiation Constants: ";
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
- }
- Debug("inst-fmf-ei") << std::endl;
-
- //create a rep set iterator and iterate over the (relevant) domain of the quantifier
- RepSetIterator riter( &(d_quantEngine->getModel()->d_rep_set) );
- if( riter.setQuantifier( f ) ){
- //set the domain for the iterator (the sufficient set of instantiations to try)
- if( useRelInstDomain ){
- riter.setDomain( d_rel_domain.d_quant_inst_domain[f] );
+void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
+ //first check if the builder can do the exhaustive instantiation
+ d_builder->d_triedLemmas = 0;
+ d_builder->d_addedLemmas = 0;
+ d_builder->d_incomplete_check = false;
+ if( d_builder->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){
+ d_triedLemmas += d_builder->d_triedLemmas;
+ d_addedLemmas += d_builder->d_addedLemmas;
+ d_incomplete_check = d_incomplete_check || d_builder->d_incomplete_check;
+ }else{
+ Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
+ Debug("inst-fmf-ei") << " Instantiation Constants: ";
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
}
- d_quantEngine->getModel()->resetEvaluate();
- int tests = 0;
- int triedLemmas = 0;
- while( !riter.isFinished() && ( addedLemmas==0 || !optOneInstPerQuantRound() ) ){
- d_testLemmas++;
- int eval = 0;
- int depIndex;
- if( d_builder->optUseModel() ){
- //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;
- tests++;
- //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;
- eval = d_quantEngine->getModel()->evaluate( d_quantEngine->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
- if( eval==1 ){
- Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
- }else{
- Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
- }
- }
- if( eval==1 ){
- //instantiation is already true -> skip
- riter.increment2( depIndex );
- }else{
+ Debug("inst-fmf-ei") << std::endl;
+ //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 ) ){
+ Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
+ 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;
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_quantEngine->getTermDatabase()->getInstantiationConstant( f, riter.d_index_order[i] ), riter.getTerm( i ) );
+ m.set( d_quantEngine, f, riter.d_index_order[i], riter.getTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
- d_triedLemmas++;
//add as instantiation
if( d_quantEngine->addInstantiation( f, m ) ){
addedLemmas++;
- //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
- if( eval==-1 && optExhInstEvalSkipMultiple() ){
- riter.increment2( depIndex );
- }else{
- riter.increment();
- }
}else{
Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
- riter.increment();
}
+ riter.increment();
}
+ d_addedLemmas += addedLemmas;
+ d_triedLemmas += triedLemmas;
}
- //print debugging information
- d_statistics.d_eval_formulas += d_quantEngine->getModel()->d_eval_formulas;
- d_statistics.d_eval_uf_terms += d_quantEngine->getModel()->d_eval_uf_terms;
- d_statistics.d_eval_lits += d_quantEngine->getModel()->d_eval_lits;
- d_statistics.d_eval_lits_unknown += d_quantEngine->getModel()->d_eval_lits_unknown;
- int relevantInst = 1;
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- relevantInst = relevantInst * (int)riter.d_domain[i].size();
- }
- d_relevantLemmas += relevantInst;
- Trace("inst-fmf-ei") << "Finished: " << std::endl;
- //Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl;
- Trace("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl;
- Trace("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl;
- Trace("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl;
- Trace("inst-fmf-ei") << " # Tests: " << tests << std::endl;
- if( addedLemmas>1000 ){
- Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
- //Trace("model-engine-warn") << " Inst Total: " << totalInst << std::endl;
- Trace("model-engine-warn") << " Inst Relevant: " << relevantInst << std::endl;
- Trace("model-engine-warn") << " Inst Tried: " << triedLemmas << std::endl;
- Trace("model-engine-warn") << " Inst Added: " << addedLemmas << std::endl;
- Trace("model-engine-warn") << " # Tests: " << tests << std::endl;
- 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 = 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 = d_incomplete_check || riter.d_incomplete;
- return addedLemmas;
}
void ModelEngine::debugPrint( const char* c ){
@@ -336,26 +274,14 @@ void ModelEngine::debugPrint( const char* c ){
ModelEngine::Statistics::Statistics():
d_inst_rounds("ModelEngine::Inst_Rounds", 0),
- d_eval_formulas("ModelEngine::Eval_Formulas", 0 ),
- d_eval_uf_terms("ModelEngine::Eval_Uf_Terms", 0 ),
- d_eval_lits("ModelEngine::Eval_Lits", 0 ),
- d_eval_lits_unknown("ModelEngine::Eval_Lits_Unknown", 0 ),
d_exh_inst_lemmas("ModelEngine::Exhaustive_Instantiation_Lemmas", 0 )
{
StatisticsRegistry::registerStat(&d_inst_rounds);
- StatisticsRegistry::registerStat(&d_eval_formulas);
- StatisticsRegistry::registerStat(&d_eval_uf_terms);
- StatisticsRegistry::registerStat(&d_eval_lits);
- StatisticsRegistry::registerStat(&d_eval_lits_unknown);
StatisticsRegistry::registerStat(&d_exh_inst_lemmas);
}
ModelEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_inst_rounds);
- StatisticsRegistry::unregisterStat(&d_eval_formulas);
- StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
- StatisticsRegistry::unregisterStat(&d_eval_lits);
- StatisticsRegistry::unregisterStat(&d_eval_lits_unknown);
StatisticsRegistry::unregisterStat(&d_exh_inst_lemmas);
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 386864164..1c2c38c51 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -20,6 +20,7 @@
#include "theory/quantifiers_engine.h"
#include "theory/quantifiers/model_builder.h"
#include "theory/model.h"
+#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/relevant_domain.h"
namespace CVC4 {
@@ -31,38 +32,31 @@ class ModelEngine : public QuantifiersModule
friend class RepSetIterator;
private:
/** builder class */
- ModelEngineBuilder* d_builder;
+ QModelBuilder* d_builder;
private: //analysis of current model:
- //relevant domain
- RelevantDomain d_rel_domain;
- //is the exhaustive instantiation incomplete?
- bool d_incomplete_check;
+ RelevantDomain* d_rel_dom;
private:
//options
- bool optOneInstPerQuantRound();
- bool optUseRelevantDomain();
bool optOneQuantPerRound();
- bool optExhInstEvalSkipMultiple();
private:
- enum{
- check_model_full,
- check_model_no_inst_gen,
- };
//check model
- int checkModel( int checkOption );
- //exhaustively instantiate quantifier (possibly using mbqi), return number of lemmas produced
- int exhaustiveInstantiate( Node f, bool useRelInstDomain = false );
+ int checkModel();
+ //exhaustively instantiate quantifier (possibly using mbqi)
+ void exhaustiveInstantiate( Node f, int effort = 0 );
private:
//temporary statistics
+ //is the exhaustive instantiation incomplete?
+ bool d_incomplete_check;
+ int d_addedLemmas;
int d_triedLemmas;
- int d_testLemmas;
int d_totalLemmas;
- int d_relevantLemmas;
public:
ModelEngine( context::Context* c, QuantifiersEngine* qe );
~ModelEngine(){}
+ //get relevant domain
+ RelevantDomain * getRelevantDomain() { return d_rel_dom; }
//get the builder
- ModelEngineBuilder* getModelBuilder() { return d_builder; }
+ QModelBuilder* getModelBuilder() { return d_builder; }
public:
void check( Theory::Effort e );
void registerQuantifier( Node f );
@@ -74,10 +68,6 @@ public:
class Statistics {
public:
IntStat d_inst_rounds;
- IntStat d_eval_formulas;
- IntStat d_eval_uf_terms;
- IntStat d_eval_lits;
- IntStat d_eval_lits_unknown;
IntStat d_exh_inst_lemmas;
Statistics();
~Statistics();
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 60f5a171d..57211ade7 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -24,8 +24,11 @@ option prenexQuant /--disable-prenex-quant bool :default true
# Whether to variable-eliminate quantifiers.
# For example, forall x y. ( P( x, y ) V x != c ) will be rewritten to
# forall y. P( c, y )
-option varElimQuant --var-elim-quant bool :default false
- enable variable elimination of quantified formulas
+option varElimQuant /--disable-var-elim-quant bool :default true
+ disable simple variable elimination for quantified formulas
+
+option simpleIteLiftQuant /--disable-ite-lift-quant bool :default true
+ disable simple ite lifting for quantified formulas
# Whether to CNF quantifier bodies
option cnfQuant --cnf-quant bool :default false
@@ -47,6 +50,9 @@ option aggressiveMiniscopeQuant --ag-miniscope-quant bool :default false
# Whether to perform quantifier macro expansion
option macrosQuant --macros-quant bool :default false
perform quantifiers macro expansions
+# Whether to perform first-order propagation
+option foPropQuant --fo-prop-quant bool :default false
+ perform first-order propagation on quantifiers
# Whether to use smart triggers
option smartTriggers /--disable-smart-triggers bool :default true
@@ -54,6 +60,8 @@ option smartTriggers /--disable-smart-triggers bool :default true
# Whether to use relevent triggers
option relevantTriggers /--disable-relevant-triggers bool :default true
prefer triggers that are more relevant based on SInE style analysis
+option relationalTriggers --relational-triggers bool :default false
+ choose relational triggers such as x = f(y), x >= f(y)
# Whether to consider terms in the bodies of quantifiers for matching
option registerQuantBodyTerms --register-quant-body-terms bool :default false
@@ -72,6 +80,8 @@ option cbqi --enable-cbqi/--disable-cbqi bool :default false
turns on counterexample-based quantifier instantiation [off by default]
/turns off counterexample-based quantifier instantiation
+option recurseCbqi --cbqi-recurse bool :default false
+ turns on recursive counterexample-based quantifier instantiation
option userPatternsQuant /--ignore-user-patterns bool :default true
ignore user-provided patterns for quantifier instantiation
@@ -88,6 +98,15 @@ option finiteModelFind --finite-model-find bool :default false
option fmfModelBasedInst /--disable-fmf-mbqi bool :default true
disable model-based quantifier instantiation for finite model finding
+option fmfFullModelCheck --fmf-fmc bool :default false
+ enable full model check for finite model finding
+option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
+ disable simple models in full model check for finite model finding
+option fmfFmcCoverSimplify /--disable-fmf-fmc-cover-simplify bool :default true
+ disable covering simplification of fmc models
+option fmfFmcInterval --fmf-fmc-interval bool :default false
+ construct interval models for fmc models
+
option fmfOneInstPerRound --fmf-one-inst-per-round bool :default false
only add one instantiation per quantifier per round for fmf
option fmfOneQuantPerRound --fmf-one-quant-per-round bool :default false
@@ -98,13 +117,17 @@ option fmfRelevantDomain --fmf-relevant-domain bool :default false
use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)
option fmfNewInstGen --fmf-new-inst-gen bool :default false
use new inst gen technique for answering sat without exhaustive instantiation
-option fmfInstGen /--disable-fmf-inst-gen bool :default true
- disable Inst-Gen instantiation techniques for finite model finding
+option fmfInstGen --fmf-inst-gen/--disable-fmf-inst-gen bool :read-write :default true
+ enable Inst-Gen instantiation techniques for finite model finding (default)
+/disable Inst-Gen instantiation techniques for finite model finding
option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false
only perform Inst-Gen instantiation techniques on one quantifier per round
option fmfFreshDistConst --fmf-fresh-dc bool :default false
use fresh distinguished representative when applying Inst-Gen techniques
+option fmfBoundInt --fmf-bound-int bool :default false
+ finite model finding on bounded integer quantification
+
option axiomInstMode --axiom-inst=MODE CVC4::theory::quantifiers::AxiomInstMode :default CVC4::theory::quantifiers::AXIOM_INST_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToAxiomInstMode :handler-include "theory/quantifiers/options_handlers.h"
policy for instantiating axioms
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 36db56d0d..59995a510 100644
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -22,6 +22,102 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
+
+bool QuantArith::getMonomial( Node n, std::map< Node, Node >& msum ) {
+ if ( n.getKind()==MULT ){
+ if( n.getNumChildren()==2 && msum.find(n[1])==msum.end() && n[0].isConst() ){
+ msum[n[1]] = n[0];
+ return true;
+ }
+ }else{
+ if( msum.find(n)==msum.end() ){
+ msum[n] = Node::null();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QuantArith::getMonomialSum( Node n, std::map< Node, Node >& msum ) {
+ if ( n.getKind()==PLUS ){
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ if (!getMonomial( n[i], msum )){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return getMonomial( n, msum );
+ }
+}
+
+bool QuantArith::getMonomialSumLit( Node lit, std::map< Node, Node >& msum ) {
+ if( lit.getKind()==GEQ || lit.getKind()==EQUAL ){
+ if( getMonomialSum( lit[0], msum ) ){
+ if( lit[1].isConst() ){
+ if( !lit[1].getConst<Rational>().isZero() ){
+ msum[Node::null()] = negate( lit[1] );
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k ) {
+ if( msum.find(v)!=msum.end() ){
+ std::vector< Node > children;
+ Rational r = msum[v].isNull() ? Rational(1) : msum[v].getConst<Rational>();
+ if ( r.sgn()!=0 ){
+ for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ if( it->first.isNull() || it->first!=v ){
+ Node m;
+ if( !it->first.isNull() ){
+ if ( !it->second.isNull() ){
+ m = NodeManager::currentNM()->mkNode( MULT, it->second, it->first );
+ }else{
+ m = it->first;
+ }
+ }else{
+ m = it->second;
+ }
+ children.push_back(m);
+ }
+ }
+ veq = children.size()>1 ? NodeManager::currentNM()->mkNode( PLUS, children ) :
+ (children.size()==1 ? children[0] : NodeManager::currentNM()->mkConst( Rational(0) ));
+ if( !r.isNegativeOne() ){
+ if( r.isOne() ){
+ veq = negate(veq);
+ }else{
+ //TODO
+ return false;
+ }
+ }
+ veq = Rewriter::rewrite( veq );
+ veq = NodeManager::currentNM()->mkNode( k, r.sgn()==1 ? v : veq, r.sgn()==1 ? veq : v );
+ return true;
+ }
+ return false;
+ }else{
+ return false;
+ }
+}
+
+Node QuantArith::negate( Node t ) {
+ Node tt = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) ), t );
+ tt = Rewriter::rewrite( tt );
+ return tt;
+}
+
+Node QuantArith::offset( Node t, int i ) {
+ Node tt = NodeManager::currentNM()->mkNode( PLUS, NodeManager::currentNM()->mkConst( Rational(i) ), t );
+ tt = Rewriter::rewrite( tt );
+ return tt;
+}
+
+
void QuantRelevance::registerQuantifier( Node f ){
//compute symbols in f
std::vector< Node > syms;
@@ -93,13 +189,13 @@ QuantPhaseReq::QuantPhaseReq( Node n, bool computeEq ){
for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){
Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl;
if( it->first.getKind()==EQUAL ){
- if( it->first[0].hasAttribute(InstConstantAttribute()) ){
- if( !it->first[1].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(it->first[0]) ){
+ if( !quantifiers::TermDb::hasInstConstAttr(it->first[1]) ){
d_phase_reqs_equality_term[ it->first[0] ] = it->first[1];
d_phase_reqs_equality[ it->first[0] ] = it->second;
Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl;
}
- }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){
+ }else if( quantifiers::TermDb::hasInstConstAttr(it->first[1]) ){
d_phase_reqs_equality_term[ it->first[1] ] = it->first[0];
d_phase_reqs_equality[ it->first[1] ] = it->second;
Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl;
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 6a5726cc7..86c7bc3a0 100644
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
@@ -28,6 +28,18 @@ namespace CVC4 {
namespace theory {
+class QuantArith
+{
+public:
+ static bool getMonomial( Node n, std::map< Node, Node >& msum );
+ static bool getMonomialSum( Node n, std::map< Node, Node >& msum );
+ static bool getMonomialSumLit( Node lit, std::map< Node, Node >& msum );
+ static bool isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k );
+ static Node negate( Node t );
+ static Node offset( Node t, int i );
+};
+
+
class QuantRelevance
{
private:
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index 5bdce5fac..909c9c388 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -32,6 +32,10 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
Trace("quant-attr") << "Set conjecture " << n << std::endl;
ConjectureAttribute ca;
n.setAttribute( ca, true );
+ }else if( attr=="rr_priority" ){
+ //Trace("quant-attr") << "Set rr priority " << n << std::endl;
+ //RrPriorityAttribute rra;
+
}
}else{
for( size_t i=0; i<n.getNumChildren(); i++ ){
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index 878d3ac50..1aebbfcc5 100644
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
@@ -34,6 +34,10 @@ typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;
struct ConjectureAttributeId {};
typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;
+/** Attribute priority for rewrite rules */
+//struct RrPriorityAttributeId {};
+//typedef expr::Attribute< RrPriorityAttributeId, uint64_t > RrPriorityAttribute;
+
struct QuantifiersAttributes
{
/** set user attribute
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 5c71f6e6f..e27897a96 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -211,10 +211,6 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
if( in.hasAttribute(NestedQuantAttribute()) ){
setNestedQuantifiers( ret, in.getAttribute(NestedQuantAttribute()) );
}
- if( in.hasAttribute(InstConstantAttribute()) ){
- InstConstantAttribute ica;
- ret.setAttribute(ica,in.getAttribute(InstConstantAttribute()) );
- }
Trace("quantifiers-rewrite") << "*** rewrite " << in << std::endl;
Trace("quantifiers-rewrite") << " to " << std::endl;
Trace("quantifiers-rewrite") << ret << std::endl;
@@ -311,7 +307,7 @@ Node QuantifiersRewriter::computeSimpleIteLift( Node body ) {
}
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ){
- Trace("var-elim-quant") << "Compute var elimination for " << body << std::endl;
+ Trace("var-elim-quant-debug") << "Compute var elimination for " << body << std::endl;
QuantPhaseReq qpr( body );
std::vector< Node > vars;
std::vector< Node > subs;
@@ -918,7 +914,7 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption
}else if( computeOption==COMPUTE_NNF ){
return false;//TODO: compute NNF (current bad idea since arithmetic rewrites equalities)
}else if( computeOption==COMPUTE_SIMPLE_ITE_LIFT ){
- return !options::finiteModelFind();
+ return options::simpleIteLiftQuant();//!options::finiteModelFind();
}else if( computeOption==COMPUTE_PRENEX ){
return options::prenexQuant() && !options::aggressiveMiniscopeQuant();
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index 2b011552c..b079ae75c 100644..100755
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -24,175 +24,159 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+void RelevantDomain::RDomain::merge( RDomain * r ) {
+ Assert( !d_parent );
+ Assert( !r->d_parent );
+ d_parent = r;
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ r->addTerm( d_terms[i] );
+ }
+ d_terms.clear();
+}
+
+void RelevantDomain::RDomain::addTerm( Node t ) {
+ if( std::find( d_terms.begin(), d_terms.end(), t )==d_terms.end() ){
+ d_terms.push_back( t );
+ }
+}
+
+RelevantDomain::RDomain * RelevantDomain::RDomain::getParent() {
+ if( !d_parent ){
+ return this;
+ }else{
+ RDomain * p = d_parent->getParent();
+ d_parent = p;
+ return p;
+ }
+}
+
+void RelevantDomain::RDomain::removeRedundantTerms( FirstOrderModel * fm ) {
+ std::map< Node, Node > rterms;
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Node r = d_terms[i];
+ if( !TermDb::hasInstConstAttr( d_terms[i] ) ){
+ r = fm->getRepresentative( d_terms[i] );
+ }
+ if( rterms.find( r )==rterms.end() ){
+ rterms[r] = d_terms[i];
+ }
+ }
+ d_terms.clear();
+ for( std::map< Node, Node >::iterator it = rterms.begin(); it != rterms.end(); ++it ){
+ d_terms.push_back( it->second );
+ }
+}
+
+
+
RelevantDomain::RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m ) : d_qe( qe ), d_model( m ){
}
+RelevantDomain::RDomain * RelevantDomain::getRDomain( Node n, int i ) {
+ if( d_rel_doms.find( n )==d_rel_doms.end() || d_rel_doms[n].find( i )==d_rel_doms[n].end() ){
+ d_rel_doms[n][i] = new RDomain;
+ d_rn_map[d_rel_doms[n][i]] = n;
+ d_ri_map[d_rel_doms[n][i]] = i;
+ }
+ return d_rel_doms[n][i]->getParent();
+}
+
void RelevantDomain::compute(){
- Trace("rel-dom") << "compute relevant domain" << std::endl;
- d_quant_inst_domain.clear();
+ for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
+ for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ it2->second->reset();
+ }
+ }
for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
Node f = d_model->getAssertedQuantifier( i );
- d_quant_inst_domain[f].resize( f[0].getNumChildren() );
+ Node icf = d_qe->getTermDatabase()->getInstConstantBody( f );
+ Trace("rel-dom-debug") << "compute relevant domain for " << icf << std::endl;
+ computeRelevantDomain( icf, true, true );
}
- Trace("rel-dom") << "account for ground terms" << std::endl;
- //add ground terms to domain (rule 1 of complete instantiation essentially uf fragment)
- for( std::map< Node, uf::UfModelTree >::iterator it = d_model->d_uf_model_tree.begin();
- it != d_model->d_uf_model_tree.end(); ++it ){
+
+ Trace("rel-dom-debug") << "account for ground terms" << std::endl;
+ for( std::map< Node, std::vector< Node > >::iterator it = d_model->d_uf_terms.begin(); it != d_model->d_uf_terms.end(); ++it ){
Node op = it->first;
- for( size_t i=0; i<d_model->d_uf_terms[op].size(); i++ ){
- Node n = d_model->d_uf_terms[op][i];
- //add arguments to domain
- for( int j=0; j<(int)n.getNumChildren(); j++ ){
- if( d_model->d_rep_set.hasType( n[j].getType() ) ){
- Node ra = d_model->getRepresentative( n[j] );
- int raIndex = d_model->d_rep_set.getIndexFor( ra );
- if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground domain: rep set does not contain : " << ra << std::endl;
- Assert( raIndex!=-1 );
- if( std::find( d_active_domain[op][j].begin(), d_active_domain[op][j].end(), raIndex )==d_active_domain[op][j].end() ){
- d_active_domain[op][j].push_back( raIndex );
- }
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ //if it is a non-redundant term
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ RDomain * rf = getRDomain( op, j );
+ rf->addTerm( n[j] );
}
}
- //add to range
- Node r = d_model->getRepresentative( n );
- int raIndex = d_model->d_rep_set.getIndexFor( r );
- if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground range: rep set does not contain : " << r << std::endl;
- Assert( raIndex!=-1 );
- if( std::find( d_active_range[op].begin(), d_active_range[op].end(), raIndex )==d_active_range[op].end() ){
- d_active_range[op].push_back( raIndex );
- }
}
}
- Trace("rel-dom") << "do quantifiers" << std::endl;
- //find fixed point for relevant domain computation
- bool success;
- do{
- success = true;
- for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
- Node f = d_model->getAssertedQuantifier( i );
- //compute the domain of relevant instantiations (rule 3 of complete instantiation, essentially uf fragment)
- if( computeRelevantInstantiationDomain( d_qe->getTermDatabase()->getInstConstantBody( f ), Node::null(), -1, f ) ){
- success = false;
- }
- //extend the possible domain for functions (rule 2 of complete instantiation, essentially uf fragment)
- RepDomain range;
- if( extendFunctionDomains( d_qe->getTermDatabase()->getInstConstantBody( f ), range ) ){
- success = false;
- }
- }
- }while( !success );
- Trace("rel-dom") << "done compute relevant domain" << std::endl;
- /*
- //debug printing
- Trace("rel-dom") << "Exhaustive instantiate " << f << std::endl;
- if( useRelInstDomain ){
- Trace("rel-dom") << "Relevant domain : " << std::endl;
- for( size_t i=0; i<d_rel_domain.d_quant_inst_domain[f].size(); i++ ){
- Trace("rel-dom") << " " << i << " : ";
- for( size_t j=0; j<d_rel_domain.d_quant_inst_domain[f][i].size(); j++ ){
- Trace("rel-dom") << d_rel_domain.d_quant_inst_domain[f][i][j] << " ";
+ //print debug
+ for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
+ Trace("rel-dom") << "Relevant domain for " << it->first << " : " << std::endl;
+ for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ Trace("rel-dom") << " " << it2->first << " : ";
+ RDomain * r = it2->second;
+ RDomain * rp = r->getParent();
+ if( r==rp ){
+ r->removeRedundantTerms( d_model );
+ for( unsigned i=0; i<r->d_terms.size(); i++ ){
+ Trace("rel-dom") << r->d_terms[i] << " ";
+ }
+ }else{
+ Trace("rel-dom") << "Dom( " << d_rn_map[rp] << ", " << d_ri_map[rp] << " ) ";
}
Trace("rel-dom") << std::endl;
}
}
- */
+
}
-bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f ){
- bool domainChanged = false;
- if( n.getKind()==INST_CONSTANT ){
- bool domainSet = false;
- int vi = n.getAttribute(InstVarNumAttribute());
- Assert( !parent.isNull() );
- if( parent.getKind()==APPLY_UF ){
- //if the child of APPLY_UF term f( ... ), only consider the active domain of f at given argument
- Node op = parent.getOperator();
- if( d_active_domain.find( op )!=d_active_domain.end() ){
- for( size_t i=0; i<d_active_domain[op][arg].size(); i++ ){
- int d = d_active_domain[op][arg][i];
- if( std::find( d_quant_inst_domain[f][vi].begin(), d_quant_inst_domain[f][vi].end(), d )==
- d_quant_inst_domain[f][vi].end() ){
- d_quant_inst_domain[f][vi].push_back( d );
- domainChanged = true;
- }
- }
- domainSet = true;
- }
- }
- if( !domainSet ){
- //otherwise, we must consider the entire domain
- TypeNode tn = n.getType();
- if( d_quant_inst_domain_complete[f].find( vi )==d_quant_inst_domain_complete[f].end() ){
- if( d_model->d_rep_set.hasType( tn ) ){
- //it is the complete domain
- d_quant_inst_domain[f][vi].clear();
- for( size_t i=0; i<d_model->d_rep_set.d_type_reps[tn].size(); i++ ){
- d_quant_inst_domain[f][vi].push_back( i );
- }
- domainChanged = true;
+void RelevantDomain::computeRelevantDomain( Node n, bool hasPol, bool pol ) {
+
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n.getKind()==APPLY_UF ){
+ RDomain * rf = getRDomain( n.getOperator(), i );
+ if( n[i].getKind()==INST_CONSTANT ){
+ Node q = d_qe->getTermDatabase()->getInstConstAttr( n[i] );
+ //merge the RDomains
+ unsigned id = n[i].getAttribute(InstVarNumAttribute());
+ Trace("rel-dom-debug") << n[i] << " is variable # " << id << " for " << q;
+ Trace("rel-dom-debug") << " with body : " << d_qe->getTermDatabase()->getInstConstantBody( q ) << std::endl;
+ RDomain * rq = getRDomain( q, id );
+ if( rf!=rq ){
+ rq->merge( rf );
}
- d_quant_inst_domain_complete[f][vi] = true;
+ }else{
+ //term to add
+ rf->addTerm( n[i] );
}
}
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( computeRelevantInstantiationDomain( n[i], n, i, f ) ){
- domainChanged = true;
- }
+
+ //TODO
+ if( n[i].getKind()!=FORALL ){
+ bool newHasPol = hasPol;
+ bool newPol = pol;
+ computeRelevantDomain( n[i], newHasPol, newPol );
}
}
- return domainChanged;
}
-bool RelevantDomain::extendFunctionDomains( Node n, RepDomain& range ){
- if( n.getKind()==INST_CONSTANT ){
- Node f = n.getAttribute(InstConstantAttribute());
- int var = n.getAttribute(InstVarNumAttribute());
- range.insert( range.begin(), d_quant_inst_domain[f][var].begin(), d_quant_inst_domain[f][var].end() );
- return false;
+Node RelevantDomain::getRelevantTerm( Node f, int i, Node r ) {
+ RDomain * rf = getRDomain( f, i );
+ Trace("rel-dom-debug") << "Get relevant domain " << rf << " " << r << std::endl;
+ if( !d_qe->getEqualityQuery()->getEngine()->hasTerm( r ) || rf->hasTerm( r ) ){
+ return r;
}else{
- Node op;
- if( n.getKind()==APPLY_UF ){
- op = n.getOperator();
- }
- bool domainChanged = false;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- RepDomain childRange;
- if( extendFunctionDomains( n[i], childRange ) ){
- domainChanged = true;
- }
- if( n.getKind()==APPLY_UF ){
- if( d_active_domain.find( op )!=d_active_domain.end() ){
- for( int j=0; j<(int)childRange.size(); j++ ){
- int v = childRange[j];
- if( std::find( d_active_domain[op][i].begin(), d_active_domain[op][i].end(), v )==d_active_domain[op][i].end() ){
- d_active_domain[op][i].push_back( v );
- domainChanged = true;
- }
- }
- }else{
- //do this?
- }
- }
- }
- //get the range
- if( n.hasAttribute(InstConstantAttribute()) ){
- if( n.getKind()==APPLY_UF && d_active_range.find( op )!=d_active_range.end() ){
- range.insert( range.end(), d_active_range[op].begin(), d_active_range[op].end() );
- }else{
- //infinite range?
- }
- }else{
- Node r = d_model->getRepresentative( n );
- int index = d_model->d_rep_set.getIndexFor( r );
- if( index==-1 ){
- //we consider all ground terms in bodies of quantifiers to be the first ground representative
- range.push_back( 0 );
- }else{
- range.push_back( index );
+ Node rr = d_model->getRepresentative( r );
+ eq::EqClassIterator eqc( rr, d_qe->getEqualityQuery()->getEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( rf->hasTerm( en ) ){
+ return en;
}
+ ++eqc;
}
- return domainChanged;
+ //otherwise, may be equal to some non-ground term
+
+ return r;
}
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h
index 6fc035e8a..c4345f828 100644..100755
--- a/src/theory/quantifiers/relevant_domain.h
+++ b/src/theory/quantifiers/relevant_domain.h
@@ -26,25 +26,33 @@ namespace quantifiers {
class RelevantDomain
{
private:
+ class RDomain
+ {
+ public:
+ RDomain() : d_parent( NULL ) {}
+ void reset() { d_parent = NULL; d_terms.clear(); }
+ RDomain * d_parent;
+ std::vector< Node > d_terms;
+ void merge( RDomain * r );
+ void addTerm( Node t );
+ RDomain * getParent();
+ void removeRedundantTerms( FirstOrderModel * fm );
+ bool hasTerm( Node n ) { return std::find( d_terms.begin(), d_terms.end(), n )!=d_terms.end(); }
+ };
+ std::map< Node, std::map< int, RDomain * > > d_rel_doms;
+ std::map< RDomain *, Node > d_rn_map;
+ std::map< RDomain *, int > d_ri_map;
+ RDomain * getRDomain( Node n, int i );
QuantifiersEngine* d_qe;
FirstOrderModel* d_model;
-
- //the domain of the arguments for each operator
- std::map< Node, std::map< int, RepDomain > > d_active_domain;
- //the range for each operator
- std::map< Node, RepDomain > d_active_range;
- //for computing relevant instantiation domain, return true if changed
- bool computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f );
- //for computing extended
- bool extendFunctionDomains( Node n, RepDomain& range );
+ void computeRelevantDomain( Node n, bool hasPol, bool pol );
public:
RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m );
virtual ~RelevantDomain(){}
//compute the relevant domain
void compute();
- //relevant instantiation domain for each quantifier
- std::map< Node, std::vector< RepDomain > > d_quant_inst_domain;
- std::map< Node, std::map< int, bool > > d_quant_inst_domain_complete;
+
+ Node getRelevantTerm( Node f, int i, Node r );
};/* class RelevantDomain */
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
new file mode 100755
index 000000000..107a99014
--- /dev/null
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -0,0 +1,184 @@
+/********************* */
+/*! \file bounded_integers.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Rewrite engine module
+ **
+ ** This class manages rewrite rules for quantifiers
+ **/
+
+#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/inst_match_generator.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+struct PrioritySort {
+ std::vector< double > d_priority;
+ bool operator() (int i,int j) {
+ return d_priority[i] < d_priority[j];
+ }
+};
+
+
+RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) {
+
+}
+
+double RewriteEngine::getPriority( Node f ) {
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Node rrr = rr[2];
+ Trace("rr-priority") << "Get priority : " << rrr << " " << rrr.getKind() << std::endl;
+ bool deterministic = rrr[1].getKind()!=OR;
+ if( rrr.getKind()==RR_REWRITE ){
+ return deterministic ? 0.0 : 3.0;
+ }else if( rrr.getKind()==RR_DEDUCTION ){
+ return deterministic ? 1.0 : 4.0;
+ }else if( rrr.getKind()==RR_REDUCTION ){
+ return deterministic ? 2.0 : 5.0;
+ }else{
+ return 6.0;
+ }
+}
+
+void RewriteEngine::check( Theory::Effort e ) {
+ if( e==Theory::EFFORT_LAST_CALL ){
+ if( !d_quantEngine->getModel()->isModelSet() ){
+ d_quantEngine->getTheoryEngine()->getModelBuilder()->buildModel( d_quantEngine->getModel(), true );
+ }
+ if( d_true.isNull() ){
+ d_true = NodeManager::currentNM()->mkConst( true );
+ }
+ std::vector< Node > priority_order;
+ PrioritySort ps;
+ std::vector< int > indicies;
+ for( int i=0; i<(int)d_rr_quant.size(); i++ ){
+ ps.d_priority.push_back( getPriority( d_rr_quant[i] ) );
+ indicies.push_back( i );
+ }
+ std::sort( indicies.begin(), indicies.end(), ps );
+ for( unsigned i=0; i<indicies.size(); i++ ){
+ priority_order.push_back( d_rr_quant[indicies[i]] );
+ }
+
+ //apply rewrite rules
+ int addedLemmas = 0;
+ //per priority level
+ int index = 0;
+ bool success = true;
+ while( success && index<(int)priority_order.size() ) {
+ addedLemmas += checkRewriteRule( priority_order[index] );
+ index++;
+ if( index<(int)priority_order.size() ){
+ success = addedLemmas==0 || getPriority( priority_order[index] )==getPriority( priority_order[index-1] );
+ }
+ }
+
+ Trace("inst-engine") << "Rewrite engine added " << addedLemmas << " lemmas." << std::endl;
+ if (addedLemmas==0) {
+ }else{
+ //otherwise, the search will continue
+ d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
+ }
+ }
+}
+
+int RewriteEngine::checkRewriteRule( Node f ) {
+ Trace("rewrite-engine-inst") << "Check " << f << ", priority = " << getPriority( f ) << "..." << std::endl;
+ int addedLemmas = 0;
+ //reset triggers
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ if( d_rr_triggers.find(f)==d_rr_triggers.end() ){
+ std::vector< inst::Trigger * > triggers;
+ if( f.getNumChildren()==3 ){
+ for(unsigned i=0; i<f[2].getNumChildren(); i++ ){
+ Node pat = f[2][i];
+ std::vector< Node > nodes;
+ Trace("rewrite-engine-trigger") << "Trigger is : ";
+ for( int j=0; j<(int)pat.getNumChildren(); j++ ){
+ Node p = d_quantEngine->getTermDatabase()->getInstConstantNode( pat[j], f );
+ nodes.push_back( p );
+ Trace("rewrite-engine-trigger") << p << " " << p.getKind() << " ";
+ }
+ Trace("rewrite-engine-trigger") << std::endl;
+ Assert( inst::Trigger::isUsableTrigger( nodes, f ) );
+ inst::Trigger * tr = inst::Trigger::mkTrigger( d_quantEngine, f, nodes, 0, true, inst::Trigger::TR_MAKE_NEW, false );
+ tr->getGenerator()->setActiveAdd(false);
+ triggers.push_back( tr );
+ }
+ }
+ d_rr_triggers[f].insert( d_rr_triggers[f].end(), triggers.begin(), triggers.end() );
+ }
+ for( unsigned i=0; i<d_rr_triggers[f].size(); i++ ){
+ Trace("rewrite-engine-inst") << "Try trigger " << *d_rr_triggers[f][i] << std::endl;
+ d_rr_triggers[f][i]->resetInstantiationRound();
+ d_rr_triggers[f][i]->reset( Node::null() );
+ bool success;
+ do
+ {
+ InstMatch m;
+ success = d_rr_triggers[f][i]->getNextMatch( f, m );
+ if( success ){
+ //see if instantiation is true in the model
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Node rrg = rr[1];
+ std::vector< Node > vars;
+ std::vector< Node > terms;
+ d_quantEngine->computeTermVector( f, m, vars, terms );
+ Trace("rewrite-engine-inst-debug") << "Instantiation : " << m << std::endl;
+ Node inst = d_rr_guard[f];
+ inst = inst.substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
+ Trace("rewrite-engine-inst-debug") << "Try instantiation, guard : " << inst << std::endl;
+ FirstOrderModel * fm = d_quantEngine->getModel();
+ Node v = fm->getValue( inst );
+ Trace("rewrite-engine-inst-debug") << "Evaluated to " << v << std::endl;
+ if( v==d_true ){
+ Trace("rewrite-engine-inst-debug") << "Add instantiation : " << m << std::endl;
+ if( d_quantEngine->addInstantiation( f, m ) ){
+ addedLemmas++;
+ Trace("rewrite-engine-inst-debug") << "success" << std::endl;
+ //set the no-match attribute (the term is rewritten and can be ignored)
+ //Trace("rewrite-engine-inst-debug") << "We matched on : " << m.d_matched << std::endl;
+ //if( !m.d_matched.isNull() ){
+ // NoMatchAttribute nma;
+ // m.d_matched.setAttribute(nma,true);
+ //}
+ }else{
+ Trace("rewrite-engine-inst-debug") << "failure." << std::endl;
+ }
+ }
+ }
+ }while(success);
+ }
+ Trace("rewrite-engine-inst") << "Rule " << f << " generated " << addedLemmas << " lemmas." << std::endl;
+ return addedLemmas;
+}
+
+void RewriteEngine::registerQuantifier( Node f ) {
+ if( f.hasAttribute(QRewriteRuleAttribute()) ){
+ Trace("rewrite-engine") << "Register quantifier " << f << std::endl;
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Trace("rewrite-engine") << " rewrite rule is : " << rr << std::endl;
+ d_rr_quant.push_back( f );
+ d_rr_guard[f] = rr[1];
+ Trace("rewrite-engine") << " guard is : " << d_rr_guard[f] << std::endl;
+ }
+}
+
+void RewriteEngine::assertNode( Node n ) {
+
+}
+
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
new file mode 100755
index 000000000..2d9d751c2
--- /dev/null
+++ b/src/theory/quantifiers/rewrite_engine.h
@@ -0,0 +1,54 @@
+/********************* */
+/*! \file bounded_integers.h
+** \verbatim
+** Original author: Andrew Reynolds
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2013 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief This class manages integer bounds for quantifiers
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__REWRITE_ENGINE_H
+#define __CVC4__REWRITE_ENGINE_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/trigger.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class RewriteEngine : public QuantifiersModule
+{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+ std::vector< Node > d_rr_quant;
+ std::map< Node, Node > d_rr_guard;
+ Node d_true;
+ /** explicitly provided patterns */
+ std::map< Node, std::vector< inst::Trigger* > > d_rr_triggers;
+ double getPriority( Node f );
+private:
+ int checkRewriteRule( Node f );
+public:
+ RewriteEngine( context::Context* c, QuantifiersEngine* qe );
+
+ void check( Theory::Effort e );
+ void registerQuantifier( Node f );
+ void assertNode( Node n );
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp
new file mode 100755
index 000000000..507a50838
--- /dev/null
+++ b/src/theory/quantifiers/symmetry_breaking.cpp
@@ -0,0 +1,314 @@
+/********************* */
+/*! \file symmetry_breaking.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief symmetry breaking module
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/symmetry_breaking.h"
+#include "theory/rewriter.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+#include "util/sort_inference.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace std;
+
+namespace CVC4 {
+
+
+SubsortSymmetryBreaker::SubsortSymmetryBreaker(QuantifiersEngine* qe, context::Context* c) :
+d_qe(qe), d_conflict(c,false) {
+ d_true = NodeManager::currentNM()->mkConst( true );
+}
+
+eq::EqualityEngine * SubsortSymmetryBreaker::getEqualityEngine() {
+ return ((uf::TheoryUF*)d_qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
+}
+
+bool SubsortSymmetryBreaker::areEqual( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
+}
+
+bool SubsortSymmetryBreaker::areDisequal( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+}
+
+
+Node SubsortSymmetryBreaker::getRepresentative( Node n ) {
+ return getEqualityEngine()->getRepresentative( n );
+}
+
+uf::StrongSolverTheoryUF * SubsortSymmetryBreaker::getStrongSolver() {
+ return ((uf::TheoryUF*)d_qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getStrongSolver();
+}
+
+SubsortSymmetryBreaker::TypeInfo::TypeInfo( context::Context * c ) :
+d_max_dom_const_sort(c,0), d_has_dom_const_sort(c,false) {
+}
+
+SubsortSymmetryBreaker::SubSortInfo::SubSortInfo( context::Context * c ) :
+d_dom_constants( c ), d_first_active( c, 0 ){
+ d_dc_nodes = 0;
+}
+
+unsigned SubsortSymmetryBreaker::SubSortInfo::getNumDomainConstants() {
+ if( d_nodes.empty() ){
+ return 0;
+ }else{
+ return 1 + d_dom_constants.size();
+ }
+}
+
+Node SubsortSymmetryBreaker::SubSortInfo::getDomainConstant( int i ) {
+ if( i==0 ){
+ return d_nodes[0];
+ }else{
+ Assert( i<=(int)d_dom_constants.size() );
+ return d_dom_constants[i-1];
+ }
+}
+
+Node SubsortSymmetryBreaker::SubSortInfo::getFirstActive(eq::EqualityEngine * ee) {
+ if( d_first_active.get()<(int)d_nodes.size() ){
+ Node fa = d_nodes[d_first_active.get()];
+ return ee->hasTerm( fa ) ? fa : Node::null();
+ }else{
+ return Node::null();
+ }
+}
+
+SubsortSymmetryBreaker::TypeInfo * SubsortSymmetryBreaker::getTypeInfo( TypeNode tn ) {
+ if( d_t_info.find( tn )==d_t_info.end() ){
+ d_t_info[tn] = new TypeInfo( d_qe->getSatContext() );
+ }
+ return d_t_info[tn];
+}
+
+SubsortSymmetryBreaker::SubSortInfo * SubsortSymmetryBreaker::getSubSortInfo( TypeNode tn, int sid ) {
+ if( d_type_info.find( sid )==d_type_info.end() ){
+ d_type_info[sid] = new SubSortInfo( d_qe->getSatContext() );
+ d_sub_sorts[tn].push_back( sid );
+ d_sid_to_type[sid] = tn;
+ }
+ return d_type_info[sid];
+}
+
+void SubsortSymmetryBreaker::newEqClass( Node n ) {
+ Trace("sym-break-temp") << "New eq class " << n << std::endl;
+ if( !d_conflict ){
+ TypeNode tn = n.getType();
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ if( si->isWellSorted( n ) ){
+ int sid = si->getSortId( n );
+ Trace("sym-break-debug") << "SSB: New eq class " << n << " : " << n.getType() << " : " << sid << std::endl;
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ if( std::find( ti->d_nodes.begin(), ti->d_nodes.end(), n )==ti->d_nodes.end() ){
+ if( ti->d_nodes.empty() ){
+ //for first subsort, we add unit equality
+ if( d_sub_sorts[tn][0]!=sid ){
+ Trace("sym-break-temp") << "Do sym break unit with " << d_type_info[d_sub_sorts[tn][0]]->getBaseConstant() << std::endl;
+ //add unit symmetry breaking lemma
+ Node eq = n.eqNode( d_type_info[d_sub_sorts[tn][0]]->getBaseConstant() );
+ eq = Rewriter::rewrite( eq );
+ d_unit_lemmas.push_back( eq );
+ Trace("sym-break-lemma") << "*** SymBreak : Unit lemma (" << sid << "==" << d_sub_sorts[tn][0] << ") : " << eq << std::endl;
+ d_pending_lemmas.push_back( eq );
+ }
+ Trace("sym-break-dc") << "* Set first domain constant : " << n << " for " << tn << " : " << sid << std::endl;
+ ti->d_dc_nodes++;
+ }
+ ti->d_node_to_id[n] = ti->d_nodes.size();
+ ti->d_nodes.push_back( n );
+ }
+ TypeInfo * tti = getTypeInfo( tn );
+ if( !tti->d_has_dom_const_sort.get() ){
+ tti->d_has_dom_const_sort.set( true );
+ tti->d_max_dom_const_sort.set( sid );
+ }
+ }
+ }
+ Trace("sym-break-temp") << "Done new eq class" << std::endl;
+}
+
+
+
+void SubsortSymmetryBreaker::merge( Node a, Node b ) {
+ if( Trace.isOn("sym-break-debug") ){
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ int as = si->getSortId( a );
+ int bs = si->getSortId( b );
+ Trace("sym-break-debug") << "SSB: New merge " << a.getType() << " :: " << a << " : " << as;
+ Trace("sym-break-debug") << " == " << b << " : " << bs << std::endl;
+ }
+}
+
+void SubsortSymmetryBreaker::assertDisequal( Node a, Node b ) {
+ if( Trace.isOn("sym-break-debug") ){
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ int as = si->getSortId( a );
+ int bs = si->getSortId( b );
+ Trace("sym-break-debug") << "SSB: New assert disequal " << a.getType() << " :: " << a << " : " << as;
+ Trace("sym-break-debug") << " != " << b << " : " << bs << std::endl;
+ }
+}
+
+void SubsortSymmetryBreaker::processFirstActive( TypeNode tn, int sid, int curr_card ){
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ if( (int)ti->getNumDomainConstants()<curr_card ){
+ //static int checkCount = 0;
+ //checkCount++;
+ //if( checkCount%1000==0 ){
+ // std::cout << "Check count = " << checkCount << std::endl;
+ //}
+
+ Trace("sym-break-dc-debug") << "Check for domain constants " << tn << " : " << sid << ", curr_card = " << curr_card << ", ";
+ Trace("sym-break-dc-debug") << "#domain constants = " << ti->getNumDomainConstants() << std::endl;
+ Node fa = ti->getFirstActive(getEqualityEngine());
+ bool invalid = true;
+ while( invalid && !fa.isNull() && (int)ti->getNumDomainConstants()<curr_card ){
+ invalid = false;
+ unsigned deq = 0;
+ for( unsigned i=0; i<ti->getNumDomainConstants(); i++ ){
+ Node dc = ti->getDomainConstant( i );
+ if( areEqual( fa, dc ) ){
+ invalid = true;
+ break;
+ }else if( areDisequal( fa, dc ) ){
+ deq++;
+ }
+ }
+ if( deq==ti->getNumDomainConstants() ){
+ Trace("sym-break-dc") << "* Can infer domain constant #" << ti->getNumDomainConstants()+1;
+ Trace("sym-break-dc") << " : " << fa << " for " << tn << " : " << sid << std::endl;
+ //add to domain constants
+ ti->d_dom_constants.push_back( fa );
+ if( ti->d_node_to_id[fa]>ti->d_dc_nodes ){
+ Trace("sym-break-dc-debug") << "Swap nodes... " << ti->d_dc_nodes << " " << ti->d_node_to_id[fa] << " " << ti->d_nodes.size() << std::endl;
+ //swap
+ Node on = ti->d_nodes[ti->d_dc_nodes];
+ int id = ti->d_node_to_id[fa];
+
+ ti->d_nodes[ti->d_dc_nodes] = fa;
+ ti->d_nodes[id] = on;
+ ti->d_node_to_id[fa] = ti->d_dc_nodes;
+ ti->d_node_to_id[on] = id;
+ }
+ ti->d_dc_nodes++;
+ Trace("sym-break-dc-debug") << "Get max type info..." << std::endl;
+ TypeInfo * tti = getTypeInfo( tn );
+ Assert( tti->d_has_dom_const_sort.get() );
+ int msid = tti->d_max_dom_const_sort.get();
+ SubSortInfo * max_ti = getSubSortInfo( d_sid_to_type[msid], msid );
+ Trace("sym-break-dc-debug") << "Swap nodes..." << std::endl;
+ //now, check if we can apply symmetry breaking to another sort
+ if( ti->getNumDomainConstants()>max_ti->getNumDomainConstants() ){
+ Trace("sym-break-dc") << "Max domain constant subsort for " << tn << " becomes " << sid << std::endl;
+ tti->d_max_dom_const_sort.set( sid );
+ }else if( ti!=max_ti ){
+ //construct symmetry breaking lemma
+ //current domain constant must be disequal from all current ones
+ Trace("sym-break-dc") << "Get domain constant " << ti->getNumDomainConstants()-1;
+ Trace("sym-break-dc") << " from max_ti, " << max_ti->getNumDomainConstants() << std::endl;
+ //apply a symmetry breaking lemma
+ Node m = max_ti->getDomainConstant(ti->getNumDomainConstants()-1);
+ //if fa and m are disequal from all previous domain constants in the other sort
+ std::vector< Node > cc;
+ for( unsigned r=0; r<2; r++ ){
+ Node n = ((r==0)==(msid>sid)) ? fa : m;
+ Node on = ((r==0)==(msid>sid)) ? m : fa;
+ SubSortInfo * t = ((r==0)==(msid>sid)) ? max_ti : ti;
+ for( unsigned i=0; i<t->d_node_to_id[on]; i++ ){
+ cc.push_back( n.eqNode( t->d_nodes[i] ) );
+ }
+ }
+ //then, we can assume fa = m
+ cc.push_back( fa.eqNode( m ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, cc );
+ lem = Rewriter::rewrite( lem );
+ if( std::find( d_lemmas.begin(), d_lemmas.end(), lem )==d_lemmas.end() ){
+ d_lemmas.push_back( lem );
+ Trace("sym-break-lemma") << "*** Symmetry break lemma for " << tn << " (" << sid << "==" << tti->d_max_dom_const_sort.get() << ") : ";
+ Trace("sym-break-lemma") << lem << std::endl;
+ d_pending_lemmas.push_back( lem );
+ }
+ }
+ invalid = true;
+ }
+ if( invalid ){
+ ti->d_first_active.set( ti->d_first_active + 1 );
+ fa = ti->getFirstActive(getEqualityEngine());
+ }
+ }
+ }
+}
+
+void SubsortSymmetryBreaker::printDebugSubSortInfo( const char * c, TypeNode tn, int sid ) {
+ Trace(c) << "SubSortInfo( " << tn << ", " << sid << " ) = " << std::endl;
+ Trace(c) << " Domain constants : ";
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ for( NodeList::const_iterator it = ti->d_dom_constants.begin(); it != ti->d_dom_constants.end(); ++it ){
+ Node dc = *it;
+ Trace(c) << dc << " ";
+ }
+ Trace(c) << std::endl;
+ Trace(c) << " First active node : " << ti->getFirstActive(getEqualityEngine()) << std::endl;
+}
+
+bool SubsortSymmetryBreaker::check( Theory::Effort level ) {
+
+ Trace("sym-break-debug") << "SymBreak : check " << level << std::endl;
+ /*
+ while( d_fact_index.get()<d_fact_list.size() ){
+ Node f = d_fact_list[d_fact_index.get()];
+ d_fact_index.set( d_fact_index.get() + 1 );
+ if( f.getKind()==EQUAL ){
+ merge( f[0], f[1] );
+ }else if( f.getKind()==NOT && f[0].getKind()==EQUAL ){
+ assertDisequal( f[0][0], f[0][1] );
+ }else{
+ newEqClass( f );
+ }
+ }
+ */
+ Trace("sym-break-debug") << "SymBreak : update first actives" << std::endl;
+ for( std::map< TypeNode, std::vector< int > >::iterator it = d_sub_sorts.begin(); it != d_sub_sorts.end(); ++it ){
+ int card = getStrongSolver()->getCardinality( it->first );
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ //check if the first active is disequal from all domain constants
+ processFirstActive( it->first, it->second[i], card );
+ }
+ }
+
+
+ Trace("sym-break-debug") << "SymBreak : finished check, now flush lemmas... (#lemmas = " << d_pending_lemmas.size() << ")" << std::endl;
+ //flush pending lemmas
+ if( !d_pending_lemmas.empty() ){
+ for( unsigned i=0; i<d_pending_lemmas.size(); i++ ){
+ getStrongSolver()->getOutputChannel().lemma( d_pending_lemmas[i] );
+ ++( getStrongSolver()->d_statistics.d_sym_break_lemmas );
+ }
+ d_pending_lemmas.clear();
+ return true;
+ }else{
+ return false;
+ }
+}
+
+
+
+}
+
diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h
new file mode 100755
index 000000000..05461d378
--- /dev/null
+++ b/src/theory/quantifiers/symmetry_breaking.h
@@ -0,0 +1,118 @@
+/********************* */
+/*! \file symmetry_breaking.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Pre-process step for first-order reasoning
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__QUANT_SYMMETRY_BREAKING_H
+#define __CVC4__QUANT_SYMMETRY_BREAKING_H
+
+#include "theory/theory.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+#include "util/sort_inference.h"
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace uf {
+ class StrongSolverTheoryUF;
+}
+
+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;
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( Node n1, Node n2 );
+ bool areEqual( Node n1, Node n2 );
+ Node getRepresentative( Node n );
+ uf::StrongSolverTheoryUF * getStrongSolver();
+ std::vector< Node > d_unit_lemmas;
+ Node d_true;
+ context::CDO< bool > d_conflict;
+public:
+ SubsortSymmetryBreaker( QuantifiersEngine* qe, context::Context* c );
+ ~SubsortSymmetryBreaker(){}
+
+private:
+ class TypeInfo {
+ public:
+ TypeInfo( context::Context* c );
+ context::CDO< int > d_max_dom_const_sort;
+ context::CDO< bool > d_has_dom_const_sort;
+ };
+ class SubSortInfo {
+ public:
+ SubSortInfo( context::Context* c );
+ //list of all nodes from this (sub)type
+ std::vector< Node > d_nodes;
+ //the current domain constants for this (sub)type
+ NodeList d_dom_constants;
+ //# nodes in d_nodes that have been domain constants, size of this distinct # of domain constants seen
+ unsigned d_dc_nodes;
+ //the node we are currently watching to become a domain constant
+ context::CDO< int > d_first_active;
+ //node to id
+ std::map< Node, unsigned > d_node_to_id;
+ Node getBaseConstant() { return d_nodes.empty() ? Node::null() : d_nodes[0]; }
+ bool hasDomainConstant( Node n );
+ unsigned getNumDomainConstants();
+ Node getDomainConstant( int i );
+ Node getFirstActive(eq::EqualityEngine * ee);
+ };
+ std::map< TypeNode, std::vector< int > > d_sub_sorts;
+ std::map< int, TypeNode > d_sid_to_type;
+ std::map< TypeNode, TypeInfo * > d_t_info;
+ std::map< int, SubSortInfo * > d_type_info;
+
+ TypeInfo * getTypeInfo( TypeNode tn );
+ SubSortInfo * getSubSortInfo( TypeNode tn, int sid );
+
+ void processFirstActive( TypeNode tn, int sid, int curr_card );
+private:
+ //void printDebugNodeInfo( const char * c, Node n );
+ void printDebugSubSortInfo( const char * c, TypeNode tn, int sid );
+ /** fact list */
+ std::vector< Node > d_pending_lemmas;
+ std::vector< Node > d_lemmas;
+public:
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** check */
+ bool check( Theory::Effort level );
+};
+
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 3153a3c64..e18a4e0dc 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -74,7 +74,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
//if this is an atomic trigger, consider adding it
//Call the children?
if( inst::Trigger::isAtomicTrigger( n ) ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( !TermDb::hasInstConstAttr(n) ){
Trace("term-db") << "register term in db " << n << std::endl;
//std::cout << "register trigger term " << n << std::endl;
Node op = n.getOperator();
@@ -117,7 +117,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
}else{
- if( options::efficientEMatching() && !n.hasAttribute(InstConstantAttribute())){
+ if( options::efficientEMatching() && !TermDb::hasInstConstAttr(n)){
//Efficient e-matching must be notified
//The term in triggers are not important here
Debug("term-db") << "New in this branch term " << n << std::endl;
@@ -167,7 +167,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
while( !eqc.isFinished() ){
Node en = (*eqc);
computeModelBasisArgAttribute( en );
- if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
+ if( en.getKind()==APPLY_UF && !TermDb::hasInstConstAttr(en) ){
if( !en.getAttribute(NoMatchAttribute()) ){
Node op = en.getOperator();
if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
@@ -194,14 +194,20 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
Node mbt;
- if( options::fmfFreshDistConst() || d_type_map[ tn ].empty() ){
- std::stringstream ss;
- ss << Expr::setlanguage(options::outputLanguage());
- ss << "e_" << tn;
- mbt = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "is a model basis term" );
- Trace("mkVar") << "ModelBasis:: Make variable " << mbt << " : " << tn << std::endl;
+ if( tn.isInteger() || tn.isReal() ){
+ mbt = NodeManager::currentNM()->mkConst( Rational( 0 ) );
+ }else if( !tn.isSort() ){
+ mbt = tn.mkGroundTerm();
}else{
- mbt = d_type_map[ tn ][ 0 ];
+ if( options::fmfFreshDistConst() || d_type_map[ tn ].empty() ){
+ std::stringstream ss;
+ ss << Expr::setlanguage(options::outputLanguage());
+ ss << "e_" << tn;
+ mbt = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "is a model basis term" );
+ Trace("mkVar") << "ModelBasis:: Make variable " << mbt << " : " << tn << std::endl;
+ }else{
+ mbt = d_type_map[ tn ][ 0 ];
+ }
}
ModelBasisAttribute mba;
mbt.setAttribute(mba,true);
@@ -254,8 +260,7 @@ void TermDb::computeModelBasisArgAttribute( Node n ){
//determine if it has model basis attribute
for( int j=0; j<(int)n.getNumChildren(); j++ ){
if( n[j].getAttribute(ModelBasisAttribute()) ){
- val = 1;
- break;
+ val++;
}
}
ModelBasisArgAttribute mbaa;
@@ -276,33 +281,75 @@ void TermDb::makeInstantiationConstantsFor( Node f ){
//set the var number attribute
InstVarNumAttribute ivna;
ic.setAttribute(ivna,i);
+ InstConstantAttribute ica;
+ ic.setAttribute(ica,f);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ ic.setAttribute(nma,true);
}
}
}
-void TermDb::setInstantiationConstantAttr( Node n, Node f ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
- bool setAttr = false;
- if( n.getKind()==INST_CONSTANT ){
- setAttr = true;
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationConstantAttr( n[i], f );
- if( n[i].hasAttribute(InstConstantAttribute()) ){
- setAttr = true;
- }
+
+Node TermDb::getInstConstAttr( Node n ) {
+ if (!n.hasAttribute(InstConstantAttribute()) ){
+ Node f;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ f = getInstConstAttr(n[i]);
+ if( !f.isNull() ){
+ break;
}
}
- if( setAttr ){
- InstConstantAttribute ica;
- n.setAttribute(ica,f);
+ InstConstantAttribute ica;
+ n.setAttribute(ica,f);
+ if( !f.isNull() ){
//also set the no-match attribute
NoMatchAttribute nma;
n.setAttribute(nma,true);
}
}
+ return n.getAttribute(InstConstantAttribute());
+}
+
+bool TermDb::hasInstConstAttr( Node n ) {
+ return !getInstConstAttr(n).isNull();
+}
+
+bool TermDb::hasBoundVarAttr( Node n ) {
+ if( !n.getAttribute(HasBoundVarComputedAttribute()) ){
+ bool hasBv = false;
+ if( n.getKind()==BOUND_VARIABLE ){
+ hasBv = true;
+ }else{
+ for (unsigned i=0; i<n.getNumChildren(); i++) {
+ if( hasBoundVarAttr(n[i]) ){
+ hasBv = true;
+ break;
+ }
+ }
+ }
+ HasBoundVarAttribute hbva;
+ n.setAttribute(hbva, hasBv);
+ HasBoundVarComputedAttribute hbvca;
+ n.setAttribute(hbvca, true);
+ Trace("bva") << n << " has bva : " << n.getAttribute(HasBoundVarAttribute()) << std::endl;
+ }
+ return n.getAttribute(HasBoundVarAttribute());
+}
+
+void TermDb::getBoundVars( Node n, std::vector< Node >& bvs) {
+ if (n.getKind()==BOUND_VARIABLE ){
+ if ( std::find( bvs.begin(), bvs.end(), n)==bvs.end() ){
+ bvs.push_back( n );
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ getBoundVars(n[i], bvs);
+ }
+ }
}
+
/** get the i^th instantiation constant of f */
Node TermDb::getInstantiationConstant( Node f, int i ) const {
std::map< Node, std::vector< Node > >::const_iterator it = d_inst_constants.find( f );
@@ -348,7 +395,6 @@ Node TermDb::getCounterexampleLiteral( Node f ){
//otherwise, ensure literal
Node ceLit = d_quantEngine->getValuation().ensureLiteral( ceBody.notNode() );
d_ce_lit[ f ] = ceLit;
- setInstantiationConstantAttr( ceLit, f );
}
return d_ce_lit[ f ];
}
@@ -362,7 +408,6 @@ Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector<Node> & var
Node n2 = n.substitute( vars.begin(), vars.end(),
inst_constants.begin(),
inst_constants.end() );
- setInstantiationConstantAttr( n2, f );
return n2;
}
@@ -390,16 +435,19 @@ Node TermDb::getSkolemizedBody( Node f ){
Node TermDb::getFreeVariableForInstConstant( Node n ){
TypeNode tn = n.getType();
if( d_free_vars.find( tn )==d_free_vars.end() ){
- //if integer or real, make zero
- if( tn.isInteger() || tn.isReal() ){
- Rational z(0);
- d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
- }else{
- if( d_type_map[ tn ].empty() ){
- d_free_vars[tn] = NodeManager::currentNM()->mkSkolem( "freevar_$$", tn, "is a free variable created by termdb" );
- Trace("mkVar") << "FreeVar:: Make variable " << d_free_vars[tn] << " : " << tn << std::endl;
+ for( unsigned i=0; i<d_type_map[ tn ].size(); i++ ){
+ if( !quantifiers::TermDb::hasInstConstAttr(d_type_map[ tn ][ i ]) ){
+ d_free_vars[tn] = d_type_map[ tn ][ i ];
+ }
+ }
+ if( d_free_vars.find( tn )==d_free_vars.end() ){
+ //if integer or real, make zero
+ if( tn.isInteger() || tn.isReal() ){
+ Rational z(0);
+ d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
}else{
- d_free_vars[tn] = d_type_map[ tn ][ 0 ];
+ d_free_vars[tn] = NodeManager::currentNM()->mkSkolem( "freevar_$$", tn, "is a free variable created by termdb" );
+ Trace("mkVar") << "FreeVar:: Make variable " << d_free_vars[tn] << " : " << tn << std::endl;
}
}
}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index 231d0ee9e..1688479f3 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -59,6 +59,19 @@ typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute;
struct ModelBasisArgAttributeId {};
typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribute;
+struct HasBoundVarAttributeId {};
+typedef expr::Attribute<HasBoundVarAttributeId, bool> HasBoundVarAttribute;
+struct HasBoundVarComputedAttributeId {};
+typedef expr::Attribute<HasBoundVarComputedAttributeId, bool> HasBoundVarComputedAttribute;
+
+//for rewrite rules
+struct QRewriteRuleAttributeId {};
+typedef expr::Attribute<QRewriteRuleAttributeId, Node> QRewriteRuleAttribute;
+
+//for bounded integers
+struct BoundIntLitAttributeId {};
+typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute;
+
class QuantifiersEngine;
@@ -83,10 +96,15 @@ public:
};/* class TermArgTrie */
+namespace fmcheck {
+ class FullModelChecker;
+}
+
class TermDb {
friend class ::CVC4::theory::QuantifiersEngine;
friend class ::CVC4::theory::inst::Trigger;
friend class ::CVC4::theory::rrinst::Trigger;
+ friend class ::CVC4::theory::quantifiers::fmcheck::FullModelChecker;
private:
/** reference to the quantifiers engine */
QuantifiersEngine* d_quantEngine;
@@ -181,9 +199,15 @@ public:
Node convertNodeToPattern( Node n, Node f,
const std::vector<Node> & vars,
const std::vector<Node> & nvars);
- /** set instantiation constant attr */
- void setInstantiationConstantAttr( Node n, Node f );
+ static Node getInstConstAttr( Node n );
+ static bool hasInstConstAttr( Node n );
+//for bound variables
+public:
+ //does n have bound variables?
+ static bool hasBoundVarAttr( Node n );
+ //get bound variables in n
+ static void getBoundVars( Node n, std::vector< Node >& bvs);
//for skolem
private:
/** map from universal quantifiers to the list of skolem constants */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 9843cd09e..066282c2c 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -65,7 +65,7 @@ void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) {
void TheoryQuantifiers::preRegisterTerm(TNode n) {
Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
- if( n.getKind()==FORALL && !n.hasAttribute(InstConstantAttribute()) ){
+ if( n.getKind()==FORALL && !TermDb::hasInstConstAttr(n) ){
getQuantifiersEngine()->registerQuantifier( n );
}
}
@@ -149,7 +149,7 @@ Node TheoryQuantifiers::getNextDecisionRequest(){
void TheoryQuantifiers::assertUniversal( Node n ){
Assert( n.getKind()==FORALL );
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( options::recurseCbqi() || !TermDb::hasInstConstAttr(n) ){
getQuantifiersEngine()->registerQuantifier( n );
getQuantifiersEngine()->assertNode( n );
}
@@ -157,13 +157,13 @@ void TheoryQuantifiers::assertUniversal( Node n ){
void TheoryQuantifiers::assertExistential( Node n ){
Assert( n.getKind()== NOT && n[0].getKind()==FORALL );
- if( !n[0].hasAttribute(InstConstantAttribute()) ){
+ if( options::recurseCbqi() || !TermDb::hasInstConstAttr(n[0]) ){
if( d_skolemized.find( n )==d_skolemized.end() ){
Node body = getQuantifiersEngine()->getTermDatabase()->getSkolemizedBody( n[0] );
NodeBuilder<> nb(kind::OR);
nb << n[0] << body.notNode();
Node lem = nb;
- Debug("quantifiers-sk") << "Skolemize lemma : " << lem << std::endl;
+ Trace("quantifiers-sk") << "Skolemize lemma : " << lem << std::endl;
d_out->lemma( lem );
d_skolemized[n] = true;
}
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index cab94fb5c..39063942d 100644
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -28,8 +28,6 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::inst;
-//#define NESTED_PATTERN_SELECTION
-
/** trigger class constructor */
Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) :
d_quantEngine( qe ), d_f( f ){
@@ -46,7 +44,7 @@ d_quantEngine( qe ), d_f( f ){
d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] );
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes[0], qe );
- d_mg->setActiveAdd();
+ d_mg->setActiveAdd(true);
}
}else{
d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption );
@@ -55,7 +53,7 @@ d_quantEngine( qe ), d_f( f ){
}
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe );
- d_mg->setActiveAdd();
+ d_mg->setActiveAdd(true);
}
if( d_nodes.size()==1 ){
if( isSimpleTrigger( d_nodes[0] ) ){
@@ -75,6 +73,7 @@ d_quantEngine( qe ), d_f( f ){
qe->getTermDatabase()->registerTrigger( this, d_nodes[i].getOperator() );
}
}
+ Trace("trigger-debug") << "Finished making trigger." << std::endl;
}
void Trigger::resetInstantiationRound(){
@@ -126,7 +125,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTermDatabase()->computeVarContains( temp[i] );
for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- if( v.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(v)==f ){
if( vars.find( v )==vars.end() ){
varCount++;
vars[ v ] = true;
@@ -146,6 +145,12 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
}
if( varCount<f[0].getNumChildren() ){
+ 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;
+
//do not generate multi-trigger if it does not contain all variables
return NULL;
}else{
@@ -225,7 +230,7 @@ bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
}
bool Trigger::isUsable( Node n, Node f ){
- if( n.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
if( !isUsable( n[i], f ) ){
@@ -249,11 +254,71 @@ bool Trigger::isUsable( Node n, Node f ){
}
}
+bool nodeContainsVar( Node n, Node v ){
+ if( n==v) {
+ return true;
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ if( nodeContainsVar(n[i], v) ){
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+Node Trigger::getIsUsableTrigger( Node n, Node f, bool pol, bool hasPol ) {
+ if( options::relationalTriggers() ){
+ if( n.getKind()==EQUAL || n.getKind()==IFF || n.getKind()==GEQ ){
+ Node rtr;
+ for( unsigned i=0; i<2; i++) {
+ unsigned j = (i==0) ? 1 : 0;
+ if( n[j].getKind()==INST_CONSTANT && isUsableTrigger(n[i], f) && !nodeContainsVar( n[i], n[j] ) ) {
+ rtr = n;
+ break;
+ }
+ }
+ if( n[0].getType().isInteger() ){
+ //try to rearrange?
+ std::map< Node, Node > m;
+ if (QuantArith::getMonomialSumLit(n, m) ){
+ for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){
+ if( !it->first.isNull() && it->first.getKind()==INST_CONSTANT ){
+ Node veq;
+ if( QuantArith::isolate( it->first, m, veq, n.getKind() ) ){
+ int vti = veq[0]==it->first ? 1 : 0;
+ if( isUsableTrigger(veq[vti], f) && !nodeContainsVar( veq[vti], veq[vti==0 ? 1 : 0]) ){
+ rtr = veq;
+ }
+ }
+ }
+ }
+ }
+ }
+ if( !rtr.isNull() ){
+ Trace("relational-trigger") << "Relational trigger : " << std::endl;
+ Trace("relational-trigger") << " " << rtr << " (from " << n << ")" << std::endl;
+ Trace("relational-trigger") << " in quantifier " << f << std::endl;
+ if( hasPol ){
+ Trace("relational-trigger") << " polarity : " << pol << std::endl;
+ }
+ Node rtr2 = (hasPol && pol) ? rtr.negate() : rtr;
+ return rtr2;
+ }
+ }
+ }
+ bool usable = quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f );
+ Trace("usable") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==f) << " " << isAtomicTrigger( n ) << " " << isUsable( n, f ) << std::endl;
+ if( usable ){
+ return n;
+ }else{
+ return Node::null();
+ }
+}
+
bool Trigger::isUsableTrigger( Node n, Node f ){
- //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF;
- bool usable = n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f );
- Trace("usable") << n << " usable : " << usable << std::endl;
- return usable;
+ Node nu = getIsUsableTrigger(n,f);
+ return !nu.isNull();
}
bool Trigger::isAtomicTrigger( Node n ){
@@ -263,7 +328,7 @@ bool Trigger::isAtomicTrigger( Node n ){
bool Trigger::isSimpleTrigger( Node n ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){
return false;
}
}
@@ -274,55 +339,51 @@ bool Trigger::isSimpleTrigger( Node n ){
}
-bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){
+bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){
if( patMap.find( n )==patMap.end() ){
patMap[ n ] = false;
+ bool newHasPol = (n.getKind()==IFF || n.getKind()==XOR) ? false : hasPol;
+ bool newPol = n.getKind()==NOT ? !pol : pol;
if( tstrt==TS_MIN_TRIGGER ){
if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt );
- return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt );
-#else
return false;
-#endif
}else{
bool retVal = false;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
+ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
retVal = true;
}
}
if( retVal ){
return true;
- }else if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
- return true;
}else{
- return false;
+ Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ if( !nu.isNull() ){
+ patMap[ nu ] = true;
+ return true;
+ }else{
+ return false;
+ }
}
}
}else{
bool retVal = false;
- if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
+ Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ if( !nu.isNull() ){
+ patMap[ nu ] = true;
if( tstrt==TS_MAX_TRIGGER ){
return true;
}else{
retVal = true;
}
}
- if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){
- // retVal = true;
- //}
- if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){
- retVal = true;
- }
-#endif
- }else{
+ if( n.getKind()!=FORALL ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
+ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
retVal = true;
}
}
@@ -367,7 +428,7 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
}
- collectPatTerms2( qe, f, n, patMap, tstrt );
+ collectPatTerms2( qe, f, n, patMap, tstrt, true, true );
for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
if( it->second ){
patTerms.push_back( it->first );
@@ -380,9 +441,9 @@ bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeff
Assert( coeffs.empty() );
NodeBuilder<> t(kind::PLUS);
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
if( n[i].getKind()==INST_CONSTANT ){
- if( n[i].getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
coeffs[ n[i] ] = Node::null();
}else{
coeffs.clear();
@@ -405,13 +466,13 @@ bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeff
}
return true;
}else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){
- if( !n[1].hasAttribute(InstConstantAttribute()) ){
+ if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[1]) ){
coeffs[ n[0] ] = n[1];
return true;
}
- }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){
- if( !n[0].hasAttribute(InstConstantAttribute()) ){
+ }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[0]) ){
coeffs[ n[1] ] = n[0];
return true;
}
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index ca9124751..28fb2acda 100644
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -92,8 +92,9 @@ public:
private:
/** is subterm of trigger usable */
static bool isUsable( Node n, Node f );
+ static Node getIsUsableTrigger( Node n, Node f, bool pol = true, bool hasPol = false );
/** collect all APPLY_UF pattern terms for f in n */
- static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt );
+ static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol );
public:
//different strategies for choosing trigger terms
enum {
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 0bb0f1f79..0fe50aad6 100644..100755
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -27,6 +27,9 @@
#include "theory/quantifiers/trigger.h"
#include "theory/rewriterules/efficient_e_matching.h"
#include "theory/rewriterules/rr_trigger.h"
+#include "theory/quantifiers/bounded_integers.h"
+#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/uf/options.h"
using namespace std;
using namespace CVC4;
@@ -47,7 +50,11 @@ d_lemmas_produced_c(u){
d_hasAddedLemma = false;
//the model object
- d_model = new quantifiers::FirstOrderModel( c, "FirstOrderModel" );
+ if( options::fmfFullModelCheck() ){
+ d_model = new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc" );
+ }else{
+ d_model = new quantifiers::FirstOrderModelIG( c, "FirstOrderModelIG" );
+ }
//add quantifiers modules
if( !options::finiteModelFind() || options::fmfInstEngine() ){
@@ -57,11 +64,24 @@ d_lemmas_produced_c(u){
}else{
d_inst_engine = NULL;
}
- if( options::finiteModelFind() ){
+ if( options::finiteModelFind() ){
d_model_engine = new quantifiers::ModelEngine( c, this );
d_modules.push_back( d_model_engine );
+ if( options::fmfBoundInt() ){
+ d_bint = new quantifiers::BoundedIntegers( c, this );
+ d_modules.push_back( d_bint );
+ }else{
+ d_bint = NULL;
+ }
}else{
d_model_engine = NULL;
+ d_bint = NULL;
+ }
+ if( options::rewriteRulesAsAxioms() ){
+ d_rr_engine = new quantifiers::RewriteEngine( c, this );
+ d_modules.push_back(d_rr_engine);
+ }else{
+ d_rr_engine = NULL;
}
//options
@@ -251,7 +271,6 @@ void QuantifiersEngine::computeTermVector( Node f, InstMatch& m, std::vector< No
bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms ){
Assert( f.getKind()==FORALL );
- Assert( !f.hasAttribute(InstConstantAttribute()) );
Assert( vars.size()==terms.size() );
Node body = getInstantiation( f, vars, terms );
//make the lemma
@@ -266,7 +285,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
Trace("inst") << "*** Instantiate " << f << " with " << std::endl;
uint64_t maxInstLevel = 0;
for( int i=0; i<(int)terms.size(); i++ ){
- if( terms[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(terms[i]) ){
Debug("inst")<< "***& Bad Instantiate " << f << " with " << std::endl;
for( int i=0; i<(int)terms.size(); i++ ){
Debug("inst") << " " << terms[i] << std::endl;
@@ -432,8 +451,6 @@ bool QuantifiersEngine::addSplit( Node n, bool reqPhase, bool reqPhasePol ){
}
bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool reqPhasePol ){
- //Assert( !n1.hasAttribute(InstConstantAttribute()) );
- //Assert( !n2.hasAttribute(InstConstantAttribute()) );
//Assert( !areEqual( n1, n2 ) );
//Assert( !areDisequal( n1, n2 ) );
Kind knd = n1.getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
@@ -463,7 +480,6 @@ void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){
if( d_phase_reqs[f]->isPhaseReq( nodes[i] ) ){
bool preq = d_phase_reqs[f]->getPhaseReq( nodes[i] );
nodes[i] = NodeManager::currentNM()->mkNode( IFF, nodes[i], NodeManager::currentNM()->mkConst<bool>(preq) );
- d_term_db->setInstantiationConstantAttr( nodes[i], f );
nodeChanged = true;
}
//else if( qe->isPhaseReqEquality( f, trNodes[i] ) ){
@@ -617,35 +633,48 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f,
}else{
int sortId = 0;
if( optInternalRepSortInference() ){
+ //if( options::ufssSymBreak() ){
sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( f, f[0][index] );
}
if( d_int_rep[sortId].find( r )==d_int_rep[sortId].end() ){
- std::vector< Node > eqc;
- getEquivalenceClass( r, eqc );
//find best selection for representative
Node r_best;
- int r_best_score = -1;
- for( size_t i=0; i<eqc.size(); i++ ){
- int score = getRepScore( eqc[i], f, index );
- if( optInternalRepSortInference() ){
- int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]);
- if( score>=0 && e_sortId!=sortId ){
- score += 100;
- }
+ if( options::fmfRelevantDomain() ){
+ Trace("internal-rep-debug") << "Consult relevant domain to mkRep " << r << std::endl;
+ r_best = d_qe->getModelEngine()->getRelevantDomain()->getRelevantTerm( f, index, r );
+ Trace("internal-rep-debug") << "Returned " << r_best << " " << r << std::endl;
+ }else{
+ std::vector< Node > eqc;
+ getEquivalenceClass( r, eqc );
+ int r_best_score = -1;
+ for( size_t i=0; i<eqc.size(); i++ ){
+ int score = getRepScore( eqc[i], f, index );
+ if( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(eqc[i]) ){
+ if( optInternalRepSortInference() ){
+ int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]);
+ if( score>=0 && e_sortId!=sortId ){
+ score += 100;
+ }
+ }
+ //score prefers earliest use of this term as a representative
+ if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){
+ r_best = eqc[i];
+ r_best_score = score;
+ }
+ }
}
- //score prefers earliest use of this term as a representative
- if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){
- r_best = eqc[i];
- r_best_score = score;
+ if( r_best.isNull() ){
+ Node ic = d_qe->getTermDatabase()->getInstantiationConstant( f, index );
+ r_best = d_qe->getTermDatabase()->getFreeVariableForInstConstant( ic );
+ }
+ //now, make sure that no other member of the class is an instance
+ if( !optInternalRepSortInference() ){
+ r_best = getInstance( r_best, eqc );
+ }
+ //store that this representative was chosen at this point
+ if( d_rep_score.find( r_best )==d_rep_score.end() ){
+ d_rep_score[ r_best ] = d_reset_count;
}
- }
- //now, make sure that no other member of the class is an instance
- if( !optInternalRepSortInference() ){
- r_best = getInstance( r_best, eqc );
- }
- //store that this representative was chosen at this point
- if( d_rep_score.find( r_best )==d_rep_score.end() ){
- d_rep_score[ r_best ] = d_reset_count;
}
d_int_rep[sortId][r] = r_best;
if( r_best!=a ){
@@ -723,4 +752,4 @@ int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){
bool EqualityQueryQuantifiersEngine::optInternalRepSortInference() {
return false; //shown to be not effective
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index bfa19bb98..b075f7be8 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -56,14 +56,17 @@ public:
virtual void assertNode( Node n ) = 0;
virtual void propagate( Theory::Effort level ){}
virtual Node getNextDecisionRequest() { return TNode::null(); }
- virtual Node explain(TNode n) = 0;
+ virtual Node explain(TNode n) { return TNode::null(); }
};/* class QuantifiersModule */
namespace quantifiers {
- class InstantiationEngine;
- class ModelEngine;
class TermDb;
class FirstOrderModel;
+ //modules
+ class InstantiationEngine;
+ class ModelEngine;
+ class BoundedIntegers;
+ class RewriteEngine;
}/* CVC4::theory::quantifiers */
namespace inst {
@@ -80,6 +83,7 @@ class EqualityQueryQuantifiersEngine;
class QuantifiersEngine {
friend class quantifiers::InstantiationEngine;
friend class quantifiers::ModelEngine;
+ friend class quantifiers::RewriteEngine;
friend class inst::InstMatch;
private:
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
@@ -87,10 +91,6 @@ private:
TheoryEngine* d_te;
/** vector of modules for quantifiers */
std::vector< QuantifiersModule* > d_modules;
- /** instantiation engine */
- quantifiers::InstantiationEngine* d_inst_engine;
- /** model engine */
- quantifiers::ModelEngine* d_model_engine;
/** equality query class */
EqualityQueryQuantifiersEngine* d_eq_query;
/** for computing relevance of quantifiers */
@@ -99,6 +99,14 @@ private:
std::map< Node, QuantPhaseReq* > d_phase_reqs;
/** efficient e-matcher */
EfficientEMatcher* d_eem;
+ /** instantiation engine */
+ quantifiers::InstantiationEngine* d_inst_engine;
+ /** model engine */
+ quantifiers::ModelEngine* d_model_engine;
+ /** bounded integers utility */
+ quantifiers::BoundedIntegers * d_bint;
+ /** rewrite rules utility */
+ quantifiers::RewriteEngine * d_rr_engine;
private:
/** list of all quantifiers seen */
std::vector< Node > d_quants;
@@ -155,6 +163,8 @@ public:
void getPhaseReqTerms( Node f, std::vector< Node >& nodes );
/** get efficient e-matching utility */
EfficientEMatcher* getEfficientEMatcher() { return d_eem; }
+ /** get bounded integers utility */
+ quantifiers::BoundedIntegers * getBoundedIntegers() { return d_bint; }
public:
/** initialize */
void finishInit();
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index f6da32bbf..800e007f7 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -14,6 +14,7 @@
#include "theory/rep_set.h"
#include "theory/type_enumerator.h"
+#include "theory/quantifiers/bounded_integers.h"
using namespace std;
using namespace CVC4;
@@ -94,26 +95,38 @@ void RepSet::toStream(std::ostream& out){
}
-RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){
+RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe), d_rep_set( rs ){
d_incomplete = false;
+}
+int RepSetIterator::domainSize( int i ) {
+ Assert(i>=0);
+ if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){
+ return d_domain[i].size();
+ }else{
+ return d_domain[i][0];
+ }
}
bool RepSetIterator::setQuantifier( Node f ){
+ Trace("rsi") << "Make rsi for " << f << std::endl;
Assert( d_types.empty() );
//store indicies
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
d_types.push_back( f[0][i].getType() );
}
+ d_owner = f;
return initialize();
}
bool RepSetIterator::setFunctionDomain( Node op ){
+ Trace("rsi") << "Make rsi for " << op << std::endl;
Assert( d_types.empty() );
TypeNode tn = op.getType();
for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
d_types.push_back( tn[i] );
}
+ d_owner = op;
return initialize();
}
@@ -132,22 +145,80 @@ bool RepSetIterator::initialize(){
Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
d_rep_set->add( var );
}
- }else if( tn.isInteger() || tn.isReal() ){
- Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl;
- d_incomplete = true;
- //enumerate if the sort is reasonably small, the upper bound of 128 is chosen arbitrarily for now
- }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=128 ){
+ }else if( tn.isInteger() ){
+ bool inc = false;
+ //check if it is bound
+ if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
+ if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
+ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded integer." << std::endl;
+ d_enum_type.push_back( ENUM_RANGE );
+ }else{
+ inc = true;
+ }
+ }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() ){
+ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded." << std::endl;
+ d_enum_type.push_back( ENUM_RANGE );
+ }else{
+ Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
+ d_incomplete = true;
+ }
+ }
+ //enumerate if the sort is reasonably small, the upper bound of 1000 is chosen arbitrarily for now
+ }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=1000 ){
d_rep_set->complete( tn );
}else{
- Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl;
+ Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
d_incomplete = true;
}
- 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 );
+ if( d_enum_type.size()<=i ){
+ 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 );
+ }
+ }else{
+ return false;
}
- }else{
- return false;
+ }
+ }
+ //must set a variable index order based on bounded integers
+ 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_owner[0].getNumChildren(); i++) {
+ if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
+ varOrder.push_back(i);
+ }
+ }
+ Trace("bound-int-rsi") << "Variable order : ";
+ for( unsigned i=0; i<varOrder.size(); i++) {
+ Trace("bound-int-rsi") << varOrder[i] << " ";
+ }
+ Trace("bound-int-rsi") << std::endl;
+ std::vector< int > indexOrder;
+ indexOrder.resize(varOrder.size());
+ for( unsigned i=0; i<varOrder.size(); i++){
+ indexOrder[varOrder[i]] = i;
+ }
+ Trace("bound-int-rsi") << "Will use index order : ";
+ for( unsigned i=0; i<indexOrder.size(); i++) {
+ Trace("bound-int-rsi") << indexOrder[i] << " ";
+ }
+ Trace("bound-int-rsi") << std::endl;
+ setIndexOrder(indexOrder);
+ }
+ //now reset the indices
+ for (unsigned i=0; i<d_index.size(); i++) {
+ if (!resetIndex(i, true)){
+ break;
}
}
return true;
@@ -161,7 +232,7 @@ void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
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() );
@@ -172,29 +243,104 @@ void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
}
}
}
+*/
+bool 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;
+ //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;
+ 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 );
+ }
+ 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>()) ){
+ 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],
+ NodeManager::currentNM()->mkConst( Rational(1) ) );
+ u = Rewriter::rewrite( u );
+ }
+ }
+ }
+
+ if( l.isNull() || u.isNull() ){
+ //failed, abort the iterator
+ d_index.clear();
+ return false;
+ }else{
+ Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " 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();
+ 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 );
+ }
+ d_lower_bounds[ii] = tl;
+ if( ra==NodeManager::currentNM()->mkConst(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 );
+ }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 );
+ }
+ }
+ }else{
+ Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl;
+ }
+ }
+ return true;
+}
-void RepSetIterator::increment2( int counter ){
+int RepSetIterator::increment2( int counter ){
Assert( !isFinished() );
#ifdef DISABLE_EVAL_SKIP_MULTIPLE
counter = (int)d_index.size()-1;
#endif
//increment d_index
- while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){
+ if( counter>=0){
+ Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << 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;
+ }
}
if( counter==-1 ){
d_index.clear();
}else{
+ d_index[counter]++;
+ bool emptyDomain = false;
for( int i=(int)d_index.size()-1; i>counter; i-- ){
- d_index[i] = 0;
+ if (!resetIndex(i)){
+ break;
+ }else if( domainSize(i)<=0 ){
+ emptyDomain = true;
+ }
+ }
+ if( emptyDomain ){
+ Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl;
+ return increment();
}
- d_index[counter]++;
}
+ return counter;
}
-void RepSetIterator::increment(){
+int RepSetIterator::increment(){
if( !isFinished() ){
- increment2( (int)d_index.size()-1 );
+ return increment2( (int)d_index.size()-1 );
+ }else{
+ return -1;
}
}
@@ -203,10 +349,18 @@ bool RepSetIterator::isFinished(){
}
Node RepSetIterator::getTerm( int i ){
- TypeNode tn = d_types[d_index_order[i]];
- Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
int index = d_index_order[i];
- return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
+ if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){
+ TypeNode tn = d_types[index];
+ 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]]];
+ }else{
+ Trace("rsi-debug") << 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]) ) );
+ t = Rewriter::rewrite( t );
+ return t;
+ }
}
void RepSetIterator::debugPrint( const char* c ){
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 24fa7473e..a619915ee 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -23,6 +23,8 @@
namespace CVC4 {
namespace theory {
+class QuantifiersEngine;
+
/** this class stores a representative set */
class RepSet {
public:
@@ -52,11 +54,27 @@ typedef std::vector< int > RepDomain;
/** this class iterates over a RepSet */
class RepSetIterator {
+public:
+ enum {
+ ENUM_DOMAIN_ELEMENTS,
+ ENUM_RANGE,
+ };
private:
+ QuantifiersEngine * d_qe;
//initialize function
bool initialize();
+ //for enum ranges
+ std::map< int, Node > d_lower_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 );
+ /** set index order */
+ void setIndexOrder( std::vector< int >& indexOrder );
public:
- RepSetIterator( RepSet* rs );
+ RepSetIterator( QuantifiersEngine * qe, RepSet* rs );
~RepSetIterator(){}
//set that this iterator will be iterating over instantiations for a quantifier
bool setQuantifier( Node f );
@@ -65,6 +83,8 @@ public:
public:
//pointer to model
RepSet* d_rep_set;
+ //enumeration type?
+ std::vector< int > d_enum_type;
//index we are considering
std::vector< int > d_index;
//types we are considering
@@ -86,15 +106,13 @@ public:
// 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:
- /** set index order */
- void setIndexOrder( std::vector< int >& indexOrder );
- /** set domain */
- void setDomain( std::vector< RepDomain >& domain );
/** increment the iterator at index=counter */
- void increment2( int counter );
+ int increment2( int counter );
/** increment the iterator */
- void increment();
+ int increment();
/** is the iterator finished? */
bool isFinished();
/** get the i_th term we are considering */
diff --git a/src/theory/rewriterules/rr_inst_match.cpp b/src/theory/rewriterules/rr_inst_match.cpp
index a4c111f86..4908e5ec0 100644
--- a/src/theory/rewriterules/rr_inst_match.cpp
+++ b/src/theory/rewriterules/rr_inst_match.cpp
@@ -137,14 +137,13 @@ class DumbPatMatcher: public PatMatcher{
/* The order of the matching is:
reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */
ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){
- // Assert( pat.hasAttribute(InstConstantAttribute()) );
//set-up d_variables, d_constants, d_childrens
for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){
//EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType());
EqualityQuery* q = qe->getEqualityQuery();
Assert( q != NULL );
- if( d_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_pattern[i]) ){
if( d_pattern[i].getKind()==INST_CONSTANT ){
//It's a variable
d_variables.push_back(make_triple((TNode)d_pattern[i],i,q));
@@ -172,7 +171,7 @@ bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){
//if t is null
Assert( !t.isNull() );
- Assert( !t.hasAttribute(InstConstantAttribute()) );
+ Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
Assert( t.getKind()==d_pattern.getKind() );
Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR)
|| t.getOperator()==d_pattern.getOperator() );
@@ -411,7 +410,7 @@ public:
size_t numFreeVar(TNode t){
size_t n = 0;
for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){
- if( t[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(t[i]) ){
if( t[i].getKind()==INST_CONSTANT ){
//variable
++n;
@@ -958,7 +957,7 @@ Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){
/** TODO: something simpler to see if the pattern is a good
arithmetic pattern */
std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){
+ if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
Message() << "(?) Unknown matching pattern is " << pat << std::endl;
Unimplemented("pattern not implemented");
return new DumbMatcher();
@@ -983,17 +982,17 @@ Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){
PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
Debug("inst-match-gen") << "Pattern term is " << pat << std::endl;
- Assert( pat.hasAttribute(InstConstantAttribute()) );
+ Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){
/* Difference */
return new UfDeqMatcher(pat, qe);
} else if (pat.getKind() == kind::EQUAL){
- if( !pat[0].hasAttribute(InstConstantAttribute() )){
- Assert(pat[1].hasAttribute(InstConstantAttribute()));
+ if( !quantifiers::TermDb::hasInstConstAttr(pat[0])){
+ Assert(quantifiers::TermDb::hasInstConstAttr(pat[1]));
return new UfCstEqMatcher(pat[1], pat[0], qe);
- }else if( !pat[1].hasAttribute(InstConstantAttribute() )){
- Assert(pat[0].hasAttribute(InstConstantAttribute()));
+ }else if( !quantifiers::TermDb::hasInstConstAttr(pat[1] )){
+ Assert(quantifiers::TermDb::hasInstConstAttr(pat[0]));
return new UfCstEqMatcher(pat[0], pat[1], qe);
}else{
std::vector< Node > pats(pat.begin(),pat.end());
@@ -1009,7 +1008,7 @@ PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
/** TODO: something simpler to see if the pattern is a good
arithmetic pattern */
std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){
+ if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl;
Message() << "(?) Unknown matching pattern is " << pat << std::endl;
return new DumbPatMatcher();
@@ -1033,7 +1032,7 @@ PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){
- if(Trigger::getPatternArithmetic(pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) )
+ if(Trigger::getPatternArithmetic(quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) )
{
Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl;
Assert(false);
diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h
index 3ec9438fd..aa89430c1 100644
--- a/src/theory/rewriterules/rr_inst_match.h
+++ b/src/theory/rewriterules/rr_inst_match.h
@@ -67,7 +67,7 @@ public:
/** legal candidate */
static inline bool isLegalCandidate( TNode n ){
return !n.getAttribute(NoMatchAttribute()) &&
- ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute())) &&
+ ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n)) &&
( !options::efficientEMatching() || n.hasAttribute(AvailableInTermDb()) );
}
diff --git a/src/theory/rewriterules/rr_trigger.cpp b/src/theory/rewriterules/rr_trigger.cpp
index 7e35be7ad..13250cf1b 100644
--- a/src/theory/rewriterules/rr_trigger.cpp
+++ b/src/theory/rewriterules/rr_trigger.cpp
@@ -65,7 +65,7 @@ bool Trigger::getNextMatch(){
int Trigger::addInstantiations( InstMatch& baseMatch ){
int addedLemmas = d_mg->addInstantiations( baseMatch,
- d_nodes[0].getAttribute(InstConstantAttribute()),
+ quantifiers::TermDb::getInstConstAttr(d_nodes[0]),
d_quantEngine);
if( addedLemmas>0 ){
Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was ";
@@ -91,7 +91,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTermDatabase()->computeVarContains( temp[i] );
for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- if( v.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(v)==f ){
if( vars.find( v )==vars.end() ){
vars[ v ] = true;
foundVar = true;
@@ -181,7 +181,7 @@ bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
}
bool Trigger::isUsable( Node n, Node f ){
- if( n.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){
std::map< Node, Node > coeffs;
return getPatternArithmetic( f, n, coeffs );
@@ -201,7 +201,7 @@ bool Trigger::isUsable( Node n, Node f ){
bool Trigger::isSimpleTrigger( Node n ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){
return false;
}
}
@@ -318,9 +318,9 @@ bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coef
Assert( coeffs.empty() );
NodeBuilder<> t(kind::PLUS);
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
if( n[i].getKind()==INST_CONSTANT ){
- if( n[i].getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
coeffs[ n[i] ] = Node::null();
}else{
coeffs.clear();
@@ -343,12 +343,12 @@ bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coef
}
return true;
}else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){
- Assert( !n[1].hasAttribute(InstConstantAttribute()) );
+ if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
+ Assert( !quantifiers::TermDb::hasInstConstAttr(n[1]) );
coeffs[ n[0] ] = n[1];
return true;
- }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){
- Assert( !n[0].hasAttribute(InstConstantAttribute()) );
+ }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
+ Assert( !quantifiers::TermDb::hasInstConstAttr(n[0]) );
coeffs[ n[1] ] = n[0];
return true;
}
diff --git a/src/theory/rewriterules/rr_trigger.h b/src/theory/rewriterules/rr_trigger.h
index f1a37d937..f02f38d0e 100644
--- a/src/theory/rewriterules/rr_trigger.h
+++ b/src/theory/rewriterules/rr_trigger.h
@@ -94,8 +94,7 @@ public:
public:
/** is usable trigger */
static inline bool isUsableTrigger( TNode n, TNode f ){
- //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF;
- return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f );
+ return quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f );
}
static inline bool isAtomicTrigger( TNode n ){
return
diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h
index 19cb3e987..a542214b2 100644
--- a/src/theory/rewriterules/theory_rewriterules.h
+++ b/src/theory/rewriterules/theory_rewriterules.h
@@ -263,7 +263,7 @@ private:
rewriter::Subst & vars);
//create inst variable
- std::vector<Node> createInstVariable( std::vector<Node> & vars );
+ std::vector<Node> createInstVariable( Node r, std::vector<Node> & vars );
/** statistics class */
class Statistics {
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp
index 589556802..7e1d42bb2 100644
--- a/src/theory/rewriterules/theory_rewriterules_rules.cpp
+++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp
@@ -151,7 +151,7 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
vars.push_back(*v);
};
/* Instantiation version */
- std::vector<Node> inst_constants = createInstVariable(vars);
+ std::vector<Node> inst_constants = createInstVariable(r,vars);
/* Body/Remove_term/Guards/Triggers */
Node body = r[2][1];
TNode new_terms = r[2][1];
@@ -232,7 +232,11 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
patternListB << static_cast<Node>(patternB);
forallB << static_cast<Node>(patternListB);
- getOutputChannel().lemma((Node) forallB);
+ Node lem = (Node) forallB;
+ lem = Rewriter::rewrite(lem);
+ QRewriteRuleAttribute qra;
+ lem.setAttribute(qra,r);
+ getOutputChannel().lemma(lem);
return;
}
@@ -376,7 +380,7 @@ bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body,
}
-std::vector<Node> TheoryRewriteRules::createInstVariable( std::vector<Node> & vars ){
+std::vector<Node> TheoryRewriteRules::createInstVariable( Node r, std::vector<Node> & vars ){
std::vector<Node> inst_constant;
inst_constant.reserve(vars.size());
for( std::vector<Node>::const_iterator v = vars.begin();
@@ -384,6 +388,11 @@ std::vector<Node> TheoryRewriteRules::createInstVariable( std::vector<Node> & va
//make instantiation constants
Node ic = NodeManager::currentNM()->mkInstConstant( (*v).getType() );
inst_constant.push_back( ic );
+ InstConstantAttribute ica;
+ ic.setAttribute(ica,r);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ ic.setAttribute(nma,true);
};
return inst_constant;
}
diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h
index 256957855..fa6bb2227 100644
--- a/src/theory/rewriterules/theory_rewriterules_type_rules.h
+++ b/src/theory/rewriterules/theory_rewriterules_type_rules.h
@@ -33,6 +33,8 @@ public:
* Compute the type for (and optionally typecheck) a term belonging
* to the theory of rewriterules.
*
+ * @param nodeManager the NodeManager in use
+ * @param n the node to compute the type of
* @param check if true, the node's type should be checked as well
* as computed.
*/
diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp
index 58b8cf697..3a767b5c3 100644
--- a/src/theory/shared_terms_database.cpp
+++ b/src/theory/shared_terms_database.cpp
@@ -131,9 +131,9 @@ bool SharedTermsDatabase::propagateSharedEquality(TheoryId theory, TNode a, TNod
// Propagate away
Node equality = a.eqNode(b);
if (value) {
- d_theoryEngine->assertToTheory(equality, theory, THEORY_BUILTIN);
+ d_theoryEngine->assertToTheory(equality, equality, theory, THEORY_BUILTIN);
} else {
- d_theoryEngine->assertToTheory(equality.notNode(), theory, THEORY_BUILTIN);
+ d_theoryEngine->assertToTheory(equality.notNode(), equality.notNode(), theory, THEORY_BUILTIN);
}
// As you were
diff --git a/src/theory/strings/Makefile b/src/theory/strings/Makefile
new file mode 100644
index 000000000..e92c24ab7
--- /dev/null
+++ b/src/theory/strings/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/strings
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/strings/Makefile.am b/src/theory/strings/Makefile.am
new file mode 100644
index 000000000..38efa33f3
--- /dev/null
+++ b/src/theory/strings/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@srcdir@/../../include -I@srcdir@/../.. -I@builddir@/../..
+AM_CXXFLAGS = -Wall $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = libstrings.la
+
+libstrings_la_SOURCES = \
+ theory_strings.h \
+ theory_strings.cpp \
+ theory_strings_rewriter.h \
+ theory_strings_rewriter.cpp \
+ theory_strings_type_rules.h \
+ type_enumerator.h \
+ theory_strings_preprocess.h \
+ theory_strings_preprocess.cpp
+
+EXTRA_DIST = \
+ kinds
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
new file mode 100644
index 000000000..814276a7c
--- /dev/null
+++ b/src/theory/strings/kinds
@@ -0,0 +1,105 @@
+# kinds [for strings theory]
+#
+
+theory THEORY_STRINGS ::CVC4::theory::strings::TheoryStrings "theory/strings/theory_strings.h"
+
+properties check parametric propagate
+
+rewriter ::CVC4::theory::strings::TheoryStringsRewriter "theory/strings/theory_strings_rewriter.h"
+
+typechecker "theory/strings/theory_strings_type_rules.h"
+
+
+operator STRING_CONCAT 2: "string concat"
+
+operator STRING_IN_REGEXP 2 "membership"
+
+operator STRING_LENGTH 1 "string length"
+
+#sort CHAR_TYPE \
+# Cardinality::INTEGERS \
+# well-founded \
+# "NodeManager::currentNM()->mkConst(::CVC4::String())" \
+# "util/regexp.h" \
+# "String type"
+
+sort STRING_TYPE \
+ Cardinality::INTEGERS \
+ well-founded \
+ "NodeManager::currentNM()->mkConst(::CVC4::String())" \
+ "util/regexp.h" \
+ "String type"
+
+sort REGEXP_TYPE \
+ Cardinality::INTEGERS \
+ well-founded \
+ "NodeManager::currentNM()->mkConst(::CVC4::RegExp())" \
+ "util/regexp.h" \
+ "RegExp type"
+
+enumerator STRING_TYPE \
+ "::CVC4::theory::strings::StringEnumerator" \
+ "theory/strings/type_enumerator.h"
+
+#enumerator REGEXP_TYPE \
+# "::CVC4::theory::strings::RegExpEnumerator" \
+# "theory/strings/type_enumerator.h"
+
+constant CONST_STRING \
+ ::CVC4::String \
+ ::CVC4::strings::StringHashFunction \
+ "util/regexp.h" \
+ "a string of characters"
+
+constant CONST_REGEXP \
+ ::CVC4::RegExp \
+ ::CVC4::RegExpHashFunction \
+ "util/regexp.h" \
+ "a regular expression"
+
+typerule CONST_STRING ::CVC4::theory::strings::StringConstantTypeRule
+typerule CONST_REGEXP ::CVC4::theory::strings::RegExpConstantTypeRule
+
+# equal equal / less than / output
+operator STRING_TO_REGEXP 1 "convert string to regexp"
+operator REGEXP_CONCAT 2: "regexp concat"
+operator REGEXP_OR 2: "regexp or"
+operator REGEXP_INTER 2: "regexp intersection"
+operator REGEXP_STAR 1 "regexp *"
+operator REGEXP_PLUS 1 "regexp +"
+operator REGEXP_OPT 1 "regexp ?"
+
+#constant REGEXP_EMPTY \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains nothing"
+
+#constant REGEXP_ALL \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains all strings"
+
+#constant REGEXP_SIGMA \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains an arbitrary charactor"
+
+typerule REGEXP_CONCAT ::CVC4::theory::strings::RegExpConcatTypeRule
+typerule REGEXP_OR ::CVC4::theory::strings::RegExpOrTypeRule
+typerule REGEXP_INTER ::CVC4::theory::strings::RegExpInterTypeRule
+typerule REGEXP_STAR ::CVC4::theory::strings::RegExpStarTypeRule
+typerule REGEXP_PLUS ::CVC4::theory::strings::RegExpPlusTypeRule
+typerule REGEXP_OPT ::CVC4::theory::strings::RegExpOptTypeRule
+
+typerule STRING_TO_REGEXP ::CVC4::theory::strings::StringToRegExpTypeRule
+
+
+typerule STRING_CONCAT ::CVC4::theory::strings::StringConcatTypeRule
+typerule STRING_LENGTH ::CVC4::theory::strings::StringLengthTypeRule
+
+typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule
+
+endtheory
diff --git a/src/theory/strings/options b/src/theory/strings/options
new file mode 100644
index 000000000..9226f9999
--- /dev/null
+++ b/src/theory/strings/options
@@ -0,0 +1,11 @@
+#
+# Option specification file for CVC4
+# See src/options/base_options for a description of this file format
+#
+
+module STRINGS "theory/strings/options.h" Strings theory
+
+option stringCharCardinality str-alphabet-card --str-alphabet-card=N int16_t :default 256 :read-write
+ the cardinality of the characters used by the theory of string, default 256
+
+endmodule
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
new file mode 100644
index 000000000..7d5edd0f7
--- /dev/null
+++ b/src/theory/strings/theory_strings.cpp
@@ -0,0 +1,1711 @@
+/********************* */
+/*! \file theory_strings.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 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 strings.
+ **
+ ** Implementation of the theory of strings.
+ **/
+
+
+#include "theory/strings/theory_strings.h"
+#include "theory/valuation.h"
+#include "expr/kind.h"
+#include "theory/rewriter.h"
+#include "expr/command.h"
+#include "theory/model.h"
+#include "smt/logic_exception.h"
+#include "theory/strings/options.h"
+#include "theory/strings/type_enumerator.h"
+#include <cmath>
+
+#define STR_UNROLL_INDUCTION
+
+using namespace std;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
+ : Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo, qe),
+ d_notify( *this ),
+ d_equalityEngine(d_notify, c, "theory::strings::TheoryStrings"),
+ d_conflict( c, false ),
+ d_infer(c),
+ d_infer_exp(c),
+ d_nf_pairs(c),
+ d_ind_map1(c),
+ d_ind_map2(c),
+ d_ind_map_exp(c),
+ d_ind_map_lemma(c),
+ //d_lit_to_decide_index( c, 0 ),
+ //d_lit_to_decide( c ),
+ d_lit_to_unroll( c )
+{
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
+ d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
+ d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
+
+ d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
+ d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ d_true = NodeManager::currentNM()->mkConst( true );
+ d_false = NodeManager::currentNM()->mkConst( false );
+}
+
+TheoryStrings::~TheoryStrings() {
+
+}
+
+Node TheoryStrings::getRepresentative( Node t ) {
+ if( d_equalityEngine.hasTerm( t ) ){
+ return d_equalityEngine.getRepresentative( t );
+ }else{
+ return t;
+ }
+}
+
+bool TheoryStrings::hasTerm( Node a ){
+ return d_equalityEngine.hasTerm( a );
+}
+
+bool TheoryStrings::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 TheoryStrings::areDisequal( Node a, Node b ){
+ if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areDisequal( a, b, false );
+ }else{
+ return false;
+ }
+}
+
+Node TheoryStrings::getLength( Node t ) {
+ EqcInfo * ei = getOrMakeEqcInfo( t );
+ Node length_term = ei->d_length_term;
+ if( length_term.isNull()) {
+ //typically shouldnt be necessary
+ length_term = t;
+ }
+ return NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, length_term );
+}
+
+void TheoryStrings::setMasterEqualityEngine(eq::EqualityEngine* eq) {
+ d_equalityEngine.setMasterEqualityEngine(eq);
+}
+
+void TheoryStrings::addSharedTerm(TNode t) {
+ Debug("strings") << "TheoryStrings::addSharedTerm(): "
+ << t << " " << t.getType().isBoolean() << endl;
+ d_equalityEngine.addTriggerTerm(t, THEORY_STRINGS);
+ Debug("strings") << "TheoryStrings::addSharedTerm() finished" << std::endl;
+}
+
+EqualityStatus TheoryStrings::getEqualityStatus(TNode a, TNode b) {
+ if( d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b) ){
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ }
+ return EQUALITY_UNKNOWN;
+}
+
+void TheoryStrings::propagate(Effort e)
+{
+ // direct propagation now
+}
+
+bool TheoryStrings::propagate(TNode literal) {
+ Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << ")" << std::endl;
+ // If already in conflict, no more propagation
+ if (d_conflict) {
+ Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << "): already in conflict" << std::endl;
+ return false;
+ }
+ Trace("strings-prop") << "strPropagate " << literal << std::endl;
+ // Propagate out
+ bool ok = d_out->propagate(literal);
+ if (!ok) {
+ d_conflict = true;
+ }
+ return ok;
+}
+
+/** explain */
+void TheoryStrings::explain(TNode literal, std::vector<TNode>& assumptions){
+ Debug("strings-explain") << "Explain " << literal << std::endl;
+ 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);
+ } else {
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ }
+}
+
+Node TheoryStrings::explain( TNode literal ){
+ std::vector< TNode > assumptions;
+ explain( literal, assumptions );
+ if( assumptions.empty() ){
+ return d_true;
+ }else if( assumptions.size()==1 ){
+ return assumptions[0];
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::AND, assumptions );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// MODEL GENERATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
+ Trace("strings-model") << "TheoryStrings : Collect model info, fullModel = " << fullModel << std::endl;
+ Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl;
+ m->assertEqualityEngine( &d_equalityEngine );
+ // Generate model
+ std::vector< Node > nodes;
+ getEquivalenceClasses( nodes );
+ std::map< Node, Node > processed;
+ std::vector< std::vector< Node > > col;
+ std::vector< Node > lts;
+ seperateByLength( nodes, col, lts );
+ //step 1 : get all values for known lengths
+ std::vector< Node > lts_values;
+ //std::map< Node, bool > values_used;
+ for( unsigned i=0; i<col.size(); i++ ){
+ Trace("strings-model") << "Checking length for " << col[i][0] << " (length is " << lts[i] << ")" << std::endl;
+ if( lts[i].isConst() ){
+ lts_values.push_back( lts[i] );
+ //values_used[ lts[i] ] = true;
+ }else{
+ //get value for lts[i];
+ if( !lts[i].isNull() ){
+ Node v = d_valuation.getModelValue(lts[i]);
+ //Node v = m->getValue(lts[i]);
+ Trace("strings-model") << "Model value for " << lts[i] << " is " << v << std::endl;
+ lts_values.push_back( v );
+ //values_used[ v ] = true;
+ }else{
+ Trace("strings-model-warn") << "No length for eqc " << col[i][0] << std::endl;
+ Assert( false );
+ lts_values.push_back( Node::null() );
+ }
+ }
+ }
+ ////step 2 : assign arbitrary values for unknown lengths?
+ //for( unsigned i=0; i<col.size(); i++ ){
+ // if(
+ //}
+ Trace("strings-model") << "Assign to equivalence classes..." << std::endl;
+ //step 3 : assign values to equivalence classes that are pure variables
+ for( unsigned i=0; i<col.size(); i++ ){
+ std::vector< Node > pure_eq;
+ Trace("strings-model") << "The equivalence classes ";
+ for( unsigned j=0; j<col[i].size(); j++ ) {
+ Trace("strings-model") << col[i][j] << " ";
+ //check if col[i][j] has only variables
+ EqcInfo* ei = getOrMakeEqcInfo( col[i][j], false );
+ Node cst = ei ? ei->d_const_term : Node::null();
+ if( cst.isNull() ){
+ Assert( d_normal_forms.find( col[i][j] )!=d_normal_forms.end() );
+ if( d_normal_forms[col[i][j]].size()==1 ){//&& d_normal_forms[col[i][j]][0]==col[i][j] ){
+ pure_eq.push_back( col[i][j] );
+ }
+ }else{
+ processed[col[i][j]] = cst;
+ }
+ }
+ Trace("strings-model") << "have length " << lts_values[i] << std::endl;
+
+ Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes ";
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Trace("strings-model") << pure_eq[j] << " ";
+ }
+ Trace("strings-model") << std::endl;
+
+ //use type enumerator
+ StringEnumeratorLength sel(lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt());
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Assert( !sel.isFinished() );
+ Node c = *sel;
+ while( d_equalityEngine.hasTerm( c ) ){
+ ++sel;
+ Assert( !sel.isFinished() );
+ c = *sel;
+ }
+ ++sel;
+ Trace("strings-model") << "*** Assigned constant " << c << " for " << pure_eq[j] << std::endl;
+ processed[pure_eq[j]] = c;
+ m->assertEquality( pure_eq[j], c, true );
+ }
+ }
+ Trace("strings-model") << "String Model : Finished." << std::endl;
+ //step 4 : assign constants to all other equivalence classes
+ for( unsigned i=0; i<nodes.size(); i++ ){
+ if( processed.find( nodes[i] )==processed.end() ){
+ Assert( d_normal_forms.find( nodes[i] )!=d_normal_forms.end() );
+ Trace("strings-model") << "Construct model for " << nodes[i] << " based on normal form ";
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ if( j>0 ) Trace("strings-model") << " ++ ";
+ Trace("strings-model") << d_normal_forms[nodes[i]][j];
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ if( !r.isConst() && processed.find( r )==processed.end() ){
+ Trace("strings-model") << "(UNPROCESSED)";
+ }
+ }
+ Trace("strings-model") << std::endl;
+ std::vector< Node > nc;
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ Assert( r.isConst() || processed.find( r )!=processed.end() );
+ nc.push_back(r.isConst() ? r : processed[r]);
+ }
+ Node cc = mkConcat( nc );
+ Assert( cc.getKind()==kind::CONST_STRING );
+ Trace("strings-model") << "*** Determined constant " << cc << " for " << nodes[i] << std::endl;
+ processed[nodes[i]] = cc;
+ m->assertEquality( nodes[i], cc, true );
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// MAIN SOLVER
+/////////////////////////////////////////////////////////////////////////////
+
+void TheoryStrings::preRegisterTerm(TNode n) {
+ Debug("strings-prereg") << "TheoryStrings::preRegisterTerm() " << n << endl;
+ //collectTerms( n );
+ switch (n.getKind()) {
+ case kind::EQUAL:
+ d_equalityEngine.addTriggerEquality(n);
+ break;
+ case kind::STRING_IN_REGEXP:
+ d_equalityEngine.addTriggerPredicate(n);
+ break;
+ default:
+ if(n.getKind() == kind::VARIABLE || n.getKind()==kind::SKOLEM) {
+ if( std::find( d_length_intro_vars.begin(), d_length_intro_vars.end(), n )==d_length_intro_vars.end() ){
+ Node n_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n);
+ Node n_len_geq_zero = NodeManager::currentNM()->mkNode( kind::GEQ, n_len, d_zero);
+ Trace("strings-lemma") << "Strings: Add lemma " << n_len_geq_zero << std::endl;
+ d_out->lemma(n_len_geq_zero);
+ }
+ }
+ if (n.getType().isBoolean()) {
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ } else {
+ // Function applications/predicates
+ d_equalityEngine.addTerm(n);
+ }
+ break;
+ }
+}
+
+void TheoryStrings::check(Effort e) {
+ bool polarity;
+ TNode atom;
+
+ if( !done() && !hasTerm( d_emptyString ) ){
+ preRegisterTerm( d_emptyString );
+ }
+
+ // Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
+ Trace("strings-check") << "Theory of strings, check : " << e << std::endl;
+ while ( !done() && !d_conflict)
+ {
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+
+ Trace("strings-assertion") << "get assertion: " << fact << endl;
+
+ polarity = fact.getKind() != kind::NOT;
+ atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ d_equalityEngine.assertEquality(atom, polarity, fact);
+ } else {
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ }
+#ifdef STR_UNROLL_INDUCTION
+ //check if it is a literal to unroll?
+ if( d_lit_to_unroll.find( atom )!=d_lit_to_unroll.end() ){
+ Trace("strings-ind") << "Strings-ind : Possibly unroll for : " << atom << ", polarity = " << polarity << std::endl;
+ }
+#endif
+ }
+ doPendingFacts();
+
+
+ bool addedLemma = false;
+ if( e == EFFORT_FULL && !d_conflict ) {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ //if eqc.getType is string
+ if (eqc.getType().isString()) {
+ //EqcInfo* ei = getOrMakeEqcInfo( eqc, true );
+ //get the constant for the equivalence class
+ //int c_len = ...;
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = (*eqc_i);
+
+ //if n is concat, and
+ //if n has not instantiatied the concat..length axiom
+ //then, add lemma
+ if( n.getKind() == kind::STRING_CONCAT || n.getKind() == kind::CONST_STRING ){
+ if( d_length_inst.find(n)==d_length_inst.end() ){
+ d_length_inst[n] = true;
+ Trace("strings-debug") << "get n: " << n << endl;
+ Node sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for concat lemma" );
+ d_length_intro_vars.push_back( sk );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, n );
+ eq = Rewriter::rewrite(eq);
+ Trace("strings-lemma") << "Strings: Add lemma " << eq << std::endl;
+ d_out->lemma(eq);
+ Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ Node lsum;
+ if( n.getKind() == kind::STRING_CONCAT ){
+ //add lemma
+ std::vector<Node> node_vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
+ node_vec.push_back(lni);
+ }
+ lsum = NodeManager::currentNM()->mkNode( kind::PLUS, node_vec );
+ }else{
+ //add lemma
+ lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
+ }
+ Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
+ ceq = Rewriter::rewrite(ceq);
+ Trace("strings-lemma") << "Strings: Add lemma " << ceq << std::endl;
+ d_out->lemma(ceq);
+ addedLemma = true;
+ }
+ }
+ ++eqc_i;
+ }
+ }
+ ++eqcs_i;
+ }
+ if( !addedLemma ){
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ){
+ addedLemma = checkInductiveEquations();
+ Trace("strings-process") << "Done check inductive equations, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
+ }
+ Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
+}
+
+TheoryStrings::EqcInfo::EqcInfo( context::Context* c ) : d_const_term(c), d_length_term(c), d_cardinality_lem_k(c) {
+
+}
+
+TheoryStrings::EqcInfo * TheoryStrings::getOrMakeEqcInfo( Node eqc, bool doMake ) {
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( eqc );
+ if( eqc_i==d_eqc_info.end() ){
+ if( doMake ){
+ EqcInfo* ei = new EqcInfo( getSatContext() );
+ d_eqc_info[eqc] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*eqc_i).second;
+ }
+}
+
+
+/** Conflict when merging two constants */
+void TheoryStrings::conflict(TNode a, TNode b){
+ Node conflictNode;
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ conflictNode = explain( a.iffNode(b) );
+ } else {
+ conflictNode = explain( a.eqNode(b) );
+ }
+ Debug("strings-conflict") << "CONFLICT: Eq engine conflict : " << conflictNode << std::endl;
+ d_out->conflict( conflictNode );
+ d_conflict = true;
+}
+
+/** called when a new equivalance class is created */
+void TheoryStrings::eqNotifyNewClass(TNode t){
+ if( t.getKind() == kind::CONST_STRING ){
+ EqcInfo * ei =getOrMakeEqcInfo( t, true );
+ ei->d_const_term = t;
+ }
+ if( t.getKind() == kind::STRING_LENGTH ){
+ Trace("strings-debug") << "New length eqc : " << t << std::endl;
+ Node r = d_equalityEngine.getRepresentative(t[0]);
+ EqcInfo * ei = getOrMakeEqcInfo( r, true );
+ ei->d_length_term = t[0];
+ }
+}
+
+/** 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( 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 " << eq << " from " << eq_exp << std::endl;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ }
+ }
+ ++eqc_i;
+ }
+ }
+ }
+}
+
+/** called when two equivalance classes have merged */
+void TheoryStrings::eqNotifyPostMerge(TNode t1, TNode t2) {
+
+}
+
+/** called when two equivalance classes are disequal */
+void TheoryStrings::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+
+}
+
+void TheoryStrings::computeCareGraph(){
+ Theory::computeCareGraph();
+}
+
+void TheoryStrings::doPendingFacts() {
+ int i=0;
+ while( !d_conflict && i<(int)d_pending.size() ){
+ Node fact = d_pending[i];
+ Node exp = d_pending_exp[ fact ];
+ Trace("strings-pending") << "Process pending fact : " << fact << " from " << exp << std::endl;
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ Assert( d_equalityEngine.hasTerm( atom[0] ) );
+ Assert( d_equalityEngine.hasTerm( atom[1] ) );
+ d_equalityEngine.assertEquality( atom, polarity, exp );
+ }else{
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ }
+ i++;
+ }
+ d_pending.clear();
+ d_pending_exp.clear();
+}
+void TheoryStrings::doPendingLemmas() {
+ if( !d_conflict && !d_lemma_cache.empty() ){
+ for( unsigned i=0; i<d_lemma_cache.size(); i++ ){
+ Trace("strings-pending") << "Process pending lemma : " << d_lemma_cache[i] << std::endl;
+ d_out->lemma( d_lemma_cache[i] );
+ }
+ for( std::map< Node, bool >::iterator it = d_pending_req_phase.begin(); it != d_pending_req_phase.end(); ++it ){
+ Trace("strings-pending") << "Require phase : " << it->first << ", polarity = " << it->second << std::endl;
+ d_out->requirePhase( it->first, it->second );
+ }
+ d_lemma_cache.clear();
+ d_pending_req_phase.clear();
+ }
+}
+
+void TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
+ std::vector< std::vector< Node > > &normal_forms, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< Node > &normal_form_src) {
+ // EqcItr
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ) {
+ Node n = (*eqc_i);
+ Trace("strings-process") << "Process term " << n << std::endl;
+ if( n.getKind() == kind::CONST_STRING || n.getKind() == kind::STRING_CONCAT ) {
+ std::vector<Node> nf_n;
+ std::vector<Node> nf_exp_n;
+ if( n.getKind() == kind::CONST_STRING ){
+ if( n!=d_emptyString ) {
+ nf_n.push_back( n );
+ }
+ } else if( n.getKind() == kind::STRING_CONCAT ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node nr = d_equalityEngine.getRepresentative( n[i] );
+ std::vector< Node > nf_temp;
+ std::vector< Node > nf_exp_temp;
+ Trace("strings-process") << "Normalizing subterm " << n[i] << " = " << nr << std::endl;
+ normalizeEquivalenceClass( nr, visited, nf_temp, nf_exp_temp );
+ if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
+ return;
+ }
+ if( nf.size()!=1 || nf[0]!=d_emptyString ) {
+ for( unsigned r=0; r<nf_temp.size(); r++ ) {
+ Assert( nf_temp[r].getKind()!=kind::STRING_CONCAT );
+ }
+ nf_n.insert( nf_n.end(), nf_temp.begin(), nf_temp.end() );
+ }
+ nf_exp_n.insert( nf_exp_n.end(), nf_exp_temp.begin(), nf_exp_temp.end() );
+ if( nr!=n[i] ) {
+ nf_exp_n.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n[i], nr ) );
+ }
+ }
+ }
+ normal_forms.push_back(nf_n);
+ normal_forms_exp.push_back(nf_exp_n);
+ normal_form_src.push_back(n);
+ }
+ /* should we add these?
+ else {
+ //var/sk?
+ std::vector<Node> nf_n;
+ std::vector<Node> nf_exp_n;
+ nf_n.push_back(n);
+ normal_forms.push_back(nf_n);
+ normal_forms_exp.push_back(nf_exp_n);
+ normal_form_src.push_back(n);
+ }*/
+ ++eqc_i;
+ }
+
+ // Test the result
+ if( !normal_forms.empty() ) {
+ Trace("strings-solve") << "--- Normal forms for equivlance class " << eqc << " : " << std::endl;
+ for( unsigned i=0; i<normal_forms.size(); i++ ) {
+ Trace("strings-solve") << "#" << i << " (from " << normal_form_src[i] << ") : ";
+ for( unsigned j=0; j<normal_forms[i].size(); j++ ) {
+ if(j>0) Trace("strings-solve") << ", ";
+ Trace("strings-solve") << normal_forms[i][j];
+ }
+ Trace("strings-solve") << std::endl;
+ Trace("strings-solve") << " Explanation is : ";
+ if(normal_forms_exp[i].size() == 0) {
+ Trace("strings-solve") << "NONE";
+ } else {
+ for( unsigned j=0; j<normal_forms_exp[i].size(); j++ ) {
+ if(j>0) Trace("strings-solve") << " AND ";
+ Trace("strings-solve") << normal_forms_exp[i][j];
+ }
+ }
+ Trace("strings-solve") << std::endl;
+ }
+ }
+}
+//nf_exp is conjunction
+void TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & visited, std::vector< Node > & nf, std::vector< Node > & nf_exp ) {
+ Trace("strings-process") << "Process equivalence class " << eqc << std::endl;
+ if( std::find( visited.begin(), visited.end(), eqc )!=visited.end() ){
+ //nf.push_back( eqc );
+ if( eqc.getKind()==kind::STRING_CONCAT ){
+ for( unsigned i=0; i<eqc.getNumChildren(); i++ ){
+ if( !d_equalityEngine.hasTerm(d_emptyString) || !d_equalityEngine.areEqual( eqc[i], d_emptyString ) ){
+ nf.push_back( eqc[i] );
+ }
+ }
+ }else if( !d_equalityEngine.hasTerm(d_emptyString) || !d_equalityEngine.areEqual( eqc, d_emptyString ) ){
+ nf.push_back( eqc );
+ }
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : already visited." << std::endl;
+ } else if (d_equalityEngine.hasTerm(d_emptyString) && d_equalityEngine.areEqual( eqc, d_emptyString )){
+ //do nothing
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : empty." << std::endl;
+ d_normal_forms[eqc].clear();
+ d_normal_forms_exp[eqc].clear();
+ } else {
+ visited.push_back( eqc );
+ if(d_normal_forms.find(eqc)==d_normal_forms.end() ){
+ //phi => t = s1 * ... * sn
+ // normal form for each non-variable term in this eqc (s1...sn)
+ std::vector< std::vector< Node > > normal_forms;
+ // explanation for each normal form (phi)
+ std::vector< std::vector< Node > > normal_forms_exp;
+ // record terms for each normal form (t)
+ std::vector< Node > normal_form_src;
+ //Get Normal Forms
+ getNormalForms(eqc, visited, nf, normal_forms, normal_forms_exp, normal_form_src);
+ if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
+ return;
+ }
+
+ unsigned i = 0;
+ //unify each normal form > 0 with normal_forms[0]
+ for( unsigned j=1; j<normal_forms.size(); j++ ) {
+
+ Trace("strings-solve") << "Process normal form #0 against #" << j << "..." << std::endl;
+ if( isNormalFormPair( normal_form_src[i], normal_form_src[j] ) ){
+ Trace("strings-solve") << "Already normalized (in cache)." << std::endl;
+ }else{
+ Trace("strings-solve") << "Not in cache." << std::endl;
+ //the current explanation for why the prefix is equal
+ std::vector< Node > curr_exp;
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[j].begin(), normal_forms_exp[j].end() );
+ curr_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, normal_form_src[i], normal_form_src[j] ) );
+ //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality
+ unsigned index_i = 0;
+ unsigned index_j = 0;
+ bool success;
+ do
+ {
+ success = false;
+ //if we are at the end
+ if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
+ if( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() ){
+ //we're done
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ }else{
+ //the remainder must be empty
+ unsigned k = index_i==normal_forms[i].size() ? j : i;
+ unsigned index_k = index_i==normal_forms[i].size() ? index_j : index_i;
+ while(!d_conflict && index_k<normal_forms[k].size()) {
+ //can infer that this string must be empty
+ Node eq_exp;
+ if( curr_exp.empty() ) {
+ eq_exp = d_true;
+ } else if( curr_exp.size() == 1 ) {
+ eq_exp = curr_exp[0];
+ } else {
+ eq_exp = NodeManager::currentNM()->mkNode( kind::AND, curr_exp );
+ }
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, d_emptyString, normal_forms[k][index_k] );
+ Trace("strings-lemma") << "Strings : Infer " << eq << " from " << eq_exp << std::endl;
+ Assert( !d_equalityEngine.areEqual( d_emptyString, normal_forms[k][index_k] ) );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ index_k++;
+ }
+ }
+ }else {
+ Trace("strings-solve-debug") << "Process " << normal_forms[i][index_i] << " ... " << normal_forms[j][index_j] << std::endl;
+ if(areEqual(normal_forms[i][index_i],normal_forms[j][index_j])){
+ Trace("strings-solve-debug") << "Case 1 : strings are equal" << std::endl;
+ //terms are equal, continue
+ if( normal_forms[i][index_i]!=normal_forms[j][index_j] ){
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL,normal_forms[i][index_i],
+ normal_forms[j][index_j]);
+ Trace("strings-solve-debug") << "Add to explanation : " << eq << std::endl;
+ curr_exp.push_back(eq);
+ }
+ index_j++;
+ index_i++;
+ success = true;
+ }else{
+ Node length_term_i = getLength( normal_forms[i][index_i] );
+ Node length_term_j = getLength( normal_forms[j][index_j] );
+ //check if length(normal_forms[i][index]) == length(normal_forms[j][index])
+ if( areEqual(length_term_i, length_term_j) ){
+ Trace("strings-solve-debug") << "Case 2 : string lengths are equal" << std::endl;
+ //length terms are equal, merge equivalence classes if not already done so
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[i][index_i], normal_forms[j][index_j] );
+ std::vector< Node > temp_exp;
+ temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
+ temp_exp.push_back(NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ));
+ Node eq_exp = temp_exp.empty() ? d_true :
+ temp_exp.size() == 1 ? temp_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, temp_exp );
+ Trace("strings-lemma") << "Strings : Infer " << eq << " from " << eq_exp << std::endl;
+ //d_equalityEngine.assertEquality( eq, true, eq_exp );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ return;
+ }else if( ( normal_forms[i][index_i].getKind()!=kind::CONST_STRING && index_i==normal_forms[i].size()-1 ) ||
+ ( normal_forms[j][index_j].getKind()!=kind::CONST_STRING && index_j==normal_forms[j].size()-1 ) ){
+ Trace("strings-solve-debug") << "Case 3 : at endpoint" << std::endl;
+ Node conc;
+ std::vector< Node > antec;
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ std::vector< Node > antec_new_lits;
+ std::vector< Node > eqn;
+ for( unsigned r=0; r<2; r++ ){
+ int index_k = r==0 ? index_i : index_j;
+ int k = r==0 ? i : j;
+ std::vector< Node > eqnc;
+ for( unsigned index_l=index_k; index_l<normal_forms[k].size(); index_l++ ){
+ eqnc.push_back( normal_forms[k][index_l] );
+ }
+ eqn.push_back( mkConcat( eqnc ) );
+ }
+ conc = eqn[0].eqNode( eqn[1] );
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Endpoint" );
+ return;
+ }else{
+ Trace("strings-solve-debug") << "Case 4 : must compare strings" << std::endl;
+ Node conc;
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ //check for loops
+ //Trace("strings-loop") << "Check for loops i,j = " << (index_i+1) << "/" << normal_forms[i].size() << " " << (index_j+1) << "/" << normal_forms[j].size() << std::endl;
+ int has_loop[2] = { -1, -1 };
+ for( unsigned r=0; r<2; r++ ){
+ int index = (r==0 ? index_i : index_j);
+ int other_index = (r==0 ? index_j : index_i );
+ int n_index = (r==0 ? i : j);
+ int other_n_index = (r==0 ? j : i);
+ if( normal_forms[other_n_index][other_index].getKind() != kind::CONST_STRING ) {
+ for( unsigned lp = index+1; lp<normal_forms[n_index].size(); lp++ ){
+ if( normal_forms[n_index][lp]==normal_forms[other_n_index][other_index] ){
+ has_loop[r] = lp;
+ break;
+ }
+ }
+ }
+ }
+ if( has_loop[0]!=-1 || has_loop[1]!=-1 ){
+ int loop_n_index = has_loop[0]!=-1 ? i : j;
+ int other_n_index = has_loop[0]!=-1 ? j : i;
+ int loop_index = has_loop[0]!=-1 ? has_loop[0] : has_loop[1];
+ int index = has_loop[0]!=-1 ? index_i : index_j;
+ int other_index = has_loop[0]!=-1 ? index_j : index_i;
+ Trace("strings-loop") << "Detected possible loop for " << normal_forms[loop_n_index][loop_index];
+ Trace("strings-loop") << " ... " << normal_forms[other_n_index][other_index] << std::endl;
+
+ //we have x * s1 * .... * sm = t1 * ... * tn * x * r1 * ... * rp
+ //check if
+ //t1 * ... * tn = n[loop_n_index][index]....n[loop_n_index][loop_index-1] = y * z
+ // and
+ //s1 * ... * sk = n[other_n_index][other_index+1].....n[other_n_index][k+1] = z * y
+ // for some y,z,k
+
+ Trace("strings-loop") << "Must add lemma." << std::endl;
+ //need to break
+ Node sk_y= NodeManager::currentNM()->mkSkolem( "ysym_$$", normal_forms[i][index_i].getType(), "created for loop detection split" );
+ Node sk_z= NodeManager::currentNM()->mkSkolem( "zsym_$$", normal_forms[i][index_i].getType(), "created for loop detection split" );
+
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ //require that x is non-empty
+ Node x_empty = normal_forms[loop_n_index][loop_index].eqNode( d_emptyString );
+ x_empty = Rewriter::rewrite( x_empty );
+ //if( d_equalityEngine.hasTerm( d_emptyString ) && d_equalityEngine.areDisequal( normal_forms[loop_n_index][loop_index], d_emptyString, true ) ){
+ // antec.push_back( x_empty.negate() );
+ //}else{
+ antec_new_lits.push_back( x_empty.negate() );
+ //}
+ d_pending_req_phase[ x_empty ] = true;
+
+
+ //t1 * ... * tn = y * z
+ std::vector< Node > c1c;
+ //n[loop_n_index][index]....n[loop_n_index][loop_lindex-1]
+ for( int r=index; r<=loop_index-1; r++ ) {
+ c1c.push_back( normal_forms[loop_n_index][r] );
+ }
+ Node conc1 = mkConcat( c1c );
+ conc1 = NodeManager::currentNM()->mkNode( kind::EQUAL, conc1,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk_y, sk_z ) );
+ std::vector< Node > c2c;
+ //s1 * ... * sk = n[other_n_index][other_index+1].....n[other_n_index][k+1]
+ for( int r=other_index+1; r < (int)normal_forms[other_n_index].size(); r++ ) {
+ c2c.push_back( normal_forms[other_n_index][r] );
+ }
+ Node left2 = mkConcat( c2c );
+ std::vector< Node > c3c;
+ c3c.push_back( sk_z );
+ c3c.push_back( sk_y );
+ //r1 * ... * rk = n[loop_n_index][loop_index+1]....n[loop_n_index][loop_index-1]
+ for( int r=loop_index+1; r < (int)normal_forms[loop_n_index].size(); r++ ) {
+ c3c.push_back( normal_forms[loop_n_index][r] );
+ }
+ Node conc2 = NodeManager::currentNM()->mkNode( kind::EQUAL, left2,
+ mkConcat( c3c ) );
+
+ Node sk_y_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_y );
+ //Node sk_z_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_z );
+ //Node len_y_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_y_len, d_zero);
+ //Node len_z_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_z_len, d_zero);
+ //Node len_y_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_y, d_emptyString);
+ //Node zz_imp_yz = NodeManager::currentNM()->mkNode( kind::IMPLIES, len_z_eq_zero, len_y_eq_zero);
+
+ //Node z_neq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_z, d_emptyString).negate();
+ //Node len_x_gt_len_y = NodeManager::currentNM()->mkNode( kind::GT,
+ // NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, normal_forms[other_n_index][other_index]),
+ // sk_y_len );
+ Node ant = mkExplain( antec, antec_new_lits );
+ conc = NodeManager::currentNM()->mkNode( kind::AND, conc1, conc2 );//, x_eq_y_rest );// , z_neq_empty //, len_x_gt_len_y
+
+ //Node x_eq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[other_n_index][other_index], d_emptyString);
+ //conc = NodeManager::currentNM()->mkNode( kind::OR, x_eq_empty, conc );
+
+ //we will be done
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ sendLemma( ant, conc, "Loop" );
+ addInductiveEquation( normal_forms[other_n_index][other_index], sk_y, sk_z, ant, "Loop Induction" );
+ return;
+ }else{
+ Trace("strings-solve-debug") << "No loops detected." << std::endl;
+ if( normal_forms[i][index_i].getKind() == kind::CONST_STRING ||
+ normal_forms[j][index_j].getKind() == kind::CONST_STRING) {
+ unsigned const_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? i : j;
+ unsigned const_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_i : index_j;
+ unsigned nconst_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? j : i;
+ unsigned nconst_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_j : index_i;
+ Node const_str = normal_forms[const_k][const_index_k];
+ Node other_str = normal_forms[nconst_k][nconst_index_k];
+ if( other_str.getKind() == kind::CONST_STRING ) {
+ unsigned len_short = const_str.getConst<String>().size() <= other_str.getConst<String>().size() ? const_str.getConst<String>().size() : other_str.getConst<String>().size();
+ if( const_str.getConst<String>().strncmp(other_str.getConst<String>(), len_short) ) {
+ //same prefix
+ //k is the index of the string that is shorter
+ int k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? i : j;
+ int index_k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_i : index_j;
+ int l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? j : i;
+ int index_l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_j : index_i;
+ Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst<String>().substr(len_short) );
+ Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
+ normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
+ normal_forms[l][index_l] = normal_forms[k][index_k];
+ success = true;
+ } else {
+ //curr_exp is conflict
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Conflict" );
+ return;
+ }
+ } else {
+ Assert( other_str.getKind()!=kind::STRING_CONCAT );
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
+ NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
+ //split the string
+ Node sk = NodeManager::currentNM()->mkSkolem( "ssym_$$", normal_forms[i][index_i].getType(), "created for split" );
+
+ Node eq1 = NodeManager::currentNM()->mkNode( kind::EQUAL, other_str, d_emptyString );
+ Node eq2_m = NodeManager::currentNM()->mkNode( kind::EQUAL, other_str,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, firstChar, sk ) );
+ Node eq2 = eq2_m;//NodeManager::currentNM()->mkNode( kind::AND, eq2_m, sk_len_geq_zero );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ Trace("strings-solve-debug") << "Break normal form constant/variable " << std::endl;
+
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Constant Split" );
+ return;
+ }
+ }else{
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+
+ Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
+ if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
+ antec.push_back( ldeq );
+ }else{
+ antec_new_lits.push_back(ldeq);
+ }
+ Node sk = NodeManager::currentNM()->mkSkolem( "ssym_$$", normal_forms[i][index_i].getType(), "created for split" );
+ Node eq1 = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[i][index_i],
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, normal_forms[j][index_j], sk ) );
+ Node eq2 = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[j][index_j],
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, normal_forms[i][index_i], sk ) );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ // |sk| > 0
+ //Node sk_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ //Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::GT, sk_len, d_zero);
+ Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, d_emptyString).negate();
+ Trace("strings-lemma") << "Strings lemma : " << sk_gt_zero << std::endl;
+ //d_out->lemma(sk_gt_zero);
+ d_lemma_cache.push_back( sk_gt_zero );
+
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Split" );
+ return;
+ }
+ }
+ }
+ }
+ }
+ }while(success);
+ }
+ }
+
+ //construct the normal form
+ if( normal_forms.empty() ){
+ Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
+ nf.push_back( eqc );
+ } else {
+ Trace("strings-solve-debug2") << "just take the first normal form" << std::endl;
+ //just take the first normal form
+ nf.insert( nf.end(), normal_forms[0].begin(), normal_forms[0].end() );
+ nf_exp.insert( nf_exp.end(), normal_forms_exp[0].begin(), normal_forms_exp[0].end() );
+ if( eqc!=normal_form_src[0] ){
+ nf_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, eqc, normal_form_src[0] ) );
+ }
+ Trace("strings-solve-debug2") << "just take the first normal form ... done" << std::endl;
+ }
+ //if( visited.empty() ){
+ //TODO : cache?
+ //}
+ d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), nf.begin(), nf.end() );
+ d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), nf_exp.begin(), nf_exp.end() );
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : returned." << std::endl;
+ }else{
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : already computed." << std::endl;
+ nf.insert( nf.end(), d_normal_forms[eqc].begin(), d_normal_forms[eqc].end() );
+ nf_exp.insert( nf_exp.end(), d_normal_forms_exp[eqc].begin(), d_normal_forms_exp[eqc].end() );
+ }
+ visited.pop_back();
+ }
+}
+
+bool TheoryStrings::normalizeDisequality( Node ni, Node nj ) {
+ //Assert( areDisequal( ni, nj ) );
+ if( d_normal_forms[ni].size()>1 || d_normal_forms[nj].size()>1 ){
+ unsigned index = 0;
+ while( index<d_normal_forms[ni].size() ){
+ Node i = d_normal_forms[ni][index];
+ Node j = d_normal_forms[nj][index];
+ Trace("strings-solve-debug") << "...Processing " << i << " " << j << std::endl;
+ if( !areEqual( i, j ) ){
+ Node li = getLength( i );
+ Node lj = getLength( j );
+ if( !areEqual(li, lj) ){
+ Trace("strings-solve") << "Case 2 : add lemma " << std::endl;
+ //must add lemma
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ antec.push_back( ni.eqNode( nj ).negate() );
+ antec_new_lits.push_back( li.eqNode( lj ) );
+ std::vector< Node > conc;
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "w1sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "w2sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "w3sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk4 = NodeManager::currentNM()->mkSkolem( "w4sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk5 = NodeManager::currentNM()->mkSkolem( "w5sym_$$", ni.getType(), "created for disequality normalization" );
+ Node w1w2w3 = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 );
+ Node w1w4w5 = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk4, sk5 );
+ Node s_eq_w1w2w3 = NodeManager::currentNM()->mkNode( kind::EQUAL, ni, w1w2w3 );
+ conc.push_back( s_eq_w1w2w3 );
+ Node t_eq_w1w4w5 = NodeManager::currentNM()->mkNode( kind::EQUAL, nj, w1w4w5 );
+ conc.push_back( t_eq_w1w4w5 );
+ Node w2_neq_w4 = sk2.eqNode( sk4 ).negate();
+ conc.push_back( w2_neq_w4 );
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational( 1 ) );
+ Node w2_len_one = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2), one);
+ conc.push_back( w2_len_one );
+ Node w4_len_one = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk4), one);
+ conc.push_back( w4_len_one );
+
+ //Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2),
+ // NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk4) );
+ //conc.push_back( eq );
+ sendLemma( mkExplain( antec, antec_new_lits ), NodeManager::currentNM()->mkNode( kind::AND, conc ), "Disequality Normalize" );
+ return true;
+ }else if( areDisequal( i, j ) ){
+ Trace("strings-solve") << "Case 1 : found equal length disequal sub strings " << i << " " << j << std::endl;
+ //we are done
+ return false;
+ }
+ }
+ index++;
+ }
+ Assert( false );
+ }
+ return false;
+}
+
+void TheoryStrings::addNormalFormPair( Node n1, Node n2 ) {
+ if( !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 );
+ Assert( isNormalFormPair( n1, n2 ) );
+ }else{
+ Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
+ }
+
+}
+bool TheoryStrings::isNormalFormPair( Node n1, Node n2 ) {
+ //TODO: modulo equality?
+ return isNormalFormPair2( n1, n2 ) || isNormalFormPair2( n2, n1 );
+}
+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;
+ }
+ }
+ }
+ return false;
+}
+
+bool TheoryStrings::addInductiveEquation( Node x, Node y, Node z, Node exp, const char * c ) {
+ Trace("strings-solve-debug") << "add inductive equation for " << x << " = (" << y << " " << z << ")* " << y << std::endl;
+#ifdef STR_UNROLL_INDUCTION
+ Node w = NodeManager::currentNM()->mkSkolem( "wsym_$$", x.getType(), "created for induction" );
+ Node x_eq_y_w = NodeManager::currentNM()->mkNode( kind::EQUAL, x,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, y, w ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, x_eq_y_w );
+ Trace("strings-lemma") << "Strings " << c << " lemma : " << lem << std::endl;
+ d_lemma_cache.push_back( lem );
+
+ //add initial induction
+ Node lit1 = w.eqNode( d_emptyString );
+ lit1 = Rewriter::rewrite( lit1 );
+ Node wp = NodeManager::currentNM()->mkSkolem( "wpsym_$$", x.getType(), "created for induction" );
+ Node lit2 = w.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, z, y, wp ) );
+ lit2 = Rewriter::rewrite( lit2 );
+ Node split_lem = NodeManager::currentNM()->mkNode( kind::OR, lit1, lit2 );
+ Trace("strings-ind") << "Strings : Lemma " << c << " for unrolling " << split_lem << std::endl;
+ Trace("strings-lemma") << "Strings : Lemma " << c << " for unrolling " << split_lem << std::endl;
+ d_lemma_cache.push_back( split_lem );
+
+ //d_lit_to_decide.push_back( lit1 );
+ d_lit_to_unroll[lit2] = true;
+ d_pending_req_phase[lit1] = true;
+ d_pending_req_phase[lit2] = false;
+
+ x = w;
+ std::vector< Node > skc;
+ skc.push_back( y );
+ skc.push_back( z );
+ y = d_emptyString;
+ z = mkConcat( skc );
+#endif
+
+ NodeListMap::iterator itr_x_y = d_ind_map1.find(x);
+ NodeList* lst1;
+ NodeList* lst2;
+ NodeList* lste;
+ NodeList* lstl;
+ if( itr_x_y == d_ind_map1.end() ) {
+ // add x->y
+ lst1 = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map1.insertDataFromContextMemory( x, lst1 );
+ // add x->z
+ lst2 = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map2.insertDataFromContextMemory( x, lst2 );
+ // add x->exp
+ lste = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map_exp.insertDataFromContextMemory( x, lste );
+ // add x->hasLemma false
+ lstl = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map_lemma.insertDataFromContextMemory( x, lstl );
+ } else {
+ //TODO: x in (yz)*y (exp) vs x in (y1 z1)*y1 (exp1)
+ lst1 = (*itr_x_y).second;
+ lst2 = (*d_ind_map2.find(x)).second;
+ lste = (*d_ind_map_exp.find(x)).second;
+ lstl = (*d_ind_map_lemma.find(x)).second;
+ Trace("strings-solve-debug") << "Already in maps " << x << " = (" << lst1 << " " << lst2 << ")* " << lst1 << std::endl;
+ Trace("strings-solve-debug") << "... with exp = " << lste << std::endl;
+ }
+ lst1->push_back( y );
+ lst2->push_back( z );
+ lste->push_back( exp );
+#ifdef STR_UNROLL_INDUCTION
+ return true;
+#else
+ return false;
+#endif
+}
+
+void TheoryStrings::sendLemma( Node ant, Node conc, const char * c ) {
+ if( conc.isNull() ){
+ d_out->conflict(ant);
+ Trace("strings-conflict") << "CONFLICT : Strings conflict : " << ant << std::endl;
+ d_conflict = true;
+ }else{
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, ant, conc );
+ Trace("strings-lemma") << "Strings " << c << " lemma : " << lem << std::endl;
+ d_lemma_cache.push_back( lem );
+ }
+}
+
+void TheoryStrings::sendSplit( Node a, Node b, const char * c ) {
+ Node eq = a.eqNode( b );
+ eq = Rewriter::rewrite( eq );
+ Node neq = NodeManager::currentNM()->mkNode( kind::NOT, eq );
+ Node lemma_or = NodeManager::currentNM()->mkNode( kind::OR, eq, neq );
+ Trace("strings-lemma") << "Strings " << c << " split lemma : " << lemma_or << std::endl;
+ d_lemma_cache.push_back(lemma_or);
+ d_pending_req_phase[eq] = true;
+}
+
+Node TheoryStrings::mkConcat( std::vector< Node >& c ) {
+ Node cc = c.size()>1 ? NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, c ) : ( c.size()==1 ? c[0] : d_emptyString );
+ return Rewriter::rewrite( cc );
+}
+
+Node TheoryStrings::mkExplain( std::vector< Node >& a, std::vector< Node >& an ) {
+ std::vector< TNode > antec_exp;
+ for( unsigned i=0; i<a.size(); i++ ){
+ Trace("strings-solve-debug") << "Ask for explanation of " << a[i] << std::endl;
+ //assert
+ if(a[i].getKind() == kind::EQUAL) {
+ //assert( hasTerm(a[i][0]) );
+ //assert( hasTerm(a[i][1]) );
+ Assert( areEqual(a[i][0], a[i][1]) );
+ } else if( a[i].getKind()==kind::NOT && a[i][0].getKind()==kind::EQUAL ){
+ Assert( hasTerm(a[i][0][0]) );
+ Assert( hasTerm(a[i][0][1]) );
+ Assert( d_equalityEngine.areDisequal(a[i][0][0], a[i][0][1], true) );
+ }
+ unsigned ps = antec_exp.size();
+ explain(a[i], antec_exp);
+ Trace("strings-solve-debug") << "Done, explanation was : " << std::endl;
+ for( unsigned j=ps; j<antec_exp.size(); j++ ){
+ Trace("strings-solve-debug") << " " << antec_exp[j] << std::endl;
+ }
+ Trace("strings-solve-debug") << std::endl;
+ }
+ for( unsigned i=0; i<an.size(); i++ ){
+ Trace("strings-solve-debug") << "Add to explanation (new literal) " << an[i] << std::endl;
+ antec_exp.push_back(an[i]);
+ }
+ Node ant;
+ if( antec_exp.empty() ) {
+ ant = d_true;
+ } else if( antec_exp.size()==1 ) {
+ ant = antec_exp[0];
+ } else {
+ ant = NodeManager::currentNM()->mkNode( kind::AND, antec_exp );
+ }
+ ant = Rewriter::rewrite( ant );
+ return ant;
+}
+
+bool TheoryStrings::checkNormalForms() {
+ Trace("strings-process") << "Normalize equivalence classes...." << std::endl;
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ for( unsigned t=0; t<2; t++ ){
+ Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl;
+ while( !eqcs2_i.isFinished() ){
+ Node eqc = (*eqcs2_i);
+ bool print = (t==0 && eqc.getType().isString() ) || (t==1 && !eqc.getType().isString() );
+ if (print) {
+ eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ Trace("strings-eqc") << "Eqc( " << eqc << " ) : ";
+ while( !eqc2_i.isFinished() ) {
+ if( (*eqc2_i)!=eqc ){
+ Trace("strings-eqc") << (*eqc2_i) << " ";
+ }
+ ++eqc2_i;
+ }
+ Trace("strings-eqc") << std::endl;
+ }
+ ++eqcs2_i;
+ }
+ Trace("strings-eqc") << std::endl;
+ }
+ Trace("strings-eqc") << std::endl;
+ for( NodeListMap::const_iterator it = d_nf_pairs.begin(); it != d_nf_pairs.end(); ++it ){
+ NodeList* lst = (*it).second;
+ NodeList::const_iterator it2 = lst->begin();
+ Trace("strings-nf") << (*it).first << " has been unified with ";
+ while( it2!=lst->end() ){
+ Trace("strings-nf") << (*it2);
+ ++it2;
+ }
+ Trace("strings-nf") << std::endl;
+ }
+ Trace("strings-nf") << std::endl;
+ Trace("strings-nf") << "Current inductive equations : " << std::endl;
+ for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
+ Node x = (*it).first;
+ NodeList* lst1 = (*it).second;
+ NodeList* lst2 = (*d_ind_map2.find(x)).second;
+ NodeList::const_iterator i1 = lst1->begin();
+ NodeList::const_iterator i2 = lst2->begin();
+ while( i1!=lst1->end() ){
+ Node y = *i1;
+ Node z = *i2;
+ Trace("strings-nf") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " ) * " << y << std::endl;
+ ++i1;
+ ++i2;
+ }
+ }
+
+ bool addedFact;
+ do {
+ Trace("strings-process") << "Check Normal Forms........next round" << std::endl;
+ //calculate normal forms for each equivalence class, possibly adding splitting lemmas
+ d_normal_forms.clear();
+ d_normal_forms_exp.clear();
+ std::map< Node, Node > nf_to_eqc;
+ std::map< Node, Node > eqc_to_exp;
+ d_lemma_cache.clear();
+ d_pending_req_phase.clear();
+ //get equivalence classes
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ Node eqc = eqcs[i];
+ Trace("strings-process") << "- Verify normal forms are the same for " << eqc << std::endl;
+ std::vector< Node > visited;
+ std::vector< Node > nf;
+ std::vector< Node > nf_exp;
+ normalizeEquivalenceClass(eqc, visited, nf, nf_exp);
+ if( d_conflict ){
+ return true;
+ }else if ( d_pending.empty() && d_lemma_cache.empty() ){
+ Node nf_term;
+ if( nf.size()==0 ){
+ nf_term = d_emptyString;
+ }else if( nf.size()==1 ) {
+ nf_term = nf[0];
+ } else {
+ nf_term = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, nf );
+ }
+ nf_term = Rewriter::rewrite( nf_term );
+ Trace("strings-debug") << "Make nf_term_exp..." << std::endl;
+ Node nf_term_exp = nf_exp.empty() ? d_true :
+ nf_exp.size()==1 ? nf_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, nf_exp );
+ if( nf_to_eqc.find(nf_term)!=nf_to_eqc.end() ){
+ //Trace("strings-debug") << "Merge because of normal form : " << eqc << " and " << nf_to_eqc[nf_term] << " both have normal form " << nf_term << std::endl;
+ //two equivalence classes have same normal form, merge
+ Node eq_exp = NodeManager::currentNM()->mkNode( kind::AND, nf_term_exp, eqc_to_exp[nf_to_eqc[nf_term]] );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, eqc, nf_to_eqc[nf_term] );
+ Trace("strings-lemma") << "Strings (by normal forms) : Infer " << eq << " from " << eq_exp << std::endl;
+ //d_equalityEngine.assertEquality( eq, true, eq_exp );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ }else{
+ nf_to_eqc[nf_term] = eqc;
+ eqc_to_exp[eqc] = nf_term_exp;
+ }
+ }
+ Trace("strings-process") << "Done verifying normal forms are the same for " << eqc << std::endl;
+ }
+
+ Trace("strings-nf-debug") << "**** Normal forms are : " << std::endl;
+ for( std::map< Node, Node >::iterator it = nf_to_eqc.begin(); it != nf_to_eqc.end(); ++it ){
+ Trace("strings-nf-debug") << " normal_form(" << it->second << ") = " << it->first << std::endl;
+ }
+ Trace("strings-nf-debug") << std::endl;
+ addedFact = !d_pending.empty();
+ doPendingFacts();
+ } while ( !d_conflict && d_lemma_cache.empty() && addedFact );
+
+
+ //process disequalities between equivalence classes
+ if( !d_conflict && d_lemma_cache.empty() ){
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( eqcs, 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 ";
+ printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ //must ensure that normal forms are disequal
+ for( unsigned j=1; j<cols[i].size(); j++ ){
+ if( !d_equalityEngine.areDisequal( cols[i][0], cols[i][j], false ) ){
+ sendSplit( cols[i][0], cols[i][j], "Disequality Normalization" );
+ break;
+ }else{
+ Trace("strings-solve") << " against ";
+ printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ if( normalizeDisequality( cols[i][0], cols[i][j] ) ){
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //flush pending lemmas
+ if( !d_conflict && !d_lemma_cache.empty() ){
+ doPendingLemmas();
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool TheoryStrings::checkCardinality() {
+ int cardinality = options::stringCharCardinality();
+ Trace("strings-solve-debug2") << "get cardinality: " << cardinality << endl;
+
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( eqcs, cols, lts );
+
+ for( unsigned i = 0; i<cols.size(); ++i ){
+ Node lr = lts[i];
+ Trace("string-cardinality") << "Number of strings with length equal to " << lr << " is " << cols[i].size() << std::endl;
+ // size > c^k
+ double k = std::log( cols[i].size() ) / log((double) cardinality);
+ unsigned int int_k = (unsigned int)k;
+ Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
+ //double c_k = pow ( (double)cardinality, (double)lr );
+ if( cols[i].size() > 1 ) {
+ 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(!d_equalityEngine.areDisequal( *itr1, *itr2, false )) {
+ allDisequal = false;
+ // add split lemma
+ sendSplit( *itr1, *itr2, "Cardinality" );
+ doPendingLemmas();
+ return true;
+ }
+ }
+ }
+ if(allDisequal) {
+ EqcInfo* ei = getOrMakeEqcInfo( lr, true );
+ Trace("string-cardinality") << "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() ){
+ //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 = NodeManager::currentNM()->mkNode( kind::EQUAL, lr, len );
+ vec_node.push_back( len_eq_lr );
+ }
+ }
+ Node antc = NodeManager::currentNM()->mkNode( kind::AND, vec_node );
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
+ Node cons = NodeManager::currentNM()->mkNode( kind::GT, len, k_node );
+ /*
+ sendLemma( antc, cons, "Cardinality" );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( !d_lemma_cache.empty() ){
+ doPendingLemmas();
+ return true;
+ }
+ */
+ Node lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, antc, cons );
+ lemma = Rewriter::rewrite( lemma );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( lemma!=d_true ){
+ Trace("strings-lemma") << "Strings cardinality lemma : " << lemma << std::endl;
+ d_out->lemma(lemma);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+int TheoryStrings::gcd ( int a, int b ) {
+ int c;
+ while ( a != 0 ) {
+ c = a; a = b%a; b = c;
+ }
+ return b;
+}
+
+bool TheoryStrings::checkInductiveEquations() {
+ bool hasEq = false;
+ if(d_ind_map1.size() != 0){
+ Trace("strings-ind") << "We are sat, with these inductive equations : " << std::endl;
+ for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
+ Node x = (*it).first;
+ Trace("strings-ind-debug") << "Check eq for " << x << std::endl;
+ NodeList* lst1 = (*it).second;
+ NodeList* lst2 = (*d_ind_map2.find(x)).second;
+ NodeList* lste = (*d_ind_map_exp.find(x)).second;
+ //NodeList* lstl = (*d_ind_map_lemma.find(x)).second;
+ NodeList::const_iterator i1 = lst1->begin();
+ NodeList::const_iterator i2 = lst2->begin();
+ NodeList::const_iterator ie = lste->begin();
+ //NodeList::const_iterator il = lstl->begin();
+ while( i1!=lst1->end() ){
+ Node y = *i1;
+ Node z = *i2;
+ //Trace("strings-ind-debug") << "Check y=" << y << " , z=" << z << std::endl;
+ //if( il==lstl->end() ) {
+ std::vector< Node > nf_y, nf_z, exp_y, exp_z;
+
+ //getFinalNormalForm( y, nf_y, exp_y);
+ //getFinalNormalForm( z, nf_z, exp_z);
+ //std::vector< Node > vec_empty;
+ //Node nexp_y = mkExplain( exp_y, vec_empty );
+ //Trace("strings-ind-debug") << "Check nexp_y=" << nexp_y << std::endl;
+ //Node nexp_z = mkExplain( exp_z, vec_empty );
+
+ //Node exp = *ie;
+ //Trace("strings-ind-debug") << "Check exp=" << exp << std::endl;
+
+ //exp = NodeManager::currentNM()->mkNode( kind::AND, exp, nexp_y, nexp_z );
+ //exp = Rewriter::rewrite( exp );
+
+ Trace("strings-ind") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " )* " << y << std::endl;
+ /*
+ for( std::vector< Node >::const_iterator itr = nf_y.begin(); itr != nf_y.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << " ++ ";
+ for( std::vector< Node >::const_iterator itr = nf_z.begin(); itr != nf_z.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << " )* ";
+ for( std::vector< Node >::const_iterator itr = nf_y.begin(); itr != nf_y.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << std::endl;
+ */
+ /*
+ Trace("strings-ind") << "Explanation is : " << exp << std::endl;
+ std::vector< Node > nf_yz;
+ nf_yz.insert( nf_yz.end(), nf_y.begin(), nf_y.end() );
+ nf_yz.insert( nf_yz.end(), nf_z.begin(), nf_z.end() );
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( nf_yz, cols, lts );
+ Trace("strings-ind") << "This can be grouped into collections : " << std::endl;
+ for( unsigned j=0; j<cols.size(); j++ ){
+ Trace("strings-ind") << " : ";
+ for( unsigned k=0; k<cols[j].size(); k++ ){
+ Trace("strings-ind") << cols[j][k] << " ";
+ }
+ Trace("strings-ind") << std::endl;
+ }
+ Trace("strings-ind") << std::endl;
+
+ Trace("strings-ind") << "Add length lemma..." << std::endl;
+ std::vector< int > co;
+ co.push_back(0);
+ for(unsigned int k=0; k<lts.size(); ++k) {
+ if(lts[k].isConst() && lts[k].getType().isInteger()) {
+ int len = lts[k].getConst<Rational>().getNumerator().toUnsignedInt();
+ co[0] += cols[k].size() * len;
+ } else {
+ co.push_back( cols[k].size() );
+ }
+ }
+ int g_co = co[0];
+ for(unsigned k=1; k<co.size(); ++k) {
+ g_co = gcd(g_co, co[k]);
+ }
+ Node lemma_len;
+ // both constants
+ Node len_x = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, x );
+ Node sk = NodeManager::currentNM()->mkSkolem( "argsym_$$", NodeManager::currentNM()->integerType(), "created for length inductive lemma" );
+ Node g_co_node = NodeManager::currentNM()->mkConst( CVC4::Rational(g_co) );
+ Node sk_m_gcd = NodeManager::currentNM()->mkNode( kind::MULT, g_co_node, sk );
+ Node len_y = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, y );
+ Node sk_m_g_p_y = NodeManager::currentNM()->mkNode( kind::PLUS, sk_m_gcd, len_y );
+ lemma_len = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_m_g_p_y, len_x );
+ //Node sk_geq_zero = NodeManager::currentNM()->mkNode( kind::GEQ, sk, d_zero );
+ //lemma_len = NodeManager::currentNM()->mkNode( kind::AND, lemma_len, sk_geq_zero );
+ lemma_len = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, lemma_len );
+ Trace("strings-lemma") << "Strings: Add lemma " << lemma_len << std::endl;
+ d_out->lemma(lemma_len);
+ lstl->push_back( d_true );
+ return true;*/
+ //}
+ ++i1;
+ ++i2;
+ ++ie;
+ //++il;
+ if( !d_equalityEngine.hasTerm( d_emptyString ) || !d_equalityEngine.areEqual( y, d_emptyString ) || !d_equalityEngine.areEqual( x, d_emptyString ) ){
+ hasEq = true;
+ }
+ }
+ }
+ }
+ if( hasEq ){
+ Trace("strings-ind") << "It is incomplete." << std::endl;
+ d_out->setIncomplete();
+ }else{
+ Trace("strings-ind") << "We can answer SAT." << std::endl;
+ }
+ return false;
+}
+
+void TheoryStrings::getEquivalenceClasses( std::vector< Node >& eqcs ) {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ) {
+ Node eqc = (*eqcs_i);
+ //if eqc.getType is string
+ if (eqc.getType().isString()) {
+ eqcs.push_back( eqc );
+ }
+ ++eqcs_i;
+ }
+}
+
+void TheoryStrings::getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp ) {
+ if( n!=d_emptyString ){
+ if( n.getKind()==kind::STRING_CONCAT ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getFinalNormalForm( n[i], nf, exp );
+ }
+ }else{
+ Trace("strings-debug") << "Get final normal form " << n << std::endl;
+ Assert( d_equalityEngine.hasTerm( n ) );
+ Node nr = d_equalityEngine.getRepresentative( n );
+ EqcInfo *eqc_n = getOrMakeEqcInfo( nr, false );
+ Node nc = eqc_n ? eqc_n->d_const_term.get() : Node::null();
+ if( !nc.isNull() ){
+ nf.push_back( nc );
+ if( n!=nc ){
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nc ) );
+ }
+ }else{
+ Assert( d_normal_forms.find( nr )!=d_normal_forms.end() );
+ if( d_normal_forms[nr][0]==nr ){
+ Assert( d_normal_forms[nr].size()==1 );
+ nf.push_back( nr );
+ if( n!=nr ){
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nr ) );
+ }
+ }else{
+ for( unsigned i=0; i<d_normal_forms[nr].size(); i++ ){
+ Assert( d_normal_forms[nr][i]!=nr );
+ getFinalNormalForm( d_normal_forms[nr][i], nf, exp );
+ }
+ exp.insert( exp.end(), d_normal_forms_exp[nr].begin(), d_normal_forms_exp[nr].end() );
+ }
+ }
+ Trace("strings-ind-nf") << "The final normal form of " << n << " is " << nf << std::endl;
+ }
+ }
+}
+
+void TheoryStrings::seperateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& cols,
+ std::vector< Node >& lts ) {
+ unsigned leqc_counter = 0;
+ std::map< Node, unsigned > eqc_to_leqc;
+ std::map< unsigned, Node > leqc_to_eqc;
+ std::map< unsigned, std::vector< Node > > eqc_to_strings;
+ for( unsigned i=0; i<n.size(); i++ ){
+ Node eqc = n[i];
+ Assert( d_equalityEngine.getRepresentative(eqc)==eqc );
+ EqcInfo* ei = getOrMakeEqcInfo( eqc, false );
+ Node lt = ei ? ei->d_length_term : Node::null();
+ if( !lt.isNull() ){
+ lt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
+ Node r = d_equalityEngine.getRepresentative( lt );
+ if( eqc_to_leqc.find( r )==eqc_to_leqc.end() ){
+ eqc_to_leqc[r] = leqc_counter;
+ leqc_to_eqc[leqc_counter] = r;
+ leqc_counter++;
+ }
+ eqc_to_strings[ eqc_to_leqc[r] ].push_back( eqc );
+ }else{
+ eqc_to_strings[leqc_counter].push_back( eqc );
+ leqc_counter++;
+ }
+ }
+ for( std::map< unsigned, std::vector< Node > >::iterator it = eqc_to_strings.begin(); it != eqc_to_strings.end(); ++it ){
+ std::vector< Node > vec;
+ vec.insert( vec.end(), it->second.begin(), it->second.end() );
+ lts.push_back( leqc_to_eqc[it->first] );
+ cols.push_back( vec );
+ }
+}
+
+void TheoryStrings::printConcat( std::vector< Node >& n, const char * c ) {
+ for( unsigned i=0; i<n.size(); i++ ){
+ if( i>0 ) Trace(c) << " ++ ";
+ Trace(c) << n[i];
+ }
+}
+
+/*
+Node TheoryStrings::getNextDecisionRequest() {
+ if( d_lit_to_decide_index.get()<d_lit_to_decide.size() ){
+ Node l = d_lit_to_decide[d_lit_to_decide_index.get()];
+ d_lit_to_decide_index.set( d_lit_to_decide_index.get() + 1 );
+ Trace("strings-ind") << "Strings-ind : decide on " << l << std::endl;
+ return l;
+ }else{
+ return Node::null();
+ }
+}
+*/
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
new file mode 100644
index 000000000..6b8144d6e
--- /dev/null
+++ b/src/theory/strings/theory_strings.h
@@ -0,0 +1,244 @@
+/********************* */
+/*! \file theory_strings.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 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 strings
+ **
+ ** Theory of strings.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
+
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+/**
+ * Decision procedure for strings.
+ *
+ */
+
+class TheoryStrings : public Theory {
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ public:
+
+ TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+ ~TheoryStrings();
+
+ void setMasterEqualityEngine(eq::EqualityEngine* eq);
+
+ std::string identify() const { return std::string("TheoryStrings"); }
+
+ Node getRepresentative( Node t );
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ Node getLength( Node t );
+ public:
+
+ void propagate(Effort e);
+ bool propagate(TNode literal);
+ void explain( TNode literal, std::vector<TNode>& assumptions );
+ Node explain( TNode literal );
+
+
+ // NotifyClass for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheoryStrings& d_str;
+ public:
+ NotifyClass(TheoryStrings& t_str): d_str(t_str) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
+ if (value) {
+ return d_str.propagate(equality);
+ } else {
+ // We use only literal triggers so taking not is safe
+ return d_str.propagate(equality.notNode());
+ }
+ }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ return d_str.propagate(predicate);
+ } else {
+ return d_str.propagate(predicate.notNode());
+ }
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
+ if (value) {
+ return d_str.propagate(t1.eqNode(t2));
+ } else {
+ return d_str.propagate(t1.eqNode(t2).notNode());
+ }
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_str.conflict(t1, t2);
+ }
+ void eqNotifyNewClass(TNode t) {
+ Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
+ d_str.eqNotifyNewClass(t);
+ }
+ void eqNotifyPreMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPreMerge(t1, t2);
+ }
+ void eqNotifyPostMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPostMerge(t1, t2);
+ }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
+ d_str.eqNotifyDisequal(t1, t2, reason);
+ }
+ };/* class TheoryStrings::NotifyClass */
+
+ private:
+ /** The notify class */
+ NotifyClass d_notify;
+ /** Equaltity engine */
+ eq::EqualityEngine d_equalityEngine;
+ /** Are we in conflict */
+ context::CDO<bool> d_conflict;
+ std::vector< Node > d_length_intro_vars;
+ Node d_emptyString;
+ Node d_true;
+ Node d_false;
+ Node d_zero;
+ //list of pairs of nodes to merge
+ std::map< Node, Node > d_pending_exp;
+ std::vector< Node > d_pending;
+ std::vector< Node > d_lemma_cache;
+ std::map< Node, bool > d_pending_req_phase;
+ /** inferences */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ //map of pairs of terms that have the same normal form
+ NodeListMap d_nf_pairs;
+ void addNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair2( Node n1, Node n2 );
+
+ NodeListMap d_ind_map1;
+ NodeListMap d_ind_map2;
+ NodeListMap d_ind_map_exp;
+ NodeListMap d_ind_map_lemma;
+ bool addInductiveEquation( Node x, Node y, Node z, Node exp, const char * c );
+
+ //for unrolling inductive equations
+ NodeBoolMap d_lit_to_unroll;
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MODEL GENERATION
+ /////////////////////////////////////////////////////////////////////////////
+ public:
+
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // NOTIFICATIONS
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ void shutdown() { }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MAIN SOLVER
+ /////////////////////////////////////////////////////////////////////////////
+ private:
+ void addSharedTerm(TNode n);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ private:
+ class EqcInfo
+ {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ //constant in this eqc
+ context::CDO< Node > d_const_term;
+ context::CDO< Node > d_length_term;
+ context::CDO< unsigned > d_cardinality_lem_k;
+ };
+ /** map from representatives to information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ EqcInfo * getOrMakeEqcInfo( Node eqc, bool doMake = true );
+ //maintain which concat terms have the length lemma instantiatied
+ std::map< Node, bool > d_length_inst;
+ private:
+ std::map< Node, std::vector< Node > > d_normal_forms;
+ std::map< Node, std::vector< Node > > d_normal_forms_exp;
+ void getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
+ std::vector< std::vector< Node > > &normal_forms, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< Node > &normal_form_src);
+ void normalizeEquivalenceClass( Node n, std::vector< Node > & visited, std::vector< Node > & nf, std::vector< Node > & nf_exp );
+ bool normalizeDisequality( Node n1, Node n2 );
+
+ bool checkNormalForms();
+ bool checkCardinality();
+ bool checkInductiveEquations();
+ int gcd(int a, int b);
+ public:
+ void preRegisterTerm(TNode n);
+ void check(Effort e);
+
+ /** Conflict when merging two constants */
+ void conflict(TNode a, TNode b);
+ /** called when a new equivalance class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalance classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalance classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+protected:
+ /** compute care graph */
+ void computeCareGraph();
+
+ //do pending merges
+ void doPendingFacts();
+ void doPendingLemmas();
+
+ void sendLemma( Node ant, Node conc, const char * c );
+ void sendSplit( Node a, Node b, const char * c );
+ /** mkConcat **/
+ Node mkConcat( std::vector< Node >& c );
+ /** mkExplain **/
+ Node mkExplain( std::vector< Node >& a, std::vector< Node >& an );
+
+ //get equivalence classes
+ void getEquivalenceClasses( std::vector< Node >& eqcs );
+ //get final normal form
+ void getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp );
+
+ //seperate into collections with equal length
+ void seperateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& col, std::vector< Node >& lts );
+private:
+ void printConcat( std::vector< Node >& n, const char * c );
+};/* class TheoryStrings */
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_H */
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
new file mode 100644
index 000000000..8fa4345e5
--- /dev/null
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file theory_strings_preprocess.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Strings Preprocess
+ **
+ ** Strings Preprocess.
+ **/
+
+#include "theory/strings/theory_strings_preprocess.h"
+#include "expr/kind.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+void StringsPreprocess::simplifyRegExp( Node s, Node r, std::vector< Node > &ret ) {
+ int k = r.getKind();
+ switch( k ) {
+ case kind::STRING_TO_REGEXP:
+ {
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, s, r[0] );
+ ret.push_back( eq );
+ }
+ break;
+ case kind::REGEXP_CONCAT:
+ {
+ std::vector< Node > cc;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node sk = NodeManager::currentNM()->mkSkolem( "recsym_$$", s.getType(), "created for regular expression concat" );
+ simplifyRegExp( sk, r[i], ret );
+ cc.push_back( sk );
+ }
+ Node cc_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, s,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, cc ) );
+ ret.push_back( cc_eq );
+ }
+ break;
+ case kind::REGEXP_OR:
+ {
+ std::vector< Node > c_or;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ simplifyRegExp( s, r[i], c_or );
+ }
+ Node eq = NodeManager::currentNM()->mkNode( kind::OR, c_or );
+ ret.push_back( eq );
+ }
+ break;
+ case kind::REGEXP_INTER:
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ simplifyRegExp( s, r[i], ret );
+ }
+ break;
+ case kind::REGEXP_STAR:
+ {
+ Node sk = NodeManager::currentNM()->mkSkolem( "ressym_$$", s.getType(), "created for regular expression star" );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, s ),
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, s, sk ));
+ ret.push_back( eq );
+ simplifyRegExp( sk, r[0], ret );
+ }
+ break;
+ case kind::REGEXP_OPT:
+ {
+ Node eq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, s, NodeManager::currentNM()->mkConst( ::CVC4::String("") ) );
+ std::vector< Node > rr;
+ simplifyRegExp( s, r[0], rr );
+ Node nrr = rr.size()==1 ? rr[0] : NodeManager::currentNM()->mkNode( kind::AND, rr );
+ ret.push_back( NodeManager::currentNM()->mkNode( kind::OR, eq_empty, nrr) );
+ }
+ break;
+ default:
+ //TODO:case kind::REGEXP_PLUS:
+ //TODO: special sym: sigma, none, all
+ break;
+ }
+}
+
+Node StringsPreprocess::simplify( Node t ) {
+ std::hash_map<TNode, Node, TNodeHashFunction>::const_iterator i = d_cache.find(t);
+ if(i != d_cache.end()) {
+ return (*i).second.isNull() ? t : (*i).second;
+ }
+
+ if( t.getKind() == kind::STRING_IN_REGEXP ){
+ // t0 in t1
+ //rewrite it
+ std::vector< Node > ret;
+ simplifyRegExp( t[0], t[1], ret );
+
+ Node n = ret.size() == 1 ? ret[0] : NodeManager::currentNM()->mkNode( kind::AND, ret );
+ d_cache[t] = (t == n) ? Node::null() : n;
+ return n;
+ }else if( t.getNumChildren()>0 ){
+ std::vector< Node > cc;
+ if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ cc.push_back(t.getOperator());
+ }
+ bool changed = false;
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node tn = simplify( t[i] );
+ cc.push_back( tn );
+ changed = changed || tn!=t[i];
+ }
+ if(changed) {
+ Node n = NodeManager::currentNM()->mkNode( t.getKind(), cc );
+ d_cache[t] = n;
+ return n;
+ } else {
+ d_cache[t] = Node::null();
+ return t;
+ }
+ }else{
+ d_cache[t] = Node::null();
+ return t;
+ }
+}
+
+void StringsPreprocess::simplify(std::vector< Node > &vec_node) {
+ for( unsigned i=0; i<vec_node.size(); i++ ){
+ vec_node[i] = simplify( vec_node[i] );
+ }
+}
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
new file mode 100644
index 000000000..f82a3cf24
--- /dev/null
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -0,0 +1,44 @@
+/********************* */
+/*! \file theory_strings_preprocess.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Strings Preprocess
+ **
+ ** Strings Preprocess.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__PREPROCESS_H
+#define __CVC4__THEORY__STRINGS__PREPROCESS_H
+
+#include <vector>
+#include "util/hash.h"
+#include "theory/theory.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringsPreprocess {
+ // NOTE: this class is NOT context-dependent
+ std::hash_map<TNode, Node, TNodeHashFunction> d_cache;
+private:
+ void simplifyRegExp( Node s, Node r, std::vector< Node > &ret );
+ Node simplify( Node t );
+public:
+void simplify(std::vector< Node > &vec_node);
+};
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__PREPROCESS_H */
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
new file mode 100644
index 000000000..412135675
--- /dev/null
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -0,0 +1,156 @@
+/********************* */
+/*! \file theory_strings_rewriter.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 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 strings.
+ **
+ ** Implementation of the theory of strings.
+ **/
+#include "theory/strings/theory_strings_rewriter.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::strings;
+
+Node TheoryStringsRewriter::rewriteConcatString(TNode node) {
+ Trace("strings-prerewrite") << "Strings::rewriteConcatString start " << node << std::endl;
+ Node retNode = node;
+ std::vector<Node> node_vec;
+ Node preNode = Node::null();
+ for(unsigned int i=0; i<node.getNumChildren(); ++i) {
+ Node tmpNode = node[i];
+ if(node[i].getKind() == kind::STRING_CONCAT) {
+ tmpNode = rewriteConcatString(node[i]);
+ if(tmpNode.getKind() == kind::STRING_CONCAT) {
+ unsigned int j=0;
+ if(!preNode.isNull()) {
+ if(tmpNode[0].isConst()) {
+ preNode = NodeManager::currentNM()->mkConst( preNode.getConst<String>().concat( tmpNode[0].getConst<String>() ) );
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ ++j;
+ } else {
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ node_vec.push_back( tmpNode[0] );
+ ++j;
+ }
+ }
+ for(; j<tmpNode.getNumChildren() - 1; ++j) {
+ node_vec.push_back( tmpNode[j] );
+ }
+ tmpNode = tmpNode[j];
+ }
+ }
+ if(!tmpNode.isConst()) {
+ if(preNode != Node::null()) {
+ if(preNode.getKind() == kind::CONST_STRING && preNode.getConst<String>().toString()=="" ) {
+ preNode = Node::null();
+ } else {
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ }
+ }
+ node_vec.push_back( tmpNode );
+ } else {
+ if(preNode.isNull()) {
+ preNode = tmpNode;
+ } else {
+ preNode = NodeManager::currentNM()->mkConst( preNode.getConst<String>().concat( tmpNode.getConst<String>() ) );
+ }
+ }
+ }
+ if(preNode != Node::null()) {
+ node_vec.push_back( preNode );
+ }
+ if(node_vec.size() > 1) {
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, node_vec);
+ } else {
+ retNode = node_vec[0];
+ }
+ Trace("strings-prerewrite") << "Strings::rewriteConcatString end " << retNode << std::endl;
+ return retNode;
+}
+
+RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
+ Trace("strings-postrewrite") << "Strings::postRewrite start " << node << std::endl;
+ Node retNode = node;
+
+ if(node.getKind() == kind::STRING_CONCAT) {
+ retNode = rewriteConcatString(node);
+ } else if(node.getKind() == kind::EQUAL) {
+ Node leftNode = node[0];
+ if(node[0].getKind() == kind::STRING_CONCAT) {
+ leftNode = rewriteConcatString(node[0]);
+ }
+ Node rightNode = node[1];
+ if(node[1].getKind() == kind::STRING_CONCAT) {
+ rightNode = rewriteConcatString(node[1]);
+ }
+
+ if(leftNode == rightNode) {
+ retNode = NodeManager::currentNM()->mkConst(true);
+ } else if(leftNode.isConst() && rightNode.isConst()) {
+ retNode = NodeManager::currentNM()->mkConst(false);
+ } else if(leftNode > rightNode) {
+ retNode = NodeManager::currentNM()->mkNode(kind::EQUAL, rightNode, leftNode);
+ } else if( leftNode != node[0] || rightNode != node[1]) {
+ retNode = NodeManager::currentNM()->mkNode(kind::EQUAL, leftNode, rightNode);
+ }
+ } else if(node.getKind() == kind::STRING_IN_REGEXP) {
+ Node leftNode = node[0];
+ if(node[0].getKind() == kind::STRING_CONCAT) {
+ leftNode = rewriteConcatString(node[0]);
+ }
+ // TODO: right part
+ Node rightNode = node[1];
+ // merge
+ if( leftNode != node[0] || rightNode != node[1]) {
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, leftNode, rightNode);
+ }
+ } else if(node.getKind() == kind::STRING_LENGTH) {
+ if(node[0].isConst()) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( node[0].getConst<String>().size() ) );
+ } else if(node[0].getKind() == kind::STRING_CONCAT) {
+ Node tmpNode = rewriteConcatString(node[0]);
+ if(tmpNode.isConst()) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode.getConst<String>().size() ) );
+ } else {
+ // it has to be string concat
+ std::vector<Node> node_vec;
+ for(unsigned int i=0; i<tmpNode.getNumChildren(); ++i) {
+ if(tmpNode[i].isConst()) {
+ node_vec.push_back( NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode[i].getConst<String>().size() ) ) );
+ } else {
+ node_vec.push_back( NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, tmpNode[i]) );
+ }
+ }
+ retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
+ }
+ }
+ }
+
+ Trace("strings-postrewrite") << "Strings::postRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, retNode);
+}
+
+RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) {
+ Node retNode = node;
+ Trace("strings-prerewrite") << "Strings::preRewrite start " << node << std::endl;
+
+ if(node.getKind() == kind::STRING_CONCAT) {
+ retNode = rewriteConcatString(node);
+ }
+
+ Trace("strings-prerewrite") << "Strings::preRewrite returning " << retNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, retNode);
+}
diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h
new file mode 100644
index 000000000..3bccd91de
--- /dev/null
+++ b/src/theory/strings/theory_strings_rewriter.h
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file theory_strings_rewriter.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 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__STRINGS__THEORY_STRINGS_REWRITER_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/type_enumerator.h"
+#include "expr/attribute.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class TheoryStringsRewriter {
+
+public:
+ static Node rewriteConcatString(TNode node);
+
+ static RewriteResponse postRewrite(TNode node);
+
+ static RewriteResponse preRewrite(TNode node);
+
+ static inline void init() {}
+ static inline void shutdown() {}
+
+};/* class TheoryStringsRewriter */
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_REWRITER_H */
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
new file mode 100644
index 000000000..8fc630206
--- /dev/null
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -0,0 +1,223 @@
+/********************* */
+/*! \file theory_strings_type_rules.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 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 arrays
+ **
+ ** Typing and cardinality rules for the theory of arrays.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringConstantTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return nodeManager->stringType();
+ }
+};
+
+class StringConcatTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms in string concat");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
+class StringLengthTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms in string length");
+ }
+ }
+ return nodeManager->integerType();
+ }
+};
+
+class RegExpConstantTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpConcatTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpOrTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpInterTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpStarTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpPlusTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpOptTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class StringToRegExpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms");
+ }
+ if( (*it).getKind() != kind::CONST_STRING ) {
+ throw TypeCheckingExceptionPrivate(n, "expecting constant string terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many terms");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class StringInRegExpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms");
+ }
+ ++it;
+ t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many terms");
+ }
+
+ return nodeManager->booleanType();
+ }
+};
+
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H */
diff --git a/src/theory/strings/type_enumerator.h b/src/theory/strings/type_enumerator.h
new file mode 100644
index 000000000..3dc12009b
--- /dev/null
+++ b/src/theory/strings/type_enumerator.h
@@ -0,0 +1,130 @@
+/********************* */
+/*! \file type_enumerator.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Enumerators for strings
+ **
+ ** Enumerators for strings.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H
+#define __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H
+
+#include <sstream>
+
+#include "util/regexp.h"
+#include "theory/type_enumerator.h"
+#include "expr/type_node.h"
+#include "expr/kind.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringEnumerator : public TypeEnumeratorBase<StringEnumerator> {
+ std::vector< unsigned > d_data;
+ unsigned d_cardinality;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
+public:
+
+ StringEnumerator(TypeNode type) throw(AssertionException) :
+ TypeEnumeratorBase<StringEnumerator>(type) {
+ Assert(type.getKind() == kind::TYPE_CONSTANT &&
+ type.getConst<TypeConstant>() == STRING_TYPE);
+ d_cardinality = 256;
+ mkCurr();
+ }
+ Node operator*() throw() {
+ return d_curr;
+ }
+ StringEnumerator& operator++() throw() {
+ bool changed = false;
+ do{
+ for(unsigned i=0; i<d_data.size(); ++i) {
+ if( d_data[i] + 1 < d_cardinality ) {
+ ++d_data[i]; changed = true;
+ break;
+ } else {
+ d_data[i] = 0;
+ }
+ }
+
+ if(!changed) {
+ d_data.push_back( 0 );
+ }
+ }while(!changed);
+
+ mkCurr();
+ return *this;
+ }
+
+ bool isFinished() throw() {
+ return d_curr.isNull();
+ }
+
+};/* class StringEnumerator */
+
+
+class StringEnumeratorLength {
+private:
+ unsigned d_cardinality;
+ std::vector< unsigned > d_data;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
+public:
+ StringEnumeratorLength(unsigned length, unsigned card = 256) : d_cardinality(card) {
+ for( unsigned i=0; i<length; i++ ){
+ d_data.push_back( 0 );
+ }
+ mkCurr();
+ }
+
+ Node operator*() throw() {
+ return d_curr;
+ }
+
+ StringEnumeratorLength& operator++() throw() {
+ bool changed = false;
+ for(unsigned i=0; i<d_data.size(); ++i) {
+ if( d_data[i] + 1 < d_cardinality ) {
+ ++d_data[i]; changed = true;
+ break;
+ } else {
+ d_data[i] = 0;
+ }
+ }
+
+ if(!changed) {
+ d_curr = Node::null();
+ }else{
+ mkCurr();
+ }
+ return *this;
+ }
+
+ bool isFinished() throw() {
+ return d_curr.isNull();
+ }
+};
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H */
diff --git a/src/theory/substitutions.cpp b/src/theory/substitutions.cpp
index c12129d01..c4f06e396 100644
--- a/src/theory/substitutions.cpp
+++ b/src/theory/substitutions.cpp
@@ -29,7 +29,7 @@ struct substitution_stack_element {
: node(node), children_added(false) {}
};/* struct substitution_stack_element */
-Node SubstitutionMap::internalSubstitute(TNode t) {
+Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) {
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl;
@@ -50,8 +50,8 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << endl;
// If node already in the cache we're done, pop from the stack
- NodeCache::iterator find = d_substitutionCache.find(current);
- if (find != d_substitutionCache.end()) {
+ NodeCache::iterator find = cache.find(current);
+ if (find != cache.end()) {
toVisit.pop_back();
continue;
}
@@ -59,7 +59,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (!d_substituteUnderQuantifiers &&
(current.getKind() == kind::FORALL || current.getKind() == kind::EXISTS)) {
Debug("substitution::internal") << "--not substituting under quantifier" << endl;
- d_substitutionCache[current] = current;
+ cache[current] = current;
toVisit.pop_back();
continue;
}
@@ -68,9 +68,9 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (find2 != d_substitutions.end()) {
Node rhs = (*find2).second;
Assert(rhs != current);
- internalSubstitute(rhs);
- d_substitutions[current] = d_substitutionCache[rhs];
- d_substitutionCache[current] = d_substitutionCache[rhs];
+ internalSubstitute(rhs, cache);
+ d_substitutions[current] = cache[rhs];
+ cache[current] = cache[rhs];
toVisit.pop_back();
continue;
}
@@ -80,17 +80,17 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
// Children have been processed, so substitute
NodeBuilder<> builder(current.getKind());
if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
- builder << Node(d_substitutionCache[current.getOperator()]);
+ builder << Node(cache[current.getOperator()]);
}
for (unsigned i = 0; i < current.getNumChildren(); ++ i) {
- Assert(d_substitutionCache.find(current[i]) != d_substitutionCache.end());
- builder << Node(d_substitutionCache[current[i]]);
+ Assert(cache.find(current[i]) != cache.end());
+ builder << Node(cache[current[i]]);
}
// Mark the substitution and continue
Node result = builder;
if (result != current) {
- find = d_substitutionCache.find(result);
- if (find != d_substitutionCache.end()) {
+ find = cache.find(result);
+ if (find != cache.end()) {
result = find->second;
}
else {
@@ -98,15 +98,15 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (find2 != d_substitutions.end()) {
Node rhs = (*find2).second;
Assert(rhs != result);
- internalSubstitute(rhs);
- d_substitutions[result] = d_substitutionCache[rhs];
- d_substitutionCache[result] = d_substitutionCache[rhs];
- result = d_substitutionCache[rhs];
+ internalSubstitute(rhs, cache);
+ d_substitutions[result] = cache[rhs];
+ cache[result] = cache[rhs];
+ result = cache[rhs];
}
}
}
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl;
- d_substitutionCache[current] = result;
+ cache[current] = result;
toVisit.pop_back();
} else {
// Mark that we have added the children if any
@@ -115,34 +115,33 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
// We need to add the operator, if any
if(current.getMetaKind() == kind::metakind::PARAMETERIZED) {
TNode opNode = current.getOperator();
- NodeCache::iterator opFind = d_substitutionCache.find(opNode);
- if (opFind == d_substitutionCache.end()) {
+ NodeCache::iterator opFind = cache.find(opNode);
+ if (opFind == cache.end()) {
toVisit.push_back(opNode);
}
}
// We need to add the children
for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) {
TNode childNode = *child_it;
- NodeCache::iterator childFind = d_substitutionCache.find(childNode);
- if (childFind == d_substitutionCache.end()) {
+ NodeCache::iterator childFind = cache.find(childNode);
+ if (childFind == cache.end()) {
toVisit.push_back(childNode);
}
}
} else {
// No children, so we're done
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl;
- d_substitutionCache[current] = current;
+ cache[current] = current;
toVisit.pop_back();
}
}
}
// Return the substituted version
- return d_substitutionCache[t];
+ return cache[t];
}/* SubstitutionMap::internalSubstitute() */
- /*
void SubstitutionMap::simplifyRHS(const SubstitutionMap& subMap)
{
// Put the new substitutions into the old ones
@@ -160,10 +159,10 @@ void SubstitutionMap::simplifyRHS(TNode x, TNode t) {
tempCache[x] = t;
// Put the new substitution into the old ones
- NodeMap::iterator it = d_substitutionsOld.begin();
- NodeMap::iterator it_end = d_substitutionsOld.end();
+ NodeMap::iterator it = d_substitutions.begin();
+ NodeMap::iterator it_end = d_substitutions.end();
for(; it != it_end; ++ it) {
- d_substitutionsOld[(*it).first] = internalSubstituteOld((*it).second, tempCache);
+ d_substitutions[(*it).first] = internalSubstitute((*it).second, tempCache);
}
// it = d_substitutionsLazy.begin();
// it_end = d_substitutionsLazy.end();
@@ -171,7 +170,7 @@ void SubstitutionMap::simplifyRHS(TNode x, TNode t) {
// d_substitutionsLazy[(*it).first] = internalSubstitute((*it).second, tempCache);
// }
}
-*/
+
/* We use subMap to simplify the left-hand sides of the current substitution map. If rewrite is true,
* we also apply the rewriter to the result.
@@ -283,6 +282,24 @@ void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache)
}
}
+
+void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache)
+{
+ SubstitutionMap::NodeMap::const_iterator it = subMap.begin();
+ SubstitutionMap::NodeMap::const_iterator it_end = subMap.end();
+ for (; it != it_end; ++ it) {
+ Assert(d_substitutions.find((*it).first) == d_substitutions.end());
+ d_substitutions[(*it).first] = (*it).second;
+ if (!invalidateCache) {
+ d_substitutionCache[(*it).first] = d_substitutions[(*it).first];
+ }
+ }
+ if (invalidateCache) {
+ d_cacheInvalidated = true;
+ }
+}
+
+
static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) CVC4_UNUSED;
static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) {
SubstitutionMap::NodeMap::const_iterator it = substitutions.begin();
@@ -311,7 +328,7 @@ Node SubstitutionMap::apply(TNode t) {
}
// Perform the substitution
- Node result = internalSubstitute(t);
+ Node result = internalSubstitute(t, d_substitutionCache);
Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl;
// Assert(check(result, d_substitutions));
diff --git a/src/theory/substitutions.h b/src/theory/substitutions.h
index bde7dfdbc..5a478a250 100644
--- a/src/theory/substitutions.h
+++ b/src/theory/substitutions.h
@@ -68,8 +68,11 @@ private:
/** Has the cache been invalidated? */
bool d_cacheInvalidated;
+ /** Whether to keep substitutions in solved form */
+ bool d_solvedForm;
+
/** Internal method that performs substitution */
- Node internalSubstitute(TNode t);
+ Node internalSubstitute(TNode t, NodeCache& cache);
/** Helper class to invalidate cache on user pop */
class CacheInvalidator : public context::ContextNotifyObj {
@@ -98,13 +101,15 @@ private:
public:
- SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true) :
+ SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true, bool solvedForm = false) :
d_context(context),
d_substitutions(context),
d_substitutionCache(),
d_substituteUnderQuantifiers(substituteUnderQuantifiers),
d_cacheInvalidated(false),
- d_cacheInvalidator(context, d_cacheInvalidated) {
+ d_solvedForm(solvedForm),
+ d_cacheInvalidator(context, d_cacheInvalidated)
+ {
}
/**
@@ -113,6 +118,11 @@ public:
void addSubstitution(TNode x, TNode t, bool invalidateCache = true);
/**
+ * Merge subMap into current set of substitutions
+ */
+ void addSubstitutions(SubstitutionMap& subMap, bool invalidateCache = true);
+
+ /**
* Returns true iff x is in the substitution map
*/
bool hasSubstitution(TNode x) const {
@@ -170,13 +180,13 @@ public:
// should best interact with cache invalidation on context
// pops.
- /*
// Simplify right-hand sides of current map using the given substitutions
void simplifyRHS(const SubstitutionMap& subMap);
// Simplify right-hand sides of current map with lhs -> rhs
void simplifyRHS(TNode lhs, TNode rhs);
+ /*
// Simplify left-hand sides of current map using the given substitutions
void simplifyLHS(const SubstitutionMap& subMap,
std::vector<std::pair<Node,Node> >& equalities,
@@ -188,6 +198,8 @@ public:
bool rewrite = true);
*/
+ bool isSolvedForm() const { return d_solvedForm; }
+
/**
* Print to the output stream
*/
diff --git a/src/theory/term_registration_visitor.cpp b/src/theory/term_registration_visitor.cpp
index 48d00130c..558975a72 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -127,15 +127,6 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
Assert(alreadyVisited(current, parent));
}
-void PreRegisterVisitor::start(TNode node) {
- d_multipleTheories = false;
-}
-
-bool PreRegisterVisitor::done(TNode node) {
- // We have multiple theories if removing the node theory from others is non-empty
- return Theory::setRemove(Theory::theoryOf(node), d_theories);
-}
-
std::string SharedTermsVisitor::toString() const {
std::stringstream ss;
TNodeVisitedMap::const_iterator it = d_visited.begin();
diff --git a/src/theory/term_registration_visitor.h b/src/theory/term_registration_visitor.h
index 768508d2c..478e82d19 100644
--- a/src/theory/term_registration_visitor.h
+++ b/src/theory/term_registration_visitor.h
@@ -55,25 +55,19 @@ class PreRegisterVisitor {
theory::Theory::Set d_theories;
/**
- * Is true if the term we're traversing involves multiple theories.
- */
- bool d_multipleTheories;
-
- /**
* String representation of the visited map, for debugging purposes.
*/
std::string toString() const;
public:
- /** Return type tells us if there are more than one theory or not */
- typedef bool return_type;
+ /** Returned set tells us which theories there are */
+ typedef theory::Theory::Set return_type;
PreRegisterVisitor(TheoryEngine* engine, context::Context* context)
: d_engine(engine)
, d_visited(context)
, d_theories(0)
- , d_multipleTheories(false)
{}
/**
@@ -89,13 +83,12 @@ public:
/**
* Marks the node as the starting literal.
*/
- void start(TNode node);
+ void start(TNode node) { }
/**
* Notifies the engine of all the theories used.
*/
- bool done(TNode node);
-
+ theory::Theory::Set done(TNode node) { return d_theories; }
};
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index 9ed20cc99..9a23d5518 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -17,6 +17,7 @@
#include "theory/theory.h"
#include "util/cvc4_assert.h"
#include "theory/quantifiers_engine.h"
+#include "theory/substitutions.h"
#include <vector>
@@ -28,9 +29,6 @@ namespace theory {
/** Default value for the uninterpreted sorts is the UF theory */
TheoryId Theory::s_uninterpretedSortOwner = THEORY_UF;
-/** By default, we use the type based theoryOf */
-TheoryOfMode Theory::s_theoryOfMode = THEORY_OF_TYPE_BASED;
-
std::ostream& operator<<(std::ostream& os, Theory::Effort level){
switch(level){
case Theory::EFFORT_STANDARD:
@@ -72,7 +70,7 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) {
// Variables
if (node.isVar()) {
if (theoryOf(node.getType()) != theory::THEORY_BOOL) {
- // We treat the varibables as uninterpreted
+ // We treat the variables as uninterpreted
return s_uninterpretedSortOwner;
} else {
// Except for the Boolean ones, which we just ignore anyhow
@@ -209,5 +207,27 @@ void Theory::computeRelevantTerms(set<Node>& termSet)
}
+Theory::PPAssertStatus Theory::ppAssert(TNode in, SubstitutionMap& outSubstitutions)
+{
+ if (in.getKind() == kind::EQUAL) {
+ if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
+ outSubstitutions.addSubstitution(in[0], in[1]);
+ return PP_ASSERT_STATUS_SOLVED;
+ }
+ if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
+ outSubstitutions.addSubstitution(in[1], in[0]);
+ return PP_ASSERT_STATUS_SOLVED;
+ }
+ if (in[0].isConst() && in[1].isConst()) {
+ if (in[0] != in[1]) {
+ return PP_ASSERT_STATUS_CONFLICT;
+ }
+ }
+ }
+
+ return PP_ASSERT_STATUS_UNSOLVED;
+}
+
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 23fd67b23..21a5aacf5 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -23,9 +23,9 @@
#include "expr/attribute.h"
#include "expr/command.h"
#include "theory/valuation.h"
-#include "theory/substitutions.h"
#include "theory/output_channel.h"
#include "theory/logic_info.h"
+#include "theory/options.h"
#include "theory/theoryof_mode.h"
#include "context/context.h"
#include "context/cdlist.h"
@@ -49,6 +49,7 @@ namespace theory {
class QuantifiersEngine;
class TheoryModel;
+class SubstitutionMap;
namespace rrinst {
class CandidateGenerator;
@@ -298,9 +299,6 @@ protected:
void printFacts(std::ostream& os) const;
void debugPrintFacts() const;
- /** Mode of the theoryOf operation */
- static TheoryOfMode s_theoryOfMode;
-
public:
/**
@@ -333,12 +331,7 @@ public:
* Returns the ID of the theory responsible for the given node.
*/
static inline TheoryId theoryOf(TNode node) {
- return theoryOf(s_theoryOfMode, node);
- }
-
- /** Set the theoryOf mode */
- static void setTheoryOfMode(TheoryOfMode mode) {
- s_theoryOfMode = mode;
+ return theoryOf(options::theoryOfMode(), node);
}
/**
@@ -349,7 +342,7 @@ public:
}
/**
- * Set the owner of the uninterpreted sort.
+ * Get the owner of the uninterpreted sort.
*/
static TheoryId getUninterpretedSortOwner() {
return s_uninterpretedSortOwner;
@@ -516,7 +509,7 @@ public:
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) { return EQUALITY_UNKNOWN; }
/**
- * Return the model value of the give shared term (or null if not avalilable.
+ * Return the model value of the give shared term (or null if not available).
*/
virtual Node getModelValue(TNode var) { return Node::null(); }
@@ -583,25 +576,7 @@ public:
* Given a literal, add the solved substitutions to the map, if any.
* The method should return true if the literal can be safely removed.
*/
- virtual PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
- if (in.getKind() == kind::EQUAL) {
- if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
- outSubstitutions.addSubstitution(in[0], in[1]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
- outSubstitutions.addSubstitution(in[1], in[0]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- if (in[0].isConst() && in[1].isConst()) {
- if (in[0] != in[1]) {
- return PP_ASSERT_STATUS_CONFLICT;
- }
- }
- }
-
- return PP_ASSERT_STATUS_UNSOLVED;
- }
+ virtual PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
/**
* Given an atom of the theory coming from the input formula, this
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 6c8341345..78710e4b9 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -110,6 +110,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_propagationMapTimestamp(context, 0),
d_propagatedLiterals(context),
d_propagatedLiteralsIndex(context, 0),
+ d_atomRequests(context),
d_iteRemover(iteRemover),
d_combineTheoriesTime("TheoryEngine::combineTheoriesTime"),
d_true(),
@@ -186,9 +187,32 @@ void TheoryEngine::preRegister(TNode preprocessed) {
}
// Pre-register the terms in the atom
- bool multipleTheories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
+ Theory::Set theories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
+ theories = Theory::setRemove(THEORY_BOOL, theories);
+ // Remove the top theory, if any more that means multiple theories were involved
+ bool multipleTheories = Theory::setRemove(Theory::theoryOf(preprocessed), theories);
+ TheoryId i;
+ // These checks don't work with finite model finding, because it
+ // uses Rational constants to represent cardinality constraints,
+ // even though arithmetic isn't actually involved.
+ if(!options::finiteModelFind()) {
+ while((i = Theory::setPop(theories)) != THEORY_LAST) {
+ if(!d_logicInfo.isTheoryEnabled(i)) {
+ LogicInfo newLogicInfo = d_logicInfo.getUnlockedCopy();
+ newLogicInfo.enableTheory(i);
+ newLogicInfo.lock();
+ stringstream ss;
+ ss << "The logic was specified as " << d_logicInfo.getLogicString()
+ << ", which doesn't include " << i
+ << ", but found a term in that theory." << endl
+ << "You might want to extend your logic to "
+ << newLogicInfo.getLogicString() << endl;
+ throw LogicException(ss.str());
+ }
+ }
+ }
if (multipleTheories) {
- // Collect the shared terms if there are multipe theories
+ // Collect the shared terms if there are multiple theories
NodeVisitor<SharedTermsVisitor>::run(d_sharedTermsVisitor, preprocessed);
}
}
@@ -204,8 +228,8 @@ void TheoryEngine::printAssertions(const char* tag) {
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
Theory* theory = d_theoryTable[theoryId];
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
- Trace(tag) << "--------------------------------------------" << std::endl;
- Trace(tag) << "Assertions of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "--------------------------------------------" << endl;
+ Trace(tag) << "Assertions of " << theory->getId() << ": " << endl;
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
if ((*it).isPreregistered) {
@@ -217,7 +241,7 @@ void TheoryEngine::printAssertions(const char* tag) {
}
if (d_logicInfo.isSharingEnabled()) {
- Trace(tag) << "Shared terms of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl;
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
Trace(tag) << "[" << i << "]: " << (*it) << endl;
@@ -287,9 +311,7 @@ void TheoryEngine::check(Theory::Effort effort) {
#endif
#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \
-Debug("theory") << "check<" << THEORY << ">" << std::endl; \
theoryOf(THEORY)->check(effort); \
-Debug("theory") << "done<" << THEORY << ">" << std::endl; \
if (d_inConflict) { \
break; \
} \
@@ -305,7 +327,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// Mark the lemmas flag (no lemmas added)
d_lemmasAdded = false;
- Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl;
// If in full effort, we have a fake new assertion just to jumpstart the checking
if (Theory::fullEffort(effort)) {
@@ -315,9 +337,9 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// Check until done
while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) {
- Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl;
- Trace("theory::assertions") << std::endl;
+ Trace("theory::assertions") << endl;
if (Trace.isOn("theory::assertions")) {
printAssertions("theory::assertions");
}
@@ -334,7 +356,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
<< CheckSatCommand();
}
- Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl;
// We are still satisfiable, propagate as much as possible
propagate(effort);
@@ -342,13 +364,14 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// We do combination if all has been processed and we are in fullcheck
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded) {
// Do the combination
- Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
combineTheories();
}
}
// 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);
@@ -365,7 +388,11 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
}
}
- Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas") << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas") << endl;
+
+ if(!d_inConflict && Theory::fullEffort(effort) && d_masterEqualityEngine != NULL && !d_lemmasAdded) {
+ AlwaysAssert(d_masterEqualityEngine->consistent());
+ }
} catch(const theory::Interrupted&) {
Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
@@ -381,7 +408,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
void TheoryEngine::combineTheories() {
- Debug("sharing") << "TheoryEngine::combineTheories()" << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories()" << endl;
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
@@ -399,7 +426,7 @@ void TheoryEngine::combineTheories() {
// Call on each parametric theory to give us its care graph
CVC4_FOR_EACH_THEORY;
- Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl;
// Now add splitters for the ones we are interested in
CareGraph::const_iterator care_it = careGraph.begin();
@@ -407,47 +434,17 @@ void TheoryEngine::combineTheories() {
for (; care_it != care_it_end; ++ care_it) {
const CarePair& carePair = *care_it;
- Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl;
Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst());
Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst());
- //AJR-temp Assert(!d_sharedTerms.areEqual(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
- //AJR-temp Assert(!d_sharedTerms.areDisequal(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
- // The equality in question
- Node equality = carePair.a < carePair.b ?
- carePair.a.eqNode(carePair.b) :
- carePair.b.eqNode(carePair.a);
-
- // Normalize the equality
- Node normalizedEquality = Rewriter::rewrite(equality);
-
- // Check if the normalized equality already has a value (this also
- // covers constants, since they always have values
- if (d_propEngine->isSatLiteral(normalizedEquality)) {
- bool value;
- if (d_propEngine->hasValue(normalizedEquality, value)) {
- Assert(equality != normalizedEquality);
- Node literal = value ? equality : equality.notNode();
- Node normalizedLiteral = value ? normalizedEquality : normalizedEquality.notNode();
- // We're sending the original literal back, backed by the normalized one
- if (markPropagation(literal, normalizedLiteral, /* to */ carePair.theory, /* from */ THEORY_SAT_SOLVER)) {
- // We assert it, and we know it's preregistereed if it's the same theory
- bool preregistered = Theory::theoryOf(literal) == carePair.theory;
- theoryOf(carePair.theory)->assertFact(literal, preregistered);
- // Mark that we have more information
- d_factsAsserted = true;
- continue;
- } else {
- Message() << "mark propagation fail: " << literal << " " << normalizedLiteral << " " << carePair.theory << std::endl;
- Unreachable();
- }
- }
- }
+ // The equality in question (order for no repetition)
+ Node equality = carePair.a.eqNode(carePair.b);
// We need to split on it
- Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << std::endl;
- lemma(equality.orNode(equality.notNode()), false, false);
+ Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << endl;
+ lemma(equality.orNode(equality.notNode()), false, false, carePair.theory);
}
}
@@ -471,15 +468,19 @@ void TheoryEngine::propagate(Theory::Effort effort) {
CVC4_FOR_EACH_THEORY;
if(Dump.isOn("missed-t-propagations")) {
- for(unsigned i = 0; i < d_possiblePropagations.size(); ++ i) {
+ for(unsigned i = 0; i < d_possiblePropagations.size(); ++i) {
Node atom = d_possiblePropagations[i];
bool value;
- if (!d_propEngine->hasValue(atom, value)) continue;
+ if(d_propEngine->hasValue(atom, value)) {
+ continue;
+ }
// Doesn't have a value, check it (and the negation)
if(d_hasPropagated.find(atom) == d_hasPropagated.end()) {
Dump("missed-t-propagations")
<< CommentCommand("Completeness check for T-propagations; expect invalid")
+ << EchoCommand(atom.toString())
<< QueryCommand(atom.toExpr())
+ << EchoCommand(atom.notNode().toString())
<< QueryCommand(atom.notNode().toExpr());
}
}
@@ -600,12 +601,12 @@ void TheoryEngine::collectModelInfo( theory::TheoryModel* m, bool fullModel ){
/* get model */
TheoryModel* TheoryEngine::getModel() {
- Debug("model") << "TheoryEngine::getModel()" << std::endl;
+ Debug("model") << "TheoryEngine::getModel()" << endl;
if( d_logicInfo.isQuantified() ) {
- Debug("model") << "Get model from quantifiers engine." << std::endl;
+ Debug("model") << "Get model from quantifiers engine." << endl;
return d_quantEngine->getModel();
} else {
- Debug("model") << "Get default model." << std::endl;
+ Debug("model") << "Get default model." << endl;
return d_curr_model;
}
}
@@ -879,11 +880,11 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
PropagationMap::const_iterator find = d_propagationMap.find(toAssert);
if (find != d_propagationMap.end()) {
// The theory already knows this
- Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl;
return false;
}
- Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl;
// Mark the propagation
d_propagationMap[toAssert] = toExplain;
@@ -893,9 +894,9 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
}
-void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
+void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
- Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << endl;
Assert(toTheoryId != fromTheoryId);
if(! d_logicInfo.isTheoryEnabled(toTheoryId) &&
@@ -915,6 +916,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// If sharing is disabled, things are easy
if (!d_logicInfo.isSharingEnabled()) {
+ Assert(assertion == originalAssertion);
if (fromTheoryId == THEORY_SAT_SOLVER) {
// Send to the apropriate theory
theory::Theory* toTheory = theoryOf(toTheoryId);
@@ -928,7 +930,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
bool value;
if (d_propEngine->hasValue(assertion, value)) {
if (!value) {
- Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict" << std::endl;
+ Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict" << endl;
d_inConflict = true;
} else {
return;
@@ -948,7 +950,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// If sending to the shared terms database, it's also simple
if (toTheoryId == THEORY_BUILTIN) {
Assert(atom.getKind() == kind::EQUAL, "atom should be an EQUALity, not `%s'", atom.toString().c_str());
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
d_sharedTerms.assertEquality(atom, polarity, assertion);
}
return;
@@ -958,9 +960,11 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// directly to the apropriate theory
if (fromTheoryId == THEORY_SAT_SOLVER) {
// We know that this is normalized, so just send it off to the theory
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
- // We assert it, and we know it's preregistereed coming from the SAT solver directly
- theoryOf(toTheoryId)->assertFact(assertion, true);
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
+ // Is it preregistered
+ bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
+ // We assert it
+ theoryOf(toTheoryId)->assertFact(assertion, preregistered);
// Mark that we have more information
d_factsAsserted = true;
}
@@ -970,7 +974,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// Propagations to the SAT solver are just enqueued for pickup by
// the SAT solver later
if (toTheoryId == THEORY_SAT_SOLVER) {
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
// Enqueue for propagation to the SAT solver
d_propagatedLiterals.push_back(assertion);
// Check for propositional conflicts
@@ -982,18 +986,16 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
return;
}
- // See if it rewrites to true or false directly
+ Assert(atom.getKind() == kind::EQUAL);
+
+ // Normalize
Node normalizedLiteral = Rewriter::rewrite(assertion);
+
+ // See if it rewrites false directly -> conflict
if (normalizedLiteral.isConst()) {
- if (normalizedLiteral.getConst<bool>()) {
- // trivially true, but theories need to share even trivially true facts
- // unless of course it is the theory that normalized it
- if (Theory::theoryOf(atom) == toTheoryId) {
- return;
- }
- } else {
+ if (!normalizedLiteral.getConst<bool>()) {
// Mark the propagation for explanations
- if (markPropagation(normalizedLiteral, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(normalizedLiteral, originalAssertion, toTheoryId, fromTheoryId)) {
// Get the explanation (conflict will figure out where it came from)
conflict(normalizedLiteral, toTheoryId);
} else {
@@ -1003,25 +1005,12 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
}
}
- // Normalize to lhs < rhs if not a sat literal
- Assert(atom.getKind() == kind::EQUAL);
- Assert(atom[0] != atom[1]);
-
- Node normalizedAtom = atom;
- if (!d_propEngine->isSatLiteral(normalizedAtom)) {
- Node reverse = atom[1].eqNode(atom[0]);
- if (d_propEngine->isSatLiteral(reverse) || atom[0] > atom[1]) {
- normalizedAtom = reverse;
- }
- }
- Node normalizedAssertion = polarity ? normalizedAtom : normalizedAtom.notNode();
-
// Try and assert (note that we assert the non-normalized one)
- if (markPropagation(normalizedAssertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
// Check if has been pre-registered with the theory
- bool preregistered = d_propEngine->isSatLiteral(normalizedAssertion) && Theory::theoryOf(normalizedAtom) == toTheoryId;
+ bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
// Assert away
- theoryOf(toTheoryId)->assertFact(normalizedAssertion, preregistered);
+ theoryOf(toTheoryId)->assertFact(assertion, preregistered);
d_factsAsserted = true;
}
@@ -1030,7 +1019,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
void TheoryEngine::assertFact(TNode literal)
{
- Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << std::endl;
+ Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl;
d_propEngine->checkTime();
@@ -1067,22 +1056,33 @@ void TheoryEngine::assertFact(TNode literal)
// to the assert the equality to the interested theories
if (atom.getKind() == kind::EQUAL) {
// Assert it to the the owning theory
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
// Shared terms manager will assert to interested theories directly, as the terms become shared
- assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
+
+ // Now, let's check for any atom triggers from lemmas
+ AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom);
+ while (!it.done()) {
+ const AtomRequests::Request& request = it.get();
+ Node toAssert = polarity ? (Node) request.atom : request.atom.notNode();
+ Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal << "): sending requested " << toAssert << endl;
+ assertToTheory(toAssert, literal, request.toTheory, THEORY_SAT_SOLVER);
+ it.next();
+ }
+
} else {
// Not an equality, just assert to the appropriate theory
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
}
} else {
// Assert the fact to the appropriate theory directly
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
}
}
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
- Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << std::endl;
+ Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
d_propEngine->checkTime();
@@ -1101,16 +1101,16 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) {
if (d_propEngine->isSatLiteral(literal)) {
// We propagate SAT literals to SAT
- assertToTheory(literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
}
if (theory != THEORY_BUILTIN) {
// Assert to the shared terms database
- assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
}
} else {
// Just send off to the SAT solver
Assert(d_propEngine->isSatLiteral(literal));
- assertToTheory(literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
}
return !d_inConflict;
@@ -1166,7 +1166,7 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
Node TheoryEngine::getExplanation(TNode node) {
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
TNode atom = polarity ? node : node[0];
@@ -1174,7 +1174,7 @@ Node TheoryEngine::getExplanation(TNode node) {
// If we're not in shared mode, explanations are simple
if (!d_logicInfo.isSharingEnabled()) {
Node explanation = theoryOf(atom)->explain(node);
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
return explanation;
}
@@ -1188,12 +1188,115 @@ Node TheoryEngine::getExplanation(TNode node) {
getExplanation(explanationVector);
Node explanation = mkExplanation(explanationVector);
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
return explanation;
}
-theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable) {
+struct AtomsCollect {
+
+ std::vector<TNode> d_atoms;
+ std::hash_set<TNode, TNodeHashFunction> d_visited;
+
+public:
+
+ typedef void return_type;
+
+ bool alreadyVisited(TNode current, TNode parent) {
+ // Check if already visited
+ d_visited.find(current) != d_visited.end();
+ // Don't visit non-boolean
+ if (!current.getType().isBoolean()) return true;
+ // New node
+ return false;
+ }
+
+ void visit(TNode current, TNode parent) {
+ if (Theory::theoryOf(current) != theory::THEORY_BOOL) {
+ d_atoms.push_back(current);
+ }
+ d_visited.insert(current);
+ }
+
+ void start(TNode node) {}
+ void done(TNode node) {}
+
+ std::vector<TNode> getAtoms() const {
+ return d_atoms;
+ }
+};
+
+void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) {
+ for (unsigned i = 0; i < atoms.size(); ++ i) {
+
+ // Non-equality atoms are either owned by theory or they don't make sense
+ if (atoms[i].getKind() != kind::EQUAL) {
+ continue;
+ }
+
+ // The equality
+ Node eq = atoms[i];
+ // Simple normalization to not repeat stuff
+ if (eq[0] > eq[1]) {
+ eq = eq[1].eqNode(eq[0]);
+ }
+
+ // Rewrite the equality
+ Node eqNormalized = Rewriter::rewrite(atoms[i]);
+
+ Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq << " with nf " << eqNormalized << endl;
+
+ // If the equality is a boolean constant, we send immediately
+ if (eqNormalized.isConst()) {
+ if (eqNormalized.getConst<bool>()) {
+ assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
+ } else {
+ assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
+ }
+ continue;
+ }
+
+ Assert(eqNormalized.getKind() == kind::EQUAL);
+
+
+ // If the normalization did the just flips, keep the flip
+ if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) {
+ eq = eqNormalized;
+ }
+
+ // Check if the equality is already known by the sat solver
+ if (d_propEngine->isSatLiteral(eqNormalized)) {
+ bool value;
+ if (d_propEngine->hasValue(eqNormalized, value)) {
+ if (value) {
+ assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
+ continue;
+ } else {
+ assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER);
+ continue;
+ }
+ }
+ }
+
+ // If the theory is asking about a different form, or the form is ok but if will go to a different theory
+ // then we must figure it out
+ if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) {
+ // If you get eqNormalized, send atoms[i] to atomsTo
+ d_atomRequests.add(eqNormalized, eq, atomsTo);
+ }
+ }
+}
+
+theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, theory::TheoryId atomsTo) {
+
+ // Do we need to check atoms
+ if (atomsTo != theory::THEORY_LAST) {
+ Debug("theory::atoms") << "TheoryEngine::lemma(" << node << ", " << atomsTo << ")" << endl;
+ AtomsCollect collectAtoms;
+ NodeVisitor<AtomsCollect>::run(collectAtoms, node);
+ ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo);
+ }
+
if(Dump.isOn("t-lemmas")) {
Node n = node;
if (negated) {
@@ -1215,6 +1318,18 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
d_iteRemover.run(additionalLemmas, iteSkolemMap);
additionalLemmas[0] = theory::Rewriter::rewrite(additionalLemmas[0]);
+ if(Debug.isOn("lemma-ites")) {
+ Debug("lemma-ites") << "removed ITEs from lemma: " << node << endl;
+ Debug("lemma-ites") << " + now have the following "
+ << additionalLemmas.size() << " lemma(s):" << endl;
+ for(std::vector<Node>::const_iterator i = additionalLemmas.begin();
+ i != additionalLemmas.end();
+ ++i) {
+ Debug("lemma-ites") << " + " << *i << endl;
+ }
+ Debug("lemma-ites") << endl;
+ }
+
// assert to prop engine
d_propEngine->assertLemma(additionalLemmas[0], negated, removable);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
@@ -1249,7 +1364,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
- Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << std::endl;
+ Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << endl;
// Mark that we are in conflict
d_inConflict = true;
@@ -1267,13 +1382,13 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
// Process the explanation
getExplanation(explanationVector);
Node fullConflict = mkExplanation(explanationVector);
- Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << std::endl;
+ Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, true, true);
+ lemma(fullConflict, true, true, THEORY_LAST);
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- lemma(conflict, true, true);
+ lemma(conflict, true, true, THEORY_LAST);
}
}
@@ -1301,9 +1416,9 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// Get the current literal to explain
NodeTheoryPair toExplain = explanationVector[i];
- Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << std::endl;
+ Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
- // If a treu constant or a negation of a false constant we can ignore it
+ // If a true constant or a negation of a false constant we can ignore it
if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) {
++ i;
continue;
@@ -1321,7 +1436,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// If an and, expand it
if (toExplain.node.getKind() == kind::AND) {
- Debug("theory::explain") << "TheoryEngine::explain(): expanding " << toExplain.node << " got from " << toExplain.theory << std::endl;
+ Debug("theory::explain") << "TheoryEngine::explain(): expanding " << toExplain.node << " got from " << toExplain.theory << endl;
for (unsigned k = 0; k < toExplain.node.getNumChildren(); ++ k) {
NodeTheoryPair newExplain(toExplain.node[k], toExplain.theory, toExplain.timestamp);
explanationVector.push_back(newExplain);
@@ -1348,7 +1463,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
} else {
explanation = theoryOf(toExplain.theory)->explain(toExplain.node);
}
- Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << 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);
@@ -1368,7 +1483,7 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
- Trace("te-attr") << "set user attribute " << attr << " " << n << std::endl;
+ Trace("te-attr") << "set user attribute " << attr << " " << n << endl;
if( d_attr_handle.find( attr )!=d_attr_handle.end() ){
for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){
d_attr_handle[attr][i]->setUserAttribute(attr, n);
@@ -1379,7 +1494,7 @@ void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
}
void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) {
- Trace("te-attr") << "Handle user attribute " << attr << " " << t << std::endl;
+ Trace("te-attr") << "Handle user attribute " << attr << " " << t << endl;
std::string str( attr );
d_attr_handle[ str ].push_back( t );
}
@@ -1395,7 +1510,13 @@ void TheoryEngine::checkTheoryAssertionsWithModel() {
++it) {
Node assertion = (*it).assertion;
Node val = getModel()->getValue(assertion);
- Assert(val == d_true);
+ if(val != d_true) {
+ stringstream ss;
+ ss << theoryId << " has an asserted fact that the model doesn't satisfy." << endl
+ << "The fact: " << assertion << endl
+ << "Model value: " << val << endl;
+ InternalError(ss.str());
+ }
}
}
}
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index c21819ea1..53ff4d167 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -28,7 +28,6 @@
#include "prop/prop_engine.h"
#include "context/cdhashset.h"
#include "theory/theory.h"
-#include "theory/substitutions.h"
#include "theory/rewriter.h"
#include "theory/substitutions.h"
#include "theory/shared_terms_database.h"
@@ -46,6 +45,7 @@
#include "theory/unconstrained_simplifier.h"
#include "theory/uf/equality_engine.h"
#include "theory/bv/bv_to_bool.h"
+#include "theory/atom_requests.h"
namespace CVC4 {
@@ -75,6 +75,9 @@ struct NodeTheoryPairHashFunction {
}
};/* struct NodeTheoryPairHashFunction */
+
+
+
namespace theory {
class TheoryModel;
class TheoryEngineModelBuilder;
@@ -271,8 +274,10 @@ class TheoryEngine {
}
void safePoint() throw(theory::Interrupted, AssertionException) {
- if (d_engine->d_interrupted)
+ spendResource();
+ if (d_engine->d_interrupted) {
throw theory::Interrupted();
+ }
}
void conflict(TNode conflictNode) throw(AssertionException) {
@@ -293,7 +298,14 @@ class TheoryEngine {
Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
++ d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable);
+ return d_engine->lemma(lemma, false, removable, theory::THEORY_LAST);
+ }
+
+ theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException) {
+ Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+ return d_engine->lemma(lemma, false, removable, d_theory);
}
void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException) {
@@ -329,6 +341,7 @@ class TheoryEngine {
void spendResource() throw() {
d_engine->spendResource();
}
+
void handleUserAttribute( const char* attr, theory::Theory* t ){
d_engine->handleUserAttribute( attr, t );
}
@@ -430,10 +443,20 @@ class TheoryEngine {
*/
bool d_outputChannelUsed;
+ /** Atom requests from lemmas */
+ AtomRequests d_atomRequests;
+
/**
* Adds a new lemma, returning its status.
+ * @param node the lemma
+ * @param negated should the lemma be asserted negated
+ * @param removable can the lemma be remove (restrictions apply)
+ * @param needAtoms if not THEORY_LAST, then
*/
- theory::LemmaStatus lemma(TNode node, bool negated, bool removable);
+ theory::LemmaStatus lemma(TNode node, bool negated, bool removable, theory::TheoryId atomsTo);
+
+ /** Enusre that the given atoms are send to the given theory */
+ void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
RemoveITE& d_iteRemover;
@@ -535,13 +558,18 @@ private:
context::CDO<bool> d_factsAsserted;
/**
+ * Map from equality atoms to theories that would like to be notified about them.
+ */
+
+
+ /**
* Assert the formula to the given theory.
* @param assertion the assertion to send (not necesserily normalized)
* @param original the assertion as it was sent in from the propagating theory
* @param toTheoryId the theory to assert to
* @param fromTheoryId the theory that sent it
*/
- void assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId);
+ void assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId);
/**
* Marks a theory propagation from a theory to a theory where a
@@ -744,7 +772,7 @@ private:
void dumpAssertions(const char* tag);
/** For preprocessing pass simplifying ITEs */
- ITESimplifier d_iteSimplifier;
+ theory::ITESimplifier d_iteSimplifier;
/** For preprocessing pass simplifying unconstrained expressions */
UnconstrainedSimplifier d_unconstrainedSimp;
diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h
index 237b09bc1..e4921b163 100644
--- a/src/theory/theory_test_utils.h
+++ b/src/theory/theory_test_utils.h
@@ -107,6 +107,11 @@ public:
d_callHistory.clear();
}
+ LemmaStatus splitLemma(TNode n, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException){
+ push(LEMMA, n);
+ return LemmaStatus(Node::null(), 0);
+ }
+
Node getIthNode(int i) {
Node tmp = (d_callHistory[i]).second;
return tmp;
diff --git a/src/theory/theoryof_mode.h b/src/theory/theoryof_mode.h
index cd8c68b1a..c50960257 100644
--- a/src/theory/theoryof_mode.h
+++ b/src/theory/theoryof_mode.h
@@ -14,10 +14,10 @@
** Option selection for theoryOf() operation.
**/
-#pragma once
-
#include "cvc4_public.h"
+#pragma once
+
namespace CVC4 {
namespace theory {
@@ -29,6 +29,18 @@ enum TheoryOfMode {
THEORY_OF_TERM_BASED
};/* enum TheoryOfMode */
+inline std::ostream& operator<<(std::ostream& out, TheoryOfMode m) throw() CVC4_PUBLIC;
+
+inline std::ostream& operator<<(std::ostream& out, TheoryOfMode m) throw() {
+ switch(m) {
+ case THEORY_OF_TYPE_BASED: return out << "THEORY_OF_TYPE_BASED";
+ case THEORY_OF_TERM_BASED: return out << "THEORY_OF_TERM_BASED";
+ default: return out << "TheoryOfMode!UNKNOWN";
+ }
+
+ Unreachable();
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/type_enumerator.h b/src/theory/type_enumerator.h
index 7a4fcdaff..467bf1927 100644
--- a/src/theory/type_enumerator.h
+++ b/src/theory/type_enumerator.h
@@ -98,13 +98,21 @@ public:
~TypeEnumerator() { delete d_te; }
bool isFinished() throw() {
-#ifdef CVC4_ASSERTIONS
+// 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(d_te->isFinished()) {
try {
**d_te;
Assert(false, "expected an NoMoreValuesException to be thrown");
} catch(NoMoreValuesException&) {
// ignore the exception, we're just asserting that it would be thrown
+ //
+ // This block can crash on clang 3.0 on Mac OS, perhaps related to
+ // bug: http://llvm.org/bugs/show_bug.cgi?id=13359
+ //
+ // Hence the #if !(defined(__APPLE__) && defined(__clang__)) above
}
} else {
try {
@@ -113,11 +121,14 @@ public:
Assert(false, "didn't expect a NoMoreValuesException to be thrown");
}
}
-#endif /* CVC4_ASSERTIONS */
+#endif /* CVC4_ASSERTIONS && !(APPLE || clang) */
return d_te->isFinished();
}
Node operator*() throw(NoMoreValuesException) {
-#ifdef CVC4_ASSERTIONS
+// On Mac clang, there appears to be a code generation bug in an exception
+// block above (and perhaps here, too). For now, there doesn't appear a
+// good workaround; just disable assertions on that setup.
+#if defined(CVC4_ASSERTIONS) && !(defined(__APPLE__) && defined(__clang__))
try {
Node n = **d_te;
Assert(n.isConst());
@@ -127,9 +138,9 @@ public:
Assert(isFinished());
throw;
}
-#else /* CVC4_ASSERTIONS */
+#else /* CVC4_ASSERTIONS && !(APPLE || clang) */
return **d_te;
-#endif /* CVC4_ASSERTIONS */
+#endif /* CVC4_ASSERTIONS && !(APPLE || clang) */
}
TypeEnumerator& operator++() throw() { ++*d_te; return *this; }
TypeEnumerator operator++(int) throw() { TypeEnumerator te = *this; ++*d_te; return te; }
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 7f0f79ebc..199581b98 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -1348,7 +1348,7 @@ void EqualityEngine::propagate() {
}
// If not merging internal nodes, notify the master
- if (d_masterEqualityEngine && !d_isInternal[mergeInto]) {
+ if (d_masterEqualityEngine && !d_isInternal[t1classId] && !d_isInternal[t2classId]) {
d_masterEqualityEngine->assertEqualityInternal(d_nodes[t1classId], d_nodes[t2classId], TNode::null());
d_masterEqualityEngine->propagate();
}
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 206fb61c7..8d1b6f1d9 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -211,11 +211,6 @@ public:
}
};/* struct EqualityEngine::statistics */
- /**
- * Store the application lookup, with enough information to backtrack
- */
- void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId);
-
private:
/** The context we are using */
@@ -254,6 +249,11 @@ private:
/** Number of application lookups, for backtracking. */
context::CDO<DefaultSizeType> d_applicationLookupsCount;
+ /**
+ * Store the application lookup, with enough information to backtrack
+ */
+ void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId);
+
/** Map from ids to the nodes (these need to be nodes as we pick up the operators) */
std::vector<Node> d_nodes;
@@ -741,7 +741,7 @@ public:
/**
* Adds a predicate p with given polarity. The predicate asserted
* should be in the congruence closure kinds (otherwise it's
- * useless.
+ * useless).
*
* @param p the (non-negated) predicate
* @param polarity true if asserting the predicate, false if
@@ -777,7 +777,7 @@ public:
void getUseListTerms(TNode t, std::set<TNode>& output);
/**
- * Get an explanation of the equality t1 = t2 begin true of false.
+ * Get an explanation of the equality t1 = t2 being true or false.
* Returns the reasons (added when asserting) that imply it
* in the assertions vector.
*/
diff --git a/src/theory/uf/options b/src/theory/uf/options
index 33d1255ef..b9f60b83d 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -8,6 +8,9 @@ module UF "theory/uf/options.h" Uninterpreted functions theory
option ufSymmetryBreaker uf-symmetry-breaker --symmetry-breaker bool :read-write :default true
use UF symmetry breaker (Deharbe et al., CADE 2011)
+option condenseFunctionValues condense-function-values --condense-function-values bool :default true
+ condense models for functions rather than explicitly representing them
+
option ufssRegions /--disable-uf-ss-regions bool :default true
disable region-based method for discovering cliques and splits in uf strong solver
option ufssEagerSplits --uf-ss-eager-split bool :default false
@@ -20,6 +23,8 @@ option ufssTotalityLimited --uf-ss-totality-limited=N int :default -1
apply totality axioms, but only up to cardinality N (-1 == do not apply totality axioms, default)
option ufssTotalityLazy --uf-ss-totality-lazy bool :default false
apply totality axioms lazily
+option ufssTotalitySymBreak --uf-ss-totality-sym-break bool :default false
+ apply symmetry breaking for totality axioms
option ufssAbortCardinality --uf-ss-abort-card=N int :default -1
tells the uf strong solver a cardinality to abort at (-1 == no limit, default)
option ufssSmartSplits --uf-ss-smart-split bool :default false
@@ -30,5 +35,12 @@ option ufssSimpleCliques --uf-ss-simple-cliques bool :default true
always use simple clique lemmas for uf strong solver
option ufssDiseqPropagation --uf-ss-deq-prop bool :default false
eagerly propagate disequalities for uf strong solver
+option ufssMinimalModel /--disable-uf-ss-min-model bool :default true
+ disable finding a minimal model in uf strong solver
+option ufssCliqueSplits --uf-ss-clique-splits bool :default false
+ use cliques instead of splitting on demand to shrink model
+
+option ufssSymBreak --uf-ss-sym-break bool :default false
+ finite model finding symmetry breaking techniques
endmodule
diff --git a/src/theory/uf/symmetry_breaker.cpp b/src/theory/uf/symmetry_breaker.cpp
index fcb6c3cd5..f5d7f9235 100644
--- a/src/theory/uf/symmetry_breaker.cpp
+++ b/src/theory/uf/symmetry_breaker.cpp
@@ -52,6 +52,8 @@ namespace CVC4 {
namespace theory {
namespace uf {
+using namespace ::CVC4::context;
+
SymmetryBreaker::Template::Template() :
d_template(),
d_sets(),
@@ -165,7 +167,10 @@ void SymmetryBreaker::Template::reset() {
d_reps.clear();
}
-SymmetryBreaker::SymmetryBreaker() :
+SymmetryBreaker::SymmetryBreaker(context::Context* context) :
+ ContextNotifyObj(context),
+ d_assertionsToRerun(context),
+ d_rerunningAssertions(false),
d_phi(),
d_phiSet(),
d_permutations(),
@@ -175,6 +180,31 @@ SymmetryBreaker::SymmetryBreaker() :
d_termEqs() {
}
+class SBGuard {
+ bool& d_ref;
+ bool d_old;
+public:
+ SBGuard(bool& b) : d_ref(b), d_old(b) {}
+ ~SBGuard() { Debug("uf") << "reset to " << d_old << std::endl; d_ref = d_old; }
+};/* class SBGuard */
+
+void SymmetryBreaker::rerunAssertionsIfNecessary() {
+ if(d_rerunningAssertions || !d_phi.empty() || d_assertionsToRerun.empty()) {
+ return;
+ }
+
+ SBGuard g(d_rerunningAssertions);
+ d_rerunningAssertions = true;
+
+ Debug("ufsymm") << "UFSYMM: rerunning assertions..." << std::endl;
+ for(CDList<Node>::const_iterator i = d_assertionsToRerun.begin();
+ i != d_assertionsToRerun.end();
+ ++i) {
+ assertFormula(*i);
+ }
+ Debug("ufsymm") << "UFSYMM: DONE rerunning assertions..." << std::endl;
+}
+
Node SymmetryBreaker::norm(TNode phi) {
Node n = Rewriter::rewrite(phi);
return normInternal(n);
@@ -254,6 +284,10 @@ Node SymmetryBreaker::normInternal(TNode n) {
}
void SymmetryBreaker::assertFormula(TNode phi) {
+ rerunAssertionsIfNecessary();
+ if(!d_rerunningAssertions) {
+ d_assertionsToRerun.push_back(phi);
+ }
// use d_phi, put into d_permutations
Debug("ufsymm") << "UFSYMM assertFormula(): phi is " << phi << endl;
d_phi.push_back(phi);
@@ -322,6 +356,7 @@ void SymmetryBreaker::clear() {
}
void SymmetryBreaker::apply(std::vector<Node>& newClauses) {
+ rerunAssertionsIfNecessary();
guessPermutations();
Debug("ufsymm") << "UFSYMM =====================================================" << endl
<< "UFSYMM have " << d_permutations.size() << " permutation sets" << endl;
diff --git a/src/theory/uf/symmetry_breaker.h b/src/theory/uf/symmetry_breaker.h
index cf54b62c2..d04da048a 100644
--- a/src/theory/uf/symmetry_breaker.h
+++ b/src/theory/uf/symmetry_breaker.h
@@ -50,13 +50,15 @@
#include "expr/node.h"
#include "expr/node_builder.h"
+#include "context/context.h"
+#include "context/cdlist.h"
#include "util/statistics_registry.h"
namespace CVC4 {
namespace theory {
namespace uf {
-class SymmetryBreaker {
+class SymmetryBreaker : public context::ContextNotifyObj {
class Template {
Node d_template;
@@ -92,6 +94,19 @@ public:
private:
+ /**
+ * This class wasn't initially built to be incremental. It should
+ * be attached to a UserContext so that it clears everything when
+ * a pop occurs. This "assertionsToRerun" is a set of assertions to
+ * feed back through assertFormula() when we started getting things
+ * again. It's not just a matter of effectiveness, but also soundness;
+ * if some assertions (still in scope) are not seen by a symmetry-breaking
+ * round, then some symmetries that don't actually exist might be broken,
+ * leading to unsound results!
+ */
+ context::CDList<Node> d_assertionsToRerun;
+ bool d_rerunningAssertions;
+
std::vector<Node> d_phi;
std::set<TNode> d_phiSet;
Permutations d_permutations;
@@ -101,6 +116,7 @@ private:
TermEqs d_termEqs;
void clear();
+ void rerunAssertionsIfNecessary();
void guessPermutations();
bool invariantByPermutations(const Permutation& p);
@@ -140,9 +156,17 @@ private:
d_initNormalizationTimer,
"theory::uf::symmetry_breaker::timers::initNormalization");
+protected:
+
+ void contextNotifyPop() {
+ Debug("ufsymm") << "UFSYMM: clearing state due to pop" << std::endl;
+ clear();
+ }
+
public:
- SymmetryBreaker();
+ SymmetryBreaker(context::Context* context);
+ ~SymmetryBreaker() throw() {}
void assertFormula(TNode phi);
void apply(std::vector<Node>& newClauses);
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 69a963360..41935984f 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -38,7 +38,8 @@ TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel&
d_conflict(c, false),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
- d_functionsTerms(c)
+ d_functionsTerms(c),
+ d_symb(u)
{
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index 228cfd2c4..c0d114052 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -17,6 +17,10 @@
#include "theory/uf/equality_engine.h"
#include "theory/uf/theory_uf.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/options.h"
+
+#include <vector>
+#include <stack>
#define RECONSIDER_FUNC_DEFAULT_VALUE
#define USE_PARTIAL_DEFAULT_VALUES
@@ -133,28 +137,60 @@ Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& inde
}
}
-Node UfModelTreeNode::getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue ){
- if( !d_data.empty() ){
+Node UfModelTreeNode::getFunctionValue(std::vector<Node>& args, int index, Node argDefaultValue, bool simplify) {
+ if(!d_data.empty()) {
Node defaultValue = argDefaultValue;
- if( d_data.find( Node::null() )!=d_data.end() ){
- defaultValue = d_data[Node::null()].getFunctionValue( args, index+1, argDefaultValue );
+ if(d_data.find(Node::null()) != d_data.end()) {
+ defaultValue = d_data[Node::null()].getFunctionValue(args, index + 1, argDefaultValue, simplify);
}
- std::vector< Node > caseArgs;
- std::map< Node, Node > caseValues;
- for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
- if( !it->first.isNull() ){
- Node val = it->second.getFunctionValue( args, index+1, defaultValue );
- caseArgs.push_back( it->first );
- caseValues[ it->first ] = val;
+
+ vector<Node> caseArgs;
+ map<Node, Node> caseValues;
+
+ for(map< Node, UfModelTreeNode>::iterator it = d_data.begin(); it != d_data.end(); ++it) {
+ if(!it->first.isNull()) {
+ Node val = it->second.getFunctionValue(args, index + 1, defaultValue, simplify);
+ caseArgs.push_back(it->first);
+ caseValues[it->first] = val;
}
}
+
+ NodeManager* nm = NodeManager::currentNM();
Node retNode = defaultValue;
- for( int i=((int)caseArgs.size()-1); i>=0; i-- ){
- retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( caseArgs[ i ] ), caseValues[ caseArgs[ i ] ], retNode );
+
+ if(!simplify) {
+ // "non-simplifying" mode - expand function values to things like:
+ // IF (x=0 AND y=0 AND z=0) THEN value1
+ // ELSE IF (x=0 AND y=0 AND z=1) THEN value2
+ // [...etc...]
+ for(int i = (int)caseArgs.size() - 1; i >= 0; --i) {
+ Node val = caseValues[ caseArgs[ i ] ];
+ if(val.getKind() == ITE) {
+ // use a stack to reverse the order, since we're traversing outside-in
+ stack<TNode> stk;
+ do {
+ stk.push(val);
+ val = val[2];
+ } while(val.getKind() == ITE);
+ AlwaysAssert(val == defaultValue, "default values don't match when constructing function definition!");
+ while(!stk.empty()) {
+ val = stk.top();
+ stk.pop();
+ retNode = nm->mkNode(ITE, nm->mkNode(AND, args[index].eqNode(caseArgs[i]), val[0]), val[1], retNode);
+ }
+ } else {
+ retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode);
+ }
+ }
+ } else {
+ // "simplifying" mode - condense function values
+ for(int i = (int)caseArgs.size() - 1; i >= 0; --i) {
+ retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode);
+ }
}
return retNode;
- }else{
- Assert( !d_value.isNull() );
+ } else {
+ Assert(!d_value.isNull());
return d_value;
}
}
@@ -259,14 +295,16 @@ void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector
}
}
-Node UfModelTree::getFunctionValue( std::vector< Node >& args ){
- Node body = d_tree.getFunctionValue( args, 0, Node::null() );
- body = Rewriter::rewrite( body );
+Node UfModelTree::getFunctionValue( std::vector< Node >& args, bool simplify ){
+ Node body = d_tree.getFunctionValue( args, 0, Node::null(), simplify );
+ if(simplify) {
+ body = Rewriter::rewrite( body );
+ }
Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args);
return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, body);
}
-Node UfModelTree::getFunctionValue( const char* argPrefix ){
+Node UfModelTree::getFunctionValue( const char* argPrefix, bool simplify ){
TypeNode type = d_op.getType();
std::vector< Node > vars;
for( size_t i=0; i<type.getNumChildren()-1; i++ ){
@@ -274,7 +312,7 @@ Node UfModelTree::getFunctionValue( const char* argPrefix ){
ss << argPrefix << (i+1);
vars.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] ) );
}
- return getFunctionValue( vars );
+ return getFunctionValue( vars, simplify );
}
Node UfModelTreeGenerator::getIntersection( TheoryModel* m, Node n1, Node n2, bool& isGround ){
@@ -309,19 +347,21 @@ void UfModelTreeGenerator::setValue( TheoryModel* m, Node n, Node v, bool ground
if( !ground ){
int defSize = (int)d_defaults.size();
for( int i=0; i<defSize; i++ ){
- bool isGround;
//for soundness, to allow variable order-independent function interpretations,
// we must ensure that the intersection of all default terms
// is also defined.
//for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
// then we must define f( b, a ).
- Node ni = getIntersection( m, n, d_defaults[i], isGround );
- if( !ni.isNull() ){
- //if the intersection exists, and is not already defined
- if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
- d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
- //use the current value
- setValue( m, ni, v, isGround, false );
+ if (!options::fmfFullModelCheck()) {
+ bool isGround;
+ Node ni = getIntersection( m, n, d_defaults[i], isGround );
+ if( !ni.isNull() ){
+ //if the intersection exists, and is not already defined
+ if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
+ d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
+ //use the current value
+ setValue( m, ni, v, isGround, false );
+ }
}
}
}
diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h
index 12c1cf244..133cd2cf2 100644
--- a/src/theory/uf/theory_uf_model.h
+++ b/src/theory/uf/theory_uf_model.h
@@ -46,7 +46,7 @@ public:
/** getConstant Value function */
Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex );
/** getFunctionValue */
- Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue );
+ Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue, bool simplify = true );
/** update function */
void update( TheoryModel* m );
/** simplify function */
@@ -125,9 +125,9 @@ public:
/** getFunctionValue
* Returns a representation of this function.
*/
- Node getFunctionValue( std::vector< Node >& args );
+ Node getFunctionValue( std::vector< Node >& args, bool simplify = true );
/** getFunctionValue for args with set prefix */
- Node getFunctionValue( const char* argPrefix );
+ Node getFunctionValue( const char* argPrefix, bool simplify = true );
/** update
* This will update all values in the tree to be representatives in m.
*/
@@ -144,18 +144,12 @@ public:
void debugPrint( std::ostream& out, TheoryModel* m, int ind = 0 ){
d_tree.debugPrint( out, m, d_index_order, ind );
}
-private:
- //helper for to ITE function.
- static Node toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode );
-public:
- /** to ITE function for function model nodes */
- static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); }
- static Node toIte( TypeNode type, Node fm_node, const char* argPrefix );
};
+
class UfModelTreeGenerator
{
-private:
+public:
//store for set values
Node d_default_value;
std::map< Node, Node > d_set_values[2][2];
diff --git a/src/theory/uf/theory_uf_rewriter.h b/src/theory/uf/theory_uf_rewriter.h
index 94ab47d23..40713fa41 100644
--- a/src/theory/uf/theory_uf_rewriter.h
+++ b/src/theory/uf/theory_uf_rewriter.h
@@ -21,6 +21,7 @@
#define __CVC4__THEORY__UF__THEORY_UF_REWRITER_H
#include "theory/rewriter.h"
+#include "theory/substitutions.h"
namespace CVC4 {
namespace theory {
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index d64f7df60..163dd3c1f 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -20,6 +20,8 @@
#include "theory/quantifiers/term_database.h"
#include "theory/uf/options.h"
#include "theory/model.h"
+#include "theory/quantifiers/symmetry_breaking.h"
+
//#define ONE_SPLIT_REGION
//#define DISABLE_QUICK_CLIQUE_CHECKS
@@ -117,6 +119,9 @@ void StrongSolverTheoryUF::SortModel::Region::setEqual( Node a, Node b ){
if( options::ufssDiseqPropagation() ){
d_cf->d_thss->getDisequalityPropagator()->assertDisequal(a, n, Node::null());
}
+ if( options::ufssSymBreak() ){
+ d_cf->d_thss->getSymmetryBreaker()->assertDisequal( a, n );
+ }
}
setDisequal( b, n, t, false );
nr->setDisequal( n, b, t, false );
@@ -322,6 +327,20 @@ bool StrongSolverTheoryUF::SortModel::Region::check( Theory::Effort level, int c
return false;
}
+bool StrongSolverTheoryUF::SortModel::Region::getCandidateClique( int cardinality, std::vector< Node >& clique ) {
+ if( d_testCliqueSize>=long(cardinality+1) ){
+ //test clique is a clique
+ for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++it ){
+ if( (*it).second ){
+ clique.push_back( (*it).first );
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
void StrongSolverTheoryUF::SortModel::Region::getRepresentatives( std::vector< Node >& reps ){
for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
RegionNodeInfo* rni = it->second;
@@ -394,9 +413,9 @@ void StrongSolverTheoryUF::SortModel::Region::debugPrint( const char* c, bool in
-StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ) : d_type( n.getType() ),
+StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, context::UserContext* u, StrongSolverTheoryUF* thss ) : d_type( n.getType() ),
d_thss( thss ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ),
- d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( 0 ),
+ d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( u, 0 ),
d_cardinality_assertions( c ), d_hasCard( c, false ){
d_cardinality_term = n;
}
@@ -501,9 +520,14 @@ void StrongSolverTheoryUF::SortModel::merge( Node a, Node b ){
}
d_reps = d_reps - 1;
- if( options::ufssDiseqPropagation() && !d_conflict ){
- //notify the disequality propagator
- d_thss->getDisequalityPropagator()->merge(a, b);
+ if( !d_conflict ){
+ if( options::ufssDiseqPropagation() ){
+ //notify the disequality propagator
+ d_thss->getDisequalityPropagator()->merge(a, b);
+ }
+ if( options::ufssSymBreak() ){
+ d_thss->getSymmetryBreaker()->merge(a, b);
+ }
}
}
}
@@ -551,9 +575,14 @@ void StrongSolverTheoryUF::SortModel::assertDisequal( Node a, Node b, Node reaso
checkRegion( bi );
}
- if( options::ufssDiseqPropagation() && !d_conflict ){
- //notify the disequality propagator
- d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null());
+ if( !d_conflict ){
+ if( options::ufssDiseqPropagation() ){
+ //notify the disequality propagator
+ d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null());
+ }
+ if( options::ufssSymBreak() ){
+ d_thss->getSymmetryBreaker()->assertDisequal(a, b);
+ }
}
}
}
@@ -595,9 +624,11 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
if( d_regions[i]->d_valid ){
std::vector< Node > clique;
if( d_regions[i]->check( level, d_cardinality, clique ) ){
- //add clique lemma
- addCliqueLemma( clique, out );
- return;
+ if( options::ufssMinimalModel() ){
+ //add clique lemma
+ addCliqueLemma( clique, out );
+ return;
+ }
}else{
Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
}
@@ -623,11 +654,21 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
//see if we have any recommended splits from large regions
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid && d_regions[i]->getNumReps()>d_cardinality ){
- if( addSplit( d_regions[i], out ) ){
- addedLemma = true;
+ //just add the clique lemma
+ if( level==Theory::EFFORT_FULL && options::ufssCliqueSplits() ){
+ std::vector< Node > clique;
+ if( d_regions[i]->getCandidateClique( d_cardinality, clique ) ){
+ //add clique lemma
+ addCliqueLemma( clique, out );
+ return;
+ }
+ }else{
+ if( addSplit( d_regions[i], out ) ){
+ addedLemma = true;
#ifdef ONE_SPLIT_REGION
- break;
+ break;
#endif
+ }
}
}
}
@@ -644,7 +685,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid ){
Node op = d_regions[i]->d_nodes.begin()->first;
- int sort_id = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId(op);
+ int sort_id = d_thss->getSortInference()->getSortId(op);
if( sortsFound.find( sort_id )!=sortsFound.end() ){
combineRegions( sortsFound[sort_id], i );
recheck = true;
@@ -659,13 +700,17 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
//naive strategy, force region combination involving the first valid region
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid ){
- forceCombineRegion( i, false );
- recheck = true;
- break;
+ int fcr = forceCombineRegion( i, false );
+ Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl;
+ if( options::ufssMinimalModel() || fcr!=-1 ){
+ recheck = true;
+ break;
+ }
}
}
}
if( recheck ){
+ Trace("uf-ss-debug") << "Must recheck." << std::endl;
check( level, out );
}
}
@@ -869,8 +914,10 @@ void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){
//now check if region is in conflict
std::vector< Node > clique;
if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
- //explain clique
- addCliqueLemma( clique, &d_thss->getOutputChannel() );
+ if( options::ufssMinimalModel() ){
+ //explain clique
+ addCliqueLemma( clique, &d_thss->getOutputChannel() );
+ }
}
}
}
@@ -947,18 +994,33 @@ void StrongSolverTheoryUF::SortModel::moveNode( Node n, int ri ){
void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
if( d_aloc_cardinality>0 ){
Trace("uf-ss-fmf") << "No model of size " << d_aloc_cardinality << " exists for type " << d_type << " in this branch" << std::endl;
- if( Trace.isOn("uf-ss-cliques") ){
- Trace("uf-ss-cliques") << "Cliques of size " << (d_aloc_cardinality+1) << " : " << std::endl;
- for( size_t i=0; i<d_cliques[ d_aloc_cardinality ].size(); i++ ){
- Trace("uf-ss-cliques") << " ";
- for( size_t j=0; j<d_cliques[ d_aloc_cardinality ][i].size(); j++ ){
- Trace("uf-ss-cliques") << d_cliques[ d_aloc_cardinality ][i][j] << " ";
- }
- Trace("uf-ss-cliques") << std::endl;
+ }
+ if( Trace.isOn("uf-ss-cliques") ){
+ Trace("uf-ss-cliques") << "Cliques of size " << (d_aloc_cardinality+1) << " for " << d_type << " : " << std::endl;
+ for( size_t i=0; i<d_cliques[ d_aloc_cardinality ].size(); i++ ){
+ Trace("uf-ss-cliques") << " ";
+ for( size_t j=0; j<d_cliques[ d_aloc_cardinality ][i].size(); j++ ){
+ Trace("uf-ss-cliques") << d_cliques[ d_aloc_cardinality ][i][j] << " ";
}
+ Trace("uf-ss-cliques") << std::endl;
+ }
+ }
+ /*
+ if( options::ufssSymBreak() ){
+ std::vector< Node > reps;
+ getRepresentatives( reps );
+ if( d_aloc_cardinality>0 ){
+ d_thss->getSymmetryBreaker()->allocateCardinality( out, d_type, d_aloc_cardinality+1, d_cliques[ d_aloc_cardinality ], reps );
+ }else{
+ std::vector< Node > clique;
+ clique.push_back( d_cardinality_term );
+ std::vector< std::vector< Node > > cliques;
+ cliques.push_back( clique );
+ d_thss->getSymmetryBreaker()->allocateCardinality( out, d_type, 1, cliques, reps );
}
}
- d_aloc_cardinality++;
+ */
+ d_aloc_cardinality = d_aloc_cardinality + 1;
//check for abort case
if( options::ufssAbortCardinality()==d_aloc_cardinality ){
@@ -969,7 +1031,7 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
if( applyTotality( d_aloc_cardinality ) ){
//must generate new cardinality lemma term
Node var;
- if( d_aloc_cardinality==1 ){
+ if( d_aloc_cardinality==1 && !options::ufssTotalitySymBreak() ){
//get arbitrary ground term
var = d_cardinality_term;
}else{
@@ -1013,8 +1075,8 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
}
bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
+ Node s;
if( r->hasSplits() ){
- Node s;
if( !options::ufssSmartSplits() ){
//take the first split you find
for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
@@ -1038,13 +1100,31 @@ bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
}
}
}
+ Assert( s!=Node::null() );
+ }else{
+ if( !options::ufssMinimalModel() ){
+ //since candidate clique is not reported, we may need to find splits manually
+ for ( std::map< Node, Region::RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){
+ if ( it->second->d_valid ){
+ for ( std::map< Node, Region::RegionNodeInfo* >::iterator it2 = r->d_nodes.begin(); it2 != r->d_nodes.end(); ++it2 ){
+ if ( it->second!=it2->second && it2->second->d_valid ){
+ if( !r->isDisequal( it->first, it2->first, 1 ) ){
+ s = NodeManager::currentNM()->mkNode( EQUAL, it->first, it2->first );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!s.isNull() ){
//add lemma to output channel
- Assert( s!=Node::null() && s.getKind()==EQUAL );
+ Assert( s.getKind()==EQUAL );
s = Rewriter::rewrite( s );
Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
if( options::sortInference()) {
for( int i=0; i<2; i++ ){
- int si = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId( s[i] );
+ int si = d_thss->getSortInference()->getSortId( s[i] );
Trace("uf-ss-split-si") << si << " ";
}
Trace("uf-ss-split-si") << std::endl;
@@ -1071,6 +1151,12 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
while( clique.size()>size_t(d_cardinality+1) ){
clique.pop_back();
}
+ //debugging information
+ if( options::ufssSymBreak() ){
+ std::vector< Node > clique_vec;
+ clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() );
+ addClique( d_cardinality, clique_vec );
+ }
if( options::ufssSimpleCliques() && !options::ufssExplainedCliques() ){
//add as lemma
std::vector< Node > eqs;
@@ -1083,16 +1169,10 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
}
eqs.push_back( d_cardinality_literal[ d_cardinality ].notNode() );
Node lem = NodeManager::currentNM()->mkNode( OR, eqs );
- Trace("uf-ss-lemma") << "*** Add clique conflict " << lem << std::endl;
+ Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
++( d_thss->d_statistics.d_clique_lemmas );
out->lemma( lem );
}else{
- //debugging information
- if( Trace.isOn("uf-ss-cliques") ){
- std::vector< Node > clique_vec;
- clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() );
- d_cliques[ d_cardinality ].push_back( clique_vec );
- }
//found a clique
Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl;
Debug("uf-ss-cliques") << " ";
@@ -1217,19 +1297,49 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
}
void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){
- Node cardLit = d_cardinality_literal[ cardinality ];
- std::vector< Node > eqs;
- for( int i=0; i<cardinality; i++ ){
- eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
+ if( std::find( d_totality_terms[0].begin(), d_totality_terms[0].end(), n )==d_totality_terms[0].end() ){
+ if( std::find( d_totality_lems[n].begin(), d_totality_lems[n].end(), cardinality ) == d_totality_lems[n].end() ){
+ d_totality_lems[n].push_back( cardinality );
+ Node cardLit = d_cardinality_literal[ cardinality ];
+ int sort_id = 0;
+ if( options::sortInference() ){
+ sort_id = d_thss->getSortInference()->getSortId(n);
+ }
+ Trace("uf-ss-totality") << "Add totality lemma for " << n << " " << cardinality << ", sort id is " << sort_id << std::endl;
+ int use_cardinality = cardinality;
+ if( options::ufssTotalitySymBreak() ){
+ if( d_sym_break_index.find(n)!=d_sym_break_index.end() ){
+ use_cardinality = d_sym_break_index[n];
+ }else if( (int)d_sym_break_terms[n.getType()][sort_id].size()<cardinality-1 ){
+ use_cardinality = d_sym_break_terms[n.getType()][sort_id].size() + 1;
+ d_sym_break_terms[n.getType()][sort_id].push_back( n );
+ d_sym_break_index[n] = use_cardinality;
+ Trace("uf-ss-totality") << "Allocate symmetry breaking term " << n << ", index = " << use_cardinality << std::endl;
+ }
+ }
+
+ std::vector< Node > eqs;
+ for( int i=0; i<use_cardinality; i++ ){
+ eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
+ }
+ Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
+ Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax );
+ Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl;
+ //send as lemma to the output channel
+ d_thss->getOutputChannel().lemma( lem );
+ ++( d_thss->d_statistics.d_totality_lemmas );
+ }
}
- Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
- Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax );
- Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl;
- //send as lemma to the output channel
- d_thss->getOutputChannel().lemma( lem );
- ++( d_thss->d_statistics.d_totality_lemmas );
}
+void StrongSolverTheoryUF::SortModel::addClique( int c, std::vector< Node >& clique ) {
+
+ if( d_clique_trie[c].add( clique ) ){
+ d_cliques[ c ].push_back( clique );
+ }
+}
+
+
/** apply totality */
bool StrongSolverTheoryUF::SortModel::applyTotality( int cardinality ){
return options::ufssTotality() || cardinality<=options::ufssTotalityLimited();
@@ -1307,22 +1417,16 @@ int StrongSolverTheoryUF::SortModel::getNumRegions(){
}
void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){
- //if( !options::ufssColoringSat() ){
- bool foundRegion = false;
- for( int i=0; i<(int)d_regions_index; i++ ){
- //should not have multiple regions at this point
- if( foundRegion ){
- Assert( !d_regions[i]->d_valid );
- }
- if( d_regions[i]->d_valid ){
- //this is the only valid region
- d_regions[i]->getRepresentatives( reps );
- foundRegion = true;
- }
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ //should not have multiple regions at this point
+ //if( foundRegion ){
+ // Assert( !d_regions[i]->d_valid );
+ //}
+ if( d_regions[i]->d_valid ){
+ //this is the only valid region
+ d_regions[i]->getRepresentatives( reps );
}
- //}else{
- // Unimplemented("Build representatives for fmf region sat is not implemented");
- //}
+ }
}
StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
@@ -1343,6 +1447,15 @@ d_rep_model_init( c )
}else{
d_deq_prop = NULL;
}
+ if( options::ufssSymBreak() ){
+ d_sym_break = new SubsortSymmetryBreaker( th->getQuantifiersEngine(), c );
+ }else{
+ d_sym_break = NULL;
+ }
+}
+
+SortInference* StrongSolverTheoryUF::getSortInference() {
+ return d_th->getQuantifiersEngine()->getTheoryEngine()->getSortInference();
}
/** get default sat context */
@@ -1361,6 +1474,9 @@ void StrongSolverTheoryUF::newEqClass( Node n ){
if( c ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: New eq class " << n << " : " << n.getType() << std::endl;
c->newEqClass( n );
+ if( options::ufssSymBreak() ){
+ d_sym_break->newEqClass( n );
+ }
}
}
@@ -1467,6 +1583,10 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
break;
}
}
+ //check symmetry breaker
+ if( !d_conflict && options::ufssSymBreak() ){
+ d_sym_break->check( level );
+ }
//disambiguate terms if necessary
//if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
// Assert( d_term_amb!=NULL );
@@ -1502,7 +1622,7 @@ void StrongSolverTheoryUF::preRegisterTerm( TNode n ){
SortModel* rm = NULL;
if( tn.isSort() ){
Trace("uf-ss-register") << "Preregister sort " << tn << "." << std::endl;
- rm = new SortModel( n, d_th->getSatContext(), this );
+ rm = new SortModel( n, d_th->getSatContext(), d_th->getUserContext(), this );
}else{
/*
if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
@@ -1572,6 +1692,14 @@ int StrongSolverTheoryUF::getCardinality( Node n ) {
}
}
+int StrongSolverTheoryUF::getCardinality( TypeNode tn ) {
+ std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
+ if( it!=d_rep_model.end() && it->second ){
+ return it->second->getCardinality();
+ }
+ return -1;
+}
+
void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){
SortModel* c = getSortModel( n );
if( c ){
@@ -1626,6 +1754,7 @@ StrongSolverTheoryUF::Statistics::Statistics():
d_clique_lemmas("StrongSolverTheoryUF::Clique_Lemmas", 0),
d_split_lemmas("StrongSolverTheoryUF::Split_Lemmas", 0),
d_disamb_term_lemmas("StrongSolverTheoryUF::Disambiguate_Term_Lemmas", 0),
+ d_sym_break_lemmas("StrongSolverTheoryUF::Symmetry_Breaking_Lemmas", 0),
d_totality_lemmas("StrongSolverTheoryUF::Totality_Lemmas", 0),
d_max_model_size("StrongSolverTheoryUF::Max_Model_Size", 1)
{
@@ -1633,6 +1762,7 @@ StrongSolverTheoryUF::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_clique_lemmas);
StatisticsRegistry::registerStat(&d_split_lemmas);
StatisticsRegistry::registerStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::registerStat(&d_sym_break_lemmas);
StatisticsRegistry::registerStat(&d_totality_lemmas);
StatisticsRegistry::registerStat(&d_max_model_size);
}
@@ -1642,6 +1772,7 @@ StrongSolverTheoryUF::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_clique_lemmas);
StatisticsRegistry::unregisterStat(&d_split_lemmas);
StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::unregisterStat(&d_sym_break_lemmas);
StatisticsRegistry::unregisterStat(&d_totality_lemmas);
StatisticsRegistry::unregisterStat(&d_max_model_size);
}
@@ -1785,4 +1916,4 @@ DisequalityPropagator::Statistics::Statistics():
DisequalityPropagator::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(& d_propagations);
-} \ No newline at end of file
+}
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 0cc995723..8e568444b 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -26,7 +26,13 @@
#include "util/statistics_registry.h"
namespace CVC4 {
+
+class SortInference;
+
namespace theory {
+
+class SubsortSymmetryBreaker;
+
namespace uf {
class TheoryUF;
@@ -40,11 +46,14 @@ protected:
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
typedef context::CDChunkList<Node> NodeList;
typedef context::CDList<bool> BoolList;
- typedef context::CDList<bool> IntList;
typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap;
public:
/** information for incremental conflict/clique finding for a particular sort */
class SortModel {
+ private:
+ std::map< Node, std::vector< int > > d_totality_lems;
+ std::map< TypeNode, std::map< int, std::vector< Node > > > d_sym_break_terms;
+ std::map< Node, int > d_sym_break_index;
public:
/** a partition of the current equality graph for which cliques can occur internally */
class Region {
@@ -146,6 +155,8 @@ public:
public:
/** check for cliques */
bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
+ /** get candidate clique */
+ bool getCandidateClique( int cardinality, std::vector< Node >& clique );
//print debug
void debugPrint( const char* c, bool incClique = false );
};
@@ -196,12 +207,29 @@ public:
/** add totality axiom */
void addTotalityAxiom( Node n, int cardinality, OutputChannel* out );
private:
+ class NodeTrie {
+ std::map< Node, NodeTrie > d_children;
+ public:
+ bool add( std::vector< Node >& n, unsigned i = 0 ){
+ Assert( i<n.size() );
+ if( i==(n.size()-1) ){
+ bool ret = d_children.find( n[i] )==d_children.end();
+ d_children[n[i]].d_children.clear();
+ return ret;
+ }else{
+ return d_children[n[i]].add( n, i+1 );
+ }
+ }
+ };
+ std::map< int, NodeTrie > d_clique_trie;
+ void addClique( int c, std::vector< Node >& clique );
+ private:
/** Are we in conflict */
context::CDO<bool> d_conflict;
/** cardinality */
context::CDO< int > d_cardinality;
/** maximum allocated cardinality */
- int d_aloc_cardinality;
+ context::CDO< int > d_aloc_cardinality;
/** cardinality lemma term */
Node d_cardinality_term;
/** cardinality totality terms */
@@ -222,7 +250,7 @@ public:
/** get totality lemma terms */
Node getTotalityLemmaTerm( int cardinality, int i );
public:
- SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss );
+ SortModel( Node n, context::Context* c, context::UserContext* u, StrongSolverTheoryUF* thss );
virtual ~SortModel(){}
/** initialize */
void initialize( OutputChannel* out );
@@ -280,6 +308,8 @@ private:
TermDisambiguator* d_term_amb;
/** disequality propagator */
DisequalityPropagator* d_deq_prop;
+ /** symmetry breaking techniques */
+ SubsortSymmetryBreaker* d_sym_break;
public:
StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
~StrongSolverTheoryUF() {}
@@ -289,6 +319,10 @@ public:
TermDisambiguator* getTermDisambiguator() { return d_term_amb; }
/** disequality propagator */
DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; }
+ /** symmetry breaker */
+ SubsortSymmetryBreaker* getSymmetryBreaker() { return d_sym_break; }
+ /** get sort inference module */
+ SortInference* getSortInference();
/** get default sat context */
context::Context* getSatContext();
/** get default output channel */
@@ -330,8 +364,10 @@ public:
TypeNode getCardinalityType( int i ) { return d_conf_types[i]; }
/** get is in conflict */
bool isConflict() { return d_conflict; }
- /** get cardinality for sort */
+ /** get cardinality for node */
int getCardinality( Node n );
+ /** get cardinality for type */
+ int getCardinality( TypeNode tn );
/** get representatives */
void getRepresentatives( Node n, std::vector< Node >& reps );
/** minimize */
@@ -343,6 +379,7 @@ public:
IntStat d_clique_lemmas;
IntStat d_split_lemmas;
IntStat d_disamb_term_lemmas;
+ IntStat d_sym_break_lemmas;
IntStat d_totality_lemmas;
IntStat d_max_model_size;
Statistics();
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 4f93f5a61..156288600 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -39,9 +39,11 @@ libutil_la_SOURCES = \
datatype.h \
datatype.cpp \
tuple.h \
- maybe.h \
record.h \
record.cpp \
+ divisible.h \
+ divisible.cpp \
+ maybe.h \
matcher.h \
gmp_util.h \
sexpr.h \
@@ -75,6 +77,7 @@ libutil_la_SOURCES = \
ite_removal.h \
ite_removal.cpp \
node_visitor.h \
+ chain.h \
index.h \
uninterpreted_constant.h \
uninterpreted_constant.cpp \
@@ -85,7 +88,8 @@ libutil_la_SOURCES = \
util_model.h \
util_model.cpp \
sort_inference.h \
- sort_inference.cpp
+ sort_inference.cpp \
+ regexp.h
libstatistics_la_SOURCES = \
statistics_registry.h \
@@ -122,7 +126,7 @@ EXTRA_DIST = \
datatype.i \
tuple.i \
record.i \
- output.i \
+ divisible.i \
cardinality.i \
result.i \
configuration.i \
@@ -136,7 +140,8 @@ EXTRA_DIST = \
rational.i \
hash.i \
predicate.i \
- uninterpreted_constant.i
+ uninterpreted_constant.i \
+ chain.i
DISTCLEANFILES = \
integer.h.tmp \
diff --git a/src/util/bitvector.h b/src/util/bitvector.h
index 2d5d29339..04e23217b 100644
--- a/src/util/bitvector.h
+++ b/src/util/bitvector.h
@@ -396,7 +396,7 @@ struct CVC4_PUBLIC BitVectorHashFunction {
/**
* The structure representing the extraction operation for bit-vectors. The
- * operation map bit-vectors to bit-vector of size <code>high - low + 1</code>
+ * operation maps bit-vectors to bit-vector of size <code>high - low + 1</code>
* by taking the bits at indices <code>high ... low</code>
*/
struct CVC4_PUBLIC BitVectorExtract {
@@ -492,6 +492,13 @@ struct CVC4_PUBLIC BitVectorRotateRight {
operator unsigned () const { return rotateRightAmount; }
};/* struct BitVectorRotateRight */
+struct CVC4_PUBLIC IntToBitVector {
+ unsigned size;
+ IntToBitVector(unsigned size)
+ : size(size) {}
+ operator unsigned () const { return size; }
+};/* struct IntToBitVector */
+
template <typename T>
struct CVC4_PUBLIC UnsignedHashFunction {
inline size_t operator()(const T& x) const {
@@ -514,6 +521,11 @@ inline std::ostream& operator <<(std::ostream& os, const BitVectorBitOf& bv) {
return os << "[" << bv.bitIndex << "]";
}
+inline std::ostream& operator <<(std::ostream& os, const IntToBitVector& bv) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const IntToBitVector& bv) {
+ return os << "[" << bv.size << "]";
+}
+
}/* CVC4 namespace */
#endif /* __CVC4__BITVECTOR_H */
diff --git a/src/util/boolean_simplification.h b/src/util/boolean_simplification.h
index e5c4ead6c..be39f69c1 100644
--- a/src/util/boolean_simplification.h
+++ b/src/util/boolean_simplification.h
@@ -22,6 +22,7 @@
#include <vector>
#include <algorithm>
+#include "expr/expr_manager_scope.h"
#include "expr/node.h"
#include "util/cvc4_assert.h"
@@ -202,6 +203,7 @@ public:
* @param e the Expr to negate (cannot be the null Expr)
*/
static Expr negate(Expr e) throw(AssertionException) {
+ ExprManagerScope ems(e);
return negate(Node::fromExpr(e)).toExpr();
}
diff --git a/src/util/chain.h b/src/util/chain.h
new file mode 100644
index 000000000..2e9cf7bf6
--- /dev/null
+++ b/src/util/chain.h
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file chain.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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"
+
+#ifndef __CVC4__CHAIN_H
+#define __CVC4__CHAIN_H
+
+#include "expr/kind.h"
+#include <iostream>
+
+namespace CVC4 {
+
+/** A class to represent a chained, built-in operator. */
+class Chain {
+ Kind d_kind;
+public:
+ explicit Chain(Kind k) : d_kind(k) { }
+ bool operator==(const Chain& ch) const { return d_kind == ch.d_kind; }
+ bool operator!=(const Chain& ch) const { return d_kind != ch.d_kind; }
+ Kind getOperator() const { return d_kind; }
+};/* class Chain */
+
+inline std::ostream& operator<<(std::ostream& out, const Chain& ch) {
+ return out << ch.getOperator();
+}
+
+struct ChainHashFunction {
+ size_t operator()(const Chain& ch) const {
+ return kind::KindHashFunction()(ch.getOperator());
+ }
+};/* struct ChainHashFunction */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__CHAIN_H */
diff --git a/src/util/chain.i b/src/util/chain.i
new file mode 100644
index 000000000..1c97a527f
--- /dev/null
+++ b/src/util/chain.i
@@ -0,0 +1,12 @@
+%{
+#include "util/chain.h"
+%}
+
+%rename(equals) CVC4::Chain::operator==(const Chain&) const;
+%ignore CVC4::Chain::operator!=(const Chain&) const;
+
+%ignore CVC4::operator<<(std::ostream&, const Chain&);
+
+%rename(apply) CVC4::ChainHashFunction::operator()(const CVC4::Chain&) const;
+
+%include "util/chain.h"
diff --git a/src/util/cvc4_assert.cpp b/src/util/cvc4_assert.cpp
index eb7b81a39..08e2867f6 100644
--- a/src/util/cvc4_assert.cpp
+++ b/src/util/cvc4_assert.cpp
@@ -136,7 +136,7 @@ void debugAssertionFailed(const AssertionException& thisException,
const char* propagatingException) {
static CVC4_THREADLOCAL(bool) alreadyFired = false;
- if(EXPECT_TRUE( !std::uncaught_exception() ) || alreadyFired) {
+ if(__builtin_expect( ( !std::uncaught_exception() ), true ) || alreadyFired) {
throw thisException;
}
diff --git a/src/util/cvc4_assert.h b/src/util/cvc4_assert.h
index c070fc389..7d359a56b 100644
--- a/src/util/cvc4_assert.h
+++ b/src/util/cvc4_assert.h
@@ -252,7 +252,7 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
// details of the exception
# define AlwaysAssert(cond, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
/* save the last assertion failure */ \
const char* lastException = ::CVC4::s_debugLastException; \
::CVC4::AssertionException exception(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
@@ -265,7 +265,7 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
// will terminate() if thrown during stack unwinding.
# define AlwaysAssert(cond, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::AssertionException(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
} \
} while(0)
@@ -283,13 +283,13 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
throw ::CVC4::IllegalArgumentException("", #arg, __PRETTY_FUNCTION__, ## msg)
#define CheckArgument(cond, arg, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::IllegalArgumentException(#cond, #arg, __PRETTY_FUNCTION__, ## msg); \
} \
} while(0)
#define AlwaysAssertArgument(cond, arg, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::AssertArgumentException(#cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
} \
} while(0)
@@ -299,9 +299,9 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
# define AssertArgument(cond, arg, msg...) AlwaysAssertArgument(cond, arg, ## msg)
# define DebugCheckArgument(cond, arg, msg...) CheckArgument(cond, arg, ## msg)
#else /* ! CVC4_ASSERTIONS */
-# define Assert(cond, msg...) /*EXPECT_TRUE( cond )*/
-# define AssertArgument(cond, arg, msg...) /*EXPECT_TRUE( cond )*/
-# define DebugCheckArgument(cond, arg, msg...) /*EXPECT_TRUE( cond )*/
+# define Assert(cond, msg...) /*__builtin_expect( ( cond ), true )*/
+# define AssertArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
+# define DebugCheckArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
#endif /* CVC4_ASSERTIONS */
}/* CVC4 namespace */
diff --git a/src/util/datatype.h b/src/util/datatype.h
index 3da441f1f..c46c10c97 100644
--- a/src/util/datatype.h
+++ b/src/util/datatype.h
@@ -33,7 +33,6 @@ namespace CVC4 {
#include "expr/expr.h"
#include "expr/type.h"
-#include "util/output.h"
#include "util/hash.h"
#include "util/exception.h"
diff --git a/src/util/debug.h b/src/util/debug.h
index 3e7c4d8be..97c176f02 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -27,11 +27,11 @@
#ifdef CVC4_ASSERTIONS
// the __builtin_expect() helps us if assert is built-in or a macro
-# define cvc4assert(x) assert(EXPECT_TRUE( x ))
+# define cvc4assert(x) assert(__builtin_expect( ( x ), true ))
#else
// TODO: use a compiler annotation when assertions are off ?
// (to improve optimization)
-# define cvc4assert(x) /*EXPECT_TRUE( x )*/
+# define cvc4assert(x) /*__builtin_expect( ( x ), true )*/
#endif /* CVC4_ASSERTIONS */
#endif /* __CVC4__DEBUG_H */
diff --git a/src/util/divisible.cpp b/src/util/divisible.cpp
new file mode 100644
index 000000000..4e20d6b5f
--- /dev/null
+++ b/src/util/divisible.cpp
@@ -0,0 +1,29 @@
+/********************* */
+/*! \file divisible.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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 "util/divisible.h"
+#include "util/exception.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+Divisible::Divisible(const Integer& n) : k(n) {
+ CheckArgument(n > 0, n, "Divisible predicate must be constructed over positive N");
+}
+
+}/* CVC4 namespace */
diff --git a/src/util/divisible.h b/src/util/divisible.h
new file mode 100644
index 000000000..0c0c7bc5b
--- /dev/null
+++ b/src/util/divisible.h
@@ -0,0 +1,62 @@
+/********************* */
+/*! \file divisible.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 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"
+
+#ifndef __CVC4__DIVISIBLE_H
+#define __CVC4__DIVISIBLE_H
+
+#include <iostream>
+#include "util/integer.h"
+#include "util/exception.h"
+
+namespace CVC4 {
+
+/**
+ * The structure representing the divisibility-by-k predicate.
+ */
+struct CVC4_PUBLIC Divisible {
+ const Integer k;
+
+ Divisible(const Integer& n);
+
+ bool operator==(const Divisible& d) const {
+ return k == d.k;
+ }
+
+ bool operator!=(const Divisible& d) const {
+ return !(*this == d);
+ }
+};/* struct Divisible */
+
+/**
+ * Hash function for the Divisible objects.
+ */
+struct CVC4_PUBLIC DivisibleHashFunction {
+ size_t operator()(const Divisible& d) const {
+ return d.k.hash();
+ }
+};/* struct DivisibleHashFunction */
+
+inline std::ostream& operator <<(std::ostream& os, const Divisible& d) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const Divisible& d) {
+ return os << "divisible-by-" << d.k;
+}
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__DIVISIBLE_H */
diff --git a/src/util/divisible.i b/src/util/divisible.i
new file mode 100644
index 000000000..7599360ca
--- /dev/null
+++ b/src/util/divisible.i
@@ -0,0 +1,10 @@
+%{
+#include "util/divisible.h"
+%}
+
+%rename(equals) CVC4::Divisible::operator==(const Divisible&) const;
+%ignore CVC4::Divisible::operator!=(const Divisible&) const;
+
+%ignore CVC4::operator<<(std::ostream&, const Divisible&);
+
+%include "util/divisible.h"
diff --git a/src/util/dump.h b/src/util/dump.h
index 2ef6010e3..0bde68d76 100644
--- a/src/util/dump.h
+++ b/src/util/dump.h
@@ -19,7 +19,6 @@
#ifndef __CVC4__DUMP_H
#define __CVC4__DUMP_H
-#include "util/output.h"
#include "expr/command.h"
namespace CVC4 {
diff --git a/src/util/exception.h b/src/util/exception.h
index 082a50ef2..cd4b763ef 100644
--- a/src/util/exception.h
+++ b/src/util/exception.h
@@ -138,13 +138,13 @@ namespace CVC4 {
#ifndef CheckArgument
template <class T> inline void CheckArgument(bool cond, const T& arg, const char* fmt, ...) CVC4_PUBLIC;
template <class T> inline void CheckArgument(bool cond, const T& arg, const char* fmt, ...) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
template <class T> inline void CheckArgument(bool cond, const T& arg) CVC4_PUBLIC;
template <class T> inline void CheckArgument(bool cond, const T& arg) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
@@ -153,13 +153,13 @@ template <class T> inline void CheckArgument(bool cond, const T& arg) {
#ifndef DebugCheckArgument
template <class T> inline void DebugCheckArgument(bool cond, const T& arg, const char* fmt, ...) CVC4_PUBLIC;
template <class T> inline void DebugCheckArgument(bool cond, const T& arg, const char* fmt, ...) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
template <class T> inline void DebugCheckArgument(bool cond, const T& arg) CVC4_PUBLIC;
template <class T> inline void DebugCheckArgument(bool cond, const T& arg) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index f26bbe0aa..7d4948251 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -30,7 +30,11 @@ void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap)
{
for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
std::vector<Node> quantVar;
- output[i] = run(output[i], output, iteSkolemMap, quantVar);
+ // Do this in two steps to avoid Node problems(?)
+ // Appears related to bug 512, splitting this into two lines
+ // fixes the bug on clang on Mac OS
+ Node itesRemoved = run(output[i], output, iteSkolemMap, quantVar);
+ output[i] = itesRemoved;
}
}
diff --git a/src/util/output.h b/src/util/output.h
index 263d5a144..7394f24ab 100644
--- a/src/util/output.h
+++ b/src/util/output.h
@@ -14,7 +14,7 @@
** Output utility classes and functions.
**/
-#include "cvc4_public.h"
+#include "cvc4_private_library.h"
#ifndef __CVC4__OUTPUT_H
#define __CVC4__OUTPUT_H
diff --git a/src/util/output.i b/src/util/output.i
deleted file mode 100644
index 74953ba53..000000000
--- a/src/util/output.i
+++ /dev/null
@@ -1,70 +0,0 @@
-%{
-#include "util/output.h"
-%}
-
-%ignore CVC4::null_streambuf;
-%ignore std::streambuf;
-%feature("valuewrapper") std::ostream;
-
-// There are issues with SWIG's attempted wrapping of these variables when
-// it tries to generate the getters and setters. For now, just ignore them.
-%ignore CVC4::null_sb;
-%ignore CVC4::null_os;
-%ignore CVC4::DumpOutC::dump_cout;
-%ignore CVC4::CVC4ostream;
-
-%ignore operator<<;
-%ignore on(std::string);
-%ignore isOn(std::string);
-%ignore off(std::string);
-%ignore printf(std::string, const char*, ...);
-
-%ignore CVC4::IndentedScope;
-%ignore CVC4::push(CVC4ostream&);
-%ignore CVC4::pop(CVC4ostream&);
-
-%ignore CVC4::ScopedDebug::ScopedDebug(std::string);
-%ignore CVC4::ScopedDebug::ScopedDebug(std::string, bool);
-
-%ignore CVC4::ScopedTrace::ScopedTrace(std::string);
-%ignore CVC4::ScopedTrace::ScopedTrace(std::string, bool);
-
-%ignore CVC4::WarningC::WarningC(std::ostream*);
-%ignore CVC4::MessageC::MessageC(std::ostream*);
-%ignore CVC4::NoticeC::NoticeC(std::ostream*);
-%ignore CVC4::ChatC::ChatC(std::ostream*);
-%ignore CVC4::TraceC::TraceC(std::ostream*);
-%ignore CVC4::DebugC::DebugC(std::ostream*);
-%ignore CVC4::DumpOutC::DumpOutC(std::ostream*);
-
-%ignore CVC4::WarningC::operator();
-%ignore CVC4::MessageC::operator();
-%ignore CVC4::NoticeC::operator();
-%ignore CVC4::ChatC::operator();
-%ignore CVC4::TraceC::operator();
-%ignore CVC4::DebugC::operator();
-%ignore CVC4::DumpOutC::operator();
-
-%ignore CVC4::WarningC::getStream();
-%ignore CVC4::MessageC::getStream();
-%ignore CVC4::NoticeC::getStream();
-%ignore CVC4::ChatC::getStream();
-%ignore CVC4::TraceC::getStream();
-%ignore CVC4::DebugC::getStream();
-%ignore CVC4::DumpOutC::getStream();
-
-%ignore CVC4::WarningC::setStream(std::ostream&);
-%ignore CVC4::MessageC::setStream(std::ostream&);
-%ignore CVC4::NoticeC::setStream(std::ostream&);
-%ignore CVC4::ChatC::setStream(std::ostream&);
-%ignore CVC4::TraceC::setStream(std::ostream&);
-%ignore CVC4::DebugC::setStream(std::ostream&);
-%ignore CVC4::DumpOutC::setStream(std::ostream&);
-
-%ignore operator std::ostream&;
-%ignore operator CVC4ostream;
-
-%rename(get) operator ();
-%rename(ok) operator bool;
-
-%include "util/output.h"
diff --git a/src/util/rational_cln_imp.h b/src/util/rational_cln_imp.h
index 1e27fa859..da2af6c1f 100644
--- a/src/util/rational_cln_imp.h
+++ b/src/util/rational_cln_imp.h
@@ -155,10 +155,10 @@ public:
#ifdef CVC4_NEED_INT64_T_OVERLOADS
Rational(int64_t n, int64_t d) : d_value(static_cast<long>(n)) {
- d_value /= static_cast<long>(d);
+ d_value /= cln::cl_I(d);
}
Rational(uint64_t n, uint64_t d) : d_value(static_cast<unsigned long>(n)) {
- d_value /= static_cast<unsigned long>(d);
+ d_value /= cln::cl_I(d);
}
#endif /* CVC4_NEED_INT64_T_OVERLOADS */
diff --git a/src/util/record.h b/src/util/record.h
index 3d6481320..63c54930e 100644
--- a/src/util/record.h
+++ b/src/util/record.h
@@ -91,7 +91,6 @@ public:
Record(const std::vector< std::pair<std::string, Type> >& fields) :
d_fields(fields) {
- CheckArgument(! fields.empty(), fields, "fields in record description cannot be empty");
}
const_iterator find(std::string name) const {
diff --git a/src/util/recursion_breaker.h b/src/util/recursion_breaker.h
index 07bf10984..a4177f600 100644
--- a/src/util/recursion_breaker.h
+++ b/src/util/recursion_breaker.h
@@ -86,7 +86,7 @@ class RecursionBreaker {
static CVC4_THREADLOCAL(Map*) s_maps;
std::string d_tag;
- const T& d_item;
+ const T d_item;
bool d_firstToTag;
bool d_recursion;
diff --git a/src/util/regexp.h b/src/util/regexp.h
new file mode 100644
index 000000000..58f58a40f
--- /dev/null
+++ b/src/util/regexp.h
@@ -0,0 +1,353 @@
+/********************* */
+/*! \file regexp.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2013 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"
+
+#ifndef __CVC4__REGEXP_H
+#define __CVC4__REGEXP_H
+
+#include <iostream>
+#include <string>
+//#include "util/exception.h"
+//#include "util/integer.h"
+#include "util/hash.h"
+
+namespace CVC4 {
+
+class CVC4_PUBLIC Char {
+
+private:
+ unsigned int d_char;
+
+public:
+ Char() {}
+
+ Char(const unsigned int c)
+ : d_char(c) {}
+
+ ~Char() {}
+
+ Char& operator =(const Char& y) {
+ if(this != &y) d_char = y.d_char;
+ return *this;
+ }
+
+ bool operator ==(const Char& y) const {
+ return d_char == y.d_char ;
+ }
+
+ bool operator !=(const Char& y) const {
+ return d_char != y.d_char ;
+ }
+
+ bool operator <(const Char& y) const {
+ return d_char < y.d_char;
+ }
+
+ bool operator >(const Char& y) const {
+ return d_char > y.d_char ;
+ }
+
+ bool operator <=(const Char& y) const {
+ return d_char <= y.d_char;
+ }
+
+ bool operator >=(const Char& y) const {
+ return d_char >= y.d_char ;
+ }
+
+ /*
+ * Convenience functions
+ */
+ std::string toString() const {
+ std::string str = "1";
+ str[0] = (char) d_char;
+ return str;
+ }
+
+ unsigned size() const {
+ return 1;
+ }
+
+ const char* c_str() const {
+ return toString().c_str();
+ }
+};/* class Char */
+
+namespace strings {
+
+struct CharHashFunction {
+ size_t operator()(const ::CVC4::Char& c) const {
+ return __gnu_cxx::hash<const char*>()(c.toString().c_str());
+ }
+};/* struct CharHashFunction */
+
+}
+
+inline std::ostream& operator <<(std::ostream& os, const Char& c) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const Char& c) {
+ return os << "\"" << c.toString() << "\"";
+}
+
+class CVC4_PUBLIC String {
+
+private:
+ std::vector<unsigned int> d_str;
+
+ bool isVecSame(const std::vector<unsigned int> &a, const std::vector<unsigned int> &b) const {
+ if(a.size() != b.size()) return false;
+ else {
+ for(unsigned int i=0; i<a.size(); ++i)
+ if(a[i] != b[i]) return false;
+ return true;
+ }
+ }
+
+public:
+ String() {}
+
+ String(const std::string &s) {
+ for(unsigned int i=0; i<s.size(); ++i) {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ }
+ }
+
+ String(const char* s) {
+ for(unsigned int i=0,len=strlen(s); i<len; ++i) {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ }
+ }
+
+ String(const std::vector<unsigned int> &s) : d_str(s) { }
+
+ ~String() {}
+
+ String& operator =(const String& y) {
+ if(this != &y) d_str = y.d_str;
+ return *this;
+ }
+
+ bool operator ==(const String& y) const {
+ return isVecSame(d_str, y.d_str);
+ }
+
+ bool operator !=(const String& y) const {
+ return ! ( isVecSame(d_str, y.d_str) );
+ }
+
+ String concat (const String& other) const {
+ std::vector<unsigned int> ret_vec(d_str);
+ ret_vec.insert( ret_vec.end(), other.d_str.begin(), other.d_str.end() );
+ return String(ret_vec);
+ }
+
+ bool operator <(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() < y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] < y.d_str[i];
+
+ return false;
+ }
+ }
+
+ bool operator >(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() > y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] > y.d_str[i];
+
+ return false;
+ }
+ }
+
+ bool operator <=(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() < y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] < y.d_str[i];
+
+ return true;
+ }
+ }
+
+ bool operator >=(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() > y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] > y.d_str[i];
+
+ return true;
+ }
+ }
+
+ bool strncmp(const String &y, unsigned int n) const {
+ for(unsigned int i=0; i<n; ++i)
+ if(d_str[i] != y.d_str[i]) return false;
+ return true;
+ }
+
+ /*
+ * Convenience functions
+ */
+ std::string toString() const {
+ std::string str;
+ for(unsigned int i=0; i<d_str.size(); ++i) {
+ str += convertUnsignedIntToChar( d_str[i] );
+ //TODO isPrintable: ( "\\" + (convertUnsignedIntToChar( d_str[i] ) );
+ }
+ return str;
+ }
+
+ unsigned size() const {
+ return d_str.size();
+ }
+
+ String substr(unsigned i) const {
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ //for(unsigned k=0; k<i; k++) ++itr;
+ ret_vec.insert(ret_vec.end(), itr, d_str.end());
+ return String(ret_vec);
+ }
+ String substr(unsigned i, unsigned j) const {
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ //for(unsigned k=0; k<i; k++) ++itr;
+ //std::vector<unsigned int>::const_iterator itr2 = itr;
+ //for(unsigned k=0; k<j; k++) ++itr2;
+ ret_vec.insert( ret_vec.end(), itr, itr + j );
+ return String(ret_vec);
+ }
+
+public:
+ static unsigned int convertCharToUnsignedInt( char c ) {
+ int i = (int)c;
+ i = i-65;
+ return (unsigned int)(i<0 ? i+256 : i);
+ }
+ static char convertUnsignedIntToChar( unsigned int i ){
+ int ii = i+65;
+ return (char)(ii>=256 ? ii-256 : ii);
+ }
+ static bool isPrintable( unsigned int i ){
+ char c = convertUnsignedIntToChar( i );
+ return isprint( (int)c );
+ }
+
+};/* class String */
+
+namespace strings {
+
+struct StringHashFunction {
+ size_t operator()(const ::CVC4::String& s) const {
+ return __gnu_cxx::hash<const char*>()(s.toString().c_str());
+ }
+};/* struct StringHashFunction */
+
+}
+
+inline std::ostream& operator <<(std::ostream& os, const String& s) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const String& s) {
+ return os << "\"" << s.toString() << "\"";
+}
+
+class CVC4_PUBLIC RegExp {
+
+private:
+ std::string d_str;
+
+public:
+ RegExp() {}
+
+ RegExp(const std::string s)
+ : d_str(s) {}
+
+ ~RegExp() {}
+
+ RegExp& operator =(const RegExp& y) {
+ if(this != &y) d_str = y.d_str;
+ return *this;
+ }
+
+ bool operator ==(const RegExp& y) const {
+ return d_str == y.d_str ;
+ }
+
+ bool operator !=(const RegExp& y) const {
+ return d_str != y.d_str ;
+ }
+
+ String concat (const RegExp& other) const {
+ return String(d_str + other.d_str);
+ }
+
+ bool operator <(const RegExp& y) const {
+ return d_str < y.d_str;
+ }
+
+ bool operator >(const RegExp& y) const {
+ return d_str > y.d_str ;
+ }
+
+ bool operator <=(const RegExp& y) const {
+ return d_str <= y.d_str;
+ }
+
+ bool operator >=(const RegExp& y) const {
+ return d_str >= y.d_str ;
+ }
+
+ /*
+ * Convenience functions
+ */
+
+ size_t hash() const {
+ unsigned int h = 1;
+
+ for (size_t i = 0; i < d_str.length(); ++i) {
+ h = (h << 5) + d_str[i];
+ }
+
+ return h;
+ }
+
+ std::string toString() const {
+ return d_str;
+ }
+
+ unsigned size() const {
+ return d_str.size();
+ }
+};/* class String */
+
+/**
+ * Hash function for the RegExp constants.
+ */
+struct CVC4_PUBLIC RegExpHashFunction {
+ inline size_t operator()(const RegExp& s) const {
+ return s.hash();
+ }
+};/* struct RegExpHashFunction */
+
+inline std::ostream& operator <<(std::ostream& os, const RegExp& s) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const RegExp& s) {
+ return os << s.toString();
+}
+}/* CVC4 namespace */
+
+#endif /* __CVC4__STRING_H */
diff --git a/src/util/result.cpp b/src/util/result.cpp
index e0e34f07d..909a7d8c6 100644
--- a/src/util/result.cpp
+++ b/src/util/result.cpp
@@ -27,11 +27,12 @@ using namespace std;
namespace CVC4 {
-Result::Result(const std::string& instr) :
+Result::Result(const std::string& instr, std::string inputName) :
d_sat(SAT_UNKNOWN),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_NONE),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
string s = instr;
transform(s.begin(), s.end(), s.begin(), ::tolower);
if(s == "sat" || s == "satisfiable") {
@@ -115,13 +116,13 @@ Result Result::asSatisfiabilityResult() const throw() {
switch(d_validity) {
case INVALID:
- return Result(SAT);
+ return Result(SAT, d_inputName);
case VALID:
- return Result(UNSAT);
+ return Result(UNSAT, d_inputName);
case VALIDITY_UNKNOWN:
- return Result(SAT_UNKNOWN, d_unknownExplanation);
+ return Result(SAT_UNKNOWN, d_unknownExplanation, d_inputName);
default:
Unhandled(d_validity);
@@ -129,7 +130,7 @@ Result Result::asSatisfiabilityResult() const throw() {
}
// TYPE_NONE
- return Result(SAT_UNKNOWN, NO_STATUS);
+ return Result(SAT_UNKNOWN, NO_STATUS, d_inputName);
}
Result Result::asValidityResult() const throw() {
@@ -141,13 +142,13 @@ Result Result::asValidityResult() const throw() {
switch(d_sat) {
case SAT:
- return Result(INVALID);
+ return Result(INVALID, d_inputName);
case UNSAT:
- return Result(VALID);
+ return Result(VALID, d_inputName);
case SAT_UNKNOWN:
- return Result(VALIDITY_UNKNOWN, d_unknownExplanation);
+ return Result(VALIDITY_UNKNOWN, d_unknownExplanation, d_inputName);
default:
Unhandled(d_sat);
@@ -155,7 +156,7 @@ Result Result::asValidityResult() const throw() {
}
// TYPE_NONE
- return Result(VALIDITY_UNKNOWN, NO_STATUS);
+ return Result(VALIDITY_UNKNOWN, NO_STATUS, d_inputName);
}
string Result::toString() const {
diff --git a/src/util/result.h b/src/util/result.h
index cb1bd50fa..21bf563bd 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -71,47 +71,58 @@ private:
enum Validity d_validity;
enum Type d_which;
enum UnknownExplanation d_unknownExplanation;
+ std::string d_inputName;
public:
Result() :
d_sat(SAT_UNKNOWN),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_NONE),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName("") {
}
- Result(enum Sat s) :
+ Result(enum Sat s, std::string inputName = "") :
d_sat(s),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_SAT),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
CheckArgument(s != SAT_UNKNOWN,
"Must provide a reason for satisfiability being unknown");
}
- Result(enum Validity v) :
+ Result(enum Validity v, std::string inputName = "") :
d_sat(SAT_UNKNOWN),
d_validity(v),
d_which(TYPE_VALIDITY),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
CheckArgument(v != VALIDITY_UNKNOWN,
"Must provide a reason for validity being unknown");
}
- Result(enum Sat s, enum UnknownExplanation unknownExplanation) :
+ Result(enum Sat s, enum UnknownExplanation unknownExplanation, std::string inputName = "") :
d_sat(s),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_SAT),
- d_unknownExplanation(unknownExplanation) {
+ d_unknownExplanation(unknownExplanation),
+ d_inputName(inputName) {
CheckArgument(s == SAT_UNKNOWN,
"improper use of unknown-result constructor");
}
- Result(enum Validity v, enum UnknownExplanation unknownExplanation) :
+ Result(enum Validity v, enum UnknownExplanation unknownExplanation, std::string inputName = "") :
d_sat(SAT_UNKNOWN),
d_validity(v),
d_which(TYPE_VALIDITY),
- d_unknownExplanation(unknownExplanation) {
+ d_unknownExplanation(unknownExplanation),
+ d_inputName(inputName) {
CheckArgument(v == VALIDITY_UNKNOWN,
"improper use of unknown-result constructor");
}
- Result(const std::string& s);
+ Result(const std::string& s, std::string inputName = "");
+
+ Result(const Result& r, std::string inputName) {
+ *this = r;
+ d_inputName = inputName;
+ }
enum Sat isSat() const {
return d_which == TYPE_SAT ? d_sat : SAT_UNKNOWN;
@@ -142,6 +153,8 @@ public:
std::string toString() const;
+ std::string getInputName() const { return d_inputName; }
+
};/* class Result */
inline bool Result::operator!=(const Result& r) const throw() {
diff --git a/src/util/result.i b/src/util/result.i
index 029a3618a..b77bfd881 100644
--- a/src/util/result.i
+++ b/src/util/result.i
@@ -12,8 +12,9 @@
%ignore CVC4::operator<<(std::ostream&, enum Result::UnknownExplanation);
%ignore CVC4::operator==(enum Result::Sat, const Result&);
-%ignore CVC4::operator==(enum Result::Validity, const Result&);
%ignore CVC4::operator!=(enum Result::Sat, const Result&);
+
+%ignore CVC4::operator==(enum Result::Validity, const Result&);
%ignore CVC4::operator!=(enum Result::Validity, const Result&);
%include "util/result.h"
diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp
index d44499fa8..b66d1cbe4 100644
--- a/src/util/sort_inference.cpp
+++ b/src/util/sort_inference.cpp
@@ -20,15 +20,70 @@
#include <vector>
#include "util/sort_inference.h"
+#include "theory/uf/options.h"
+//#include "theory/rewriter.h"
using namespace CVC4;
using namespace std;
namespace CVC4 {
+void SortInference::UnionFind::print(const char * c){
+ for( std::map< int, int >::iterator it = d_eqc.begin(); it != d_eqc.end(); ++it ){
+ Trace(c) << "s_" << it->first << " = s_" << it->second << ", ";
+ }
+ for( unsigned i=0; i<d_deq.size(); i++ ){
+ Trace(c) << "s_" << d_deq[i].first << " != s_" << d_deq[i].second << ", ";
+ }
+ Trace(c) << std::endl;
+}
+void SortInference::UnionFind::set( UnionFind& c ) {
+ clear();
+ for( std::map< int, int >::iterator it = c.d_eqc.begin(); it != c.d_eqc.end(); ++it ){
+ d_eqc[ it->first ] = it->second;
+ }
+ d_deq.insert( d_deq.end(), c.d_deq.begin(), c.d_deq.end() );
+}
+int SortInference::UnionFind::getRepresentative( int t ){
+ std::map< int, int >::iterator it = d_eqc.find( t );
+ if( it==d_eqc.end() || it->second==t ){
+ return t;
+ }else{
+ int rt = getRepresentative( it->second );
+ d_eqc[t] = rt;
+ return rt;
+ }
+}
+void SortInference::UnionFind::setEqual( int t1, int t2 ){
+ if( t1!=t2 ){
+ int rt1 = getRepresentative( t1 );
+ int rt2 = getRepresentative( t2 );
+ if( rt1>rt2 ){
+ d_eqc[rt1] = rt2;
+ }else{
+ d_eqc[rt2] = rt1;
+ }
+ }
+}
+bool SortInference::UnionFind::isValid() {
+ for( unsigned i=0; i<d_deq.size(); i++ ){
+ if( areEqual( d_deq[i].first, d_deq[i].second ) ){
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void SortInference::recordSubsort( int s ){
+ s = d_type_union_find.getRepresentative( s );
+ if( std::find( d_sub_sorts.begin(), d_sub_sorts.end(), s )==d_sub_sorts.end() ){
+ d_sub_sorts.push_back( s );
+ }
+}
void SortInference::printSort( const char* c, int t ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
Trace(c) << d_type_types[rt];
}else{
@@ -43,30 +98,49 @@ void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){
std::map< Node, Node > var_bound;
process( assertions[i], var_bound );
}
- //print debug
- if( Trace.isOn("sort-inference") ){
- for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
- Trace("sort-inference") << it->first << " : ";
- if( !d_op_arg_types[ it->first ].empty() ){
- Trace("sort-inference") << "( ";
- for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
- printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
- Trace("sort-inference") << " ";
- }
- Trace("sort-inference") << ") -> ";
+ for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
+ Trace("sort-inference") << it->first << " : ";
+ if( !d_op_arg_types[ it->first ].empty() ){
+ Trace("sort-inference") << "( ";
+ for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
+ recordSubsort( d_op_arg_types[ it->first ][i] );
+ printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
+ Trace("sort-inference") << " ";
}
- printSort( "sort-inference", it->second );
- Trace("sort-inference") << std::endl;
+ Trace("sort-inference") << ") -> ";
}
- for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){
- Trace("sort-inference") << "Quantified formula " << it->first << " : " << std::endl;
- for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- printSort( "sort-inference", it2->second );
- Trace("sort-inference") << std::endl;
- }
+ recordSubsort( it->second );
+ printSort( "sort-inference", it->second );
+ Trace("sort-inference") << std::endl;
+ }
+ for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){
+ Trace("sort-inference") << "Quantified formula : " << it->first << " : " << std::endl;
+ for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ printSort( "sort-inference", it2->second );
Trace("sort-inference") << std::endl;
}
+ Trace("sort-inference") << std::endl;
}
+
+ //determine monotonicity of sorts
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ Trace("sort-inference-debug") << "Process monotonicity for " << assertions[i] << std::endl;
+ std::map< Node, Node > var_bound;
+ processMonotonic( assertions[i], true, true, var_bound );
+ }
+
+ Trace("sort-inference") << "We have " << d_sub_sorts.size() << " sub-sorts : " << std::endl;
+ for( unsigned i=0; i<d_sub_sorts.size(); i++ ){
+ printSort( "sort-inference", d_sub_sorts[i] );
+ if( d_type_types.find( d_sub_sorts[i] )!=d_type_types.end() ){
+ Trace("sort-inference") << " is interpreted." << std::endl;
+ }else if( d_non_monotonic_sorts.find( d_sub_sorts[i] )==d_non_monotonic_sorts.end() ){
+ Trace("sort-inference") << " is monotonic." << std::endl;
+ }else{
+ Trace("sort-inference") << " is not monotonic." << std::endl;
+ }
+ }
+
if( doRewrite ){
//simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers)
for( unsigned i=0; i<assertions.size(); i++ ){
@@ -82,47 +156,43 @@ void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){
}
//add lemma enforcing introduced constants to be distinct?
}
- }
-}
-
-int SortInference::getRepresentative( int t ){
- std::map< int, int >::iterator it = d_type_union_find.find( t );
- if( it!=d_type_union_find.end() ){
- if( it->second==t ){
- return t;
- }else{
- int rt = getRepresentative( it->second );
- d_type_union_find[t] = rt;
- return rt;
+ }else if( !options::ufssSymBreak() ){
+ std::map< int, Node > constants;
+ //just add a bunch of unit lemmas
+ for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
+ int rt = d_type_union_find.getRepresentative( it->second );
+ if( d_op_arg_types[ it->first ].empty() && constants.find( rt )==constants.end() ){
+ constants[ rt ] = it->first;
+ }
}
- }else{
- return t;
+ //add unit lemmas for each constant
+ Node first_const;
+ for( std::map< int, Node >::iterator it = constants.begin(); it != constants.end(); ++it ){
+ if( first_const.isNull() ){
+ first_const = it->second;
+ }else{
+ Node eq = first_const.eqNode( it->second );
+ //eq = Rewriter::rewrite( eq );
+ Trace("sort-inference-lemma") << "Sort inference lemma : " << eq << std::endl;
+ assertions.push_back( eq );
+ }
+ }
+
+
}
+ initialSortCount = sortCount;
}
void SortInference::setEqual( int t1, int t2 ){
if( t1!=t2 ){
- int rt1 = getRepresentative( t1 );
- int rt2 = getRepresentative( t2 );
+ int rt1 = d_type_union_find.getRepresentative( t1 );
+ int rt2 = d_type_union_find.getRepresentative( t2 );
if( rt1!=rt2 ){
Trace("sort-inference-debug") << "Set equal : ";
printSort( "sort-inference-debug", rt1 );
Trace("sort-inference-debug") << " ";
printSort( "sort-inference-debug", rt2 );
Trace("sort-inference-debug") << std::endl;
- //check if they must be a type
- std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 );
- std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 );
- if( it2!=d_type_types.end() ){
- if( it1==d_type_types.end() ){
- //swap sides
- int swap = rt1;
- rt1 = rt2;
- rt2 = swap;
- }else{
- Assert( rt1==rt2 );
- }
- }
/*
d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() );
d_type_eq_class[rt2].clear();
@@ -132,7 +202,19 @@ void SortInference::setEqual( int t1, int t2 ){
}
Trace("sort-inference-debug") << "}" << std::endl;
*/
- d_type_union_find[rt2] = rt1;
+ if( rt2>rt1 ){
+ //swap
+ int swap = rt1;
+ rt1 = rt2;
+ rt2 = swap;
+ }
+ d_type_union_find.d_eqc[rt1] = rt2;
+ std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 );
+ if( it1!=d_type_types.end() ){
+ Assert( d_type_types.find( rt2 )==d_type_types.end() );
+ d_type_types[rt2] = it1->second;
+ d_type_types.erase( rt1 );
+ }
}
}
}
@@ -155,14 +237,17 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
Trace("sort-inference-debug") << "Process " << n << std::endl;
//add to variable bindings
if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- //TODO: try applying sort inference to quantified variables
- d_var_types[n][ n[0][i] ] = sortCount;
- sortCount++;
+ if( d_var_types.find( n )!=d_var_types.end() ){
+ return getIdForType( n.getType() );
+ }else{
+ for( size_t i=0; i<n[0].getNumChildren(); i++ ){
+ //apply sort inference to quantified variables
+ d_var_types[n][ n[0][i] ] = sortCount;
+ sortCount++;
- //type of the quantified variable must be the same
- //d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() );
- var_bound[ n[0][i] ] = n;
+ //type of the quantified variable must be the same
+ var_bound[ n[0][i] ] = n;
+ }
}
}
@@ -192,6 +277,9 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
if( n.getKind()==kind::EQUAL ){
//we only require that the left and right hand side must be equal
setEqual( child_types[0], child_types[1] );
+ //int eqType = getIdForType( n[0].getType() );
+ //setEqual( child_types[0], eqType );
+ //setEqual( child_types[1], eqType );
retType = getIdForType( n.getType() );
}else if( n.getKind()==kind::APPLY_UF ){
Node op = n.getOperator();
@@ -227,11 +315,11 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
//d_type_eq_class[sortCount].push_back( n );
}
retType = d_op_return_types[n];
- }else if( n.isConst() ){
- Trace("sort-inference-debug") << n << " is a constant." << std::endl;
+ //}else if( n.isConst() ){
+ // Trace("sort-inference-debug") << n << " is a constant." << std::endl;
//can be any type we want
- retType = sortCount;
- sortCount++;
+ // retType = sortCount;
+ // sortCount++;
}else{
Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl;
//it is an interpretted term
@@ -251,9 +339,43 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
return retType;
}
+void SortInference::processMonotonic( Node n, bool pol, bool hasPol, std::map< Node, Node >& var_bound ) {
+ if( n.getKind()==kind::FORALL ){
+ for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
+ var_bound[n[0][i]] = n;
+ }
+ processMonotonic( n[1], pol, hasPol, var_bound );
+ for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
+ var_bound.erase( n[0][i] );
+ }
+ }else if( n.getKind()==kind::EQUAL ){
+ if( !hasPol || pol ){
+ for( unsigned i=0; i<2; i++ ){
+ if( var_bound.find( n[i] )==var_bound.end() ){
+ int sid = getSortId( var_bound[n[i]], n[i] );
+ d_non_monotonic_sorts[sid] = true;
+ break;
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool npol = pol;
+ bool nhasPol = hasPol;
+ if( n.getKind()==kind::NOT || ( n.getKind()==kind::IMPLIES && i==0 ) ){
+ npol = !npol;
+ }
+ if( ( n.getKind()==kind::ITE && i==0 ) || n.getKind()==kind::XOR || n.getKind()==kind::IFF ){
+ nhasPol = false;
+ }
+ processMonotonic( n[i], npol, nhasPol, var_bound );
+ }
+ }
+}
+
TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
return d_type_types[rt];
}else{
@@ -278,7 +400,7 @@ TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){
}
TypeNode SortInference::getTypeForId( int t ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
return d_type_types[rt];
}else{
@@ -414,15 +536,71 @@ Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){
}
int SortInference::getSortId( Node n ) {
Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n;
- return getRepresentative( d_op_return_types[op] );
+ if( d_op_return_types.find( op )!=d_op_return_types.end() ){
+ return d_type_union_find.getRepresentative( d_op_return_types[op] );
+ }else{
+ return 0;
+ }
}
int SortInference::getSortId( Node f, Node v ) {
- return getRepresentative( d_var_types[f][v] );
+ if( d_var_types.find( f )!=d_var_types.end() ){
+ return d_type_union_find.getRepresentative( d_var_types[f][v] );
+ }else{
+ return 0;
+ }
}
void SortInference::setSkolemVar( Node f, Node v, Node sk ){
+ Trace("sort-inference-temp") << "Set skolem var for " << f << ", variable " << v << std::endl;
+ if( isWellSortedFormula( f ) && d_var_types.find( f )==d_var_types.end() ){
+ std::map< Node, Node > var_bound;
+ process( f, var_bound );
+ }
d_op_return_types[sk] = getSortId( f, v );
+ Trace("sort-inference-temp") << "Set skolem sort id for " << sk << " to " << d_op_return_types[sk] << std::endl;
+}
+
+bool SortInference::isWellSortedFormula( Node n ) {
+ if( n.getType().isBoolean() && n.getKind()!=kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isWellSortedFormula( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return isWellSorted( n );
+ }
+}
+
+bool SortInference::isWellSorted( Node n ) {
+ if( getSortId( n )==0 ){
+ return false;
+ }else{
+ if( n.getKind()==kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int s1 = getSortId( n[i] );
+ int s2 = d_type_union_find.getRepresentative( d_op_arg_types[ n.getOperator() ][i] );
+ if( s1!=s2 ){
+ return false;
+ }
+ if( !isWellSorted( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
+void SortInference::getSortConstraints( Node n, UnionFind& uf ) {
+ if( n.getKind()==kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getSortConstraints( n[i], uf );
+ uf.setEqual( getSortId( n[i] ), d_type_union_find.getRepresentative( d_op_arg_types[ n.getOperator() ][i] ) );
+ }
+ }
}
}/* CVC4 namespace */
diff --git a/src/util/sort_inference.h b/src/util/sort_inference.h
index 1bcb8a208..8f0fc5e9f 100644
--- a/src/util/sort_inference.h
+++ b/src/util/sort_inference.h
@@ -28,11 +28,33 @@ namespace CVC4 {
class SortInference{
private:
- //for debugging
- //std::map< int, std::vector< Node > > d_type_eq_class;
+ //all subsorts
+ std::vector< int > d_sub_sorts;
+ std::map< int, bool > d_non_monotonic_sorts;
+ void recordSubsort( int s );
+public:
+ class UnionFind {
+ public:
+ UnionFind(){}
+ UnionFind( UnionFind& c ){
+ set( c );
+ }
+ std::map< int, int > d_eqc;
+ //pairs that must be disequal
+ std::vector< std::pair< int, int > > d_deq;
+ void print(const char * c);
+ void clear() { d_eqc.clear(); d_deq.clear(); }
+ void set( UnionFind& c );
+ int getRepresentative( int t );
+ void setEqual( int t1, int t2 );
+ void setDisequal( int t1, int t2 ){ d_deq.push_back( std::pair< int, int >( t1, t2 ) ); }
+ bool areEqual( int t1, int t2 ) { return getRepresentative( t1 )==getRepresentative( t2 ); }
+ bool isValid();
+ };
private:
int sortCount;
- std::map< int, int > d_type_union_find;
+ int initialSortCount;
+ UnionFind d_type_union_find;
std::map< int, TypeNode > d_type_types;
std::map< TypeNode, int > d_id_for_types;
//for apply uf operators
@@ -41,12 +63,17 @@ private:
//for bound variables
std::map< Node, std::map< Node, int > > d_var_types;
//get representative
- int getRepresentative( int t );
void setEqual( int t1, int t2 );
int getIdForType( TypeNode tn );
void printSort( const char* c, int t );
//process
int process( Node n, std::map< Node, Node >& var_bound );
+
+//for monotonicity inference
+private:
+ void processMonotonic( Node n, bool pol, bool hasPol, std::map< Node, Node >& var_bound );
+
+//for rewriting
private:
//mapping from old symbols to new symbols
std::map< Node, Node > d_symbol_map;
@@ -60,15 +87,24 @@ private:
Node getNewSymbol( Node old, TypeNode tn );
//simplify
Node simplify( Node n, std::map< Node, Node >& var_bound );
+
public:
- SortInference() : sortCount( 0 ){}
+ SortInference() : sortCount( 1 ){}
~SortInference(){}
void simplify( std::vector< Node >& assertions, bool doRewrite = false );
+ //get sort id for term n
int getSortId( Node n );
+ //get sort id for variable of quantified formula f
int getSortId( Node f, Node v );
//set that sk is the skolem variable of v for quantifier f
void setSkolemVar( Node f, Node v, Node sk );
+public:
+ //is well sorted
+ bool isWellSortedFormula( Node n );
+ bool isWellSorted( Node n );
+ //get constraints for being well-typed according to computed sub-types
+ void getSortConstraints( Node n, SortInference::UnionFind& uf );
};
}
diff --git a/src/util/statistics_registry.h b/src/util/statistics_registry.h
index 3bec559d5..8ffc60d17 100644
--- a/src/util/statistics_registry.h
+++ b/src/util/statistics_registry.h
@@ -847,7 +847,7 @@ public:
* like in this example, which takes the place of the declaration of a
* statistics field "d_checkTimer":
*
- * KEEP_STATISTIC(TimerStat, d_checkTimer, "theory::uf::morgan::checkTime");
+ * KEEP_STATISTIC(TimerStat, d_checkTimer, "theory::uf::checkTime");
*
* If any args need to be passed to the constructor, you can specify
* them after the string.
diff --git a/src/util/util_model.cpp b/src/util/util_model.cpp
index ab4c95ea5..1c2dc2edf 100644
--- a/src/util/util_model.cpp
+++ b/src/util/util_model.cpp
@@ -24,7 +24,7 @@ using namespace std;
namespace CVC4 {
-std::ostream& operator<<(std::ostream& out, Model& m) {
+std::ostream& operator<<(std::ostream& out, const Model& m) {
smt::SmtScope smts(&m.d_smt);
Expr::dag::Scope scope(out, false);
Printer::getPrinter(options::outputLanguage())->toStream(out, m);
diff --git a/src/util/util_model.h b/src/util/util_model.h
index 535493a2d..e5bd1f955 100644
--- a/src/util/util_model.h
+++ b/src/util/util_model.h
@@ -29,10 +29,14 @@ class Command;
class SmtEngine;
class Model;
-std::ostream& operator<<(std::ostream&, Model&);
+std::ostream& operator<<(std::ostream&, const Model&);
class Model {
- friend std::ostream& operator<<(std::ostream&, Model&);
+ friend std::ostream& operator<<(std::ostream&, const Model&);
+ friend class SmtEngine;
+
+ /** the input name (file name, etc.) this model is associated to */
+ std::string d_inputName;
protected:
/** The SmtEngine we're associated with */
@@ -50,6 +54,10 @@ public:
const Command* getCommand(size_t i) const;
/** get the smt engine that this model is hooked up to */
SmtEngine* getSmtEngine() { return &d_smt; }
+ /** get the smt engine (as a pointer-to-const) that this model is hooked up to */
+ const SmtEngine* getSmtEngine() const { return &d_smt; }
+ /** get the input name (file name, etc.) this model is associated to */
+ std::string getInputName() const { return d_inputName; }
public:
/** get value for expression */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback